Annotation of nono/vm/newsctlr.cpp, revision 1.1.1.8

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2022 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // NEWS の各種制御ポート(?)
                      9: //
                     10: 
                     11: // NWS-1750 の $e100'0000..$e1ff'ffff
                     12: //
                     13: //            +0 +1 +2 +3 +4 +5 +6 +7  +8 +9 +A +B +C +D +E +F'0000
                     14: // e100'0000 |TIC                      PE
                     15: // e110'0000 |                         I2D
                     16: // e120'0000 |                         ASD
                     17: // e130'0000 |L2E                      POW
                     18: // e140'0000 |
                     19: // e150'0000 |
                     20: // e160'0000 |
                     21: // e170'0000 |
                     22: // e180'0000 |
                     23: // e190'0000 |L2D
                     24: // e1a0'0000 |PD
                     25: // e1b0'0000 |
                     26: // e1c0'0000 |(*)
                     27: // e1d0'0000 |
                     28: // e1e0'0000 |
                     29: // e1f0'0000 |
                     30: //
                     31: // TIC: Timer Interrupt Control
                     32: // PE/PD: Parity Enable/Disable
                     33: // I2D: Lv2 Interrupt Disable
                     34: // ASD: AST Disable
                     35: // L2E/L2D: L2 Cache Enable/Disable
                     36: // POW: Power Control
                     37: // (*): IDROM, DIP-SW, Parity Vector, Interupt Status
                     38: //
                     39: // また、ここに書いてない $e000'0000 ブロックにあるデバイスも一部担当している。
                     40: // newsio.cpp 冒頭のメモリマップも参照。
                     41: 
                     42: #include "newsctlr.h"
                     43: #include "dipsw.h"
                     44: #include "ethernet.h"
1.1.1.7   root       45: #include "event.h"
1.1       root       46: #include "interrupt.h"
                     47: #include "scheduler.h"
1.1.1.6   root       48: #include "syncer.h"
1.1.1.4   root       49: #include "textscreen.h"
1.1       root       50: 
                     51: // コンストラクタ
                     52: NewsCtlrDevice::NewsCtlrDevice()
                     53:        : inherited(OBJ_NEWSCTLR)
                     54: {
                     55:        // ROM のうち固定のもの
                     56:        oidrom[0] = 0x0d;       // ModelID = NWS-1750
                     57: }
                     58: 
                     59: // デストラクタ
                     60: NewsCtlrDevice::~NewsCtlrDevice()
                     61: {
                     62: }
                     63: 
                     64: // 初期化
                     65: bool
                     66: NewsCtlrDevice::Init()
                     67: {
                     68:        dipsw = GetDipswDevice();
                     69: 
1.1.1.6   root       70:        // クロックの同期方法。
                     71:        sync_rt = GetSyncer()->GetSyncRealtime();
                     72: 
1.1       root       73:        // ステータス読み出しのためにキャストしたのを持っておく
                     74:        interrupt = dynamic_cast<NewsInterrupt*>(GetInterruptDevice());
                     75:        assert(interrupt);
                     76: 
                     77:        // MAC アドレスを ROM にセット。
1.1.1.5   root       78:        MacAddr macaddr;
1.1.1.2   root       79:        if (EthernetDevice::GetConfigMacAddr(0, &macaddr, false) == false) {
1.1       root       80:                // エラーメッセージは表示済み
                     81:                return false;
                     82:        }
                     83:        putmsg(1, "macaddr=%s", macaddr.ToString(':').c_str());
                     84:        memcpy(&oidrom[8], &macaddr, sizeof(macaddr));
                     85: 
1.1.1.7   root       86:        auto evman = GetEventManager();
                     87:        timer_event = evman->Regist(this,
                     88:                ToEventCallback(&NewsCtlrDevice::TimerCallback),
                     89:                "SystemTimer");
                     90:        timer_event->time = TIMER_PERIOD;
1.1.1.4   root       91: 
1.1       root       92:        return true;
                     93: }
                     94: 
                     95: void
                     96: NewsCtlrDevice::ResetHard(bool poweron)
                     97: {
                     98:        // たぶん止まるだろう。知らんけど。
                     99:        timer_intr = false;
                    100:        timer_enable = false;
1.1.1.3   root      101:        ChangeInterrupt();
1.1       root      102: 
                    103:        // たぶん消すだろう。知らんけど。
                    104:        led = 0;
                    105: 
                    106:        // たぶん電源オンで即起動? 知らんけど。
                    107:        if (poweron) {
1.1.1.6   root      108:                if (sync_rt) {
                    109:                        stime = GetSyncer()->GetRealTime();
                    110:                }
1.1       root      111:                scheduler->StartEvent(timer_event);
                    112:        }
                    113: }
                    114: 
1.1.1.3   root      115: busdata
1.1.1.4   root      116: NewsCtlrDevice::Read(busaddr addr)
1.1       root      117: {
1.1.1.4   root      118:        uint32 paddr = addr.Addr() | 0xc0000000;
1.1       root      119: 
1.1.1.4   root      120:        if ((paddr >> 16) == 0xe1c0) {
                    121:                uint idx = (paddr >> 8) & 3;
                    122:                busdata data;
1.1       root      123:                switch (idx) {
                    124:                 case 0:                // e1c0'00xx
1.1.1.4   root      125:                        data = GetIDROM(paddr);
                    126:                        putlog(2, "$%08x.B (IDROM) -> $%02x", paddr, data.Data());
1.1       root      127:                        break;
                    128:                 case 2:                // e1c0'02xx
                    129:                        // 割り込みステータス
                    130:                        data = interrupt->PeekStatus();
1.1.1.4   root      131:                        putlog(1, "$%08x.B (IntStat) -> $%02x", paddr, data.Data());
1.1       root      132:                        break;
                    133:                 default:               // e1c0'01xx
                    134:                        // DIP-SW
                    135:                        data = GetDIPSW();
1.1.1.4   root      136:                        putlog(1, "$%08x.B (DIPSW) -> $%02x", paddr, data.Data());
1.1       root      137:                        break;
                    138:                }
1.1.1.4   root      139:                data |= BusData::Size1;
1.1       root      140:                return data;
                    141:        }
1.1.1.4   root      142:        VMPANIC("Read($%08x)", paddr);
1.1       root      143: }
                    144: 
