2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
19 #define STA_STB_B 0x20
20 #define STA_INTE_B 0x20
21 #define STA_INTR_T 0x40
24 #define CMD_INTE_A 0x10
25 #define CMD_INTE_B 0x20
28 #define PIO_MODE_3 ((cmdreg & 0xc) == 4)
29 #define PIO_MODE_4 ((cmdreg & 0xc) == 8)
31 void I8155::initialize()
35 count = countreg = 0x3fff;
38 now_count = stop_tc = false;
42 memset(ram, 0, sizeof(ram));
48 for(int i = 0; i < 3; i++) {
57 // stop count but don't reset timer
61 void I8155::write_data8(uint32_t addr, uint32_t data)
63 ram[addr & 0xff] = data;
66 uint32_t I8155::read_data8(uint32_t addr)
68 return ram[addr & 0xff];
71 void I8155::write_io8(uint32_t addr, uint32_t data)
75 pio[0].rmask = (data & 1) ? 0 : 0xff;
76 pio[1].rmask = (data & 2) ? 0 : 0xff;
77 pio[2].rmask = (data & 0xc) ? 0 : 0xff;
78 statreg &= ~(STA_INTE_A | STA_INTE_B);
79 if(data & CMD_INTE_A) {
80 statreg |= STA_INTE_A;
82 if(data & CMD_INTE_B) {
83 statreg |= STA_INTE_B;
107 data = (data & ~7) | (pio[2].wreg & 7);
110 set_pio(2, data & 0x3f);
114 countreg = (countreg & 0xff00) | data;
117 countreg = (countreg & 0xff) | (data << 8);
122 uint32_t I8155::read_io8(uint32_t addr)
126 if(statreg & STA_INTR_T) {
127 statreg &= ~STA_INTR_T;
128 return statreg | STA_INTR_T;
132 if(PIO_MODE_3 || PIO_MODE_4) {
133 statreg &= ~(STA_INTR_A | STA_BF_A);
134 set_pio(2, pio[2].wreg & ~(STA_INTR_A | STA_BF_A));
136 return (pio[0].rreg & pio[0].rmask) | (pio[0].wreg & ~pio[0].rmask);
139 statreg &= ~(STA_INTR_B | STA_BF_B);
140 set_pio(2, pio[2].wreg & ~(STA_INTR_B | STA_BF_B));
142 return (pio[1].rreg & pio[1].rmask) | (pio[1].wreg & ~pio[1].rmask);
144 return (pio[2].rreg & pio[2].rmask) | (pio[2].wreg & ~pio[2].rmask);
150 return ((count >> 8) & 0x3f) | ((countreg >> 8) & 0xc0);
155 void I8155::write_signal(int id, uint32_t data, uint32_t mask)
158 case SIG_I8155_PORT_A:
159 if(PIO_MODE_3 || PIO_MODE_4) {
160 // note: strobe signal must be checked
161 uint32_t val = pio[2].wreg | STA_BF_A;
163 if(cmdreg & CMD_INTE_A) {
165 statreg |= STA_INTR_A;
169 pio[0].rreg = (pio[0].rreg & ~mask) | (data & mask);
171 case SIG_I8155_PORT_B:
173 // note: strobe signal must be checked
174 uint32_t val = pio[2].wreg | STA_BF_B;
176 if(cmdreg & CMD_INTE_B) {
178 statreg |= STA_INTR_B;
182 pio[1].rreg = (pio[1].rreg & ~mask) | (data & mask);
184 case SIG_I8155_PORT_C:
185 pio[2].rreg = (pio[2].rreg & ~mask) | (data & mask);
187 case SIG_I8155_CLOCK:
188 if(prev_in && !(data & mask)) {
191 prev_in = ((data & mask) != 0);
196 #define COUNT_VALUE ((countreg & 0x3fff) > 2 ? (countreg & 0x3fff) : 2)
198 void I8155::event_callback(int event_id, int err)
201 input_clock(input_clk);
203 // register next event
204 if(freq && now_count) {
205 input_clk = get_next_clock();
206 period = (int)(cpu_clocks * input_clk / freq) + err;
207 prev_clk = get_current_clock() + err;
208 register_event_by_clock(this, 0, period, false, ®ister_id);
212 void I8155::input_clock(int clock)
214 if(!(now_count && clock)) {
220 int32_t tmp = COUNT_VALUE;
223 set_signal(count > (tmp >> 1));
225 set_signal(count > 1);
228 statreg |= STA_INTR_T;
239 void I8155::start_count()
242 stop_tc = ((countreg & 0x4000) == 0);
243 half = ((countreg & 0x8000) == 0);
250 if(freq && register_id == -1) {
251 input_clk = get_next_clock();
252 period = (int)(cpu_clocks * input_clk / freq);
253 prev_clk = get_current_clock();
254 register_event_by_clock(this, 0, period, false, ®ister_id);
259 void I8155::stop_count()
261 if(register_id != -1) {
262 cancel_event(this, register_id);
268 void I8155::update_count()
270 if(register_id != -1) {
272 int passed = get_passed_clock(prev_clk);
273 uint32_t input = (uint32_t)(freq * passed / cpu_clocks);
274 if(input_clk <= input) {
275 input = input_clk - 1;
279 // cancel and re-register event
280 cancel_event(this, register_id);
283 prev_clk = get_current_clock();
284 register_event_by_clock(this, 0, period, false, ®ister_id);
289 int I8155::get_next_clock()
292 int32_t tmp = COUNT_VALUE >> 1;
293 return (count > tmp) ? count - tmp : count;
295 return (count > 1) ? count - 1 : 1;
298 void I8155::set_signal(bool signal)
300 if(prev_out && !signal) {
302 write_signals(&outputs_timer, 0);
303 } else if(!prev_out && signal) {
305 write_signals(&outputs_timer, 0xffffffff);
310 void I8155::set_pio(int ch, uint8_t data)
312 if(pio[ch].wreg != data || pio[ch].first) {
313 write_signals(&pio[ch].outputs, data);
315 pio[ch].first = false;
319 #define STATE_VERSION 1
321 bool I8155::process_state(FILEIO* state_fio, bool loading)
323 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
326 if(!state_fio->StateCheckInt32(this_device_id)) {
329 state_fio->StateValue(count);
330 state_fio->StateValue(countreg);
331 state_fio->StateValue(now_count);
332 state_fio->StateValue(stop_tc);
333 state_fio->StateValue(half);
334 state_fio->StateValue(prev_out);
335 state_fio->StateValue(prev_in);
336 state_fio->StateValue(freq);
337 state_fio->StateValue(register_id);
338 state_fio->StateValue(input_clk);
339 state_fio->StateValue(prev_clk);
340 state_fio->StateValue(period);
341 state_fio->StateValue(cpu_clocks);
342 for(int i = 0; i < 3; i++) {
343 state_fio->StateValue(pio[i].wreg);
344 state_fio->StateValue(pio[i].rreg);
345 state_fio->StateValue(pio[i].rmask);
346 state_fio->StateValue(pio[i].mode);
347 state_fio->StateValue(pio[i].first);
349 state_fio->StateValue(cmdreg);
350 state_fio->StateValue(statreg);
351 state_fio->StateArray(ram, sizeof(ram), 1);