So far the last log brought us the following code:
; snake.y8 ; in Bank 2 : .EQU last_choice 1 .ORG 0 ; init set last_choice A2 set Right_Handler D2 ; ; ... Top_Handler: set D1 D2 ; ... set Select_direction PC Right_Handler: set D1 D2 ; ... set Select_direction PC Bottom_Handler: set D1 D2 ; ... set Select_direction PC Left_Handler: set D1 D2 ; ... set Select_direction PC ; .... Select_direction: set last_choice A2 in buttons R1 ; read the external state and 15 R1 ; mask only the relevant buttons set D2 PC IFZ ; jump to last choice if no button add (jump_table-1) R1 LDCL R1 PC ; lookup and jump jump_table: ; .DW 0 ; 0000 => handled by the dispatcher .DW Top_Handler ; 0001 (it's a priority encoder) .DW Right_Handler ; 0010 .DW Top_Handler ; 0011 .DW Bottom_Handler ; 0100 .DW Top_Handler ; 0101 .DW Right_Handler ; 0110 .DW Top_Handler ; 0111 .DW Left_Handler ; 1000 .DW Top_Handler ; 1001 .DW Right_Handler ; 1010 .DW Top_Handler ; 1011 .DW Bottom_Handler ; 1100 .DW Top_Handler ; 1101 .DW Right_Handler ; 1110 .DW Top_Handler ; 1111
This is where coordinates must be updated. I define the resolution of one of my flipdot boards: the 24×16 squares from Hannio.
; constants .EQU MAX_X 24 .EQU MAX_Y 16 ; variables' addresses: .EQU X_Head 2 .EQU Y_Head 3 .EQU X_Tail 4 .EQU Y_Tail 5
Since the lookup/jump table uses only one index, we can use A1 again to point at other things and preload the X and Y before the jump:
Select_direction: set X_Head A1 set D1 R2 set Y_Head A1 set D1 R3 set last_choice A2 in buttons R1 ; read the external state and 15 R1 ; mask only the relevant buttons set D2 PC IFZ ; jump to last choice if no button add (jump_table-1) R1 LDCL R1 PC ; lookup and jump
And now that the "default" choice is handled individually, the jump table could be relocated and save one instruction in the loop. The very first, unused, entry can be a jump to the initialisation code.
.ORG 0 set init PC ; jump over the jumptable ; 0000 is already decoded .DW Top_Handler ; 0001 (it's a priority encoder) .DW Right_Handler ; 0010 .DW Top_Handler ; 0011 ;....... .DW Top_Handler ; 1101 .DW Right_Handler ; 1110 .DW Top_Handler ; 1111 init: set X_Head A1 set (MAX_X/2) D1 set Y_Head A1 set (MAX_Y/2) D1 ;...
The handlers can now be elaborated a bit:
Top_Handler: SET ($+1) D1 ADD -1 R3 SET -1 PC IFC ; jump to failure if negative ; ... Right_Handler: set ($+1) D1 ADD 1 R2 CMPU (MAX_X-1) R2 SET -1 PC IFC ; jump to failure if overflow ; ... Bottom_Handler: set ($+1) D1 ADD 1 R3 CMPU (MAX_Y-1) R2 SET -1 PC IFC ; jump to failure if overflow ; ... Left_Handler: set ($+1) D1 ADD -1 R2 SET -1 PC IFC ; jump to failure if negative ; ...
The address -1 in the code is a trampoline to the routine that handles the end of the game:
Failure: ; play the defeat song here. HLT .ORG 255 set Failure PC
This way, the immediate address is short and the jump can be conditional, called from about anywhere at no cost. The addresses 0 to 7 are already allocated to the priority/jump table, but there are 7 more "short addresses" for trampolines to other routines.
Now comes the big problem. The memory.
There are only 256 bytes per bank and only 2 banks by default. To get things going, we assume the playground is only 16×16 sites so one site is one byte. This is enough to store the required information since this buffer does not directly represent the graphics (each dot is black or white, controlled externally).
Each site needs to store the following information:
- if the site is a "body" part (1 bit), and if so, the direction to the next one (2 bits)
- if the site is a candy (another bit) (we can't represent a poison/trap with only 2 colors)
That's 4 bits only out of 8 and we will see later how to compact them. Let's first lay out the logic and solve addressing later.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.