static void z80ctc_timercallback (int param) { int which = param >> 2; int ch = param & 3; z80ctc *ctc = ctcs + which; /* down counter has reached zero - see if we should interrupt */ if ((ctc->mode[ch] & INTERRUPT) == INTERRUPT_ON) { if( !(ctc->int_state[ch] & Z80_INT_REQ) ) { ctc->int_state[ch] |= Z80_INT_REQ; z80ctc_interrupt_check( ctc ); } } /* generate the clock pulse */ if (ctc->zc[ch]) { (*ctc->zc[ch])(0,1); (*ctc->zc[ch])(0,0); } /* reset the down counter */ ctc->down[ch] = ctc->tconst[ch]; }
void z80ctc_reset (int which) { z80ctc *ctc = ctcs + which; int i; /* set up defaults */ for (i = 0; i < 4; i++) { ctc->mode[i] = RESET_ACTIVE; ctc->tconst[i] = 0x100; timer_adjust(ctc->timer[i], TIME_NEVER, 0, 0); ctc->int_state[i] = 0; } z80ctc_interrupt_check( ctc ); }
void z80ctc_reset (int which) { z80ctc *ctc = ctcs + which; int i; /* set up defaults */ for (i = 0; i < 4; i++) { ctc->mode[i] = RESET_ACTIVE; ctc->tconst[i] = 0x100; if (ctc->timer[i]) timer_remove (ctc->timer[i]); ctc->timer[i] = NULL; ctc->int_state[i] = 0; } z80ctc_interrupt_check( ctc ); }
/* when operate RETI , soud be call this function for request pending interrupt */ void z80ctc_reti( int which ) { z80ctc *ctc = ctcs + which; int ch; for( ch = 0 ; ch < 4 ; ch++ ) { if( ctc->int_state[ch] & Z80_INT_IEO ) { /* highest served interrupt found */ /* clear interrupt status */ ctc->int_state[ch] &= ~Z80_INT_IEO; /* search next interrupt */ break; } } /* set next interrupt stattus */ z80ctc_interrupt_check( ctc ); }
int z80ctc_interrupt( int which ) { z80ctc *ctc = ctcs + which; int ch; for( ch = 0 ; ch < 4 ; ch++ ) { if( ctc->int_state[ch] ) { if( ctc->int_state[ch] == Z80_INT_REQ) ctc->int_state[ch] = Z80_INT_IEO; break; } } if( ch > 3 ) { if (errorlog) fprintf(errorlog,"CTC entry INT : non IRQ\n"); ch = 0; } z80ctc_interrupt_check( ctc ); return ctc->vector + ch * 2; }
void z80ctc_w (int which, int offset, int data) { z80ctc *ctc = ctcs + which; int mode, ch; /* keep channel within range, and get the current mode */ ch = offset & 3; mode = ctc->mode[ch]; /* if we're waiting for a time constant, this is it */ if ((mode & CONSTANT) == CONSTANT_LOAD) { /* set the time constant (0 -> 0x100) */ ctc->tconst[ch] = data ? data : 0x100; /* clear the internal mode -- we're no longer waiting */ ctc->mode[ch] &= ~CONSTANT; /* also clear the reset, since the constant gets it going again */ ctc->mode[ch] &= ~RESET; /* if we're in timer mode.... */ if ((mode & MODE) == MODE_TIMER) { /* if we're triggering on the time constant, reset the down counter now */ if ((mode & TRIGGER) == TRIGGER_AUTO) { double clock = ((mode & PRESCALER) == PRESCALER_16) ? ctc->invclock16 : ctc->invclock256; if (ctc->timer[ch]) timer_remove (ctc->timer[ch]); if (!(ctc->notimer & (1<<ch))) ctc->timer[ch] = timer_pulse (clock * (double)ctc->tconst[ch], (which << 2) + ch, z80ctc_timercallback); } /* else set the bit indicating that we're waiting for the appropriate trigger */ else ctc->mode[ch] |= WAITING_FOR_TRIG; } /* also set the down counter in case we're clocking externally */ ctc->down[ch] = ctc->tconst[ch]; /* all done here */ return; } /* if we're writing the interrupt vector, handle it specially */ #if 0 /* Tatsuyuki Satoh changes */ /* The 'Z80family handbook' wrote, */ /* interrupt vector is able to set for even channel (0 or 2) */ if ((data & CONTROL) == CONTROL_VECTOR && (ch&1) == 0) #else if ((data & CONTROL) == CONTROL_VECTOR && ch == 0) #endif { ctc->vector = data & 0xf8; if (errorlog) fprintf (errorlog, "CTC Vector = %02x\n", ctc->vector); return; } /* this must be a control word */ if ((data & CONTROL) == CONTROL_WORD) { /* set the new mode */ ctc->mode[ch] = data; if (errorlog) fprintf (errorlog,"CTC ch.%d mode = %02x\n", ch, data); /* if we're being reset, clear out any pending timers for this channel */ if ((data & RESET) == RESET_ACTIVE) { if (ctc->timer[ch]) timer_remove (ctc->timer[ch]); ctc->timer[ch] = NULL; if( ctc->int_state[ch] != 0 ) { /* clear interrupt service , request */ ctc->int_state[ch] = 0; z80ctc_interrupt_check( ctc ); } } /* all done here */ return; } }