diff --git a/installer/Makefile b/installer/Makefile index 72a2bfe..6e08556 100644 --- a/installer/Makefile +++ b/installer/Makefile @@ -1,4 +1,5 @@ -INSTALLER_ADDRESS=0x1016 +CODE_LOCATION=0x1000 +INSTALLER_ADDRESS=0x1100 CC = sdcc CC_FLAGS = -mmcs51 @@ -8,13 +9,13 @@ AFLAGS= -plosgff SRCS = installer.c OBJS = ${SRCS:.c=.rel} -all: updatebuilder rtlinstall.bin +all: updatebuilder rtlplayground.bin updatebuilder: updatebuilder.c gcc $^ -o $@ -%.rel: %.c - $(CC) $(CC_FLAGS) -–code-loc 0x1000 -c $< +installer.rel: installer.c + $(CC) $(CC_FLAGS) --code-loc ${CODE_LOCATION} -c $< %.rel: %.asm ${ASM} ${AFLAGS} $^ @@ -22,12 +23,12 @@ updatebuilder: updatebuilder.c %.rel: %.c $(CC) $(CC_FLAGS) -c $< -rtlinstall.ihx: crtstart.rel $(OBJS) +rtlinstaller.ihx: crtstart.rel $(OBJS) $(CC) $(CC_FLAGS) -Wl-bHOME=${INSTALLER_ADDRESS} -Wl-r -o $@ $^ -%.bin: %.ihx - objcopy --input-target=ihex -O binary $< $@ +rtlplayground.bin: rtlinstaller.ihx ../rtlplayground.bin + cp ../rtlplayground.bin . + ./updatebuilder -i $< rtlplayground.bin clean: - rm *.lst *.rel *.rst *.sym *.lst *.map *.mem *.lk $(OBJS) - + rm *.ihx *.lst *.rel *.rst *.sym *.lst *.map *.mem *.lk $(OBJS) installer.asm diff --git a/installer/crtstart.asm b/installer/crtstart.asm new file mode 100644 index 0000000..caeb20a --- /dev/null +++ b/installer/crtstart.asm @@ -0,0 +1,26 @@ + .globl __start__stack +;-------------------------------------------------------- +; Stack segment in internal ram +;-------------------------------------------------------- + .area SSEG (DATA) +__start__stack: + .ds 1 + + .area VECTOR (CODE) + .globl __interrupt_vect +__interrupt_vect: + ljmp __sdcc_gsinit_startup + 0x1000 + ljmp _isr_ext0 ; 0x03 + .ds 5 + ljmp _isr_timer0 ; 0x0b + .ds 5 + ljmp _isr_ext1 ; 0x13 + .globl __start__stack + + .area GSINIT0 (CODE) + +__sdcc_gsinit_startup: + mov sp,#__start__stack - 1 + + .area GSFINAL (CODE) + ljmp _installer diff --git a/installer/installer.c b/installer/installer.c index c75373f..c66f06f 100644 --- a/installer/installer.c +++ b/installer/installer.c @@ -4,7 +4,12 @@ // #define REGDBG 1 // #define RXTXDBG 1 +#define UPDATE_LOC 0x0001D000 +#define HEADER_LENGTH 0x14 +#define UPDATE_CODE_LOC (UPDATE_LOC + HEADER_LENGTH) + #include "../rtl837x_sfr.h" +#include "../rtl837x_regs.h" #define SYS_TICK_HZ 100 #define SERIAL_BAUD_RATE 57600 @@ -25,6 +30,12 @@ volatile __xdata uint32_t ticks; volatile __xdata uint8_t sec_counter; volatile __xdata uint16_t sleep_ticks; +// We buffer 1 sector as this is also the erase size +__xdata uint8_t buffer[0x1000]; +__xdata uint8_t dio_enabled; + +__code uint8_t * __code hex = "0123456789abcdef"; + void isr_timer0(void) __interrupt(1) { TR0 = 0; // Stop timer 0 @@ -77,6 +88,20 @@ void print_string(__code char *p) } +void print_byte(uint8_t a) +{ + write_char(hex[(a >> 4) & 0xf]); + write_char(hex[a & 0xf]); +} + +void print_short(uint16_t a) +{ + print_string("0x"); + for (signed char i = 12; i >= 0; i -= 4) { + write_char(hex[(a >> i) & 0xf]); + } +} + void setup_serial(void) { IE = 0; @@ -98,6 +123,214 @@ void setup_serial(void) ES = 1; // Enable serial IRQ } +/* + * Configure Memory Managed IO + */ +void flash_configure_mmio(void) +{ + // Set configuration for MMIO access by controller + if (dio_enabled) { + SFR_FLASH_MODEB = 0x18; + SFR_FLASH_CMD_R = 0xbb; // By default we read with Dual speed + SFR_FLASH_DUMMYCYCLES = 4; + return; + } + + SFR_FLASH_MODEB = 0x0; + SFR_FLASH_CMD_R = 0xb; // By default we read with single speed + SFR_FLASH_DUMMYCYCLES = 8; +} + + +/* + * Initializes the flash controller for programmed control + * The configuration options are not really understood, the SPI speed + * seems to be directly linked to the CPU frequency + * This configures fast single IO at 20.8 MHz when the CPU clock is at 20.8MHz + * and 62.5MHz when the CPU clock is configured at 125MHz + */ +void flash_init(uint8_t enable_dio) +{ + if (enable_dio) { + // Configure fast DIO via divider/DIO/SIOconfig = 4 and read-cmd being 0xbb (for mmio) + SFR_FLASH_CONFIG = 9; // There may be a chip-select in here + SFR_FLASH_CONF_RCMD = 0xbb; + SFR_FLASH_CONF_DIV = 4; + } else { + // Configure fast read via divider = 8 and read-cmd being 0xb (for mmio) + SFR_FLASH_CONFIG = 9; + SFR_FLASH_CONF_RCMD = 0xb; + SFR_FLASH_CONF_DIV = 8; + } + // Test Controller Busy + while(SFR_FLASH_EXEC_BUSY); + + // Write 0 to status register + SFR_FLASH_DUMMYCYCLES = 8; + SFR_FLASH_MODEB = 0; + SFR_FLASH_TCONF = 0x19; + SFR_FLASH_CMD = 1; + SFR_FLASH_DATA0 = 0; + SFR_FLASH_EXEC_GO = 1; + while(SFR_FLASH_EXEC_BUSY); + + dio_enabled = enable_dio; + flash_configure_mmio(); +} + + +uint8_t flash_read_status(void) +{ + // Test Controller Busy (we might call this directly after executing a command) + while(SFR_FLASH_EXEC_BUSY); + + // setup status read command + SFR_FLASH_TCONF = 0x11; + SFR_FLASH_CMD_R = 5; + + // execute and wait for controller done + SFR_FLASH_EXEC_GO = 1; + while(SFR_FLASH_EXEC_BUSY); + + return SFR_FLASH_DATA0; +} + + +/* + * Reads bulk data of length len from the flash memory starging at address src + * and writes the data into a buffer pointed to by dst in XMEM + */ +void flash_read_bulk(register __xdata uint8_t *dst, __xdata uint32_t src, register uint16_t len) +{ + short status; + do { + status = flash_read_status(); + } while (status & 0x1); + + // Set fast read mode + if (dio_enabled) { + SFR_FLASH_MODEB = 0x18; + SFR_FLASH_CMD_R = 0xbb; + SFR_FLASH_DUMMYCYCLES = 4; + } else { + SFR_FLASH_MODEB = 0x0; + SFR_FLASH_CMD_R = 0xb; // Fast read + SFR_FLASH_DUMMYCYCLES = 8; // Add 8 dummy clocks after read? + } + // Read 4 bytes + SFR_FLASH_TCONF = 4; + while (len) { + SFR_FLASH_ADDR16 = src >> 16; + SFR_FLASH_ADDR8 = src >> 8; + SFR_FLASH_ADDR0 = src; + src += 4; + + SFR_FLASH_EXEC_GO = 1; + while(SFR_FLASH_EXEC_BUSY); + + *dst++ = SFR_FLASH_DATA0; + if (len == 1) + return; + *dst++ = SFR_FLASH_DATA8; + if (len == 2) + return; + *dst++ = SFR_FLASH_DATA16; + if (len == 3) + return; + *dst++ = SFR_FLASH_DATA24; + + len -= 4; + } +} + + +void flash_write_enable(void) +{ + short status; + + // Wait until busy bit clear + do { + status = flash_read_status(); + } while (status & 0x1); +// while (flash_read_status() & 0x1); + + SFR_FLASH_TCONF = 0x18; + SFR_FLASH_CMD = 6; +// The following is explicitly set for SIO, is this necessary?: + SFR_FLASH_DUMMYCYCLES = 0; + SFR_FLASH_MODEB = 0; + + SFR_FLASH_EXEC_GO = 1; + // Wait for write status enabled + do { + status = flash_read_status(); + } while (!(status & 0x2)); +} + + +// Erases the 4k sector in which the address lies +void flash_sector_erase(uint32_t addr) +{ + flash_write_enable(); + SFR_FLASH_TCONF = 8; + SFR_FLASH_CMD = 0x20; + + SFR_FLASH_ADDR16 = addr >> 16; + SFR_FLASH_ADDR8 = addr >> 8; + SFR_FLASH_ADDR0 = addr; + + SFR_FLASH_EXEC_GO = 1; + while (flash_read_status() & 0x1); + + flash_configure_mmio(); + +} + + +void flash_write_bytes(__xdata uint32_t addr, __xdata uint8_t *ptr, uint16_t len) +{ + uint8_t exit_loop = 0; + + while(1) { + flash_write_enable(); + SFR_FLASH_CMD = 2; + SFR_FLASH_TCONF = 0x40 | 8 | 4; // Bytes written is 4, 8 enables write, 0x40 is unknown + // Last transfer? + if (len < 5) { + SFR_FLASH_TCONF = 8 | len; + exit_loop = 1; + } + + SFR_FLASH_ADDR16 = addr >> 16; + SFR_FLASH_ADDR8 = addr >> 8; + SFR_FLASH_ADDR0 = addr; + SFR_FLASH_DATA0 = *ptr++; + SFR_FLASH_DATA8 = *ptr++; + SFR_FLASH_DATA16 = *ptr++; + SFR_FLASH_DATA24 = *ptr++; + + // Execute transfer, we wait for completion at top of loop + SFR_FLASH_EXEC_GO = 1; + if (exit_loop) + break; + len -= 4; + addr += 4; + } + + while (flash_read_status() & 0x1); + flash_configure_mmio(); +} + + +void reg_write(uint16_t reg_addr) +{ + /* Data to write must be in SFR A4, A5, A6, A7 */ + SFR_REG_ADDR_U16 = reg_addr; + SFR_EXEC_GO = SFR_EXEC_WRITE_REG; + do { + } while (SFR_EXEC_STATUS != 0); +} + void installer(void) { @@ -117,6 +350,27 @@ void installer(void) EA = 0; // SFR A8.7 / IE.7 setup_serial(); - while (1) - print_string("Image installer running\n"); + print_string("\nRTLPlayground installer starting...\n"); + + // Initialize flash functions with disable DIO because writing does not work otherwise + flash_init(0); + + __xdata uint32_t dest = 0x0; + __xdata uint32_t source = UPDATE_CODE_LOC; + // A 512kByte = 4MBit Flash has 128 sectors, we copy only 120 + for (uint8_t i=0; i < 120; i++) { + print_string("Moving block\n"); + flash_read_bulk(buffer, source, 0x1000); + for (uint8_t j = 0; j < 32; j++) { + write_char(' '); print_byte(buffer[j]); + } + write_char('\n'); + flash_sector_erase(dest); + flash_write_bytes(dest, buffer, 0x1000); + dest += 0x1000; + source += 0x1000; + } + print_string("Done.\n"); + print_string("Reseting now\n"); + REG_SET(RTL837X_REG_RESET, 1); } diff --git a/installer/updatebuilder.c b/installer/updatebuilder.c index a8c14ef..1ec6a15 100644 --- a/installer/updatebuilder.c +++ b/installer/updatebuilder.c @@ -27,6 +27,7 @@ uint8_t buffer[BUFFER_SIZE]; FILE *inptr; int outptr; +char line[256]; const char *argp_program_version = "updatebuilder 0.1"; const char *argp_program_bug_address = ""; @@ -49,6 +50,32 @@ struct arguments { }; +int get_byte(int pos) +{ + int c1 = line[pos]; + if (c1 >= '0' && c1 <= '9') + c1 -= '0'; + else if (c1 >= 'a' && c1 <= 'f') + c1 = c1 - 'a' + 10; + else if (c1 >= 'A' && c1 <= 'F') + c1 = c1 - 'A' + 10; + else + return -1; + + int c2 = line[pos + 1]; + if (c2 >= '0' && c2 <= '9') + c2 -= '0'; + else if (c2 >= 'a' && c2 <= 'f') + c2 = c2 - 'a' + 10; + else if (c2 >= 'A' && c2 <= 'F') + c2 = c2 - 'A' + 10; + else + return -1; + + return c1 << 4 | c2; +} + + static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; @@ -110,7 +137,7 @@ int main(int argc, char **argv) printf("File too large.\n"); return 5; } - size_t bytes_read = fread(buffer + SEG_1d000_OFFSET + HEADER_LENGTH, 1, sizeof(buffer), inptr); + size_t bytes_read = fread(buffer + SEG_1d000_OFFSET + 2 * HEADER_LENGTH, 1, sizeof(buffer), inptr); printf("Bytes read: %ld\n", bytes_read); @@ -119,31 +146,60 @@ int main(int argc, char **argv) return 5; } fclose(inptr); - filesize += SEG_1d000_OFFSET + HEADER_LENGTH; + filesize += SEG_1d000_OFFSET + 2 * HEADER_LENGTH; + // Read the installer file, which is in Intel Hex format if (arguments.installer_file) { inptr = fopen(arguments.installer_file, "rb"); if (inptr == NULL) { printf("Cannot open installer file %s\n", arguments.installer_file); return 5; } - - fseek(inptr, 0L, SEEK_END); - size_t isize = ftell(inptr); - rewind(inptr); - printf("Installer file size: %ld\n", isize); - if (isize > SEG_01002_LENGTH) { - printf("File too large.\n"); - return 5; + int line_num = 1; + int address_high = 0; + bool eof = false; + while(fgets(line, 255, inptr)) { + if (line[0] != ':') { + printf("Unknwon installer file format for %s\n", arguments.installer_file); + return 5; + } + int bytes = get_byte(1); + if (bytes < 0 || bytes > 200) { + printf("Error in %s, line %d, incorrect byte number\n", arguments.installer_file, line_num); + return 5; + } + int address = (get_byte(3) *256) + get_byte(5); + if (address < 0) { + printf("Error in %s, line %d, not an address\n", arguments.installer_file, line_num); + return 5; + } + int type = get_byte(7); + if (type < 0 || type > 5) { + printf("Error in %s, line %d incorrect type\n", arguments.installer_file, line_num); + return 5; + } + if (type == 0) { + for (int i = 0; i < bytes; i++) { + int data = get_byte(9 + 2 * i); + if (data < 0) { + printf("Error in %s, line %d, illegal data byte\n", arguments.installer_file, line_num); + return 5; + } else { + address = address > 0x1000 ? address - 0x1000 : address; + buffer[address + HEADER_LENGTH + i] = data; + } + } + } else if (type == 1) { + eof = true; + printf("EOF\n"); + } else { + printf("UNKNOWN type, line %d\n", line_num); + } + line_num++; } - size_t bytes_read = fread(buffer + HEADER_LENGTH, 1, sizeof(buffer), inptr); + if (!eof) + printf("Something was wrong: EOF not found\n"); - printf("Bytes read: %ld\n", bytes_read); - - if (bytes_read != isize) { - printf("Error reading input file.\n"); - return 5; - } fclose(inptr); }