// cia.c // // 20060803 Markku Alén #include "cia.h" #define TA_BIT 0 #define TA_MASK (1<mask = 0; cia_interrupt->request = 0; } static void cia_interrupt_raise(cia_interrupt_t *cia_interrupt) { cia_interrupt->request = 1; } static int cia_interrupt_get_request(cia_interrupt_t *cia_interrupt) { int request; request = cia_interrupt->request; cia_interrupt->request = 0; return request; } static void cia_port_init(cia_port_t *cia_port) { cia_port->input = 0x00; cia_port->output = 0x00; cia_port->direction = 0x00; UPDATE_CIA_PORT_PINS(cia_port); } static void cia_port_set_data(cia_port_t *cia_port, int data) { cia_port->output = data; UPDATE_CIA_PORT_PINS(cia_port); } static void cia_port_set_direction(cia_port_t *cia_port, int direction) { cia_port->direction = direction; UPDATE_CIA_PORT_PINS(cia_port); } static void cia_timer_init(cia_timer_t *cia_timer) { cia_timer->latch = 0x0000; cia_timer->counter = 0x0000; cia_timer->running = 0; cia_timer->toggle_mode = 0; cia_timer->one_shot = 0; cia_interrupt_init(&cia_timer->interrupt); } static int cia_timer_exec(cia_timer_t *cia_timer, unsigned int cycles) { if(!cia_timer->running) return 0; cia_timer->counter -= cycles; if(cia_timer->counter >= 0) return 0; cia_timer->counter += cia_timer->latch; cia_interrupt_raise(&cia_timer->interrupt); if(cia_timer->one_shot) cia_timer->running = 0; return 1; } void cia_init(cia_t *cia) { cia_port_init(&cia->port_a); cia_port_init(&cia->port_b); cia_timer_init(&cia->timer_a); cia_timer_init(&cia->timer_b); cia->inmode_a = 0; cia->inmode_b = 0; cia->irq_pin = 0; } int cia_read(cia_t *cia, int address) { switch(address & 0x000f) { case 0x0000: return cia->port_a.pins; case 0x0001: return cia->port_b.pins; case 0x0002: return cia->port_a.direction; case 0x0003: return cia->port_b.direction; case 0x0004: return cia->timer_a.counter % 256; case 0x0005: return cia->timer_a.counter / 256; case 0x0006: return cia->timer_b.counter % 256; case 0x0007: return cia->timer_b.counter / 256; case 0x000d: return 0 | (cia_interrupt_get_request(&cia->timer_a.interrupt) != 0 ? TA_MASK : 0) | (cia_interrupt_get_request(&cia->timer_b.interrupt) != 0 ? TB_MASK : 0) | (cia->irq_pin != 0 ? IR_MASK : 0) ; case 0x000e: return 0 | cia->timer_a.running | cia->timer_a.toggle_mode | cia->timer_a.one_shot | cia->inmode_a ; case 0x000f: return 0 | cia->timer_b.running | cia->timer_b.toggle_mode | cia->timer_b.one_shot | cia->inmode_b ; default: return regs[address % sizeof(regs)]; } } void cia_write(cia_t *cia, int address, int data) { switch(address & 0x000f) { case 0x0000: cia_port_set_data(&cia->port_a, data); break; case 0x0001: cia_port_set_data(&cia->port_b, data); break; case 0x0002: cia_port_set_direction(&cia->port_a, data); break; case 0x0003: cia_port_set_direction(&cia->port_b, data); break; case 0x0004: cia->timer_a.latch = (cia->timer_a.latch & 0xff00) | (data & 0xff); break; case 0x0005: cia->timer_a.latch = (cia->timer_a.latch & 0x00ff) | ((data & 0xff) << 8); if(!cia->timer_a.running) cia->timer_a.counter = cia->timer_a.latch; break; case 0x0006: cia->timer_b.latch = (cia->timer_b.latch & 0xff00) | (data & 0xff); break; case 0x0007: cia->timer_b.latch = (cia->timer_b.latch & 0x00ff) | ((data & 0xff) << 8); if(!cia->timer_b.running) cia->timer_b.counter = cia->timer_b.latch; break; case 0x000d: if((data & TA_MASK) != 0) cia->timer_a.interrupt.mask = data & SC_MASK; if((data & TB_MASK) != 0) cia->timer_b.interrupt.mask = data & SC_MASK; break; case 0x000e: cia->timer_a.running = data & START_MASK; cia->timer_a.toggle_mode = data & OUTMODE_MASK; cia->timer_a.one_shot = data & RUNMODE_MASK; if((data & LOAD_MASK) != 0) cia->timer_a.counter = cia->timer_a.latch; cia->inmode_a = data & INMODEA_MASK; break; case 0x000f: cia->timer_b.running = data & START_MASK; cia->timer_b.toggle_mode = data & OUTMODE_MASK; cia->timer_b.one_shot = data & RUNMODE_MASK; if((data & LOAD_MASK) != 0) cia->timer_b.counter = cia->timer_b.latch; cia->inmode_b = data & INMODEB_MASK; break; default: regs[address % sizeof(regs)] = data; } } int cia_a_port_output(cia_t *cia) { return cia->port_a.pins; } int cia_b_port_output(cia_t *cia) { return cia->port_b.pins; } void cia_port_a_input(cia_t *cia, int data) { cia->port_a.input = data; UPDATE_CIA_PORT_PINS(&cia->port_a); } void cia_port_b_input(cia_t *cia, int data) { cia->port_b.input = data; UPDATE_CIA_PORT_PINS(&cia->port_b); } void cia_exec(cia_t *cia, unsigned int cycles) { int timer_a_underflowed; switch(cia->inmode_a) { case TA_CLK: timer_a_underflowed = cia_timer_exec(&cia->timer_a, cycles); break; default: timer_a_underflowed = 0; } switch(cia->inmode_b) { case TB_CLK: cia_timer_exec(&cia->timer_b, cycles); break; case TB_TMRA: if(timer_a_underflowed) cia_timer_exec(&cia->timer_b, 1); break; } cia->irq_pin = 0 | (cia->timer_a.interrupt.mask != 0 ? cia->timer_a.interrupt.request : 0) | (cia->timer_b.interrupt.mask != 0 ? cia->timer_b.interrupt.request : 0) ; }