Annotation of nono/vm/nereid.cpp, revision 1.1.1.3

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2023 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // Nereid Ethernet/メモリ/USB 複合ボード (のうち Ethernet/バンクメモリ)
                      9: //
                     10: 
                     11: // Nereid の DIPSW
                     12: //
                     13: //  SW1,2   : RAM をメインメモリとして使う場合の容量
                     14: //            OFF,OFF = 割り当てない (この時だけバンクメモリが 16MB 使える)
                     15: //  SW3,4,5 : RAM をメインメモリとして使う場合の開始アドレス
                     16: //  SW6     : RAM をバンクメモリとして使う場合のウィンドウ
                     17: //            OFF = $ee0000
                     18: //            ON  = $ef0000
                     19: //  SW7     : アドレス、割り込みベクタ設定
                     20: //            OFF = $ece3xx, $f9, $fb
                     21: //            ON  = $ecebxx, $f8, $fa
                     22: //  SW8     : バンクメモリ有効無効
                     23: //            OFF = 無効
                     24: //            ON  = 有効
                     25: //
                     26: //  バンクメモリの容量は、SW1-2 でメインメモリに割り当てた余りのうち
                     27: //  4MB か 16MB のどちらか。Nereid のメモリをメインメモリに割り当てる機能は
                     28: //  (意味がないので) 実装せず、SW1-2 を設定した結果バンクメモリ容量が 4MB か
                     29: //  16MB にできるところだけ再現する。
                     30: //
                     31: //  Nereid は SW-6,7 により2枚まで同時に運用することが可能。
                     32: //  SW6 と SW7 の組み合わせは本来自由だが、そこまで自由度を上げるメリットは
                     33: //  なさそうなので、ここでは
                     34: //    Nereid#0 が SW6=OFF、SW7=OFF
                     35: //    Nereid#1 が SW6=ON、 SW7=ON
                     36: //  と固定して扱う。
                     37: 
                     38: // 各デバイスのアドレス配置、割り込みベクタ
                     39: //
                     40: //  #0 (SW7=OFF)   #1 (SW7=ON)
                     41: //  -------------- --------------
                     42: //  $ece300-ece33f $eceb00-eceb3f : RTL8019AS (偶数アドレスのみ)
                     43: //  $ece380-ece383 $eceb80-eceb83 : SL811HS/T (奇数アドレスのみ)
                     44: //  $ece3f0        $ecebf0        : バンクページ選択
                     45: //  $ece3f1        $ecebf1        : 制御ポート
                     46: //
                     47: //  $f9            $f8            : RTL8019AS 割り込みベクタ
                     48: //  $fb            $fa            : SL811HS/T 割り込みベクタ
                     49: 
                     50: #include "nereid.h"
                     51: #include "bankram.h"
                     52: #include "config.h"
                     53: #include "rtl8019as.h"
                     54: 
                     55: //
                     56: // Nereid 空間担当デバイス
                     57: //
                     58: 
                     59: // boards[0]、board[1] を所有し、アクセスをディスパッチする。
                     60: 
                     61: // コンストラクタ
                     62: NereidDevice::NereidDevice()
                     63:        : inherited(OBJ_NEREID)
                     64: {
                     65:        monitor.func = ToMonitorCallback(&NereidDevice::MonitorUpdate);
                     66:        monitor.SetSize(41, 9);
                     67:        monitor.Regist(ID_MONITOR_NEREID);
                     68: }
                     69: 
                     70: // デストラクタ
                     71: NereidDevice::~NereidDevice()
                     72: {
                     73: }
                     74: 
                     75: // デバイス作成
                     76: bool
                     77: NereidDevice::Create()
                     78: {
1.1.1.3 ! root       79:        // ボードの有無は nereid%u-enable だけで決まる。
1.1       root       80:        for (int i = 0; i < 2; i++) {
1.1.1.3 ! root       81:                std::string name = string_format("nereid%u-enable", i);
1.1       root       82:                bool enable = gConfig->Find(name).AsInt();
                     83: 
                     84:                if (enable) {
                     85:                        boards[i].reset(new NereidBoardDevice(i));
                     86: 
                     87:                        // 配置場所
                     88:                        if (i == 0) {
                     89:                                loc[i] = 0x03;  // $ece300-
                     90:                        } else {
                     91:                                loc[i] = 0x0b;  // $eceb00-
                     92:                        }
                     93:                } else {
                     94:                        // アドレス比較で一致させないため -1 にしておく。
                     95:                        loc[i] = -1;
                     96:                }
                     97:        }
                     98: 
                     99:        return true;
                    100: }
                    101: 
                    102: // Nereid が1枚でもささっていれば true。
                    103: // (X68kIO.Init() から呼ばれる)
                    104: bool
                    105: NereidDevice::IsInstalled() const
                    106: {
                    107:        return (bool)boards[0] || (bool)boards[1];
                    108: }
                    109: 
                    110: inline uint32
                    111: NereidDevice::Decoder(uint32 addr) const
                    112: {
                    113:        // ここで返すのはオフセットではなく、チップセレクトに近い。
                    114:        // $ece3xx or $ecebxx の $3 か $b のところ (厳密にはそれを含む
                    115:        // 5ビット) を返し、あらかじめ用意してある loc[i] と比較する。
                    116:        return (addr >> 8) & 0x1f;
                    117: }
                    118: 
