OSDN Git Service

[VM][COMMON_VM] Include IO:: class to common_vm.
[csp-qt/common_source_project-fm7.git] / source / src / vm / i8251.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.09.14 -
6
7         [ i8251 ]
8 */
9
10 #include "i8251.h"
11 #include "../fifo.h"
12
13 // max 256kbytes
14 #define BUFFER_SIZE     0x40000
15 // 100usec/byte
16 #define RECV_DELAY      100
17 #define SEND_DELAY      100
18
19 #define EVENT_RECV      0
20 #define EVENT_SEND      1
21
22 #define TXRDY           0x01
23 #define RXRDY           0x02
24 #define TXE             0x04
25 #define PE              0x08
26 #define OE              0x10
27 #define FE              0x20
28 #define SYNDET          0x40
29 #define DSR             0x80
30
31 #define MODE_CLEAR      0
32 #define MODE_SYNC       1
33 #define MODE_ASYNC      2
34 #define MODE_SYNC1      3
35 #define MODE_SYNC2      4
36
37 #define RECV_BREAK      -1
38
39 void I8251::initialize()
40 {
41         DEVICE::initialize();
42         recv_buffer = new FIFO(BUFFER_SIZE);
43         send_buffer = new FIFO(4);
44         status = TXRDY | TXE;
45 }
46
47 void I8251::release()
48 {
49         recv_buffer->release();
50         delete recv_buffer;
51         send_buffer->release();
52         delete send_buffer;
53 }
54
55 void I8251::reset()
56 {
57         mode = MODE_CLEAR;
58         recv = 0x00;    // XM8 version 1.10
59 //      recv = 0xff;
60         
61         // dont reset dsr
62         status &= DSR;
63         status |= TXRDY | TXE;
64         txen = rxen = loopback = false;
65         txen = rxen = true;
66         
67         recv_buffer->clear();
68         send_buffer->clear();
69         recv_id = send_id = -1;
70 }
71
72 void I8251::write_io8(uint32_t addr, uint32_t data)
73 {
74         if(addr & 1) {
75                 switch(mode) {
76                 case MODE_CLEAR:
77                         if(data & 3) {
78                                 mode = MODE_ASYNC;
79                         } else if(data & 0x80) {
80                                 mode = MODE_SYNC2;      // 1char
81                         } else {
82                                 mode = MODE_SYNC1;      // 2chars
83                         }
84                         break;
85                 case MODE_SYNC1:
86                         mode = MODE_SYNC2;
87                         break;
88                 case MODE_SYNC2:
89                         mode = MODE_SYNC;
90                         break;
91                 case MODE_ASYNC:
92                 case MODE_SYNC:
93                         if(data & 0x40) {
94                                 mode = MODE_CLEAR;
95                                 break;
96                         }
97                         if(data & 0x10) {
98                                 status &= ~(PE | OE | FE);
99                         }
100                         // dtr
101                         write_signals(&outputs_dtr, (data & 2) ? 0xffffffff : 0);
102                         // rst/sbrk
103                         write_signals(&outputs_rst, (data & 8) ? 0xffffffff : 0);
104                         // rxen
105                         rxen = ((data & 4) != 0);
106                         if(rxen && !recv_buffer->empty() && recv_id == -1) {
107                                 register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id);
108                         }
109                         // txen
110                         txen = ((data & 1) != 0);
111                         if(txen && !send_buffer->empty() && send_id == -1) {
112                                 register_event(this, EVENT_SEND, SEND_DELAY, false, &send_id);
113                         }
114                         // note: when txen=false, txrdy signal must be low
115                         break;
116                 }
117         } else {
118                 if(status & TXRDY) {
119                         send_buffer->write(data);
120                         // txrdy
121                         if(send_buffer->full()) {
122                                 status &= ~TXRDY;
123                                 write_signals(&outputs_txrdy, 0);
124                         }
125                         // txempty
126                         status &= ~TXE;
127                         write_signals(&outputs_txe, 0);
128                         // register event
129                         if(txen && send_id == -1) {
130                                 register_event(this, EVENT_SEND, SEND_DELAY, false, &send_id);
131                         }
132                 }
133         }
134 }
135
136 uint32_t I8251::read_io8(uint32_t addr)
137 {
138         if(addr & 1) {
139                 // XM8 version 1.10
140                 if(!txen) {
141                         return status & ~(TXRDY | TXE);
142                 }
143                 return status;
144         } else {
145                 if(status & RXRDY) {
146                         status &= ~RXRDY;
147                         write_signals(&outputs_rxrdy, 0);
148                 }
149                 return recv;
150         }
151 }
152
153 void I8251::write_signal(int id, uint32_t data, uint32_t mask)
154 {
155         if(id == SIG_I8251_RECV) {
156                 recv_buffer->write(data & mask);
157                 // register event
158                 if(rxen && !recv_buffer->empty() && recv_id == -1) {
159                         register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id);
160                 }
161         } else if(id == SIG_I8251_BREAK) {
162                 if(data & mask) {
163                         recv_buffer->write(RECV_BREAK);
164                         // register event
165                         if(rxen && !recv_buffer->empty() && recv_id == -1) {
166                                 register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id);
167                         }
168                 }
169         } else if(id == SIG_I8251_DSR) {
170                 if(data & mask) {
171                         status |= DSR;
172                 } else {
173                         status &= ~DSR;
174                 }
175         } else if(id == SIG_I8251_CLEAR) {
176                 recv_buffer->clear();
177         } else if(id == SIG_I8251_LOOPBACK) {
178                 loopback = ((data & mask) != 0);
179         }
180 }
181
182 void I8251::event_callback(int event_id, int err)
183 {
184         if(event_id == EVENT_RECV) {
185                 if(rxen && !(status & RXRDY)) {
186                         if(!recv_buffer->empty()) {
187                                 int val = recv_buffer->read();
188                                 if(val == RECV_BREAK) {
189                                         // break
190                                         status |= SYNDET;
191                                         write_signals(&outputs_syndet, 0xffffffff);
192                                 } else {
193                                         recv = (uint8_t)val;
194                                         status |= RXRDY;
195                                         write_signals(&outputs_rxrdy, 0xffffffff);
196                                 }
197                         }
198                 }
199                 // if data is still left in buffer, register event for next data
200                 if(rxen && !recv_buffer->empty()) {
201                         register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id);
202                 } else {
203                         recv_id = -1;
204                 }
205         } else if(event_id == EVENT_SEND) {
206                 if(txen && !send_buffer->empty()) {
207                         uint8_t send = send_buffer->read();
208                         if(loopback) {
209                                 // send to this device
210                                 write_signal(SIG_I8251_RECV, send, 0xff);
211                         } else {
212                                 // send to external devices
213                                 write_signals(&outputs_out, send);
214                         }
215                         // txrdy
216                         status |= TXRDY;
217                         write_signals(&outputs_txrdy, 0xffffffff);
218                         // txe
219                         if(send_buffer->empty()) {
220                                 status |= TXE;
221                                 write_signals(&outputs_txe, 0xffffffff);
222                         }
223                 }
224                 // if data is still left in buffer, register event for next data
225                 if(txen && !send_buffer->empty()) {
226                         register_event(this, EVENT_SEND, SEND_DELAY, false, &send_id);
227                 } else {
228                         send_id = -1;
229                 }
230         }
231 }
232
233 #define STATE_VERSION   1
234
235 bool I8251::process_state(FILEIO* state_fio, bool loading)
236 {
237         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
238                 return false;
239         }
240         if(!state_fio->StateCheckInt32(this_device_id)) {
241                 return false;
242         }
243         state_fio->StateValue(recv);
244         state_fio->StateValue(status);
245         state_fio->StateValue(mode);
246         state_fio->StateValue(txen);
247         state_fio->StateValue(rxen);
248         state_fio->StateValue(loopback);
249         if(!recv_buffer->process_state((void *)state_fio, loading)) {
250                 return false;
251         }
252         if(!send_buffer->process_state((void *)state_fio, loading)) {
253                 return false;
254         }
255         state_fio->StateValue(recv_id);
256         state_fio->StateValue(send_id);
257         return true;
258 }