summaryrefslogtreecommitdiff
path: root/assembly/trap-test/trap-test.S
blob: 98084987ef521a689e6315eaa43850639a267241 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
la t0,handler
csrw mtvec,t0 # Set trap handler address and mode (0/direct)
li t0,0x400
csrc mstatush,t0 # Enable trap handler

li t0,0xdeadbeef # No RAM here
lw t1,0(t0) # This should give a load access fault, which should be handled

li a7,4 # Print string
la a0,readvalmsg # "Read value "
ecall

li a7,1 # Print integer
mv a0,t1 # Get the value read earlier
ecall

li a7,11 # Print character
li a0,'\n'
ecall

li a7,10 # Exit program
ecall

readvalmsg: .asciz "Read value "

.balign 4
handler:
# IMPORTANT NOTE: This handler is for demonstration purposes only and clobbers a0/a1/a7/t1!
# Its "handling" is also roughly the equivalent of Visual Basic's infamous "on error resume next"
li a7,4 # Print string
la a0,trapmsg # "Got trap "
ecall

li a7,1 # Print integer
csrr a0,mcause # Read trap cause
ecall

li a7,11 # Print character
li a0,'\n'
ecall

li a7,4 # Print string
la a0,mepcmsg # "at "
ecall

li a7,1 # Print integer
csrr a0,mepc # Read faulting address
ecall

li a7,11 # Print character
li a0,'\n'
ecall

csrr a0,mepc # Read faulting address again
lw a1,0(a0) # Read faulting instruction into a1
li a7,0x00000003
andn a1,a7,a1 # Invert it and AND with 0x3 (gives 0 if last two bits were 11, nonzero otherwise)
addi a0,a0,2 # Move fault address 2 bytes forward (all instructions are at least this long)
bnez a1,handler_compressed # If it was compressed, that's all the movement needed
addi a0,a0,2 # Otherwise it needs to go two more bytes forward
handler_compressed:
csrw mepc,a0 # Write the adjusted return address back
li t1,1234 # Fake the load having succeeded
mret # And go back there

trapmsg: .asciz "Got trap "
mepcmsg: .asciz "at "