#include "hazard3_csr.h" #define IO_BASE 0xc0000000 #define IO_PRINT_CHAR (IO_BASE + 0x0) #define IO_PRINT_U32 (IO_BASE + 0x4) #define IO_EXIT (IO_BASE + 0x8) // Provide trap vector table, reset handler and weak default trap handlers for // Hazard3. This is not a crt0: the reset handler calls an external _start .option push .option norelax .file 1 "vendor/Hazard3/test/sim/common/init.S" .section .vectors,"ax",@progbits .macro VEC name:req .p2align 2 j \name .p2align 2 .endm // ---------------------------------------------------------------------------- // Vector table (must be at least aligned to its size rounded up to power of 2) .p2align 12 .vector_table: // Single exception vector, also takes IRQs if vectoring is disabled VEC handle_exception // Standard interrupts, if vectoring is enabled // Note: global EIRQ does not fire. Instead we have 16 separate vectors // handle_exception ^^^ takes the slot where U-mode softirq would be VEC .halt VEC .halt VEC isr_machine_softirq VEC .halt VEC .halt VEC .halt VEC isr_machine_timer VEC .halt VEC .halt VEC .halt VEC isr_external_irq VEC .halt VEC .halt VEC .halt VEC .halt // ---------------------------------------------------------------------------- // Reset handler .reset_handler: // Set counters running, as they are off by default. This may trap if counters // are unimplemented, so catch the trap and continue. .loc 1 59 0 ; la a0, 1f .loc 1 60 0 ; csrw mtvec, a0 .loc 1 61 0 ; csrci mcountinhibit, 0x5 .loc 1 62 0 ; j 2f .p2align 2 1: .loc 1 65 0 ; csrw mcause, zero 2: // Set up trap vector table. mtvec LSB enables vectoring .loc 1 69 0 ; la a0, .vector_table + 1 .loc 1 70 0 ; csrw mtvec, a0 // Ensure gp is initialised on all cores -- don't wait for newlib _start // as that is core-0-only .option push .option norelax .loc 1 76 0 ; la gp, __global_pointer$ .option pop // Put spare cores to sleep before setting up core 0 stack // Note csrr is a NOP when there are no CSRs at all (no traps!): .loc 1 81 0 ; li a0, 0 .loc 1 82 0 ; csrr a0, mhartid .loc 1 83 0 ; bnez a0, .core1_wait // Set up stack pointer before doing anything else .loc 1 86 0 ; la sp, __stack_top // newlib _start expects argc, argv on the stack. Leave stack 16-byte aligned. .loc 1 89 0 ; addi sp, sp, -16 .loc 1 90 0 ; li a0, 1 .loc 1 91 0 ; sw a0, (sp) .loc 1 92 0 ; la a0, progname .loc 1 93 0 ; sw a0, 4(sp) .loc 1 95 0 ; jal _start .loc 1 96 0 ; j .halt .core1_wait: // IRQs disabled, but soft IRQ unmasked -> soft IRQ will exit WFI. csrci mstatus, 0x8 csrw mie, 0x8 .core1_wait_loop: wfi la a0, core1_entry_vector lw a0, (a0) beqz a0, .core1_wait_loop la sp, __stack_top - 0x10000 jalr a0 .core1_finish: wfi j .core1_finish .p2align 2 .global core1_entry_vector core1_entry_vector: .word 0 .global _exit _exit: li a1, IO_EXIT sw a0, (a1) .global _sbrk _sbrk: la a1, heap_ptr lw a2, (a1) add a0, a0, a2 sw a0, (a1) mv a0, a2 ret .p2align 2 heap_ptr: .word _end .global .halt .halt: j .halt progname: .asciz "hazard3-testbench" .p2align 2 // ---------------------------------------------------------------------------- // Weak handler/ISR symbols // Routine to print out trap name, trap address, and some core registers // (x8..x15, ra, sp). The default handlers are all patched into this routine, // so the CPU will print some basic diagnostics on any unhandled trap // (assuming the processor is not internally completely broken) // argument in t0, IO pointer in t1, return in tp, trashes t0 and t2; _tb_puts: 1: lbu t2, (t0) addi t0, t0, 1 beqz t2, 2f sw t2, IO_PRINT_CHAR - IO_BASE(t1) j 1b 2: jr tp .macro print_reg str reg la t0, \str jal tp, _tb_puts sw \reg, IO_PRINT_U32 - IO_BASE(t1) .endm _weak_handler_name_in_gp: la t0, _str_unhandled_trap li t1, IO_BASE jal tp, _tb_puts mv t0, gp jal tp, _tb_puts la t0, _str_at_mepc jal tp, _tb_puts csrr t0, mepc sw t0, IO_PRINT_U32 - IO_BASE(t1) csrr gp, mcause bltz gp, 1f print_reg _str_mcause gp 1: print_reg _str_s0 s0 print_reg _str_s1 s1 print_reg _str_a0 a0 print_reg _str_a1 a1 print_reg _str_a2 a2 print_reg _str_a3 a3 print_reg _str_a4 a4 print_reg _str_a5 a5 print_reg _str_ra ra print_reg _str_sp sp li t2, -1 sw t2, IO_EXIT - IO_BASE(t1) // Should be unreachable: j .halt _str_unhandled_trap: .asciz "*** Unhandled trap ***\n" _str_at_mepc: .asciz " @ mepc = " _str_mcause: .asciz " mcause = " _str_s0: .asciz "s0: " _str_s1: .asciz "s1: " _str_a0: .asciz "a0: " _str_a1: .asciz "a1: " _str_a2: .asciz "a2: " _str_a3: .asciz "a3: " _str_a4: .asciz "a4: " _str_a5: .asciz "a5: " _str_ra: .asciz "ra: " _str_sp: .asciz "sp: " .p2align 2 // Provide a default weak handler for each trap, which calls into the above // diagnostic routine with the trap name (a null-terminated string) in gp .macro weak_handler name:req .p2align 2 .global \name .weak \name \name: la gp, _str_\name j _weak_handler_name_in_gp _str_\name: .asciz "\name" .endm weak_handler handle_exception weak_handler isr_machine_softirq weak_handler isr_machine_timer weak_handler isr_external_irq // You can relax now .option pop