--- nono/vm/spc.h 2026/04/29 17:04:36 1.1.1.4 +++ nono/vm/spc.h 2026/04/29 17:05:17 1.1.1.14 @@ -4,13 +4,19 @@ // Licensed under nono-license.txt // +// +// SPC (MB89352) +// + #pragma once #include "device.h" +#include "event.h" #include "fixedqueue.h" -#include "scheduler.h" +#include "monitor.h" #include "scsidev.h" -#include "vm.h" + +class InterruptDevice; struct SPC { @@ -55,8 +61,17 @@ struct SPC static const int SCMD_TERM_MODE = 0x01; // Termination Mode // INTS レジスタ - // 全ビットを保持。 - uint8 ints; + // + // 内部変数 ints は割り込み状態を一度に判別するため SERR レジスタの + // xfer ビット(SERR_XFER_OUT) もここの bit8 に含めている。 + // 残りの下位8ビットは INTS と同じ。 + // + // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // INTS |SEL |RESL|DIS |CMPL|SERV|TOUT|HERR|REST| + // b8 + // ints変数 |xfer|SEL |RESL|DIS |CMPL|SERV|TOUT|HERR|REST| + // + uint16 ints; static const int INTS_SELECTED = 0x80; // Selected static const int INTS_RESELECTED = 0x40; // Reselected static const int INTS_DISCONNECTED = 0x20; // Disconnected @@ -66,6 +81,13 @@ struct SPC static const int INTS_HARD_ERR = 0x02; // SPC Hard Error static const int INTS_RESET_COND = 0x01; // Reset Condition + static const int INTS_XFER_OUT = 0x100; // SERR_XFER_OUT + + // 割り込みマスク (INTS_RESET_COND はノンマスカブル割り込み) + uint16 ints_mask; + static const int INTS_ENABLE_MASK = 0x01ff; + static const int INTS_DISABLE_MASK = 0x0001; + // PSNS レジスタ uint8 psns; static const int PSNS_REQ = 0x80; @@ -94,6 +116,8 @@ struct SPC static const int SSTS_DREG_EMPTY = 0x01; // DREG Status (Empty) // SERR レジスタ + // XFER_OUT 以外の4つの有効ビットを保持。 + // XFER_OUT は ints が担当している。 uint8 serr; static const int SERR_DATAERR_SCSI = 0x80; // Data Error: SCSI static const int SERR_DATAERR_SPC = 0x40; // Data Error: SPC @@ -102,9 +126,10 @@ struct SPC static const int SERR_SHORT_XFER = 0x02; // Short Transfer Period // PCTL レジスタ - // ここでは BusFree INT Enable ビットだけを保持。 - // 残りの MSG, C/D, I/O は親クラスの信号線フラグから生成。 + // BusFree INT Enable は独立して保持。 + // MSG, CD, IO の3ビットは pctl_out で保持。 bool busfree_intr_enable; + uint8 pctl_out; static const int PCTL_MASK = 0x87; // 書き込みマスク static const int PCTL_BFINT_EN = 0x80; // BusFree INT Enable static const int PCTL_MSG = 0x04; @@ -131,13 +156,10 @@ class SPCDevice : public SCSIHostDevice using inherited = SCSIHostDevice; public: SPCDevice(); - ~SPCDevice() override; + virtual ~SPCDevice() override; bool Init() override; - void ResetHard() override; - void ResetSoft() override; - - bool MonitorUpdate() override; + void ResetHard(bool poweron) override; // SCSIBus コールバック @@ -150,23 +172,26 @@ class SPCDevice : public SCSIHostDevice // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される) void TransferReqCB() override; + // BusIO インタフェース + // (内蔵 ROM からのアクセス用に特別に public にしてある) + uint64 Write(uint32 offset, uint32 data); + protected: // BusIO インタフェース static const uint32 NPORT = 16; - uint64 Read(uint32 addr); - uint64 Write(uint32 addr, uint32 data); - uint64 Peek(uint32 addr); + uint64 Read(uint32 offset); + uint64 Peek(uint32 offset); private: - void Reset(); + DECLARE_MONITOR_CALLBACK(MonitorUpdate); - void MonitorReg(int x, int y, uint32 reg, const char * const *names); + void MonitorReg(TextScreen&, + int x, int y, uint32 reg, const char * const *names); // SCTL レジスタへの書き込み void WriteSCTL(uint32); - - // SCMD レジスタ値の取得 - uint32 GetSCMD() const; + // 割り込みマスクの再構成 + void MakeIntsMask(); // SCMD レジスタへの書き込み void WriteSCMD(uint32); @@ -178,6 +203,10 @@ class SPCDevice : public SCSIHostDevice // INTS 設定 void SetINTS(uint32); + // INTS レジスタ値の取得 + uint32 GetINTS() const; + // 割り込み信号線の状態を変える + void ChangeInterrupt(); // PSNS レジスタ値の取得 uint32 GetPSNS() const; @@ -187,6 +216,11 @@ class SPCDevice : public SCSIHostDevice // 表示のための前回値 uint32 prev_ssts {}; + // SERR レジスタ値の取得 + uint32 GetSERR() const; + + // PCTL レジスタへの書き込み + void WritePCTL(uint32); // PCTL レジスタ値の取得 uint32 GetPCTL() const; @@ -204,23 +238,22 @@ class SPCDevice : public SCSIHostDevice // Select コマンド実行 void SelectCommand(); - void Arbitration1(int code); - void Arbitration2(int code); - void Selection1(int code); - void SelectionTimeout(int code); + void Arbitration1(Event& ev); + void Arbitration2(Event& ev); + void Selection1(Event& ev); + void SelectionTimeout(Event& ev); // SetATN コマンド実行 void SetATNCommand(); // セレクションフェーズで ATN を立てる - bool set_atn_in_selection = false; + bool set_atn_in_selection {}; // Transfer コマンド実行 void TransferCommand(); - void TransferCommandStart(int code); - void HardwareTransfer(int code); + void HardwareTransfer(Event& ev); void TransferComplete(); // Transfer コマンド実行中なら true - bool transfer_command_running = false; + bool transfer_command_running {}; // SCSI コマンド void ExecCommand(); @@ -229,14 +262,25 @@ class SPCDevice : public SCSIHostDevice struct SPC spc {}; // VM 種別 - vmtype_t vmtype {}; + VMType vmtype {}; // SPC に入力されるクロック周期 [nsec] - int t_CLF = 0; + int t_CLF {}; + + // アクセスウェイト + uint32 read_wait {}; + uint32 write_wait {}; + + // 割り込み信号線の接続先デバイス + InterruptDevice *interrupt {}; // イベント - Event event {}; - Event event_tc {}; + Event event { this }; + Event event_tc { this }; + + Monitor monitor { this }; }; -extern std::unique_ptr gSPC; +static inline SPCDevice *GetSPCDevice() { + return Object::GetObject(OBJ_SPC); +}