summaryrefslogtreecommitdiff
path: root/assembly/extint-test/extint-test.S
diff options
context:
space:
mode:
Diffstat (limited to 'assembly/extint-test/extint-test.S')
-rw-r--r--assembly/extint-test/extint-test.S145
1 files changed, 145 insertions, 0 deletions
diff --git a/assembly/extint-test/extint-test.S b/assembly/extint-test/extint-test.S
new file mode 100644
index 0000000..c1b872d
--- /dev/null
+++ b/assembly/extint-test/extint-test.S
@@ -0,0 +1,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 " "