;redcode ;name stack stuff ;author mjp ;assert 1 load0 z for 0 rof org main ;strategy implements common stack machine primitives and mixed ;strategy red/stack code example. ;strategy One stack for data and the other for return addresses. Makes ;strategy things simpler when you don't have to manage the return address ;strategy around data. The stack cell .b fields are the ones that hold ;strategy actual data, with .a fields being ignored. sp equ (load0-1000) ; data stack pointer rsp equ (load0+4000) ; return stack pointer ip equ CURLINE ; instruction pointer ; use 'ADR lab' for the absolute address of label 'lab' ADR equ -load0 + ;;-- data stack operations ;; ; ; implemented as macros (some of which take arguments) ; ; stack effect DUP equ mov.b @sp , sp ; (n --() DROP2 equ add #2 , sp ; (n2 n1 -- ) DROPN equ mov >sp , #0 ; ( nk ... n1 k -- ) equ add.b -1 , sp SWAP equ mov.b >sp , #0 ; (n2 n1 -- n1 n2) equ mov.b >sp , #0 equ mov.b -2 , sp+2 , @sp+2 equ mov.b @sp , sp , @sp ; (n2 n1 -- n2 n1) MINUS equ sub.b >sp , @sp TIMES equ mul.b >sp , @sp REM equ mod.b >sp , @sp DIVIDE equ div.b >sp , @sp NEG equ mul #-1 , @sp ; (n -- -n) tos equ @sp ;;-- return stacks ;; ; I wanted to use this: ; ;CALL equ mov #ip+2 , rsp , 2 ; load ret.adr. equ sub.a #ip+1 , 1 ; make relative equ jmp 0 ; and jump HALT equ stp.b 1 , #1 equ dat 0 , ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Main program ;; ; ; generates a random table and quicksorts it ; ;; :fib ( n -- fib(n) ) ;; fib: slt tos , #2 ; ( if n < 2 ) jmp fib_else fib_then: mov #1 , tos ; 1 jmp fib_out ; ( return ) fib_else: DUP ; ( calc. fib(n-1) ) sub #1 , tos ; dup 1- fib SAVERET jmp fib SWAP ; ( calc. fib(n-2) ) sub #2 , tos ; swap 2 - fib SAVERET jmp fib PLUS ; +~ fib_out: RET ; ( return ) ;; :rand ( -- n ) ;; rand: mul #6121 , _seed add #111 , _seed mov.b _seed , sp , #0 ; these are static variables, but gt_tab mov.b >sp , #0 ; that's ok as we don't recurse. jmz gt_out , gt_len ; if (len == 0) return sub #ADR gt_tab, gt_tab ; make the address of table ; relative gt_loop: SAVERET jmp rand ; get a rand() mov.b >sp , >gt_tab ; store it into the table djn gt_loop , gt_len gt_out RET ;; :qpartition ( table len -- low_partition_len ) ;; ; partition subroutine for quick sort ; qpartition: qp_len mov.b >sp , #0 ; pop argument len qp_tab mov.b >sp , #0 ; pop arg. table ptr. mov.ba qp_tab , qp_ptr ; lo := tab mov.ab qp_ptr , qp_ptr ; hi := lo+len add.b qp_len , qp_ptr sub # ADR qp_ptr, qp_ptr ; make pointers lo and hi sub.a # ADR qp_ptr, qp_ptr ; relative qp_x mov.b *qp_ptr , #0 ; choose a pivot element x ; (first in table) qp_loop: slt.b qp_x , = than jmp 2 ; the pivot jmp -2 , }qp_ptr slt.ab qp_ptr , qp_ptr ; if lo >= hi jmp qp_out , >qp_ptr ; then we exit qp_swap: ; else we swap *lo and *hi mov.b *qp_ptr , #0 mov.b @qp_ptr , *qp_ptr mov.b -2 , @qp_ptr jmp qp_loop qp_out: add #ADR qp_ptr, qp_ptr ; make absolute sub.b qp_tab , qp_ptr ; return index of hi mov.b qp_ptr , sp , #0 ; save parameters table and len q_tab mov.b >sp , #0 slt #1 , q_len ; if len <= 1 exit early jmp qs_out sub #2 , sp SAVERET jmp qpartition q_lolen mov.b >sp , #0 ; save lo partition length mov.b q_tab ,