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

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

unix.superglobalmegacorp.com

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