1.1.1.2   root      119: busdata
1.1.1.3 ! root      120: NereidDevice::Read(busaddr addr)
1.1       root      121: {
1.1.1.3 ! root      122:        uint32 paddr = addr.Addr();
1.1       root      123: 
1.1.1.3 ! root      124:        putlog(2, "Read  $%06x.%c", paddr, (addr.GetSize() == 1 ? 'B' : 'W'));
1.1       root      125: 
1.1.1.3 ! root      126:        uint32 cs = Decoder(paddr);
1.1       root      127:        for (int i = 0; i < boards.size(); i++) {
                    128:                if (cs == loc[i]) {
1.1.1.3 ! root      129:                        return boards[i]->Read(addr);
1.1       root      130:                }
                    131:        }
                    132: 
1.1.1.3 ! root      133:        return BusData::BusErr;
1.1       root      134: }
                    135: 
1.1.1.2   root      136: busdata
1.1.1.3 ! root      137: NereidDevice::Write(busaddr addr, uint32 data)
1.1       root      138: {
1.1.1.3 ! root      139:        uint32 paddr = addr.Addr();
1.1       root      140: 
1.1.1.3 ! root      141:        putlog(2, "Write $%06x.%c", paddr, (addr.GetSize() == 1 ? 'B' : 'W'));
        !           142: 
        !           143:        uint32 cs = Decoder(paddr);
1.1       root      144:        for (int i = 0; i < boards.size(); i++) {
                    145:                if (cs == loc[i]) {
1.1.1.3 ! root      146:                        return boards[i]->Write(addr, data);
1.1       root      147:                }
                    148:        }
1.1.1.3 ! root      149:        return BusData::BusErr;
1.1       root      150: }
                    151: 
