Example #1
0
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);
                }
            }
Example #2
0
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 */
}