# Railroad Crossing 2 for RVController - Main File # A product of Scheiße & Broken Signalling Systems, a Cheapie Systems company # This is free and unencumbered software released into the public domain. # See http://unlicense.org/ for more information j _start .include "util.S" _start: li t0,0x400 csrs mseccfg,t0 # Turn on MLPE (enable Zicfilp) li sp,0x10000 # Set up stack pointer la t0,handler csrw mtvec,t0 # Set up trap handler li t0,0x400 csrc mstatush,t0 # Turn off MDT li a7,131 ecall # Clear console input buffer li t0,0x60000 csrw mie,t0 # Mask all interrupts except digilines and console li gp,0xffff0000 csrw 0x801,gp # Map MMIO region at 0xffff0000 li t1,0xffffffff mv t2,t1 sd t1,10(gp) # Set mtimecmp to 0xffffffffffffffff csrw mip,zero # Clear any pending interrupts csrsi mstatus,0x8 # Turn on MIE to enable interrupts # Hardware initialization digiline_send lightchannel,lightoffmsg digiline_send gatechannel,gateupmsg digiline_send bellchannel,belloffmsg digiline_send signalchannel,lightredmsg .include "ui.S" .align 2 handler: csrw 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 addi t1,t1,1 # Interrupt 18 = console beq t0,t1,handler_console li t1,0x80000007 # Interrupt 7 = timer beq t0,t1,handler_timer j handler_other # Something else handler_digilines: li t0,131072 # 2^17, value of MDIP bit csrc mip,t0 # Acknowledge digilines interrupt la a0,channelbuf li a1,16 la a2,msgbuf li a3,16 li a7,135 ecall # Read the next digilines message la t0,channelbuf ld t1,0(t0) li t3,0x65746564 # 'dete' bne t1,t3,1f # not the detector li t3,0x00ffffff and t2,t2,t3 li t3,0x00007463 # 'ct\0\0' bne t2,t3,1f # not the detector la t0,traincounter lw t1,0(t0) addi t1,t1,1 # Increment train counter sw t1,0(t0) la t0,currstate lb t0,0(t0) # Read current state from RAM andi t0,t0,0xf # Mask out the country bnez t0,2f # State 0: start sequence la t1,country lb t1,0(t1) # Read current country setting slli t1,t1,4 # Multiply by 16 to get the offset into the state table addi t1,t1,1 # And add 1 to get to the first non-idle state la t0,currstate sb t1,0(t0) # Update state in RAM to the first state in the current country la t0,states sh2add t0,t1,t0 # Calculate the proper offset in the list of pointers (state number * 4 + base address) lw t0,0(t0) # Load the pointer jalr ra,t0,0 # And call that function 2: la t0,currstate lb s0,0(t0) # Re-read current state from RAM li t1,5 beq s0,t1,1f # State 5: reset timer li t1,21 beq s0,t1,1f # State 21 (UK state 5): reset timer li t1,35 beq s0,t1,1f # State 35 (US state 3): reset timer j 2f # None of the above, skip over the reset 1: set_timer_to extensiontime 2: li a7,133 ecall # Check if there are more messages to process bnez a0,handler_digilines j handler_epilogue handler_timer: stop_timer # Stopping timer acknowledges the interrupt too la t2,currstate lb s0,0(t2) # Read current state from RAM beqz s0,handler_epilogue # State 0: timer shouldn't have fired in the first place li t3,16 beq s0,t3,handler_epilogue # State 16 (UK state 0): timer shouldn't have fired in the first place li t3,32 beq s0,t3,handler_epilogue # State 32 (US state 0): timer shouldn't have fired in the first place addi s0,s0,1 # Increment to get to next state sb s0,0(t2) # Write new state to RAM la t1,4 mul t0,s0,t1 la t1,states add t0,t0,t1 # Calculate address of function address for new state lw t1,0(t0) # Read what the function address should be addi t2,s0,1 # Landing pad label is state number + 1 (to avoid having any of them be 0) slli t2,t2,12 jalr ra,t1,0 # And call the proper function # Fall through to epilogue handler_epilogue: csrr t0,mip # Check if there are any interrupts still pending bexti t1,t0,7 # Bit 7 = MTIP (timer) bnez t1,handler_timer bexti t1,t0,17 # Bit 17 = MDIP (digilines) bnez t1,handler_digilines bexti t1,t0,18 # Bit 18 = MCIP (console) bnez t1,handler_console 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,uiunimplementedtrap 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 states: .word destate0,destate1,destate2,destate3,destate4,destate5,destate6,0,0,0,0,0,0,0,0,0 .word ukstate0,ukstate1,ukstate2,ukstate3,ukstate4,ukstate5,ukstate6,ukstate7,0,0,0,0,0,0,0,0 .word usstate0,usstate1,usstate2,usstate3,usstate4,0,0,0,0,0,0,0,0,0,0,0 .align 2 destate0: lpad 1 stop_timer digiline_send lightchannel,lightoffmsg digiline_send gatechannel,gateupmsg digiline_send bellchannel,belloffmsg digiline_send signalchannel,lightredmsg ret .align 2 destate1: lpad 2 digiline_send lightchannel,lightyellowmsg set_timeri 2 ret .align 2 destate2: lpad 3 digiline_send bellchannel,bellonmsg set_timeri 3 ret .align 2 destate3: lpad 4 digiline_send lightchannel,lightredmsg set_timer_to gatedroptime ret .align 2 destate4: lpad 5 digiline_send gatechannel,gatedownmsg set_timeri 3 ret .align 2 destate5: lpad 6 digiline_send signalchannel,lightgreenmsg digiline_send bellchannel,belloffmsg set_timer_to activetime ret .align 2 destate6: lpad 7 digiline_send signalchannel,lightredmsg digiline_send gatechannel,gateupmsg set_timeri 2 la t0,currstate li t1,-1 sb t1,0(t0) # Next state should be 0 ret .align 2 ukstate0: lpad 17 stop_timer digiline_send lightchannel,lightoffmsg digiline_send gatechannel,gateupmsg digiline_send bellchannel,belloffmsg digiline_send signalchannel,lightredmsg ret .align 2 ukstate1: lpad 18 digiline_send lightchannel,lightyellowmsg digiline_send bellchannel,bellonmsg set_timeri 3 ret .align 2 ukstate2: lpad 19 digiline_send lightchannel,lightredmsg set_timeri 1 ret .align 2 ukstate3: lpad 20 digiline_send lightchannel,lightflashredmsg set_timer_to gatedroptime ret .align 2 ukstate4: lpad 21 digiline_send gatechannel,gatedownmsg set_timeri 3 ret .align 2 ukstate5: lpad 22 digiline_send signalchannel,lightgreenmsg set_timer_to activetime ret .align 2 ukstate6: lpad 23 digiline_send signalchannel,lightredmsg digiline_send bellchannel,belloffmsg set_timeri 1 ret .align 2 ukstate7: lpad 24 digiline_send gatechannel,gateupmsg set_timeri 3 la t0,currstate li t1,15 sb t1,0(t0) # Next state should be 16 (UK state 0) ret .align 2 usstate0: lpad 33 stop_timer digiline_send lightchannel,lightoffmsg digiline_send gatechannel,gateupmsg digiline_send bellchannel,belloffmsg digiline_send signalchannel,lightredmsg ret .align 2 usstate1: lpad 34 digiline_send lightchannel,lightflashredmsg digiline_send bellchannel,bellonmsg set_timer_to gatedroptime ret .align 2 usstate2: lpad 35 digiline_send gatechannel,gatedownmsg set_timeri 3 ret .align 2 usstate3: lpad 36 digiline_send bellchannel,belloffmsg digiline_send signalchannel,lightgreenmsg set_timer_to activetime ret .align 2 usstate4: lpad 37 digiline_send signalchannel,lightredmsg digiline_send gatechannel,gateupmsg set_timeri 3 la t0,currstate li t1,31 sb t1,0(t0) # Next state should be 32 (US state 0) ret hcontext: .skip 32*4 currstate: .byte 0 country: .byte 0 # 0 = DE, 1 = UK, 2 = US gatedroptime: .byte 3 activetime: .byte 15 extensiontime: .byte 25 traincounter: .word 0 uiunimplementedtrap: .asciz "Unimplemented trap!\nmcause: " channelbuf: .skip 16 msgbuf: .skip 16 lightchannel: .asciz "light" bellchannel: .asciz "bell" gatechannel: .asciz "gate" signalchannel: .asciz "signal" lightoffmsg: .asciz "OFF" lightredmsg: .asciz "RED" lightyellowmsg: .asciz "YELLOW" lightgreenmsg: .asciz "GREEN" lightflashredmsg: .asciz "FLASHRED" lightflashyellowmsg: .asciz "FLASHYELLOW" belloffmsg: .asciz "off" bellonmsg: .asciz "on" gateupmsg: .asciz "up" gatedownmsg: .asciz "down"