92 lines
3.0 KiB
Bash
Executable File
92 lines
3.0 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# ass.sh: a bad assembler for my VM instruction set
|
|
#
|
|
# WARNING: this assembler is ASS! That is why I named it that (in addition to
|
|
# being short for 'ass'embler). This was purely a quick hack so that I could
|
|
# get working on writing my imaginary VM code ASAP. I would be embarassed if I
|
|
# had any shame left.
|
|
#
|
|
# Assumes GNU sed, will need to be modified if using BSD sed
|
|
|
|
die() {
|
|
printf "$1\n"
|
|
exit $2
|
|
}
|
|
|
|
|
|
# bad_assemble: "assembles" the temporary source file provided by $1 (converts
|
|
# instructions to opcodes, pretty simple)
|
|
# Forgive me for how this function is implemented...
|
|
bad_assemble() {
|
|
sed -i '/^[[:blank:]]*#/d;s/#.*//' "$1" # remove comments starting with '#'
|
|
sed -i 's/0X//gi' "$1" # remove hex prefix '0x'
|
|
sed -i 's/HALT[[:blank:]]*/00 00 00/gi' "$1"
|
|
sed -i 's/PUSH[[:blank:]]/01/gi' "$1"
|
|
sed -i 's/POP[[:blank:]]/02/gi' "$1"
|
|
sed -i 's/PUSHI[[:blank:]]/03/gi' "$1"
|
|
sed -i 's/LDLR[[:blank:]]/04/gi' "$1"
|
|
sed -i 's/STLR[[:blank:]]/05/gi' "$1"
|
|
sed -i 's/SETI[[:blank:]]/06/gi' "$1"
|
|
sed -i 's/DUP[[:blank:]]*/07 00 00/gi' "$1"
|
|
sed -i 's/ADD[[:blank:]]*/08 00 00/gi' "$1"
|
|
sed -i 's/SUB[[:blank:]]*/09 00 00/gi' "$1"
|
|
sed -i 's/XOR[[:blank:]]*/0a 00 00/gi' "$1"
|
|
sed -i 's/CALL[[:blank:]]/0b/gi' "$1"
|
|
sed -i 's/RET[[:blank:]]*/0c 00 00/gi' "$1"
|
|
sed -i 's/JMP[[:blank:]]/0d/gi' "$1"
|
|
sed -i 's/BEQ[[:blank:]]/0e/gi' "$1"
|
|
sed -i 's/BNQ[[:blank:]]/0f/gi' "$1"
|
|
sed -i 's/NOP[[:blank:]]*/ff 00 00/gi' "$1"
|
|
|
|
sed -i 's/H//gi' "$1" # remove hex suffix 'h' after only hex digits remain
|
|
sed -i 's/ //g' "$1"
|
|
#sed -i 's/\n//g' "$1"
|
|
}
|
|
|
|
|
|
# link_asm_zp: "links" assembled code to zero page file by simply concatenating
|
|
# them, with the total result stored in $1. $1 is the temporary assembled file,
|
|
# and $2 is the zero page hexdump file
|
|
link_asm_zp() {
|
|
cat "$2" "$1" > "$1"-new # cat to temporary file
|
|
mv "$1"-new "$1"
|
|
rm -f "$1"-new
|
|
}
|
|
|
|
|
|
# write_binary: takes path to an "assembled" file in $1 (contains hex), writes
|
|
# it to a binary file, path provided by $2
|
|
write_binary() {
|
|
sed -i 's/ //g' "$1"
|
|
tr -d '\n' < "$1" > "$1"mod; mv "$1"mod "$1" # in-place remove newlines
|
|
xxd -p -r "$1" > "$2" # writes raw binary
|
|
}
|
|
|
|
usage_msg="Usage: $(basename $0) [vm-source-code] [optional-zero-page-hexdump]"
|
|
[ "$#" -ne 1 ] && [ "$#" -ne 2 ] && die "$usage_msg" 69
|
|
|
|
vm_src="$1"
|
|
zp_file="$2"
|
|
|
|
! [ -f "$vm_src" ] && die "[ERROR]: file $vm_src does not exist" 65
|
|
if [ "$#" = 2 ]; then
|
|
! [ -f "$zp_file" ] && die "[ERROR]: file $zp_file does not exist" 65
|
|
fi
|
|
|
|
vm_out=$(printf "$vm_src" | sed 's/.asm$/.bin/') # in file.asm, out file.bin
|
|
temp_src="${vm_src}-TEMP$(date --iso-8601=ns)" # create temporary file
|
|
cp -v "$vm_src" "$temp_src" # copy to temp file
|
|
|
|
bad_assemble "$temp_src"
|
|
if [ "$zp_file" != "" ]; then
|
|
link_asm_zp "$temp_src" "$zp_file"
|
|
write_binary "$temp_src" "$vm_out"
|
|
else
|
|
write_binary "$temp_src" "$vm_out"
|
|
fi
|
|
|
|
rm -vf $temp_src # clean up
|
|
echo "Assembling $vm_src done. Results in $vm_out"
|
|
|