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

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.7   root       18: // コンストラクタ
1.1       root       19: TVRAMDevice::TVRAMDevice()
1.1.1.7   root       20:        : inherited("TVRAM", 1024, 1024)
1.1       root       21: {
                     22:        devaddr = baseaddr;
                     23:        devlen  = 512 * 1024;
                     24: 
1.1.1.7   root       25:        // プレーン数は4枚固定
                     26:        nplane = NPLANE;
1.1.1.4   root       27: 
1.1.1.7   root       28:        modify_mask = 0xff00;
                     29: 
                     30:        mem.reset(new uint8[devlen]);
1.1       root       31: }
                     32: 
1.1.1.7   root       33: // デストラクタ
1.1       root       34: TVRAMDevice::~TVRAMDevice()
                     35: {
                     36: }
                     37: 
1.1.1.7   root       38: bool
                     39: TVRAMDevice::Init()
                     40: {
                     41:        // 加工済みパレットを取得
                     42:        palette = gVideoCtlr->GetHostPalette();
                     43: 
                     44:        return true;
                     45: }
                     46: 
                     47: // リセット
1.1       root       48: void
1.1.1.7   root       49: TVRAMDevice::ResetHard(bool poweron)
1.1       root       50: {
                     51:        // XXX ここ?
                     52:        Invalidate();
                     53: }
                     54: 
1.1.1.2   root       55: inline uint64
                     56: TVRAMDevice::Decoder(uint32 addr) const
                     57: {
                     58:        return addr - baseaddr;
                     59: }
                     60: 
1.1       root       61: uint64
                     62: TVRAMDevice::Read8(uint32 addr)
                     63: {
1.1.1.5   root       64:        gMPU->AddCycle(9);      // Inside/Out p.135
1.1.1.2   root       65:        uint32 offset = Decoder(addr);
1.1.1.7   root       66:        return mem[HLB(offset)];
1.1       root       67: }
                     68: 
                     69: uint64
                     70: TVRAMDevice::Read16(uint32 addr)
                     71: {
1.1.1.5   root       72:        gMPU->AddCycle(9);      // Inside/Out p.135
1.1.1.2   root       73:        uint32 offset = Decoder(addr);
1.1.1.7   root       74:        return *(uint16 *)&mem[HLW(offset)];
1.1       root       75: }
                     76: 
                     77: uint64
                     78: TVRAMDevice::Write8(uint32 addr, uint32 data)
                     79: {
1.1.1.2   root       80:        uint32 offset = Decoder(addr);
1.1.1.7   root       81:        uint8 *ptr;
                     82:        uint8 mask8;
1.1       root       83: 
1.1.1.5   root       84:        gMPU->AddCycle(9);      // Inside/Out p.135
                     85: 
1.1       root       86:        // XXX とりあえずね
1.1.1.8 ! root       87:        putlog(3, "Write $%06x.B <- $%02x", addr, data);
1.1       root       88: 
1.1.1.7   root       89:        if (tvram.men) {
                     90:                if ((addr & 1) == 0) {
                     91:                        mask8 = tvram.mask >> 8;
                     92:                } else {
                     93:                        mask8 = tvram.mask;
                     94:                }
                     95:        } else {
                     96:                mask8 = 0;
                     97:        }
                     98: 
1.1       root       99:        if (tvram.sa) {
                    100:                // 同時アクセス
                    101:                uint32 poffset = offset & 0x1ffff;
                    102:                for (int plane = 0; plane < 4; plane++) {
                    103:                        if (tvram.ap[plane]) {
1.1.1.7   root      104:                                ptr = &mem[HLB(0x20000 * plane + poffset)];
                    105:                                *ptr = (data & ~mask8) | (*ptr & mask8);
1.1       root      106:                        }
                    107:                }
                    108:        } else {
                    109:                // 通常アクセス
1.1.1.7   root      110:                ptr = &mem[HLB(offset)];
                    111:                *ptr = (data & ~mask8) | (*ptr & mask8);
1.1       root      112:        }
1.1.1.7   root      113:        SetDirty(offset);
1.1       root      114:        return 0;
                    115: }
                    116: 
                    117: uint64
                    118: TVRAMDevice::Write16(uint32 addr, uint32 data)
                    119: {
1.1.1.2   root      120:        uint32 offset = Decoder(addr);
1.1.1.7   root      121:        uint16 *ptr;
                    122:        uint16 mask16;
1.1       root      123: 
1.1.1.5   root      124:        gMPU->AddCycle(9);      // Inside/Out p.135
                    125: 
1.1       root      126:        // XXX とりあえずね
1.1.1.8 ! root      127:        putlog(3, "Write $%06x.W <- $%04x", addr, data);
1.1       root      128: 
1.1.1.7   root      129:        if (tvram.men) {
                    130:                mask16 = tvram.mask;
                    131:        } else {
                    132:                mask16 = 0;
                    133:        }
                    134: 
1.1       root      135:        if (tvram.sa) {
                    136:                // 同時アクセス
                    137:                uint32 poffset = offset & 0x1ffff;
                    138:                for (int plane = 0; plane < 4; plane++) {
                    139:                        if (tvram.ap[plane]) {
1.1.1.7   root      140:                                ptr = (uint16 *)&mem[HLW(0x20000 * plane + poffset)];
                    141:                                *ptr = (data & ~mask16) | (*ptr & mask16);
1.1       root      142:                        }
                    143:                }
                    144:        } else {
                    145:                // 通常アクセス
1.1.1.7   root      146:                ptr = (uint16 *)&mem[HLW(offset)];
                    147:                *ptr = (data & ~mask16) | (*ptr & mask16);
1.1       root      148:        }
1.1.1.7   root      149:        SetDirty(offset);
1.1       root      150:        return 0;
                    151: }
                    152: 
                    153: uint64
                    154: TVRAMDevice::Peek8(uint32 addr)
                    155: {
1.1.1.2   root      156:        uint32 offset = Decoder(addr);
1.1.1.7   root      157:        return mem[HLB(offset)];
1.1       root      158: }
                    159: 
