Annotation of nono/vm/tvram.cpp, revision 1.1.1.11

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1       root        7: //
                      8: // TVRAM
                      9: //
                     10: 
1.1.1.7   root       11: // TVRAM (PlaneVRAM) はロングワード単位でホストバイトオーダ配置なので、
                     12: // バイトアクセス時は HLB()、ワードアクセス時は HLW() マクロを使用のこと。
                     13: 
1.1       root       14: #include "tvram.h"
1.1.1.3   root       15: #include "videoctlr.h"
1.1       root       16: 
1.1.1.10  root       17: // InsideOut p.135
                     18: static const busdata wait = busdata::Wait(9 * 40_nsec);
                     19: 
1.1.1.7   root       20: // コンストラクタ
1.1       root       21: TVRAMDevice::TVRAMDevice()
1.1.1.9   root       22:        : inherited(1024, 1024)
1.1       root       23: {
1.1.1.9   root       24:        SetName("TVRAM");
                     25:        ClearAlias();
                     26:        AddAlias("TVRAM");
                     27: 
                     28:        uint devlen = 512 * 1024;
1.1       root       29: 
1.1.1.7   root       30:        // プレーン数は4枚固定
                     31:        nplane = NPLANE;
1.1.1.4   root       32: 
1.1.1.7   root       33:        mem.reset(new uint8[devlen]);
1.1       root       34: }
                     35: 
1.1.1.7   root       36: // デストラクタ
1.1       root       37: TVRAMDevice::~TVRAMDevice()
                     38: {
                     39: }
                     40: 
1.1.1.9   root       41: // 初期化
1.1.1.7   root       42: bool
                     43: TVRAMDevice::Init()
                     44: {
1.1.1.9   root       45:        if (inherited::Init() == false) {
                     46:                return false;
                     47:        }
                     48: 
                     49:        renderer = GetRenderer();
                     50:        auto videoctlr = GetVideoCtlrDevice();
                     51: 
1.1.1.7   root       52:        // 加工済みパレットを取得
1.1.1.9   root       53:        palette = &(videoctlr->GetHostPalette())[0];
1.1.1.7   root       54: 
                     55:        return true;
                     56: }
                     57: 
1.1.1.10  root       58: inline uint32
1.1.1.2   root       59: TVRAMDevice::Decoder(uint32 addr) const
                     60: {
                     61:        return addr - baseaddr;
                     62: }
                     63: 
1.1.1.10  root       64: busdata
1.1.1.11! root       65: TVRAMDevice::Read(busaddr addr)
1.1       root       66: {
1.1.1.10  root       67:        busdata data;
1.1.1.11! root       68:        uint32 offset = Decoder(addr.Addr());
        !            69:        data = *(uint32 *)&mem[offset & ~3U];
1.1.1.10  root       70:        data |= wait;
1.1.1.11! root       71:        data |= BusData::Size4;
1.1.1.10  root       72:        return data;
1.1       root       73: }
                     74: 
1.1.1.10  root       75: busdata
1.1.1.11! root       76: TVRAMDevice::Write(busaddr addr, uint32 data)
1.1       root       77: {
1.1.1.11! root       78:        uint32 offset = Decoder(addr.Addr());
        !            79:        uint32 reqsize = addr.GetSize();
        !            80:        uint32 datasize = std::min(2 - (offset & 1U), reqsize);
        !            81:        data >>= (reqsize - datasize) * 8;
1.1       root       82: 
1.1.1.11! root       83:        uint32 mask;
1.1.1.7   root       84:        if (tvram.men) {
1.1.1.11! root       85:                if (datasize == 1) {
        !            86:                        if ((offset & 1U) == 0) {
        !            87:                                mask = tvram.mask >> 8;
        !            88:                        } else {
        !            89:                                mask = tvram.mask & 0xff;
        !            90:                        }
1.1.1.7   root       91:                } else {
1.1.1.11! root       92:                        mask = tvram.mask;
1.1.1.7   root       93:                }
                     94:        } else {
1.1.1.11! root       95:                mask = 0;
1.1.1.7   root       96:        }
                     97: 
1.1.1.9   root       98:        uint32 poffset = offset & 0x1ffff;
1.1.1.11! root       99:        if (datasize == 1) {
        !           100:                Set8(offset, poffset, data, mask);
1.1       root      101:        } else {
1.1.1.11! root      102:                Set16(offset, poffset, data, mask);
1.1       root      103:        }
1.1.1.9   root      104:        SetDirty(poffset);
1.1.1.11! root      105: 
        !           106:        busdata r = wait;
        !           107:        r |= busdata::Size(datasize);
        !           108:        return r;
1.1       root      109: }
                    110: 
1.1.1.10  root      111: busdata
1.1.1.11! root      112: TVRAMDevice::Peek1(uint32 addr)
1.1       root      113: {
1.1.1.2   root      114:        uint32 offset = Decoder(addr);
1.1.1.11! root      115:        return mem[HLB(offset)];
        !           116: }
