2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
14 #define BUFFER_SIZE 0x40000
16 #define RECV_DELAY 100
17 #define SEND_DELAY 100
39 void I8251::initialize()
41 recv_buffer = new FIFO(BUFFER_SIZE);
42 send_buffer = new FIFO(4);
48 recv_buffer->release();
50 send_buffer->release();
60 status |= TXRDY | TXE;
61 txen = rxen = loopback = false;
65 recv_id = send_id = -1;
68 void I8251::write_io8(uint32 addr, uint32 data)
75 } else if(data & 0x80) {
76 mode = MODE_SYNC2; // 1char
78 mode = MODE_SYNC1; // 2chars
94 status &= ~(PE | OE | FE);
97 write_signals(&outputs_dtr, (data & 2) ? 0xffffffff : 0);
99 write_signals(&outputs_rst, (data & 8) ? 0xffffffff : 0);
101 rxen = ((data & 4) != 0);
102 if(rxen && !recv_buffer->empty() && recv_id == -1) {
103 register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id);
106 txen = ((data & 1) != 0);
107 if(txen && !send_buffer->empty() && send_id == -1) {
108 register_event(this, EVENT_SEND, SEND_DELAY, false, &send_id);
110 // note: when txen=false, txrdy signal must be low
115 send_buffer->write(data);
117 if(send_buffer->full()) {
119 write_signals(&outputs_txrdy, 0);
123 write_signals(&outputs_txe, 0);
125 if(txen && send_id == -1) {
126 register_event(this, EVENT_SEND, SEND_DELAY, false, &send_id);
132 uint32 I8251::read_io8(uint32 addr)
139 write_signals(&outputs_rxrdy, 0);
145 void I8251::write_signal(int id, uint32 data, uint32 mask)
147 if(id == SIG_I8251_RECV) {
148 recv_buffer->write(data & mask);
150 if(rxen && !recv_buffer->empty() && recv_id == -1) {
151 register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id);
153 } else if(id == SIG_I8251_BREAK) {
155 recv_buffer->write(RECV_BREAK);
157 if(rxen && !recv_buffer->empty() && recv_id == -1) {
158 register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id);
161 } else if(id == SIG_I8251_DSR) {
167 } else if(id == SIG_I8251_CLEAR) {
168 recv_buffer->clear();
169 } else if(id == SIG_I8251_LOOPBACK) {
170 loopback = ((data & mask) != 0);
174 void I8251::event_callback(int event_id, int err)
176 if(event_id == EVENT_RECV) {
177 if(rxen && !(status & RXRDY)) {
178 if(!recv_buffer->empty()) {
179 int val = recv_buffer->read();
180 if(val == RECV_BREAK) {
183 write_signals(&outputs_syndet, 0xffffffff);
187 write_signals(&outputs_rxrdy, 0xffffffff);
191 // if data is still left in buffer, register event for next data
192 if(rxen && !recv_buffer->empty()) {
193 register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id);
197 } else if(event_id == EVENT_SEND) {
198 if(txen && !send_buffer->empty()) {
199 uint8 send = send_buffer->read();
201 // send to this device
202 write_signal(SIG_I8251_RECV, send, 0xff);
204 // send to external devices
205 write_signals(&outputs_out, send);
209 write_signals(&outputs_txrdy, 0xffffffff);
211 if(send_buffer->empty()) {
213 write_signals(&outputs_txe, 0xffffffff);
216 // if data is still left in buffer, register event for next data
217 if(txen && !send_buffer->empty()) {
218 register_event(this, EVENT_SEND, SEND_DELAY, false, &send_id);
225 #define STATE_VERSION 1
227 void I8251::save_state(FILEIO* state_fio)
229 state_fio->FputUint32(STATE_VERSION);
230 state_fio->FputInt32(this_device_id);
232 state_fio->FputUint8(recv);
233 state_fio->FputUint8(status);
234 state_fio->FputUint8(mode);
235 state_fio->FputBool(txen);
236 state_fio->FputBool(rxen);
237 state_fio->FputBool(loopback);
238 recv_buffer->save_state((void *)state_fio);
239 send_buffer->save_state((void *)state_fio);
240 state_fio->FputInt32(recv_id);
241 state_fio->FputInt32(send_id);
244 bool I8251::load_state(FILEIO* state_fio)
246 if(state_fio->FgetUint32() != STATE_VERSION) {
249 if(state_fio->FgetInt32() != this_device_id) {
252 recv = state_fio->FgetUint8();
253 status = state_fio->FgetUint8();
254 mode = state_fio->FgetUint8();
255 txen = state_fio->FgetBool();
256 rxen = state_fio->FgetBool();
257 loopback = state_fio->FgetBool();
258 if(!recv_buffer->load_state((void *)state_fio)) {
261 if(!send_buffer->load_state((void *)state_fio)) {
264 recv_id = state_fio->FgetInt32();
265 send_id = state_fio->FgetInt32();