1.1.1.2   root      152: busdata
1.1.1.3 ! root      153: NereidDevice::Peek1(uint32 addr)
1.1       root      154: {
                    155:        uint32 cs = Decoder(addr);
                    156: 
                    157:        for (int i = 0; i < boards.size(); i++) {
                    158:                if (cs == loc[i]) {
1.1.1.3 ! root      159:                        return boards[i]->Peek1(addr);
1.1       root      160:                }
                    161:        }
1.1.1.3 ! root      162:        return BusData::BusErr;
1.1       root      163: }
                    164: 
                    165: void
                    166: NereidDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    167: {
                    168:        int y;
                    169: 
                    170:        screen.Clear();
                    171: 
                    172:        // 0123456789012345678901234567890123456789
                    173:        //                #0           #1
                    174:        // Board        : NotInstalled NotInstalled
                    175:        //  Ethernet    : Enable
                    176:        //   Address    : $ece300
                    177:        //   Vector     : $f9
                    178:        //  Bank Memory : 16MB
                    179:        //   Page Select: $ece380
                    180:        //   Bank Window: $ee0000
                    181:        //   CurrentPage: $00
                    182: 
                    183:        y = 1;
                    184:        screen.Puts(0, y++, "Board        :");
                    185:        screen.Puts(1, y++,  "Ethernet    :");
                    186:        screen.Puts(2, y++,   "Address    :");
                    187:        screen.Puts(2, y++,   "Vector     :");
                    188:        screen.Puts(1, y++,  "Bank Memory :");
                    189:        screen.Puts(2, y++,   "Page Select:");
                    190:        screen.Puts(2, y++,   "Bank Window:");
                    191:        screen.Puts(2, y++,   "CurrentPage:");
                    192: 
                    193:        for (int i = 0; i < 2; i++) {
                    194:                int x = 15 + i * 14;
                    195:                TA attr;
                    196: 
                    197:                y = 0;
1.1.1.3 ! root      198:                screen.Print(x, y++, "#%u", i);
1.1       root      199: 
                    200:                // ボードがささっているか
                    201:                bool installed = (bool)boards[i];
                    202:                if (installed) {
                    203:                        screen.Puts(x, y, "Installed");
                    204:                } else {
                    205:                        screen.Puts(x, y, "NotInstalled");
                    206:                }
                    207:                y++;
                    208: 
                    209:                // イーサネット
                    210:                attr = TA::Disable;
                    211:                if (installed) {
                    212:                        if (boards[i]->IsNetEnable()) {
                    213:                                screen.Puts(x, y, "Available");
                    214:                                attr = TA::Normal;
                    215:                        } else {
                    216:                                screen.Puts(x, y, "NotAvailable");
                    217:                        }
                    218:                } else {
                    219:                        screen.Puts(x, y, attr, "-");
                    220:                }
                    221:                y++;
                    222:                screen.Print(x, y++, attr, "$%06x", 0xece300 + i * 0x800);
                    223:                screen.Print(x, y++, attr, "$%02x", 0xf9 - i);
                    224: 
                    225:                // バンクメモリ
                    226:                attr = TA::Disable;
                    227:                int ramsize = 0;
                    228:                if (installed) {
                    229:                        ramsize = boards[i]->GetBankRAMSize();
                    230:                        if (ramsize > 0) {
1.1.1.3 ! root      231:                                screen.Print(x, y, "%u MB", ramsize);
1.1       root      232:                                attr = TA::Normal;
                    233:                        } else {
                    234:                                screen.Puts(x, y, "Disabled");
                    235:                        }
                    236:                } else {
                    237:                        screen.Puts(x, y, attr, "-");
                    238:                }
                    239:                y++;
                    240:                screen.Print(x, y++, attr, "$%06x", 0xece3f0 + i * 0x800);
                    241:                screen.Print(x, y++, attr, "$%06x", 0xee0000 + i * 0x10000);
                    242:                if (installed) {
                    243:                        if (ramsize > 0) {
                    244:                                attr = TA::Normal;
                    245:                        } else {
                    246:                                attr = TA::Disable;
                    247:                        }
                    248:                        screen.Print(x, y, attr, "$%02x", boards[i]->GetPage());
                    249:                } else {
                    250:                        screen.Puts(x, y, attr, "---");
                    251:                }
                    252:        }
                    253: }
                    254: 
                    255: 
                    256: //
                    257: // Nereid ボード1枚分
                    258: //
                    259: 
                    260: // コンストラクタ
                    261: NereidBoardDevice::NereidBoardDevice(int id_)
                    262:        : inherited(OBJ_NEREID_BOARD(id_))
                    263: {
                    264:        id = id_;
                    265: }
                    266: 
                    267: // デストラクタ
                    268: NereidBoardDevice::~NereidBoardDevice()
                    269: {
                    270: }
                    271: 
                    272: bool
                    273: NereidBoardDevice::Create()
                    274: {
1.1.1.3 ! root      275:        std::string netname = string_format("nereid%u-net", id);
        !           276:        std::string ramname = string_format("nereid%u-ram-size", id);
1.1       root      277: 
                    278:        const ConfigItem inet = gConfig->Find(netname);
                    279:        bool net_enable = inet.AsInt();
                    280: 
                    281:        const ConfigItem iramsize = gConfig->Find(ramname);
                    282:        ramsize_MB = iramsize.AsInt();
                    283:        switch (ramsize_MB) {
                    284:         case 0:
                    285:         case 4:
                    286:         case 16:
                    287:         case -4:
                    288:         case -16:
                    289:                // 負数は、バンクメモリ無効時の制御ポート bit6 を明示したい場合用。
                    290:                break;
                    291:         default:
                    292:                iramsize.Err("Valid value is one of 0, 4, 16 (or -4, -16)");
                    293:                return false;
                    294:        }
                    295: 
                    296:        // ネットワークが無効の場合 (これは正常な実機では起きないが)、
                    297:        // RTL8019ASDevice インスタンスの生成自体を行わず、net は NULL。
                    298:        if (net_enable) {
                    299:                int vector;
                    300:                if (id == 0) {
                    301:                        vector = 0xf9;
                    302:                } else {
                    303:                        vector = 0xf8;
                    304:                }
                    305:                net.reset(new RTL8019ASDevice(id, vector));
                    306:        }
                    307: 
                    308:        // バンクメモリは (DIPSW によって) 有効/無効どちらであっても
                    309:        // BankRAMDevice インスタンスの生成自体は行う。
                    310:        // ページレジスタは存在している(はずの)ため。
                    311:        if (ramsize_MB <= 0) {
                    312:                bank.reset(new BankRAMDevice(OBJ_BANKRAM(id), 0));
                    313:        } else {
                    314:                bank.reset(new BankRAMDevice(OBJ_BANKRAM(id), ramsize_MB));
1.1.1.2   root      315:                // I/O 空間への登録は X68kIO 側から行っている。
1.1       root      316:        }
                    317:        return true;
                    318: }
                    319: 
                    320: inline uint32
                    321: NereidBoardDevice::Decoder(uint32 addr) const
                    322: {
                    323:        return addr & 0xff;
                    324: }
                    325: 
1.1.1.2   root      326: busdata
1.1.1.3 ! root      327: NereidBoardDevice::Read(busaddr addr)
1.1       root      328: {
1.1.1.3 ! root      329:        busdata data = BusData::BusErr;
1.1       root      330: 
1.1.1.3 ! root      331:        uint32 paddr = addr.Addr();
        !           332:        uint32 offset = Decoder(paddr);
1.1       root      333: 
                    334:        if (offset < 0x40) {
                    335:                if ((bool)net) {
1.1.1.3 ! root      336:                        return net->Read(addr);
1.1       root      337:                }
1.1.1.3 ! root      338:        } else {
        !           339:                uint32 reqsize = addr.GetSize();
        !           340:                uint32 datasize = std::min(2 - (paddr & 1), reqsize);
        !           341:                if (datasize == 1) {
        !           342:                        if (offset == 0xf0) {
        !           343:                                data = GetPage();
        !           344:                        } else if (offset == 0xf1) {
        !           345:                                data = GetCtrl();
        !           346:                        }
        !           347:                        data |= BusData::Size1;
        !           348:                } else {
        !           349:                        if (offset == 0xf0) {
        !           350:                                data  = GetPage() << 8;
        !           351:                                data |= GetCtrl();
        !           352:                        }
        !           353:                        data |= BusData::Size2;
1.1       root      354:                }
                    355:        }
1.1.1.3 ! root      356:        return data;
1.1       root      357: }
                    358: 
1.1.1.2   root      359: busdata
1.1.1.3 ! root      360: NereidBoardDevice::Write(busaddr addr, uint32 data)
1.1       root      361: {
1.1.1.3 ! root      362:        busdata r;
        !           363: 
        !           364:        uint32 paddr = addr.Addr();
        !           365:        uint32 offset = Decoder(paddr);
1.1       root      366: 
                    367:        if (offset < 0x40) {
                    368:                if ((bool)net) {
1.1.1.3 ! root      369:                        return net->Write(addr, data);
        !           370:                }
        !           371:        } else {
        !           372:                uint32 reqsize = addr.GetSize();
        !           373:                uint32 datasize = std::min(2 - (paddr & 1), reqsize);
        !           374:                data >>= (reqsize - datasize) * 8;
        !           375:                if (datasize == 1) {
        !           376:                        if (offset == 0xf0) {
        !           377:                                SetPage(data);
        !           378:                        } else if (offset == 0xf1) {
        !           379:                                SetCtrl(data);
        !           380:                        } else {
        !           381:                                r.SetBusErr();
        !           382:                        }
        !           383:                        r |= BusData::Size1;
        !           384:                } else {
        !           385:                        if (offset == 0xf0) {
        !           386:                                SetPage(data >> 8);
        !           387:                                SetCtrl(data & 0xff);
        !           388:                        } else {
        !           389:                                r.SetBusErr();
        !           390:                        }
        !           391:                        r |= BusData::Size2;
1.1       root      392:                }
                    393:        }
1.1.1.3 ! root      394:        return r;
1.1       root      395: }
                    396: 
