@@ 1,18 1,16 @@
; go6502-cookbook/00_arithmetic_program/program.asm
; contains basic math operations, such as addition, subtraction,
; multiplication, and division.
-; ---------------------
-; go6502 Initialization
-; ---------------------
+
+;-[ go6502 initialization. ]--------------------------------------------------
.ARCH 65c02 ; select CMOS 65c02 chip.
.ORG $1000 ; origin address for machine code.
-; -------
-; Exports
-; -------
+;-[ go6502 symbol exports. ]--------------------------------------------------
.EX START
- .EX DATA
.EX END
+
+ ; arithmetic functions.
.EX ADDITION_8_BIT
.EX ADDITION_16_BIT
.EX SUBTRACTION_16_BIT
@@ 21,11 19,8 @@
.EX DIVISION_16_BY_8_BIT
.EX DIVIDE_16_BIT_BY_10
.EX DIVISION_8_BY_8_BIT
- .EX END_LOOP
-; ----------------
-; Memory Addresses
-; ----------------
+;-[ memory addresses. ]-------------------------------------------------------
; These addresses are on the zero page, which requires only one byte to
; address. More info about that here:
; https://en.wikipedia.org/wiki/Zero_page
@@ 35,9 30,7 @@ RESULT = $20
TEMP = $30
REMAINDER = $10
-; -------
-; Program
-; -------
+;-[ the program. ]------------------------------------------------------------
START:
CLD ; clear decimal bit.
@@ 59,14 52,10 @@ START:
JSR DIVIDE_16_BIT_BY_10
JSR DIVISION_8_BY_8_BIT
-; that's all, folks!
-END_LOOP:
- JMP END_LOOP ; infinite loop so the PC doesn't fall off.
-
-; -----------
-; Subroutines
-; -----------
+; infinite loop so the PC doesn't fall off.
+END: JMP END
+;-[ subroutines. ]------------------------------------------------------------
; simple 8-bit addition.
; operands are loaded from OPERAND_1 and OPERAND_2 addresses.
; result is stored as at RESULT address.
@@ 351,10 340,3 @@ DIV_L2: ROL OPERAND_1
BNE DIV_L1
RTS
-; ----
-; Data
-; ----
-DATA:
- .ALIGN 16 ; align next addr on 16-byte boundary.
-
-END
@@ 35,60 35,52 @@
; deleted element won't be re-used unless a new list is formed or the list
; shrinks and regrows over that element's data.
-; ---------------------
-; go6502 Initialization
-; ---------------------
+;-[ go6502 initialization. ]--------------------------------------------------
.ARCH 65c02 ; select CMOS 65c02 chip.
.ORG $1000 ; origin address for machine code.
-; -------
-; Exports
-; -------
+;-[ go6502 symbol exports. ]--------------------------------------------------
.EX START
+ .EX EXAMPLE_1
+ .EX EXAMPLE_2
.EX BP ; breakpoint ("b add bp")
+
+ ; linked list functions.
.EX LL_INIT
.EX LL_CLEAR
.EX LL_PUSH_BACK
.EX LL_POP_BACK
.EX LL_POP_FRONT
.EX LL_IS_EMPTY
- .EX LL_GET
- .EX LL_ERASE
.EX LL_NEXT
+ .EX LL_SEEK
+ .EX LL_GET
+ .EX LL_SET
+ .EX LL_DELETE
-
-; ----------------
-; Memory Addresses
-; ----------------
+;-[ memory addresses. ]-------------------------------------------------------
; offsets for internal linked list use.
LL_START_ADDR = $00 ; points to the start of the list or 0.
LL_END_ADDR = $01 ; points to the end of the list or 0.
LL_NODE_SIZE = $03 ; total size of a node.
; parameters and return values for linked list subroutine calls.
-LL_HEAP_ADDR = $00
+LL_HEAP_ADDR = $00 ; the start address of a 255-byte heap.
+LL_NODE_PTR = $02 ; an iteration pointer.
OPERAND_1 = $10
RESULT = $20
TEMP = $30
-; -------
-; Program
-; -------
+;-[ the program. ]------------------------------------------------------------
START:
; clear decimal bit.
CLD
- ; store the value $ff at addr $200.
- LDA #$ff
- STA $200
- ; store the value $d0 at addr $300.
- LDA #$d0
- STA $300
-
- ; in this example, we're going to push addresses $200 and $300
- ; onto the end of the linked list. we'll also pop them back off.
- ; you can watch the RESULT address in go6502 to see the effects
- ; as you "step over" the LL_POP_FRONT operations.
+; in this example, we're going to push addresses $200 and $300
+; onto the end of the linked list. we'll also pop them back off.
+; you can watch the RESULT address in go6502 to see the effects
+; as you "step over" the LL_POP_BACK operations.
+EXAMPLE_1:
; first, initialize the linked list at LL_HEAP_ADDR $100.
LDA #$00
STA LL_HEAP_ADDR
@@ 114,34 106,82 @@ START:
; pop elements from the end of the linked list.
; popped data addresses go into RESULT.
-BP: JSR LL_POP_BACK
+ JSR LL_POP_BACK
JSR LL_POP_BACK
; check if the linked list is empty.
- ; skip to END if it is.
+ ; skip to EXAMPLE_2 if it is.
JSR LL_IS_EMPTY
LDA RESULT
- BEQ END
+ BEQ EXAMPLE_2
; this shouldn't be executed.
JSR LL_POP_BACK
+; in this example, we're going to push addresses $200, $300, $400, and $500
+; onto the end of a linked list. then we'll iterate through the list.
+; we'll also seek to a specified index, get the element, and set it.
+EXAMPLE_2:
+ ; clear the list, push addresses $200, $300, $400, and $500 onto it.
+ JSR LL_CLEAR
+ LDA #$00
+ STA OPERAND_1
+ LDA #$2
+ STA OPERAND_1+1
+_EXAMPLE_2_PUSH_ELEMENT:
+ JSR LL_PUSH_BACK
+ INC OPERAND_1+1
+ LDA OPERAND_1+1
+ CMP #$6
+ BNE _EXAMPLE_2_PUSH_ELEMENT
+
+_EXAMPLE_2_ITERATE:
+ ; iterate through the linked list.
+ ; RESULT will be set to $200, $300, $400, and then $500.
+ JSR LL_NEXT
+ LDA LL_NODE_PTR
+ BEQ _EXAMPLE_2_SEEK
+ JSR LL_GET
+ JMP _EXAMPLE_2_ITERATE
+
+_EXAMPLE_2_SEEK:
+ ; seek to the element at index 2, then fetch it to RESULT ($400).
+ LDA #2
+ STA OPERAND_1
+ JSR LL_SEEK
+ JSR LL_GET
+
+ ; seek to the element at index 1 ($300), then set it to $FFFF.
+ LDA #1
+ STA OPERAND_1
+ JSR LL_SEEK
+ LDA #$ff
+ STA OPERAND_1
+ STA OPERAND_1+1
+ JSR LL_SET
+
+ ; seek to the element at index 2 ($400), then delete it.
+ LDA #2
+ STA OPERAND_1
+ JSR LL_SEEK
+BP: JSR LL_DELETE
+
; infinite loop so the PC doesn't fall off.
END: JMP END
-; -----------
-; Subroutines
-; -----------
-
+;-[ subroutines. ]------------------------------------------------------------
; initializes or resets the linked list at LL_HEAP_ADDR.
+; also sets the LL_NODE_PTR to 0.
LL_INIT:
LL_CLEAR:
; push A and Y onto the stack.
PHA
TYA
PHA
- ; set LL_HEAP_ADDR+LL_START_ADDR and LL_HEAP_ADDR+LL_END_ADDR to 0.
+ ; set LL_NODE_PTR to 0.
LDA #0
+ STA LL_NODE_PTR
+ ; set LL_HEAP_ADDR+LL_START_ADDR and LL_HEAP_ADDR+LL_END_ADDR to 0.
LDY #LL_START_ADDR
STA (LL_HEAP_ADDR),Y
LDY #LL_END_ADDR
@@ 355,12 395,196 @@ LL_IS_EMPTY:
PLA
RTS
+; moves LL_NODE_PTR by iterating through the linked list at LL_HEAP_ADDR.
+; if LL_NODE_PTR is 0, LL_NODE_PTR will begin from the first of the list.
+; if LL_NODE_PTR is at the end of the list when this is called,
+; LL_NODE_PTR will be set to 0.
+LL_NEXT:
+ ; push A and Y onto the stack.
+ PHA
+ TYA
+ PHA
+ ; see where LL_NODE_PTR is pointing to.
+ LDA LL_NODE_PTR
+ BEQ _LL_NEXT_GO_TO_FIRST_ELEM
+ ; iterate to the next node.
+ LDY LL_NODE_PTR
+ LDA (LL_HEAP_ADDR),Y
+ STA LL_NODE_PTR
+ JMP _LL_NEXT_RETURN
+_LL_NEXT_GO_TO_FIRST_ELEM:
+ LDY #LL_START_ADDR
+ LDA (LL_HEAP_ADDR),Y
+ STA LL_NODE_PTR
+_LL_NEXT_RETURN:
+ ; pull A and Y from the stack.
+ PLA
+ TAY
+ PLA
+ RTS
+
+; sets LL_NODE_PTR to the index specified by OPERAND_1 for the linked list
+; at LL_HEAP_ADDR. wraps around if the index exceeds the size of the list.
+LL_SEEK:
+ ; push A, X, and Y onto the stack.
+ PHA
+ TXA
+ PHA
+ TYA
+ PHA
+ ; reset to the beginning of the linked list.
+ LDA #0
+ STA LL_NODE_PTR
+ ; seek to the index specified at OPERAND_1.
+ LDX OPERAND_1
+_LL_SEEK_ITERATE:
+ JSR LL_NEXT
+ DEX
+ BMI _LL_SEEK_RETURN
+ JMP _LL_SEEK_ITERATE
+_LL_SEEK_RETURN:
+ ; pull A, X, and Y from the stack.
+ PLA
+ TAY
+ PLA
+ TAX
+ PLA
+ RTS
+
+; saves the current node's LL_DATA_ADDR to RESULT for the linked list at
+; LL_HEAP_ADDR. if LL_NODE_PTR is 0, does not modify RESULT.
LL_GET:
+ ; push A and Y onto the stack.
+ PHA
+ TYA
+ PHA
+ ; see where LL_NODE_PTR is pointing to. return if it's 0.
+ LDA LL_NODE_PTR
+ BEQ _LL_GET_RETURN
+ ; copy LL_NODE_PTR's LL_DATA_ADDR to RESULT.
+ TAY
+ INY
+ LDA (LL_HEAP_ADDR),Y
+ STA RESULT
+ INY
+ LDA (LL_HEAP_ADDR),Y
+ STA RESULT+1
+_LL_GET_RETURN:
+ ; pull A and Y from the stack.
+ PLA
+ TAY
+ PLA
RTS
-LL_ERASE:
+; saves OPERAND_1 to the current node's LL_DATA_ADDR for the linked list at
+; LL_HEAP_ADDR. if LL_NODE_PTR is 0, does not modify the linked list.
+LL_SET:
+ ; push A and Y onto the stack.
+ PHA
+ TYA
+ PHA
+ ; see where LL_NODE_PTR is pointing to. return if it's 0.
+ LDA LL_NODE_PTR
+ BEQ _LL_SET_RETURN
+ ; copy LL_NODE_PTR's LL_DATA_ADDR to RESULT.
+ TAY
+ INY
+ LDA OPERAND_1
+ STA (LL_HEAP_ADDR),Y
+ INY
+ LDA OPERAND_1+1
+ STA (LL_HEAP_ADDR),Y
+_LL_SET_RETURN:
+ ; pull A and Y from the stack.
+ PLA
+ TAY
+ PLA
RTS
-LL_NEXT:
+; deletes the current node at LL_NODE_PTR for the linked list at
+; LL_HEAP_ADDR. if LL_NODE_PTR is 0, does not modify the linked list.
+LL_DELETE:
+ ; push A, TEMP, RESULT, and Y onto the stack.
+ PHA
+ LDA TEMP
+ PHA
+ LDA RESULT
+ PHA
+ LDA RESULT+1
+ PHA
+ TYA
+ PHA
+ ; see where LL_NODE_PTR is pointing to. return if it's 0.
+ LDA LL_NODE_PTR
+ BEQ _LL_DELETE_RETURN
+ ; if LL_NODE_PTR is the only element, this is an LL_CLEAR.
+ LDY #LL_START_ADDR
+ LDA (LL_HEAP_ADDR),Y
+ LDY #LL_END_ADDR
+ CMP (LL_HEAP_ADDR),Y
+ BEQ _LL_DELETE_CLEAR_LIST
+ ; if LL_NODE_PTR is the first element, this is an LL_POP_FRONT.
+ LDY #LL_START_ADDR
+ LDA (LL_HEAP_ADDR),Y
+ CMP LL_NODE_PTR
+ BEQ _LL_DELETE_FIRST_NODE
+ ; if LL_NODE_PTR is the last element, this is an LL_POP_BACK.
+ LDY #LL_END_ADDR
+ LDA (LL_HEAP_ADDR),Y
+ CMP LL_NODE_PTR
+ BEQ _LL_DELETE_LAST_NODE
+ ; LL_NODE_PTR is in the middle of the list.
+ ; store LL_NODE_PTR at TEMP for comparison later.
+ LDA LL_NODE_PTR
+ STA TEMP
+ ; iterate through the list to find the previous node.
+ LDY #LL_START_ADDR
+_LL_DELETE_CHECK_IS_NEXT_NODE_CURRENT:
+ LDA (LL_HEAP_ADDR),Y
+ TAY
+ LDA (LL_HEAP_ADDR),Y
+ CMP TEMP
+ BNE _LL_DELETE_CHECK_IS_NEXT_NODE_CURRENT
+ ; set the previous node's (Y's) LL_NEXT_ADDR to LL_NODE_PTR's next.
+ ; push X and Y onto the stack.
+ TXA
+ PHA
+ TYA
+ PHA
+ LDY TEMP
+ LDA (LL_HEAP_ADDR),Y
+ TAX
+ PLA
+ ; pull Y (the previous node) from the stack.
+ TAY
+ TXA
+ STA (LL_HEAP_ADDR),Y
+ ; pull X from the stack.
+ PLA
+ TAX
+ ; set LL_NODE_PTR to the previous node.
+ TYA
+ STA LL_NODE_PTR
+ JMP _LL_DELETE_RETURN
+_LL_DELETE_CLEAR_LIST:
+ JSR LL_CLEAR
+ JMP _LL_DELETE_RETURN
+_LL_DELETE_FIRST_NODE:
+ JSR LL_POP_FRONT
+ JMP _LL_DELETE_RETURN
+_LL_DELETE_LAST_NODE:
+ JSR LL_POP_BACK
+ JMP _LL_DELETE_RETURN
+_LL_DELETE_RETURN:
+ ; pull A, TEMP, RESULT, and Y from the stack.
+ PLA
+ TAY
+ PLA
+ STA RESULT+1
+ PLA
+ STA RESULT
+ PLA
+ STA TEMP
+ PLA
RTS