forked from MightyPork/crsn
parent
be1ee66970
commit
d489b214e0
@ -0,0 +1,286 @@ |
||||
# CROISSANT VIRTUAL MACHINE |
||||
|
||||
Croissant (or Crsn for short) is an extensible runtime emulating a weird microcomputer. |
||||
|
||||
## FAQ |
||||
|
||||
### What is this for? |
||||
|
||||
F U N |
||||
|
||||
#### What if I don't enjoy writing assembly that looks like Lisp? |
||||
|
||||
maybe go play fortnite instead |
||||
|
||||
# Architecture |
||||
|
||||
## Registers |
||||
|
||||
- 8 general purpose registers `reg0`-`reg7` |
||||
- 8 argument registers `arg0`-`arg7` |
||||
- 8 result registers `res0`-`res7` |
||||
|
||||
All registers are 64-bit unsigned integers that can be treated as |
||||
signed, if you want to. Overflow is allowed and reported by status flags. |
||||
|
||||
8-, 16-, and 32-bit arithmetic is not currently implemented (only 64-bit), but will be |
||||
added later. Probably. Maybe. |
||||
|
||||
## Status Flags |
||||
|
||||
Arithmetic and other operations set status flags that can be used for conditional jumps. |
||||
|
||||
- Equal … Values are equal |
||||
- Lower … A < B |
||||
- Greater … A > B |
||||
- Zero … Value is zero, buffer is empty, etc. |
||||
- Positive … Value is positive |
||||
- Negative … Value is negative |
||||
- Overflow … Arithmetic overflow or underflow, buffer underflow, etc. |
||||
- Invalid … Invalid arguments for an instruction |
||||
- Carry … Arithmetic carry *this is not currently used for anything* |
||||
|
||||
### Status Tests |
||||
|
||||
These keywords (among others) are used in conditional branches to specify flag tests: |
||||
|
||||
- `eq` … Equal, |
||||
- `ne` … NotEqual, |
||||
- `z` … Zero, |
||||
- `nz` … NotZero, |
||||
- `lt` … Lower, |
||||
- `le` … LowerOrEqual, |
||||
- `gt` … Greater, |
||||
- `ge` … GreaterOrEqual, |
||||
- `pos` … Positive, |
||||
- `neg` … Negative, |
||||
- `npos` … NonPositive, |
||||
- `nneg` … NonNegative, |
||||
- `c` … Carry, |
||||
- `nc` … NotCarry, |
||||
- `valid` … Valid, |
||||
- `inval` … Invalid, |
||||
- `ov` … Overflow, |
||||
- `nov` … NotOverflow, |
||||
|
||||
# Syntax |
||||
|
||||
*The syntax is very much subject to change at the moment. The format described here |
||||
is valid at the time this file is added to version control.* |
||||
|
||||
Instructions are written using S-expressions, because they are easy to parse |
||||
and everyone loves Lisp. |
||||
|
||||
A program has this format: |
||||
|
||||
``` |
||||
( |
||||
(RoutineName Instructions…) |
||||
… |
||||
) |
||||
``` |
||||
|
||||
Instructions are written like this: |
||||
|
||||
``` |
||||
(Keyword Args… ConditionalBranches…) |
||||
``` |
||||
|
||||
Args are either: |
||||
- one of the registers (`reg0`, `arg3` etc) |
||||
- `_` to discard an output value |
||||
- a literal value (decimal, hex or binary) |
||||
- label or routine name |
||||
- condition flag keyword |
||||
- anything else an extension supports... |
||||
|
||||
Conditonal branches are written like this: |
||||
|
||||
``` |
||||
(Condition? Instructions…) |
||||
``` |
||||
|
||||
If there is more than one conditional branch chained to an instruction, |
||||
then only one branch is taken - there is no fall-through. The definition order |
||||
is preserved, i.e. if the `inval` flag is to be checked, it should be done |
||||
before checking e.g. `nz`, which is, incidentally, true by default, |
||||
because all flags start cleared. |
||||
|
||||
Example routine to calculate the factorial of `arg0`: |
||||
|
||||
``` |
||||
(fac |
||||
(cmp arg0 2 |
||||
(eq? (ret 2))) |
||||
(sub r0 arg0 1) |
||||
(call fac r0) |
||||
(mul r0 arg0 res0) |
||||
(ret r0) |
||||
) |
||||
``` |
||||
|
||||
# Instruction Set |
||||
|
||||
Crsn instruction set is composed of extensions. |
||||
|
||||
Extensions can also define special syntax for their instructions, so long as it's valid S-expressions. |
||||
|
||||
## Labels, jumps and barriers |
||||
|
||||
These are defined as part of the built-in instruction set (see below). |
||||
|
||||
- Barrier - marks the boundary between routines to prevent overrun. Cannot be jumped across. |
||||
- Local labels - can be jumped to within the same routine, both forward and backward. |
||||
- Far labels - can be jumped to from any place in the code using a far jump (disregarding barriers). |
||||
This is a very cursed functionality that may or may not have some valid use case. |
||||
- Skips - cannot cross a barrier, similar to a local label but without explicitly defining a label. |
||||
|
||||
Skipping across conditional branches may have *surprising results* - conditional branches are expanded |
||||
to series of simple and conditional skips by the assembler. Only use skips if you really know what you're doing. |
||||
Jumping to a label is always a safer choice. |
||||
|
||||
## Built-in Instructions |
||||
|
||||
``` |
||||
; Do nothing |
||||
(nop) |
||||
|
||||
; Stop execution |
||||
(halt) |
||||
|
||||
; Mark a jump target. |
||||
(:LABEL) |
||||
|
||||
; Mark a far jump target (can be jumped to from another routine). |
||||
; This label is preserved in optimized code. |
||||
(far :LABEL) |
||||
|
||||
; Jump to a label |
||||
(j :LABEL) |
||||
|
||||
; Jump to a label if a flag is set |
||||
(jif COND :LABEL) |
||||
|
||||
; Jump to a label that can be in another function |
||||
(fj :LABEL) |
||||
|
||||
; Far jump to a label if a flag is set |
||||
(fjif COND :LABEL) |
||||
|
||||
; Skip backward or forward |
||||
(s COUNT) |
||||
|
||||
; Skip if a flag is set |
||||
(sif COND COUNT) |
||||
|
||||
; Mark a routine entry point (call target). |
||||
(routine NAME) |
||||
|
||||
; Call a routine with arguments. |
||||
; The arguments are passed as argX. Return values are stored in resX registers. |
||||
(call ROUTINE ARGS…) |
||||
|
||||
; Exit the current routine with return values |
||||
(ret VALS…) |
||||
|
||||
; Deny jumps, skips and run across this address, producing a run-time fault with a message. |
||||
(barrier) |
||||
(barrier "message text") |
||||
|
||||
; Generate a run-time fault with a debugger message |
||||
(fault) |
||||
(fault "message text") |
||||
|
||||
; Copy value |
||||
(ld DST SRC) |
||||
|
||||
; Store status flags to a register |
||||
(sst DST) |
||||
|
||||
; Load status flags from a register |
||||
(sld SRC) |
||||
``` |
||||
|
||||
## Arithmetic Module |
||||
|
||||
This module makes heavy use of status flags. |
||||
|
||||
Many instructions have two forms: |
||||
- 3 args ... explicit source and destination |
||||
- 2 args ... destination is also used as the first argument |
||||
|
||||
``` |
||||
; Test properties of a value - zero, positive, negative |
||||
(tst SRC) |
||||
|
||||
; Compare two values |
||||
(cmp A B) |
||||
|
||||
; Add A+B |
||||
(add DST A B) |
||||
(add DST B) |
||||
|
||||
; Subtract A-B |
||||
(sub DST A B) |
||||
(sub DST B) |
||||
|
||||
; Multiply A*B |
||||
(mul DST A B) |
||||
(mul DST B) |
||||
|
||||
; Divide A/B |
||||
(div DST A B) |
||||
(div DST B) |
||||
|
||||
; Divide and get remainder |
||||
; Both DST and REM are output registers |
||||
(divr DST REM A B) |
||||
(divr DST REM B) |
||||
|
||||
; Get remainder A%B |
||||
; This is equivalent to (divr _ REM A B), |
||||
; except status flags are updated by the remainder value |
||||
(mod DST A B) |
||||
(mod DST B) |
||||
|
||||
; AND A&B |
||||
(and DST A B) |
||||
(and DST B) |
||||
|
||||
; OR A|B |
||||
(or DST A B) |
||||
(or DST B) |
||||
|
||||
; XOR A&B |
||||
(xor DST A B) |
||||
(xor DST B) |
||||
|
||||
; CPL ~A (negate all bits) |
||||
(cpl DST A) |
||||
(cpl DST) |
||||
|
||||
; Rotate right (wrap around) |
||||
(ror DST A B) |
||||
(ror DST B) |
||||
|
||||
; Rotate left (wrap around) |
||||
(rol DST A B) |
||||
(rol DST B) |
||||
|
||||
; Logical shift right (fill with zeros) |
||||
(lsr DST A B) |
||||
(lsr DST B) |
||||
|
||||
; Logical shift left (fill with zeros) |
||||
(lsl DST A B) |
||||
(lsl DST B) |
||||
|
||||
; Arithmetic shift right (copy sign bit) |
||||
(asr DST A B) |
||||
(asr DST B) |
||||
|
||||
; Arithmetic shift left (this is identical to `lsl`, added for completeness) |
||||
(asl DST A B) |
||||
(asl DST B) |
||||
``` |
||||
|
Loading…
Reference in new issue