All is one-op instructions (save push). Code in memory (this will allow compilation)
This commit is contained in:
172
scmvm/vm.scm
172
scmvm/vm.scm
@@ -4,7 +4,8 @@
|
||||
#:use-module (rnrs bytevectors)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:export (make-vm run-vm vm-memory-ref vm-memory-set! vm-memory
|
||||
#:export (make-vm run-vm vm-memory-ref vm-memory-set! vm-memory vm-load-program!
|
||||
vm-pc-ref vm-pc-set!
|
||||
*instruction-set* instruction-type instruction-code))
|
||||
|
||||
;;; Data Structures
|
||||
@@ -65,13 +66,8 @@
|
||||
((stack 'ref) k))
|
||||
|
||||
(define* (make-ram #:optional (memory-size *memory-size*))
|
||||
(make-vector memory-size #x00))
|
||||
(make-bytevector memory-size #x00))
|
||||
|
||||
(define (ram-ref ram k)
|
||||
(vector-ref ram k))
|
||||
|
||||
(define (ram-set! ram k v)
|
||||
(vector-set! ram k v))
|
||||
|
||||
;;; IO
|
||||
(define (read-word)
|
||||
@@ -81,31 +77,34 @@
|
||||
|
||||
;;; Instructions
|
||||
(define *instruction-set*
|
||||
'((push #x01 i)
|
||||
(pop #x02 o)
|
||||
(store #x03 i)
|
||||
(load #x04 i)
|
||||
(+ #x05 o)
|
||||
(- #x06 o)
|
||||
(and #x07 o)
|
||||
(or #x08 o)
|
||||
(nand #x09 o)
|
||||
(nor #x0a o)
|
||||
(xor #x0b o)
|
||||
(if #x0c j)
|
||||
(call #x0d j)
|
||||
(return #x0e o)
|
||||
(>R #x0f o)
|
||||
(R> #x10 o)
|
||||
(= #x11 o)
|
||||
(> #x12 o)
|
||||
(< #x13 o)
|
||||
(dup #x14 o)
|
||||
(swap #x15 o)
|
||||
(jmp #x16 j)))
|
||||
'((push #x01)
|
||||
(! #x02)
|
||||
(@ #x03)
|
||||
(+ #x04)
|
||||
(- #x05)
|
||||
(and #x06)
|
||||
(or #x07)
|
||||
(nand #x08)
|
||||
(nor #x09)
|
||||
(xor #x0a)
|
||||
(= #x0b)
|
||||
(> #x0c)
|
||||
(< #x0d)
|
||||
(jmp #x0e)
|
||||
(branch #x0f)
|
||||
(call #x10)
|
||||
(return #x11)
|
||||
(>R #x12)
|
||||
(R> #x13)
|
||||
(drop #x14)
|
||||
(nip #x15)
|
||||
(dup #x16)
|
||||
(swap #x17)
|
||||
(rot #x18)
|
||||
(over #x19)
|
||||
(bye #xff)))
|
||||
|
||||
(define instruction-code cadr)
|
||||
(define instruction-type caddr)
|
||||
|
||||
(define (op-lookup code)
|
||||
(car (find (lambda (x) (= (instruction-code x) code)) *instruction-set*)))
|
||||
@@ -128,32 +127,46 @@
|
||||
|
||||
|
||||
;;; Execution
|
||||
(define (jump addr)
|
||||
(seek (current-input-port) addr SEEK_SET))
|
||||
|
||||
(define (tell)
|
||||
(ftell (current-input-port)))
|
||||
|
||||
(define* (make-vm #:key stack-size memory-size)
|
||||
"Create a fresh VM, with optional stack and memory sizes"
|
||||
(define data-stack (if stack-size (make-stack stack-size) (make-stack)))
|
||||
(define ret-stack (if stack-size (make-stack stack-size) (make-stack)))
|
||||
(define ram (if memory-size (make-ram memory-size) (make-ram)))
|
||||
(define (ram-word-ref k)
|
||||
(if (< k 1)
|
||||
(error "null memory read")
|
||||
(bytevector-s32-native-ref ram (1- k))))
|
||||
(define (ram-byte-ref k)
|
||||
(if (< k 1)
|
||||
(error "null memory read")
|
||||
(bytevector-u8-ref ram (1- k))))
|
||||
(define (ram-word-set! k v)
|
||||
(if (< k 1)
|
||||
(error "null memory write")
|
||||
(bytevector-s32-native-set! ram (1- k) v)))
|
||||
(define pc 1)
|
||||
(define (jump x) (set! pc x))
|
||||
(define (fetch-byte)
|
||||
(let ([byte (ram-byte-ref pc)])
|
||||
(set! pc (+ pc 1))
|
||||
byte))
|
||||
(define (fetch-word)
|
||||
(let ([word (ram-word-ref pc)])
|
||||
(set! pc (+ pc 4))
|
||||
word))
|
||||
(define (fetch-and-execute)
|
||||
(define op (read-u8))
|
||||
(unless (eof-object? op)
|
||||
(define exit? #f)
|
||||
(let lp ([op (fetch-byte)])
|
||||
(case (op-lookup op)
|
||||
[(push)
|
||||
(push data-stack (read-word))]
|
||||
[(pop)
|
||||
(pop data-stack)]
|
||||
[(store)
|
||||
(let ([addr (read-word)]
|
||||
(push data-stack (fetch-word))]
|
||||
[(!)
|
||||
(let ([addr (pop data-stack)]
|
||||
[v (pop data-stack)])
|
||||
(ram-set! ram addr v))]
|
||||
[(load)
|
||||
(let* ([addr (read-word)]
|
||||
[v (ram-ref ram addr)])
|
||||
(ram-word-set! addr v))]
|
||||
[(@)
|
||||
(let* ([addr (pop data-stack)]
|
||||
[v (ram-word-ref addr)])
|
||||
(push data-stack v))]
|
||||
[(+ - and or nand nor xor)
|
||||
(let ([v2 (pop data-stack)]
|
||||
@@ -165,13 +178,15 @@
|
||||
(if ((relop-lookup op) v1 v2)
|
||||
(push data-stack 1)
|
||||
(push data-stack 0)))]
|
||||
[(if)
|
||||
(let ([addr (read-word)])
|
||||
(when (zero? (peek data-stack))
|
||||
[(jmp)
|
||||
(jump (pop data-stack))]
|
||||
[(branch)
|
||||
(let ([addr (pop data-stack)])
|
||||
(when (zero? (pop data-stack))
|
||||
(jump addr)))]
|
||||
[(call)
|
||||
(let ([addr (read-word)])
|
||||
(push ret-stack (tell))
|
||||
(let ([addr (pop data-stack)])
|
||||
(push ret-stack pc)
|
||||
(jump addr))]
|
||||
[(return)
|
||||
(jump (pop ret-stack))]
|
||||
@@ -179,19 +194,41 @@
|
||||
(push ret-stack (pop data-stack))]
|
||||
[(R>)
|
||||
(push data-stack (pop ret-stack))]
|
||||
[(drop)
|
||||
(pop data-stack)]
|
||||
[(nip)
|
||||
(let ([v (pop data-stack)])
|
||||
(pop data-stack)
|
||||
(push data-stack v))]
|
||||
[(dup)
|
||||
(push data-stack (peek data-stack))]
|
||||
[(swap)
|
||||
(swap data-stack)]
|
||||
[(jmp)
|
||||
(jump (read-word))])
|
||||
[(rot)
|
||||
(let* ([a (pop data-stack)]
|
||||
[b (pop data-stack)]
|
||||
[c (pop data-stack)])
|
||||
(push data-stack a)
|
||||
(push data-stack c)
|
||||
(push data-stack b))]
|
||||
[(over)
|
||||
(let* ([a (pop data-stack)]
|
||||
[b (pop data-stack)])
|
||||
(push data-stack b)
|
||||
(push data-stack a)
|
||||
(push data-stack b))]
|
||||
[(bye) (set! exit? #t)]))
|
||||
(when (not exit?)
|
||||
(fetch-and-execute)))
|
||||
(lambda (x)
|
||||
(case x
|
||||
[(run) fetch-and-execute]
|
||||
[(vm-run) fetch-and-execute]
|
||||
[(vm-memory) (lambda () ram)]
|
||||
[(vm-memory-ref) (cute ram-ref ram <>)]
|
||||
[(vm-memory-set!) (lambda (k v) (ram-set! ram k v))])))
|
||||
[(vm-memory-ref) ram-word-ref]
|
||||
[(vm-memory-set!) ram-word-set!]
|
||||
[(vm-pc-ref) (lambda () pc)]
|
||||
[(vm-pc-set!) (lambda (v) (set! pc v))]
|
||||
[else (error "vm unknown dispatch")])))
|
||||
|
||||
(define (vm-memory-ref vm k)
|
||||
"Externally access VM memory at k"
|
||||
@@ -205,6 +242,21 @@
|
||||
"Just get the memory vector"
|
||||
((vm 'vm-memory)))
|
||||
|
||||
(define (run-vm vm port)
|
||||
"Read and execute instructions read from port on VM"
|
||||
(with-input-from-port port (vm 'run)))
|
||||
(define (vm-load-program! vm prgm)
|
||||
"Loads the bytevector into the vm, starting at memory address 1"
|
||||
(let ([ram ((vm 'vm-memory))])
|
||||
(bytevector-copy! prgm 0
|
||||
ram 0
|
||||
(bytevector-length prgm))))
|
||||
|
||||
(define (vm-pc-ref vm)
|
||||
"Return the value of the pc"
|
||||
((vm 'vm-pc-ref)))
|
||||
|
||||
(define (vm-pc-set! vm pc)
|
||||
"Set the value of the pc"
|
||||
((vm 'vm-pc-set!) pc))
|
||||
|
||||
(define (run-vm vm)
|
||||
"Begin execution at pc"
|
||||
((vm 'vm-run)))
|
||||
|
||||
Reference in New Issue
Block a user