-
Notifications
You must be signed in to change notification settings - Fork 0
/
io_cycle.cpp
112 lines (99 loc) · 3.25 KB
/
io_cycle.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "cycle.h"
#if !defined(NO_EXCEPTIONS)
#include <stdexcept>
#endif
using namespace llz80emu;
/* I/O read */
z80_io_read_cycle::z80_io_read_cycle(z80_pins_t& pins) : z80_read_cycle(pins, Z80_IO_READ_CYCLE) {
}
bool z80_io_read_cycle::clock(bool clk) {
z80_cycle::clock(clk);
int t_half = (_t << 1) | !clk; // T half-cycle
switch (t_half) {
case 0: // T1 high
_pins = Z80_PINS_NOMINAL; // reset pins to nominal state
_pins.state =
(_pins.state & ~Z80_A_ALL) // clear all address lines
| ((z80_pinbits_t)_addr << Z80_PIN_A_BASE); // set address lines to the address we want to read from (NOTE: we can actually put a 16-bit address in here)
break;
case 1: // T1 low
break; // nothing to do here
case 2: // T2 high
_pins.state &= ~(Z80_IORQ | Z80_RD); // start I/O read
break;
case 3: // T2 low
break; // nothing to do here (WAIT and Dx pin sampling are to be done at the start of T3 high)
case 4: // TW high (implicit wait state)
break;
case 5: // TW low (implicit wait state)
break;
case 6: // T3 high
_wait = !(_pins.state & Z80_WAIT); // sample WAIT pin (true = WAIT state activated)
if (_wait) _t--; // stay in T2
sample_busreq();
break;
case 7: // T3 low
*_val_out = (uint8_t)((_pins.state & Z80_D_ALL) >> Z80_PIN_D_BASE); // sample Dx pins
_pins.state |= Z80_IORQ | Z80_RD; // stop I/O read
if (!_bus_release) return true;
break;
default:
if (!handle_bus_release(clk))
#if defined(NO_EXCEPTIONS)
abort();
#else
throw std::runtime_error("Invalid T cycle - no transition has occurred from I/O read cycle?");
#endif
else if (!clk && !_bus_release) return true;
break;
}
return false;
}
z80_io_write_cycle::z80_io_write_cycle(z80_pins_t& pins) : z80_write_cycle(pins, Z80_IO_WRITE_CYCLE) {
}
bool z80_io_write_cycle::clock(bool clk) {
z80_cycle::clock(clk);
int t_half = (_t << 1) | !clk; // T half-cycle
switch (t_half) {
case 0: // T1 high
_pins = Z80_PINS_NOMINAL; // reset pins to nominal state
_pins.state =
(_pins.state & ~Z80_A_ALL) // clear all address lines
| ((z80_pinbits_t)_addr << Z80_PIN_A_BASE); // set address lines to the address we want to read from (NOTE: we can actually put a 16-bit address in here)
break;
case 1: // T1 low
_pins.dir |= Z80_D_ALL; // start driving data lines
_pins.state =
(_pins.state & ~Z80_D_ALL) // clear all data pins
| ((z80_pinbits_t)_val << Z80_PIN_D_BASE); // set data pins to the value we want to write
break;
case 2: // T2 high
_pins.state &= ~(Z80_IORQ | Z80_WR); // start I/O write
break;
case 3: // T2 low
break; // nothing to do here (WAIT and Dx pin sampling are to be done at the start of T3 high)
case 4: // TW high (implicit wait state)
break;
case 5: // TW low (implicit wait state)
break;
case 6: // T3 high
_wait = !(_pins.state & Z80_WAIT); // sample WAIT pin (true = WAIT state activated)
if (_wait) _t--; // stay in T2
sample_busreq();
break;
case 7: // T3 low
_pins.state |= Z80_IORQ | Z80_WR; // stop I/O write
if (!_bus_release) return true;
break;
default:
if (!handle_bus_release(clk))
#if defined(NO_EXCEPTIONS)
abort();
#else
throw std::runtime_error("Invalid T cycle - no transition has occurred from I/O write cycle?");
#endif
else if (!clk && !_bus_release) return true;
break;
}
return false;
}