|
|
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: mainbus = GetMainbusDevice();
87:
88: gfpic = GetGFPICDevice(1);
89: gfpic->RegistIRQ(32, "GFTTY", this);
90:
91: scheduler->ConnectMessage(MessageID::HOSTCOM_RX, this,
92: ToMessageCallback(&GFTTYDevice::RxMessage));
93: return true;
94: }
95:
96: // 電源オン/リセット
97: void
98: GFTTYDevice::ResetHard(bool poweron)
99: {
100: rxq.clear();
101: intr_enable = false;
102: ChangeInterrupt();
103: }
104:
105: busdata
1.1.1.2 root 106: GFTTYDevice::ReadPort(uint32 offset)
1.1 root 107: {
108: busdata data;
109:
110: switch (offset) {
111: case BYTES_READY:
1.1.1.2 root 112: data = GetREADY();
113: putlog(2, "BYTES_READY -> $%08x", data.Data());
1.1 root 114: break;
115:
116: case VERSION:
1.1.1.2 root 117: data = GFTTYVersion;
1.1 root 118: putlog(2, "VERSION -> $%08x", data.Data());
119: break;
120:
121: default:
1.1.1.2 root 122: putlog(1, "Read $%08x.L", mpu->GetPaddr());
1.1 root 123: data.SetBusErr();
124: break;
125: }
126:
1.1.1.2 root 127: data |= BusData::Size4;
1.1 root 128: return data;
129: }
130:
131: busdata
1.1.1.2 root 132: GFTTYDevice::WritePort(uint32 offset, uint32 data)
1.1 root 133: {
134: busdata r;
135:
136: switch (offset) {
137: case PUT_CHAR:
138: putlog(2, "PUT_CHAR <- $%02x", data);
139: hostcom->Tx(data);
140: break;
141:
142: case COMMAND:
143: Command(data);
144: break;
145:
146: case DATA_PTR:
147: putlog(2, "DATA_PTR <- $%08x", data);
148: dma_ptr = data;
149: break;
150:
151: case DATA_LEN:
152: putlog(2, "DATA_LEN <- $%08x", data);
153: dma_len = data;
154: break;
155:
156: default:
1.1.1.2 root 157: putlog(1, "Write $%08x.L", mpu->GetPaddr());
1.1 root 158: r.SetBusErr();
159: break;
160: }
1.1.1.2 root 161:
162: r |= BusData::Size4;
1.1 root 163: return r;
164: }
165:
166: busdata
1.1.1.2 root 167: GFTTYDevice::PeekPort(uint32 offset)
168: {
169: switch (offset) {
170: case BYTES_READY:
171: return GetREADY();
172: case VERSION:
173: return GFTTYVersion;
174: default:
175: return BusData::BusErr;
176: }
177: }
178:
179: // 着信しているバイト数を返す。
180: uint32
181: GFTTYDevice::GetREADY() const
1.1 root 182: {
1.1.1.2 root 183: return rxq.size();
1.1 root 184: }
185:
186: void
187: GFTTYDevice::Command(uint32 cmd)
188: {
189: switch (cmd) {
190: case CMD_INT_DISABLE:
191: putlog(1, "CMD_INT_DISABLE");
192: intr_enable = false;
193: ChangeInterrupt();
194: break;
195:
196: case CMD_INT_ENABLE:
197: putlog(1, "CMD_INT_ENABLE");
198: intr_enable = true;
199: ChangeInterrupt();
200: break;
201:
202: case CMD_WRITE_BUFFER:
203: {
204: // ゲストからの書き込み
205: putlog(1, "CMD_WRITE_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
206: uint32 addr = dma_ptr;
207: uint32 end = addr + dma_len;
208: for (; addr < end; addr++) {
1.1.1.2 root 209: busdata data = mainbus->HVRead1(addr);
1.1 root 210: if (data.IsBusErr()) {
211: putlog(1, "WRITE_BUFFER: BusError at $%08x", addr);
212: break;
213: }
214: hostcom->Tx(data);
215: }
216: break;
217: }
218:
219: case CMD_READ_BUFFER:
220: {
221: // ゲストからの読み込み (ゲスト空間へ書き出し)
222: putlog(1, "CMD_READ_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
223: uint32 addr = dma_ptr;
224: uint32 len = std::min(dma_len, (uint32)rxq.size());
225: for (uint32 end = addr + len; addr < end; addr++) {
226: uint32 data = rxq.front();
227: rxq.pop_front();
1.1.1.2 root 228: busdata bd = mainbus->HVWrite1(addr, data);
1.1 root 229: if (bd.IsBusErr()) {
230: putlog(1, "READ_BUFFER: BusError at $%08x", addr);
231: break;
232: }
233: }
234: ChangeInterrupt();
235: break;
236: }
237:
238: default:
239: putlog(1, "Unknown command $%08x", cmd);
240: break;
241: }
242: }
243:
244: void
245: GFTTYDevice::ChangeInterrupt()
246: {
247: bool irq = (intr_enable && rxq.empty() == false);
248: gfpic->ChangeINT(this, irq);
249: }
250:
251: // ホストスレッドからの受信通知
252: // (HostCOM スレッドで呼ばれる)
253: void
254: GFTTYDevice::HostRxCallback()
255: {
256: scheduler->SendMessage(MessageID::HOSTCOM_RX);
257: }
258:
259: // ホストシリアルからの1バイト(以上)受信メッセージ
260: // (VM スレッドで呼ばれる)
261: void
262: GFTTYDevice::RxMessage(MessageID msgid, uint32 arg)
263: {
264: bool recv = false;
265:
266: for (;;) {
267: uint32 data = hostcom->Rx();
268: if ((int32)data < 0) {
269: break;
270: }
271: rxq.push_back(data);
272: recv = true;
273: }
274:
275: if (recv) {
276: ChangeInterrupt();
277: }
278: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.