1.1.1.2   root      397: busdata
1.1.1.3 ! root      398: NereidBoardDevice::Peek1(uint32 addr)
1.1       root      399: {
                    400:        uint32 offset = Decoder(addr);
                    401: 
                    402:        if (offset < 0x40) {
                    403:                if ((bool)net) {
1.1.1.3 ! root      404:                        return net->Peek1(addr);
1.1       root      405:                }
                    406:        } else if (offset == 0xf0) {
                    407:                return GetPage();
                    408: 
                    409:        } else if (offset == 0xf1) {
                    410:                return GetCtrl();
                    411:        }
1.1.1.3 ! root      412:        return BusData::BusErr;
1.1       root      413: }
                    414: 
                    415: // バンクページ選択レジスタの値を取得。
                    416: uint32
                    417: NereidBoardDevice::GetPage() const
                    418: {
                    419:        return bank->GetPage();
                    420: }
                    421: 
                    422: // バンクページ選択レジスタに値を設定。
                    423: void
                    424: NereidBoardDevice::SetPage(uint32 data)
                    425: {
                    426:        bank->SetPage(data);
                    427: }
                    428: 
                    429: // 制御ポートの値を取得。
                    430: uint32
                    431: NereidBoardDevice::GetCtrl() const
                    432: {
                    433:        uint32 data;
                    434: 
                    435:        // bit7: バンクメモリ有効 (%0=無効、%1=有効)、DIPSW8 が見える
                    436:        // bit6: バンクメモリサイズ (%0=4M、%1=16M)
                    437:        // bit5: バンクメモリウィンドウ (%0=$EE0000、%1=$EF0000)、DIPSW6 が見える
                    438:        // bit4
                    439:        // bit3
                    440:        // bit2: USB 割り込み
                    441:        // bit1: USB 電源
                    442:        // bit0: USB 有効
                    443: 
                    444:        // bit5、バンクメモリウィンドウは $EE0000 なら %0、$EF0000 なら %1 だが、
                    445:        // 現状はボード #0 が $EE0000、ボード #1 が $EF0000 と固定してある。
                    446:        data = id << 5;
                    447: 
                    448:        // bit7、bit6。
                    449:        //
                    450:        // bit6 は DIPSW1=OFF, DIPSW2=OFF (メインメモリへの割り当てなし、
                    451:        // つまり 16MB 全部をバンクメモリに割ける) 時に %1 になる。
                    452:        // まったく実用性はないけど再現できるようにしておく。
                    453:        //
                    454:        // DIP8 DIP1 DIP2   bit7 bit6   BankRAM   nereid?-ram-size=
                    455:        // ---------------+-----------+----------+------
                    456:        // ON   OFF  OFF  :    1    1 : 16MB     | 16
                    457:        // ON   *    *    :    1    0 : 4MB      | 4
                    458:        // OFF  OFF  OFF  :    0    1 : Disabled | 0
                    459:        // OFF  OFF  OFF  :    0    1 : Disabled | -16
                    460:        // OFF  *    *    :    0    0 : Disabled | -4
                    461:        if (ramsize_MB > 0) {
                    462:                data |= 0x80;
                    463:                if (ramsize_MB != 4) {
                    464:                        data |= 0x40;
                    465:                }
                    466:        } else {
                    467:                if (ramsize_MB != -4) {
                    468:                        data |= 0x40;
                    469:                }
                    470:        }
                    471: 
                    472:        // USB 関連は無効なままなので %0
                    473: 
                    474:        return data;
                    475: }
                    476: 
                    477: void
                    478: NereidBoardDevice::SetCtrl(uint32 data)
                    479: {
                    480:        // USB はないので書き込みは無効
                    481: }

unix.superglobalmegacorp.com

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