summaryrefslogtreecommitdiff
diff options
authorDmitry Salychev <[email protected]>2017-03-01 11:36:57 +0100
committerDmitry Salychev <[email protected]>2017-03-01 11:36:57 +0100
commit0af8fd652c3d27bd0779782eb3339eb62024cba0 (patch)
treee7a1ba0367ffddfdb04ed65d82863cf7cfcba007
parent3d9961f4ae5a4f632c073d7f2d9d920e868cd041 (diff)
parent58dcb89d1a7c5d8737f99af012ec06919eec1d6a (diff)
downloadmcusim-master.tar.gz
Merge branch 'm8a-data-memory'HEADmaster
-rw-r--r--avr/simm8a.c167
-rw-r--r--include/avr/sim/sim.h3
-rw-r--r--include/avr/sim/simm8a.h88
-rw-r--r--tests/m8a_test.c27
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));