Skip to content

Microcode Language

Will edited this page Jun 9, 2019 · 24 revisions

About

After the emulator is done, this will be the next required component, in order to tell it how each assembly instruction works. The language will be used to program a memory used for combinatorial logic, so is just going to be a way of expressing something like a 16 input -> 100 output truth table. The chances are that only one file is ever going to be written in this language, the one for this emulator, as the output will be useless anywhere else. That said, it still should be readable for debugging.

EBNF

microcode -> statement:*

statement -> opcode;
statement -> header;
statement -> output;
statement -> input;

opcode -> opcodelong | opcodeshort;
header -> headerlong | headershort;
output -> outputlong | outputshort;
input  -> inputlong  | inputshort;

opcodelong -> opcodeheader "{" line (";":+ line):* ";":* "}"
opcodeshort -> opcodeheader "=" line ";"
opcodeheader -> "opcode" number identifier "(" identifier ("," identifier):* ")"

headerlong -> "header" "{" bits "}";
headershort -> "header" "=" bits ";";

outputlong -> "output" "(" number ")" "{" number ":" idenitifier (";":+ number ":" identifier):* ";":* "}";
outputshort -> "output" "(" number ")" "=" number ":" identifier ";";

inputlong -> "input" "{" ideintifer ":" number (";":+ identifier ":" number ";":* ):* ";":* "}";
inputshort -> "input" "=" identifier ":" number ";";

line -> (conditions ":"):? bits:?
conditions -> condition ("," condition):*;
conditions -> "*"
condition -> identifier | identifier "=" number;
bits -> identifier ("," identifier):*;

identifier -> [^ 0-9(){};:*,=\t\n\r#][^(){};:*,= \t\n\r#]:*;

number -> decimal | hex;
decimal -> [0-9]:+;
hex -> "0x" [0-9a-fA-F]:+;

_ -> " " | "\t" | "\n" | "\r" | comment;  # whitespace allowed between any two tokens
comment -> "#" .:* "\n";

Code Snippets

identifiers: sequence of any printable character not in {}()=;,# that does not start with [0-9]

Condition codes:

*  # run always
admin = 0 # run when admin flag is 0
admin = 1 # run when admin flag is 1

If a flag is tested, both conditions (0,1) need to be tested or it will error. Only one condition can be tested at a time (How would multiple conditions be designed? For two codes would 4 lines be needed?)

Operations:

# create opcode for value 0x78, depends on three registers
opcode 78 ADD(Reg, Reg, Reg) {
    MI,GE,HE;  # assert the MI, GE, and HE signals when the phase counter is 0, opcode is 78 for all flags
    HI,ME,ME,HM;
    *: ; # explicit no operation, `*:` reqired as repeated `;` ignored
    overflow = 1: HR, JQ, LE;
    overflow = 0: ;
}

Each operation has to have the same header so the next instruction can be loaded, regardless of what the previous instruction was or what the condition codes are.

header {
  HE, TE, MT # any condition codes here are an error (other than `*:`)
}

If the total number of instruction lines in the header and an opcode is greater than 16, then it is an error as the phase counter will reset to 0 as it is only 4 bits. An instruction line is either prefixed with * or all parts of a condition, as an example, the ADD opcode above is 4 instruction lines.

macros allows an identifier to expand to a series of bits to set.

macro TX <- BR {
  HE,RE,HU
}
opcode 11 JMP(Reg) {
  TX <- BR, RE;
}

Assign names to each bit that can be set, that name can be used instead of the number in all code in the file. Bracketed value is the number of output bits per microcode ROM, ceil(bit count / output width) binaries are created.

output(8) {
 0: RE;
 9: TY;
}

What the input is, phase clock size, opcode size, all others are 1 bit flags with size = 1 implicitly. opcode and phase are required.

input {
  opsize: 7;
  phase: 4;
  overflow;
}

Brackets: for multi-statement sections of code. If only one statement is required an equals sign can be used with a required semi-colon. In bracketed blocks, the last semi-colon before } is optional.

header =
  HE, GT, BA;
opcode 11 JMP(Reg) = TX <- BR, RE;

imports: no circular imports allowed

import alu; # finds alu.uasm relative to the cwd and imports it
import alu/addition.microcode; # uses .microcode, not .uasm, folder support

TODO: type definitions, type values, possibly re-work opcode dependancies, should non-mnemonic names of opcodes be included in the definition?

Clone this wiki locally