1.1.1.3   root      145: busdata
1.1.1.4   root      146: NewsCtlrDevice::Write(busaddr addr, uint32 data)
1.1       root      147: {
1.1.1.4   root      148:        uint32 paddr = addr.Addr() | 0xc0000000;
                    149:        uint32 reqsize = addr.GetSize();
                    150:        data >>= (reqsize - 1) * 8;
1.1       root      151: 
1.1.1.4   root      152:        if (paddr == 0xe0c8'0000) {
1.1       root      153:                // PWS-1560 FDC?
                    154:                putlog(0, "FDC <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      155: 
                    156:        } else if (paddr == 0xe0dc'0000) {
1.1       root      157:                WriteLED(data);
1.1.1.4   root      158: 
                    159:        } else if (paddr == 0xe100'0000) {
1.1       root      160:                WriteTimer(data);
1.1.1.4   root      161: 
                    162:        } else if (paddr == 0xe108'0000) {
1.1       root      163:                // Parity enable?
                    164:                putlog(0, "Parity enable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      165: 
                    166:        } else if (paddr == 0xe118'0000) {
1.1       root      167:                // Level2 Interrupt ?
                    168:                putlog(0, "Lv2 Interrupt disable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      169: 
                    170:        } else if (paddr == 0xe128'0000) {
1.1       root      171:                putlog(0, "AST disable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      172: 
                    173:        } else if (paddr == 0xe130'0000) {
1.1       root      174:                putlog(0, "L2 cache enable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      175: 
                    176:        } else if (paddr == 0xe138'0000) {
1.1       root      177:                putlog(0, "Power Control <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      178: 
                    179:        } else if (paddr == 0xe190'0000) {
1.1       root      180:                putlog(0, "L2 cache disable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      181: 
                    182:        } else if (paddr == 0xe1a0'0000) {
1.1       root      183:                putlog(0, "Parity disable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      184: 
                    185:        } else if (paddr == 0xe1c0'0200) {
1.1       root      186:                // XXX たぶん 0xe1c0'02ff まで全部同じかも
                    187:                putlog(0, "Parity Vector? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4   root      188: 
                    189:        } else {
                    190:                VMPANIC("Write($%08x) <- $%02x", paddr, data);
1.1       root      191:        }
                    192: 
1.1.1.4   root      193:        busdata r = BusData::Size1;
                    194:        return r;
1.1       root      195: }
                    196: 
1.1.1.3   root      197: busdata
1.1.1.4   root      198: NewsCtlrDevice::Peek1(uint32 addr)
1.1       root      199: {
                    200:        addr |= 0xc0000000;
                    201: 
                    202:        if ((addr >> 16) == 0xe1c0) {
                    203:                uint idx = (addr >> 8) & 3;
                    204:                switch (idx) {
                    205:                 case 0:        // e1c0'00xx
                    206:                        return GetIDROM(addr);
                    207:                 case 2:        // e1c0'02xx
                    208:                        return interrupt->PeekStatus();
                    209:                 default:       // e1c0'01xx
                    210:                        return GetDIPSW();
                    211:                }
                    212:        }
                    213: 
1.1.1.4   root      214:        return BusData::BusErr;
1.1.1.3   root      215: }
                    216: 
                    217: // NewsIO の下請けとして呼ばれる。
                    218: void
1.1.1.8 ! root      219: NewsCtlrDevice::MonitorScreenNewsCtlr(TextScreen& screen, int y)
1.1.1.3   root      220: {
                    221:        // テーブル方式ではないので、Read/Write と手動で揃える…。
                    222: 
                    223:        uint32 addr = 0xe100;
                    224:        for (int i = 0; i < 32; i++) {
                    225:                screen.Print(0, y, "$%04x'0000:", addr);
                    226: 
                    227:                const char *name = NULL;
                    228:                TA attr;
                    229:                for (int j = 0; j < 8; j++) {
                    230:                        switch (addr) {
                    231:                         case 0xe100:   name = "Timer";         break;
                    232:                         case 0xe108:   name = "ParEn?";        break;
                    233:                         case 0xe118:   name = "Lv2Int?";       break;
                    234:                         case 0xe128:   name = "ASTDis?";       break;
                    235:                         case 0xe130:   name = "L2CE?";         break;
                    236:                         case 0xe138:   name = "Power";         break;
                    237:                         case 0xe190:   name = "L2CD?";         break;
                    238:                         case 0xe1a0:   name = "ParDis?";       break;
                    239:                         case 0xe1c0:   name = "Misc";          break;
                    240:                         default:
                    241:                                name = NULL;
                    242:                                break;
                    243:                        }
                    244:                        if (name) {
                    245:                                attr = TA::Normal;
                    246:                        } else {
                    247:                                name = "NopIO";
                    248:                                attr = TA::Disable;
                    249:                        }
                    250:                        screen.Puts(12 + j * 8, y, attr, name);
                    251:                        addr++;
                    252:                }
                    253:                y++;
                    254:        }
1.1       root      255: }
                    256: 
                    257: // IDROM の値を返す。この関数は副作用を起こしてはいけない。
                    258: uint8
                    259: NewsCtlrDevice::GetIDROM(uint32 addr) const
                    260: {
                    261:        uint32 data;
                    262: 
                    263:        // $e1c0'00xx はたぶん 256x4bit ROM。
                    264:        //
                    265:        // 生データ oidrom[] はバイトで持っておき(つまり128バイト)、
                    266:        // アクセス時に分解する。
                    267:        // 実際に使われているのはこのうち先頭の 16バイト(32ニブル)分のようだ。
                    268: 
                    269:        int n = (addr & 0xff) / 2;
                    270:        if ((addr & 1) == 0) {
                    271:                data = oidrom[n] >> 4;
                    272:        } else {
                    273:                data = oidrom[n];
                    274:        }
                    275:        return data | 0xf0;
                    276: }
                    277: 
                    278: // DIPSW の状態を読み出す。この関数は副作用を起こしてはいけない。
                    279: // SW1 が LSB 側。
                    280: // オン(true)なら %0、オフ(false)なら %1。
                    281: uint8
                    282: NewsCtlrDevice::GetDIPSW() const
                    283: {
                    284:        uint8 data = 0;
                    285: 
                    286:        for (int i = 0; i < 8; i++) {
                    287:                if (dipsw->Get(i) == false) {
                    288:                        data |= 1U << i;
                    289:                }
                    290:        }
                    291:        return data;
                    292: }
                    293: 
                    294: // LED 制御ポート書き込み
                    295: void
                    296: NewsCtlrDevice::WriteLED(uint32 data)
                    297: {
                    298:        // bit0 が緑 LED、bit1 がオレンジ LED のオンオフらしい。
                    299:        led = data & 0x03;
                    300:        putlog(1, "LED <- $%02x", led);
                    301: }
                    302: 
                    303: // システムタイマー
                    304: void
                    305: NewsCtlrDevice::WriteTimer(uint32 data)
                    306: {
                    307:        switch (data) {
                    308:         case 0:
                    309:                timer_enable = false;
                    310:                timer_intr = false;
                    311:                break;
                    312:         case 1:
                    313:                timer_enable = true;
                    314:                break;
                    315:         default:
                    316:                VMPANIC("Unknown Timer Control $%02x", data);
                    317:                break;
                    318:        }
                    319:        ChangeInterrupt();
                    320: }
                    321: 
                    322: // システムタイマーイベント
                    323: void
1.1.1.7   root      324: NewsCtlrDevice::TimerCallback(Event *ev)
1.1       root      325: {
                    326:        timer_intr = true;
                    327:        ChangeInterrupt();
                    328: 
1.1.1.6   root      329:        // 足す前は前回の割り込み発生時刻なので period を足すと現在時刻。
                    330:        if (sync_rt) {
                    331:                stime += TIMER_PERIOD;
                    332:                scheduler->StartRealtimeEvent(ev, stime, TIMER_PERIOD);
                    333:        } else {
                    334:                scheduler->RestartEvent(ev);
                    335:        }
1.1       root      336: }
                    337: 
                    338: // 割り込み信号線の状態を変える
                    339: void
                    340: NewsCtlrDevice::ChangeInterrupt()
                    341: {
                    342:        interrupt->ChangeINT(this, (bool)(timer_enable && timer_intr));
                    343: }

unix.superglobalmegacorp.com

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