summaryrefslogtreecommitdiff
path: root/assembly/rrxing2/rrxing2.S
diff options
context:
space:
mode:
authorcheapie <cheapiephp@gmail.com>2026-11-04 19:34:16 -0600
committercheapie <cheapiephp@gmail.com>2026-11-04 19:34:16 -0600
commit203798c72f10d003f16485b1ffb2758b9bcfa58c (patch)
tree9a2ce6d1ab689bff19ea71b0379836645905a286 /assembly/rrxing2/rrxing2.S
parent6fc47c5b8ff009bbae39ac11b57909bff6fb9039 (diff)
downloadrvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.tar
rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.tar.gz
rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.tar.bz2
rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.tar.xz
rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.zip
Add work-in-progress rrxing2 program
Diffstat (limited to 'assembly/rrxing2/rrxing2.S')
-rw-r--r--assembly/rrxing2/rrxing2.S373
1 files changed, 373 insertions, 0 deletions
diff --git a/assembly/rrxing2/rrxing2.S b/assembly/rrxing2/rrxing2.S
new file mode 100644
index 0000000..2118ca1
--- /dev/null
+++ b/assembly/rrxing2/rrxing2.S
@@ -0,0 +1,373 @@
+j _start
+
+.include "util.S"
+
+_start:
+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:
+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
+
+li t0,0x400
+csrw mseccfg,t0 # Turn on MLPE (enable Zicfilp)
+
+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,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
+
+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"
+belloffmsg: .asciz "off"
+bellonmsg: .asciz "on"
+gateupmsg: .asciz "up"
+gatedownmsg: .asciz "down"
+