aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2025-03-13 18:49:41 +0200
committerJan Tuomi <jan@jantuomi.fi>2025-03-13 18:49:41 +0200
commit06e8b8dbadf769507abf5368caee253ded139adc (patch)
tree0e4d7b495ecba85afc2738ff7ca254880f5b922c
parent7f83828988c2efab56f37c1711cbf6118be8234f (diff)
Improvements
-rw-r--r--atk16_schasm/bootstrap.scm6
-rw-r--r--atk16_schasm/core.scm200
-rw-r--r--atk16_schasm/macros.scm48
-rw-r--r--atk16_schasm/main.scm20
-rw-r--r--atk16_schasm/utils.scm95
5 files changed, 212 insertions, 157 deletions
diff --git a/atk16_schasm/bootstrap.scm b/atk16_schasm/bootstrap.scm
index d9105f8..30d2324 100644
--- a/atk16_schasm/bootstrap.scm
+++ b/atk16_schasm/bootstrap.scm
@@ -17,7 +17,7 @@
;; Set stack pointer to end of heap segment, i.e. one below addr-segment-mmio.
;; Stack grows down.
;; Heap grows up from addr-segment-heap until it meets the stack.
- (ld SP ZR (u16 (- addr-segment-mmio 1)))
+ (%ld SP (u16 (- addr-segment-mmio 1)))
;; Set graphics mode to disabled.
- (ld R0 ZR (u16 addr-mmio-graphics-mode))
- (st R0 ZR (u16 graphics-disabled)))
+ (%ld R0 (u16 addr-mmio-graphics-mode))
+ (%st R0 (u16 graphics-disabled)))
diff --git a/atk16_schasm/core.scm b/atk16_schasm/core.scm
index 32462da..4dd4974 100644
--- a/atk16_schasm/core.scm
+++ b/atk16_schasm/core.scm
@@ -2,60 +2,10 @@
(chicken bitwise)
(chicken format)
(chicken io)
+ (chicken keyword)
(only srfi-1 iota))
-;; Utils
-
-(define-syntax comment
- (syntax-rules ()
- ((_ expr* ...)
- (begin))))
-
-(define-syntax @
- (syntax-rules ()
- ((_ fn-body expr ...)
- (lambda (x) (fn-body expr ... x)))))
-
-(define (zip alist blist)
- (if (null? alist)
- '()
- ;; else, cons and recurse
- (cons (cons (car alist) (car blist)) (zip (cdr alist) (cdr blist)))))
-
-(define (type-of pair)
- (if (pair? pair) (car pair) (error "not a pair" pair)))
-(define (val-of pair)
- (if (pair? pair) (cdr pair) (error "not a pair" pair)))
-
-(define (assocar k alist)
- (let ((v (assoc k alist)))
- (and v (car v))))
-(define (assocdr k alist)
- (let ((v (assoc k alist)))
- (and v (cdr v))))
-
-(define-syntax inc!
- (syntax-rules ()
- ((_ n)
- (set! n (+ n 1)))
- ((_ n m)
- (set! n (+ n m)))))
-(define-syntax sub!
- (syntax-rules ()
- ((_ n)
- (set! n (- n 1)))
- ((_ n m)
- (set! n (- n m)))))
-
-(define (string->ascii-list s)
- (let* ((len (string-length s))
- (dummy (cons #f '()))
- (tail dummy))
- (do ((i 0 (+ i 1)))
- ((= i len))
- (set-cdr! tail (cons (char->integer (string-ref s i)) '()))
- (set! tail (cdr tail)))
- (cdr dummy)))
+(load "utils.scm")
;; State
@@ -101,10 +51,12 @@
;; Encode and emit
+(define (foobar x y . rest) #f)
+
(define (encode-byte . chunks)
(let ((total-bits (apply + (map car chunks))))
(unless (= total-bits 8)
- (error "emit: total bits in chunks must equal 8, got" total-bits)))
+ (error "total bits in chunks must equal 8, got" total-bits)))
(let loop ((chs chunks) (acc 0))
(if (null? chs)
@@ -153,15 +105,21 @@
;; Directives
-(define-syntax def-label
- (syntax-rules ()
- ((_ sym exprs* ...)
- (begin
- (when (assoc sym *labels*)
- (error "label already defined" sym))
+(begin
+ (define (def-label-fn sym)
+ (when (assoc sym *labels*)
+ (error "label already defined" sym))
- (set! *labels* (cons (cons sym *cursor*) *labels*))
- exprs* ...))))
+ (set! *labels* (cons (cons sym *cursor*) *labels*))
+ )
+ (define-syntax def-label
+ (syntax-rules ()
+ ((_ sym exprs* ...)
+ (begin
+ (def-label-fn sym)
+ exprs* ...))))
+
+ )
(define-syntax at-addr
(syntax-rules ()
@@ -271,66 +229,64 @@
;; Instructions
-(define (hlt)
+(define (%hlt)
;; just full zeros
(emit-word 0))
-(define (alu op lhs rhs)
- (unless (eq? 'alu-op (type-of op)) (error "invalid op" op))
- (unless (eq? 'reg (type-of lhs)) (error "invalid lhs" lhs))
+(define (%alu op lhs rhs1 #!optional rhs2)
+ (unless (eq? 'reg (type-of lhs)) (error "invalid lhs register" lhs))
+ (define rhs-offset-pair (parse-rhs-offset rhs1 rhs2))
+ (define rhs (car rhs-offset-pair))
+ (define offset (cdr rhs-offset-pair))
- (define rhs-type (type-of rhs))
;; Addressing modes
;; 0: reg (1 word)
- ;; 1: reg + word (2 words)
- (define m-mode
- (cond ((eq? 'reg rhs-type) 0)
- ((eq? 'imm rhs-type) 1)
- ((eq? 'label rhs-type) 1)
- (else (error "invalid rhs" rhs))))
+ ;; 1: reg + word (2 words
- (if (= m-mode 0)
- ;; reg mode
- (begin
- (emit-byte-chunks `(4 . 1)
- `(3 . ,(val-of op))
- `(1 . ,m-mode))
- (emit-byte-chunks `(4 . ,(val-of lhs))
- `(4 . ,(val-of rhs))))
+ (define m-mode (if offset 1 0))
- ;; immediate mode
- (begin
- (emit-byte-chunks `(4 . 1)
- `(3 . ,(val-of op))
- `(1 . ,m-mode))
- (emit-byte-chunks `(4 . ,(val-of lhs))
- `(4 . 0))
+ (emit-byte-chunks `(4 . 1)
+ `(3 . ,(val-of op))
+ `(1 . ,m-mode))
+ (emit-byte-chunks `(4 . ,(val-of lhs))
+ `(4 . ,(val-of rhs)))
- (if (eq? 'label rhs-type)
- ;; if label, emit a label reference
- (begin (emit-deferred-sexpr `(label . (hi ,(val-of rhs))))
- (emit-deferred-sexpr `(label . (lo ,(val-of rhs)))))
- ;; otherwise, emit the value
- (emit-word (val-of rhs))))))
+ (cond
+ ;; in reg+word mode, if label, emit a label reference
+ ((and offset (eq? 'label (type-of offset)))
+ (emit-deferred-sexpr `(label . (hi ,(val-of offset))))
+ (emit-deferred-sexpr `(label . (lo ,(val-of offset)))))
+ ;; in reg+word mode, if imm, emit the value
+ ((and offset (eq? 'imm (type-of offset)))
+ (emit-word (val-of offset)))
+ (offset
+ (error "invalid offset in reg+word addressing mode" offset))))
-(define (add lhs rhs) (alu (alu-op 0) lhs rhs))
-(define (sub lhs rhs) (alu (alu-op 1) lhs rhs))
-(define (and lhs rhs) (alu (alu-op 2) lhs rhs))
-(define (or lhs rhs) (alu (alu-op 3) lhs rhs))
-(define (xor lhs rhs) (alu (alu-op 4) lhs rhs))
-(define (shl lhs rhs) (alu (alu-op 5) lhs rhs))
-(define (shr lhs rhs) (alu (alu-op 6) lhs rhs))
-(define (sar lhs rhs) (alu (alu-op 7) lhs rhs))
+(define (%add lhs rhs1 #!optional rhs2) (%alu (alu-op 0) lhs rhs1 rhs2))
+(define (%sub lhs rhs1 #!optional rhs2) (%alu (alu-op 1) lhs rhs1 rhs2))
+(define (%and lhs rhs1 #!optional rhs2) (%alu (alu-op 2) lhs rhs1 rhs2))
+(define (%or lhs rhs1 #!optional rhs2) (%alu (alu-op 3) lhs rhs1 rhs2))
+(define (%xor lhs rhs1 #!optional rhs2) (%alu (alu-op 4) lhs rhs1 rhs2))
+(define (%shl lhs rhs1 #!optional rhs2) (%alu (alu-op 5) lhs rhs1 rhs2))
+(define (%shr lhs rhs1 #!optional rhs2) (%alu (alu-op 6) lhs rhs1 rhs2))
+(define (%sar lhs rhs1 #!optional rhs2) (%alu (alu-op 7) lhs rhs1 rhs2))
;; Load data to to-reg from memory pointed by from-reg + offset.
;; With indirect = 0, copies the value from-reg + offset to to-reg without memory access.
-(define (ld to-reg from-reg #!optional offset #!key (indirect 0) (preinc #f))
- (unless (eq? 'reg (type-of to-reg)) (error "invalid target register" to-reg))
- (unless (eq? 'reg (type-of from-reg)) (error "invalid source register" from-reg))
- (unless (or (not offset)
- (eq? 'imm (type-of offset))
- (eq? 'label (type-of offset)))
- (error "invalid offset" offset))
+
+;; TODO tää ei toimi niinkun kuvittelis. key arg menee optionaalin paikalle.
+
+(define (%ld lhs rhs1 . rest)
+ (define-values (pos kws) (rest-args rest))
+ (define rhs2 (if (> (length pos) 0) (car pos) #f))
+ (define indirect (or (assocdr #:indirect kws) 0))
+ (define preinc (or (assocdr #:preinc kws) #f))
+
+ (unless (eq? 'reg (type-of lhs)) (error "invalid lhs register" lhs))
+ (define rhs-offset-pair (parse-rhs-offset rhs1 rhs2))
+ (define rhs (car rhs-offset-pair))
+ (define offset (cdr rhs-offset-pair))
+
(unless (and (number? indirect)
(>= indirect 0)
(< indirect 4))
@@ -349,8 +305,8 @@
`(2 . ,indirect)
`(1 . ,m-mode)
`(1 . ,p-mode))
- (emit-byte-chunks `(4 . ,(val-of to-reg))
- `(4 . ,(val-of from-reg)))
+ (emit-byte-chunks `(4 . ,(val-of lhs))
+ `(4 . ,(val-of rhs)))
(cond
;; in reg+word mode, if label, emit a label reference
@@ -364,13 +320,17 @@
(error "invalid offset in reg+word addressing mode" offset))))
;; Store data in from-reg to memory pointed by to-reg + offset.
-(define (st from-reg to-reg #!optional offset #!key (indirect 1) (postdec #f))
- (unless (eq? 'reg (type-of to-reg)) (error "invalid target register" to-reg))
- (unless (eq? 'reg (type-of from-reg)) (error "invalid source register" from-reg))
- (unless (or (not offset)
- (eq? 'imm (type-of offset))
- (eq? 'label (type-of offset)))
- (error "invalid offset" offset))
+(define (%st lhs rhs1 . rest)
+ (define-values (pos kws) (rest-args rest))
+ (define rhs2 (if (> (length pos) 0) (car pos) #f))
+ (define indirect (or (assocdr #:indirect kws) 1))
+ (define postdec (or (assocdr #:postdec kws) #f))
+
+ (unless (eq? 'reg (type-of lhs)) (error "invalid lhs register" lhs))
+ (define rhs-offset-pair (parse-rhs-offset rhs1 rhs2))
+ (define rhs (car rhs-offset-pair))
+ (define offset (cdr rhs-offset-pair))
+
(unless (and (number? indirect)
(>= indirect 1)
(< indirect 4))
@@ -389,8 +349,8 @@
`(2 . ,indirect)
`(1 . ,m-mode)
`(1 . ,p-mode))
- (emit-byte-chunks `(4 . ,(val-of from-reg))
- `(4 . ,(val-of to-reg)))
+ (emit-byte-chunks `(4 . ,(val-of lhs))
+ `(4 . ,(val-of rhs)))
(cond
;; in reg+word mode, if label, emit a label reference
@@ -403,7 +363,7 @@
(offset
(error "invalid offset in reg+word addressing mode" offset))))
-(define (br flag offset #!key (asserted #t))
+(define (%br flag offset #!key (asserted #t))
(unless (eq? 'flag (type-of flag)) (error "invalid flag selector" flag))
(define set
diff --git a/atk16_schasm/macros.scm b/atk16_schasm/macros.scm
index fb1ed3e..a2091b3 100644
--- a/atk16_schasm/macros.scm
+++ b/atk16_schasm/macros.scm
@@ -18,21 +18,21 @@
(define-syntax emit-test-eq
(syntax-rules ()
((_ lhs rhs dest set)
- (begin (sub lhs rhs)
- (br flag-zero (label dest) set: set)))))
+ (begin (%sub lhs rhs)
+ (%br flag-zero (label dest) #:asserted set)))))
(define-syntax emit-test-lt
(syntax-rules ()
((_ lhs rhs dest set)
- (begin (sub lhs rhs)
- (br flag-sign (label dest) set: set)))))
+ (begin (%sub lhs rhs)
+ (%br flag-sign (label dest) #:asserted set)))))
(define-syntax emit-test-lte
(syntax-rules ()
((_ lhs rhs dest set)
- (begin (sub lhs rhs)
- (sub lhs (u16 1))
- (br flag-sign (label dest) set: set)))))
+ (begin (%sub lhs rhs)
+ (%sub lhs ZR (u16 1))
+ (%br flag-sign (label dest) #:asserted set)))))
(define-syntax emit-inverted-test
;; jump to dest if <lhs op rhs> is NOT true.
@@ -60,12 +60,12 @@
(n (next-unique))
(sym-false (string->symbol (format "~A-false" n)))
(sym-end (string->symbol (format "~A-end" n))))
- (ld *macro-scratch-reg* lhs)
+ (%ld *macro-scratch-reg* lhs)
(emit-inverted-test *macro-scratch-reg* op rhs sym-false)
tb
- (ld PC ZR (label sym-end))
+ (%ld PC ZR (label sym-end))
(def-label sym-false)
fb
(def-label sym-end)))))
@@ -78,7 +78,7 @@
(rhs (eval (caddr `pred)))
(n (next-unique))
(sym-end (string->symbol (format "~A-end" n))))
- (ld *macro-scratch-reg* lhs)
+ (%ld *macro-scratch-reg* lhs)
(emit-inverted-test *macro-scratch-reg* op rhs sym-end)
@@ -95,19 +95,19 @@
(n (next-unique))
(sym-test (string->symbol (format "~A-test" n)))
(sym-end (string->symbol (format "~A-end" n))))
- (ld *macro-scratch-reg* lhs)
+ (%ld *macro-scratch-reg* lhs)
(def-label sym-test)
(emit-inverted-test *macro-scratch-reg* op rhs sym-end)
body body* ...
- (ld PC ZR (label sym-test))
+ (%ld PC ZR (label sym-test))
(def-label sym-end)))))
(define *procedures* '())
-(define-syntax %decl-proc
+(define-syntax decl-proc
(syntax-rules ()
((_ signature)
(set! *procedures*
@@ -137,11 +137,11 @@
(n-max-params 12))
(unless (<= (length params) n-max-params)
(error (format "proc has too many params (~A > ~A)" (length params) n-max-params)))
- (%decl-proc signature)
+ (decl-proc signature)
(def-label name)
(parameterize ((*proc-scope* bindings))
body* ...)
- (ld PC SP #f preinc: #t indirect: 1)
+ (%ld PC SP #f preinc: #t indirect: 1)
))))
(define-syntax %call
@@ -177,29 +177,29 @@
(itype (type-of argi)))
(cond
((eq? 'reg itype)
- (ld rn argi))
+ (%ld rn argi))
((or (eq? 'imm itype)
(eq? 'label itype))
- (ld rn ZR argi))
+ (%ld rn ZR argi))
(else (error "invalid argument" argi))))
(loop (+ 1 i))))
- (ld *macro-scratch-reg* ZR (label sym-ret))
- (st *macro-scratch-reg* SP #f postdec: #t)
+ (%ld *macro-scratch-reg* ZR (label sym-ret))
+ (%st *macro-scratch-reg* SP #f #:postdec #t)
- (ld PC ZR (label `name))
+ (%ld PC ZR (label `name))
(def-label sym-ret)
))))
(define (spush datum)
(cond
((eq? 'reg (type-of datum))
- (st datum SP push: #t))
+ (%st datum SP #:postdec #t))
(else
- (ld *macro-scratch-reg* datum)
- (st *macro-scratch-reg* SP push: #t indirect: 1))))
+ (%ld *macro-scratch-reg* datum)
+ (%st *macro-scratch-reg* SP #:postdec #t #:indirect 1))))
(define (spop reg)
(unless (eq? 'reg (type-of reg))
(error "not a register" reg))
- (ld reg SP pop: #t indirect: 1))
+ (%ld reg SP #:preinc #t #:indirect 1))
diff --git a/atk16_schasm/main.scm b/atk16_schasm/main.scm
index 4dc353a..62d2919 100644
--- a/atk16_schasm/main.scm
+++ b/atk16_schasm/main.scm
@@ -8,7 +8,7 @@
(emit-word #x1234)
;; compile instructions
-(ld SP ZR (u16 0))
+(%ld SP ZR (u16 0))
;; set labels
(def-label 'some-data
@@ -18,19 +18,19 @@
;; set the current emit address
(at-addr #x20)
(def-label 'main
- (add R1 R2)
- (add R3 (u16 #xFF)))
+ (%add R1 R2)
+ (%add R3 (u16 #xFE)))
;; abs jump
-(ld PC ZR (label 'main))
+(%ld PC (label 'main))
;; rel jump
-(add PC (i16 10))
+(%add PC (i16 10))
;; jump forward to a currently undefined label
-(ld PC ZR (label 'forward))
+(%ld PC (label 'forward))
(def-label 'forward
- (hlt))
+ (%hlt))
;; store string data in memory
(def-label 'text-data
@@ -39,7 +39,7 @@
(at-addr #x50)
;; branch based on an ALU flag
-(br flag-carry (label 'branch-true) set: #t)
+(%br flag-carry (label 'branch-true) #:asserted #t)
(def-label 'branch-false
(emit-word 1))
(def-label 'branch-true
@@ -66,10 +66,10 @@
)
;; procedure calls
-(ld R1 ZR (u16 10))
+(%ld R1 (u16 10))
(%while (R1 > (u16 0))
(%call println (label 'text-data))
- (sub R1 (u16 1)))
+ (%sub R1 (u16 1)))
;; compile to a 128KB image file
(write-image-to "out.bin")
diff --git a/atk16_schasm/utils.scm b/atk16_schasm/utils.scm
new file mode 100644
index 0000000..f5e74e3
--- /dev/null
+++ b/atk16_schasm/utils.scm
@@ -0,0 +1,95 @@
+;; Utils
+
+(define-syntax comment
+ (syntax-rules ()
+ ((_ expr* ...)
+ (begin))))
+
+(define-syntax @
+ (syntax-rules ()
+ ((_ fn-body expr ...)
+ (lambda (x) (fn-body expr ... x)))))
+
+(define (zip alist blist)
+ (if (null? alist)
+ '()
+ ;; else, cons and recurse
+ (cons (cons (car alist) (car blist)) (zip (cdr alist) (cdr blist)))))
+
+(define (type-of pair)
+ (if (pair? pair) (car pair) (error "not a pair" pair)))
+(define (val-of pair)
+ (if (pair? pair) (cdr pair) (error "not a pair" pair)))
+
+(define (parse-rhs-offset rhs1 rhs2)
+ (define t1 (and rhs1 (type-of rhs1)))
+ (define t2 (and rhs2 (type-of rhs2)))
+
+ (define regs '())
+ (when (eq? 'reg t1)
+ (set! regs (cons rhs1 regs)))
+ (when (eq? 'reg t2)
+ (set! regs (cons rhs2 regs)))
+ (unless (<= (length regs) 1)
+ (error "only one register can be supplied as rhs"))
+
+ (define offsets '())
+ (when (or (eq? 'imm t1) (eq? 'label t1))
+ (set! offsets (cons rhs1 offsets)))
+ (when (or (eq? 'imm t2) (eq? 'label t2))
+ (set! offsets (cons rhs2 offsets)))
+ (unless (<= (length offsets) 1)
+ (error "only one imm or label can be supplied as rhs"))
+
+ (define rhs (if (null? regs) ZR (car regs)))
+ (define offset (if (null? offsets) (imm 0) (car offsets)))
+
+ (cons rhs offset))
+
+(define (assocar k alist)
+ (let ((v (assoc k alist)))
+ (and v (car v))))
+(define (assocdr k alist)
+ (let ((v (assoc k alist)))
+ (and v (cdr v))))
+
+(define-syntax inc!
+ (syntax-rules ()
+ ((_ n)
+ (set! n (+ n 1)))
+ ((_ n m)
+ (set! n (+ n m)))))
+(define-syntax sub!
+ (syntax-rules ()
+ ((_ n)
+ (set! n (- n 1)))
+ ((_ n m)
+ (set! n (- n m)))))
+
+(define (string->ascii-list s)
+ (let* ((len (string-length s))
+ (dummy (cons #f '()))
+ (tail dummy))
+ (do ((i 0 (+ i 1)))
+ ((= i len))
+ (set-cdr! tail (cons (char->integer (string-ref s i)) '()))
+ (set! tail (cdr tail)))
+ (cdr dummy)))
+
+(define (rest-args args)
+ (define pos '())
+ (define kws '())
+
+ (let loop ((as args))
+ (when (not (null? as))
+ (let ((head (car as))
+ (tail (cdr as)))
+ (cond
+ ((keyword? head)
+ (set! kws (cons (cons head (car tail)) kws))
+ (loop (cdr tail)))
+ (else
+ (set! pos (append pos (list head)))
+ (loop tail))))))
+
+ (values pos kws))