feat: implement simple opcodes
This commit is contained in:
parent
fa7a8b792b
commit
290a2ad681
1
host/assembler.fnl
Normal file
1
host/assembler.fnl
Normal file
@ -0,0 +1 @@
|
|||||||
|
(local opcodes (require :host.assembler.opcodes))
|
||||||
@ -1,5 +1,3 @@
|
|||||||
(local {: print-string} (require :print))
|
|
||||||
|
|
||||||
(local byte string.char)
|
(local byte string.char)
|
||||||
(fn word->byte [x]
|
(fn word->byte [x]
|
||||||
"convert a 32 bit word into a little endian byte string"
|
"convert a 32 bit word into a little endian byte string"
|
||||||
@ -70,7 +68,3 @@
|
|||||||
:section-header-count 0
|
:section-header-count 0
|
||||||
:string-section-index 0
|
:string-section-index 0
|
||||||
:phead-count 0}))
|
:phead-count 0}))
|
||||||
|
|
||||||
(with-open [f (io.open :test.elf :w)]
|
|
||||||
(f:write elf))
|
|
||||||
(print-string elf)
|
|
||||||
|
|||||||
92
host/assembler/opcodes.fnl
Normal file
92
host/assembler/opcodes.fnl
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
(local util (require :host.util))
|
||||||
|
|
||||||
|
(local conditions {:equal 0x0
|
||||||
|
:not-equal 0x1
|
||||||
|
:carry 0x2
|
||||||
|
:not-carry 0x3
|
||||||
|
:negative 0x4
|
||||||
|
:positive 0x5
|
||||||
|
:overflow 0x6
|
||||||
|
:no-overflow 0x7
|
||||||
|
:higher-unsigned 0x8
|
||||||
|
:lower-unsigned 0x9
|
||||||
|
:greater-equal-signed 0xa
|
||||||
|
:less-signed 0xb
|
||||||
|
:greater-signed 0xc
|
||||||
|
:less-equal-signed 0xd
|
||||||
|
:always 0xe})
|
||||||
|
|
||||||
|
(fn r [n]
|
||||||
|
"Create a register for use in instructions"
|
||||||
|
{:register (case n
|
||||||
|
:pc 0xf
|
||||||
|
:lr 0xe
|
||||||
|
:sp 0xd
|
||||||
|
n n)})
|
||||||
|
|
||||||
|
(fn register? [x]
|
||||||
|
(and (= (type x) :table) (. x :register)))
|
||||||
|
|
||||||
|
|
||||||
|
(fn bit [flag]
|
||||||
|
"Convert a boolean to an integer for shifting"
|
||||||
|
(if flag 1 0))
|
||||||
|
|
||||||
|
(fn calculate-rotation [x]
|
||||||
|
"Construct a valid arm rotation of x"
|
||||||
|
(faccumulate [acc nil i 0 32 2 &until acc]
|
||||||
|
(let [rotated (util.rotate-left x i)] (if (<= rotated 0xff) i))))
|
||||||
|
|
||||||
|
(fn parse-conditions [?options]
|
||||||
|
(let [{:cond cond :flags set-flags} (or ?options {})
|
||||||
|
set-flags (bit (or set-flags false))
|
||||||
|
cond (. conditions (or cond :always))]
|
||||||
|
{: cond : set-flags}))
|
||||||
|
|
||||||
|
(fn move [dest source ?options]
|
||||||
|
{:fnl/docstring "Set register *dest* to a value\n*source* can be a register or an immediate value smaller than 4096"
|
||||||
|
:fnl/arglist [dest source & {: cond : flags}]}
|
||||||
|
(let [{: cond : set-flags} (parse-conditions ?options)
|
||||||
|
source-register (register? source)
|
||||||
|
dest (register? dest)]
|
||||||
|
(when (not dest) (error "dest must be a register"))
|
||||||
|
(if source-register
|
||||||
|
(bor
|
||||||
|
(lshift cond 28)
|
||||||
|
(lshift 0xd 21)
|
||||||
|
(lshift set-flags 20)
|
||||||
|
(lshift dest 12)
|
||||||
|
source-register)
|
||||||
|
(let [rotation (calculate-rotation source)]
|
||||||
|
(when (= nil rotation) (error "Unencodable immediate value"))
|
||||||
|
(bor
|
||||||
|
(lshift cond 28)
|
||||||
|
(lshift 1 25)
|
||||||
|
(lshift 0xd 21)
|
||||||
|
(lshift set-flags 20)
|
||||||
|
(lshift dest 12)
|
||||||
|
(lshift (/ rotation 2) 8)
|
||||||
|
(band (util.rotate-left source rotation) 0xff))))))
|
||||||
|
|
||||||
|
(fn branch [offset ?options]
|
||||||
|
(let [{: cond} (parse-conditions ?options)
|
||||||
|
max-immediate 0xffffff
|
||||||
|
offset (band offset util.word-max)]
|
||||||
|
(bor
|
||||||
|
(lshift cond 28)
|
||||||
|
(lshift 10 24)
|
||||||
|
(band (rshift offset 2) 0xffffff))))
|
||||||
|
|
||||||
|
(fn branch-link [offset ?options]
|
||||||
|
(let [{: cond} (parse-conditions ?options)
|
||||||
|
max-immediate 0xffffff
|
||||||
|
offset (band offset util.word-max)]
|
||||||
|
(bor
|
||||||
|
(lshift cond 28)
|
||||||
|
(lshift 11 24)
|
||||||
|
(band (rshift offset 2) 0xffffff))))
|
||||||
|
|
||||||
|
{: r
|
||||||
|
: move
|
||||||
|
: branch
|
||||||
|
: branch-link}
|
||||||
@ -1,42 +1,44 @@
|
|||||||
(local {:map map} (require :lume))
|
(local {:map map} (require :deps.lume))
|
||||||
|
|
||||||
(local string->bytes (fn [s]
|
(fn string->bytes [s]
|
||||||
(table.pack (string.byte s 1 -1))))
|
(table.pack (string.byte s 1 -1)))
|
||||||
|
|
||||||
(local bytes->string (fn [x] (string.char (table.unpack x))))
|
(fn bytes->string [x] (string.char (table.unpack x)))
|
||||||
|
|
||||||
(local show-bytes (fn [byte-string]
|
(fn show-bytes [byte-string]
|
||||||
"print a string as human readble bytes"
|
"print a string as human readble bytes"
|
||||||
(let [formatted (map (string->bytes byte-string)
|
(let [formatted (map (string->bytes byte-string)
|
||||||
(λ [byte]
|
(λ [byte]
|
||||||
(if byte
|
(if byte
|
||||||
(string.format :%02x byte)
|
(string.format :%02x byte)
|
||||||
"##")))]
|
"##")))]
|
||||||
(table.concat formatted " "))))
|
(table.concat formatted " ")))
|
||||||
|
|
||||||
(local show-ascii
|
(fn show-ascii [byte-string]
|
||||||
(fn [byte-string] (-> byte-string
|
(-> byte-string
|
||||||
(string->bytes)
|
(string->bytes)
|
||||||
(map (lambda [byte] (if (< 31 byte 126) byte 46)))
|
(map (lambda [byte] (if (< 31 byte 126) byte 46)))
|
||||||
(bytes->string))))
|
(bytes->string)))
|
||||||
|
|
||||||
(local pad-string (fn [s count]
|
(fn pad-string [s count]
|
||||||
(string.format (.. :%- count :s) s)))
|
(string.format (.. :%- count :s) s))
|
||||||
|
|
||||||
(local print-string
|
(fn print-string [byte-string]
|
||||||
(fn [byte-string]
|
(let [row-len 8
|
||||||
(let [row-len 8
|
|
||||||
len (length byte-string)
|
len (length byte-string)
|
||||||
full-rows (math.floor (/ len row-len))
|
full-rows (math.floor (/ len row-len))
|
||||||
rest (math.modf len full-rows)]
|
rest (math.modf len full-rows)]
|
||||||
(for [i 0 full-rows 1]
|
(for [i 0 full-rows 1]
|
||||||
(let [row (byte-string:sub (+ 1 (* row-len i)) (+ row-len (* row-len i)))]
|
(let [row (byte-string:sub
|
||||||
(when (< 0 (length row)) (print (..
|
(+ 1 (* row-len i))
|
||||||
:| (pad-string (show-bytes row) (- (* 3 row-len) 1))
|
(+ row-len (* row-len i)))]
|
||||||
:|
|
(when (< 0 (length row))
|
||||||
" "
|
(print (..
|
||||||
:|
|
:| (pad-string (show-bytes row) (- (* 3 row-len) 1))
|
||||||
(pad-string (show-ascii row) row-len)
|
:|
|
||||||
:|))))))))
|
" "
|
||||||
|
:|
|
||||||
|
(pad-string (show-ascii row) row-len)
|
||||||
|
:|)))))))
|
||||||
|
|
||||||
{: print-string}
|
{: print-string}
|
||||||
|
|||||||
17
host/assembler/util.fnl
Normal file
17
host/assembler/util.fnl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
(local byte string.char)
|
||||||
|
(fn word->byte [x]
|
||||||
|
"convert a 32 bit word into a little endian byte string"
|
||||||
|
(string.char
|
||||||
|
(-> x (band 0xff))
|
||||||
|
(-> x (rshift 8) (band 0xff))
|
||||||
|
(-> x (rshift 16) (band 0xff))
|
||||||
|
(-> x (rshift 24))))
|
||||||
|
(fn half->byte [x]
|
||||||
|
"convert a 16 bit half-word into a little endian byte string"
|
||||||
|
(string.char
|
||||||
|
(-> x (band 0xff))
|
||||||
|
(-> x (rshift 8) (band 0xff))))
|
||||||
|
|
||||||
|
{: byte
|
||||||
|
: word->byte
|
||||||
|
: half->byte}
|
||||||
34
host/util.fnl
Normal file
34
host/util.fnl
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
(local byte string.char)
|
||||||
|
(fn word->byte [x]
|
||||||
|
"convert a 32 bit word into a little endian byte string"
|
||||||
|
(string.char
|
||||||
|
(-> x (band 0xff))
|
||||||
|
(-> x (rshift 8) (band 0xff))
|
||||||
|
(-> x (rshift 16) (band 0xff))
|
||||||
|
(-> x (rshift 24))))
|
||||||
|
(fn half->byte [x]
|
||||||
|
"convert a 16 bit half-word into a little endian byte string"
|
||||||
|
(string.char
|
||||||
|
(-> x (band 0xff))
|
||||||
|
(-> x (rshift 8) (band 0xff))))
|
||||||
|
|
||||||
|
(local word-max 0xffffffff)
|
||||||
|
|
||||||
|
(fn rotate-right [x n]
|
||||||
|
"Rotate *x* right as a 32 bit integer by *n* bits."
|
||||||
|
(bor (rshift x n) (band word-max (lshift x (- 32 n)))))
|
||||||
|
(fn rotate-left [x n]
|
||||||
|
"Rotate *x* right as a 32 bit integer by *n* bits."
|
||||||
|
(bor (band word-max (lshift x n)) (rshift x (- 32 n))))
|
||||||
|
|
||||||
|
(fn hex [x ?padding]
|
||||||
|
"Convert x to hexadecimal, optionally padding to ?padding characters"
|
||||||
|
(string.format (.. :% :0 (or ?padding 0) :x) x))
|
||||||
|
|
||||||
|
{: byte
|
||||||
|
: word->byte
|
||||||
|
: half->byte
|
||||||
|
: rotate-left
|
||||||
|
: rotate-right
|
||||||
|
: hex
|
||||||
|
: word-max}
|
||||||
Loading…
Reference in New Issue
Block a user