From a5d7e68af96d9b62821d8fd47f5039c5bae5d421 Mon Sep 17 00:00:00 2001 From: Reiner Herrmann Date: Fri, 10 Feb 2012 14:25:38 +0100 Subject: added original sam_player code --- c64/cia.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 c64/cia.c (limited to 'c64/cia.c') diff --git a/c64/cia.c b/c64/cia.c new file mode 100644 index 0000000..cf0d2c0 --- /dev/null +++ b/c64/cia.c @@ -0,0 +1,279 @@ +// 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) + ; +} -- cgit v1.2.3