1.1       root      117: 
1.1.1.11! root      118: bool
        !           119: TVRAMDevice::Poke1(uint32 addr, uint32 data)
        !           120: {
        !           121:        if ((int32)data >= 0) {
        !           122:                uint32 offset = Decoder(addr);
        !           123:                uint32 poffset = offset & 0x1ffff;
        !           124:                mem[HLB(offset)] = data;
        !           125:                // この場合も画面を更新する
        !           126:                SetDirty(poffset);
1.1.1.7   root      127:        }
1.1.1.11! root      128:        return true;
        !           129: }
1.1.1.7   root      130: 
1.1.1.11! root      131: // マスクと同時アクセスを含むバイト書き込み。
        !           132: void
        !           133: TVRAMDevice::Set8(uint32 offset, uint32 poffset, uint32 data, uint32 mask)
        !           134: {
1.1       root      135:        if (tvram.sa) {
                    136:                // 同時アクセス
                    137:                for (int plane = 0; plane < 4; plane++) {
                    138:                        if (tvram.ap[plane]) {
1.1.1.11! root      139:                                uint8 *p = &mem[HLB(0x20000 * plane + poffset)];
        !           140:                                *p = (data & ~mask) | (*p & mask);
1.1       root      141:                        }
                    142:                }
                    143:        } else {
                    144:                // 通常アクセス
1.1.1.11! root      145:                uint8 *p = &mem[HLB(offset)];
        !           146:                *p = (data & ~mask) | (*p & mask);
1.1       root      147:        }
                    148: }
                    149: 
1.1.1.11! root      150: // マスクと同時アクセスを含むワード書き込み。
        !           151: void
        !           152: TVRAMDevice::Set16(uint32 offset, uint32 poffset, uint32 data, uint32 mask)
1.1.1.9   root      153: {
1.1.1.11! root      154:        if (tvram.sa) {
        !           155:                // 同時アクセス
        !           156:                for (int plane = 0; plane < 4; plane++) {
        !           157:                        if (tvram.ap[plane]) {
        !           158:                                uint16 *p = (uint16 *)&mem[HLW(0x20000 * plane + poffset)];
        !           159:                                *p = (data & ~mask) | (*p & mask);
        !           160:                        }
        !           161:                }
        !           162:        } else {
        !           163:                // 通常アクセス
        !           164:                uint16 *p = (uint16 *)&mem[HLW(offset)];
        !           165:                *p = (data & ~mask) | (*p & mask);
1.1.1.9   root      166:        }
                    167: }
                    168: 
1.1.1.7   root      169: // offset の位置に対応する更新フラグを立てる。
1.1.1.9   root      170: // offset はプレーン先頭からのバイトオフセット。
1.1.1.7   root      171: inline void
                    172: TVRAMDevice::SetDirty(uint32 offset)
                    173: {
1.1.1.9   root      174:        // VRAM は横 1024 ドット(128バイト) x 縦 1024 ドット。
1.1.1.7   root      175:        //
                    176:        //              1                               0
                    177:        //        3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
                    178:        //       +-----------+-------+-----+-------+-----+
                    179:        // VRAM  |  Y座標 (1024dot)  | X (128byte) : 8bit|
                    180:        //       +-----------+-------+-----+-------+-----+
1.1.1.9   root      181:        //       :                   :
                    182:        //       +-------------------+
                    183:        // Dirty |                   |
                    184:        //       +-------------------+
                    185:        //        9 8 7 6 5 4 3 2 1 0
                    186: 
                    187:        // 更新フラグはラスタ単位
1.1.1.11! root      188:        uint y = offset >> 7;
1.1.1.9   root      189:        dirty[y] = 1;
                    190: }
                    191: 
                    192: // X 方向にはみ出したときに対応する仮想画面の Y 座標を返す。
                    193: int
                    194: TVRAMDevice::GetWrapY(int y) const
                    195: {
                    196:        // はみ出すと次のラスタの先頭から表示するが、
                    197:        // TVRAM は 4 ラスタがひとかたまりで構成されていて、
                    198:        // 末尾 2bit が 3 のラスタの次は、末尾だけ 0 のラスタに戻る。ようだ。
                    199:        return (y & ~3) + ((y + 1) & 3);
1.1       root      200: }
                    201: 
1.1.1.3   root      202: void
                    203: TVRAMDevice::SetScrollX(int x)
                    204: {
1.1.1.7   root      205:        xscroll = x;
1.1.1.3   root      206: }
                    207: 
                    208: void
                    209: TVRAMDevice::SetScrollY(int y)
                    210: {
1.1.1.7   root      211:        yscroll = y;
1.1.1.9   root      212:        renderer->Invalidate2();
1.1.1.3   root      213: }
                    214: 
1.1.1.7   root      215: // CRTC R21 での同時アクセス設定を反映する。
                    216: // CRTC から呼ばれる。
