diff options
| author | cheapie <cheapiephp@gmail.com> | 2026-11-04 19:34:16 -0600 |
|---|---|---|
| committer | cheapie <cheapiephp@gmail.com> | 2026-11-04 19:34:16 -0600 |
| commit | 203798c72f10d003f16485b1ffb2758b9bcfa58c (patch) | |
| tree | 9a2ce6d1ab689bff19ea71b0379836645905a286 | |
| parent | 6fc47c5b8ff009bbae39ac11b57909bff6fb9039 (diff) | |
| download | rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.tar rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.tar.gz rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.tar.bz2 rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.tar.xz rvcontroller-203798c72f10d003f16485b1ffb2758b9bcfa58c.zip | |
Add work-in-progress rrxing2 program
| -rw-r--r-- | assembly/rrxing2/Makefile | 24 | ||||
| -rw-r--r-- | assembly/rrxing2/rrxing2.S | 373 | ||||
| l--------- | assembly/rrxing2/rvcontroller.ld | 1 | ||||
| -rw-r--r-- | assembly/rrxing2/ui.S | 452 | ||||
| -rw-r--r-- | assembly/rrxing2/util.S | 43 |
5 files changed, 893 insertions, 0 deletions
diff --git a/assembly/rrxing2/Makefile b/assembly/rrxing2/Makefile new file mode 100644 index 0000000..0d3b39b --- /dev/null +++ b/assembly/rrxing2/Makefile @@ -0,0 +1,24 @@ +MARCH ?= rv32imacbzicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt_zicfilp + +.PHONY: all dump load clean + +all: rrxing2.hex + +rrxing2.o: rrxing2.S ui.S util.S + riscv32-none-elf-as -I../rvcontroller-libraries -march=${MARCH} -o rrxing2.o rrxing2.S + +rrxing2.elf: rrxing2.o + riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o rrxing2.elf rrxing2.o + +dump: rrxing2.elf + riscv32-none-elf-objdump -d rrxing2.elf + +rrxing2.hex: rrxing2.elf + riscv32-none-elf-objcopy -O ihex rrxing2.elf rrxing2.hex + +load: rrxing2.hex + bash -c "wl-copy < rrxing2.hex" + +clean: + rm -f rrxing2.hex rrxing2.elf rrxing2.o + 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" + diff --git a/assembly/rrxing2/rvcontroller.ld b/assembly/rrxing2/rvcontroller.ld new file mode 120000 index 0000000..bc01402 --- /dev/null +++ b/assembly/rrxing2/rvcontroller.ld @@ -0,0 +1 @@ +../../rvcontroller.ld
\ No newline at end of file diff --git a/assembly/rrxing2/ui.S b/assembly/rrxing2/ui.S new file mode 100644 index 0000000..ef3734d --- /dev/null +++ b/assembly/rrxing2/ui.S @@ -0,0 +1,452 @@ +mainloop: +la ra,uidrawend # Will call a function to draw the current page, but it will return to the end instead of here +la t0,uipage +lbu t0,0(t0) + +beqz t0,uidrawidle # Page 0: Idle screen + +li t1,1 +beq t0,t1,uidrawmainmenu # Page 1: Main menu + +li t1,2 +beq t0,t1,uidrawcountryselect # Page 2: Country selection + +li t1,3 +beq t0,t1,uidrawadjusttiming # Page 3: Timing adjustments + +li t1,4 +beq t0,t1,uidrawgatedropdelay # Page 4: Gate drop delay adjustment + +li t1,5 +beq t0,t1,uidrawinitialtime # Page 5: Initial active time adjustment + +li t1,6 +beq t0,t1,uidrawextensiontime # Page 6: Extension time adjustment + +li t1,7 +beq t0,t1,uidrawinvalidinput # Page 7: Invalid (time) input + +j uidrawunknown + +uidrawend: +wfi # Program is entirely interrupt-driven, so wait for something to happen +j mainloop + +handler_console: +li t0,262144 # 2^18, value of MCIP bit +csrc mip,t0 +la ra,uihandlingend # Will call a function to handle input for the current page, but it will return to the end instead of here +la t0,uipage +lbu t0,0(t0) + +beqz t0,uihandleidle # Page 0: Idle screen + +li t1,1 +beq t0,t1,uihandlemainmenu # Page 1: Main menu + +li t1,2 +beq t0,t1,uihandlecountryselect # Page 2: Country selection + +li t1,3 +beq t0,t1,uihandleadjusttiming # Page 3: Timing adjustments + +li t1,4 +beq t0,t1,uihandlegatedropdelay # Page 4: Gate drop delay adjustment + +li t1,5 +beq t0,t1,uihandleinitialtime # Page 5: Initial active time adjustment + +li t1,6 +beq t0,t1,uihandleextensiontime # Page 6: Extension time adjustment + +li t1,7 +beq t0,t1,uihandleinvalidinput # Page 7: Invalid (time) input + +uihandlingend: +li a7,131 +ecall # Drop anything else the user may have typed +j handler_epilogue + +copystring: +# Destination pointer in a0, source pointer in a1, copies until null is reached (but doesn't copy the null), not very optimized +lb t0,0(a1) +beqz t0,1f +sb t0,0(a0) +addi a0,a0,1 +addi a1,a1,1 +j copystring +1: ret + +uidrawidle: +cm.push {ra},-16 +la a0,uiidle+44 +la a3,uiidle +la t0,currstate # Check if currently running or not +lbu t0,0(t0) +andi t0,t0,0xf +beqz t0,1f +la a0,uiactive+44 # If so, then show the active message instead +la a3,uiactive +1: la a1,uide +la t0,country +lb t0,0(t0) +li t1,1 +bne t0,t1,1f +la a1,uiuk +1: li t1,2 +bne t0,t1,1f +la a1,uius +1: call copystring +mv a0,a3 +li a7,4 +ecall +cm.popret {ra},16 + +uihandleidle: +cm.push {ra},-16 +li a7,132 +ecall # Read one character of input +li t0,'m' +bne a0,t0,1f # If it was 'm'... +la t0,uipage +li t1,1 +sb t1,0(t0) # ...go to the main menu (page 1) +1: li t0,'a' +bne a0,t0,1f # If it was 'a', then start the sequence now +la t0,currstate +lbu t0,0(t0) +andi t0,t0,0xf +bnez t0,1f # Unless it's already running, that is +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 +1: cm.popret {ra},16 +ret + +uidrawmainmenu: +la a0,uimainmenu +li a7,4 +ecall +ret + +uihandlemainmenu: +li a7,132 +ecall # Read one character of input +li t0,'1' +bne a0,t0,1f +la t1,uipage +li t2,2 +sb t2,0(t1) # User entered '1', go to country selection (page 2) +1: li t0,'2' +bne a0,t0,1f +la t1,uipage +li t2,3 +sb t2,0(t1) # User entered '2', go to timing adjustment (page 3) +1: li t0,'0' +bne a0,t0,1f +la t1,uipage +sb x0,0(t1) # User entered '0', go to idle screen (page 0) +1: ret + +uidrawcountryselect: +la a0,uicountryselect +li a7,4 +ecall +ret + +uihandlecountryselect: +li a7,132 +ecall # Read one character of input +li t0,'1' +bne a0,t0,1f +la t1,country +sb x0,0(t1) # User entered '1', change country to DE (0) +la t1,uipage +li t2,1 +sb t2,0(t1) # Return to main menu (page 1) +1: li t0,'2' +bne a0,t0,1f +la t1,country +li t2,1 +sb t2,0(t1) # User entered '2', change country to UK (1) +la t1,uipage +li t2,1 +sb t2,0(t1) # Return to main menu (page 1) +1: li t0,'3' +bne a0,t0,1f +la t1,country +li t2,2 +sb t2,0(t1) # User entered '3', change country to US (2) +la t1,uipage +li t2,1 +sb t2,0(t1) # Return to main menu (page 1) +1: li t0,'0' +bne a0,t0,1f +la t1,uipage +li t2,1 +sb t2,0(t1) # User entered '0', return to main menu (page 1) without changing anything +1: ret + +uidrawadjusttiming: +la a0,uiadjusttiming +li a7,4 +ecall +ret + +uihandleadjusttiming: +li a7,132 +ecall # Read one character of input +li t0,'1' +bne a0,t0,1f +la t1,uipage +li t2,4 +sb t2,0(t1) # User entered '1', go to gate drop time setting (page 4) +1: li t0,'2' +bne a0,t0,1f +la t1,uipage +li t2,5 +sb t2,0(t1) # User entered '2', go to initial active time setting (page 5) +1: li t0,'3' +bne a0,t0,1f +la t1,uipage +li t2,6 +sb t2,0(t1) # User entered '3', go to extension time setting (page 6) +1: li t0,'0' +bne a0,t0,1f +la t1,uipage +li t2,1 +sb t2,0(t1) # User entered '0', go to main menu (page 1) +1: ret +ret + +uidrawgatedropdelay: +la a0,uigatedropdelay +la t0,gatedroptime +lbu t0,0(t0) # Load the current setting +li t1,10 +div t2,t0,t1 # Split it into tens and ones places +rem t3,t0,t1 +addi t2,t2,0x30 # Convert to ASCII +addi t3,t3,0x30 +sb t2,27(a0) # Insert the digits into the string +sb t3,28(a0) +li a7,4 +ecall # And print it +ret + +uihandlegatedropdelay: +# Read first digit +li a7,132 +ecall + +# Check if the user wanted to cancel +li t0,'c' +bne a0,t0,1f +la t0,uipage +li t1,3 # User chose to cancel, go back to timing adjustment (page 3) +sb t1,0(t0) +ret +1: + +# Validate and process first digit +addi s0,a0,-0x30 # Convert the first digit to ASCII +li t0,10 +bltu s0,t0,1f # Inputs less than 0x30 become negative in the addi above, this branch is unsigned so those become large positive numbers +la t0,uipage # ^ Thank the RISC-V manual for that trick +li t1,7 +sb t1,0(t0) # First digit was not valid, go to invalid input error (page 7) +ret +1: mul s0,s0,t0 # Multiply the first digit by 10 + +# Read second digit +li a7,132 +ecall +bnez a0,1f +div s0,s0,t0 # Second digit was null, so the first digit was really the ones place +li a0,0x30 # Pretend this digit was 0 so validation still passes but the addition doesn't change anything +1: addi a0,a0,-0x30 +bltu a0,t0,1f # Inputs less than 0x30 become negative in the addi above +la t0,uipage +li t1,7 +sb t1,0(t0) # Second digit was not valid, go to invalid input error (page 7) +ret +1: add s0,s0,a0 # Sum the two digits together +bnez s0,1f +la t0,uipage +li t1,7 +sb t1,0(t0) # Input was 0, go to invalid input error (page 7) +ret +1: la t0,gatedroptime +sb s0,0(t0) # Write out the new setting +la t0,uipage +li t1,3 # Go back to timing adjustment (page 3) +sb t1,0(t0) +ret + +uidrawinitialtime: +la a0,uiinitialtime +la t0,activetime +lbu t0,0(t0) # Load the current setting +li t1,10 +div t2,t0,t1 # Split it into tens and ones places +rem t3,t0,t1 +addi t2,t2,0x30 # Convert to ASCII +addi t3,t3,0x30 +sb t2,29(a0) # Insert the digits into the string +sb t3,30(a0) +li a7,4 +ecall # And print it +ret + +uihandleinitialtime: +# Read first digit +li a7,132 +ecall + +# Check if the user wanted to cancel +li t0,'c' +bne a0,t0,1f +la t0,uipage +li t1,3 # User chose to cancel, go back to timing adjustment (page 3) +sb t1,0(t0) +ret +1: + +# Validate and process first digit +addi s0,a0,-0x30 # Convert the first digit to ASCII +li t0,10 +bltu s0,t0,1f # Inputs less than 0x30 become negative in the addi above, this branch is unsigned so those become large positive numbers +la t0,uipage # ^ Thank the RISC-V manual for that trick +li t1,7 +sb t1,0(t0) # First digit was not valid, go to invalid input error (page 7) +ret +1: mul s0,s0,t0 # Multiply the first digit by 10 + +# Read second digit +li a7,132 +ecall +bnez a0,1f +div s0,s0,t0 # Second digit was null, so the first digit was really the ones place +li a0,0x30 # Pretend this digit was 0 so validation still passes but the addition doesn't change anything +1: addi a0,a0,-0x30 +bltu a0,t0,1f # Inputs less than 0x30 become negative in the addi above +la t0,uipage +li t1,7 +sb t1,0(t0) # Second digit was not valid, go to invalid input error (page 7) +ret +1: add s0,s0,a0 # Sum the two digits together +bnez s0,1f +la t0,uipage +li t1,7 +sb t1,0(t0) # Input was 0, go to invalid input error (page 7) +ret +1: la t0,activetime +sb s0,0(t0) # Write out the new setting +la t0,uipage +li t1,3 # Go back to timing adjustment (page 3) +sb t1,0(t0) +ret + +uidrawextensiontime: +la a0,uiextensiontime +la t0,extensiontime +lbu t0,0(t0) # Load the current setting +li t1,10 +div t2,t0,t1 # Split it into tens and ones places +rem t3,t0,t1 +addi t2,t2,0x30 # Convert to ASCII +addi t3,t3,0x30 +sb t2,26(a0) # Insert the digits into the string +sb t3,27(a0) +li a7,4 +ecall # And print it +ret + +uihandleextensiontime: +# Read first digit +li a7,132 +ecall + +# Check if the user wanted to cancel +li t0,'c' +bne a0,t0,1f +la t0,uipage +li t1,3 # User chose to cancel, go back to timing adjustment (page 3) +sb t1,0(t0) +ret +1: + +# Validate and process first digit +addi s0,a0,-0x30 # Convert the first digit to ASCII +li t0,10 +bltu s0,t0,1f # Inputs less than 0x30 become negative in the addi above, this branch is unsigned so those become large positive numbers +la t0,uipage # ^ Thank the RISC-V manual for that trick +li t1,7 +sb t1,0(t0) # First digit was not valid, go to invalid input error (page 7) +ret +1: mul s0,s0,t0 # Multiply the first digit by 10 + +# Read second digit +li a7,132 +ecall +bnez a0,1f +div s0,s0,t0 # Second digit was null, so the first digit was really the ones place +li a0,0x30 # Pretend this digit was 0 so validation still passes but the addition doesn't change anything +1: addi a0,a0,-0x30 +bltu a0,t0,1f # Inputs less than 0x30 become negative in the addi above +la t0,uipage +li t1,7 +sb t1,0(t0) # Second digit was not valid, go to invalid input error (page 7) +ret +1: add s0,s0,a0 # Sum the two digits together +bnez s0,1f +la t0,uipage +li t1,7 +sb t1,0(t0) # Input was 0, go to invalid input error (page 7) +ret +1: la t0,extensiontime +sb s0,0(t0) # Write out the new setting +la t0,uipage +li t1,3 # Go back to timing adjustment (page 3) +sb t1,0(t0) +ret + +uidrawinvalidinput: +la a0,uiinvalidinput +li a7,4 +ecall +ret + +uihandleinvalidinput: +la t0,uipage +li t1,3 # Go back to timing adjustment (page 3) +sb t1,0(t0) +ret + +uidrawunknown: +la a0,uiunknown +li a7,4 +ecall +ret + +uipage: .byte 0 +uiidle: .asciz "\nRailroad Crossing 2\nfor RVController\nMode: ??\n\nPress 'm' for menu\n'a' to activate now" +uiactive: .asciz "\nRailroad Crossing 2\nfor RVController\nMode: ??\nCrossing is active\n\nPress 'm' for menu" +uimainmenu: .asciz "\nMAIN MENU\n1: Change Country\n2: Adjust Timing\n\n\n0: Exit" +uiunknown: .asciz "\nInternal error\n\nUnknown UI page\n\n\n" +uicountryselect: .asciz "\nCHANGE COUNTRY\n1: Germany\n2: United Kingdom\n3: United States\n\n0: Cancel" +uiadjusttiming: .asciz "\nADJUST TIMING\n1: Gate Drop Delay\n2: Init. Active Time\n3: Extension Time\n\n0: Cancel" +uigatedropdelay: .asciz "\nGATE DROP DELAY\n\nCurrent: XX sec\n\nEnter new time or\n'c' to cancel:" +uiinitialtime: .asciz "\nINIT. ACTIVE TIME\n\nCurrent: XX sec\n\nEnter new time or\n'c' to cancel:" +uiextensiontime: .asciz "\nEXTENSION TIME\n\nCurrent: XX sec\n\nEnter new time or\n'c' to cancel:" +uiinvalidinput: .asciz "\nInvalid entry\n\nPress any key\n\n\n" +uide: .asciz "DE" +uiuk: .asciz "UK" +uius: .asciz "US" diff --git a/assembly/rrxing2/util.S b/assembly/rrxing2/util.S new file mode 100644 index 0000000..9dda1ab --- /dev/null +++ b/assembly/rrxing2/util.S @@ -0,0 +1,43 @@ +.macro digiline_send channel msg + la a0,(\channel) + la a1,(\msg) + li a7,129 + ecall +.endm + +.macro set_timeri time + li t0,0x80 + csrs mie,t0 # unmask timer interrupt + ld t1,2(gp) # read mtime + li t0,(\time) + add t1,t1,t0 # calculate target value (lower half) + sltu t0,t1,t0 # check if it overflowed + add t2,t2,t0 # add the overflow into the high half if there was any + sd t1,10(gp) # set mtimecmp to the target value +.endm + +.macro stop_timer + li t1,0xffffffff + li t2,0xffffffff + sd t1,10(gp) # set mtime to far in the future + li t1,0x80 + csrc mie,t1 # mask timer interrupt +.endm + +.macro set_timer_to label + cm.push {ra},-16 + la a0,(\label) + lbu a0,0(a0) + call set_timer + cm.pop {ra},16 +.endm + +set_timer: +li t0,0x80 +csrs mie,t0 # unmask timer interrupt +ld t1,2(gp) # read mtime +add t1,t1,a0 # calculate target value (lower half) +sltu t0,t1,a0 # check if it overflowed +add t2,t2,t0 # add the overflow into the high half if there was any +sd t1,10(gp) # set mtimecmp to the target value +ret |
