From 203798c72f10d003f16485b1ffb2758b9bcfa58c Mon Sep 17 00:00:00 2001 From: cheapie Date: Wed, 4 Nov 2026 19:34:16 -0600 Subject: Add work-in-progress rrxing2 program --- assembly/rrxing2/rrxing2.S | 373 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 assembly/rrxing2/rrxing2.S (limited to 'assembly/rrxing2/rrxing2.S') 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" + -- cgit v1.2.3