diff options
| -rw-r--r-- | Makefile | 68 | ||||
| -rw-r--r-- | asm/crt0.asm | 75 | ||||
| -rw-r--r-- | boot/Makefile | 62 | ||||
| -rw-r--r-- | boot/boot.asm | 128 | ||||
| -rw-r--r-- | boot/bootloader.c | 376 | ||||
| -rw-r--r-- | boot/cmd/Makefile | 12 | ||||
| -rw-r--r-- | boot/cmd/main.c | 4 | ||||
| -rw-r--r-- | boot/crt0.asm | 88 | ||||
| -rw-r--r-- | boot/devmode/Makefile | 12 | ||||
| -rw-r--r-- | boot/devmode/bootloader.c | 339 | ||||
| -rw-r--r-- | boot/devmode/crc16.c (renamed from boot/crc16.c) | 30 | ||||
| -rw-r--r-- | boot/devmode/devmode.h | 42 | ||||
| -rw-r--r-- | boot/main.c | 7 | ||||
| -rw-r--r-- | include.mk | 48 | ||||
| -rw-r--r-- | payload.mk | 4 | 
15 files changed, 725 insertions, 570 deletions
| @@ -1,66 +1,34 @@ -PROJECT=firmware +export PROJECT_ROOT=$(abspath .) -AS=sdasz80 -CC=sdcc -CPP=sdcpp - -ASM=crt0.asm\ -	isr.asm\ -	delay.asm -SRC=font.c\ -	i2c.c\ -	input.c\ -	main.c\ -	tft.c\ -	tty.c\ -	menu.c - -INCLUDE=include  BUILD=build -OBJ=$(ASM:%.asm=$(BUILD)/%.rel)\ -	$(SRC:%.c=$(BUILD)/%.rel) - -IHX=$(BUILD)/$(PROJECT).ihx -TARGET=$(BUILD)/$(PROJECT).hex +TARGET=$(BUILD)/rom.hex  BOOTLOADER=$(BUILD)/boot/bootloader.hex +FIRMWARE=$(BUILD)/firmware.hex -CFLAGS=-mz80 -I$(INCLUDE) --Werror -LDFLAGS=-mz80 --no-std-crt0\ -		--code-loc 0x0100\ -		--data-loc 0x8010\ -		-Wl-b_ISR_TABLE=0x0070\ -		-Wl-b_GSINIT=0x0080 +CODE_LOC=0x8100 +DATA_LOC=0xC000 +STACK_LOC=0x0000 +GSINIT_LOC=0x8080  ROM_CHIP=AT28C256 -all : $(TARGET) - -$(OBJ): | $(BUILD) +DIRS=$(addprefix $(BUILD)/,asm src) -$(BUILD): -	@mkdir -p $(BUILD) +ASM=$(wildcard asm/*.asm) +SRC=$(wildcard src/*.c) -$(BUILD)/%.rel : asm/%.asm -	@echo '  (AS)' $< -	@$(CPP) -P -I$(INCLUDE) -DASSEMBLY $< > $(BUILD)/$(notdir $<) -	@$(AS) -g -o $@ $(BUILD)/$(notdir $<) - -$(BUILD)/%.rel : src/%.c -	@echo '  (CC)' $< -	@$(CC) $(CFLAGS) -c -o $@ $< - -$(IHX) : $(OBJ) -	@echo '  (LD)' $(OBJ) -	@$(CC) $(LDFLAGS) -o $@ $(OBJ) +all : $(TARGET) -$(TARGET) : $(IHX) $(BOOTLOADER) -	@hex2bin.py -l 32768 $< $@ -	@dd if=$(BOOTLOADER) of=$@ obs=1024 seek=28 conv=notrunc 2>/dev/null +$(TARGET) : $(BOOTLOADER) $(FIRMWARE) +	cat $^ > $@ +	cp $(BOOTLOADER) /tmp/rom.hex +	dd if=$(FIRMWARE) of=/tmp/rom.hex obs=4096 seek=3 conv=notrunc 2>/dev/null +	mv /tmp/rom.hex $@  .PHONY : $(BOOTLOADER)  $(BOOTLOADER) : -	@make -C boot +	make -C boot  .PHONY : flash  flash : @@ -69,3 +37,5 @@ flash :  .PHONY : clean  clean :  	@find $(BUILD) -type f -delete + +include include.mk diff --git a/asm/crt0.asm b/asm/crt0.asm index fd03997..a53c9e8 100644 --- a/asm/crt0.asm +++ b/asm/crt0.asm @@ -1,32 +1,17 @@  #include <hardware.h> -    .module crt0 -    .globl  _main +	.module	crt0 +	.globl	_main  	.area	_HEADER (ABS) -    .org    0x0000 +	.org	0x8000  start: -    di -    xor     a -    ld      i, a -    ld      sp, #0x0000 -    ;; Init PIO and check for KEY2 -    ld      a, #PIO_MODE_3 -    out     (PORT_B_CTRL), a -    ld      a, #0x7F -    out     (PORT_B_CTRL), a -    in      a, (PORT_B_DATA) -    and     #KEY2               ; is KEY2 pressed? If so, start booloader -    jr      NZ, main -    ;; Load payload (bootloader) -    ld      hl, #0x7000         ; src -    ld      de, #0x8000         ; dest -    ld      bc, #0x1000         ; size -    ldir -    ;; Start bootloader -    jp      0x8000 +	di +	ld	a, #0x80 +	ld	i, a +	ld	sp, #0x0000  main: -    call	gsinit +	call	gsinit  	call	_main  1$:  	halt @@ -36,44 +21,44 @@ main:  	.area	_HOME  	.area	_CODE  	.area	_INITIALIZER -	.area   _GSINIT -	.area   _GSFINAL +	.area	_GSINIT +	.area	_GSFINAL  	.area	_DATA  	.area	_INITIALIZED  	.area	_BSEG -	.area   _BSS -	.area   _HEAP +	.area	_BSS +	.area	_HEAP -	.area   _CODE +	.area	_CODE -	.area   _GSINIT +	.area	_GSINIT  gsinit:  	;; Default-initialized global variables. -    ld      bc, #l__DATA -    ld      a, b -    or      a, c -    jr      Z, zeroed_data -    ld      hl, #s__DATA -    ld      (hl), #0x00 -    dec     bc -    ld      a, b -    or      a, c -    jr      Z, zeroed_data -    ld      e, l -    ld      d, h -    inc     de -    ldir +	ld	bc, #l__DATA +	ld	a, b +	or	a, c +	jr	z, zeroed_data +	ld	hl, #s__DATA +	ld	(hl), #0x00 +	dec	bc +	ld	a, b +	or	a, c +	jr	z, zeroed_data +	ld	e, l +	ld	d, h +	inc	de +	ldir  zeroed_data:  	;; Explicitly initialized global variables.  	ld	bc, #l__INITIALIZER  	ld	a, b  	or	a, c -	jr	Z, gsinit_next +	jr	z, gsinit_next  	ld	de, #s__INITIALIZED  	ld	hl, #s__INITIALIZER  	ldir  gsinit_next: -	.area   _GSFINAL +	.area	_GSFINAL  	ret diff --git a/boot/Makefile b/boot/Makefile index 2fff22d..88d3c6e 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -1,50 +1,32 @@ -AS=sdasz80 -CC=sdcc -CPP=sdcpp +BUILD=$(PROJECT_ROOT)/build/boot -ASM=crt0.asm -SRC=crc16.c\ -	bootloader.c - -INCLUDE=../include -BUILD=../build/boot - -OBJ=$(ASM:%.asm=$(BUILD)/%.rel)\ -	$(SRC:%.c=$(BUILD)/%.rel) - -IHX=$(BUILD)/bootloader.ihx  TARGET=$(BUILD)/bootloader.hex +IHX=$(BUILD)/boot.ihx -CFLAGS=-mz80 -I$(INCLUDE) --Werror -LDFLAGS=-mz80 --no-std-crt0\ -		--code-loc 0x8100\ -		--data-loc 0xC000\ -		--stack-loc 0x0000\ -		-Wl-b_GSINIT=0x8080 +ASM=$(filter-out crt0.asm, $(wildcard *.asm)) +SRC=$(wildcard *.c) +PAYLOADS=cmd devmode -all : $(TARGET) - -$(OBJ): | $(BUILD) +PAYLOADS_HEX=$(foreach payload,$(PAYLOADS),$(BUILD)/$(payload)/$(payload).hex) -$(BUILD) : -	@mkdir -p $(BUILD) +HEX=$(BUILD)/boot.hex $(PAYLOADS_HEX) -$(BUILD)/%.rel : %.asm -	@echo '  (AS)' $< -	@$(CPP) -P -I$(INCLUDE) -DASSEMBLY $< > $(BUILD)/$(notdir $<) -	@$(AS) -g -o $@ $(BUILD)/$(notdir $<) +CODE_LOC=0x0120 +DATA_LOC=0xC000 +STACK_LOC=0x0000 +GSINIT_LOC=0x0090 -$(BUILD)/%.rel : %.c -	@echo '  (CC)' $< -	@$(CC) $(CFLAGS) -c -o $@ $< +all : $(TARGET) -$(IHX) : $(OBJ) -	@echo '  (LD)' $(OBJ) -	@$(CC) $(LDFLAGS) -o $@ $(OBJ) +$(TARGET) : $(HEX) +	cp $(BUILD)/boot.hex /tmp/bootloader.hex +	dd if=$(BUILD)/cmd/cmd.hex of=/tmp/bootloader.hex obs=4096 seek=1 conv=notrunc 2>/dev/null +	dd if=$(BUILD)/cmd/cmd.hex of=/tmp/bootloader.hex obs=4096 seek=2 conv=notrunc 2>/dev/null +	mv /tmp/bootloader.hex $@ -$(TARGET) : $(IHX) -	@hex2bin.py $< $@ +.PHONY : $(PAYLOADS_HEX) +$(PAYLOADS_HEX) : $(BUILD)/crt0.rel +	make -C $(notdir $(basename $@)) CRT0=$< -.PHONY : clean -clean : -	@find $(BUILD) -type f -delete +include $(PROJECT_ROOT)/include.mk +-include $(BUILD)/crt0.d diff --git a/boot/boot.asm b/boot/boot.asm new file mode 100644 index 0000000..b598d6e --- /dev/null +++ b/boot/boot.asm @@ -0,0 +1,128 @@ +#include <hardware.h> +	.module	boot +	.globl	_main + +	.area	_HEADER (ABS) +	.org	0x0000 +rst_0: +	di +	jr	start +	.org	0x0008 +rst_1: +	.org	0x0010 +rst_2: +	.org	0x0018 +rst_3: +	.org	0x0020 +rst_4: +	.org	0x0028 +rst_5: +	.org	0x0030 +rst_6: +	.org	0x0038 +rst_7: +	.org	0x0040 +start: +	xor	a +	ld	i, a +	ld	sp, #0x0000 +	;; Init PIO +	ld	a, #PIO_MODE_3 +	out	(PORT_B_CTRL), a +	ld	a, #0x7F +	out	(PORT_B_CTRL), a +	;; Check keys +	in	a, (PORT_B_DATA) +	bit	KEY2_BIT, a +	jr	z, development_mode +	bit	KEY3_BIT, a +	jr	z, command_line +	;; No payload selected; try to load os from sd card +	jr	temporary_payload +main: +	call	gsinit +	call	_main +1$: +	halt +	jr	1$ + +;;; ROM Payloads +development_mode: +	ld	hl, #0x1000	; src +	ld	de, #0x8000	; dest +	ld	bc, #0x1000	; size +	ldir +	jp	0x8000 +command_line: +	ld	hl, #0x2000	; src +	ld	de, #0x8000	; dest +	ld	bc, #0x1000	; size +	ldir +	jp	0x8000 +temporary_payload: +	ld	hl, #0x3000	; src +	ld	de, #0x8000	; dest +	ld	bc, #0x5000	; size +	ldir +	jp	0x8000 + +;;; Interrupt table +	.org	0x0100 +_ctc0_isr_ptr:: +	.dw	#0 +_ctc1_isr_ptr:: +	.dw	#0 +_ctc2_isr_ptr:: +	.dw	#0 +_ctc3_isr_ptr:: +	.dw	#0 +_port_a_isr_ptr:: +	.dw	#0 +_port_b_isr_ptr:: +	.dw	#0 +_rx_isr_ptr:: +	.dw	#0 + +	;; Ordering of segments for the linker. +	.area	_HOME +	.area	_CODE +	.area	_INITIALIZER +	.area	_GSINIT +	.area	_GSFINAL +	.area	_DATA +	.area	_INITIALIZED +	.area	_BSEG +	.area	_BSS +	.area	_HEAP +	.area	_CODE +	.area	_GSINIT + +gsinit: +	;; Default-initialized global variables. +	ld	bc, #l__DATA +	ld	a, b +	or	a, c +	jr	Z, zeroed_data +	ld	hl, #s__DATA +	ld	(hl), #0x00 +	dec	bc +	ld	a, b +	or	a, c +	jr	Z, zeroed_data +	ld	e, l +	ld	d, h +	inc		de +	ldir +zeroed_data: +	;; Explicitly initialized global variables. +	ld	bc, #l__INITIALIZER +	ld	a, b +	or	a, c +	jr	Z, gsinit_next +	ld	de, #s__INITIALIZED +	ld	hl, #s__INITIALIZER +	ldir + +gsinit_next: +	.area	_GSFINAL +	ret diff --git a/boot/bootloader.c b/boot/bootloader.c deleted file mode 100644 index 042414b..0000000 --- a/boot/bootloader.c +++ /dev/null @@ -1,376 +0,0 @@ -#include <hardware.h> -#include <zeta.h> -#include <fifo.h> - -#include <assert.h> -#include <stddef.h> -#include <string.h> - -#ifdef __GNUC__ -#define PACKED __attribute__((packed)) -#else -#define PACKED -#endif - -u16 -crc16(const void *buf, size_t len); - -enum header_type { -    CMD_PING, -    CMD_INFO, -    CMD_BOOT, -    CMD_READ, -    CMD_WRITE, -    CMD_IO_READ, -    CMD_IO_WRITE, -    CMD_ECHO -}; - -struct header { -    u8 type; -    u8 bank; -    u16 address; -    u16 length; -    u16 checksum; -} PACKED; - -// static_assert(sizeof(struct header) == 8, "struct header is not PACKED"); - -enum error { -    ERR_TIMEOUT = -1 -}; - -#define MAX_PACKET_SIZE 256 -#define TIMEOUT_MS 500 -#define MAX_ATTEMPTS 3 -#define MAX_TRANS_ATTEMPTS 5 - -u16 -crc16(const void *buf, size_t len); - -volatile struct fifo rx_fifo = {0, 0, {0}}; - -enum ack { -    ACK = 0x00, -    NACK = 0xFF -}; - -void -rx_isr(void) __critical __interrupt(0) -{ -    fifo_push(&rx_fifo, sio_a_data); -} - -static volatile uint32_t millis = 0; - -void -ctc1_isr(void) __critical __interrupt(1) -{ -    millis += 5; -} - -uint32_t -clock(void) -{ -    volatile uint32_t ret; -    DI; -    ret = millis; -    EI; -    return ret; -} - -void -putbyte(unsigned char b) -{ -    unsigned char ctrl = 0; - -    sio_a_data = b; - -    while (!(ctrl & 0x04)) { -        sio_a_ctrl = 0; -        ctrl = sio_a_ctrl; -    } -} - -static volatile int32_t errno = 0; - -u8 -getbyte(void) -{ -    u8 b; -    uint32_t ms = clock(); -    errno = 0; -    while (fifo_empty(&rx_fifo)) { -        if (clock() - ms > TIMEOUT_MS) { -            errno = ERR_TIMEOUT; -            return 0; -        } -    } -    DI; -    b = fifo_pop(&rx_fifo); -    EI; -    return b; -} - -void -flush(void) -{ -    DI; -    fifo_clear(&rx_fifo); -    EI; -} - - -// Hamming(7,4) encoding -u8 -encode(u8 x) -{ -    u8 y = 0; -    const u8 c[4] = {0x61, 0x52, 0x34, 0x78}; - -    for (u8 i = 0; i < 4; ++i) -        y ^= ((x >> i) & 1) ? c[i] : 0; - -    return y; -} - -// Hamming(7,4) decoding -u8 -decode(u8 x) -{ -    u8 p = 0; -    const u8 r[7] = {6, 5, 3, 7, 1, 2, 4}; - -    for (int i = 0; i < 7; ++i) -        p ^= ((x >> i) & 1) ? r[i] : 0; - -    // Assume simple error, attempt correction -    if (p) { -        size_t i = 0; - -        for (i = 0; i < LENGTH(r); ++i) { -            if (r[i] == x) -                break; -        } - -        x ^= (1 << i); -    } - -    return x & 0x0F; -} - - -int -read(void *buf, size_t count) -{ -    u8 b; -    u8 *p = buf; - -    for (int n = 0; n < count; ++n) { -        b = decode(getbyte()); -        if (errno) -            return errno; - -        b |= (decode(getbyte()) << 4); -        if (errno) -            return errno; - -        p[n] = b; -    } - -    return 0; -} - -int -write(const void *buf, size_t count) -{ -    const u8 *p = buf; - -    for (size_t i = 0; i < count; ++i) { -        putbyte(encode(p[i] & 0x0F)); -        putbyte(encode((p[i] >> 4) & 0x0F)); -    } - -    return 0; -} - -int -read_header(struct header *header) -{ -    int err; -    u8 ack; -    u16 checksum; - -    while (1) { -        if ((err = read(header, sizeof(*header)))) -            return err; - -        checksum = header->checksum; -        header->checksum = 0; - -        if (checksum == crc16(header, sizeof(*header))) { -            header->checksum = checksum; -            ack = ACK; -            write(&ack, sizeof(ack)); -            return 0; -        } else { -            ack = NACK; -            write(&ack, sizeof(ack)); -        } -    } -} - -int -read_buf(size_t len, void *buf) -{ -    int err; -    u8 ack; -    u16 checksum; - -    for (int i = 0; i < MAX_TRANS_ATTEMPTS; ++i) { -        // TODO: reduce code? -        if ((err = read(&checksum, sizeof(checksum))) -            || (err = read(buf, len))) -            break; - -        if (checksum == crc16(buf, len)) { -            ack = ACK; -            write(&ack, sizeof(ack)); -            return 0; -        } else { -            ack = NACK; -            write(&ack, sizeof(ack)); -        } -    } - -    return -1; -} - -int -write_buf(size_t len, const void *buf) -{ -    int err; -    u8 ack = NACK; -    u16 checksum = crc16(buf, len); - -    for (int i = 0; i < MAX_TRANS_ATTEMPTS; ++i){ -        write(&checksum, sizeof(checksum)); -        write(buf, len); - -        // If TIMEOUT sending just give up -        if ((err = read(&ack, sizeof(ack)))) -            return err; - -        if (ack == ACK) -            return 0; -    } - -    return -1; -} - -// TODO: Restart after timeouts -void -loop(void) -{ -    struct header header; -    u8 buf[MAX_PACKET_SIZE]; - -    while (1) { -        if (read_header(&header)) { -            flush(); -            continue; -        } - -        switch (header.type) { -        case CMD_BOOT: -            ((void (*)(void))header.address)(); -            break; - -        case CMD_READ: -            write_buf(header.length, (const void *)header.address); -            break; - -        case CMD_WRITE: -            if (!read_buf(header.length, buf)) -                memcpy((void *)header.address, buf, header.length); -            break; - -        case CMD_ECHO: -            if (!read_buf(header.length, buf)) -                write_buf(header.length, buf); -            break; - -        default: -            break; -        } - -        flush(); -    } -} - -static inline void -init_ctc(void) -{ -	ctc_channel_0 = CTC_CTRL(0); - -	/* 200Hz clock */ -	ctc_channel_1 = CTC_CTRL(CTC_INT_BIT | CTC_PRESCALER_BIT -							 | CTC_TIME_CONST_BIT | CTC_RST_BIT); -	ctc_channel_1 = 0; - -	ctc_channel_2 = CTC_CTRL(0); -	ctc_channel_3 = CTC_CTRL(0); - -	// Interrupt table for CTC -	// Final address is (Ireg << 8) | ctc_isr_ptr | {00/01/10/11} | 0 -	ctc_channel_0 = CTC_INT_VEC(0x10); -} - -static inline void -init_pio(void) -{ -	// Disable PIO interrupts -	port_a_ctrl = PIO_INT_CTRL(0); -	port_b_ctrl = PIO_INT_CTRL(0); -} - -static inline void -init_sio(void) -{ -	static const u8 sio_a_cfg[] = { -		0b00011000,                      // Reset channel -		4         ,                      // wr4 -		0b01000100,                      // X16 clock (115200), one stop bit, no parity -		1         ,                      // wr1 -		SIO_RX_INT_MD0 | SIO_RX_INT_MD1, // interrupt on every Rx, no wait function -		3         ,                      // wr3 -		0b11000001,                      // enable Rx - 8 bit char -		5         ,                      // wr5 -		0b01101000                       // enable Tx - 8 bit char -	}; - -	static const u8 sio_b_cfg[] = { -		0b00011000,                     // Reset channel -		2         ,                     // load interrupt vector -		0x1C                            // int_table_rx -	}; - -    for (u8 i = 0; i < LENGTH(sio_a_cfg); ++i) -        sio_a_ctrl = sio_a_cfg[i]; - -    for (u8 i = 0; i < LENGTH(sio_b_cfg); ++i) -        sio_b_ctrl = sio_b_cfg[i]; -} - -void -main(void) -{ -	init_ctc(); -	init_pio(); -	init_sio(); - -	IM(2); -	EI; - -	loop(); -} diff --git a/boot/cmd/Makefile b/boot/cmd/Makefile new file mode 100644 index 0000000..5c359e4 --- /dev/null +++ b/boot/cmd/Makefile @@ -0,0 +1,12 @@ +BUILD=$(PROJECT_ROOT)/build/boot/cmd + +TARGET=$(BUILD)/cmd.hex +IHX=$(BUILD)/cmd.ihx + +ASM=$(wildcard *.asm) +SRC=$(wildcard *.c) + +all : $(TARGET) $(PROJECT_ROOT)/payload.mk + +include $(PROJECT_ROOT)/payload.mk +include $(PROJECT_ROOT)/include.mk diff --git a/boot/cmd/main.c b/boot/cmd/main.c new file mode 100644 index 0000000..b363531 --- /dev/null +++ b/boot/cmd/main.c @@ -0,0 +1,4 @@ +void +main(void) +{ +} diff --git a/boot/crt0.asm b/boot/crt0.asm index 09e4166..e7177ed 100644 --- a/boot/crt0.asm +++ b/boot/crt0.asm @@ -1,69 +1,67 @@  #include <hardware.h> -    .module crt0 -    .globl  _main +	.module	crt0 +	.globl	_main  	.area	_HEADER (ABS) -    .org    0x8000 +	.org	0x8000  start: -    di -    ld      a, #0x80 -    ld      i, a -    ld      sp, #0x0000 -    jr      main -    .org    0x8010 +	ld	a, #0x80 +	ld	i, a +	ld	sp, #0x0000 +main: +	call	gsinit +	call	_main +1$: +	halt +	jr	1$ + +;;; Interrupt table +	.org	0x8020  _ctc0_isr_ptr:: -    .dw     #0 +	.dw	#0  _ctc1_isr_ptr:: -    .dw     #_ctc1_isr +	.dw	#0  _ctc2_isr_ptr:: -    .dw     #0 +	.dw	#0  _ctc3_isr_ptr:: -    .dw     #0 +	.dw	#0  _port_a_isr_ptr:: -    .dw     #0 +	.dw	#0  _port_b_isr_ptr:: -    .dw     #0 +	.dw	#0  _rx_isr_ptr:: -    .dw     #_rx_isr -main: -    call	gsinit -	call	_main -1$: -	halt -	jr	1$ +	.dw	#0  	;; Ordering of segments for the linker.  	.area	_HOME  	.area	_CODE  	.area	_INITIALIZER -	.area   _GSINIT -	.area   _GSFINAL - +	.area	_GSINIT +	.area	_GSFINAL  	.area	_DATA  	.area	_INITIALIZED  	.area	_BSEG -	.area   _BSS -	.area   _HEAP - -	.area   _CODE +	.area	_BSS +	.area	_HEAP +	.area	_CODE +	.area	_GSINIT -	.area   _GSINIT  gsinit:  	;; Default-initialized global variables. -    ld      bc, #l__DATA -    ld      a, b -    or      a, c -    jr      Z, zeroed_data -    ld      hl, #s__DATA -    ld      (hl), #0x00 -    dec     bc -    ld      a, b -    or      a, c -    jr      Z, zeroed_data -    ld      e, l -    ld      d, h -    inc     de -    ldir +	ld	bc, #l__DATA +	ld	a, b +	or	a, c +	jr	Z, zeroed_data +	ld	hl, #s__DATA +	ld	(hl), #0x00 +	dec	bc +	ld	a, b +	or	a, c +	jr	Z, zeroed_data +	ld	e, l +	ld	d, h +	inc		de +	ldir  zeroed_data:  	;; Explicitly initialized global variables.  	ld	bc, #l__INITIALIZER @@ -75,5 +73,5 @@ zeroed_data:  	ldir  gsinit_next: -	.area   _GSFINAL +	.area	_GSFINAL  	ret diff --git a/boot/devmode/Makefile b/boot/devmode/Makefile new file mode 100644 index 0000000..24c841a --- /dev/null +++ b/boot/devmode/Makefile @@ -0,0 +1,12 @@ +BUILD=$(PROJECT_ROOT)/build/boot/devmode + +TARGET=$(BUILD)/devmode.hex +IHX=$(BUILD)/devmode.ihx + +ASM=$(wildcard *.asm) +SRC=$(wildcard *.c) + +all : $(TARGET) + +include $(PROJECT_ROOT)/payload.mk +include $(PROJECT_ROOT)/include.mk diff --git a/boot/devmode/bootloader.c b/boot/devmode/bootloader.c new file mode 100644 index 0000000..dfa9786 --- /dev/null +++ b/boot/devmode/bootloader.c @@ -0,0 +1,339 @@ +#include "devmode.h" + +#include <hardware.h> + +#include <fifo.h> + +#include <assert.h> +#include <stddef.h> +#include <string.h> + +u16 +crc16(const void *buf, size_t len); + +volatile struct fifo rx_fifo = {0, 0, {0}}; + +enum ack { +    ACK = 0x00, +    NACK = 0xFF +}; + +void +rx_isr(void) __critical __interrupt(0) +{ +    fifo_push(&rx_fifo, sio_a_data); +} + +static volatile uint32_t millis = 0; + +void +ctc1_isr(void) __critical __interrupt(1) +{ +    millis += 5; +} + +uint32_t +clock(void) +{ +    volatile uint32_t ret; +    DI; +    ret = millis; +    EI; +    return ret; +} + +void +putbyte(unsigned char b) +{ +    unsigned char ctrl = 0; + +    sio_a_data = b; + +    while (!(ctrl & 0x04)) { +	sio_a_ctrl = 0; +	ctrl = sio_a_ctrl; +    } +} + +static volatile int32_t errno = 0; + +u8 +getbyte(void) +{ +    u8 b; +    uint32_t ms = clock(); +    errno = 0; +    while (fifo_empty(&rx_fifo)) { +	if (clock() - ms > TIMEOUT_MS) { +	    errno = ERR_TIMEOUT; +	    return 0; +	} +    } +    DI; +    b = fifo_pop(&rx_fifo); +    EI; +    return b; +} + +void +flush(void) +{ +    DI; +    fifo_clear(&rx_fifo); +    EI; +} + + +// Hamming(7,4) encoding +u8 +encode(u8 x) +{ +    u8 y = 0; +    const u8 c[4] = {0x61, 0x52, 0x34, 0x78}; + +    for (u8 i = 0; i < 4; ++i) +	y ^= ((x >> i) & 1) ? c[i] : 0; + +    return y; +} + +// Hamming(7,4) decoding +u8 +decode(u8 x) +{ +    u8 p = 0; +    const u8 r[7] = {6, 5, 3, 7, 1, 2, 4}; + +    for (int i = 0; i < 7; ++i) +	p ^= ((x >> i) & 1) ? r[i] : 0; + +    // Assume simple error, attempt correction +    if (p) { +	size_t i = 0; + +	for (i = 0; i < LENGTH(r); ++i) { +	    if (r[i] == x) +		break; +	} + +	x ^= (1 << i); +    } + +    return x & 0x0F; +} + + +int +read(void *buf, size_t count) +{ +    u8 b; +    u8 *p = buf; + +    for (int n = 0; n < count; ++n) { +	b = decode(getbyte()); +	if (errno) +	    return errno; + +	b |= (decode(getbyte()) << 4); +	if (errno) +	    return errno; + +	p[n] = b; +    } + +    return 0; +} + +int +write(const void *buf, size_t count) +{ +    const u8 *p = buf; + +    for (size_t i = 0; i < count; ++i) { +	putbyte(encode(p[i] & 0x0F)); +	putbyte(encode((p[i] >> 4) & 0x0F)); +    } + +    return 0; +} + +int +read_header(struct header *header) +{ +    int err; +    u8 ack; +    u16 checksum; + +    while (1) { +	if ((err = read(header, sizeof(*header)))) +	    return err; + +	checksum = header->checksum; +	header->checksum = 0; + +	if (checksum == crc16(header, sizeof(*header))) { +	    header->checksum = checksum; +	    ack = ACK; +	    write(&ack, sizeof(ack)); +	    return 0; +	} else { +	    ack = NACK; +	    write(&ack, sizeof(ack)); +	} +    } +} + +int +read_buf(size_t len, void *buf) +{ +    int err; +    u8 ack; +    u16 checksum; + +    for (int i = 0; i < MAX_TRANS_ATTEMPTS; ++i) { +	// TODO: reduce code? +	if ((err = read(&checksum, sizeof(checksum))) +	    || (err = read(buf, len))) +	    break; + +	if (checksum == crc16(buf, len)) { +	    ack = ACK; +	    write(&ack, sizeof(ack)); +	    return 0; +	} else { +	    ack = NACK; +	    write(&ack, sizeof(ack)); +	} +    } + +    return -1; +} + +int +write_buf(size_t len, const void *buf) +{ +    int err; +    u8 ack = NACK; +    u16 checksum = crc16(buf, len); + +    for (int i = 0; i < MAX_TRANS_ATTEMPTS; ++i){ +	write(&checksum, sizeof(checksum)); +	write(buf, len); + +	// If TIMEOUT sending just give up +	if ((err = read(&ack, sizeof(ack)))) +	    return err; + +	if (ack == ACK) +	    return 0; +    } + +    return -1; +} + +// TODO: Restart after timeouts +void +loop(void) +{ +    struct header header; +    u8 buf[MAX_PACKET_SIZE]; + +    while (1) { +	if (read_header(&header)) { +	    flush(); +	    continue; +	} + +	switch (header.type) { +	case CMD_BOOT: +	    ((void (*)(void))header.address)(); +	    break; + +	case CMD_READ: +	    write_buf(header.length, (const void *)header.address); +	    break; + +	case CMD_WRITE: +	    if (!read_buf(header.length, buf)) +		memcpy((void *)header.address, buf, header.length); +	    break; + +	case CMD_ECHO: +	    if (!read_buf(header.length, buf)) +		write_buf(header.length, buf); +	    break; + +	default: +	    break; +	} + +	flush(); +    } +} + +static inline void +init_ctc(void) +{ +    ctc_channel_0 = CTC_CTRL(0); + +    /* 200Hz clock */ +    ctc_channel_1 = CTC_CTRL(CTC_INT_BIT | CTC_PRESCALER_BIT +			     | CTC_TIME_CONST_BIT | CTC_RST_BIT); +    ctc_channel_1 = 0; + +    ctc_channel_2 = CTC_CTRL(0); +    ctc_channel_3 = CTC_CTRL(0); + +    // Interrupt table for CTC +    // Final address is (Ireg << 8) | ctc_isr_ptr | {00/01/10/11} | 0 +    ctc_channel_0 = CTC_INT_VEC(0x10); +} + +static inline void +init_pio(void) +{ +    // Disable PIO interrupts +    port_a_ctrl = PIO_INT_CTRL(0); +    port_b_ctrl = PIO_INT_CTRL(0); +} + +static inline void +init_sio(void) +{ +    static const u8 sio_a_cfg[] = { +	0b00011000,			 // Reset channel +	4	  ,			 // wr4 +	0b01000100,			 // X16 clock (115200), one stop bit, no parity +	1	  ,			 // wr1 +	SIO_RX_INT_MD0 | SIO_RX_INT_MD1, // interrupt on every Rx, no wait function +	3	  ,			 // wr3 +	0b11000001,			 // enable Rx - 8 bit char +	5	  ,			 // wr5 +	0b01101000			 // enable Tx - 8 bit char +    }; + +    static const u8 sio_b_cfg[] = { +	0b00011000,			// Reset channel +	2	  ,			// load interrupt vector +	0x1C				// int_table_rx +    }; + +    for (u8 i = 0; i < LENGTH(sio_a_cfg); ++i) +	sio_a_ctrl = sio_a_cfg[i]; + +    for (u8 i = 0; i < LENGTH(sio_b_cfg); ++i) +	sio_b_ctrl = sio_b_cfg[i]; +} + +void +main(void) +{ +    init_ctc(); +    init_pio(); +    init_sio(); + +    IM(2); +    EI; + +    loop(); +} diff --git a/boot/crc16.c b/boot/devmode/crc16.c index ec7b015..ac17529 100644 --- a/boot/crc16.c +++ b/boot/devmode/crc16.c @@ -6,33 +6,33 @@ static const u16 crc_table[256] = {      0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,      0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,      0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, -	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, +    0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,      0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, -	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, +    0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,      0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, -	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, +    0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,      0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, -	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, +    0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,      0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, -	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, +    0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,      0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, -	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, +    0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,      0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, -	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, +    0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,      0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, -	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, +    0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,      0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, -	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, +    0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,      0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, -	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, +    0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,      0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, -	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, +    0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,      0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, -	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, +    0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,      0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, -	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, +    0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,      0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, -	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, +    0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,      0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0  }; @@ -43,7 +43,7 @@ crc16(const void *buf, size_t len)      u16 crc = 0;      while (len--) -        crc = crc_table[(crc >> 8) ^ (*p++)] ^ (crc << 8); +	crc = crc_table[(crc >> 8) ^ (*p++)] ^ (crc << 8);      return crc;  } diff --git a/boot/devmode/devmode.h b/boot/devmode/devmode.h new file mode 100644 index 0000000..f3322d0 --- /dev/null +++ b/boot/devmode/devmode.h @@ -0,0 +1,42 @@ +#ifndef DEVMODE_H +#define DEVMODE_H + +#include <zeta.h> + +#ifdef __GNUC__ +#define PACKED __attribute__((packed)) +#else +#define PACKED +#endif + +enum header_type { +    CMD_PING, +    CMD_INFO, +    CMD_BOOT, +    CMD_READ, +    CMD_WRITE, +    CMD_IO_READ, +    CMD_IO_WRITE, +    CMD_ECHO +}; + +struct header { +    u8 type; +    u8 bank; +    u16 address; +    u16 length; +    u16 checksum; +} PACKED; + +// static_assert(sizeof(struct header) == 8, "struct header is not PACKED"); + +enum error { +    ERR_TIMEOUT = -1 +}; + +#define MAX_PACKET_SIZE 256 +#define TIMEOUT_MS 500 +#define MAX_ATTEMPTS 3 +#define MAX_TRANS_ATTEMPTS 5 + +#endif // DEVMODE_H diff --git a/boot/main.c b/boot/main.c new file mode 100644 index 0000000..5fa3c81 --- /dev/null +++ b/boot/main.c @@ -0,0 +1,7 @@ +#include <hardware.h> + +void +main(void) +{ +	tft_ctrl = 0; +} diff --git a/include.mk b/include.mk new file mode 100644 index 0000000..196f319 --- /dev/null +++ b/include.mk @@ -0,0 +1,48 @@ +AS=sdasz80 +CC=sdcc +CPP=sdcpp + +INCLUDE=$(PROJECT_ROOT)/include + +DEPFLAGS=-MP -MMD -MF$(basename $@).d -MT$@ + +ASFLAGS=-g +ASCPPFLAGS=$(DEPFLAGS) -P -I$(INCLUDE) -DASSEMBLY +CFLAGS=-mz80 -I$(INCLUDE) --Werror $(patsubst %,-Wp%,$(DEPFLAGS)) +LDFLAGS=-mz80 --no-std-crt0\ +		--code-loc $(CODE_LOC)\ +		--data-loc $(DATA_LOC)\ +		--stack-loc $(STACK_LOC)\ +		-Wl-b_GSINIT=$(GSINIT_LOC) + +OBJ=$(patsubst %.asm,$(BUILD)/%.rel,$(ASM))\ +	$(patsubst %.c,$(BUILD)/%.rel,$(SRC)) +DEPS=$(patsubst $(BUILD)/%.rel,$(BUILD)/%.d,$(OBJ)) + +$(OBJ): | $(BUILD) $(DIRS) + +$(BUILD) : +	@mkdir -p $(BUILD) + +$(DIRS) : +	@mkdir -p $(DIRS) + +$(BUILD)/%.rel : %.asm +	@echo '  (CPP)' $< +	@$(CPP) $(ASCPPFLAGS) $< > $(basename $@).asm +	@echo '  (AS)' $< +	@$(AS) $(ASFLAGS) -o $@ $(basename $@).asm + +$(BUILD)/%.rel : %.c +	@echo '  (CC)' $< +	@$(CC) $(CFLAGS) -c -o $@ $< + +$(BUILD)/%.hex : $(BUILD)/%.ihx +	@hex2bin.py $< $@ + +.SECONDARY : +$(BUILD)/%.ihx : $(CRT0) $(OBJ) +	@echo '  (LD)' $(OBJ) +	@$(CC) $(LDFLAGS) -o $@ $+ + +-include $(DEPS) diff --git a/payload.mk b/payload.mk new file mode 100644 index 0000000..8386628 --- /dev/null +++ b/payload.mk @@ -0,0 +1,4 @@ +CODE_LOC=0x8100 +DATA_LOC=0xC000 +STACK_LOC=0x0000 +GSINIT_LOC=0x8090 | 
