Kyler Olsen
NOTICE: This project is still a work in progress.
It is a custom computer and instruction set architecture. It also has its own assembly language with assembler written in Python. Custom high level language currently in development.
The purpose of this project is for me to practice creating an ISA and a compiler and assembler tool chain for the platform. I also plan to possibly build a redstone computer in Minecraft that implements this ISA.
See file docs/12-bit ISA.html
ZR
: Zero RegisterPC
: Program CounterSP
: Stack PointerMP
: Memory PointerD0
: Data 0D1
: Data 1D2
: Data 2D3
: Data 3
NOP
HLT
BNZ
BNA
BNP
BNN
GLA
Destination Register
GET
Destination Register
LOD
Destination Register
STR
Source Register
POP
Destination Register
PSH
Source Register
LIU
Immediate Value (Integer)
LDI
Immediate Value (Integer)
LDI
:Label
LIL
Immediate Value (Integer)
LSH
Destination Register
Source Register
RSH
Destination Register
Source Register
INC
Destination Register
Source Register
DEC
Destination Register
Source Register
AND
Destination Register
Source Register A
Source Register B
OR
Destination Register
Source Register A
Source Register B
SUB
Destination Register
Source Register A
Source Register B
XOR
Destination Register
Source Register A
Source Register B
NOR
Destination Register
Source Register A
Source Register B
NAD
Destination Register
Source Register A
Source Register B
ADD
Destination Register
Source Register A
Source Register B
Label
:
.Integer
; Yeahbut - Feb 2024
; Fibonacci
.0x0
main:
; Initialize Fibonacci values
ldi 1
or D0 MP ZR
or D1 ZR ZR
or D2 ZR ZR
loop:
; Output current value
liu 0x1f
lil 0x3D
str D0
; Move values down
or D2 D1 ZR
or D1 D0 ZR
; Add last two values to get the next value
add D0 D1 D2
ldi :loop
or PC MP ZR
Yes, you may cringe that I used Comic Sans in my logo.
I do when others do so. <3 Kyler
- Name: DuoDeca-Script
- Paradigm: Multi-Paradigm: Procedural (Imperative), Structured
- Designer: Kyler Olsen
- Created: Mar 2024
- Typing Discipline: Static, Weak, Manifest
- Platform: ytd 12-bit computer, ytd 12-bit emulator (from pytd12dk, multi-platform)
- License: MIT
- Filename extension:
.ytd12c
,.duox
- Compiler Implementations:
pytd12dk
(Python),ytd12nc
(native compiler)
Note: The following sections define the language and may not be as well suited for learning the language.
Directives start with #
and end at the end of a line.
They are used to give additional instructions to the compiler.
Comments can either be single-line comments or multi-line comments.
Single-line comments start with //
and end at the end of a line.
Multi-line comments start with /*
and end with */
.
pytd12dk implementation detail: Comments and their content are ignored by the lexer after they are tokenized. There are no comments in the output of the lexer.
Can be up to 15 characters in length, and are case sensitive. They cannot be a keyword.
Identifier ::= ID_Start ID_Continue*
ID_Start ::= <Any latin alphabet ligature or an underscore: "A"-"Z", "a"-"z", "_">
ID_Continue ::= ID_Start | <Any decimal ligature: "0"-"9">
struct fn enum static
if else do while
for break continue let
unsigned int fixed float
True False None
Number Literals
number ::= decinteger | bininteger | octinteger | hexinteger | pointfloat | exponentfloat
decinteger ::= nonzerodigit (["_"] digit)* | "0"+ (["_"] "0")*
bininteger ::= "0" ("b" | "B") (["_"] bindigit)+
octinteger ::= "0" ("o" | "O") (["_"] octdigit)+
hexinteger ::= "0" ("x" | "X") (["_"] hexdigit)+
nonzerodigit ::= "1"..."9"
digit ::= "0"..."9"
bindigit ::= "0" | "1"
octdigit ::= "0"..."7"
hexdigit ::= digit | "a"..."f" | "A"..."F"
pointfloat ::= ([digitpart] fraction) | (digitpart ".")
exponentfloat ::= (digitpart | pointfloat) exponent
digitpart ::= digit (["_"] digit)*
fraction ::= "." digitpart
exponent ::= ("e" | "E") ["+" | "-"] digitpart
Character Literals
Character Literals must be on one line and begin and end with '
. They can only
have one printable ascii character or escape code.
String Literals
String Literals must be on one line and begin and end with "
. They can have a
unspecified number of printable ascii characters and escape codes.
Escape Codes
Code | Meaning |
---|---|
\0 |
Null Character |
\a |
Alert (Beep, Bell) |
\b |
Backspace |
\e |
Escape Character |
\f |
Formfeed Page Break* |
\n |
Line Feed |
\r |
Return Carriage |
\t |
Horizontal Tab |
\v |
Vertical Tab* |
\\ |
Backslash |
\' |
Single Quotation Mark (In char literals) |
\" |
Double Quotation Mark (In str literals) |
++ -- @ $ + -
* / % ~ & |
^ << >> = += -=
*= /= %= &= |= ^=
<<= >>= ! && || ^^
== != < <= > >=
{ } [ ] ( )
? . -> , ; :
The syntactical structure starts with a File
at the root.
A File
can contain any number of the following elements:
directive
struct
enum
function
Just a directive
.
pytd12dk implementation detail: Their content is stored here for later when directive compilation occurs.
A struct
begins with the struct
keyword. It then has its identifier
followed by a comma (,
) separated list enclosed in curly braces ({
and }
)
of structure members.
A structure member begins with its identifier
, which may optionally be
preceded with the static
keyword. After a colon (:
) is its data type
. It
may then optionally be followed by an equal sign (=
) and a literal
.
A enum
begins with the enum
keyword. It then has its identifier
followed
by a comma (,
) separated list enclosed in curly braces ({
and }
) of
enum members.
An enum member begins with its identifier
. It can then optionally be
followed by an equal sign (=
) and a number literal
.
A function
begins with the fn
keyword. It then has its identifier
followed
by a comma (,
) separated list enclosed in parentheses ((
and )
) of
function parameters. After that is an arrow (->
) followed by a data type
denoting the function's return type. After that is a list enclosed in curly
braces ({
and }
) of statements
.
A function parameter begins with its identifier
, followed by a colon (:
)
and its data type
. It may then optionally be followed by an equal sign (=
)
and a literal
.
An if statement
begins with the if
keyword, followed by its condition, an
expression
enclosed in parentheses ((
and )
), then a single statement
or a list enclosed in curly braces ({
and }
) of statements
. It may then
optionally be followed by an else block
.
A do loop
begins with the do
keyword, followed by a single statement
or a
list enclosed in curly braces ({
and }
) of statements
. It is then followed
with the while
keyword, then by its condition, an expression
enclosed in
parentheses ((
and )
). It is then followed by a single statement
or
another list enclosed in curly braces ({
and }
) of statements
. Finally
the do loop
may optionally be followed by an else block
.
A while loop
begins with the while
keyword, followed by its condition, an
expression
enclosed in parentheses ((
and )
), then a single statement
or a list enclosed in curly braces ({
and }
) of statements
. It may then
optionally be followed by an else block
.
A for loop
begins with the for
keyword, followed by three expressions
enclosed in parentheses ((
and )
), separated by semicolons (;
). The
first expression is a pre-loop expression, the second is its condition which
is a normal expression
, and the last is its post-loop expression which is
another normal expression
. It is ended with a single statement
or a list
enclosed in curly braces ({
and }
) of statements
. It may then optionally
be followed by an else block
.
A pre-loop expression can be a normal expression
or a special variable
definition. It starts its identifier, then a colon (:
) is its data type
,
then an equal sign (=
) followed by an expression
.
An else block
begins with the else
keyword, followed by a single
statement
or a list enclosed in curly braces ({
and }
) of statements
.
A let statement
begins with the let
keyword, which may optionally be
preceded with the static
keyword. It then has its identifier
, followed by
a colon (:
) and its data type
. It may then optionally be followed by an
equal sign (=
) and an expression
. It must then be finished with a semicolon
(;
).
A unary expression
is made up of one expression
and one unary operator
.
The operator may come before or after the expression.
A binary expression
is made up of one expression
, then one
binary operator
, then another expression
.
A ternary expression
is made up of one expression
which is the condition,
then a question mark (?
) followed by two expression
s separated by a colon
(:
).
A function call
starts with an identifier
followed by a comma (,
)
separated list enclosed in parentheses ((
and )
) of function arguments.
A function argument is an expression
that may optionally be preceded by an
identifier
which is immediately followed by an equal sign (=
).
An enclosed expression
is simply an expression
enclosed in parentheses
((
and )
).
Here are all operators and their types and names in order of operator precedence.
Operator | Type | Name |
---|---|---|
@ |
Unary (Prefix) | Address of Operator |
$ |
Unary (Prefix) | Dereference Operator |
~ |
Unary (Prefix) | Bitwise NOT Operator |
-- |
Unary (Postfix) | Postfix Decrement Operator |
++ |
Unary (Postfix) | Postfix Increment Operator |
-- |
Unary (Prefix) | Prefix Decrement Operator |
++ |
Unary (Prefix) | Prefix Increment Operator |
- |
Unary (Prefix) | Negate Operator |
! |
Unary (Prefix) | Boolean NOT Operator |
. |
Binary | Member of Operator |
>> |
Binary | Right Shift Operator |
<< |
Binary | Left Shift Operator |
^ |
Binary | Bitwise XOR Operator |
| |
Binary | Bitwise OR Operator |
& |
Binary | Bitwise AND Operator |
% |
Binary | Modulus Operator |
/ |
Binary | Division Operator |
* |
Binary | Multiplication Operator |
- |
Binary | Subtraction Operator |
+ |
Binary | Addition Operator |
>= |
Binary | Greater or Equal to Than Operator |
> |
Binary | Greater Than Operator |
<= |
Binary | Less or Equal to Than Operator |
< |
Binary | Less Than Operator |
!= |
Binary | Inequality Comparison Operator |
== |
Binary | Equality Comparison Operator |
^^ |
Binary | Boolean XOR Operator |
|| |
Binary | Boolean OR Operator |
&& |
Binary | Boolean AND Operator |
? : |
Ternary | Ternary Conditional Operator |
>>= |
Binary | Right Shift Assignment Operator |
<<= |
Binary | Left Shift Assignment Operator |
^= |
Binary | Bitwise XOR Assignment Operator |
|= |
Binary | Bitwise OR Assignment Operator |
&= |
Binary | Bitwise AND Assignment Operator |
%= |
Binary | Modulus Assignment Operator |
/= |
Binary | Division Assignment Operator |
*= |
Binary | Multiplication Assignment Operator |
-= |
Binary | Subtraction Assignment Operator |
+= |
Binary | Addition Assignment Operator |
= |
Binary | Assignment Operator |
A literal
is just simply the content of the literal. There are three types of
literals:
- Number Literal
- Character Literal
- String Literal
A identifier
is just simply the name of the identifier.
A data type
is made up of an identifier
or default data type
, and may
optionally be preceded by an at symbol (@
).
There are four default data types represented by the following keywords:
unsigned
int
fixed
float
A statement
is made up of an expression
followed by a semicolon (;
), a
let statement
, a loop statement
, or a nestable code block
.
There are four nestable code block
s:
if statement
do loop
while loop
for loop
A loop statement
are either the keyword continue
or break
followed by a
semicolon (;
).
Currently directives are ignored by the compiler. In future versions of the language, directives will be used.
pytd12dk
(Python ytd 12-bit development kit) is a tool set written in Python
to assist in developing software for the ytd 12-bit computer. It includes a
compiler, assembler with linker, and emulator.
NOTICE: pytd12dk
requires Python version 3.12 (or higher).
The first part of the tool kit is the compiler. It is currently unfinished and can not yet produce an executable.
Running the following command we can get the arguments for the
compiler python -m pytd12dk cm -h
:
usage: __main__.py cm [-h] [-t TOKEN_FILE] [-x SYNTAX_FILE] input_file
positional arguments:
input_file
options:
-h, --help show this help message and exit
-t TOKEN_FILE, --token_file TOKEN_FILE
-x SYNTAX_FILE, --syntax_file SYNTAX_FILE
The only required positional argument is input_file
. This is the source
code file to be compiled.
The optional argument --token_file
is a text file output which contains debug
information from the output of the lexer. It is a list of the tokens parsed from
the source file and their lexical types.
The optional argument --syntax_file
is a text file output which contains debug
information from the output of the syntactical analyzer. It is a text
representation of the syntax tree.
Additional optional arguments for semantical debug info, object file, and executable file will be added.
The second part of the tool kit is the assembler. Included with the assembler is a simple linker.
Running the following command we can get the arguments for the
compiler python -m pytd12dk am -h
:
usage: __main__.py am [-h] [-o OUTPUT_FILE] [-l LABELS_FILE] [-x HEX_FILE] input_file
positional arguments:
input_file
options:
-h, --help show this help message and exit
-o OUTPUT_FILE, --output_file OUTPUT_FILE
-l LABELS_FILE, --labels_file LABELS_FILE
-x HEX_FILE, --hex_file HEX_FILE
The only required positional argument is input_file
. This is the assembly
code file to be assembled.
The optional argument --labels_file
is a text file output which contains a
list of the labels found and their address locations in the executable.
The optional argument --hex_file
is a text file output which contains the
generated machine code in hexadecimal representation.
The optional argument --output_file
is a binary file output which contains the
generated machine code which can directly be executed by the emulator.
The third part of the tool kit is the emulator.
Running the following command we can get the arguments for the
compiler python -m pytd12dk em -h
:
usage: __main__.py em [-h] [-m {tty}] [-v] [-s] [-c CLOCK] rom_file
positional arguments:
rom_file
options:
-h, --help show this help message and exit
-m {tty}, --machine {tty}
-v, --verbose
-s, --step
-c CLOCK, --clock CLOCK
The only required positional argument is rom_file
. This is the executable
binary generated by the assembler or compiler.
The optional argument --machine
allows for the selection of a pre-configured
virtual machine. Later in the section Pre-configured VMs
are a list of included machine(s). The default selection is tty
.
The optional argument --verbose
turns on printing the current program address,
the value at the address, the interpreted instruction, and each register and
their current values every clock cycle.
The optional argument --step
turns on waiting for user input between each
clock cycle. This disables any set or default value of the option --clock
,
making it essentially zero.
The optional argument --clock
sets the time between each clock cycle in
thousandths of a second. The default value is 100
(one tenth of a second).
Here are the pre-configured virtual machine(s) included with pytd12dk
.
The machine tty
includes a tty IO device.
-
Writing to address
0x7FD
outputs a signed integer. -
Writing to address
0x7FE
outputs an unsigned integer. -
Writing to address
0x7FF
outputs an ASCII/UTF-8 character.
- Reading from address
0x7FF
inputs an ASCII/UTF-8 character.
Included in the repo is an examples
directory. Inside there is the
file test1.s
. It contains a simple assembly program to calculate and output
the fibonacci sequence.
; Kyler Olsen - Feb 2024
; Example 1 - ytd 12-bit Computer
; Fibonacci
; .0x5
main:
; Initialize Fibonacci values
ldi 1
or D0 MP ZR
or D1 ZR ZR
or D2 ZR ZR
loop:
; Output current value
liu 0x1f
lil 0x3D
str D0
; Move values down
or D2 D1 ZR
or D1 D0 ZR
; Add last two values to get the next value
add D0 D1 D2
ldi :loop
or PC MP ZR
We can assemble and link it using the following command. Notice: Python 3.12
or higher is required for pytd12dk
.
python3 -m pytd12dk am examples/test1.s -o bin/a.out
We can then execute the binary using the included emulator. We should see the
fibonacci sequence printed to the console. We can use ctrl
+ c
to exit the
emulator.
python3 -m pytd12dk em bin/a.out
Also inside the examples
directory there is a Hello World program in the
file test2.s
.
ytd12nc
(ytd 12-bit native compiler) is a compiler and assembler with linker
written in the native high-level programming language and assembly language
to compile software for the ytd 12-bit computer natively.
Currently development of ytd12nc
has not yet started.