Skip to content

Instantly share code, notes, and snippets.

@xobs
Created March 14, 2023 08:19
Show Gist options
  • Save xobs/218adafdd1b7b3670561e845e10ee4a3 to your computer and use it in GitHub Desktop.
Save xobs/218adafdd1b7b3670561e845e10ee4a3 to your computer and use it in GitHub Desktop.
Demo program showing that Renode is incorrectly generating exceptions
// This program tests `ecall` and `ebreak`. Link with the
// following linker script:
//
//-- linker.x ----------------------------------------------
// MEMORY { FLASH : ORIGIN = 0x80000000, LENGTH = 512K }
// SECTIONS { .text : { *(.text .text.*); } > FLASH }
//----------------------------------------------------------
//
// Compile and link into a binary with:
// riscv-none-elf-gcc -march=rv32imac_zicsr -g my.S -o my.elf -nostdinc -nostdlib -T my.ld
// riscv-none-elf-objcopy -O binary my.elf my.bin
//
// Run this in tinyemu with the following configuration:
//-- my.cfg ------------------------------------------------
// { version: 1, memory_size: 1, machine: "riscv32", bios: "my.bin", }
//----------------------------------------------------------
//
// Run this in Renode with the following script:
//-- my.resc -----------------------------------------------
// mach create
// using sysbus
// machine LoadPlatformDescriptionFromString "cpu: CPU.VexRiscv @ sysbus { cpuType: \"rv32gc\"; timeProvider: empty }"
// machine LoadPlatformDescriptionFromString "mem: Memory.MappedMemory @ sysbus 0x80000000 { size: 0x1000 }"
// machine LoadPlatformDescriptionFromString "uart: UART.LiteX_UART @ sysbus 0x40008000"
// sysbus LoadELF @my.elf
// showAnalyzer uart
// start
//----------------------------------------------------------
// These values come from tinyemu, and is the HTIF offset
.equ UART_BASE, 0x40008000
// This value needs to be written to UART_BASE+4 in order
// to print a character.
.equ CONSOLE_OUTPUT, 0x1010000
.section .text
.globl _start
_start:
// Set up s0 and s1 for character printing
li s0, UART_BASE
li s1, CONSOLE_OUTPUT
// Print a character to make sure things work
li a0, '!'
jal ra, putc
// Print out a test string to make sure things work
lui a0, %hi(start_msg)
addi a0, a0, %lo(start_msg)
jal ra, puts
// Assign our exception handler
lui a0, %hi(exception_handler)
addi a0, a0, %lo(exception_handler)
csrw mtvec, a0
// Set mstatus.MIE=1 (enable M mode interrupt)
li a0, 8
csrs mstatus, a0
// Set mie.MSIP=1 (enable M software interrupts)
li a0, 8
csrs mie, a0
// Perform our test
ecall
ebreak
ecall
ebreak
lui a0, %hi(finish_msg)
addi a0, a0, %lo(finish_msg)
jal ra, puts
j exit
.align 4
exception_handler:
// Skip past the instruction. Note: It may be a
// compressed instruction (noted by the bottom two
// bits being 0b10)
csrr t0, mepc
lh t1, 0(t0)
li t2, 2
andi t1, t1, 3
beq t1, t2, 1f
addi t0, t0, 4
j 2f
1: addi t0, t0, 2
2: csrw mepc, t0
csrr t0, mcause
li t1, 11
beq t0, t1, m_ecall
li t1, 3
beq t0, t1, m_ebreak
lui a0, %hi(unhandled_exception_happened_str)
addi a0, a0, %lo(unhandled_exception_happened_str)
jal ra, puts
j exit
m_ecall:
lui a0, %hi(m_ecall_happened_str)
addi a0, a0, %lo(m_ecall_happened_str)
jal ra, puts
mret
m_ebreak:
lui a0, %hi(ebreak_happened_str)
addi a0, a0, %lo(ebreak_happened_str)
jal ra, puts
mret
exit:
li a0, 1
sw a0, 0(s0)
sw zero, 4(s0)
2: j 2b
putc:
sw a0, 0(s0)
sw s1, 4(s0)
ret
puts:
1: lbu a1, (a0)
beqz a1, 3f
sw a1, 0(s0)
sw s1, 4(s0)
addi a0, a0, 1
j 1b
3: ret
start_msg:
.string "starting test...\n"
finish_msg:
.string "finished test\n"
unhandled_exception_happened_str:
.string "unhandled exception happened\n"
m_ecall_happened_str:
.string "ecall instruction from machine mode\n"
ebreak_happened_str:
.string "ebreak instruction\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment