The YGREC8 Assembler

A project log for YGREC8

A byte-wide stripped-down version of the YGREC16 architecture

Yann Guidon / YGDESYann Guidon / YGDES 11/20/2021 at 16:200 Comments

This is a copy of the current documentation for y8asm :


The YGREC8 Assembler

Y8asm is a 2-pass assembler written in VHDL. It transforms source/assembly language .y8 files into .hyx files suitable for flashing/emulation. The VHDL code is compiled and elaborated with GHDL by the provided build/test script, and generates an executable program.


The program can't include files or manage macros. Use external programs such as cpp or m4. You could also concatenate source files with cat to a temporary file.

Program invocation

The program runs on the command line interface or in a script. There are 3 active parameters:

• Input file name: -gname

$ ./y8asm -gname=example.y8

will assemble the file named example.y8.

The output file name is derived from this parameter, with the .hyx suffix.

The output file will be overwritten without a warning.

• Symbol table output: -gdump

$ ./y8asm -gname=example.y8 -gdump=yes

appends a dump of the user-defined symbols in the comments at the end of the .hyx output file.

The dump also contains the number of times the symbol has been referenced (though it might be over-estimated because it includes both passes). That's still convenient if you want to clean up your source code and prune some useless lines.

The option -gdump=full dumps all the defined symbols, including the reserved words, keywords, opcodes etc.

• Maximum Symbol Length : -gmax_sym_len

$ ./y8asm -gname=example.y8 -gmax_sym_len=12

changes the maximum length of symbols (labels, identifiers etc.) from the defaut 16 characters to 12 characters.

Basic Syntax

• Comments start at ';' and remove the rest of the line.

• All the symbols are translated to upper case during parsing.

• The symbols can not be redefined. Unless they are in a nested context (not yet implemented).

• User's symbols have a range dependent on the VHDL simulator, "at least 32 bits". This is practical for intermediary values since the assembler checks each range for every instruction field.

• Identifiers can contain the following letters: '_', 'A' to 'Z' and '0' to '9' (but no digit at the first position).

• Separators are space ' ', comma ',', horizontal tab, and ASCII character 160 (  in HTML).

• The dollar sign '$' represents/returns the value of the current address.

• Numbers are decimal by default. Binary numbers have the b suffix and h is the hexadecimal suffix.

• Numerical computations ("expressions") are always between parenthesis, to avoid precedence. The assembler supports the following arithmetic operations: '+', '-', '*', '/', '%'. VHDL does not allow easy boolean operations on integers, unless you go the std_logic_vector route, but I can't change the standard... I'll add later if needed.

• By default, code is assembled starting at address 0. Don't forget to ORG if you need otherwise.


The assembler provides some housekeeping commands that greatly help even basic programs.


Ends parsing of the file. The source file can contain any garbage below this line.


DEFines a new user symbol.

The line

DEF plop 42

defines the symbol "PLOP" and assigns the value 42. The symbol "PLOP" can be used later in the source file, and even before for instructions and DW.

See the -gdump=yes command line argument to list all the user-defined symbols.

• Label:

The line


is a shorthand to the line "DEF plop $".

There is no separator before ':' and the label must be alone on the line.


Change the address to which the next instruction will be assembled/stored.

ORG 42

means that the next instruction will be stored at address 42.

The value may be a number, symbol or expression, but can not be post-defined or have a value lower than the current address.

• DW

DW 42

will output the value 42 to the instruction memory space, as if it was an instruction.

Just like an instruction, it is 16-bit wide and can have a post-defined value.


The assembler pre-defines the following keywords as elements of an instruction:

• Opcodes

"ADD", "AND", "ANDN", "CALL", "CMPS", "CMPU", "HLT", "IN", "INV", "LDCH", "LDCL", "NOP", "OR", "OUT", "RC", "RO", "SA", "SET", "SH", "SUB", "XOR"

• Registers

"A1", "A2", "D1", "D2", "PC", "R1", "R2", "R3"

• Conditions

"ALWS", "IF0", "IF1", "IF2", "IF3", "IFC", "IFN0", "IFN1", "IFN2", "IFN3", "IFN", "IFNC", "IFNZ", "IFP", "IFZ", "NEVR"

Follow the opcode map to see which operations are possible:

The instruction's textual format follows the binary format (except the condition which is a suffix).

• No operand: "HLT", "INV", "NOP"


NOP ; do nothing

HLT ; put the core in sleep mode until the next IRQ

INV ; trigger a trap/reboot/panic

• One immediate operand and a register: "IN", "OUT"


IN 67, D3  ; get value from IOspace at address 67 and write register D3

OUT 45 A1 ; Put the value of A1 into IOspace at address 45

• One short immediate or a source register, a destination register and optional condition: "LDCH", "LDCL", "RC", "RO", "SA", "SH"


RC  1  D1      ; Rotate register D1 through carry by 1 position (left)

RO -3  D2 IFNC ; Rotate register D2 by 3 positions (right) when the carry bit is clear

SA  R1 A1      ; Arithmetic Shift of A1 by R1 positions

SH  R2 A2 IFZ  ; Logic shift of A2 by R2 positions if Zero flag is clear

• One long immediate and a destination register, OR One short immediate or a source register, a destination register and optional condition: "ADD", "AND", "ANDN", "CALL", "CMPS", "CMPU", "OR", "SET", "SUB", "XOR"


AND 123 R1 ; bit-mask R1 with byte 123

ADD -76 R2 ; subtract byte 76 from register R2

SUB  95 R3 ; Subtract R3 from byte 95 and put the result in R3

ADD 1 A1 IFC ; increment A1 by short 1 if the carry bit is set

ADD 0 A1 IFC ; INVALID !  \ short add increments positive
ADD 8 A1 IFC ;   VALID !  /     immediate values by 1             ;                 to extend the range of jumps

ADD D1 A1 IFN ; Add D1 to A1 (result in A1) if the Negative flag is set.