summaryrefslogtreecommitdiff
path: root/assembly/extint-test/extint-test.S
blob: c1b872d6989a510f409c486625db694c48ca5fe3 (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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
li t0,0xffff0000
csrw 0x801,t0 # Map the MMIO region somewhere
la t0,handler
csrw mtvec,t0 # Set up trap handler
li t0,0x400
csrc mstatush,t0 # Turn off MDT
li t0,0x30000
csrw mie,t0 # Mask all interrupts except mesecons/digilines
csrw mip,zero # Clear any pending interrupts
csrsi mstatus,0x8 # Turn on MIE to enable interrupts

mainloop:
li a7,4
la a0,waitingmsg
ecall # Print waiting message
wfi # And do nothing else, this program is entirely interrupt-driven
j mainloop



.align 4
handler:
csrrw x31,mscratch,x31 # Free up x31 to hold the context address
la x31,hcontext # Using x register numbers here since trap handlers don't use the usual calling convention
sw x1,0(x31) # Save all the registers to the context
sd x2,4(x31) # Two at a time since we have Zilsd/Zclsd
sd x4,12(x31) # Note that I don't actually _need_ all of the registers in the handler,
sd x6,20(x31) # but I wanted to try this anyway to see how it goes
sd x8,28(x31)
sd x10,36(x31)
sd x12,44(x31)
sd x14,52(x31)
sd x16,60(x31)
sd x18,68(x31)
sd x20,76(x31)
sd x22,84(x31)
sd x24,92(x31)
sd x26,100(x31)
sd x28,108(x31)
sw x30,116(x31)
csrr x30,mscratch # Get the old x31 value back into a register
sw x30,120(x31) # and write that back out too

csrr t0,mcause # Read why the trap occurred

li t1,0x80000010 # Interrupt 16 = mesecons
beq t0,t1,handler_mesecons

li t1,0x80000011 # Interrupt 17 = digilines
beq t0,t1,handler_digilines

j handler_other # Something else

handler_mesecons:
li a7,4
la a0,meseconsmsg
ecall # Show that this was a mesecons event

li a7,1
li t0,0xffff0000
lb a0,1(t0) # Read the mesecons I/O port value
ecall # And print that

li a7,11
li a0,'\n'
ecall # Line feed

j handler_epilogue

handler_digilines:
li a7,4
la a0,digilinesmsg
ecall # Show that this was a digilines event

li a7,135
la a0,channelbuf
li a1,21
la a2,msgbuf
li a3,21
ecall # Read what the event was

li a7,4
la a0,channelbuf
ecall # Print the channel

li a7,4
la a0,digilinesmsg2
ecall # "Message:", this has its own line feeds in it

li a7,4
la a0,msgbuf
ecall # Print the message

li a7,11
li a0,'\n'
ecall # Line feed

li a7,134
ecall # Clear out any other digilines messages

j handler_epilogue

handler_other:
li a7,4
la a0,unimplementedmsg
ecall # Display unimplemented trap message

csrr a0,mcause # Read what the cause was
li a7,1
ecall # Tell the user

li a7,10
ecall # Then halt

handler_epilogue:
csrw mip,zero # Clear out all pending interrupts
la x31,hcontext # x numbers here for the same reason as during the save
lw x1,0(x31) # Load all of the registers from the context
ld x2,4(x31) # Two at a time since we have Zilsd/Zclsd
ld x4,12(x31)
ld x6,20(x31)
ld x8,28(x31)
ld x10,36(x31)
ld x12,44(x31)
ld x14,52(x31)
ld x16,60(x31)
ld x18,68(x31)
ld x20,76(x31)
ld x22,84(x31)
ld x24,92(x31)
ld x26,100(x31)
ld x28,108(x31)
ld x30,116(x31)
mret # Return to the program (not that the rest of the program does much)

hcontext: .skip 32*4


waitingmsg: .asciz "Waiting...\n"
meseconsmsg: .asciz "Mesecons event!\nInput value: "
digilinesmsg: .asciz "Digilines event!\nChannel:\n"
digilinesmsg2: .asciz "\nMessage:\n"
unimplementedmsg: .asciz "Unimplemented trap!\nmcause: "
channelbuf: .asciz "                    "
msgbuf: .asciz "                    "