1.1.1.7   root      160: // offset の位置に対応する更新フラグを立てる。
                    161: // offset は TVRAM 先頭からのバイトオフセット (プレーン先頭からではない)。
                    162: inline void
                    163: TVRAMDevice::SetDirty(uint32 offset)
                    164: {
                    165:        // VRAM は横 1024 ドット(128バイト) x 縦 1024 ドットで、これを
                    166:        // 横 128 ドット(16バイト) x 縦 16 ドットずつのブロックに分割する。
                    167:        // ブロック数は横 8個 x 縦 64個。
                    168:        //
                    169:        //              1                               0
                    170:        //        3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
                    171:        //       +-----------+-------+-----+-------+-----+
                    172:        // VRAM  |  Y座標 (1024dot)  | X (128byte) : 8bit|
                    173:        //       +-----------+-------+-----+-------+-----+
                    174:        //       :           :       :     :             :
                    175:        //       +-----------+-------+-----+-------------+
                    176:        // Block | Y(64blks) | 16dot | X(8)|   128 dot   | *: X は 8 blocks
                    177:        //       +-----------+-------+-----+-------------+
                    178:        //        \          \     |     |
                    179:        //          \          \   |     |
                    180:        //            \          \ |     |
                    181:        //               +-----------+-----+
                    182:        // Dirty         | Y(64blks) | X(8)|
                    183:        //               +-----------+-----+
                    184:        //                8 7 6 5 4 3 2 1 0
                    185: 
                    186:        // x 座標(バイト単位 7 bit)の上位 3 bit
                    187:        int x = (offset >> 4) & 0x07;
                    188:        // y 座標(10bit) の上位 6 bit
                    189:        int y = (offset >> 8) & 0x1f8;
                    190: 
                    191:        // からインデックスを求める
                    192:        int b = x + y;
                    193: 
                    194:        dirty[b] = 1;
                    195: 
                    196: #if defined(PERF_HIT)
                    197:        // どのロングワードが更新されたか
                    198:        dirty_word[(offset & 0x1ffff) >> 2] = true;
                    199: #endif
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;
                    212:        gRenderer->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
                    255: TVRAMDevice::RasterCopy(int src_ras, int dst_ras)
                    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 にする。
        !           266: #if !defined(PERF_HIT)
        !           267:        // dirty は、1ブロックが縦 16dot 収容しているので、4の倍数から始まる
        !           268:        // 4ラインは必ず1ブロックに収まる。横方向は1ブロックにつき 128dot 収容して
        !           269:        // いるので全部で8ブロック。
        !           270:        // よって dirty を立てるだけなら 8回の呼び出しで済む。
        !           271:        for (int x = 0; x < 8; x++) {
        !           272:                SetDirty(dst_ras * 128 + (x << 4));
        !           273:        }
        !           274: #else
        !           275:        // PERF_HIT の更新を行う場合は律儀に全プレーンの全ロングワード分ループする
        !           276:        for (int plane = 0; plane < 4; plane++) {
        !           277:                for (int i = 0; i < 4; i++) {
        !           278:                        int y = dst_ras + i;
        !           279:                        for (int x = 0; x < 128 / sizeof(uint32); x++) {
        !           280:                                SetDirty(0x20000 * plane + y * 128 + x * sizeof(uint32));
        !           281:                        }
1.1.1.7   root      282:                }
                    283:        }
1.1.1.8 ! root      284: #endif
1.1       root      285: }

unix.superglobalmegacorp.com

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