1 (define bank-1-used? #f)
3 (define (linearize-and-cleanup cfg)
5 (define bbs-vector (cfg->vector cfg))
10 (set! todo (cons bb todo)))
15 (set! rev-code (cons instr rev-code)))
17 (define (outside-bank-0? adr)
18 (if (and (> adr #x5F) (< adr #xF60)) ; not a special register
19 (begin (set! bank-1-used? #t) #t)
21 (define (emit-byte-oriented op file #!optional (d? #t) (w? #f))
22 ;; we might have to access the second bank
23 (emit (if (outside-bank-0? file)
25 (list op (- file 96) (if w? 'w 'f) 'b)
26 (list op (- file 96) 'b))
28 (list op file (if w? 'w 'f) 'a)
30 (define (emit-bit-oriented op file bit)
31 (emit (if (outside-bank-0? file)
32 (list op (- file 96) bit 'b)
33 (list op file bit 'a))))
36 (emit (list 'movlw val)))
38 (emit-byte-oriented 'movwf adr #f))
40 (emit-byte-oriented 'movf adr #t #t))
41 (define (movff src dst)
42 ;; anything over #x5f is in the second bank (at #x100)
43 (let ((src (if (outside-bank-0? src)
46 (dst (if (outside-bank-0? dst)
49 (emit (list 'movff src dst))))
52 (emit-byte-oriented 'clrf adr #f))
54 (emit-byte-oriented 'setf adr #f))
57 (emit-byte-oriented 'incf adr))
59 (emit-byte-oriented 'decf adr))
62 (emit-byte-oriented 'addwf adr))
64 (emit-byte-oriented 'addwfc adr))
67 (emit-byte-oriented 'subwf adr))
69 (emit-byte-oriented 'subwfb adr))
72 (emit (list 'mullw adr)))
74 (emit-byte-oriented 'mulwf adr #f))
77 (emit-byte-oriented 'andwf adr))
79 (emit-byte-oriented 'iorwf adr))
81 (emit-byte-oriented 'xorwf adr))
84 (emit-byte-oriented 'rlcf adr))
86 (emit-byte-oriented 'rrcf adr))
89 (emit-bit-oriented 'bcf adr bit))
91 (emit-bit-oriented 'bsf adr bit))
93 (emit-bit-oriented 'btg adr bit))
96 (emit-byte-oriented 'comf adr))
98 (define (tblrd) ;; TODO support the different modes
102 (emit-byte-oriented 'cpfseq adr #f))
104 (emit-byte-oriented 'cpfslt adr #f))
106 (emit-byte-oriented 'cpfsgt adr #f))
109 (emit (list 'bc label)))
110 (define (bra-or-goto label)
111 (emit (list 'bra-or-goto label)))
113 (emit (list 'goto label)))
115 (define (rcall label)
116 (emit (list 'rcall label)))
119 (if (and #f (and (not (null? rev-code))
120 (eq? (caar rev-code) 'rcall)))
121 (let ((label (cadar rev-code)))
122 (set! rev-code (cdr rev-code))
124 (emit (list 'return))))
127 (if (and #f (and (not (null? rev-code))
128 (eq? (caar rev-code) 'bra-or-goto)
129 (eq? (cadar rev-code) lab)))
131 (set! rev-code (cdr rev-code))
133 (emit (list 'label lab))))
136 (emit (list 'sleep)))
138 (define (move-reg src dst)
147 ;; takes 2 cycles (as much as movfw src ; movwf dst), but takes
148 ;; only 1 instruction
151 (define (bb-linearize bb)
152 (let ((label-num (bb-label-num bb)))
153 (let ((bb (vector-ref bbs-vector label-num)))
155 (define (move-lit n adr)
164 (define (dump-instr instr)
165 (cond ((call-instr? instr)
166 (let* ((def-proc (call-instr-def-proc instr))
167 (entry (def-procedure-entry def-proc)))
171 (let ((label (bb-label entry)))
174 ((return-instr? instr)
177 (let ((src1 (instr-src1 instr))
178 (src2 (instr-src2 instr))
179 (dst (instr-dst instr)))
180 (if (and (or (not (byte-cell? dst))
182 (or (not (byte-cell? src1))
183 (byte-cell-adr src1))
184 (or (not (byte-cell? src2))
185 (byte-cell-adr src2)))
187 (case (instr-id instr)
191 (let ((n (byte-lit-val src1))
192 (z (byte-cell-adr dst)))
194 (let ((x (byte-cell-adr src1))
195 (z (byte-cell-adr dst)))
200 (let ((n (byte-lit-val src2))
201 (z (byte-cell-adr dst))
202 (id (instr-id instr)))
204 (move-lit (byte-lit-val src1) z)
205 (move-reg (byte-cell-adr src1) z))
206 (if (not (and (= n 0) ; nop
210 ((add) (cond ((= n 1) (incf z))
211 ((= n #xff) (decf z)) ;; TODO set the carry if needed ?
214 ((addc) (movlw n) (addwfc z))
215 ((sub) (cond ((= n 1) (decf z))
216 ((= n #xff) (incf z)) ;; TODO same
219 ((subb) (movlw n) (subwfb z)))))
220 (let ((x (byte-cell-adr src1))
221 (y (byte-cell-adr src2))
222 (z (byte-cell-adr dst)))
223 (cond ((and (not (= x y))
225 (memq (instr-id instr)
227 ;; since this basically swaps the
228 ;; arguments, it can't be used for
233 ;; for subtraction, preserves argument
236 ;; this NEEDS to be done with movff, or
237 ;; else wreg will get clobbered and this
240 (else ;; TODO check if it could be merged with the previous case
243 (case (instr-id instr)
248 (else (error "..."))))))
250 ((mul) ; 8 by 8 multiplication
252 ;; since multiplication is commutative, the
253 ;; arguments are set up so the second one will
254 ;; be a literal if the operator is applied on a
255 ;; literal and a variable
256 (let ((n (byte-lit-val src2)))
258 (movlw (byte-lit-val src1))
259 (move-reg (byte-cell-adr src1) WREG))
260 ;; literal multiplication
262 (let ((x (byte-cell-adr src1))
263 (y (byte-cell-adr src2)))
268 (let* ((x (if (byte-lit? src1)
270 (byte-cell-adr src1)))
271 (y (if (byte-lit? src2)
273 (byte-cell-adr src2)))
274 (z (byte-cell-adr dst))
275 (id (instr-id instr))
280 (else (error "...")))))
282 (cond ((or (and (eq? id 'and) (= y #xff))
283 (and (eq? id 'ior) (= y #x00)))
284 ;; nop, just move the value
288 ((and (eq? id 'and) (= y #x00))
290 ((and (eq? id 'ior) (= y #xff))
292 (else (if (byte-lit? src1)
297 (begin (if (and (not (= x y)) (= y z))
305 (let ((x (if (byte-lit? src1)
307 (byte-cell-adr src1)))
308 (z (byte-cell-adr dst)))
309 (cond ((byte-lit? src1) (move-lit x z))
310 ((not (= x z)) (move-reg x z)))
311 (case (instr-id instr)
317 (if (not (byte-lit? src2))
318 (error "bit offset must be a literal"))
319 (let ((x (byte-cell-adr src1))
320 (y (byte-lit-val src2)))
321 (case (instr-id instr)
324 ((toggle) (btg x y)))))
327 (let ((z (byte-cell-adr dst)))
329 (move-lit (byte-lit-val src1) z)
330 (move-reg (byte-cell-adr src1) z))
335 (move-lit (byte-lit-val src1) TBLPTRL)
336 (move-reg (byte-cell-adr src1) TBLPTRL))
338 (move-lit (byte-lit-val src2) TBLPTRH)
339 (move-reg (byte-cell-adr src2) TBLPTRH))
340 ;; TODO the 5 high bits are not used for now
344 (if (null? (bb-succs bb))
345 (error "I think you might have given me an empty source file."))
346 (let* ((succs (bb-succs bb))
348 (bra-or-goto (bb-label dest))
351 (let* ((succs (bb-succs bb))
352 (dest-true (car succs))
353 (dest-false (cadr succs)))
355 (define (compare flip adr)
356 (case (instr-id instr)
357 ((x<y) (if flip (cpfsgt adr) (cpfslt adr)))
358 ((x>y) (if flip (cpfslt adr) (cpfsgt adr)))
360 (bra-or-goto (bb-label dest-false))
361 (bra-or-goto (bb-label dest-true))
362 (add-todo dest-false)
363 (add-todo dest-true))
365 (cond ((byte-lit? src1)
366 (let ((n (byte-lit-val src1))
367 (y (byte-cell-adr src2)))
368 (if #f #;(and (or (= n 0) (= n 1) (= n #xff))
369 (eq? (instr-id instr) 'x==y))
370 (special-compare-eq-lit n x)
375 (let ((x (byte-cell-adr src1))
376 (n (byte-lit-val src2)))
377 (if #f #;(and (or (= n 0) (= n 1) (= n #xff))
378 (eq? (instr-id instr) 'x==y))
379 (special-compare-eq-lit n x)
384 (let ((x (byte-cell-adr src1))
385 (y (byte-cell-adr src2)))
390 (let* ((succs (bb-succs bb))
391 (dest-true (car succs))
392 (dest-false (cadr succs))
393 ;; scratch is always a byte cell
394 (scratch (byte-cell-adr src1)))
395 ;; note : bc is too short for some cases
396 ;; (bc (bb-label dest-true))
397 ;; (bra-or-goto (bb-label dest-false))
398 ;; instead, we use scratch to indirectly test the
399 ;; carry and use regular branches
404 (bra-or-goto (bb-label dest-false))
405 (bra-or-goto (bb-label dest-true))))
408 (let ((off (if (byte-lit? src1) ; branch no
410 (byte-cell-adr src1)))
411 (scratch (byte-cell-adr src2))) ; working space
412 ;; precalculate the low byte of the PC
413 ;; note: both branches (off is a literal or a
414 ;; register) are of the same length in terms of
415 ;; code, which is important
419 ;; we add 4 times the offset, since gotos are 4
428 ;; to compensate for the PC advancing while we calculate
431 (movfw PCL) ;; TODO at assembly, this can all be known statically
437 ;; create the jump table
438 (for-each (lambda (bb)
445 (emit (list (instr-id instr))))))))))
449 (vector-set! bbs-vector label-num #f)
450 (label (bb-label bb))
451 (for-each dump-instr (reverse (bb-rev-instrs bb)))
452 (for-each add-todo (bb-succs bb)))))))
454 (let ((prog-label (asm-make-label 'PROG)))
459 (add-todo (vector-ref bbs-vector 0))
464 (let ((bb (car todo)))
465 (set! todo (cdr todo))
470 (define (assembler-gen filename cfg)
474 ((eval (car instr)) (cadr instr)))
476 ((eval (car instr)) (cadr instr) (caddr instr)))
478 ((eval (car instr)) (cadr instr) (caddr instr) (cadddr instr)))
482 ((movff movwf clrf setf cpfseq cpfslt cpfsgt mulwf)
484 ((incf decf addwf addwfc subwf subwfb andwf iorwf xorwf rlcf rrcf comf
488 (tblrd*)) ;; TODO support the other modes
496 (bra-or-goto (cadr instr)))
498 (rcall-or-call (cadr instr)))
503 (string-append (symbol->string (asm-label-id (cadr instr))) ":"))
504 (asm-label (cadr instr)))
508 (error "unknown instruction" instr))))
512 ;; (pretty-print cfg)
514 (let ((code (linearize-and-cleanup cfg)))
515 ;; (pretty-print code)
516 ;; if we would need a second bank, load the address for the second bank in BSR
518 (begin (gen (list 'movlw 1))
519 (gen (list 'movwf BSR 'a))))
520 (for-each gen code)))