la t0,handler csrw mtvec,t0 # Set up trap handler li t0,0x400 csrc mstatush,t0 # Turn off MDT li t0,0x20000 csrw mie,t0 # Mask all interrupts except digilines csrw mip,zero # Clear any pending interrupts csrsi mstatus,0x8 # Turn on MIE to enable interrupts la t0,pedwaiting sb zero,0(t0) # Clear the pedestrian waiting flag (really it should already be clear, this handles the case of a program restart) restart: la a0,lightchannel la a1,greenmsg li a7,129 ecall # Light -> green la a0,pedchannel la a1,redmsg li a7,129 ecall # Ped -> red (don't walk) li a0,20 call sleep waitloop: la t0,pedwaiting lb t0,0(t0) bnez t0,startsequence # Check if someone is waiting wfi # Otherwise wait for something to happen j waitloop startsequence: la a0,lightchannel la a1,yellowmsg li a7,129 ecall # Light -> yellow li a0,3 call sleep la a0,lightchannel la a1,redmsg li a7,129 ecall # Light -> red li a0,2 call sleep la a0,pedchannel la a1,greenmsg li a7,129 ecall # Ped -> green (walk) li a0,8 call sleep la a0,pedchannel la a1,flashredmsg li a7,129 ecall # Ped -> flashing red (flashing don't walk) la t0,pedwaiting sb zero,0(t0) # Clear the detection flag at this point too li a0,20 call sleep la a0,pedchannel la a1,redmsg li a7,129 ecall # Ped -> red (don't walk) li a0,1 call sleep la a0,lightchannel la a1,redyellowmsg li a7,129 ecall # Light -> red+yellow li a0,2 call sleep j restart # This will turn the light green before going back to waiting sleep: csrr t0,time # Only using 32 bits here, this will have problems after 136ish years add a0,t0,a0 sleep_loop: pause csrr t0,time blt t0,a0,sleep_loop ret .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) sd x6,20(x31) 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,0x80000011 # Interrupt 17 = digilines beq t0,t1,handler_digilines j handler_other # Something else handler_digilines: li a7,135 la a0,channelbuf li a1,21 la a2,msgbuf li a3,21 ecall # Read what the event was la t0,channelbuf lb t0,0(t0) li t1,'b' bne t0,t1,handler_notbutton # Check if the channel started with 'b' (not going to bother checking the rest) la t0,pedwaiting li t1,1 sb t1,0(t0) # Set the pedestrian waiting flag handler_notbutton: li a7,133 ecall # Check if there are more messages to process bnez a0,handler_digilines 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 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 hcontext: .skip 32*4 unimplementedmsg: .asciz "Unimplemented trap!\nmcause: " channelbuf: .asciz " " msgbuf: .asciz " " lightchannel: .asciz "light" pedchannel: .asciz "ped" redmsg: .asciz "RED" yellowmsg: .asciz "YELLOW" greenmsg: .asciz "GREEN" flashredmsg: .asciz "FLASHRED" redyellowmsg: .asciz "REDYELLOW" pedwaiting: .byte 0