diff --git a/src/bootloader/Makefile b/src/bootloader/Makefile index 7d895e5..2f800e2 100644 --- a/src/bootloader/Makefile +++ b/src/bootloader/Makefile @@ -31,14 +31,15 @@ ROMGEN=$(MIPS_HOME)/tools/romgen all: bootloader_flash -libsys: startup_boot.S kernel_boot.S libsys_boot.c +libsys: startup_boot.S kernel_boot.S libsys_boot.c ../libsys/xcpt.c $(CC) $(CFLAGS) -c startup_boot.S -o startup.o $(CC) $(CFLAGS) -c kernel_boot.S -o kernel.o $(CC) $(CFLAGS) -c libsys_boot.c -o libsys.o + $(CC) $(CFLAGS) -c ../libsys/xcpt.c -o xcpt.o bootloader: libsys bootloader.c $(CC) $(CFLAGS) -g -c bootloader.c - $(LD) $(LFLAGS) $(LIB_DIRS) startup.o kernel.o libsys.o bootloader.o -o $@.elf $(LIBS) >$@.map + $(LD) $(LFLAGS) $(LIB_DIRS) startup.o kernel.o xcpt.o libsys.o bootloader.o -o $@.elf $(LIBS) >$@.map $(OBJDUMP) -D $@.elf > $@.dis $(OBJCOPY) $@.elf -O binary $@.ROM.bin $(OBJCOPY) -O srec $@.elf $@.srec @@ -53,13 +54,15 @@ bootloader_flash: libsys bootloader_with_flash.c $(OBJCOPY) -O srec $@.elf $@.srec $(ROMGEN) $@.ROM.bin 11 $(ENDIAN_FLAGS) -test: libsys test.c +test: libsys test.c ../libsys/irq.c ../libsys/xcpt.c $(CC) $(CFLAGS) -g -c test.c - $(LD) $(LFLAGS) $(LIB_DIRS) startup.o kernel.o libsys.o test.o -o $@.elf $(LIBS) >$@.map - $(OBJDUMP) -d $@.elf > $@.dis - $(OBJCOPY) $@.elf -O binary $@.ROM.bin + $(CC) $(CFLAGS) -g -c ../libsys/irq.c + $(CC) $(CFLAGS) -g -c ../libsys/xcpt.c + $(LD) $(LFLAGS) $(LIB_DIRS) startup.o kernel.o libsys.o irq.o xcpt.o test.o -o $@.elf $(LIBS) >$@.map + $(OBJDUMP) -D $@.elf > $@.dis + $(OBJCOPY) $@.elf -j ROM --output-target=binary $@.ROM.bin $(OBJCOPY) -O srec $@.elf $@.srec - $(ROMGEN) $@.ROM.bin 10 $(ENDIAN_FLAGS) + $(ROMGEN) $@.ROM.bin 11 $(ENDIAN_FLAGS) clean: rm -rf *.o *.bin *.map *.dis *.srec *.elf *.vhd* *.tcl bootloader > /dev/null diff --git a/src/bootloader/bootloader.ld b/src/bootloader/bootloader.ld index 3b5149f..60cc538 100644 --- a/src/bootloader/bootloader.ld +++ b/src/bootloader/bootloader.ld @@ -18,27 +18,16 @@ sys_timer_sec = 0xA000000C; SECTIONS { - .init ORIGIN(rom) : + ROM : { start = ALIGN(4); entry = ALIGN(4); _entry = ALIGN(4); __entry = ALIGN(4); *(.init) - } > rom - - .ktext ORIGIN(rom) + 0x180 : - { + . = ORIGIN(rom) + 0x180; *(.ktext) - } > rom - - .text . : - { - *(.text) - } > rom - - .rodata . : - { + *(.text*) *(.rodata*) } > rom diff --git a/src/bootloader/kernel_boot.S b/src/bootloader/kernel_boot.S index 62fd710..b79b254 100644 --- a/src/bootloader/kernel_boot.S +++ b/src/bootloader/kernel_boot.S @@ -1,3 +1,6 @@ +#include +#include + .file "kernel.S" .section .ktext,"ax" @@ -13,34 +16,178 @@ addiu $sp, -4 .endm -_exc_handler: - - .set noreorder +LEAF(_xcpt_handler) + .set noreorder + .set noat + /* Note: exceptions do not save and restore registers k0 and k1. + * on entry, k1 = exception class. + */ - # Set Error LED and ExcCode LEDs - # Get Cause - mfc0 $26, $13 - li $27, 0xC0000000 - srl $26, 2 - andi $26, 0x000F - or $26, $27 - la $27, sys_led_port - sw $26, 0($27) + /* allocate exception stack frame (on 8-byte boundary) */ + subu k1, sp, XCP_SIZE + srl k1, 3 /* shift right/left -> alligned on boundary */ + sll k1, 3 - # wait for all interrupts = 0 -$w4x: mfc0 $26, $13 - nop - srl $26, 8 - andi $26, 0xFF - bnez $26, $w4x - nop + /* save enough registers to get by */ + sw AT, XCP_AT(k1) + sw v0, XCP_V0(k1) + sw v1, XCP_V1(k1) + sw a0, XCP_A0(k1) + sw a1, XCP_A1(k1) + sw a2, XCP_A2(k1) + sw a3, XCP_A3(k1) + sw sp, XCP_SP(k1) + sw ra, XCP_RA(k1) - # Get return address - mfc0 $26, $14 + /* get coprocessor 0 exception state */ + mfc0 a0, CP0_CR + mfc0 a1, CP0_SR + mfc0 a2, CP0_BADDR + mfc0 a3, CP0_EPC - # Return - nop - jr $26 + /* we can safely use AT now */ + .set at + + /* switch to using sp to point at exception frame */ + move sp, k1 + + /* nothing sensible to store for k0/k1, store zero */ + sw zero, XCP_K0(sp) + sw zero, XCP_K1(sp) + + /* we are now interruptible: dump all remaining state + * into the exception stack frame. + */ + /* coprocessor exception state */ + sw a0, XCP_CR(sp) + sw a1, XCP_SR(sp) + sw a2, XCP_BADDR(sp) + sw a3, XCP_EPC(sp) + + /* mdhi and mdlo */ + mfhi v0 + mflo v1 + sw v0, XCP_MDHI(sp) + sw v1, XCP_MDLO(sp) + + /* Save all the other general registers. + * We save zero, s0-s7 and s8 as well, as instruction emulators (e.g. FP + * operations) and debuggers rely on all registers stored together in + * well-defined structure. + */ + sw zero, XCP_ZERO(sp) + sw t0, XCP_T0(sp) + sw t1, XCP_T1(sp) + sw t2, XCP_T2(sp) + sw t3, XCP_T3(sp) + sw t4, XCP_T4(sp) + sw t5, XCP_T5(sp) + sw t6, XCP_T6(sp) + sw t7, XCP_T7(sp) + sw s0, XCP_S0(sp) + sw s1, XCP_S1(sp) + sw s2, XCP_S2(sp) + sw s3, XCP_S3(sp) + sw s4, XCP_S4(sp) + sw s5, XCP_S5(sp) + sw s6, XCP_S6(sp) + sw s7, XCP_S7(sp) + sw t8, XCP_T8(sp) + sw t9, XCP_T9(sp) + sw gp, XCP_GP(sp) + sw s8, XCP_S8(sp) + + /* I don't know what the following does. [rb] */ + /* load our _gp pointer */ +# la gp, _gp + + /* and call the C exception handler */ + move a0, sp # arg1 = &xcp + subu sp, 16 # (arg save area) + j _xcpt_call + move ra, zero # fake return address + + /* This strange call to _xcpt_call with zero return address is to + * help exception-aware debuggers to trace back over the exception event. + * We are basically interposing a bogus stackframe (with a zero return + * address) between the C exception handler and the actual machine + * exception. + */ +$xcptrest: + .set noat + add AT, sp, 16 + + /* at points to exception frame */ +$xcptrestother: + /* restore all state */ + /* restore most general registers */ + lw t0, XCP_T0(AT) + lw t1, XCP_T1(AT) + lw t2, XCP_T2(AT) + lw t3, XCP_T3(AT) + lw t4, XCP_T4(AT) + lw t5, XCP_T5(AT) + lw t6, XCP_T6(AT) + lw t7, XCP_T7(AT) + lw s0, XCP_S0(AT) + lw s1, XCP_S1(AT) + lw s2, XCP_S2(AT) + lw s3, XCP_S3(AT) + lw s4, XCP_S4(AT) + lw s5, XCP_S5(AT) + lw s6, XCP_S6(AT) + lw s7, XCP_S7(AT) + lw t8, XCP_T8(AT) + lw t9, XCP_T9(AT) + lw gp, XCP_GP(AT) + lw s8, XCP_S8(AT) + + /* mdhi and mdlo */ + lw v0, XCP_MDHI(AT) + lw v1, XCP_MDLO(AT) + mthi v0 + mtlo v1 + + /* remaining general registers */ + lw a0, XCP_A0(AT) + lw a1, XCP_A1(AT) + lw a2, XCP_A2(AT) + lw a3, XCP_A3(AT) + lw ra, XCP_RA(AT) + + /* restore the exception-time status register */ + .set noreorder + lw v0, XCP_SR(AT) + nop + mtc0 v0, CP0_SR + lw v1, XCP_V1(AT) + lw v0, XCP_V0(AT) + lw sp, XCP_SP(AT) + + /* we are not uninterruptible and can use k1 safely */ + lw k1, XCP_EPC(AT) + lw AT, XCP_AT(AT) + mtc0 k1, CP0_EPC + j k1 rfe - .set reorder - + + .set reorder + .set at +END(_xcpt_handler) + + +LEAF(_xcpt_call) + /* on entry: a0 == &xcp */ + subu sp, 24 + sw ra, 16(sp) + + /* punt out to _xcpt_deliver */ + jal _xcpt_deliver + nop + lw ra, 16(sp) + addu sp, 24 + beqz ra, $xcptrest + nop + j ra + nop +END(_xcpt_call) diff --git a/src/bootloader/libsys_boot.c b/src/bootloader/libsys_boot.c index 00950f6..a5e6600 100644 --- a/src/bootloader/libsys_boot.c +++ b/src/bootloader/libsys_boot.c @@ -7,6 +7,16 @@ #include "libsys_boot.h" // --------------------------------------------------------------------------------- +void _exit(int reason) +{ +} + +void libsys_init() +{ + // Initialzie interrupt support + interrupt_init(); +} + // MIPS specific uint32_t CP0_SR_read(void) { diff --git a/src/bootloader/test.c b/src/bootloader/test.c index f9f5580..f5973c8 100644 --- a/src/bootloader/test.c +++ b/src/bootloader/test.c @@ -3,6 +3,7 @@ void main() { uint32_t i; + volatile uint32_t *pUART0_stat = (uint32_t*)SYS_UART_STAT; volatile uint32_t *pGPIO = (uint32_t*)SYS_GPIO_0_DATA; volatile uint32_t *pGPIODIR = (uint32_t*)SYS_GPIO_0_DIR; volatile uint32_t *pRAM = (uint32_t*)SDRAM_BASE; @@ -10,21 +11,23 @@ void main() *pGPIODIR = GPIO_0_DFLT_DIR; uint8_t led = 0; + // UART: enable RX interrupt + *pUART0_stat |= (1 << 6); + interrupt_enable(3); + sputs("Hello, world!\n"); while(1) { sputs("Iteration # ");print_word(led);sputs("\n"); + sputs("Uart status : ");print_word(*pUART0_stat);sputs("\n"); + sputs("CPU status : ");print_word(CP0_SR_read());sputs("\n"); + *pGPIO = led; if(led == 0) { memdump((uint8_t*)pRAM, 0, 16, 256); } - *pGPIO = led; - for (i=0; i < 1024*1024; i++) - { - pRAM[i] = i; - } led = (led+1) % 64; } *pGPIO = 1;