2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
12 #define MODE_OUTPUT 0x00
13 #define MODE_INPUT 0x40
14 #define MODE_BIDIRECT 0x80
15 #define MODE_CONTROL 0xc0
19 for(int ch = 0; ch < 2; ch++) {
20 port[ch].wreg = 0xffffff00; // force output the first written data
21 port[ch].mode = MODE_INPUT;
27 port[ch].set_dir = false;
28 port[ch].set_mask = false;
30 port[ch].ready_signal = -1;
31 port[ch].input_empty = false;
32 port[ch].output_ready = false;
34 port[ch].enb_intr = false;
35 port[ch].req_intr = false;
36 port[ch].in_service = false;
43 AD0 is to C/~D, AD1 is to B/~A:
51 void Z80PIO::write_io8(uint32_t addr, uint32_t data)
53 int ch = (addr >> 1) & 1;
54 bool mode_changed = false;
61 if(port[ch].wreg != data) {
62 write_signals(&port[ch].outputs_data, data);
65 if(port[ch].output_ready) {
66 port[ch].output_ready = false;
69 port[ch].output_ready = true;
71 if(port[ch].mode == MODE_OUTPUT || port[ch].mode == MODE_BIDIRECT) {
72 if(!port[ch].hand_shake) {
73 // the peripheral reads the data and sets the strobe signal immediately
74 if(!(ch == 1 && port[0].mode == MODE_BIDIRECT)) {
75 write_signal(SIG_Z80PIO_STROBE_A + ch, 1, 1);
78 } else if(port[ch].mode == MODE_CONTROL) {
85 if(port[ch].set_dir) {
87 port[ch].set_dir = false;
88 } else if(port[ch].set_mask) {
90 port[ch].set_mask = false;
91 port[ch].enb_intr = port[ch].enb_intr_tmp;
93 } else if(!(data & 0x01)) {
94 port[ch].vector = data;
95 } else if((data & 0x0f) == 0x03) {
96 port[ch].enb_intr = ((data & 0x80) != 0);
97 port[ch].ctrl2 = data;
99 } else if((data & 0x0f) == 0x07) {
100 port[ch].enb_intr = ((data & 0x80) != 0);
101 port[ch].ctrl1 = data;
103 port[ch].set_mask = true;
104 // canel pending interrup ???
105 port[ch].req_intr = false;
106 // disable interrupt until the mask register is written
107 port[ch].enb_intr_tmp = port[ch].enb_intr;
108 port[ch].enb_intr = false;
111 } else if((data & 0x0f) == 0x0f) {
112 // port[].dir 0=output, 1=input
113 if((data & 0xc0) == MODE_OUTPUT) {
115 } else if((data & 0xc0) == MODE_INPUT || (data & 0xc0) == MODE_BIDIRECT) {
117 } else if((data & 0xc0) == MODE_CONTROL) {
118 port[ch].set_dir = true;
120 mode_changed = (port[ch].mode != (data & 0xc0));
121 port[ch].mode = data & 0xc0;
123 if(port[ch].mode == MODE_BIDIRECT) {
124 check_mode3_intr(ch);
127 port[ch].input_empty = false;
128 port[ch].output_ready = false;
135 uint32_t Z80PIO::read_io8(uint32_t addr)
137 int ch = (addr >> 1) & 1;
143 if(!port[ch].input_empty) {
144 port[ch].input_empty = true;
147 return (port[ch].rreg & port[ch].dir) | (port[ch].wreg & ~port[ch].dir);break;
150 // status (sharp z-80pio special function)
151 return port[0].mode | (port[1].mode >> 4);
156 void Z80PIO::write_signal(int id, uint32_t data, uint32_t mask)
158 // port[].dir 0=output, 1=input
162 case SIG_Z80PIO_PORT_A:
164 case SIG_Z80PIO_PORT_B:
165 port[ch].rreg = (port[ch].rreg & ~mask) | (data & mask);
166 if(port[ch].input_empty) {
167 port[ch].input_empty = false;
170 if(port[ch].mode == MODE_INPUT || port[ch].mode == MODE_BIDIRECT) {
171 if(!port[ch].hand_shake) {
172 // the peripheral sets the strobe signal immediately after it writes the data
173 if(ch == 0 && port[0].mode == MODE_BIDIRECT) {
174 write_signal(SIG_Z80PIO_STROBE_B, 1, 1);
175 } else if(!(ch == 1 && port[0].mode == MODE_BIDIRECT)) {
176 write_signal(SIG_Z80PIO_STROBE_A + ch, 1, 1);
179 } else if(port[ch].mode == MODE_CONTROL) {
180 check_mode3_intr(ch);
183 case SIG_Z80PIO_STROBE_A:
185 case SIG_Z80PIO_STROBE_B:
187 if(port[ch].output_ready) {
188 port[ch].output_ready = false;
191 port[ch].req_intr = true;
198 void Z80PIO::update_ready()
200 for(int ch = 0; ch < 2; ch++) {
202 if(ch == 1 && port[0].mode == MODE_BIDIRECT) {
203 next_signal = (port[0].input_empty == true);
205 if(port[ch].mode == MODE_OUTPUT || port[ch].mode == MODE_BIDIRECT) {
206 next_signal = (port[ch].output_ready == true);
207 } else if(port[ch].mode == MODE_INPUT) {
208 next_signal = (port[ch].input_empty == true);
211 if(port[ch].ready_signal != next_signal) {
212 write_signals(&port[ch].outputs_ready, (next_signal != 0) ? 0xffffffff : 0);
213 port[ch].ready_signal = next_signal;
218 void Z80PIO::check_mode3_intr(int ch)
220 // check mode3 interrupt status
221 uint8_t mask = ~port[ch].mask;
222 uint8_t val = (port[ch].rreg & port[ch].dir) | (port[ch].wreg & ~port[ch].dir);
225 if((port[ch].ctrl1 & 0x60) == 0x00 && val != mask) {
226 port[ch].req_intr = true;
227 } else if((port[ch].ctrl1 & 0x60) == 0x20 && val != 0) {
228 port[ch].req_intr = true;
229 } else if((port[ch].ctrl1 & 0x60) == 0x40 && val == 0) {
230 port[ch].req_intr = true;
231 } else if((port[ch].ctrl1 & 0x60) == 0x60 && val == mask) {
232 port[ch].req_intr = true;
234 port[ch].req_intr = false;
239 void Z80PIO::set_intr_iei(bool val)
247 #define set_intr_oei(val) { \
251 d_child->set_intr_iei(oei); \
256 void Z80PIO::update_intr()
261 if((next = iei) == true) {
262 for(int ch = 0; ch < 2; ch++) {
263 if(port[ch].in_service) {
272 if((next = iei) == true) {
274 for(int ch = 0; ch < 2; ch++) {
275 if(port[ch].in_service) {
278 if(port[ch].enb_intr && port[ch].req_intr) {
285 d_cpu->set_intr_line(next, true, intr_bit);
289 uint32_t Z80PIO::get_intr_ack()
292 for(int ch = 0; ch < 2; ch++) {
293 if(port[ch].in_service) {
294 // invalid interrupt status
297 if(port[ch].enb_intr && port[ch].req_intr) {
298 port[ch].req_intr = false;
299 port[ch].in_service = true;
301 return port[ch].vector;
305 return d_child->get_intr_ack();
310 void Z80PIO::notify_intr_reti()
313 for(int ch = 0; ch < 2; ch++) {
314 if(port[ch].in_service) {
315 port[ch].in_service = false;
321 d_child->notify_intr_reti();
325 #define STATE_VERSION 1
327 bool Z80PIO::process_state(FILEIO* state_fio, bool loading)
329 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
332 if(!state_fio->StateCheckInt32(this_device_id)) {
335 for(int i = 0; i < 2; i++) {
336 state_fio->StateValue(port[i].wreg);
337 state_fio->StateValue(port[i].rreg);
338 state_fio->StateValue(port[i].mode);
339 state_fio->StateValue(port[i].ctrl1);
340 state_fio->StateValue(port[i].ctrl2);
341 state_fio->StateValue(port[i].dir);
342 state_fio->StateValue(port[i].mask);
343 state_fio->StateValue(port[i].vector);
344 state_fio->StateValue(port[i].set_dir);
345 state_fio->StateValue(port[i].set_mask);
346 state_fio->StateValue(port[i].hand_shake);
347 state_fio->StateValue(port[i].ready_signal);
348 state_fio->StateValue(port[i].input_empty);
349 state_fio->StateValue(port[i].output_ready);
350 state_fio->StateValue(port[i].enb_intr);
351 state_fio->StateValue(port[i].enb_intr_tmp);
352 state_fio->StateValue(port[i].req_intr);
353 state_fio->StateValue(port[i].in_service);
355 state_fio->StateValue(iei);
356 state_fio->StateValue(oei);
357 state_fio->StateValue(intr_bit);