.include "../platform/c64_0.oph" .require "../platform/c64kernal.oph" .outfile "structuredemo.prg" jsr print'unsorted jsr insertion'sort jsr print'list rts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Linked list data: head, next, lb, hb. ; lb/hb: Low/high bytes of the data array. These are immutable and ; kept with the program text. ; head: Array index of the first element in the list, or #$FF if the ; list is empty ; next: Array of successor indices. If you've just read element X, ; the value of memory location next+X is the index of the ; next element. If next is #$FF, you've reached the end of ; the list. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .data .org $C000 .space head 1 .space next 16 .text lb: .byte <$838,<$618,<$205,<$984,<$724,<$301,<$249,<$946 .byte <$925,<$043,<$114,<$697,<$985,<$633,<$312,<$086 hb: .byte >$838,>$618,>$205,>$984,>$724,>$301,>$249,>$946 .byte >$925,>$043,>$114,>$697,>$985,>$633,>$312,>$086 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; insertion'sort: Sorts the list defined by head, next, hb, lb. ; Arguments: None. ; Modifies: All registers destroyed, head and next array sorted. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; insertion'sort: lda #$FF ; Clear list by storing the terminator in 'head' sta head ldx #$0 ; Loop through the lb/hb array, adding each insertion'sort'loop: ; element one at a time txa pha jsr insert_elt pla tax inx cpx #$10 bne insertion'sort'loop rts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; insert_elt: Insert an element into the linked list. Maintains the ; list in sorted, ascending order. Used by ; insertion'sort. ; Arguments: X register holds the index of the element to add. ; Modifies: All registers destroyed; head and next arrays updated ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .data .space lbtoinsert 1 .space hbtoinsert 1 .space indextoinsert 1 .text insert_elt: ldy head ; If the list is empty, make cpy #$FF ; head point at it, and return. bne insert_elt'list'not'empty stx head tya sta next,x rts insert_elt'list'not'empty: lda lb,x ; Cache the data we're inserting sta lbtoinsert lda hb,x sta hbtoinsert stx indextoinsert ldy head ; Compare the first value with sec ; the data. If the data must lda lb,y ; be inserted at the front... sbc lbtoinsert lda hb,y sbc hbtoinsert bmi insert_elt'not'smallest tya ; Set its next pointer to the sta next,x ; old head, update the head stx head ; pointer, and return. rts insert_elt'not'smallest: ldx head insert_elt'loop: ; At this point, we know that lda next,x ; argument > data[X]. tay cpy #$FF ; if next[X] = #$FF, insert arg at end. beq insert_elt'insert'after'current lda lb,y ; Otherwise, compare arg to sec ; data[next[X]]. If we insert sbc lbtoinsert ; before that... lda hb,y sbc hbtoinsert bmi insert_elt'goto'next insert_elt'insert'after'current: ; Fix up all the next links tya ldy indextoinsert sta next,y tya sta next,x rts ; and return. insert_elt'goto'next: ; Otherwise, let X = next[X] tya ; and go looping again. tax jmp insert_elt'loop ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; print'unsorted: Steps through the data array and prints each value. ; Standalone procedure. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print'unsorted: lda #unsorted'hdr jsr put'string ldy #$00 print'unsorted'loop: lda hb, Y jsr print'hex lda lb, y jsr print'hex lda #$20 jsr chrout iny cpy #$10 bne print'unsorted'loop lda #$0D jsr chrout rts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; print'list: Starts at head, and prints out every value in the ; linked list. ; Standalone procedure. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print'list: lda #sorted'hdr jsr put'string ldy head print'list'loop: cpy #$FF beq print'list'done lda hb, y jsr print'hex lda lb, y jsr print'hex lda #$20 jsr chrout lda next, Y tay jmp print'list'loop print'list'done: lda #$0d jsr chrout rts ;; String data for the above routines. unsorted'hdr: .byte 147 ; Clear screen first! .byte "UNSORTED DATA:",13,0 sorted'hdr: .byte "SORTED DATA:",13,0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; print'hex: outputs a two-character hex representation of a one- ; byte value. ; Arguments: Byte to print in accumulator ; Modifies: .A and .X ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print'hex: pha clc lsr lsr lsr lsr tax lda hexstr,x jsr chrout pla and #$0F tax lda hexstr,X jsr chrout rts ; Character data array for print'hex. hexstr: .byte "0123456789ABCDEF" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; put'string: outputs a C-style null terminated string with length ; less than 256 to the screen. If 256 bytes are written ; without finding a terminator, the routine ends quietly. ; Arguments: Low byte of string address in .A, high byte in .X ; Modifies: .A and .Y ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .data zp .space put'string'addr 2 .text put'string: sta put'string'addr stx put'string'addr+1 ldy #$00 put'string'loop: lda (put'string'addr),y beq put'string'done jsr chrout iny bne put'string'loop put'string'done: rts