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