(define-module (bytepusher) #:use-module (rnrs bytevectors) #:use-module (srfi srfi-1) #:use-module (srfi srfi-60) #:use-module (ice-9 binary-ports) #:use-module (sdl2) #:use-module (sdl2 render) #:use-module (sdl2 surface) #:use-module (sdl2 events) #:use-module (sdl2 video) #:use-module (sdl2 rect) #:use-module (sdl2 image)) (define width 256) (define height 256) (define scale 2) (define keys (make-bitvector 16 #f)) (define memory (make-bytevector (* 1024 1024 16))) ;; key control ---- (define (set-key! index) (bitvector-set-bit! keys index)) (define (clear-keys!) (bitvector-clear-all-bits! keys)) (define (keys->half) (let loop ((i 0) (acc 0)) (if (= i (bitvector-length keys)) acc (loop (+ 1 i) (+ acc (if (bitvector-bit-set? keys i) (expt 2 i) 0)))))) ;; ---- key control ;; memory ---- (define (get-pc) (get-addr 2)) (define (set-pc! value) (set-byte! 4 (ash value 0)) (set-byte! 3 (ash value -8)) (set-byte! 2 (ash value -16))) (define (get-addr pos) (+ (ash (get-byte (+ 2 pos)) 0) (ash (get-byte (+ 1 pos)) 8) (ash (get-byte pos) 16))) (define (get-initial-pixel) (ash (get-byte 5) 16)) (define (get-sample) (bytevector-u16-ref memory 6 (endianness big))) (define (get-byte n) (bytevector-u8-ref memory n)) (define (set-byte! n v) (bytevector-u8-set! memory n (logand v #xFF))) ;; ---- memory ;; colors ---- ; Only used to set the colormap, use the faster version is below (define (pixel->color pixel) (if (> pixel 216) 0 (let* ((r (modulo pixel 6)) (g (modulo (/ (- pixel (modulo pixel 6)) 6) 6)) (b (modulo (/ (- pixel (modulo pixel 36)) 36) 6))) (+ #xFF (ash (* #x33 (+ (ash r 16) (ash g 8) b)) 8))))) (define colormap (uint-list->bytevector (map pixel->color (iota 256)) (endianness big) 4)) (define (pixel->color-fast pixel) (bytevector-u32-ref colormap (* 4 pixel) (endianness big))) ;; ---- colors ;; debug ---- (define (peek-memory start end) (for-each (lambda (i) (display "0x") (display (number->string i 16)) (newline)) (take (drop (bytevector->u8-list memory) start) (- end start)))) (define (display-state) (sdl-init) (call-with-window (make-window #:title "BytePusher" #:size (list (* scale width) (* scale height))) (lambda (w) (call-with-renderer (make-renderer w) (lambda (renderer) (set-renderer-scale! renderer scale scale) (let ((texture (make-display-texture renderer))) (clear-renderer renderer) (load-display! texture) (render-copy renderer texture) (present-renderer renderer) (sleep 10)))))) (sdl-quit)) ;; ---- debug ;; rendering ---- (define (get-pixels) (let* ((initial (get-initial-pixel)) (len (* width height)) (base (make-bytevector len)) (final (make-bytevector (* 4 len)))) (bytevector-copy! memory initial base 0 len) (let loop ((i 0)) (bytevector-u32-set! final (* 4 i) (pixel->color-fast (bytevector-u8-ref base i)) (endianness big)) (unless (= i (- len 1)) (loop (+ 1 i)))) final)) (define (make-display-texture renderer) (make-texture renderer 'argb8888 'streaming width height)) (define (load-display! texture) (update-texture texture (make-rect 0 0 width height) (get-pixels) (* width 4))) ;; ---- rendering ;; main operation ---- (define (load-program! path) (call-with-input-file path (lambda (p) (let ((program (get-bytevector-all p))) (bytevector-copy! program 0 memory 0 (bytevector-length program)))))) (define (execute! instruction-addr) (call-with-values (lambda () (load-instruction instruction-addr)) (lambda (a b c) (set-byte! b (get-byte a)) (set-pc! c)))) (define (load-instruction instruction-addr) (let ((a (get-addr (+ 0 instruction-addr))) (b (get-addr (+ 3 instruction-addr))) (c (get-addr (+ 6 instruction-addr)))) #;(display (string-append "a: " (number->string a 16) " ")) #;(display (string-append "b: " (number->string b 16) " ")) #;(display (string-append "c: " (number->string c 16) "\n")) (values a b c))) (define (loop-frame!) (let loop ((count 65536)) (execute! (get-pc)) (unless (= count 0) (loop (- count 1))))) (define (loop! renderer) (define texture (make-display-texture renderer)) (set-renderer-scale! renderer scale scale) (let loop () (let ((t0 (sdl-ticks))) (loop-frame!) (clear-renderer renderer) (load-display! texture) (render-copy renderer texture) (present-renderer renderer) (let* ((t1 (sdl-ticks)) (frame-time (exact->inexact 1000/60)) (max-time (+ t0 frame-time))) (when (> max-time t1) (usleep (inexact->exact (floor (* 1000 (- max-time t1)))))) (display (string-append "FPS: " (number->string (exact->inexact (/ 1000 (- (sdl-ticks) t0)))) "(" (number->string (exact->inexact (/ 1000 (- t1 t0)))) ")\n")))) (loop))) (define (main) (load-program! "tests/palette.bp") (sdl-init) (call-with-window (make-window #:title "BytePusher" #:size (list (* scale width) (* scale height))) (lambda (w) (call-with-renderer (make-renderer w '(accelerated)) loop!))) (sdl-quit)) ;; ---- main operation ;; tests ---- (define (test-pc) (for-each (lambda (addr) (set-pc! addr) (when (not (= (get-pc) addr)) (error "Error in set pc"))) (iota #x1000000))) ;; ---- tests