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 void I8155::save_state(FILEIO* state_fio)
323 state_fio->FputUint32(STATE_VERSION);
324 state_fio->FputInt32(this_device_id);
326 state_fio->FputUint16(count);
327 state_fio->FputUint16(countreg);
328 state_fio->FputBool(now_count);
329 state_fio->FputBool(stop_tc);
330 state_fio->FputBool(half);
331 state_fio->FputBool(prev_out);
332 state_fio->FputBool(prev_in);
333 state_fio->FputUint64(freq);
334 state_fio->FputInt32(register_id);
335 state_fio->FputUint32(input_clk);
336 state_fio->FputUint32(prev_clk);
337 state_fio->FputInt32(period);
338 state_fio->FputUint64(cpu_clocks);
339 for(int i = 0; i < 3; i++) {
340 state_fio->FputUint8(pio[i].wreg);
341 state_fio->FputUint8(pio[i].rreg);
342 state_fio->FputUint8(pio[i].rmask);
343 state_fio->FputUint8(pio[i].mode);
344 state_fio->FputBool(pio[i].first);
346 state_fio->FputUint8(cmdreg);
347 state_fio->FputUint8(statreg);
348 state_fio->Fwrite(ram, sizeof(ram), 1);
351 bool I8155::load_state(FILEIO* state_fio)
353 if(state_fio->FgetUint32() != STATE_VERSION) {
356 if(state_fio->FgetInt32() != this_device_id) {
359 count = state_fio->FgetUint16();
360 countreg = state_fio->FgetUint16();
361 now_count = state_fio->FgetBool();
362 stop_tc = state_fio->FgetBool();
363 half = state_fio->FgetBool();
364 prev_out = state_fio->FgetBool();
365 prev_in = state_fio->FgetBool();
366 freq = state_fio->FgetUint64();
367 register_id = state_fio->FgetInt32();
368 input_clk = state_fio->FgetUint32();
369 prev_clk = state_fio->FgetUint32();
370 period = state_fio->FgetInt32();
371 cpu_clocks = state_fio->FgetUint64();
372 for(int i = 0; i < 3; i++) {
373 pio[i].wreg = state_fio->FgetUint8();
374 pio[i].rreg = state_fio->FgetUint8();
375 pio[i].rmask = state_fio->FgetUint8();
376 pio[i].mode = state_fio->FgetUint8();
377 pio[i].first = state_fio->FgetBool();
379 cmdreg = state_fio->FgetUint8();
380 statreg = state_fio->FgetUint8();
381 state_fio->Fread(ram, sizeof(ram), 1);