feat: implement simple opcodes

This commit is contained in:
Fey Naomi Schrewe 2025-10-11 23:11:34 +02:00
parent fa7a8b792b
commit 290a2ad681
6 changed files with 177 additions and 37 deletions

1
host/assembler.fnl Normal file
View File

@ -0,0 +1 @@
(local opcodes (require :host.assembler.opcodes))

View File

@ -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)

View 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}

View File

@ -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
View 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
View 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}