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

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

unix.superglobalmegacorp.com

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