diff options
| author | Dmitry Salychev <[email protected]> | 2017-03-01 11:36:57 +0100 |
|---|---|---|
| committer | Dmitry Salychev <[email protected]> | 2017-03-01 11:36:57 +0100 |
| commit | 0af8fd652c3d27bd0779782eb3339eb62024cba0 (patch) | |
| tree | e7a1ba0367ffddfdb04ed65d82863cf7cfcba007 | |
| parent | 3d9961f4ae5a4f632c073d7f2d9d920e868cd041 (diff) | |
| parent | 58dcb89d1a7c5d8737f99af012ec06919eec1d6a (diff) | |
| download | mcusim-master.tar.gz | |
| -rw-r--r-- | avr/simm8a.c | 167 | ||||
| -rw-r--r-- | include/avr/sim/sim.h | 3 | ||||
| -rw-r--r-- | include/avr/sim/simm8a.h | 88 | ||||
| -rw-r--r-- | tests/m8a_test.c | 27 |
4 files changed, 245 insertions, 40 deletions
diff --git a/avr/simm8a.c b/avr/simm8a.c index ac6f9d5..aec180d 100644 --- a/avr/simm8a.c +++ b/avr/simm8a.c @@ -33,6 +33,8 @@ static int set_fuse_bytes(struct avr *mcu, uint8_t fuse_high, uint8_t fuse_low); static int set_bldr_size(struct avr *mcu, uint8_t fuse_high); static int set_frequency(struct avr *mcu, uint8_t fuse_high, uint8_t fuse_low); static int set_reset_vector(struct avr *mcu, uint8_t fuse_high); +static int set_progmem(struct avr *mcu, uint16_t *mem, uint32_t size); +static int set_datamem(struct avr *mcu, uint8_t *mem, uint32_t size); /* * Set ATmega8A lock bits to the default values @@ -70,7 +72,8 @@ static int set_reset_vector(struct avr *mcu, uint8_t fuse_high); * Default value for low byte means: * - ... */ -int m8a_init(struct avr *mcu) +int m8a_init(struct avr *mcu, uint16_t *pm, uint32_t pm_size, + uint8_t *dm, uint32_t dm_size) { if (!mcu) { fprintf(stderr, "MCU should not be NULL\n"); @@ -86,11 +89,9 @@ int m8a_init(struct avr *mcu) mcu->spm_pagesize = SPM_PAGESIZE; mcu->flashstart = FLASHSTART; mcu->flashend = FLASHEND; - mcu->ramstart = RAMSTART; mcu->ramend = RAMEND; mcu->ramsize = RAMSIZE; - mcu->e2start = E2START; mcu->e2end = E2END; mcu->e2size = E2SIZE; @@ -103,24 +104,10 @@ int m8a_init(struct avr *mcu) return -1; } - return 0; -} - -int m8a_set_progmem(struct avr *mcu, uint16_t *mem, uint32_t size) -{ - uint16_t flash_size; - - /* Size in 16-bits words */ - flash_size= (uint16_t) ((mcu->flashend - mcu->flashstart) + 1) / 2; - if (size != flash_size) { - fprintf(stderr, "Program memory is limited by %d KiB," - " %u.%03u KiB doesn't match", - (mcu->flashend + 1) / 1024, - (size * 2) / 1024, (size * 2) % 1024); + if (set_progmem(mcu, pm, pm_size)) + return -1; + if (set_datamem(mcu, dm, dm_size)) return -1; - } - - mcu->prog_mem = mem; return 0; } @@ -178,9 +165,145 @@ int m8a_load_progmem(struct avr *mcu, FILE *fp) return 0; } -int m8a_set_datamem(struct avr *mcu, uint8_t *mem, uint32_t size) +static int set_progmem(struct avr *mcu, uint16_t *mem, uint32_t size) +{ + uint16_t flash_size; + + /* Size in 16-bits words */ + flash_size= (uint16_t) ((mcu->flashend - mcu->flashstart) + 1) / 2; + if (size != flash_size) { + fprintf(stderr, "Program memory is limited by %d KiB," + " %u.%03u KiB doesn't match\n", + (mcu->flashend + 1) / 1024, + (size * 2) / 1024, (size * 2) % 1024); + return -1; + } + + mcu->prog_mem = mem; + + return 0; +} + +static int set_datamem(struct avr *mcu, uint8_t *mem, uint32_t size) { - return -1; + if ((mcu->ramsize + 96) != size) { + fprintf(stderr, "Data memory is limited by %u.%03u KiB," + " %u.%03u KiB doesn't match\n", + (mcu->ramsize + 96) / 1024, + (mcu->ramsize + 96) % 1024, + size / 1024, + size % 1024); + return -1; + } + + mcu->data_mem = mem; + + mcu->data_mem[SREG_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[SPH_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[SPL_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[GICR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[GIFR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TIMSK_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TIFR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[SPMCR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TWCR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[MCUCR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[MCUCSR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TCCR0_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TCNT0_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[OSCCAL_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[SFIOR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TCCR1A_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TCCR1B_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TCNT1H_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TCNT1L_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[OCR1AH_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[OCR1AL_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[OCR1BH_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[OCR1BL_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[ICR1H_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[ICR1L_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TCCR2_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TCNT2_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[OCR2_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[ASSR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[WDTCR_ADDR + __SFR_OFFSET] = 0x00; + /* + * From datasheet: + * + * The UBRRH Register shares the same I/O location + * as the UCSRC Register. When doing a write access of this + * I/O location, the high bit of the value written, the + * USART Register Select (URSEL) bit, controls which one of the two + * registers that will be written. + * + * If URSEL is zero during a write operation, the UBRRH value + * will be updated. If URSEL is one, the UCSRC setting will be updated. + * + * // Set UBRRH to 2 + * UBRRH = 0x02; + * + * // Set the USBS and the UCSZ1 bit to one, and + * // the remaining bits to zero. + * UCSRC = (1<<URSEL) | (1<<USBS) | (1<<UCSZ1); + * + * Doing a read access to the UBRRH or the UCSRC Register is a + * more complex operation. The read access is controlled by a + * timed sequence. Reading the I/O location once returns the UBRRH + * Register contents. If the register location was read in previous + * system clock cycle, reading the register in the current clock + * cycle will return the UCSRC contents. Note that the timed + * sequence for reading the UCSRC is an atomic operation. + * Interrupts must therefore be controlled (e.g., by disabling + * interrupts globally) during the read operation. + * + * unsigned char USART_ReadUCSRC(void) + * { + * unsigned char ucsrc; + * // Read UCSRC + * ucsrc = UBRRH; + * ucsrc = UCSRC; + * return ucsrc; + * } + */ + mcu->data_mem[UBRRH_ADDR + __SFR_OFFSET] = 0x00; + /* mcu->data_mem[UCSRC_ADDR + __SFR_OFFSET] = 0x82; */ + mcu->data_mem[EEARH_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[EEARL_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[EECR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[EECR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[PORTB_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[DDRB_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[PINB_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[PORTC_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[DDRC_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[PINC_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[PORTD_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[DDRD_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[PIND_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[SPDR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[SPDR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[SPSR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[SPCR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[UDR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[UCSRA_ADDR + __SFR_OFFSET] = 0x20; + mcu->data_mem[UCSRB_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[UBRRL_ADDR + __SFR_OFFSET] = 0x00; + /* + * ACSR:5(ACO) - The output of the Analog Comparator is synchronized + * and then directly connected to ACO, i.e. it is an analog output. + */ + mcu->data_mem[ACSR_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[ADMUX_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[ADCSRA_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[ADCH_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[ADCL_ADDR + __SFR_OFFSET] = 0x00; + mcu->data_mem[TWDR_ADDR + __SFR_OFFSET] = 0x01; + mcu->data_mem[TWAR_ADDR + __SFR_OFFSET] = 0x02; + mcu->data_mem[TWSR_ADDR + __SFR_OFFSET] = 0x08; + mcu->data_mem[TWBR_ADDR + __SFR_OFFSET] = 0x00; + + return 0; } static int set_fuse_bytes(struct avr *mcu, uint8_t high, uint8_t low) diff --git a/include/avr/sim/sim.h b/include/avr/sim/sim.h index 8dba657..8c4d2bb 100644 --- a/include/avr/sim/sim.h +++ b/include/avr/sim/sim.h @@ -76,7 +76,8 @@ struct avr { avr_flashaddr_t pc; /* Current program counter register */ avr_flashaddr_t reset_pc; /* This is a value used to jump to at reset time. */ - avr_flashaddr_t ivt; + avr_flashaddr_t ivt; /* Address of Interrupt Vectors Table + in program memory. */ uint8_t *sreg; /* Points directly to SREG placed in data section. */ diff --git a/include/avr/sim/simm8a.h b/include/avr/sim/simm8a.h index ccc6244..7ce9b86 100644 --- a/include/avr/sim/simm8a.h +++ b/include/avr/sim/simm8a.h @@ -26,16 +26,94 @@ extern "C" { #endif -/* Public prototypes */ +/* Addresses of the 64 I/O registers */ + +#define SREG_ADDR 0x3F +#define SPH_ADDR 0x3E +#define SPL_ADDR 0x3D +/* Reserved 0x3C */ +#define GICR_ADDR 0x3B +#define GIFR_ADDR 0x3A +#define TIMSK_ADDR 0x39 +#define TIFR_ADDR 0x38 +#define SPMCR_ADDR 0x37 +#define TWCR_ADDR 0x36 +#define MCUCR_ADDR 0x35 +#define MCUCSR_ADDR 0x34 +#define TCCR0_ADDR 0x33 +#define TCNT0_ADDR 0x32 /* Timer/Counter0 (8 Bits) */ +#define OSCCAL_ADDR 0x31 /* Oscillator Calibration Register */ +#define SFIOR_ADDR 0x30 +#define TCCR1A_ADDR 0x2F +#define TCCR1B_ADDR 0x2E +#define TCNT1H_ADDR 0x2D /* Timer/Counter1 – Counter Register + High byte */ +#define TCNT1L_ADDR 0x2C /* Timer/Counter1 – Counter Register + Low byte */ +#define OCR1AH_ADDR 0x2B /* Timer/Counter1 – Output Compare + Register A High byte */ +#define OCR1AL_ADDR 0x2A /* Timer/Counter1 – Output Compare + Register A Low byte */ +#define OCR1BH_ADDR 0x29 /* Timer/Counter1 – Output Compare + Register B High byte */ +#define OCR1BL_ADDR 0x28 /* Timer/Counter1 – Output Compare + Register B Low byte */ +#define ICR1H_ADDR 0x27 /* Timer/Counter1 – Input Capture + Register High byte */ +#define ICR1L_ADDR 0x26 /* Timer/Counter1 – Input Capture + Register Low byte */ +#define TCCR2_ADDR 0x25 +#define TCNT2_ADDR 0x24 /* Timer/Counter2 (8 Bits) */ +#define OCR2_ADDR 0x23 /* Timer/Counter2 Output Compare + Register */ +#define ASSR_ADDR 0x22 +#define WDTCR_ADDR 0x21 +#define UBRRH_ADDR 0x20 /* Refer to the USART description + for details on how to access + UBRRH and UCSRC. */ +#define UCSRC_ADDR 0x20 +#define EEARH_ADDR 0x1F +#define EEARL_ADDR 0x1E +#define EEDR_ADDR 0x1D /* EEPROM Data Register */ +#define EECR_ADDR 0x1C +/* Reserved 0x1B */ +/* Reserved 0x1A */ +/* Reserved 0x19 */ +#define PORTB_ADDR 0x18 +#define DDRB_ADDR 0x17 +#define PINB_ADDR 0x16 +#define PORTC_ADDR 0x15 +#define DDRC_ADDR 0x14 +#define PINC_ADDR 0x13 +#define PORTD_ADDR 0x12 +#define DDRD_ADDR 0x11 +#define PIND_ADDR 0x10 +#define SPDR_ADDR 0x0F /* SPI Data Register */ +#define SPSR_ADDR 0x0E +#define SPCR_ADDR 0x0D +#define UDR_ADDR 0x0C /* USART I/O Data Register */ +#define UCSRA_ADDR 0x0B +#define UCSRB_ADDR 0x0A +#define UBRRL_ADDR 0x09 /* USART Baud Rate Register Low byte */ +#define ACSR_ADDR 0x08 +#define ADMUX_ADDR 0x07 +#define ADCSRA_ADDR 0x06 +#define ADCH_ADDR 0x05 /* ADC Data Register High byte */ +#define ADCL_ADDR 0x04 /* ADC Data Register Low byte */ +#define TWDR_ADDR 0x03 /* Two-wire Serial Interface Data + Register */ +#define TWAR_ADDR 0x02 +#define TWSR_ADDR 0x01 +#define TWBR_ADDR 0x00 /* Two-wire Serial Interface Bit + Rate Register */ -int m8a_init(struct avr *mcu); +/* Public prototypes */ -int m8a_set_progmem(struct avr *mcu, uint16_t *mem, uint32_t size); +int m8a_init(struct avr *mcu, uint16_t *pm, uint32_t pm_size, + uint8_t *dm, uint32_t dm_size); int m8a_load_progmem(struct avr *mcu, FILE *fp); -int m8a_set_datamem(struct avr *mcu, uint8_t *mem, uint32_t size); - /* END Public prototypes */ #ifdef __cplusplus diff --git a/tests/m8a_test.c b/tests/m8a_test.c index bb04089..92c65ff 100644 --- a/tests/m8a_test.c +++ b/tests/m8a_test.c @@ -19,10 +19,18 @@ #include <stdio.h> #include <stdint.h> -#include "minunit.h" +/* + * We would like to include headers specific to the + * ATMega8A microcontroller. + */ +#define __AVR_ATmega8A__ 1 + +#include "avr/io.h" #include "avr/sim/sim.h" #include "avr/sim/bootloader.h" + #include "tools/gis/ihex.h" +#include "minunit.h" #define SUITE_NAME "Atmel ATMega8A tests" @@ -34,6 +42,7 @@ int tests_run = 0; static struct avr m8a; static struct avr_bootloader bldr; static uint16_t prog_mem[4096]; +static uint8_t data_mem[1120]; /* Test functions prototypes */ int m8a_initialized(void); @@ -43,8 +52,9 @@ int m8a_initialized(void) { m8a.boot_loader = &bldr; - _mu_assert(m8a_init(&m8a) == 0); - + _mu_assert(m8a_init(&m8a, prog_mem, + sizeof(prog_mem) / sizeof(prog_mem[0]), data_mem, + sizeof(data_mem) / sizeof(data_mem[0])) == 0); _mu_test(strcmp(m8a.name, "atmega8a") == 0); _mu_test(m8a.spm_pagesize == 64); @@ -79,9 +89,6 @@ int m8a_initialized(void) _mu_test(m8a.e2size == 512); _mu_test(m8a.e2pagesize == 4); - /* - * Reset vector - */ _mu_test(m8a.reset_pc == 0x000); return 0; @@ -100,18 +107,14 @@ int progmem_loaded(void) * ATmega8A. */ while (Read_IHexRecord(&rec, fp) == IHEX_OK) { + /* Print_IHexRecord(&rec); printf("\n"); + */ } rewind(fp); /* - * Assign program memory to the MCU. - */ - _mu_assert(!m8a_set_progmem(&m8a, prog_mem, sizeof(prog_mem)/ - sizeof(prog_mem[0]))); - - /* * Load program memory from the HEX file. */ _mu_test(!m8a_load_progmem(&m8a, fp)); |
