Annotation of nono/vm/newsctlr.cpp, revision 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.