This project implements code translation to uneven bytecode, disassembly tool for generated bytecode, and bytecode executor (Soft Processor Unit).
In addition, I implemented code analyser that checks for syntax mistakes. Analyser outputs info in clang format, so most IDEs highlight wrong expressions and provide descriptions of errors as well as possible solutions when possible.
During the translation, .lst file is generated. It provides information about bytecode generation and what command at what offset is located.
Enter project's directory and execute:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
Three files will be created:
- SPU - Soft Processor Unit, executes created programs
- SPUAsm - translates source file (.spus) to binary file (.spub) that can be executed by SPU
- SPUDisAsm - disassembly for generated binary files
SPUAsm
$ SPUAsm <source file>
--input <filename.spus> - source file (can be specified without --input)
--output <filename.spub> - binary assembled file
-E - generate preprocessed file
--verbose - output assembly debug information
--lst <filename.lst> - listing file of generated code (assembly.lst by default)
-h, --help - show help message
SPUDisAsm
$ SPUDisAsm <binary file>
--input <filename.spub> - binary assembled file
--output <filename.spus> - source file (if not specified, stdout selected)
--verbose - output assembly debug information
-h, --help - show help message
SPU
$ SPU <binary file>
--input <filename.spub> - binary assembled file
--output <filename.spus> - source file (if not specified, stdout selected)
--verbose - output assembly debug information
--vsync - render vram after every command
-h, --help - show help message
All examples are available in this dir.
Show code
;
; Squares
;
in rbx ; rbx as counter
push 0
pop rax
loop:
dec rbx ; decrease counter
; Calculating square
push rax
push rax
mul
out
; Prepare for the next loop
pop
inc rax
jm mondayOnly ; exit if it is monday
; Insert conditional jump operands
push 0
push rbx
jne loop
mondayOnly:
Show code
; height 32
; width 64
push 32
push 16
push 10
push 35
call drawCircle
clrscr
push 32
push 16
push 4
push 42
call drawCircle
clrscr
push 16
push 8
push 2
push 42
call drawCircle
clrscr
rend
push 40
push 25
push 4
push 48
call drawCircle
clrscr
rend
push 60
push 13
push 8
push 48
call drawCircle
hlt
drawCircle: ;(x0, y0, r, symbol)
pop [2]
pop rcx ; r
pop rbx ; y0
pop rax ; x0
mov rdx 0 ; initial angle
loop:
push rbx
push rdx
sin
push rcx
mul
add ; y0 + r*sin(alpha)
pop [0] ; y coordinate
push rax
push rdx
cos
push rcx
push 2
mul
mul
add ; x0 + r*cos(alpha)
pop [1] ; x coordinate
pixset [1] [0] [2]
rend
slp 10000
; loop params
mov rdx rdx+0.1
push rdx
push 3.1415926535897
push 2
mul
jbe loop
ret
Show code
;
; Data input
; (a, b, c)
;
in rax
in rbx
in rcx
;
; D calculation
;
push rbx
push 2
pow
push 4
push rax
mul
push rcx
mul
sub
sqrt
pop rdx
;
; First x
;
clear
push -1
push rbx
mul
push rdx
sub
push 2
div
push rax
div
pop rcx
;
; Second x
;
clear
push -1
push rbx
mul
push rdx
add
push 2
div
push rax
div
pop rax
;
; Output
;
out rax
out rcx
Binary generation can be splitted into several parts:
- Cleanup
- Analysis
- Final cleanup
- Translation
- Final checks
If process fails on any part, the next parts are not executed.
Just double whitespaces, trailing/leading whitespaces removed. Operations that does not change code structure, lines number etc.
Analyses code for syntax errors, builds temporary code to calculate labels offsets. Prints errors descriptions in clang format.
All unnecessary indent symbols removed (comments, blank lines, unneded whitespaces). Code structure will be altered, line numbers are not preserved.
Code is translated using labels table generated on analysis step. At this point, all errors must be catched by analysis, but still some can make thir way to this point. In this case, generation will fail, dumping wrong instruction and its number.
Check that all operations completed correctly; labels table is complete and not redundant.
Operators with arguments accept complex value argument. Argument can be assignable or not assignable
Complex value examples:
- [rax+5] - assignable, RAM on adress rax+5 with double adressation
- 4 - not assignable, immediate value 4
- [5] - assignable, RAM on adress 5 with double adressation
- [rcx] - assignable, RAM on adress rcx with double adressation
- rcx - assignable, register rcx
- (rcx) - assignable, RAM on adress rcx with char adressation
- (rcx+10) - assignable, RAM on adress rcx+10 with char adressation
- (10) - assignable, RAM on adress 10 with char adressation
Notice: whitespaces inside complex value are not allowed and considered as syntax error.
Push value to the stack
Pop value from the stack
- no args - just delete
- cvalue - pop and save to assignable cvalue
Request value from the console
- no args - push value to the stack
- cvalue - save to assignable cvalue
Prints value to the console
- no args - last stack value
- cvalue - cvalue value
destination -> source
Sets the first argument value to the secon argument's value
Dump stack information
Clear stack
Force render vram
Sleep for ... nanoseconds
Finish the program
x y value
Set vram pixel (x, y) to value
Fill vram with spaces
Increments the value
- no args - last stack value
- cvalue - cvalue value
Decrements the value
- no args - last stack value
- cvalue - cvalue value
Add two last stack values and push to the stack
Substract two last stack values and push to the stack
Multiply two last stack values and push to the stack
Divide two last stack values and push to the stack
Sin of the last stack value
Cos of the last stack value
Abs of the last stack value
Square root of the last stack value
The pre-last element of the stack to the power of the last one
Gives execution to the label block. Can be returned to the call instruction using ret
Returnes to the last call position. May fail if there were no calls.
Jump to the label
Jump if last element is bigger than pre-last. Removes both operands from the stack
Jump if last element is bigger-or-equal than pre-last. Removes both operands from the stack
Jump if last element is equal to the pre-last one. Removes both operands from the stack
Jump if last element is not equal to the pre-last one. Removes both operands from the stack
Jump if last element is lower than pre-last. Removes both operands from the stack
Jump if last element is lower-or-equal than pre-last. Removes both operands from the stack
Jump if it's Monday.
Creates label