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

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

unix.superglobalmegacorp.com

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