diff options
| author | Reiner Herrmann <reiner@reiner-h.de> | 2012-02-10 14:25:38 +0100 |
|---|---|---|
| committer | Reiner Herrmann <reiner@reiner-h.de> | 2012-02-10 14:25:38 +0100 |
| commit | a5d7e68af96d9b62821d8fd47f5039c5bae5d421 (patch) | |
| tree | ab7d1a70312afb74dc7184d8b269b08f332f4b74 /c64/cia.c | |
added original sam_player code
Diffstat (limited to 'c64/cia.c')
| -rw-r--r-- | c64/cia.c | 279 |
1 files changed, 279 insertions, 0 deletions
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<<TA_BIT)
+#define TB_BIT 1
+#define TB_MASK (1<<TB_BIT)
+#define ALRM_BIT 2
+#define ALRM_MASK (1<<ALRM_BIT)
+#define SP_BIT 3
+#define SP_MASK (1<<SP_BIT)
+#define FLAG_BIT 4
+#define FLAG_MASK (1<<FLAG_BIT)
+#define IR_BIT 7
+#define IR_MASK (7<<IR_BIT)
+#define SC_BIT 7
+#define SC_MASK (7<<SC_BIT)
+
+#define START_BIT 0
+#define START_MASK (1<<START_BIT)
+#define PBON_BIT 1
+#define PBON_MASK (1<<PBON_BIT)
+#define OUTMODE_BIT 2
+#define OUTMODE_MASK (1<<OUTMODE_BIT)
+#define RUNMODE_BIT 3
+#define RUNMODE_MASK (1<<RUNMODE_BIT)
+#define LOAD_BIT 4
+#define LOAD_MASK (1<<LOAD_BIT)
+#define SPMODE_BIT 6
+#define SPMODE_MASK (1<<SPMODE_BIT)
+#define TODIN_BIT 7
+#define TODIN_MASK (1<<TODMODE_BIT)
+
+#define INMODEA_SHIFT 5
+#define INMODEA_MASK (0x1<<INMODEA_SHIFT)
+#define TA_CLK (0<<INMODEA_SHIFT)
+#define TA_CNT (1<<INMODEA_SHIFT)
+
+#define INMODEB_SHIFT 5
+#define INMODEB_MASK (0x3<<INMODEB_SHIFT)
+#define TB_CLK (0<<INMODEB_SHIFT)
+#define TB_CNT (1<<INMODEB_SHIFT)
+#define TB_TMRA (2<<INMODEB_SHIFT)
+#define TB_TMRA_CNT (3<<INMODEB_SHIFT)
+
+#define ALARM_BIT 7
+#define ALARM_MASK (1<<ALARM_BIT)
+
+static unsigned char regs[16];
+
+static void cia_interrupt_init(cia_interrupt_t *cia_interrupt)
+{
+ cia_interrupt->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)
+ ;
+}
|
