--- nono/vm/spc.h 2026/04/29 17:04:28 1.1 +++ nono/vm/spc.h 2026/04/29 17:04:56 1.1.1.10 @@ -1,14 +1,17 @@ // // nono -// Copyright (C) 2017 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // #pragma once #include "device.h" -#include "scsi.h" -#include "scheduler.h" #include "fixedqueue.h" +#include "monitor.h" +#include "scheduler.h" +#include "scsidev.h" +#include "vm.h" struct SPC { @@ -44,7 +47,7 @@ struct SPC static const int SCTL_INTR_EN = 0x01; // Interrupt Enable // SCMD レジスタ - // RST は読み出し時に GetRST() から生成。 + // 全ビットを保持。 uint8 scmd; static const int SCMD_CMD_MASK = 0xe0; // Command code static const int SCMD_RST_OUT = 0x10; // RST Out @@ -53,8 +56,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 @@ -64,8 +76,14 @@ 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 レジスタ - // REQ, ACK, ATN は今のところ保持? uint8 psns; static const int PSNS_REQ = 0x80; static const int PSNS_ACK = 0x40; @@ -93,6 +111,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 @@ -123,80 +143,115 @@ struct SPC uint8 mbc() const { return tc & 15; } - - // Set/Reset ACK/REQ 内部状態 - bool ackreq; }; class SPCDevice : public SCSIHostDevice { - typedef SCSIHostDevice inherited; - private: - // X680x0 では $E96000〜 - // LUNA では $E100_0000〜 - + using inherited = SCSIHostDevice; public: - SPCDevice(uint32); - virtual ~SPCDevice(); + SPCDevice(); + virtual ~SPCDevice() override; + + bool Init() override; + void ResetHard() override; - virtual bool Init(); - virtual void ResetHard(); - virtual void ResetSoft(); - void Reset(); - - virtual uint64 Read8(uint32 addr); - virtual uint64 Read16(uint32 addr); - virtual uint64 Write8(uint32 addr, uint32 data); - virtual uint64 Write16(uint32 addr, uint32 data); - virtual uint64 Peek8(uint32 addr); - virtual bool MonitorUpdate(); - - // イベントコールバック - void BusFreeCallback(int); - void SelectionCompleteCallback(int); - void SelectionFailedCallback(int); + // 接続中のデバイスを ID 順に並べたリストを返す (UI ステータスパネル用) + const std::vector& GetConnectedDevices() const { + return connected_devices; + } + + // SCSIBus コールバック + + // バスフリーになった (全員に通知される) + void BusFreeCB(int id) override; - // ターゲットがバスフリーフェーズに移行した - virtual void BusRelease(); + // ターゲットがセレクションに応答した (イニシエータのみ通知される) + void SelectionAckCB() override; + + // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される) + void TransferReqCB() override; + + // BusIO インタフェース + // (内蔵 ROM からのアクセス用に特別に public にしてある) + uint64 Write(uint32 offset, uint32 data); + + protected: + // BusIO インタフェース + static const uint32 NPORT = 16; + uint64 Read(uint32 offset); + uint64 Peek(uint32 offset); private: - void MonitorReg(int x, int y, uint32 reg, const char * const *names); + DECLARE_MONITOR_CALLBACK(MonitorUpdate); + + 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); // INTS レジスタへの書き込み void WriteINTS(uint32); + // 表示のための前回値 + uint32 prev_ints {}; // INTS 設定 void SetINTS(uint32); + // INTS レジスタ値の取得 + uint32 GetINTS() const; + // 割り込み信号線の状態を変える + void ChangeInterrupt(); // PSNS レジスタ値の取得 uint32 GetPSNS() const; // SSTS レジスタ値の取得 uint32 GetSSTS() const; + // 表示のための前回値 + uint32 prev_ssts {}; + + // SERR レジスタ値の取得 + uint32 GetSERR() const; // PCTL レジスタ値の取得 uint32 GetPCTL() const; + // DREG レジスタアクセス + uint64 ReadDREG(); + uint64 WriteDREG(uint32 data); + // バスフリーフェーズに移行する void BusFree(); + // 直近のバスフリーフェーズになった時刻 + // (アービトレーション/セレクション開始時に使う) + uint64 last_busfree_time {}; + // バスをリリースする + void BusRelease(); // Select コマンド実行 void SelectCommand(); + 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 {}; // Transfer コマンド実行 void TransferCommand(); - - // DREG へのデータの充填 - void EnqueueToDREG(); + void TransferCommandStart(Event& ev); + void HardwareTransfer(Event& ev); + void TransferComplete(); + // Transfer コマンド実行中なら true + bool transfer_command_running {}; // SCSI コマンド void ExecCommand(); @@ -204,24 +259,27 @@ class SPCDevice : public SCSIHostDevice // レジスタ struct SPC spc {}; - uint32 regbase = 0; // レジスタの先頭アドレス - int regstride = 0; // レジスタ間の距離 + // VM 種別 + vmtype_t vmtype {}; // SPC に入力されるクロック周期 [nsec] - int t_CLF = 0; + int t_CLF {}; - // 現在のフェーズ - uint phase = 0; + // アクセスウェイト + uint32 read_wait {}; + uint32 write_wait {}; - // Command フェーズで受け取ったコマンド列 - std::vector cmds {}; + // 割り込み信号線の接続先デバイス + InterruptDevice *interrupt {}; - // Data{In,Out} フェーズのバッファ - uint8 *dataptr = NULL; - uint datalen = 0; + // 接続中のデバイス(イニシエータ含む)を ID 順に並べたリスト (モニタ用) + std::vector connected_devices {}; // イベント - Event event {}; + Event event { this }; + Event event_tc { this }; + + Monitor monitor { this }; }; -extern SPCDevice *gSPC; +extern std::unique_ptr gSPC;