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

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

unix.superglobalmegacorp.com

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