2015-10-16 14:36:56 +00:00
|
|
|
SixtyPical
|
2015-10-16 08:30:24 +00:00
|
|
|
==========
|
|
|
|
|
2015-10-18 15:34:18 +00:00
|
|
|
This document describes the SixtyPical programming language version 0.4,
|
2015-10-16 14:36:56 +00:00
|
|
|
both its execution aspect and its static analysis aspect (even though
|
|
|
|
these are, technically speaking, separate concepts.)
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
This document is nominally normative, but the tests in the `tests` directory
|
|
|
|
are even more normative.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 18:15:01 +00:00
|
|
|
Refer to the bottom of this document for an EBNF grammar of the syntax of
|
|
|
|
the language.
|
|
|
|
|
2015-10-16 08:30:24 +00:00
|
|
|
Types
|
|
|
|
-----
|
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
There are two TYPES in SixtyPical:
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
* bit (2 possible values)
|
|
|
|
* byte (256 possible values)
|
|
|
|
|
|
|
|
Memory locations
|
|
|
|
----------------
|
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
A primary concept in SixtyPical is the MEMORY LOCATION. At any given point
|
2015-10-16 08:30:24 +00:00
|
|
|
in time during execution, each memory location is either UNINITIALIZED or
|
|
|
|
INITIALIZED. At any given point in the program text, too, each memory
|
|
|
|
location is either uninitialized or initialized. Where-ever it is one or
|
|
|
|
the other during execution, it is the same in the corresponding place in
|
|
|
|
the program text; thus, it is a static property.
|
|
|
|
|
|
|
|
There are four general kinds of memory location. The first three are
|
|
|
|
pre-defined and built-in.
|
|
|
|
|
|
|
|
### Registers ###
|
|
|
|
|
|
|
|
Each of these hold a byte. They are initially uninitialized.
|
|
|
|
|
|
|
|
a
|
|
|
|
x
|
|
|
|
y
|
|
|
|
|
|
|
|
### Flags ###
|
|
|
|
|
|
|
|
Each of these hold a bit. They are initially uninitialized.
|
|
|
|
|
|
|
|
c (carry)
|
|
|
|
z (zero)
|
|
|
|
v (overflow)
|
|
|
|
n (negative)
|
|
|
|
|
|
|
|
### Constants ###
|
|
|
|
|
|
|
|
It may be strange to think of constants as memory locations, but keep in mind
|
2015-10-16 14:36:56 +00:00
|
|
|
that a memory location in SixtyPical need not map to a memory location in the
|
|
|
|
underlying hardware. All constants are read-only. Each is initially
|
|
|
|
initialized with the value that corresponds with its name.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
They come in bit and byte types. There are two bit constants,
|
|
|
|
|
|
|
|
off
|
|
|
|
on
|
|
|
|
|
|
|
|
and two-hundred and fifty-six byte constants,
|
|
|
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
...
|
|
|
|
255
|
|
|
|
|
|
|
|
### User-defined ###
|
|
|
|
|
|
|
|
There may be any number of user-defined memory locations. They are defined
|
|
|
|
by giving the type, which must be `byte`, and the name.
|
|
|
|
|
|
|
|
byte pos
|
|
|
|
|
2015-10-18 15:22:36 +00:00
|
|
|
A location in memory may be given explicitly on a user-defined memory location.
|
|
|
|
|
|
|
|
byte screen @ 1024
|
|
|
|
|
2015-10-16 08:30:24 +00:00
|
|
|
Routines
|
|
|
|
--------
|
|
|
|
|
|
|
|
Every routine must list all the memory locations it READS from, i.e. its
|
|
|
|
INPUTS, and all the memory locations it WRITES to, whether they are OUTPUTS
|
2015-10-16 14:36:56 +00:00
|
|
|
or merely TRASHED. Every memory location that is not written to by the
|
|
|
|
routine (or any routines that the routine calls) is PRESERVED by the routine.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
routine foo
|
|
|
|
inputs a, score
|
|
|
|
outputs x
|
|
|
|
trashes y {
|
|
|
|
...
|
|
|
|
}
|
|
|
|
|
|
|
|
Routines may call only routines previously defined in the program source.
|
|
|
|
Thus, recursive routines are not allowed.
|
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
For a SixtyPical program to be run, there must be one routine called `main`.
|
|
|
|
This routine is executed when the program is run.
|
|
|
|
|
|
|
|
The memory locations given given as inputs are considered to be initialized
|
|
|
|
at the beginning of the routine. Various instructions cause memory locations
|
|
|
|
to be initialized after they are executed. Calling a routine which trashes
|
|
|
|
some memory locations causes those memory locations to be uninitialized after
|
|
|
|
that routine is called. At the end of a routine, all memory locations listed
|
|
|
|
as outputs must be initialised.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-17 12:50:21 +00:00
|
|
|
A routine can also be declared as "external", in which case its body need
|
|
|
|
not be defined but an absolute address must be given for where the routine
|
|
|
|
is located in memory.
|
|
|
|
|
|
|
|
routine chrout
|
|
|
|
inputs a
|
|
|
|
trashes a
|
|
|
|
@ 65490
|
|
|
|
|
2015-10-16 08:30:24 +00:00
|
|
|
Instructions
|
|
|
|
------------
|
|
|
|
|
|
|
|
### ld ###
|
|
|
|
|
|
|
|
ld <dest-memory-location>, <src-memory-location>
|
|
|
|
|
|
|
|
Reads from src and writes to dest.
|
|
|
|
|
|
|
|
* It is illegal if dest is not a register.
|
2015-10-16 14:36:56 +00:00
|
|
|
* It is illegal if dest does not occur in the WRITES lists of the current
|
2015-10-16 08:30:24 +00:00
|
|
|
routine.
|
|
|
|
* It is illegal if src is not of same type as dest (i.e., is not a byte.)
|
|
|
|
* It is illegal if src is uninitialized.
|
|
|
|
|
|
|
|
After execution, dest is considered initialized. The flags `z` and `n` may be
|
2015-10-16 14:36:56 +00:00
|
|
|
changed by this instruction; they must be named in the WRITES lists, and they
|
|
|
|
are considered initialized after it has executed.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
Some combinations, such as `ld x, y`, are illegal because they do not map to
|
|
|
|
underlying opcodes.
|
|
|
|
|
|
|
|
### st ###
|
|
|
|
|
|
|
|
st <src-memory-location>, <dest-memory-location>
|
|
|
|
|
|
|
|
Reads from src and writes to dest.
|
|
|
|
|
|
|
|
* It is illegal if dest is a register or if dest is read-only.
|
2015-10-16 14:36:56 +00:00
|
|
|
* It is illegal if dest does not occur in the WRITES lists of the current
|
2015-10-16 08:30:24 +00:00
|
|
|
routine.
|
|
|
|
* It is illegal if src is not of same type as dest.
|
|
|
|
* It is illegal if src is uninitialized.
|
|
|
|
|
|
|
|
After execution, dest is considered initialized. No flags are
|
|
|
|
changed by this instruction (unless of course dest is a flag.)
|
|
|
|
|
|
|
|
### add dest, src ###
|
|
|
|
|
|
|
|
add <dest-memory-location>, <src-memory-location>
|
|
|
|
|
|
|
|
Adds the contents of src to dest and stores the result in dest.
|
|
|
|
|
|
|
|
* It is illegal if src OR dest OR c is uninitialized.
|
|
|
|
* It is illegal if dest is read-only.
|
2015-10-16 14:36:56 +00:00
|
|
|
* It is illegal if dest does not occur in the WRITES lists
|
2015-10-16 08:30:24 +00:00
|
|
|
of the current routine.
|
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
Affects n, z, c, and v flags, requiring that they be in the WRITES lists,
|
|
|
|
and initializing them afterwards.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
dest and src continue to be initialized afterwards.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
### inc ###
|
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
inc <dest-memory-location>
|
|
|
|
|
|
|
|
Increments the value in dest. Does not honour carry.
|
|
|
|
|
|
|
|
* It is illegal if dest is uninitialized.
|
|
|
|
* It is illegal if dest is read-only.
|
|
|
|
* It is illegal if dest does not occur in the WRITES lists
|
|
|
|
of the current routine.
|
|
|
|
|
|
|
|
Affects n and z flags, requiring that they be in the WRITES lists,
|
|
|
|
and initializing them afterwards.
|
|
|
|
|
2015-10-16 08:30:24 +00:00
|
|
|
### sub ###
|
|
|
|
|
|
|
|
sub <dest-memory-location>, <src-memory-location>
|
|
|
|
|
|
|
|
Subtracts the contents of src from dest and stores the result in dest.
|
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
* It is illegal if src OR dest OR c is uninitialized.
|
|
|
|
* It is illegal if dest is read-only.
|
|
|
|
* It is illegal if dest does not occur in the WRITES lists
|
|
|
|
of the current routine.
|
|
|
|
|
|
|
|
Affects n, z, c, and v flags, requiring that they be in the WRITES lists,
|
|
|
|
and initializing them afterwards.
|
|
|
|
|
|
|
|
dest and src continue to be initialized afterwards.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
### dec ###
|
|
|
|
|
2015-10-16 18:15:01 +00:00
|
|
|
dec <dest-memory-location>
|
2015-10-16 14:36:56 +00:00
|
|
|
|
|
|
|
Decrements the value in dest. Does not honour carry.
|
|
|
|
|
|
|
|
* It is illegal if dest is uninitialized.
|
|
|
|
* It is illegal if dest is read-only.
|
|
|
|
* It is illegal if dest does not occur in the WRITES lists
|
|
|
|
of the current routine.
|
|
|
|
|
|
|
|
Affects n and z flags, requiring that they be in the WRITES lists,
|
|
|
|
and initializing them afterwards.
|
|
|
|
|
2015-10-16 08:30:24 +00:00
|
|
|
### cmp ###
|
|
|
|
|
|
|
|
cmp <dest-memory-location>, <src-memory-location>
|
|
|
|
|
2015-10-16 18:15:01 +00:00
|
|
|
Subtracts the contents of src from dest (without considering carry) but
|
|
|
|
does not store the result anywhere, only sets the resulting flags.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 14:36:56 +00:00
|
|
|
* It is illegal if src OR dest is uninitialized.
|
|
|
|
|
|
|
|
Affects n, z, and c flags, requiring that they be in the WRITES lists,
|
|
|
|
and initializing them afterwards.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
### and, or, xor ###
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
and <dest-memory-location>, <src-memory-location>
|
|
|
|
or <dest-memory-location>, <src-memory-location>
|
2015-10-16 17:39:38 +00:00
|
|
|
xor <dest-memory-location>, <src-memory-location>
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
Applies the given bitwise Boolean operation to src and dest and stores
|
|
|
|
the result in dest.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
* It is illegal if src OR dest OR is uninitialized.
|
|
|
|
* It is illegal if dest is read-only.
|
|
|
|
* It is illegal if dest does not occur in the WRITES lists
|
|
|
|
of the current routine.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
Affects n and z flags, requiring that they be in the WRITES lists of the
|
|
|
|
current routine, and sets them as initialized afterwards.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
dest and src continue to be initialized afterwards.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
### shl, shr ###
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
shl <dest-memory-location>
|
2015-10-16 17:39:38 +00:00
|
|
|
shr <dest-memory-location>
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
`shl` shifts the dest left one bit position. The rightmost position becomes `c`,
|
2015-10-16 08:30:24 +00:00
|
|
|
and `c` becomes the bit that was shifted off the left.
|
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
`shr` shifts the dest right one bit position. The leftmost position becomes `c`,
|
|
|
|
and `c` becomes the bit that was shifted off the right.
|
|
|
|
|
2015-10-16 08:30:24 +00:00
|
|
|
* It is illegal if dest is a register besides `a`.
|
|
|
|
* It is illegal if dest is read-only.
|
|
|
|
* It is illegal if dest OR c is uninitialized.
|
2015-10-16 17:39:38 +00:00
|
|
|
* It is illegal if dest does not occur in the WRITES lists
|
2015-10-16 08:30:24 +00:00
|
|
|
of the current routine.
|
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
Affects the c flag, requiring that it be in the WRITES lists of the
|
|
|
|
current routine, and it continues to be initialized afterwards.
|
|
|
|
|
2015-10-16 08:30:24 +00:00
|
|
|
### call ###
|
|
|
|
|
|
|
|
call <routine-name>
|
|
|
|
|
|
|
|
Just before the call,
|
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
* It is illegal if any of the memory locations in the called routine's
|
|
|
|
READS list is uninitialized.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
Just after the call,
|
|
|
|
|
2015-10-16 17:39:38 +00:00
|
|
|
* All memory locations listed as TRASHED in the called routine's WRITES
|
|
|
|
list are considered uninitialized.
|
|
|
|
* All memory locations listed as TRASHED in the called routine's OUTPUTS
|
|
|
|
list are considered initialized.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
### if ###
|
|
|
|
|
2015-10-16 18:15:01 +00:00
|
|
|
if <src-memory-location> {
|
|
|
|
<true-branch>
|
2015-10-16 08:30:24 +00:00
|
|
|
} else {
|
2015-10-16 18:15:01 +00:00
|
|
|
<false-branch>
|
2015-10-16 08:30:24 +00:00
|
|
|
}
|
|
|
|
|
2015-10-16 18:15:01 +00:00
|
|
|
Executes the true-branch if the value in src is nonzero, otherwise executes
|
|
|
|
the false-branch. The false-branch is optional may be omitted; in this case
|
|
|
|
it is treated like an empty block.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-16 18:15:01 +00:00
|
|
|
* It is illegal if src is not z, c, n, or v.
|
|
|
|
* It is illegal if src is not initialized.
|
|
|
|
* It is illegal if any location initialized at the end of the true-branch
|
|
|
|
is not initialized at the end of the false-branch, and vice versa.
|
2015-10-16 08:30:24 +00:00
|
|
|
|
2015-10-18 12:37:35 +00:00
|
|
|
### repeat ###
|
|
|
|
|
|
|
|
repeat {
|
|
|
|
<block>
|
|
|
|
} until <src-memory-location>
|
|
|
|
|
|
|
|
Executes the block repeatedly until the src (observed at the end of the
|
|
|
|
execution of the block) is non-zero. The block is always executed as least
|
|
|
|
once.
|
|
|
|
|
|
|
|
* It is illegal if any memory location is uninitialized at the exit of
|
|
|
|
the loop when that memory location is initialized at the start of
|
|
|
|
the loop.
|
|
|
|
|
|
|
|
To simulate a "while" loop, use an `if` internal to the block, like
|
|
|
|
|
|
|
|
repeat {
|
|
|
|
cmp y, 25
|
|
|
|
if z {
|
|
|
|
}
|
|
|
|
} until z
|
|
|
|
|
2015-10-18 14:32:28 +00:00
|
|
|
"until" is optional, but if omitted, must be replaced with "forever".
|
|
|
|
|
2015-10-16 08:30:24 +00:00
|
|
|
Grammar
|
|
|
|
-------
|
|
|
|
|
|
|
|
Program ::= {Defn} {Routine}.
|
|
|
|
Defn ::= "byte" NewIdent.
|
|
|
|
Routine ::= "routine" NewIdent
|
|
|
|
["inputs" LocExprs] ["outputs" LocExprs] ["trashes" LocExprs]
|
2015-10-17 12:50:21 +00:00
|
|
|
(Block | "@" WordConst).
|
2015-10-16 08:30:24 +00:00
|
|
|
LocExprs::= LocExpr {"," LocExpr}.
|
2015-10-17 12:50:21 +00:00
|
|
|
LocExpr ::= Register | Flag | LitByte | DefnIdent.
|
2015-10-16 08:30:24 +00:00
|
|
|
Register::= "a" | "x" | "y".
|
|
|
|
Flag ::= "c" | "z" | "n" | "v".
|
2015-10-17 12:50:21 +00:00
|
|
|
LitByte ::= "0" ... "255".
|
|
|
|
LitWord ::= "0" ... "65535".
|
2015-10-16 08:30:24 +00:00
|
|
|
Block ::= "{" {Instr} "}".
|
|
|
|
Instr ::= "ld" LocExpr "," LocExpr
|
|
|
|
| "st" LocExpr "," LocExpr
|
|
|
|
| "add" LocExpr "," LocExpr
|
|
|
|
| "sub" LocExpr "," LocExpr
|
|
|
|
| "cmp" LocExpr "," LocExpr
|
|
|
|
| "and" LocExpr "," LocExpr
|
|
|
|
| "or" LocExpr "," LocExpr
|
|
|
|
| "xor" LocExpr "," LocExpr
|
|
|
|
| "shl" LocExpr
|
|
|
|
| "shr" LocExpr
|
|
|
|
| "inc" LocExpr
|
|
|
|
| "dec" LocExpr
|
|
|
|
| "call" RoutineIdent
|
2015-10-18 12:37:35 +00:00
|
|
|
| "if" ["not"] LocExpr Block ["else" Block]
|
2015-10-18 14:32:28 +00:00
|
|
|
| "repeat" Block ("until" ["not"] LocExpr | "forever")
|
2015-10-18 12:37:35 +00:00
|
|
|
.
|