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)
|
||||
(fn word->byte [x]
|
||||
"convert a 32 bit word into a little endian byte string"
|
||||
@ -70,7 +68,3 @@
|
||||
:section-header-count 0
|
||||
:string-section-index 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]
|
||||
(table.pack (string.byte s 1 -1))))
|
||||
(fn string->bytes [s]
|
||||
(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]
|
||||
"print a string as human readble bytes"
|
||||
(let [formatted (map (string->bytes byte-string)
|
||||
(λ [byte]
|
||||
(if byte
|
||||
(string.format :%02x byte)
|
||||
"##")))]
|
||||
(table.concat formatted " "))))
|
||||
(fn show-bytes [byte-string]
|
||||
"print a string as human readble bytes"
|
||||
(let [formatted (map (string->bytes byte-string)
|
||||
(λ [byte]
|
||||
(if byte
|
||||
(string.format :%02x byte)
|
||||
"##")))]
|
||||
(table.concat formatted " ")))
|
||||
|
||||
(local show-ascii
|
||||
(fn [byte-string] (-> byte-string
|
||||
(string->bytes)
|
||||
(map (lambda [byte] (if (< 31 byte 126) byte 46)))
|
||||
(bytes->string))))
|
||||
(fn show-ascii [byte-string]
|
||||
(-> byte-string
|
||||
(string->bytes)
|
||||
(map (lambda [byte] (if (< 31 byte 126) byte 46)))
|
||||
(bytes->string)))
|
||||
|
||||
(local pad-string (fn [s count]
|
||||
(string.format (.. :%- count :s) s)))
|
||||
(fn pad-string [s count]
|
||||
(string.format (.. :%- count :s) s))
|
||||
|
||||
(local print-string
|
||||
(fn [byte-string]
|
||||
(let [row-len 8
|
||||
(fn print-string [byte-string]
|
||||
(let [row-len 8
|
||||
len (length byte-string)
|
||||
full-rows (math.floor (/ len row-len))
|
||||
rest (math.modf len full-rows)]
|
||||
(for [i 0 full-rows 1]
|
||||
(let [row (byte-string:sub (+ 1 (* row-len i)) (+ 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)
|
||||
:|))))))))
|
||||
(for [i 0 full-rows 1]
|
||||
(let [row (byte-string:sub
|
||||
(+ 1 (* row-len i))
|
||||
(+ 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)
|
||||
:|)))))))
|
||||
|
||||
{: 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