1.1       root      217: void
1.1.1.7   root      218: TVRAMDevice::SetAccessPlane(uint16 data)
1.1       root      219: {
1.1.1.7   root      220:        tvram.cp[0] = (data & 0x01);
                    221:        tvram.cp[1] = (data & 0x02);
                    222:        tvram.cp[2] = (data & 0x04);
                    223:        tvram.cp[3] = (data & 0x08);
1.1       root      224:        tvram.ap[0] = (data & 0x10);
                    225:        tvram.ap[1] = (data & 0x20);
                    226:        tvram.ap[2] = (data & 0x40);
                    227:        tvram.ap[3] = (data & 0x80);
1.1.1.7   root      228:        tvram.sa = (data & 0x100);
                    229:        tvram.men = (data & 0x200);
1.1       root      230: 
                    231:        if (0) {
                    232:                if (tvram.sa) {
                    233:                        putlog(2, "テキスト画面同時アクセス有効 %c%c%c%c",
                    234:                                tvram.ap[0] ? '0' : '-',
                    235:                                tvram.ap[1] ? '1' : '-',
                    236:                                tvram.ap[2] ? '2' : '-',
                    237:                                tvram.ap[3] ? '3' : '-');
                    238:                } else {
                    239:                        putlog(2, "テキスト画面同時アクセス無効");
                    240:                }
                    241:        }
                    242: }
                    243: 
1.1.1.7   root      244: // CRTC R23 でのアクセスマスク設定を反映する。
                    245: // CRTC から呼ばれる。
                    246: void
                    247: TVRAMDevice::SetAccessMask(uint16 data)
1.1       root      248: {
1.1.1.7   root      249:        tvram.mask = data;
                    250: }
1.1.1.4   root      251: 
1.1.1.7   root      252: // ラスターコピーを開始する。
                    253: // src_ras, dst_ras はライン番号 (レジスタ設定値を4倍したもの)。
                    254: void
1.1.1.11! root      255: TVRAMDevice::RasterCopy(uint src_ras, uint dst_ras)
1.1.1.7   root      256: {
                    257:        for (int plane = 0; plane < 4; plane++) {
                    258:                if (tvram.cp[plane]) {
1.1.1.8   root      259:                        uint8 *src = &mem[0x20000 * plane + src_ras * 128];
                    260:                        uint8 *dst = &mem[0x20000 * plane + dst_ras * 128];
1.1.1.7   root      261:                        memcpy(dst, src, 128 * 4);
1.1       root      262:                }
                    263:        }
                    264: 
1.1.1.8   root      265:        // dst からの4ラインを全部 dirty にする。
1.1.1.9   root      266:        for (int y = 0; y < 4; y++) {
                    267:                SetDirty((dst_ras + y) * 128);
1.1.1.8   root      268:        }
1.1.1.9   root      269: }
                    270: 
                    271: // (x, y) 位置のピクセル情報を screen に描画。(ビットマップモニタの情報欄)
                    272: void
                    273: TVRAMDevice::UpdateInfo(TextScreen& screen, int x, int y) const
                    274: {
                    275:        screen.Clear();
                    276: 
                    277:        //0         1         2         3         4         5         6
                    278:        //012345678901234567890123456789012345678901234567890123456789012345
                    279:        //X=1024 Y=2024: (P0) $e01234: $00 (%00000000) ColorCode=$d
                    280: 
                    281:        screen.Puts(0, 0, "X=     Y=");
                    282:        for (int i = 0; i < nplane; i++) {
1.1.1.11! root      283:                screen.Print(15, i, "(P%u)", i);
1.1.1.9   root      284:        }
                    285: 
                    286:        // カーソルが範囲外ならここまで。
                    287:        if (x < 0) {
                    288:                return;
                    289:        }
                    290: 
                    291:        screen.Print(2, 0, "%4d Y=%4d", x, y);
                    292: 
                    293:        // 1プレーン内のバイトオフセット
                    294:        uint32 planeoffset = ((uint)y * 128) + ((uint)x / 8);
                    295: 
                    296:        uint cc = 0;
                    297:        for (int i = 0; i < nplane; i++) {
                    298:                // プレーン0先頭からのバイトオフセット
                    299:                uint32 totaloffset = 0x20000 * i + planeoffset;
                    300: 
                    301:                uint8 data = mem[HLB(totaloffset)];
1.1.1.11! root      302:                screen.Print(15, i, "(P%u) $%06x: $%02x (%%",
1.1.1.9   root      303:                        i, baseaddr + totaloffset, data);
                    304: 
                    305:                // ビットパターン
                    306:                for (int m = 0x80; m != 0; m >>= 1) {
                    307:                        screen.Putc((data & m) ? '1' : '0');
                    308:                }
                    309:                screen.Putc(')');
                    310: 
                    311:                // カーソル位置をハイライト
                    312:                screen.Locate(35 + (x % 8), i);
                    313:                screen.SetAttr(TA::Em);
                    314: 
                    315:                // カラーコードを計算
                    316:                if ((data & (0x80U >> (x % 8))) != 0) {
                    317:                        cc |= (1U << i);
1.1.1.7   root      318:                }
                    319:        }
1.1.1.9   root      320: 
                    321:        screen.Print(45, 0, "ColorCode=$%x", cc);
1.1       root      322: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.