void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) { CLOCK rclk; if (*(via_context->rmw_flag)) { (*(via_context->clk_ptr))--; *(via_context->rmw_flag) = 0; viacore_store(via_context, addr, via_context->last_read); (*(via_context->clk_ptr))++; } /* stores have a one-cycle offset if CLK++ happens before store */ rclk = *(via_context->clk_ptr) - via_context->write_offset; addr &= 0xf; switch (addr) { /* these are done with saving the value */ case VIA_PRA: /* port A */ via_context->ifr &= ~VIA_IM_CA1; if (!IS_CA2_INDINPUT()) { via_context->ifr &= ~VIA_IM_CA2; } if (IS_CA2_HANDSHAKE()) { via_context->ca2_state = 0; (via_context->set_ca2)(via_context, via_context->ca2_state); if (IS_CA2_PULSE_MODE()) { via_context->ca2_state = 1; (via_context->set_ca2)(via_context, via_context->ca2_state); } } if (via_context->ier & (VIA_IM_CA1 | VIA_IM_CA2)) { update_myviairq(via_context); } case VIA_PRA_NHS: /* port A, no handshake */ via_context->via[VIA_PRA_NHS] = byte; addr = VIA_PRA; case VIA_DDRA: via_context->via[addr] = byte; byte = via_context->via[VIA_PRA] | ~(via_context->via[VIA_DDRA]); (via_context->store_pra)(via_context, byte, via_context->oldpa, addr); via_context->oldpa = byte; break; case VIA_PRB: /* port B */ via_context->ifr &= ~VIA_IM_CB1; if ((via_context->via[VIA_PCR] & 0xa0) != 0x20) { via_context->ifr &= ~VIA_IM_CB2; } if (IS_CB2_HANDSHAKE()) { via_context->cb2_state = 0; (via_context->set_cb2)(via_context, via_context->cb2_state); if (IS_CB2_PULSE_MODE()) { via_context->cb2_state = 1; (via_context->set_cb2)(via_context, via_context->cb2_state); } } if (via_context->ier & (VIA_IM_CB1 | VIA_IM_CB2)) { update_myviairq(via_context); } case VIA_DDRB: via_context->via[addr] = byte; byte = via_context->via[VIA_PRB] | ~(via_context->via[VIA_DDRB]); (via_context->store_prb)(via_context, byte, via_context->oldpb, addr); via_context->oldpb = byte; break; case VIA_SR: /* Serial Port output buffer */ via_context->via[addr] = byte; /* shift state can only be reset once 8 bits are complete */ if (via_context->ifr & VIA_IM_SR) { via_context->ifr &= ~VIA_IM_SR; update_myviairq(via_context); via_context->shift_state = 0; } (via_context->store_sr)(via_context, byte); break; /* Timers */ case VIA_T1CL: case VIA_T1LL: via_context->via[VIA_T1LL] = byte; update_myviatal(via_context, rclk); break; case VIA_T1CH: /* Write timer A high */ via_context->via[VIA_T1LH] = byte; update_myviatal(via_context, rclk); /* load counter with latch value */ via_context->tau = rclk + via_context->tal + 3 + TAUOFFSET; via_context->tai = rclk + via_context->tal + 2; alarm_set(via_context->t1_alarm, via_context->tai); /* set pb7 state */ via_context->pb7 = 0; via_context->pb7o = 0; /* Clear T1 interrupt */ via_context->ifr &= ~VIA_IM_T1; update_myviairq(via_context); break; case VIA_T1LH: /* Write timer A high order latch */ via_context->via[addr] = byte; update_myviatal(via_context, rclk); /* IF: Does not change T1 interrupt, see Synertek notes */ break; case VIA_T2LL: /* Write timer 2 low latch */ via_context->via[VIA_T2LL] = byte; (via_context->store_t2l)(via_context, byte); break; case VIA_T2CH: /* Write timer 2 high counter/latch */ /* update counter and latch values */ via_context->via[VIA_T2LH] = byte; via_context->t2cl = via_context->via[VIA_T2LL]; via_context->t2ch = byte; /* start T2 only in timer mode, leave unchanged in pulse counting mode */ if (!(via_context->via[VIA_ACR] & 0x20)) { /* set the next alarm to the low latch value as timer cascading mode change matters at each underflow of the T2 low counter */ via_context->tbu = rclk + via_context->t2cl + 3; via_context->tbi = rclk + via_context->t2cl + 2; alarm_set(via_context->t2_alarm, via_context->tbi); } /* Clear T2 interrupt */ via_context->ifr &= ~VIA_IM_T2; update_myviairq(via_context); break; /* Interrupts */ case VIA_IFR: /* 6522 Interrupt Flag Register */ via_context->ifr &= ~byte; update_myviairq(via_context); /* FIXME: clearing any timer interrupt should set the relevant timer alarm */ break; case VIA_IER: /* Interrupt Enable Register */ if (byte & VIA_IM_IRQ) { /* set interrupts */ via_context->ier |= byte & 0x7f; } else { /* clear interrupts */ via_context->ier &= ~byte; } update_myviairq(via_context); break; /* Control */ case VIA_ACR: /* bit 7 timer 1 output to PB7 */ update_myviatal(via_context, rclk); if ((via_context->via[VIA_ACR] ^ byte) & 0x80) { if (byte & 0x80) { via_context->pb7 = 1 ^ via_context->pb7x; } } if ((via_context->via[VIA_ACR] ^ byte) & 0x40) { via_context->pb7 ^= via_context->pb7sx; if ((byte & 0x40)) { if (via_context->pb7x || via_context->pb7xx) { if (via_context->tal) { via_context->pb7o = 1; } else { via_context->pb7o = 0; if ((via_context->via[VIA_ACR] & 0x80) && via_context->pb7x && (!(via_context->pb7xx))) { via_context->pb7 ^= 1; } } } } } via_context->pb7sx = via_context->pb7x; /* bit 1, 0 latch enable port B and A */ #ifdef MYVIA_NEED_LATCHING /* switch on port A latching - FIXME: is this ok? */ if ((!(via_context->via[addr] & 1)) && (byte & 1)) { via_context->ila = (via_context->read_pra)(via_context, addr); } /* switch on port B latching - FIXME: is this ok? */ if ((!(via_context->via[addr] & 2)) && (byte & 2)) { via_context->ilb = (via_context->read_prb)(via_context); } #endif /* switch between timer and pulse counting mode if bit 5 changes */ if ((via_context->via[VIA_ACR] ^ byte) & 0x20) { if (byte & 0x20) { /* Pulse counting mode: set t2 to the current T2 value; PB6 should always update t2 and update irq on underflow */ CLOCK stop = myviatb(via_context); via_context->t2cl = (BYTE)(stop & 0xff); via_context->t2ch = (BYTE)((stop >> 8) & 0xff); /* stop alarm to prevent t2 and T2 updates */ alarm_unset(via_context->t2_alarm); via_context->tbi = 0; } else { /* Timer mode; set the next alarm to the low latch value as timer cascading mode change matters at each underflow of the T2 low counter */ via_context->tbu = rclk + via_context->t2cl + 3; via_context->tbi = rclk + via_context->t2cl + 2; alarm_set(via_context->t2_alarm, via_context->tbi); } }
void REGPARM2 via2_store(WORD addr, BYTE data) { viacore_store(machine_context.via2, addr, data); }
void ieeevia2_store(WORD addr, BYTE data) { viacore_store(machine_context.ieeevia2, addr, data); }
void via1d2031_store(drive_context_t *ctxptr, WORD addr, BYTE data) { viacore_store(ctxptr->via1d2031, addr, data); }
void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) { CLOCK rclk; if (*(via_context->rmw_flag)) { (*(via_context->clk_ptr))--; *(via_context->rmw_flag) = 0; viacore_store(via_context, addr, via_context->last_read); (*(via_context->clk_ptr))++; } /* stores have a one-cycle offset if CLK++ happens before store */ rclk = *(via_context->clk_ptr) - via_context->write_offset; addr &= 0xf; switch (addr) { /* these are done with saving the value */ case VIA_PRA: /* port A */ via_context->ifr &= ~VIA_IM_CA1; if (!IS_CA2_INDINPUT()) { via_context->ifr &= ~VIA_IM_CA2; } if (IS_CA2_HANDSHAKE()) { via_context->ca2_state = 0; (via_context->set_ca2)(via_context, via_context->ca2_state); if (IS_CA2_PULSE_MODE()) { via_context->ca2_state = 1; (via_context->set_ca2)(via_context, via_context->ca2_state); } } if (via_context->ier & (VIA_IM_CA1 | VIA_IM_CA2)) update_myviairq(via_context); case VIA_PRA_NHS: /* port A, no handshake */ via_context->via[VIA_PRA_NHS] = byte; addr = VIA_PRA; case VIA_DDRA: via_context->via[addr] = byte; byte = via_context->via[VIA_PRA] | ~(via_context->via[VIA_DDRA]); (via_context->store_pra)(via_context, byte, via_context->oldpa, addr); via_context->oldpa = byte; break; case VIA_PRB: /* port B */ via_context->ifr &= ~VIA_IM_CB1; if ((via_context->via[VIA_PCR] & 0xa0) != 0x20) { via_context->ifr &= ~VIA_IM_CB2; } if (IS_CB2_HANDSHAKE()) { via_context->cb2_state = 0; (via_context->set_cb2)(via_context, via_context->cb2_state); if (IS_CB2_PULSE_MODE()) { via_context->cb2_state = 1; (via_context->set_cb2)(via_context, via_context->cb2_state); } } if (via_context->ier & (VIA_IM_CB1 | VIA_IM_CB2)) update_myviairq(via_context); case VIA_DDRB: via_context->via[addr] = byte; byte = via_context->via[VIA_PRB] | ~(via_context->via[VIA_DDRB]); (via_context->store_prb)(via_context, byte, via_context->oldpb, addr); via_context->oldpb = byte; break; case VIA_SR: /* Serial Port output buffer */ via_context->via[addr] = byte; (via_context->store_sr)(via_context, byte); break; /* Timers */ case VIA_T1CL: case VIA_T1LL: via_context->via[VIA_T1LL] = byte; update_myviatal(via_context, rclk); break; case VIA_T1CH: /* Write timer A high */ via_context->via[VIA_T1LH] = byte; update_myviatal(via_context, rclk); /* load counter with latch value */ via_context->tau = rclk + via_context->tal + 3 + TAUOFFSET; via_context->tai = rclk + via_context->tal + 2; alarm_set(via_context->t1_alarm, via_context->tai); /* set pb7 state */ via_context->pb7 = 0; via_context->pb7o = 0; /* Clear T1 interrupt */ via_context->ifr &= ~VIA_IM_T1; update_myviairq(via_context); break; case VIA_T1LH: /* Write timer A high order latch */ via_context->via[addr] = byte; update_myviatal(via_context, rclk); /* Clear T1 interrupt */ via_context->ifr &= ~VIA_IM_T1; update_myviairq(via_context); break; case VIA_T2LL: /* Write timer 2 low latch */ via_context->via[VIA_T2LL] = byte; update_myviatbl(via_context); (via_context->store_t2l)(via_context, byte); break; case VIA_T2CH: /* Write timer 2 high */ via_context->via[VIA_T2CH] = byte; update_myviatbl(via_context); via_context->tbu = rclk + via_context->tbl + 3; via_context->tbi = rclk + via_context->tbl + 2; alarm_set(via_context->t2_alarm, via_context->tbi); /* Clear T2 interrupt */ via_context->ifr &= ~VIA_IM_T2; update_myviairq(via_context); break; /* Interrupts */ case VIA_IFR: /* 6522 Interrupt Flag Register */ via_context->ifr &= ~byte; update_myviairq(via_context); break; case VIA_IER: /* Interrupt Enable Register */ if (byte & VIA_IM_IRQ) { /* set interrupts */ via_context->ier |= byte & 0x7f; } else { /* clear interrupts */ via_context->ier &= ~byte; } update_myviairq(via_context); break; /* Control */ case VIA_ACR: /* bit 7 timer 1 output to PB7 */ update_myviatal(via_context, rclk); if ((via_context->via[VIA_ACR] ^ byte) & 0x80) { if (byte & 0x80) { via_context->pb7 = 1 ^ via_context->pb7x; } } if ((via_context->via[VIA_ACR] ^ byte) & 0x40) { via_context->pb7 ^= via_context->pb7sx; if ((byte & 0x40)) { if (via_context->pb7x || via_context->pb7xx) { if (via_context->tal) { via_context->pb7o = 1; } else { via_context->pb7o = 0; if ((via_context->via[VIA_ACR] & 0x80) && via_context->pb7x && (!(via_context->pb7xx))) via_context->pb7 ^= 1; } } } } via_context->pb7sx = via_context->pb7x; /* bit 1, 0 latch enable port B and A */ #ifdef MYVIA_NEED_LATCHING /* switch on port A latching - FIXME: is this ok? */ if ( (!(via_context->via[addr] & 1)) && (byte & 1)) { via_context->ila = (via_context->read_pra)(via_context, addr); } /* switch on port B latching - FIXME: is this ok? */ if ((!(via_context->via[addr] & 2)) && (byte & 2)) { via_context->ilb = (via_context->read_prb)(via_context); } #endif via_context->via[addr] = byte; (via_context->store_acr)(via_context, byte); /* bit 5 timer 2 count mode */ if (byte & 32) { /* TODO */ /* update_myviatb(0); *//* stop timer if mode == 1 */ } /* bit 4, 3, 2 shift register control */ break; case VIA_PCR: /* bit 7, 6, 5 CB2 handshake/interrupt control */ /* bit 4 CB1 interrupt control */ /* bit 3, 2, 1 CA2 handshake/interrupt control */ /* bit 0 CA1 interrupt control */ if ((byte & 0x0e) == 0x0c) { /* set output low */ via_context->ca2_state = 0; } else if ((byte & 0x0e) == 0x0e) { /* set output high */ via_context->ca2_state = 1; } else { /* set to toggle/pulse/input */ /* FIXME: is this correct if handshake is already active? */ via_context->ca2_state = 1; } (via_context->set_ca2)(via_context, via_context->ca2_state); if ((byte & 0xe0) == 0xc0) { /* set output low */ via_context->cb2_state = 0; } else if ((byte & 0xe0) == 0xe0) { /* set output high */ via_context->cb2_state = 1; } else { /* set to toggle/pulse/input */ /* FIXME: is this correct if handshake is already active? */ via_context->cb2_state = 1; } (via_context->set_cb2)(via_context, via_context->cb2_state); (via_context->store_pcr)(via_context, byte, addr); via_context->via[addr] = byte; break; default: via_context->via[addr] = byte; } /* switch */ }
void via_store(WORD addr, BYTE data) { viacore_store(machine_context.via, addr, data); }