|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.7 root 7: //
1.1 root 8: // SCSI バス
1.1.1.7 root 9: //
1.1 root 10:
1.1.1.9 root 11: #pragma once
12:
13: #include "scsi.h"
1.1.1.11 root 14: #include <array>
1.1.1.9 root 15:
16: class SCSIDevice;
17: class SCSIDisk;
1.1.1.11 root 18: class SCSIDomain;
1.1.1.9 root 19: class SCSIHostDevice;
20: class SCSITarget;
1.1 root 21:
22: //
23: // SCSI バス
24: //
25: class SCSIBus : public Device
26: {
1.1.1.6 root 27: using inherited = Device;
1.1.1.9 root 28:
29: public:
30: // (1<<id) が1つだけ立ててあるビットマップから ID を返す。
31: // ビットが立っていなければ -1 を返す? 複数立ってたら?
32: static inline int DecodeID(uint32 mask)
33: {
34: mask &= 0xff;
35: if (mask == 0)
36: return -1;
37: return 31 - __builtin_clz(mask);
38: }
39:
1.1 root 40: public:
1.1.1.11 root 41: explicit SCSIBus(SCSIDomain *);
1.1.1.8 root 42: ~SCSIBus() override;
1.1 root 43:
1.1.1.9 root 44: bool Init() override;
1.1.1.7 root 45: void ResetHard(bool poweron) override;
1.1.1.3 root 46:
1.1.1.11 root 47: SCSIDomain *GetDomain() const noexcept { return domain; }
48:
49: // デバイス情報を更新する。
50: void Refresh();
1.1 root 51:
52: // 信号線の操作
53: bool GetRST() const { return rst; }
54: void AssertRST();
55: void NegateRST();
56: bool GetREQ() const { return req; }
57: void AssertREQ();
58: void NegateREQ();
59: bool GetACK() const { return ack; }
60: void AssertACK();
61: void NegateACK();
62: bool GetATN() const { return atn; }
63: void AssertATN();
64: void NegateATN();
65: uint8 GetSEL() const { return sel; }
66: void AssertSEL(uint id);
67: void NegateSEL(uint id);
68: uint8 GetBSY() const { return bsy; }
69: void AssertBSY(uint id);
70: void NegateBSY(uint id);
71: bool GetMSG() const { return (xfer & SCSI::MSG); }
72: bool GetCD() const { return (xfer & SCSI::CD); }
73: bool GetIO() const { return (xfer & SCSI::IO); }
74:
75: // MSG,CD,IO で示されるビットを val で指定した状態に変更する。
76: void SetXfer(uint8 val);
77:
78: // 現在の情報転送フェーズ(の信号線の状態) を返す。
79: // 現在のフェーズが Transfer の時のみ戻り値の内容は有効。
80: SCSI::XferPhase GetXfer() const { return (SCSI::XferPhase)xfer; }
81:
82: uint8 GetData() const { return data; }
83: void SetData(uint8 val) { data = val; }
84:
85: // 現在のフェーズを返す
86: SCSI::Phase GetPhase() const { return phase; }
87: // フェーズを変更する
88: void SetPhase(SCSI::Phase val) { phase = val; }
89: // 現在のフェーズ名を返す
90: const char *GetPhaseName() const { return SCSI::GetPhaseName(phase); }
91:
92: // 現在選択中のターゲットを返す、なければ NULL を返す。(モニタ用)
1.1.1.11 root 93: const SCSIDevice *GetSelectedTarget() const {
94: if (__predict_true(0 <= target_id && target_id < 8)) {
95: return device[target_id];
1.1 root 96: }
97: return NULL;
98: }
99:
1.1.1.3 root 100: // 次の REQ アサートの前に指定のウェイトを入れる
101: // (シークタイムなどを簡易的に再現するため)。
102: // ウェイトは一度適用されると 0 に戻る。
1.1.1.13! root 103: void SetOneshotReqWait(uint64 tsec) { req_wait += tsec; }
1.1.1.3 root 104:
1.1 root 105: private:
1.1.1.9 root 106: void BusFree(uint id);
1.1.1.12 root 107: void SelectionStart(Event *);
108: void Selected(Event *);
109: void SelectionAck(Event *);
110: void StartTransfer(Event *);
111: void TransferReq(Event *);
1.1 root 112:
113: // 現在のフェーズ
114: SCSI::Phase phase {};
115:
116: // SEL, BSY は同時に複数が重畳出来るので、アサートしたデバイスがそれぞれ
117: // 自身の ID を立てる。ネゲートは 0 かどうかで判断する。
118: // 現在の実装では実際には同時に立つことはないけど。
119: bool rst {};
120: bool req {};
121: bool ack {};
122: bool atn {};
123: uint8 sel {};
124: uint8 bsy {};
125: uint8 xfer {}; // MSG,CD,IO
126: uint8 data {};
127: // bool parity; 未実装
128:
129: // 前回 ACK を立てた時刻。
130: // 転送速度をここで律速させている。
1.1.1.3 root 131: uint64 last_req_time {};
132:
1.1.1.13! root 133: // 次の REQ アサートに入れるウェイト [tsec]
1.1.1.3 root 134: uint64 req_wait {};
1.1 root 135:
136: // 実際のバスではそんなことはないが、ここではバスがイニシエータと
137: // ターゲットの ID を把握している。どちらも非選択状態なら -1。
138: int init_id {};
139: int target_id {};
140:
1.1.1.11 root 141: // SCSI 管理
142: SCSIDomain *domain {};
1.1.1.9 root 143:
1.1.1.11 root 144: // 接続されているデバイス (イニシエータも含む) へのポインタ。
145: std::array<SCSIDevice *, 8> device {};
1.1.1.9 root 146:
1.1 root 147: // イベント
1.1.1.12 root 148: Event *event {};
1.1.1.9 root 149: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.