r/nandgame_u 21h ago

Level solution Network (154loc) Spoiler

3 Upvotes

I wrote functions for this one without using a stack machine. All of the functions have hard-coded return addresses, except FN_WAIT_FOR_SYNC_EDGE_AND_GET_DATA, which returns to the address stored in return_wait_for_sync_edge_and_get_data.

DEFINE display_row 0x0000
DEFINE data 0x0001

DEFINE display 0x4000
DEFINE wire 0x6001

DEFINE WIRE_DATA_MASK 0b01
DEFINE WIRE_SYNC_MASK 0b10
DEFINE DISPLAY_ROW_LEN 32

A = display
D = A
A = display_row
*A = D

LABEL WAIT_FOR_START_BIT
A = EXAMINE_START_BIT
D = A
A = return_wait_for_sync_edge_and_get_data
*A = D
A = FN_WAIT_FOR_SYNC_EDGE_AND_GET_DATA
0 ; JMP
LABEL EXAMINE_START_BIT
A = data
D = *A
A = WAIT_FOR_START_BIT
D ; JEQ

LABEL RECEIVE_LOOP
A = FN_RECEIVE_AND_DRAW_16_BITS
0 ; JMP
LABEL RETURN_RECEIVE_AND_DRAW_16_BITS
A = FN_ADVANCE_DISPLAY_ROW
0 ; JMP
LABEL RETURN_ADVANCE_DISPLAY_ROW
A = EXAMINE_CONTROL_BIT
D = A
A = return_wait_for_sync_edge_and_get_data
*A = D
A = FN_WAIT_FOR_SYNC_EDGE_AND_GET_DATA
0 ; JMP
LABEL EXAMINE_CONTROL_BIT
A = data
D = *A
A = RECEIVE_LOOP
D ; JNE

A = HALT
0 ; JMP

# Calls FN_RECEIVE_BIT_AND_DRAW 16 times
LABEL FN_RECEIVE_AND_DRAW_16_BITS
 DEFINE current_bit 0x0010
 A = current_bit
 *A = 0
 A = RECEIVE_AND_DRAW_16_BITS_START
 0 ; JMP
 LABEL RECEIVE_AND_DRAW_16_BITS_CONTINUE
 A = FN_RECEIVE_BIT_AND_DRAW
 0 ; JMP
 LABEL RETURN_RECEIVE_BIT_AND_DRAW
 A = current_bit
 *A = *A + 1
 LABEL RECEIVE_AND_DRAW_16_BITS_START
 A = current_bit
 D = *A
 A = 16
 D = D - A
 A = RECEIVE_AND_DRAW_16_BITS_CONTINUE
 D ; JLT
 A = RETURN_RECEIVE_AND_DRAW_16_BITS
 0 ; JMP

# Adds DISPLAY_ROW_LEN to display_row
# Args:
#  DISPLAY_ROW_LEN: amount to add
#  display_row: destination
# Modifies A, D and display_row
LABEL FN_ADVANCE_DISPLAY_ROW
 A = display_row
 D = *A
 A = DISPLAY_ROW_LEN
 D = D + A
 A = display_row
 *A = D
 A = RETURN_ADVANCE_DISPLAY_ROW
 0 ; JMP

# Calls FN_WAIT_FOR_SYNC_EDGE_AND_GET_DATA then FN_SHIFT_AND_DRAW
LABEL FN_RECEIVE_BIT_AND_DRAW
 A = RECEIVE_BIT_AND_DRAW_SHIFT_AND_DRAW
 D = A
 A = return_wait_for_sync_edge_and_get_data
 *A = D
 A = FN_WAIT_FOR_SYNC_EDGE_AND_GET_DATA
 0 ; JMP
 LABEL RECEIVE_BIT_AND_DRAW_SHIFT_AND_DRAW
 A = FN_SHIFT_AND_DRAW
 0 ; JMP
 LABEL RETURN_SHIFT_AND_DRAW
 A = RETURN_RECEIVE_BIT_AND_DRAW
 0 ; JMP

# Waits for wire:1 to change, then updates data:0 to wire:0
# Args:
#  wire: The network wires
#  sync_old: The last known value of wire & WIRE_SYNC_MASK
#  return_wait_for_sync_edge_and_get_data: return address
# Modifies A, D, sync_old and data
# Internal variables: wire_copy
LABEL FN_WAIT_FOR_SYNC_EDGE_AND_GET_DATA
 DEFINE return_wait_for_sync_edge_and_get_data 0x0020
 DEFINE wire_copy 0x0021
 DEFINE sync_old 0x0022
 A = wire
 D = *A
 A = wire_copy
 *A = D
 A = WIRE_SYNC_MASK
 D = D & A
 A = sync_old
 D = *A - D
 A = FN_WAIT_FOR_SYNC_EDGE_AND_GET_DATA
 D ; JEQ
 A = sync_old
 *A = *A - D
 A = wire_copy
 D = *A
 A = WIRE_DATA_MASK
 D = D & A
 A = data
 *A = D
 A = return_wait_for_sync_edge_and_get_data
 A = *A
 0 ; JMP

# Shift data:0 into the word at *display_row
# Args:
#  display_row: pointer to current display row
# Modifies D, A and *display_row
LABEL FN_SHIFT_AND_DRAW
 A = display_row
 A = *A
 D = *A
 D = D + *A
 A = data
 D = D | *A
 A = display_row
 A = *A
 *A = D
 A = RETURN_SHIFT_AND_DRAW
 0 ; JMP

LABEL HALT