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