static avr_cycle_count_t avr_watchdog_timer( struct avr_t * avr, avr_cycle_count_t when, void * param) { avr_watchdog_t * p = (avr_watchdog_t *)param; if (avr_regbit_get(avr, p->watchdog.enable)) { AVR_LOG(avr, LOG_TRACE, "WATCHDOG: timer fired.\n"); avr_raise_interrupt(avr, &p->watchdog); return when + p->cycle_count; } else if (avr_regbit_get(avr, p->wde)) { AVR_LOG(avr, LOG_TRACE, "WATCHDOG: timer fired without interrupt. Resetting\n"); p->reset_context.avr_run = avr->run; p->reset_context.wdrf = 1; /* Ideally we would perform a reset here via 'avr_reset' * However, returning after reset would result in an unconsistent state. * It seems our best (and cleanest) solution is to set a temporary call * back which can safely perform the reset for us... During reset, * the previous callback can be restored and safely resume. */ avr->run = avr_watchdog_run_callback_software_reset; } return 0; }
static int avr_flash_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param) { if (ctl != AVR_IOCTL_FLASH_SPM) return -1; avr_flash_t * p = (avr_flash_t *)port; avr_t * avr = p->io.avr; avr_flashaddr_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); if (avr->rampz) z |= avr->data[avr->rampz] << 16; uint16_t r01 = avr->data[0] | (avr->data[1] << 8); // printf("AVR_IOCTL_FLASH_SPM %02x Z:%04x R01:%04x\n", avr->data[p->r_spm], z,r01); avr_cycle_timer_cancel(avr, avr_progen_clear, p); avr_regbit_clear(avr, p->selfprgen); if (avr_regbit_get(avr, p->pgers)) { z &= ~1; AVR_LOG(avr, LOG_TRACE, "FLASH: Erasing page %04x (%d)\n", (z / p->spm_pagesize), p->spm_pagesize); for (int i = 0; i < p->spm_pagesize; i++) avr->flash[z++] = 0xff; } else if (avr_regbit_get(avr, p->pgwrt)) { z &= ~1; AVR_LOG(avr, LOG_TRACE, "FLASH: Writing page %04x (%d)\n", (z / p->spm_pagesize), p->spm_pagesize); } else if (avr_regbit_get(avr, p->blbset)) { AVR_LOG(avr, LOG_TRACE, "FLASH: Setting lock bits (ignored)\n"); } else { z &= ~1; avr->flash[z++] = r01; avr->flash[z] = r01 >> 8; } return 0; }
static void _avr_io_command_write (struct avr_t *avr, avr_io_addr_t addr, uint8_t v, void *param) { AVR_LOG (avr, LOG_TRACE, "%s %02x\n", __FUNCTION__, v); switch (v) { case SIMAVR_CMD_VCD_START_TRACE: if (avr->vcd) avr_vcd_start (avr->vcd); break; case SIMAVR_CMD_VCD_STOP_TRACE: if (avr->vcd) avr_vcd_stop (avr->vcd); break; case SIMAVR_CMD_UART_LOOPBACK: { avr_irq_t *src = avr_io_getirq (avr, AVR_IOCTL_UART_GETIRQ ('0'), UART_IRQ_OUTPUT); avr_irq_t *dst = avr_io_getirq (avr, AVR_IOCTL_UART_GETIRQ ('0'), UART_IRQ_INPUT); if (src && dst) { AVR_LOG (avr, LOG_TRACE, "%s activating uart local echo IRQ src %p dst %p\n", __FUNCTION__, src, dst); avr_connect_irq (src, dst); } } break; } }
static void avr_watchdog_set_cycle_count_and_timer (avr_t * avr, avr_watchdog_t * p, uint8_t was_enabled, int8_t old_wdp) { // If nothing else, always ensure we have a valid cycle count... uint8_t wdp = avr_regbit_get_array (avr, p->wdp, 4); p->cycle_count = 2048 << wdp; p->cycle_count = (p->cycle_count * avr->frequency) / 128000; uint8_t wde = avr_regbit_get (avr, p->wde); uint8_t wdie = avr_regbit_get (avr, p->watchdog.enable); uint8_t enable_changed = (was_enabled != (wde || wdie)); uint8_t wdp_changed = ((old_wdp >= 0) ? (wdp != old_wdp) : 0); if (!enable_changed && !wdp_changed) return; static char *message[2][2] = { {0, "reset"}, {"enabled", "enabled and set"} }; if (wde || wdie) { AVR_LOG (avr, LOG_TRACE, "WATCHDOG: %s to %d cycles @ 128kz (* %d) = %d CPU cycles.\n", message[enable_changed][wdp_changed], 2048 << wdp, 1 << wdp, (int) p->cycle_count); avr_cycle_timer_register (avr, p->cycle_count, avr_watchdog_timer, p); } else if (enable_changed) { AVR_LOG (avr, LOG_TRACE, "WATCHDOG: disabled\n"); avr_cycle_timer_cancel (avr, avr_watchdog_timer, p); } }
void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v) { if (addr > avr->ramend) { AVR_LOG(avr, LOG_ERROR, "CORE: *** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x out of ram\n", avr->pc, _avr_sp_get(avr), avr->flash[avr->pc + 1] | (avr->flash[avr->pc]<<8), addr, v); CRASH(); } if (addr < 32) { AVR_LOG(avr, LOG_ERROR, "CORE: *** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x low registers\n", avr->pc, _avr_sp_get(avr), avr->flash[avr->pc + 1] | (avr->flash[avr->pc]<<8), addr, v); CRASH(); } #if AVR_STACK_WATCH /* * this checks that the current "function" is not doctoring the stack frame that is located * higher on the stack than it should be. It's a sign of code that has overrun it's stack * frame and is munching on it's own return address. */ if (avr->trace_data->stack_frame_index > 1 && addr > avr->trace_data->stack_frame[avr->trace_data->stack_frame_index-2].sp) { printf( FONT_RED "%04x : munching stack SP %04x, A=%04x <= %02x\n" FONT_DEFAULT, avr->pc, _avr_sp_get(avr), addr, v); } #endif if (avr->gdb) { avr_gdb_handle_watchpoints(avr, addr, AVR_GDB_WATCH_WRITE); } avr->data[addr] = v; }
static void avr_timer_reconfigure(avr_timer_t * p) { avr_t * avr = p->io.avr; avr_timer_wgm_t zero={0}; p->mode = zero; // cancel everything p->comp[AVR_TIMER_COMPA].comp_cycles = 0; p->comp[AVR_TIMER_COMPB].comp_cycles = 0; p->comp[AVR_TIMER_COMPC].comp_cycles = 0; p->tov_cycles = 0; avr_cycle_timer_cancel(avr, avr_timer_tov, p); avr_cycle_timer_cancel(avr, avr_timer_compa, p); avr_cycle_timer_cancel(avr, avr_timer_compb, p); avr_cycle_timer_cancel(avr, avr_timer_compc, p); long clock = avr->frequency; // only can exists on "asynchronous" 8 bits timers if (avr_regbit_get(avr, p->as2)) clock = 32768; uint8_t cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); if (cs == 0) { AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c clock turned off\n", __FUNCTION__, p->name); return; } uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); uint8_t cs_div = p->cs_div[cs]; uint32_t f = clock >> cs_div; p->mode = p->wgm_op[mode]; //printf("%s-%c clock %d, div %d(/%d) = %d ; mode %d\n", __FUNCTION__, p->name, clock, cs, 1 << cs_div, f, mode); switch (p->mode.kind) { case avr_timer_wgm_normal: avr_timer_configure(p, f, (1 << p->mode.size) - 1); break; case avr_timer_wgm_fc_pwm: avr_timer_configure(p, f, (1 << p->mode.size) - 1); break; case avr_timer_wgm_ctc: { avr_timer_configure(p, f, _timer_get_ocr(p, AVR_TIMER_COMPA)); } break; case avr_timer_wgm_pwm: { uint16_t top = p->mode.top == avr_timer_wgm_reg_ocra ? _timer_get_ocr(p, AVR_TIMER_COMPA) : _timer_get_icr(p); avr_timer_configure(p, f, top); } break; case avr_timer_wgm_fast_pwm: avr_timer_configure(p, f, (1 << p->mode.size) - 1); break; default: AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c unsupported timer mode wgm=%d (%d)\n", __FUNCTION__, p->name, mode, p->mode.kind); } }
static void avr_adc_configure_trigger( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_adc_t * p = (avr_adc_t *)param; uint8_t adate = avr_regbit_get(avr, p->adate); uint8_t old_adts = p->adts_mode; static char * auto_trigger_names[] = { "none", "free_running", "analog_comparator_0", "analog_comparator_1", "analog_comparator_2", "analog_comparator_3", "external_interrupt_0", "timer_0_compare_match_a", "timer_0_compare_match_b", "timer_0_overflow", "timer_1_compare_match_b", "timer_1_overflow", "timer_1_capture_event", "pin_change_interrupt", "psc_module_0_sync_signal", "psc_module_1_sync_signal", "psc_module_2_sync_signal", }; if( adate ) { uint8_t adts = avr_regbit_get_array(avr, p->adts, ARRAY_SIZE(p->adts)); p->adts_mode = p->adts_op[adts]; switch(p->adts_mode) { case avr_adts_free_running: { // do nothing at free running mode } break; // TODO: implement the other auto trigger modes default: { AVR_LOG(avr, LOG_WARNING, "ADC: unimplemented auto trigger mode: %s\n", auto_trigger_names[p->adts_mode]); p->adts_mode = avr_adts_none; } break; } } else { // TODO: remove previously configured auto triggers p->adts_mode = avr_adts_none; } if( old_adts != p->adts_mode ) AVR_LOG(avr, LOG_TRACE, "ADC: auto trigger configured: %s\n", auto_trigger_names[p->adts_mode]); }
static void avr_adc_write_adcsra( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_adc_configure_trigger(avr, addr, v, param); avr_adc_t * p = (avr_adc_t *)param; uint8_t adsc = avr_regbit_get(avr, p->adsc); uint8_t aden = avr_regbit_get(avr, p->aden); avr->data[p->adsc.reg] = v; // can't write zero to adsc if (adsc && !avr_regbit_get(avr, p->adsc)) { avr_regbit_set(avr, p->adsc); v = avr->data[p->adsc.reg]; } if (!aden && avr_regbit_get(avr, p->aden)) { // first conversion p->first = 1; AVR_LOG(avr, LOG_TRACE, "ADC: Start AREF %d AVCC %d\n", avr->aref, avr->avcc); } if (aden && !avr_regbit_get(avr, p->aden)) { // stop ADC avr_cycle_timer_cancel(avr, avr_adc_int_raise, p); avr_regbit_clear(avr, p->adsc); v = avr->data[p->adsc.reg]; // Peter Ross [email protected] } if (!adsc && avr_regbit_get(avr, p->adsc)) { // start one! uint8_t muxi = avr_regbit_get_array(avr, p->mux, ARRAY_SIZE(p->mux)); union { avr_adc_mux_t mux; uint32_t v; } e = { .mux = p->muxmode[muxi] }; avr_raise_irq(p->io.irq + ADC_IRQ_OUT_TRIGGER, e.v); // clock prescaler are just a bit shift.. and 0 means 1 uint32_t div = avr_regbit_get_array(avr, p->adps, ARRAY_SIZE(p->adps)); if (!div) div++; div = avr->frequency >> div; if (p->first) AVR_LOG(avr, LOG_TRACE, "ADC: starting at %uKHz\n", div / 13 / 100); div /= p->first ? 25 : 13; // first cycle is longer avr_cycle_timer_register(avr, avr_hz_to_cycles(avr, div), avr_adc_int_raise, p); } avr_core_watch_write(avr, addr, v); }
void avr_register_io_write( avr_t *avr, avr_io_addr_t addr, avr_io_write_t writep, void * param) { avr_io_addr_t a = AVR_DATA_TO_IO(addr); if (a >= MAX_IOs) { AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_write(): IO address 0x%04x out of range (max 0x%04x).\n", a, MAX_IOs); abort(); } /* * Verifying that some other piece of code is not installed to watch write * on this address. If there is, this code installs a "dispatcher" callback * instead to handle multiple clients, otherwise, it continues as usual */ if (avr->io[a].w.param || avr->io[a].w.c) { if (avr->io[a].w.param != param || avr->io[a].w.c != writep) { // if the muxer not already installed, allocate a new slot if (avr->io[a].w.c != _avr_io_mux_write) { int no = avr->io_shared_io_count++; if (avr->io_shared_io_count > 4) { AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_write(): Too many shared IO registers.\n"); abort(); } AVR_LOG(avr, LOG_TRACE, "IO: avr_register_io_write(%04x): Installing muxer on register.\n", addr); avr->io_shared_io[no].used = 1; avr->io_shared_io[no].io[0].param = avr->io[a].w.param; avr->io_shared_io[no].io[0].c = avr->io[a].w.c; avr->io[a].w.param = (void*)(intptr_t)no; avr->io[a].w.c = _avr_io_mux_write; } int no = (intptr_t)avr->io[a].w.param; int d = avr->io_shared_io[no].used++; if (avr->io_shared_io[no].used > 4) { AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_write(): Too many callbacks on %04x.\n", addr); abort(); } avr->io_shared_io[no].io[d].param = param; avr->io_shared_io[no].io[d].c = writep; return; } } avr->io[a].w.param = param; avr->io[a].w.c = writep; }
int avr_init(avr_t * avr) { avr->flash = malloc(avr->flashend + 1); memset(avr->flash, 0xff, avr->flashend + 1); avr->codeend = avr->flashend; avr->data = malloc(avr->ramend + 1); memset(avr->data, 0, avr->ramend + 1); #ifdef CONFIG_SIMAVR_TRACE avr->trace_data = calloc(1, sizeof(struct avr_trace_data_t)); #endif AVR_LOG(avr, LOG_TRACE, "%s init\n", avr->mmcu); // cpu is in limbo before init is finished. avr->state = cpu_Limbo; avr->frequency = 1000000; // can be overridden via avr_mcu_section avr_cmd_init(avr); avr_interrupt_init(avr); if (avr->custom.init) avr->custom.init(avr, avr->custom.data); if (avr->init) avr->init(avr); // set default (non gdb) fast callbacks avr->run = avr_callback_run_raw; avr->sleep = avr_callback_sleep_raw; // number of address bytes to push/pull on/off the stack avr->address_size = avr->eind ? 3 : 2; avr->log = 1; avr_reset(avr); return 0; }
static avr_cycle_count_t avr_progen_clear(struct avr_t * avr, avr_cycle_count_t when, void * param) { avr_flash_t * p = (avr_flash_t *)param; avr_regbit_clear(p->io.avr, p->selfprgen); AVR_LOG(avr, LOG_WARNING, "FLASH: avr_progen_clear - SPM not received, clearing PRGEN bit\n"); return 0; }
static void avr_uart_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_uart_t * p = (avr_uart_t *)param; if (addr == p->r_udr) { avr_core_watch_write(avr, addr, v); if ( p->udrc.vector) avr_regbit_clear(avr, p->udrc.raised); avr_cycle_timer_register_usec(avr, p->usec_per_byte, avr_uart_txc_raise, p); // should be uart speed dependent if (p->flags & AVR_UART_FLAG_STDIO) { const int maxsize = 256; if (!p->stdio_out) p->stdio_out = malloc(maxsize); p->stdio_out[p->stdio_len++] = v < ' ' ? '.' : v; p->stdio_out[p->stdio_len] = 0; if (v == '\n' || p->stdio_len == maxsize) { p->stdio_len = 0; AVR_LOG(avr, LOG_TRACE, FONT_GREEN "%s\n" FONT_DEFAULT, p->stdio_out); } } TRACE(printf("UDR%c(%02x) = %02x\n", p->name, addr, v);) // tell other modules we are "outputting" a byte if (avr_regbit_get(avr, p->txen))
// no sanity checks checking here, on purpose static void avr_cycle_timer_insert( avr_t * avr, avr_cycle_count_t when, avr_cycle_timer_t timer, void * param) { avr_cycle_timer_pool_t * pool = &avr->cycle_timers; when += avr->cycle; avr_cycle_timer_slot_p t = pool->timer_free; if (!t) { AVR_LOG(avr, LOG_ERROR, "CYCLE: %s: ran out of timers (%d)!\n", __func__, MAX_CYCLE_TIMERS); return; } // detach head pool->timer_free = t->next; t->next = NULL; t->timer = timer; t->param = param; t->when = when; // find its place in the list avr_cycle_timer_slot_p loop = pool->timer, last = NULL; while (loop) { if (loop->when > when) break; last = loop; loop = loop->next; } INSERT(pool->timer, last, t); }
void avr_reset (avr_t * avr) { AVR_LOG (avr, LOG_TRACE, "%s reset\n", avr->mmcu); avr->state = cpu_Running; for (int i = 0x20; i <= MAX_IOs; i++) avr->data[i] = 0; _avr_sp_set (avr, avr->ramend); avr->pc = 0; for (int i = 0; i < 8; i++) avr->sreg[i] = 0; avr_interrupt_reset (avr); avr_cycle_timer_reset (avr); if (avr->reset) avr->reset (avr); avr_io_t *port = avr->io_port; while (port) { if (port->reset) port->reset (port); port = port->next; } }
/* * check whether interrupts are pending. If so, check if the interrupt "latency" is reached, * and if so triggers the handlers and jump to the vector. */ void avr_service_interrupts( avr_t * avr) { if (!avr->sreg[S_I] || !avr->interrupt_state) return; if (avr->interrupt_state < 0) { avr->interrupt_state++; if (avr->interrupt_state == 0) avr->interrupt_state = avr_has_pending_interrupts(avr); return; } avr_int_table_p table = &avr->interrupts; // how many are pending... int cnt = avr_int_pending_get_read_size(&table->pending); // locate the highest priority one int min = 0xff; int mini = 0; for (int ii = 0; ii < cnt; ii++) { avr_int_vector_t * v = avr_int_pending_read_at(&table->pending, ii); if (v->vector < min) { min = v->vector; mini = ii; } } avr_int_vector_t * vector = avr_int_pending_read_at(&table->pending, mini); // now move the one at the front of the fifo in the slot of // the one we service table->pending.buffer[(table->pending.read + mini) % avr_int_pending_fifo_size] = avr_int_pending_read(&table->pending); avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); // if that single interrupt is masked, ignore it and continue // could also have been disabled, or cleared if (!avr_regbit_get(avr, vector->enable) || !vector->pending) { vector->pending = 0; avr->interrupt_state = avr_has_pending_interrupts(avr); } else { if (vector && vector->trace) printf("%s calling %d\n", __FUNCTION__, (int)vector->vector); _avr_push_addr(avr, avr->pc); avr_sreg_set(avr, S_I, 0); avr->pc = vector->vector * avr->vector_size; avr_raise_irq(vector->irq + AVR_INT_IRQ_RUNNING, 1); avr_raise_irq(table->irq + AVR_INT_IRQ_RUNNING, vector->vector); if (table->running_ptr == ARRAY_SIZE(table->running)) { AVR_LOG(avr, LOG_ERROR, "%s run out of nested stack!", __func__); } else { table->running[table->running_ptr++] = vector; } avr_clear_interrupt(avr, vector); } }
void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, avr_flashaddr_t address) { if ((address + size) > avr->flashend+1) { AVR_LOG(avr, LOG_ERROR, "avr_loadcode(): Attempted to load code of size %d but flash size is only %d.\n", size, avr->flashend + 1); abort(); } memcpy(avr->flash + address, code, size); }
static void avr_timer_configure( avr_timer_t * p, uint32_t clock, uint32_t top, uint8_t reset) { p->tov_cycles = 0; p->tov_top = top; p->tov_cycles = clock * (top+1); AVR_LOG(p->io.avr, LOG_TRACE, "TIMER: %s-%c TOP %.2fHz = %d cycles = %dusec\n", __FUNCTION__, p->name, (p->io.avr->frequency / (float)p->tov_cycles), (int)p->tov_cycles, (int)avr_cycles_to_usec(p->io.avr, p->tov_cycles)); for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { if (!p->comp[compi].r_ocr) continue; uint32_t ocr = _timer_get_ocr(p, compi); uint32_t comp_cycles = clock * (ocr + 1); p->comp[compi].comp_cycles = 0; if (p->trace & (avr_timer_trace_compa << compi)) printf("%s-%c clock %f top %d OCR%c %d\n", __FUNCTION__, p->name, (float)(p->io.avr->frequency / clock), top, 'A'+compi, ocr); if (ocr && ocr <= top) { p->comp[compi].comp_cycles = comp_cycles; // avr_hz_to_cycles(p->io.avr, fa); if (p->trace & (avr_timer_trace_compa << compi)) printf( "TIMER: %s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name, 'A'+compi, (float)(p->io.avr->frequency / ocr), (int)p->comp[compi].comp_cycles); } } if (p->tov_cycles > 1) { if (reset) { avr_cycle_timer_register(p->io.avr, p->tov_cycles, avr_timer_tov, p); // calling it once, with when == 0 tells it to arm the A/B/C timers if needed p->tov_base = 0; avr_timer_tov(p->io.avr, p->io.avr->cycle, p); } else { uint64_t orig_tov_base = p->tov_base; avr_cycle_timer_register(p->io.avr, p->tov_cycles - (p->io.avr->cycle - orig_tov_base), avr_timer_tov, p); // calling it once, with when == 0 tells it to arm the A/B/C timers if needed p->tov_base = 0; avr_timer_tov(p->io.avr, orig_tov_base, p); } } }
void avr_register_io_read( avr_t *avr, avr_io_addr_t addr, avr_io_read_t readp, void * param) { avr_io_addr_t a = AVR_DATA_TO_IO(addr); if (avr->io[a].r.param || avr->io[a].r.c) { if (avr->io[a].r.param != param || avr->io[a].r.c != readp) { AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_read(): Already registered, refusing to override.\n"); AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_read(%04x : %p/%p): %p/%p\n", a, avr->io[a].r.c, avr->io[a].r.param, readp, param); abort(); } } avr->io[a].r.param = param; avr->io[a].r.c = readp; }
void avr_callback_run_gdb(avr_t * avr) { avr_gdb_processor(avr, avr->state == cpu_Stopped); if (avr->state == cpu_Stopped) return ; // if we are stepping one instruction, we "run" for one.. int step = avr->state == cpu_Step; if (step) avr->state = cpu_Running; avr_flashaddr_t new_pc = avr->pc; if (avr->state == cpu_Running) { new_pc = avr_run_one(avr); #if CONFIG_SIMAVR_TRACE avr_dump_state(avr); #endif } // if we just re-enabled the interrupts... // double buffer the I flag, to detect that edge if (avr->sreg[S_I] && !avr->i_shadow) avr->interrupts.pending_wait++; avr->i_shadow = avr->sreg[S_I]; // run the cycle timers, get the suggested sleep time // until the next timer is due avr_cycle_count_t sleep = avr_cycle_timer_process(avr); avr->pc = new_pc; if (avr->state == cpu_Sleeping) { if (!avr->sreg[S_I]) { if (avr->log) AVR_LOG(avr, LOG_TRACE, "simavr: sleeping with interrupts off, quitting gracefully\n"); avr->state = cpu_Done; return; } /* * try to sleep for as long as we can (?) */ avr->sleep(avr, sleep); avr->cycle += 1 + sleep; } // Interrupt servicing might change the PC too, during 'sleep' if (avr->state == cpu_Running || avr->state == cpu_Sleeping) avr_service_interrupts(avr); // if we were stepping, use this state to inform remote gdb if (step) avr->state = cpu_StepDone; }
void avr_sadly_crashed (avr_t * avr, uint8_t signal) { AVR_LOG (avr, LOG_ERROR, "%s\n", __FUNCTION__); avr->state = cpu_Stopped; if (avr->gdb_port && !avr->gdb) // enable gdb server, and wait avr_gdb_init (avr); if (!avr->gdb) avr->state = cpu_Crashed; }
static void avr_usb_udaddr_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { if (v & 0x80) AVR_LOG(avr, LOG_TRACE, "USB: Activate address %d\n", v & 0x7f); avr_core_watch_write(avr, addr, v); }
avr_t * avr_make_mcu_by_name( const char *name) { avr_kind_t * maker = NULL; for (int i = 0; avr_kind[i] && !maker; i++) { for (int j = 0; avr_kind[i]->names[j]; j++) if (!strcmp(avr_kind[i]->names[j], name)) { maker = avr_kind[i]; break; } } if (!maker) { AVR_LOG(((avr_t*)0), LOG_ERROR, "%s: AVR '%s' not known\n", __FUNCTION__, name); return NULL; } avr_t * avr = maker->make(); AVR_LOG(avr, LOG_TRACE, "Starting %s - flashend %04x ramend %04x e2end %04x\n", avr->mmcu, avr->flashend, avr->ramend, avr->e2end); return avr; }
static void avr_uart_baud_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_uart_t * p = (avr_uart_t *)param; avr_core_watch_write(avr, addr, v); uint32_t val = avr->data[p->r_ubrrl] | (avr->data[p->r_ubrrh] << 8); uint32_t baud = avr->frequency / (val+1); if (avr_regbit_get(avr, p->u2x)) baud /= 8; else baud /= 16; const int databits[] = { 5,6,7,8, /* 'reserved', assume 8 */8,8,8, 9 }; int db = databits[avr_regbit_get(avr, p->ucsz) | (avr_regbit_get(avr, p->ucsz2) << 2)]; int sb = 1 + avr_regbit_get(avr, p->usbs); int word_size = 1 /* start */ + db /* data bits */ + 1 /* parity */ + sb /* stops */; AVR_LOG(avr, LOG_TRACE, "UART: %c configured to %04x = %d bps (x%d), %d data %d stop\n", p->name, val, baud, avr_regbit_get(avr, p->u2x)?2:1, db, sb); // TODO: Use the divider value and calculate the straight number of cycles p->usec_per_byte = 1000000 / (baud / word_size); AVR_LOG(avr, LOG_TRACE, "UART: Roughly %d usec per bytes\n", (int)p->usec_per_byte); }
static void avr_timer_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_t * p = (avr_timer_t *)param; uint8_t as2 = avr_regbit_get(avr, p->as2); uint8_t cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); avr_core_watch_write(avr, addr, v); uint8_t new_as2 = avr_regbit_get(avr, p->as2); uint8_t new_cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); uint8_t new_mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); // only reconfigure the timer if "relevant" bits have changed // this prevent the timer reset when changing the edge detector // or other minor bits if (new_cs != cs || new_mode != mode || new_as2 != as2) { /* cs */ if (new_cs == 0) { // cancel everything avr_timer_cancel_all_cycle_timers(avr, p, 1); AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c clock turned off\n", __func__, p->name); return; } if (new_as2) { // AVR clock and external 32KHz source does not have // to be synced. To obtain better simulation results // p->tov_base type must be float or avr->frequency // must be multiple of 32768. p->cs_div_value = (uint32_t)((uint64_t)avr->frequency * (1 << p->cs_div[new_cs]) / 32768); } else { p->cs_div_value = 1 << p->cs_div[new_cs]; } /* mode */ p->mode = p->wgm_op[new_mode]; p->wgm_op_mode_kind = p->mode.kind; p->wgm_op_mode_size = (1 << p->mode.size) - 1; avr_timer_reconfigure(p, 1); } }
static void avr_timer_configure(avr_timer_t * p, uint32_t clock, uint32_t top) { float t = clock / (float)(top+1); float frequency = p->io.avr->frequency; p->tov_cycles = 0; p->tov_top = top; p->tov_cycles = frequency / t; // avr_hz_to_cycles(frequency, t); AVR_LOG(p->io.avr, LOG_TRACE, "TIMER: %s-%c TOP %.2fHz = %d cycles = %dusec\n", __FUNCTION__, p->name, t, (int)p->tov_cycles, (int)avr_cycles_to_usec(p->io.avr, p->tov_cycles)); for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { if (!p->comp[compi].r_ocr) continue; uint32_t ocr = _timer_get_ocr(p, compi); float fc = clock / (float)(ocr+1); p->comp[compi].comp_cycles = 0; // printf("%s-%c clock %d top %d OCR%c %d\n", __FUNCTION__, p->name, clock, top, 'A'+compi, ocr); if (ocr && ocr <= top) { p->comp[compi].comp_cycles = frequency / fc; // avr_hz_to_cycles(p->io.avr, fa); AVR_LOG(p->io.avr, LOG_TRACE, "TIMER: %s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name, 'A'+compi, fc, (int)p->comp[compi].comp_cycles); } } if (p->tov_cycles > 1) { avr_cycle_timer_register(p->io.avr, p->tov_cycles, avr_timer_tov, p); // calling it once, with when == 0 tells it to arm the A/B/C timers if needed p->tov_base = 0; avr_timer_tov(p->io.avr, p->io.avr->cycle, p); } }
uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr) { if (addr > avr->ramend) { AVR_LOG(avr, LOG_ERROR, FONT_RED "CORE: *** Invalid read address PC=%04x SP=%04x O=%04x Address %04x out of ram (%04x)\n" FONT_DEFAULT, avr->pc, _avr_sp_get(avr), avr->flash[avr->pc + 1] | (avr->flash[avr->pc]<<8), addr, avr->ramend); CRASH(); } if (avr->gdb) { avr_gdb_handle_watchpoints(avr, addr, AVR_GDB_WATCH_READ); } return avr->data[addr]; }
static void avr_timer_write_ocr( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_comp_p comp = (avr_timer_comp_p)param; avr_timer_t *timer = comp->timer; uint16_t oldv; /* check to see if the OCR values actually changed */ oldv = _timer_get_comp_ocr(avr, comp); avr_core_watch_write(avr, addr, v); switch (timer->wgm_op_mode_kind) { case avr_timer_wgm_normal: avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_fc_pwm: // OCR is not used here avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_ctc: avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_pwm: if (timer->mode.top != avr_timer_wgm_reg_ocra) { avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA)); } else { avr_timer_reconfigure(timer, 0); // if OCRA is the top, reconfigure needed } avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB)); break; case avr_timer_wgm_fast_pwm: if (oldv != _timer_get_comp_ocr(avr, comp)) avr_timer_reconfigure(timer, 0); avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA)); avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB)); break; default: AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c mode %d UNSUPPORTED\n", __FUNCTION__, timer->name, timer->mode.kind); avr_timer_reconfigure(timer, 0); break; } }
static void _avr_io_console_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { static char * buf = NULL; static int size = 0, len = 0; if (v == '\r' && buf) { buf[len] = 0; AVR_LOG(avr, LOG_OUTPUT, "O:" "%s" "" "\n", buf); len = 0; return; } if (len + 1 >= size) { size += 128; buf = (char*)realloc(buf, size); } if (v >= ' ') buf[len++] = v; }
void avr_register_vector( avr_t *avr, avr_int_vector_t * vector) { if (!vector->vector) return; avr_int_table_p table = &avr->interrupts; vector->irq.irq = vector->vector; table->vector[table->vector_count++] = vector; if (vector->trace) printf("%s register vector %d (enabled %04x:%d)\n", __FUNCTION__, vector->vector, vector->enable.reg, vector->enable.bit); if (!vector->enable.reg) AVR_LOG(avr, LOG_WARNING, "INT: avr_register_vector: No 'enable' bit on vector %d !\n", vector->vector); }
static void _avr_io_console_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { if (v == '\r' && avr->io_console_buffer.buf) { avr->io_console_buffer.buf[avr->io_console_buffer.len] = 0; AVR_LOG(avr, LOG_OUTPUT, "O:" "%s" "" "\n", avr->io_console_buffer.buf); avr->io_console_buffer.len = 0; return; } if (avr->io_console_buffer.len + 1 >= avr->io_console_buffer.size) { avr->io_console_buffer.size += 128; avr->io_console_buffer.buf = (char*)realloc( avr->io_console_buffer.buf, avr->io_console_buffer.size); } if (v >= ' ') avr->io_console_buffer.buf[avr->io_console_buffer.len++] = v; }