|
|
1.1 root 1: //
2: // nono
1.1.1.4 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #pragma once
8:
9: #include "device.h"
10: #include "fixedqueue.h"
1.1.1.10! root 11: #include "monitor.h"
1.1.1.4 root 12: #include "scheduler.h"
13: #include "scsidev.h"
1.1.1.3 root 14: #include "vm.h"
1.1 root 15:
16: struct SPC
17: {
18: static const int BDID = 0x0; // $E96021 RW $E100_0000
19: static const int SCTL = 0x1; // $E96023 RW $E100_0004
20: static const int SCMD = 0x2; // $E96025 RW $E100_0008
21: static const int TMOD = 0x3; // (MB89352 にはない)
22: static const int INTS = 0x4; // $E96029 RW $E100_0010
23: static const int PSNS = 0x5; // $E9602B R- $E100_0014
24: static const int SDGC = 0x5; // $E9602B -W $E100_0014
25: static const int SSTS = 0x6; // $E9602D R- $E100_0018
26: static const int SERR = 0x7; // $E9602F R- $E100_001C
27: static const int PCTL = 0x8; // $E96031 RW $E100_0020
28: static const int MBC = 0x9; // $E96033 R- $E100_0024
29: static const int DREG = 0xa; // $E96035 RW $E100_0028
30: static const int TEMP = 0xb; // $E96037 RW $E100_002C
31: static const int TCH = 0xc; // $E96039 RW $E100_0030
32: static const int TCM = 0xd; // $E9603B RW $E100_0034
33: static const int TCL = 0xe; // $E9603D RW $E100_0038
34: static const int EXBF = 0xf; // (MB89352 にはない)
35:
36:
37: // SCTL レジスタ
38: // 全ビットを保持。
39: uint8 sctl;
40: static const int SCTL_RESET = 0x80; // Reset & Disable
41: static const int SCTL_CTL_RESET = 0x40; // Control Reset
42: static const int SCTL_DIAG_MODE = 0x20; // Diag Mode
43: static const int SCTL_ARBIT_EN = 0x10; // Arbitration Enable
44: static const int SCTL_PARITY_EN = 0x08; // Parity Enable
45: static const int SCTL_SEL_EN = 0x04; // Select Enable
46: static const int SCTL_RESEL_EN = 0x02; // Reselect Enable
47: static const int SCTL_INTR_EN = 0x01; // Interrupt Enable
48:
49: // SCMD レジスタ
1.1.1.2 root 50: // 全ビットを保持。
1.1 root 51: uint8 scmd;
52: static const int SCMD_CMD_MASK = 0xe0; // Command code
53: static const int SCMD_RST_OUT = 0x10; // RST Out
54: static const int SCMD_INTERCEPT = 0x08; // Intersept Transfer
55: static const int SCMD_PROGRAM = 0x04; // Program Transfer
56: static const int SCMD_TERM_MODE = 0x01; // Termination Mode
57:
58: // INTS レジスタ
1.1.1.7 root 59: //
60: // 内部変数 ints は割り込み状態を一度に判別するため SERR レジスタの
61: // xfer ビット(SERR_XFER_OUT) もここの bit8 に含めている。
62: // 残りの下位8ビットは INTS と同じ。
63: //
64: // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
65: // INTS |SEL |RESL|DIS |CMPL|SERV|TOUT|HERR|REST|
66: // b8
67: // ints変数 |xfer|SEL |RESL|DIS |CMPL|SERV|TOUT|HERR|REST|
68: //
69: uint16 ints;
1.1 root 70: static const int INTS_SELECTED = 0x80; // Selected
71: static const int INTS_RESELECTED = 0x40; // Reselected
72: static const int INTS_DISCONNECTED = 0x20; // Disconnected
73: static const int INTS_COMPLETE = 0x10; // Command Complete
74: static const int INTS_SERV_REQ = 0x08; // Service Required
75: static const int INTS_TIMEOUT = 0x04; // Time Out
76: static const int INTS_HARD_ERR = 0x02; // SPC Hard Error
77: static const int INTS_RESET_COND = 0x01; // Reset Condition
78:
1.1.1.7 root 79: static const int INTS_XFER_OUT = 0x100; // SERR_XFER_OUT
80:
81: // 割り込みマスク (INTS_RESET_COND はノンマスカブル割り込み)
82: uint16 ints_mask;
83: static const int INTS_ENABLE_MASK = 0x01ff;
84: static const int INTS_DISABLE_MASK = 0x0001;
85:
1.1 root 86: // PSNS レジスタ
87: uint8 psns;
88: static const int PSNS_REQ = 0x80;
89: static const int PSNS_ACK = 0x40;
90: static const int PSNS_ATN = 0x20;
91: static const int PSNS_SEL = 0x10;
92: static const int PSNS_BSY = 0x08;
93: static const int PSNS_MSG = 0x04;
94: static const int PSNS_CD = 0x02;
95: static const int PSNS_IO = 0x01;
96:
97: // SDGC レジスタ
98: uint8 sdgc;
99: static const int SDGC_XFER_ENABLE = 0x20;
100:
101: // SSTS レジスタ
102: // 上位4ビットを保持。下位4ビットは読み出し時に生成。
103: uint8 ssts;
104: static const int SSTS_CONN_INIT = 0x80; // Connected (Initiator)
105: static const int SSTS_CONN_TARG = 0x40; // Connected (Target)
106: static const int SSTS_SPC_BUSY = 0x20; // SPC Busy
107: static const int SSTS_IN_PROGRESS = 0x10; // Transfer in Progress
108: static const int SSTS_RST_IN = 0x08; // SCSI RST In
109: static const int SSTS_TC_ZERO = 0x04; // TC=0
110: static const int SSTS_DREG_FULL = 0x02; // DREG Status (Full)
111: static const int SSTS_DREG_EMPTY = 0x01; // DREG Status (Empty)
112:
113: // SERR レジスタ
1.1.1.7 root 114: // XFER_OUT 以外の4つの有効ビットを保持。
115: // XFER_OUT は ints が担当している。
1.1 root 116: uint8 serr;
117: static const int SERR_DATAERR_SCSI = 0x80; // Data Error: SCSI
118: static const int SERR_DATAERR_SPC = 0x40; // Data Error: SPC
119: static const int SERR_XFER_OUT = 0x20; // Xfer Out
120: static const int SERR_TC_PARITY_ERR = 0x08; // TC Parity Error
121: static const int SERR_SHORT_XFER = 0x02; // Short Transfer Period
122:
123: // PCTL レジスタ
124: // ここでは BusFree INT Enable ビットだけを保持。
125: // 残りの MSG, C/D, I/O は親クラスの信号線フラグから生成。
126: bool busfree_intr_enable;
127: static const int PCTL_MASK = 0x87; // 書き込みマスク
128: static const int PCTL_BFINT_EN = 0x80; // BusFree INT Enable
129: static const int PCTL_MSG = 0x04;
130: static const int PCTL_CD = 0x02;
131: static const int PCTL_IO = 0x01;
132:
133: FixedQueue<uint8, 8> dreg; // DREG レジスタ
134:
135: uint8 temp_in; // TEMP レジスタ (SCSI -> MPU)
136: uint8 temp_out; // TEMP レジスタ (MPU -> SCSI)
137: uint32 tc; // TC
138:
139: uint32 GetTCL() const { return tc & 0x0000ff; } // TCL
140:
141: // MBC (内部の読み込み専用レジスタ)
142: // TC の下位4ビットが読めるらしい
143: uint8 mbc() const {
144: return tc & 15;
145: }
146: };
147:
148: class SPCDevice : public SCSIHostDevice
149: {
1.1.1.4 root 150: using inherited = SCSIHostDevice;
1.1 root 151: public:
1.1.1.3 root 152: SPCDevice();
1.1.1.7 root 153: virtual ~SPCDevice() override;
1.1 root 154:
1.1.1.4 root 155: bool Init() override;
156: void ResetHard() override;
1.1 root 157:
1.1.1.9 root 158: // 接続中のデバイスを ID 順に並べたリストを返す (UI ステータスパネル用)
159: const std::vector<SCSIDevice*>& GetConnectedDevices() const {
160: return connected_devices;
161: }
162:
1.1.1.2 root 163: // SCSIBus コールバック
164:
165: // バスフリーになった (全員に通知される)
1.1.1.4 root 166: void BusFreeCB(int id) override;
1.1 root 167:
1.1.1.2 root 168: // ターゲットがセレクションに応答した (イニシエータのみ通知される)
1.1.1.4 root 169: void SelectionAckCB() override;
1.1.1.2 root 170:
171: // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される)
1.1.1.4 root 172: void TransferReqCB() override;
1.1 root 173:
1.1.1.8 root 174: // BusIO インタフェース
175: // (内蔵 ROM からのアクセス用に特別に public にしてある)
176: uint64 Write(uint32 offset, uint32 data);
177:
1.1.1.3 root 178: protected:
179: // BusIO インタフェース
180: static const uint32 NPORT = 16;
1.1.1.8 root 181: uint64 Read(uint32 offset);
182: uint64 Peek(uint32 offset);
1.1.1.3 root 183:
1.1 root 184: private:
1.1.1.10! root 185: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
! 186:
1.1.1.5 root 187: void MonitorReg(TextScreen&,
188: int x, int y, uint32 reg, const char * const *names);
1.1 root 189:
190: // SCTL レジスタへの書き込み
191: void WriteSCTL(uint32);
1.1.1.7 root 192: // 割り込みマスクの再構成
193: void MakeIntsMask();
1.1 root 194:
195: // SCMD レジスタへの書き込み
196: void WriteSCMD(uint32);
197:
198: // INTS レジスタへの書き込み
199: void WriteINTS(uint32);
1.1.1.3 root 200: // 表示のための前回値
201: uint32 prev_ints {};
1.1 root 202:
203: // INTS 設定
204: void SetINTS(uint32);
1.1.1.7 root 205: // INTS レジスタ値の取得
206: uint32 GetINTS() const;
207: // 割り込み信号線の状態を変える
208: void ChangeInterrupt();
1.1 root 209:
210: // PSNS レジスタ値の取得
211: uint32 GetPSNS() const;
212:
213: // SSTS レジスタ値の取得
214: uint32 GetSSTS() const;
1.1.1.3 root 215: // 表示のための前回値
216: uint32 prev_ssts {};
1.1 root 217:
1.1.1.7 root 218: // SERR レジスタ値の取得
219: uint32 GetSERR() const;
220:
1.1 root 221: // PCTL レジスタ値の取得
222: uint32 GetPCTL() const;
223:
1.1.1.3 root 224: // DREG レジスタアクセス
225: uint64 ReadDREG();
226: uint64 WriteDREG(uint32 data);
227:
1.1 root 228: // バスフリーフェーズに移行する
229: void BusFree();
1.1.1.2 root 230: // 直近のバスフリーフェーズになった時刻
231: // (アービトレーション/セレクション開始時に使う)
232: uint64 last_busfree_time {};
233: // バスをリリースする
234: void BusRelease();
1.1 root 235:
236: // Select コマンド実行
237: void SelectCommand();
1.1.1.6 root 238: void Arbitration1(Event& ev);
239: void Arbitration2(Event& ev);
240: void Selection1(Event& ev);
241: void SelectionTimeout(Event& ev);
1.1.1.2 root 242:
243: // SetATN コマンド実行
244: void SetATNCommand();
245: // セレクションフェーズで ATN を立てる
1.1.1.6 root 246: bool set_atn_in_selection {};
1.1 root 247:
248: // Transfer コマンド実行
249: void TransferCommand();
1.1.1.6 root 250: void TransferCommandStart(Event& ev);
251: void HardwareTransfer(Event& ev);
1.1.1.3 root 252: void TransferComplete();
1.1.1.2 root 253: // Transfer コマンド実行中なら true
1.1.1.6 root 254: bool transfer_command_running {};
1.1 root 255:
256: // SCSI コマンド
257: void ExecCommand();
258:
259: // レジスタ
260: struct SPC spc {};
261:
1.1.1.3 root 262: // VM 種別
263: vmtype_t vmtype {};
1.1 root 264:
265: // SPC に入力されるクロック周期 [nsec]
1.1.1.6 root 266: int t_CLF {};
267:
268: // アクセスウェイト
269: uint32 read_wait {};
270: uint32 write_wait {};
271:
1.1.1.7 root 272: // 割り込み信号線の接続先デバイス
273: InterruptDevice *interrupt {};
274:
1.1.1.6 root 275: // 接続中のデバイス(イニシエータ含む)を ID 順に並べたリスト (モニタ用)
276: std::vector<SCSIDevice*> connected_devices {};
1.1 root 277:
278: // イベント
1.1.1.10! root 279: Event event { this };
! 280: Event event_tc { this };
! 281:
! 282: Monitor monitor { this };
1.1 root 283: };
284:
1.1.1.3 root 285: extern std::unique_ptr<SPCDevice> gSPC;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.