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

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

unix.superglobalmegacorp.com

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