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

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"
                     45: #include "interrupt.h"
                     46: #include "scheduler.h"
                     47: 
                     48: // コンストラクタ
                     49: NewsCtlrDevice::NewsCtlrDevice()
                     50:        : inherited(OBJ_NEWSCTLR)
                     51: {
                     52:        // ROM のうち固定のもの
                     53:        oidrom[0] = 0x0d;       // ModelID = NWS-1750
                     54: 
                     55:        timer_event.func = ToEventCallback(&NewsCtlrDevice::TimerCallback);
                     56:        timer_event.time = 10_msec;
                     57:        timer_event.Regist("SystemTimer");
                     58: }
                     59: 
                     60: // デストラクタ
                     61: NewsCtlrDevice::~NewsCtlrDevice()
                     62: {
                     63: }
                     64: 
                     65: // 初期化
                     66: bool
                     67: NewsCtlrDevice::Init()
                     68: {
                     69:        if (inherited::Init() == false) {
                     70:                return false;
                     71:        }
                     72: 
                     73:        dipsw = GetDipswDevice();
                     74: 
                     75:        // ステータス読み出しのためにキャストしたのを持っておく
                     76:        interrupt = dynamic_cast<NewsInterrupt*>(GetInterruptDevice());
                     77:        assert(interrupt);
                     78: 
                     79:        // MAC アドレスを ROM にセット。
                     80:        macaddr_t macaddr;
                     81:        if (EthernetDevice::GetConfigMacAddr(&macaddr, false) == false) {
                     82:                // エラーメッセージは表示済み
                     83:                return false;
                     84:        }
                     85:        putmsg(1, "macaddr=%s", macaddr.ToString(':').c_str());
                     86:        memcpy(&oidrom[8], &macaddr, sizeof(macaddr));
                     87: 
                     88:        return true;
                     89: }
                     90: 
                     91: void
                     92: NewsCtlrDevice::ResetHard(bool poweron)
                     93: {
                     94:        // たぶん止まるだろう。知らんけど。
                     95:        timer_intr = false;
                     96:        timer_enable = false;
                     97: 
                     98:        // たぶん消すだろう。知らんけど。
                     99:        led = 0;
                    100: 
                    101:        // たぶん電源オンで即起動? 知らんけど。
                    102:        if (poweron) {
                    103:                scheduler->StartEvent(timer_event);
                    104:        }
                    105: }
                    106: 
                    107: uint64
                    108: NewsCtlrDevice::Read8(uint32 addr)
                    109: {
                    110:        uint64 data = -1;
                    111: 
                    112:        addr |= 0xc0000000;
                    113: 
                    114:        if ((addr >> 16) == 0xe1c0) {
                    115:                uint idx = (addr >> 8) & 3;
                    116:                switch (idx) {
                    117:                 case 0:                // e1c0'00xx
                    118:                        data = GetIDROM(addr);
                    119:                        putlog(2, "$%08x.B (IDROM) -> $%02x", addr, (uint32)data);
                    120:                        break;
                    121:                 case 2:                // e1c0'02xx
                    122:                        // 割り込みステータス
                    123:                        data = interrupt->PeekStatus();
                    124:                        putlog(1, "$%08x.B (IntStat) -> $%02x", addr, (uint32)data);
                    125:                        break;
                    126:                 default:               // e1c0'01xx
                    127:                        // DIP-SW
                    128:                        data = GetDIPSW();
                    129:                        putlog(1, "$%08x.B (DIPSW) -> $%02x", addr, (uint32)data);
                    130:                        break;
                    131:                }
                    132:                return data;
                    133:        }
                    134: 
                    135:        VMPANIC("Read8($%08x)", addr);
                    136:        return data;
                    137: }
                    138: 
                    139: uint64
                    140: NewsCtlrDevice::Write8(uint32 addr, uint32 data)
                    141: {
                    142:        addr |= 0xc0000000;
                    143: 
                    144:        if (addr == 0xe0c8'0000) {
                    145:                // PWS-1560 FDC?
                    146:                putlog(0, "FDC <- $%02x (NOT IMPLEMENTED)", data);
                    147:                return 0;
                    148:        }
                    149:        if (addr == 0xe0dc'0000) {
                    150:                WriteLED(data);
                    151:                return 0;
                    152:        }
                    153:        if (addr == 0xe100'0000) {
                    154:                WriteTimer(data);
                    155:                return 0;
                    156:        }
                    157:        if (addr == 0xe108'0000) {
                    158:                // Parity enable?
                    159:                putlog(0, "Parity enable? <- $%02x (NOT IMPLEMENTED)", data);
                    160:                return 0;
                    161:        }
                    162:        if (addr == 0xe118'0000) {
                    163:                // Level2 Interrupt ?
                    164:                putlog(0, "Lv2 Interrupt disable? <- $%02x (NOT IMPLEMENTED)", data);
                    165:                return 0;
                    166:        }
                    167:        if (addr == 0xe128'0000) {
                    168:                putlog(0, "AST disable? <- $%02x (NOT IMPLEMENTED)", data);
                    169:                return 0;
                    170:        }
                    171:        if (addr == 0xe130'0000) {
                    172:                putlog(0, "L2 cache enable? <- $%02x (NOT IMPLEMENTED)", data);
                    173:                return 0;
                    174:        }
                    175:        if (addr == 0xe138'0000) {
                    176:                putlog(0, "Power Control <- $%02x (NOT IMPLEMENTED)", data);
                    177:                return 0;
                    178:        }
                    179:        if (addr == 0xe190'0000) {
                    180:                putlog(0, "L2 cache disable? <- $%02x (NOT IMPLEMENTED)", data);
                    181:                return 0;
                    182:        }
                    183:        if (addr == 0xe1a0'0000) {
                    184:                putlog(0, "Parity disable? <- $%02x (NOT IMPLEMENTED)", data);
                    185:                return 0;
                    186:        }
                    187:        if (addr == 0xe1c0'0200) {
                    188:                // XXX たぶん 0xe1c0'02ff まで全部同じかも
                    189:                putlog(0, "Parity Vector? <- $%02x (NOT IMPLEMENTED)", data);
                    190:                return 0;
                    191:        }
                    192: 
                    193:        VMPANIC("Write8($%08x) <- $%02x", addr, data);
                    194:        return (uint64)-1;
                    195: }
                    196: 
                    197: uint64
                    198: NewsCtlrDevice::Peek8(uint32 addr)
                    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: 
                    214:        return (uint64)-1;
                    215: }
                    216: 
                    217: // IDROM の値を返す。この関数は副作用を起こしてはいけない。
                    218: uint8
                    219: NewsCtlrDevice::GetIDROM(uint32 addr) const
                    220: {
                    221:        uint32 data;
                    222: 
                    223:        // $e1c0'00xx はたぶん 256x4bit ROM。
                    224:        //
                    225:        // 生データ oidrom[] はバイトで持っておき(つまり128バイト)、
                    226:        // アクセス時に分解する。
                    227:        // 実際に使われているのはこのうち先頭の 16バイト(32ニブル)分のようだ。
                    228: 
                    229:        int n = (addr & 0xff) / 2;
                    230:        if ((addr & 1) == 0) {
                    231:                data = oidrom[n] >> 4;
                    232:        } else {
                    233:                data = oidrom[n];
                    234:        }
                    235:        return data | 0xf0;
                    236: }
                    237: 
                    238: // DIPSW の状態を読み出す。この関数は副作用を起こしてはいけない。
                    239: // SW1 が LSB 側。
                    240: // オン(true)なら %0、オフ(false)なら %1。
                    241: uint8
                    242: NewsCtlrDevice::GetDIPSW() const
                    243: {
                    244:        uint8 data = 0;
                    245: 
                    246:        for (int i = 0; i < 8; i++) {
                    247:                if (dipsw->Get(i) == false) {
                    248:                        data |= 1U << i;
                    249:                }
                    250:        }
                    251:        return data;
                    252: }
                    253: 
                    254: // LED 制御ポート書き込み
                    255: void
                    256: NewsCtlrDevice::WriteLED(uint32 data)
                    257: {
                    258:        // bit0 が緑 LED、bit1 がオレンジ LED のオンオフらしい。
                    259:        led = data & 0x03;
                    260:        putlog(1, "LED <- $%02x", led);
                    261: }
                    262: 
                    263: // システムタイマー
                    264: void
                    265: NewsCtlrDevice::WriteTimer(uint32 data)
                    266: {
                    267:        switch (data) {
                    268:         case 0:
                    269:                timer_enable = false;
                    270:                timer_intr = false;
                    271:                break;
                    272:         case 1:
                    273:                timer_enable = true;
                    274:                break;
                    275:         default:
                    276:                VMPANIC("Unknown Timer Control $%02x", data);
                    277:                break;
                    278:        }
                    279:        ChangeInterrupt();
                    280: }
                    281: 
                    282: // システムタイマーイベント
                    283: void
                    284: NewsCtlrDevice::TimerCallback(Event& ev)
                    285: {
                    286:        timer_intr = true;
                    287:        ChangeInterrupt();
                    288: 
                    289:        // XXX clock-sync はまた後ほど
                    290:        scheduler->RestartEvent(ev);
                    291: }
                    292: 
                    293: // 割り込み信号線の状態を変える
                    294: void
                    295: NewsCtlrDevice::ChangeInterrupt()
                    296: {
                    297:        interrupt->ChangeINT(this, (bool)(timer_enable && timer_intr));
                    298: }

unix.superglobalmegacorp.com

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