void viacore_signal(via_context_t *via_context, int line, int edge) { switch (line) { case VIA_SIG_CA1: if ((edge ? 1 : 0) == (via_context->via[VIA_PCR] & 0x01)) { if (IS_CA2_TOGGLE_MODE() && !(via_context->ca2_state)) { via_context->ca2_state = 1; (via_context->set_ca2)(via_context, via_context->ca2_state); } via_context->ifr |= VIA_IM_CA1; update_myviairq(via_context); #ifdef MYVIA_NEED_LATCHING if (IS_PA_INPUT_LATCH()) { via_context->ila = (via_context->read_pra)(via_context, addr); } #endif } break; case VIA_SIG_CA2: if (!(via_context->via[VIA_PCR] & 0x08)) { via_context->ifr |= (((edge << 2) ^ via_context->via[VIA_PCR]) & 0x04) ? 0 : VIA_IM_CA2; update_myviairq(via_context); } break; case VIA_SIG_CB1: if ((edge ? 0x10 : 0) == (via_context->via[VIA_PCR] & 0x10)) { if (IS_CB2_TOGGLE_MODE() && !(via_context->cb2_state)) { via_context->cb2_state = 1; (via_context->set_cb2)(via_context, via_context->cb2_state); } via_context->ifr |= VIA_IM_CB1; update_myviairq(via_context); #ifdef MYVIA_NEED_LATCHING if (IS_PB_INPUT_LATCH()) { via_context->ilb = (via_context->read_prb)(via_context); } #endif } break; case VIA_SIG_CB2: if (!(via_context->via[VIA_PCR] & 0x80)) { via_context->ifr |= (((edge << 6) ^ via_context->via[VIA_PCR]) & 0x40) ? 0 : VIA_IM_CB2; update_myviairq(via_context); } break; } }
static void viacore_intt1(CLOCK offset, void *data) { via_context_t *via_context = (via_context_t *)data; #ifdef MYVIA_TIMER_DEBUG if (app_resources.debugFlag) log_message(via_context->log, "myvia timer A interrupt"); #endif if (!(via_context->via[VIA_ACR] & 0x40)) { /* one-shot mode */ #ifdef MYVIA_TIMER_DEBUG log_message(via_context->log, "MYVIA Timer A interrupt -- one-shot mode: next int won't happen"); #endif alarm_unset(via_context->t1_alarm); via_context->tai = 0; } else { /* continuous mode */ /* load counter with latch value */ via_context->tai += via_context->tal + 2; alarm_set(via_context->t1_alarm, via_context->tai); } via_context->ifr |= VIA_IM_T1; update_myviairq(via_context); /* TODO: toggle PB7? */ /*(viaier & VIA_IM_T1) ? 1:0; */ }
/* * according to Rockwell, all internal registers are cleared, except * for the Timer (1 and 2, counter and latches) and the shift register. */ void viacore_reset(via_context_t *via_context) { int i; /* clear registers */ for (i = 0; i < 4; i++) { via_context->via[i] = 0; } for (i = 4; i < 10; i++) { via_context->via[i] = 0xff; } for (i = 11; i < 16; i++) { via_context->via[i] = 0; } via_context->tal = 0xffff; via_context->t2cl = 0xff; via_context->t2ch = 0xff; via_context->tau = *(via_context->clk_ptr); via_context->tbu = *(via_context->clk_ptr); via_context->read_clk = 0; via_context->ier = 0; via_context->ifr = 0; via_context->pb7 = 0; via_context->pb7x = 0; via_context->pb7o = 0; via_context->pb7xx = 0; via_context->pb7sx = 0; via_context->shift_state = 0; /* disable vice interrupts */ via_context->tai = 0; via_context->tbi = 0; alarm_unset(via_context->t1_alarm); alarm_unset(via_context->t2_alarm); update_myviairq(via_context); via_context->oldpa = 0xff; via_context->oldpb = 0xff; via_context->ca2_state = 1; via_context->cb2_state = 1; (via_context->set_ca2)(via_context, via_context->ca2_state); /* input = high */ (via_context->set_cb2)(via_context, via_context->cb2_state); /* input = high */ if (via_context && via_context->reset) { (via_context->reset)(via_context); } via_context->enabled = 1; }
static void viacore_intt2(CLOCK offset, void *data) { via_context_t *via_context = (via_context_t *)data; #ifdef MYVIA_TIMER_DEBUG if (app_resources.debugFlag) log_message(via_context->log, "MYVIA timer B interrupt."); #endif alarm_unset(via_context->t2_alarm); /*int_clk[I_MYVIAT2] = 0; */ via_context->tbi = 0; via_context->ifr |= VIA_IM_T2; update_myviairq(via_context); }
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); } }
BYTE viacore_read_(via_context_t *via_context, WORD addr) { #endif BYTE byte = 0xff; CLOCK rclk; addr &= 0xf; via_context->read_clk = *(via_context->clk_ptr); via_context->read_offset = 0; rclk = *(via_context->clk_ptr); if (addr >= VIA_T1CL && addr <= VIA_IER) { if (via_context->tai && (via_context->tai < *(via_context->clk_ptr))) viacore_intt1(*(via_context->clk_ptr) - via_context->tai, (void *)via_context); if (via_context->tbi && (via_context->tbi < *(via_context->clk_ptr))) viacore_intt2(*(via_context->clk_ptr) - via_context->tbi, (void *)via_context); } switch (addr) { case VIA_PRA: /* port A */ via_context->ifr &= ~VIA_IM_CA1; if ((via_context->via[VIA_PCR] & 0x0a) != 0x02) { 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 */ /* WARNING: this pin reads the voltage of the output pins, not the ORA value as the other port. Value read might be different from what is expected due to excessive load. */ #ifdef MYVIA_NEED_LATCHING if (IS_PA_INPUT_LATCH()) { byte = via_context->ila; } else { byte = (via_context->read_pra)(via_context, addr); } #else byte = (via_context->read_pra)(via_context, addr); #endif via_context->ila = byte; via_context->last_read = byte; return byte; 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 (via_context->ier & (VIA_IM_CB1 | VIA_IM_CB2)) update_myviairq(via_context); /* WARNING: this pin reads the ORA for output pins, not the voltage on the pins as the other port. */ #ifdef MYVIA_NEED_LATCHING if (IS_PB_INPUT_LATCH()) { byte = via_context->ilb; } else { byte = (via_context->read_prb)(via_context); } #else byte = (via_context->read_prb)(via_context); #endif via_context->ilb = byte; byte = (byte & ~(via_context->via[VIA_DDRB])) | (via_context->via[VIA_PRB] & via_context->via[VIA_DDRB]); if (via_context->via[VIA_ACR] & 0x80) { update_myviatal(via_context, rclk); byte = (byte & 0x7f) | (((via_context->pb7 ^ via_context->pb7x) | via_context->pb7o) ? 0x80 : 0); } via_context->last_read = byte; return byte; /* Timers */ case VIA_T1CL /*TIMER_AL */ : /* timer A low */ via_context->ifr &= ~VIA_IM_T1; update_myviairq(via_context); via_context->last_read = (BYTE)(myviata(via_context) & 0xff); return via_context->last_read; case VIA_T1CH /*TIMER_AH */ : /* timer A high */ via_context->last_read = (BYTE)((myviata(via_context) >> 8) & 0xff); return via_context->last_read; case VIA_T2CL /*TIMER_BL */ : /* timer B low */ via_context->ifr &= ~VIA_IM_T2; update_myviairq(via_context); via_context->last_read = (BYTE)(myviatb(via_context) & 0xff); return via_context->last_read; case VIA_T2CH /*TIMER_BH */ : /* timer B high */ via_context->last_read = (BYTE)((myviatb(via_context) >> 8) & 0xff); return via_context->last_read; case VIA_SR: /* Serial Port Shift Register */ via_context->last_read = via_context->via[addr]; return via_context->last_read; /* Interrupts */ case VIA_IFR: /* Interrupt Flag Register */ { BYTE t = via_context->ifr; if (via_context->ifr & via_context->ier /*[VIA_IER] */ ) t |= 0x80; via_context->last_read = t; return (t); } case VIA_IER: /* 6522 Interrupt Control Register */ via_context->last_read = (via_context->ier /*[VIA_IER] */ | 0x80); return via_context->last_read; } /* switch */ via_context->last_read = via_context->via[addr]; return via_context->via[addr]; }
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 */ }