Low level language, based on Java bytecode/ assembly, written in Java.
This project contains a parser and emulator to run the code.
Warning
Work in progress, use at your own risk.
Example file: code.xf
Run with java -jar thisjar.jar --input code.xf
Example:
; equivalent of IntStream.range(1, 4).forEach(System.out::println);
@define max 4
mov $ax 1 ; i
lp: mov $cx max
sub $cx $ax ; max - i
jnz $cx hlt
; loop body
out $ax
inc $ax ; i++
pd ; added this so you can see what's going on internally (print diagnostics)
jmp lp
hlt: hlt
A file starts with preprocessor directives (@define foo bar
), similar to how C handles such directives.
These will be replaced in the source code before parsing, e.g. every occurrence of foo
will be replaced with bar
.
This can be useful to avoid magic values.
Note
More directives will come in future releases.
Example:
@define ON 1
@define OFF 0
@define bool_addr 128
mov [bool_addr] ON
; or with address notation
@define bool_addr [128]
mov bool_addr ON
Every further line is either a marker or an instruction. A marker acts as yes a marker to some instruction behind it.
This is useful for jumps, so you write something like jmp my_marker
instead of magic values, markers will be preprocessed too.
Note
When writing a marker, the expression it points to must be on the same line, this will be resolved in a future release.
Example marker:
exit: hlt ; exit is the marker and hlt is the opcode which halts execution of the program
; program start
mov [0] 100
jp [0] exit ; if 100 is positive, halt program execution
Internally, markers decay to constants.
Syntax: opcode
(see below) zero or more operands
Example instructions:
; move the constant 12 to the ax register
mov $ax 12
Opcode | Syntax (case insensitive) | Description |
---|---|---|
NOP |
nop | does nothing |
MOV |
(mov <destination: address> <source: operand>) | move memory |
LDE |
(lde <index: operand>) | load array element, subject to deprecation |
ADD |
(add <destination: operand> <value: operand>) | add value to destination |
SUB |
(sub <destination: address> <value: operand>) | similar |
MUL |
(mul <destination: address> <value: operand>) | similar |
DIV |
(div <destination: address> <value: operand>) | similar |
INC |
(inc <destination: address> [value: operand | 1]) | increase the inner value of destination by one |
IN |
in <mode: constant> | todo |
OUT |
out <what: operand> | prints to stdout |
JMP |
jmp <destination: address> | jumps to an address and continues execution from there |
JP |
jp <value: operand> <destination: address> | jump if positive, similar |
JPZ |
jpz <value: operand> <destination: address> | jump is positive or zero |
JNE |
jne <value: operand> <destination: address> | jump if negative |
JNZ |
jnz <value: operand> <destination: address> | jump if negative or zero |
JZ |
jz <value: operand> <destination: address> | jump if zero |
HLT |
hlt | stops execution, must be called to cleanup and exit |
PD |
pd | prints diagnostic info on the stdout |
All operands are currently 32-bit
Note
Floating point numbers are not supported yet.
Operands come in three forms:
- immediate value (constant) e.g.
2
- address e.g.
[124]
- register, e.g.
$ax
, currently fromax
todx
, always preceded by$
Operand
├─ Constant
├─ Register
├─ Address
(operand means really anything can be given as argument)
Operands can be combined to make more complicated operands:
[$bc + 2]
array element access, $bx contains the base address of the array and we read the second element[$cx + [addr_directive]]
uhh
- [] Boolean related instructions (and, or, etc.)
- [] Bitshift instructions
- [] Implementing strings
- [] Implementing function calls, probably with some custom calling convention
- [] Implementing floating point values
- [] Syscall interface maybe?