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 " "
|