summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine/6532riot.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/machine/6532riot.c')
-rw-r--r--src/emu/machine/6532riot.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/src/emu/machine/6532riot.c b/src/emu/machine/6532riot.c
new file mode 100644
index 00000000000..42abec15464
--- /dev/null
+++ b/src/emu/machine/6532riot.c
@@ -0,0 +1,373 @@
+/***************************************************************************
+
+ RIOT 6532 emulation
+
+The timer seems to follow these rules:
+- When the timer flag changes from 0 to 1 the timer continues to count
+ down at a 1 cycle rate.
+- When the timer is being read or written the timer flag is reset.
+- When the timer flag is set and the timer contents are 0, the counting
+ stops.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "machine/6532riot.h"
+
+struct riot6532
+{
+ const struct riot6532_interface *intf;
+
+ UINT8 in_a;
+ UINT8 out_a;
+ UINT8 in_b;
+ UINT8 out_b;
+ UINT8 ddr_a;
+ UINT8 ddr_b;
+
+ int shift;
+
+ int pa7_enable;
+ int pa7_direction; /* 0x80 = high-to-low, 0x00 = low-to-high */
+ int pa7_flag;
+ UINT8 pa7;
+
+ int timer_irq_enable;
+ int timer_irq;
+ emu_timer *counter_timer;
+
+ int clock;
+};
+
+
+static struct riot6532 r6532[MAX_R6532];
+
+
+INLINE void r6532_set_timer(int which, UINT8 count)
+{
+ timer_adjust( r6532[which].counter_timer, attotime_mul(ATTOTIME_IN_HZ(r6532[which].clock), (count << r6532[which].shift) + 1), which, attotime_zero );
+}
+
+
+static TIMER_CALLBACK( r6532_irq_timer_callback )
+{
+ int which = param;
+
+ if ( r6532[which].timer_irq_enable )
+ {
+ r6532[which].timer_irq = 1;
+ if (r6532[which].intf->irq_func)
+ (*r6532[which].intf->irq_func)(ASSERT_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is asserted but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+}
+
+
+static void r6532_pa7_check(int which){
+ UINT8 data = ( ( r6532[which].ddr_a & r6532[which].out_a ) | ( ~r6532[which].ddr_a & r6532[which].in_a ) ) & 0x80;
+ if ((r6532[which].pa7 ^ data) && (r6532[which].pa7_direction ^ data))
+ {
+ r6532[which].pa7_flag = 1;
+ if (r6532[which].pa7_enable)
+ {
+ if (r6532[which].intf->irq_func)
+ (*r6532[which].intf->irq_func)(ASSERT_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is asserted but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+ }
+ r6532[which].pa7 = data;
+}
+
+
+void r6532_write(int which, offs_t offset, UINT8 data)
+{
+ if (offset & 4)
+ {
+ if (offset & 0x10)
+ {
+ switch (offset & 3)
+ {
+ case 0:
+ r6532[which].shift = 0;
+ break;
+ case 1:
+ r6532[which].shift = 3;
+ break;
+ case 2:
+ r6532[which].shift = 6;
+ break;
+ case 3:
+ r6532[which].shift = 10;
+ break;
+ }
+ r6532[which].timer_irq_enable = (offset & 8);
+ r6532_set_timer( which, data );
+ }
+ else
+ {
+ r6532[which].pa7_enable = (offset & 2) >> 1;
+ r6532[which].pa7_direction = ( offset & 1 ) << 7;
+ }
+ }
+ else
+ {
+ offset &= 3;
+
+ switch (offset)
+ {
+ case 0:
+ r6532[which].out_a = data;
+ if (r6532[which].ddr_a)
+ {
+ UINT8 write_data = ( r6532[which].ddr_a & r6532[which].out_a ) | ( ~r6532[which].ddr_a & 0xFF );
+ if (r6532[which].intf->out_a_func)
+ r6532[which].intf->out_a_func(0, write_data);
+ else
+ logerror("6532RIOT chip #%d: Port A is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ /* Check for PA7 change */
+ r6532_pa7_check(which);
+ }
+ break;
+ case 1:
+ r6532[which].ddr_a = data;
+ r6532_pa7_check(which);
+ break;
+ case 2:
+ r6532[which].out_b = data;
+ if (r6532[which].ddr_b)
+ {
+ UINT8 write_data = ( r6532[which].ddr_b & r6532[which].out_b ) | ( ~r6532[which].ddr_b & 0xFF );
+ if (r6532[which].intf->out_b_func)
+ r6532[which].intf->out_b_func(0, write_data);
+ else
+ logerror("6532RIOT chip #%d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ break;
+ case 3:
+ r6532[which].ddr_b = data;
+ break;
+ }
+ }
+}
+
+
+INLINE UINT8 r6532_read_timer(int which)
+{
+ int timer_cycles_left = ( attotime_to_double(timer_timeleft( r6532[which].counter_timer )) * r6532[which].clock ) - 1;
+ if ( timer_cycles_left >= 0)
+ {
+ timer_cycles_left = timer_cycles_left >> r6532[which].shift;
+ }
+ else
+ {
+ if (timer_cycles_left != -1)
+ {
+ if (r6532[which].intf->irq_func && r6532[which].timer_irq)
+ (*r6532[which].intf->irq_func)(CLEAR_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+
+ /* Timer flag is cleared, so adjust the target */
+ timer_cycles_left = ( timer_cycles_left > -256 ) ? timer_cycles_left & 0xFF : 0;
+ r6532_set_timer( which, timer_cycles_left );
+ }
+ }
+ return timer_cycles_left;
+}
+
+
+void r6532_set_input_a(int which, UINT8 data)
+{
+ r6532[which].in_a = data;
+ /* Check for PA7 change */
+ r6532_pa7_check(which);
+}
+
+
+void r6532_set_input_b(int which, UINT8 data)
+{
+ r6532[which].in_b = data;
+}
+
+
+INLINE UINT8 r6532_read_irq_flags(int which)
+{
+ int timer_cycles_left = ( attotime_to_double(timer_timeleft( r6532[which].counter_timer )) * r6532[which].clock ) - 1;
+ int res = 0;
+
+ if ( timer_cycles_left < 0 )
+ {
+ res |= 0x80;
+ if ( timer_cycles_left < -1 )
+ {
+ if ( r6532[which].intf->irq_func)
+ (*r6532[which].intf->irq_func)(CLEAR_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+
+ /* Timer flag is cleared, so adjust the target */
+ r6532_set_timer( which, timer_cycles_left > -256 ? timer_cycles_left & 0xFF : 0 );
+ }
+ }
+
+ if (r6532[which].pa7_flag)
+ {
+ res |= 0x40;
+ r6532[which].pa7_flag = 0;
+
+ if (r6532[which].intf->irq_func && timer_cycles_left != -1)
+ (*r6532[which].intf->irq_func)(CLEAR_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ return res;
+}
+
+
+UINT8 r6532_read(int which, offs_t offset)
+{
+ UINT8 val = 0;
+
+ switch (offset & 7)
+ {
+ case 0:
+ if (r6532[which].intf->in_a_func)
+ r6532[which].in_a = r6532[which].intf->in_a_func(0);
+ else
+ logerror("6532RIOT chip #%d: Port A is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ val = ( r6532[which].ddr_a & r6532[which].out_a ) | ( ~r6532[which].ddr_a & r6532[which].in_a );
+ /* Check for PA7 change */
+ r6532_pa7_check(which);
+ break;
+ case 1:
+ val = r6532[which].ddr_a;
+ break;
+ case 2:
+ if (r6532[which].intf->in_b_func)
+ r6532[which].in_b = r6532[which].intf->in_b_func(0);
+ else
+ logerror("6532RIOT chip #%d: Port B is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+
+ val = ( r6532[which].ddr_b & r6532[which].out_b ) | ( ~r6532[which].ddr_b & r6532[which].in_b );
+ break;
+ case 3:
+ val = r6532[which].ddr_b;
+ break;
+ case 4:
+ case 6:
+ r6532[which].timer_irq_enable = offset & 8;
+ val = r6532_read_timer(which);
+ break;
+ case 5:
+ case 7:
+ val = r6532_read_irq_flags(which);
+ break;
+ }
+
+ return val;
+}
+
+
+void r6532_set_clock(int which, int clock)
+{
+ r6532[which].clock = clock;
+}
+
+
+void r6532_reset(int which)
+{
+ r6532[which].out_a = 0;
+ r6532[which].out_b = 0;
+ r6532[which].ddr_a = 0;
+ r6532[which].ddr_b = 0;
+
+ r6532[which].shift = 10;
+
+ r6532[which].counter_timer = timer_alloc(r6532_irq_timer_callback);
+
+ r6532_set_timer( which, 0xFF );
+
+ r6532[which].pa7_enable = 0;
+ r6532[which].pa7_direction = 0x80;
+ r6532[which].pa7_flag = 0;
+ r6532[which].pa7 = 0;
+
+ r6532[which].timer_irq_enable = 0;
+ r6532[which].timer_irq = 0;
+
+ if (r6532[which].intf->irq_func)
+ (*r6532[which].intf->irq_func)(CLEAR_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+}
+
+
+void r6532_config(int which, const struct riot6532_interface* intf)
+{
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call r6532_init at init time!");
+ assert_always( which < MAX_R6532, "which exceeds maximum number of configured r6532s!" );
+
+ r6532[which].intf = intf;
+
+ /* Default clock is CPU #0 clock */
+ r6532_set_clock( which, Machine->drv->cpu[0].clock );
+}
+
+
+WRITE8_HANDLER( r6532_0_w ) { r6532_write(0, offset, data); }
+WRITE8_HANDLER( r6532_1_w ) { r6532_write(1, offset, data); }
+WRITE8_HANDLER( r6532_2_w ) { r6532_write(2, offset, data); }
+WRITE8_HANDLER( r6532_3_w ) { r6532_write(3, offset, data); }
+WRITE8_HANDLER( r6532_4_w ) { r6532_write(4, offset, data); }
+WRITE8_HANDLER( r6532_5_w ) { r6532_write(5, offset, data); }
+WRITE8_HANDLER( r6532_6_w ) { r6532_write(6, offset, data); }
+WRITE8_HANDLER( r6532_7_w ) { r6532_write(7, offset, data); }
+
+READ8_HANDLER( r6532_0_r ) { return r6532_read(0, offset); }
+READ8_HANDLER( r6532_1_r ) { return r6532_read(1, offset); }
+READ8_HANDLER( r6532_2_r ) { return r6532_read(2, offset); }
+READ8_HANDLER( r6532_3_r ) { return r6532_read(3, offset); }
+READ8_HANDLER( r6532_4_r ) { return r6532_read(4, offset); }
+READ8_HANDLER( r6532_5_r ) { return r6532_read(5, offset); }
+READ8_HANDLER( r6532_6_r ) { return r6532_read(6, offset); }
+READ8_HANDLER( r6532_7_r ) { return r6532_read(7, offset); }
+
+WRITE8_HANDLER( r6532_0_porta_w) { r6532_set_input_a(0, data); }
+WRITE8_HANDLER( r6532_1_porta_w) { r6532_set_input_a(1, data); }
+WRITE8_HANDLER( r6532_2_porta_w) { r6532_set_input_a(2, data); }
+WRITE8_HANDLER( r6532_3_porta_w) { r6532_set_input_a(3, data); }
+WRITE8_HANDLER( r6532_4_porta_w) { r6532_set_input_a(4, data); }
+WRITE8_HANDLER( r6532_5_porta_w) { r6532_set_input_a(5, data); }
+WRITE8_HANDLER( r6532_6_porta_w) { r6532_set_input_a(6, data); }
+WRITE8_HANDLER( r6532_7_porta_w) { r6532_set_input_a(7, data); }
+
+WRITE8_HANDLER( r6532_0_portb_w) { r6532_set_input_b(0, data); }
+WRITE8_HANDLER( r6532_1_portb_w) { r6532_set_input_b(1, data); }
+WRITE8_HANDLER( r6532_2_portb_w) { r6532_set_input_b(2, data); }
+WRITE8_HANDLER( r6532_3_portb_w) { r6532_set_input_b(3, data); }
+WRITE8_HANDLER( r6532_4_portb_w) { r6532_set_input_b(4, data); }
+WRITE8_HANDLER( r6532_5_portb_w) { r6532_set_input_b(5, data); }
+WRITE8_HANDLER( r6532_6_portb_w) { r6532_set_input_b(6, data); }
+WRITE8_HANDLER( r6532_7_portb_w) { r6532_set_input_b(7, data); }
+
+READ8_HANDLER( r6532_0_porta_r) { return r6532[0].in_a; }
+READ8_HANDLER( r6532_1_porta_r) { return r6532[1].in_a; }
+READ8_HANDLER( r6532_2_porta_r) { return r6532[2].in_a; }
+READ8_HANDLER( r6532_3_porta_r) { return r6532[3].in_a; }
+READ8_HANDLER( r6532_4_porta_r) { return r6532[4].in_a; }
+READ8_HANDLER( r6532_5_porta_r) { return r6532[5].in_a; }
+READ8_HANDLER( r6532_6_porta_r) { return r6532[6].in_a; }
+READ8_HANDLER( r6532_7_porta_r) { return r6532[7].in_a; }
+
+READ8_HANDLER( r6532_0_portb_r) { return r6532[0].in_b; }
+READ8_HANDLER( r6532_1_portb_r) { return r6532[1].in_b; }
+READ8_HANDLER( r6532_2_portb_r) { return r6532[2].in_b; }
+READ8_HANDLER( r6532_3_portb_r) { return r6532[3].in_b; }
+READ8_HANDLER( r6532_4_portb_r) { return r6532[4].in_b; }
+READ8_HANDLER( r6532_5_portb_r) { return r6532[5].in_b; }
+READ8_HANDLER( r6532_6_portb_r) { return r6532[6].in_b; }
+READ8_HANDLER( r6532_7_portb_r) { return r6532[7].in_b; }
+