|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2024 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // Goldfish TTY
9: //
10:
11: // レジスタ仕様は次の通り。
12: // +$00.L PUT_CHAR -W: 1バイト出力
13: // +$04.L BYTES_READY R-: 受信キューにあるバイト数を取得
14: // +$08.L COMMAND -W: コマンド
15: // +$0c.L -
16: // +$10.L DATA_PTR -W: DMA 開始アドレス
17: // +$14.L DATA_LEN -W: DMA データ長
18: // +$18.L DATA_PTR_HIGH W: DMA 開始アドレスの上位 32 ビット
19: // +$1c.L -
20: // +$20.L VERSION R-: このデバイスのバージョン ($1)
21: //
22: // コマンドは
23: // $00 INT_DISABLE
24: // $01 INT_ENABLE
25: // $02 WRITE_BUFFER
26: // $03 READ_BUFFER
27: //
28: // 受信キューにデータがあれば割り込みを上げる。
29: // 受信キューが空になると割り込みを下げる。
30: //
31: // WRITE_BUFFER, READ_BUFFER はたぶんバスマスタ的転送。
32: // 読み出し時 (READ_BUFFER) は、DATA_PTR で指定したアドレスにたぶん最大
33: // DATA_LEN バイトを GFTTY デバイスが書き込む。
34: // 書き込み時 (WRITE_BUFFER) は、DATA_PTR で指定したアドレスから DATA_LEN
35: // バイトを GFTTY デバイスが読み込む。
36: //
37: // nono では DATA_PTR_HIGH は実装しない。
38:
39: #include "goldfish_tty.h"
40: #include "goldfish_pic.h"
41: #include "hostcom.h"
42: #include "mainbus.h"
1.1.1.2 ! root 43: #include "mpu.h"
1.1 root 44: #include "scheduler.h"
45:
46: // コンストラクタ
47: GFTTYDevice::GFTTYDevice()
48: : inherited(OBJ_GFTTY)
49: {
50: }
51:
52: // デストラクタ
53: GFTTYDevice::~GFTTYDevice()
54: {
55: if ((bool)hostcom) {
56: hostcom->SetRxCallback(NULL);
57: }
58: }
59:
60: bool
61: GFTTYDevice::Create()
62: {
63: // 対応するホストドライバを作成
64: hostcom.reset(new HostCOMDevice(this, "HostCOM"));
65: if ((bool)hostcom == false) {
66: return false;
67: }
68: hostcom->SetRxCallback(ToDeviceCallback(&GFTTYDevice::HostRxCallback));
69:
70: return true;
71: }
72:
73: void
74: GFTTYDevice::SetLogLevel(int loglevel_)
75: {
76: inherited::SetLogLevel(loglevel_);
77:
78: assert((bool)hostcom);
79: hostcom->SetLogLevel(loglevel_);
80: }
81:
82: // 初期化
83: bool
84: GFTTYDevice::Init()
85: {
86: if (inherited::Init() == false) {
87: return false;
88: }
89:
90: mainbus = GetMainbusDevice();
91:
92: gfpic = GetGFPICDevice(1);
93: gfpic->RegistIRQ(32, "GFTTY", this);
94:
95: scheduler->ConnectMessage(MessageID::HOSTCOM_RX, this,
96: ToMessageCallback(&GFTTYDevice::RxMessage));
97: return true;
98: }
99:
100: // 電源オン/リセット
101: void
102: GFTTYDevice::ResetHard(bool poweron)
103: {
104: rxq.clear();
105: intr_enable = false;
106: ChangeInterrupt();
107: }
108:
109: busdata
1.1.1.2 ! root 110: GFTTYDevice::ReadPort(uint32 offset)
1.1 root 111: {
112: busdata data;
113:
114: switch (offset) {
115: case BYTES_READY:
1.1.1.2 ! root 116: data = GetREADY();
! 117: putlog(2, "BYTES_READY -> $%08x", data.Data());
1.1 root 118: break;
119:
120: case VERSION:
1.1.1.2 ! root 121: data = GFTTYVersion;
1.1 root 122: putlog(2, "VERSION -> $%08x", data.Data());
123: break;
124:
125: default:
1.1.1.2 ! root 126: putlog(1, "Read $%08x.L", mpu->GetPaddr());
1.1 root 127: data.SetBusErr();
128: break;
129: }
130:
1.1.1.2 ! root 131: data |= BusData::Size4;
1.1 root 132: return data;
133: }
134:
135: busdata
1.1.1.2 ! root 136: GFTTYDevice::WritePort(uint32 offset, uint32 data)
1.1 root 137: {
138: busdata r;
139:
140: switch (offset) {
141: case PUT_CHAR:
142: putlog(2, "PUT_CHAR <- $%02x", data);
143: hostcom->Tx(data);
144: break;
145:
146: case COMMAND:
147: Command(data);
148: break;
149:
150: case DATA_PTR:
151: putlog(2, "DATA_PTR <- $%08x", data);
152: dma_ptr = data;
153: break;
154:
155: case DATA_LEN:
156: putlog(2, "DATA_LEN <- $%08x", data);
157: dma_len = data;
158: break;
159:
160: default:
1.1.1.2 ! root 161: putlog(1, "Write $%08x.L", mpu->GetPaddr());
1.1 root 162: r.SetBusErr();
163: break;
164: }
1.1.1.2 ! root 165:
! 166: r |= BusData::Size4;
1.1 root 167: return r;
168: }
169:
170: busdata
1.1.1.2 ! root 171: GFTTYDevice::PeekPort(uint32 offset)
! 172: {
! 173: switch (offset) {
! 174: case BYTES_READY:
! 175: return GetREADY();
! 176: case VERSION:
! 177: return GFTTYVersion;
! 178: default:
! 179: return BusData::BusErr;
! 180: }
! 181: }
! 182:
! 183: // 着信しているバイト数を返す。
! 184: uint32
! 185: GFTTYDevice::GetREADY() const
1.1 root 186: {
1.1.1.2 ! root 187: return rxq.size();
1.1 root 188: }
189:
190: void
191: GFTTYDevice::Command(uint32 cmd)
192: {
193: switch (cmd) {
194: case CMD_INT_DISABLE:
195: putlog(1, "CMD_INT_DISABLE");
196: intr_enable = false;
197: ChangeInterrupt();
198: break;
199:
200: case CMD_INT_ENABLE:
201: putlog(1, "CMD_INT_ENABLE");
202: intr_enable = true;
203: ChangeInterrupt();
204: break;
205:
206: case CMD_WRITE_BUFFER:
207: {
208: // ゲストからの書き込み
209: putlog(1, "CMD_WRITE_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
210: uint32 addr = dma_ptr;
211: uint32 end = addr + dma_len;
212: for (; addr < end; addr++) {
1.1.1.2 ! root 213: busdata data = mainbus->HVRead1(addr);
1.1 root 214: if (data.IsBusErr()) {
215: putlog(1, "WRITE_BUFFER: BusError at $%08x", addr);
216: break;
217: }
218: hostcom->Tx(data);
219: }
220: break;
221: }
222:
223: case CMD_READ_BUFFER:
224: {
225: // ゲストからの読み込み (ゲスト空間へ書き出し)
226: putlog(1, "CMD_READ_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
227: uint32 addr = dma_ptr;
228: uint32 len = std::min(dma_len, (uint32)rxq.size());
229: for (uint32 end = addr + len; addr < end; addr++) {
230: uint32 data = rxq.front();
231: rxq.pop_front();
1.1.1.2 ! root 232: busdata bd = mainbus->HVWrite1(addr, data);
1.1 root 233: if (bd.IsBusErr()) {
234: putlog(1, "READ_BUFFER: BusError at $%08x", addr);
235: break;
236: }
237: }
238: ChangeInterrupt();
239: break;
240: }
241:
242: default:
243: putlog(1, "Unknown command $%08x", cmd);
244: break;
245: }
246: }
247:
248: void
249: GFTTYDevice::ChangeInterrupt()
250: {
251: bool irq = (intr_enable && rxq.empty() == false);
252: gfpic->ChangeINT(this, irq);
253: }
254:
255: // ホストスレッドからの受信通知
256: // (HostCOM スレッドで呼ばれる)
257: void
258: GFTTYDevice::HostRxCallback()
259: {
260: scheduler->SendMessage(MessageID::HOSTCOM_RX);
261: }
262:
263: // ホストシリアルからの1バイト(以上)受信メッセージ
264: // (VM スレッドで呼ばれる)
265: void
266: GFTTYDevice::RxMessage(MessageID msgid, uint32 arg)
267: {
268: bool recv = false;
269:
270: for (;;) {
271: uint32 data = hostcom->Rx();
272: if ((int32)data < 0) {
273: break;
274: }
275: rxq.push_back(data);
276: recv = true;
277: }
278:
279: if (recv) {
280: ChangeInterrupt();
281: }
282: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.