|
|
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"
43: #include "scheduler.h"
44:
45: // コンストラクタ
46: GFTTYDevice::GFTTYDevice()
47: : inherited(OBJ_GFTTY)
48: {
49: }
50:
51: // デストラクタ
52: GFTTYDevice::~GFTTYDevice()
53: {
54: if ((bool)hostcom) {
55: hostcom->SetRxCallback(NULL);
56: }
57: }
58:
59: bool
60: GFTTYDevice::Create()
61: {
62: // 対応するホストドライバを作成
63: hostcom.reset(new HostCOMDevice(this, "HostCOM"));
64: if ((bool)hostcom == false) {
65: return false;
66: }
67: hostcom->SetRxCallback(ToDeviceCallback(&GFTTYDevice::HostRxCallback));
68:
69: return true;
70: }
71:
72: void
73: GFTTYDevice::SetLogLevel(int loglevel_)
74: {
75: inherited::SetLogLevel(loglevel_);
76:
77: assert((bool)hostcom);
78: hostcom->SetLogLevel(loglevel_);
79: }
80:
81: // 初期化
82: bool
83: GFTTYDevice::Init()
84: {
85: if (inherited::Init() == false) {
86: return false;
87: }
88:
89: mainbus = GetMainbusDevice();
90:
91: gfpic = GetGFPICDevice(1);
92: gfpic->RegistIRQ(32, "GFTTY", this);
93:
94: scheduler->ConnectMessage(MessageID::HOSTCOM_RX, this,
95: ToMessageCallback(&GFTTYDevice::RxMessage));
96: return true;
97: }
98:
99: // 電源オン/リセット
100: void
101: GFTTYDevice::ResetHard(bool poweron)
102: {
103: rxq.clear();
104: intr_enable = false;
105: ChangeInterrupt();
106: }
107:
108: busdata
109: GFTTYDevice::Read32(uint32 addr)
110: {
111: uint32 offset = addr & 0xfff;
112: busdata data;
113:
114: switch (offset) {
115: case BYTES_READY:
116: data = rxq.size();
117: putlog(2, "BYTES_READ -> $%08x", data.Data());
118: break;
119:
120: case VERSION:
121: data = 1;
122: putlog(2, "VERSION -> $%08x", data.Data());
123: break;
124:
125: default:
126: putlog(1, "Read $%08x.L", addr);
127: data.SetBusErr();
128: break;
129: }
130:
131: return data;
132: }
133:
134: busdata
135: GFTTYDevice::Write32(uint32 addr, uint32 data)
136: {
137: uint32 offset = addr & 0xfff;
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:
161: putlog(1, "Write $%08x.L", addr);
162: r.SetBusErr();
163: break;
164: }
165: return r;
166: }
167:
168: busdata
169: GFTTYDevice::Peek8(uint32 addr)
170: {
171: return busdata::BusErr;
172: }
173:
174: void
175: GFTTYDevice::Command(uint32 cmd)
176: {
177: switch (cmd) {
178: case CMD_INT_DISABLE:
179: putlog(1, "CMD_INT_DISABLE");
180: intr_enable = false;
181: ChangeInterrupt();
182: break;
183:
184: case CMD_INT_ENABLE:
185: putlog(1, "CMD_INT_ENABLE");
186: intr_enable = true;
187: ChangeInterrupt();
188: break;
189:
190: case CMD_WRITE_BUFFER:
191: {
192: // ゲストからの書き込み
193: putlog(1, "CMD_WRITE_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
194: uint32 addr = dma_ptr;
195: uint32 end = addr + dma_len;
196: for (; addr < end; addr++) {
197: busdata data = mainbus->HVRead8(addr);
198: if (data.IsBusErr()) {
199: putlog(1, "WRITE_BUFFER: BusError at $%08x", addr);
200: break;
201: }
202: hostcom->Tx(data);
203: }
204: break;
205: }
206:
207: case CMD_READ_BUFFER:
208: {
209: // ゲストからの読み込み (ゲスト空間へ書き出し)
210: putlog(1, "CMD_READ_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
211: uint32 addr = dma_ptr;
212: uint32 len = std::min(dma_len, (uint32)rxq.size());
213: for (uint32 end = addr + len; addr < end; addr++) {
214: uint32 data = rxq.front();
215: rxq.pop_front();
216: busdata bd = mainbus->HVWrite8(addr, data);
217: if (bd.IsBusErr()) {
218: putlog(1, "READ_BUFFER: BusError at $%08x", addr);
219: break;
220: }
221: }
222: ChangeInterrupt();
223: break;
224: }
225:
226: default:
227: putlog(1, "Unknown command $%08x", cmd);
228: break;
229: }
230: }
231:
232: void
233: GFTTYDevice::ChangeInterrupt()
234: {
235: bool irq = (intr_enable && rxq.empty() == false);
236: gfpic->ChangeINT(this, irq);
237: }
238:
239: // ホストスレッドからの受信通知
240: // (HostCOM スレッドで呼ばれる)
241: void
242: GFTTYDevice::HostRxCallback()
243: {
244: scheduler->SendMessage(MessageID::HOSTCOM_RX);
245: }
246:
247: // ホストシリアルからの1バイト(以上)受信メッセージ
248: // (VM スレッドで呼ばれる)
249: void
250: GFTTYDevice::RxMessage(MessageID msgid, uint32 arg)
251: {
252: bool recv = false;
253:
254: for (;;) {
255: uint32 data = hostcom->Rx();
256: if ((int32)data < 0) {
257: break;
258: }
259: rxq.push_back(data);
260: recv = true;
261: }
262:
263: if (recv) {
264: ChangeInterrupt();
265: }
266: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.