📄 dv-tx3904tmr.c
字号:
/* write requested byte out */ memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1); } return nr_bytes;} static unsignedtx3904tmr_io_write_buffer (struct hw *me, const void *source, int space, unsigned_word base, unsigned nr_bytes){ struct tx3904tmr *controller = hw_data (me); unsigned byte; HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); for (byte = 0; byte < nr_bytes; byte++) { address_word address = base + byte; unsigned_1 write_byte = ((const char*) source)[byte]; int reg_number = (address - controller->base_address) / 4; int reg_offset = 3 - (address - controller->base_address) % 4; /* fill in entire register_value word */ switch (reg_number) { case TCR_REG: if(reg_offset == 0) /* first byte */ { /* update register, but mask out NOP bits */ controller->tcr = (unsigned_4) (write_byte & 0xef); /* Reset counter value if timer suspended and CRE is set. */ if(GET_TCR_TCE(controller) == 0 && GET_TCR_CRE(controller) == 1) controller->trr = 0; } /* HW_TRACE ((me, "tcr: %08lx", (long) controller->tcr)); */ break; case ITMR_REG: if(reg_offset == 1) /* second byte */ { SET_ITMR_TIIE(controller, write_byte & 0x80); } else if(reg_offset == 0) /* first byte */ { SET_ITMR_TZCE(controller, write_byte & 0x01); } /* HW_TRACE ((me, "itmr: %08lx", (long) controller->itmr)); */ break; case CCDR_REG: if(reg_offset == 0) /* first byte */ { controller->ccdr = write_byte & 0x07; } /* HW_TRACE ((me, "ccdr: %08lx", (long) controller->ccdr)); */ break; case PMGR_REG: if(reg_offset == 1) /* second byte */ { SET_PMGR_TPIBE(controller, write_byte & 0x80); SET_PMGR_TPIAE(controller, write_byte & 0x40); } else if(reg_offset == 0) /* first byte */ { SET_PMGR_FFI(controller, write_byte & 0x01); } /* HW_TRACE ((me, "pmgr: %08lx", (long) controller->pmgr)); */ break; case WTMR_REG: if(reg_offset == 1) /* second byte */ { SET_WTMR_TWIE(controller, write_byte & 0x80); } else if(reg_offset == 0) /* first byte */ { SET_WTMR_WDIS(controller, write_byte & 0x80); SET_WTMR_TWC(controller, write_byte & 0x01); } /* HW_TRACE ((me, "wtmr: %08lx", (long) controller->wtmr)); */ break; case TISR_REG: if(reg_offset == 0) /* first byte */ { /* All bits must be zero in given byte, according to spec. */ /* Send an "interrupt off" event on the interrupt port */ if(controller->tisr != 0) /* any interrupts active? */ { hw_port_event(me, INT_PORT, 0); } /* clear interrupt status register */ controller->tisr = 0; } /* HW_TRACE ((me, "tisr: %08lx", (long) controller->tisr)); */ break; case CPRA_REG: if(reg_offset < 3) /* first, second, or third byte */ { MBLIT32(controller->cpra, (reg_offset*8)+7, (reg_offset*8), write_byte); } /* HW_TRACE ((me, "cpra: %08lx", (long) controller->cpra)); */ break; case CPRB_REG: if(reg_offset < 3) /* first, second, or third byte */ { MBLIT32(controller->cprb, (reg_offset*8)+7, (reg_offset*8), write_byte); } /* HW_TRACE ((me, "cprb: %08lx", (long) controller->cprb)); */ break; default: HW_TRACE ((me, "write to illegal register %d", reg_number)); } } /* loop over bytes */ /* Schedule a timer event in near future, so we can increment or stop the counter, to respond to register updates. */ hw_event_queue_schedule(me, 1, deliver_tx3904tmr_tick, NULL); return nr_bytes;} /* Deliver a clock tick to the counter. */static voiddeliver_tx3904tmr_tick (struct hw *me, void *data){ struct tx3904tmr *controller = hw_data (me); SIM_DESC sd = hw_system (me); signed_8 this_ticks = sim_events_time(sd); signed_8 warp; signed_8 divisor; signed_8 quotient, remainder; /* compute simulation ticks between last tick and this tick */ if(controller->last_ticks != 0) warp = this_ticks - controller->last_ticks + controller->roundoff_ticks; else { controller->last_ticks = this_ticks; /* initialize */ warp = controller->roundoff_ticks; } if(controller->event != NULL) hw_event_queue_deschedule(me, controller->event); controller->event = NULL; /* Check whether the timer ticking is enabled at this moment. This largely a function of the TCE bit, but is also slightly mode-dependent. */ switch((int) GET_TCR_TMODE(controller)) { case 0: /* interval */ /* do not advance counter if TCE = 0 or if holding at count = CPRA */ if(GET_TCR_TCE(controller) == 0 || controller->trr == controller->cpra) return; break; case 1: /* pulse generator */ /* do not advance counter if TCE = 0 */ if(GET_TCR_TCE(controller) == 0) return; break; case 2: /* watchdog */ /* do not advance counter if TCE = 0 and WDIS = 1 */ if(GET_TCR_TCE(controller) == 0 && GET_WTMR_WDIS(controller) == 1) return; break; case 3: /* disabled */ /* regardless of TCE, do not advance counter */ return; } /* In any of the above cases that return, a subsequent register write will be needed to restart the timer. A tick event is scheduled by any register write, so it is more efficient not to reschedule dummy events here. */ /* find appropriate divisor etc. */ if(GET_TCR_CCS(controller) == 0) /* internal system clock */ { /* apply internal clock divider */ if(GET_TCR_CCDE(controller)) /* divisor circuit enabled? */ divisor = controller->clock_ticks * (1 << (1 + GET_CCDR_CDR(controller))); else divisor = controller->clock_ticks; } else { divisor = controller->ext_ticks; } /* how many times to increase counter? */ quotient = warp / divisor; remainder = warp % divisor; /* NOTE: If the event rescheduling code works properly, the quotient should never be larger than 1. That is, we should receive events here at least as frequently as the simulated counter is supposed to decrement. So the remainder (-> roundoff_ticks) will slowly accumulate, with the quotient == 0. Once in a while, quotient will equal 1. */ controller->roundoff_ticks = remainder; controller->last_ticks = this_ticks; while(quotient > 0) /* Is it time to increment counter? */ { /* next 24-bit counter value */ unsigned_4 next_trr = (controller->trr + 1) % (1 << 24); quotient --; switch((int) GET_TCR_TMODE(controller)) { case 0: /* interval timer mode */ { /* Current or next counter value matches CPRA value? The first case covers counter holding at maximum before reset. The second case covers normal counting behavior. */ if(controller->trr == controller->cpra || next_trr == controller->cpra) { /* likely hold CPRA value */ if(controller->trr == controller->cpra) next_trr = controller->cpra; SET_TISR_TIIS(controller); /* Signal an interrupt if it is enabled with TIIE, and if we just arrived at CPRA. Don't repeatedly interrupt if holding due to TZCE=0 */ if(GET_ITMR_TIIE(controller) && next_trr != controller->trr) { hw_port_event(me, INT_PORT, 1); } /* Reset counter? */ if(GET_ITMR_TZCE(controller)) { next_trr = 0; } } } break; case 1: /* pulse generator mode */ { /* first trip point */ if(next_trr == controller->cpra) { /* flip flip-flop & report */ controller->ff ^= 1; hw_port_event(me, FF_PORT, controller->ff); SET_TISR_TPIAS(controller); /* signal interrupt */ if(GET_PMGR_TPIAE(controller)) { hw_port_event(me, INT_PORT, 1); } } /* second trip point */ else if(next_trr == controller->cprb) { /* flip flip-flop & report */ controller->ff ^= 1; hw_port_event(me, FF_PORT, controller->ff); SET_TISR_TPIBS(controller); /* signal interrupt */ if(GET_PMGR_TPIBE(controller)) { hw_port_event(me, INT_PORT, 1); } /* clear counter */ next_trr = 0; } } break; case 2: /* watchdog timer mode */ { /* watchdog timer expiry */ if(next_trr == controller->cpra) { SET_TISR_TWIS(controller); /* signal interrupt */ if(GET_WTMR_TWIE(controller)) { hw_port_event(me, INT_PORT, 1); } /* clear counter */ next_trr = 0; } } break; case 3: /* disabled */ default: } /* update counter and report */ controller->trr = next_trr; /* HW_TRACE ((me, "counter trr %ld tisr %lx", (long) controller->trr, (long) controller->tisr)); */ } /* end quotient loop */ /* Reschedule a timer event in near future, so we can increment the counter again. Set the event about 75% of divisor time away, so we will experience roughly 1.3 events per counter increment. */ controller->event = hw_event_queue_schedule(me, divisor*3/4, deliver_tx3904tmr_tick, NULL);}const struct hw_descriptor dv_tx3904tmr_descriptor[] = { { "tx3904tmr", tx3904tmr_finish, }, { NULL },};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -