This complier is an attempt to make generating the micro code for MyCpu less error prone. Along the way I learnt a lot this code is still quite
buggy but does produce correct micro code.
The micro-code complier works with the assembler thst has gone though several rewirtes it will publish here soon.
The assembler takes the processed output from the micro code compiler to generate the tables for the assembler. I have a seperate program that generates the tables for the assembler the format for thi is encodded in the comments for each instruction
I did this so as I change the instruction set I do not have to completely rebuilt the assembler. This document by its nature will reffer to the architecture of the MyCpu as it is the mirco code builder/compiler for this cpu. The output is current a very basic hex format the [digital]: https://github.com/hneemann/Digital simulator. I will keep the parts of this project seperate as the assembler and table bulider can be used for other 8 bit processors. The assembler is at a very basic stage but it has room to grow.
Table of contents generated with markdown-toc
XX: starts generation of instruction
op: 0xnn ; the start of an instruction the semi colon finish the line all valid lines must have a semi colon.
I have used c++ style quotes for comments as a semi colon on it own now is a syntax error.
end:; end the instruction build sequence code
ram[pc]->REGA gets dat from ram using the PC and place in REG(A)
pc(inc) this increments the PC counter this will be extend to X , Y and SP in the up coming redesign.
The target of -> can be any of the following;
A register including the mar[lsb],mar[msb],pc[lsb] and so on.
The structure define the makeup of the micro code instruction word
struct inst_word {
int Sreg_code : 4 ; //bit 0-3
int Dreg_code : 4 ; //Bit 4-7
int W16 : 1 ; //Bit 8 Saves current address to 16 bit reg
int DBtoALU : 1 ; //Bit 9
int ex_alu : 1 ; //Bit 10
int inc_pc : 1 ; //Bit 11 now increments selected 16 reg
int sp_func : 2 ; //Bit 12-13
int __sel_msb : 1 ; //Bit 14
int __sel_lsb : 1 ; //Bit 15
int ldinst : 1 ; //Bit 16
int en_jmp0 : 1 ; //bit 17
int ad_mast : 2 ; //bit 18-19
int alu_func : 4 ; //bit 20-23
int alu_flags : 3 ; //Bit 24-26
int alu_cntrl : 3 ; //Bit 27-29
int dec_sp : 1 ; //Bit 30 Decrements selected register
int _AorD : 1 ; //Bit 31 // Select A or d register set to ALU
};
This a dynamic thing and is not yet complete for example the MyCpu current doesn't yet implement interrupts. There is some disconnect between the structure above and the documented fields below .
The CPU as currently implemented exists as a [digital]: https://github.com/hneemann/Digital Simulation. The ALU is based on 74LS181
Codes to select item for output onto DB designed so only one item can output.
Code | Function notes | Mnemonic |
---|---|---|
0 | Nothing selected this does away with enable bit. | None |
1 | Enable Register A onto the main data bus | REGA |
2 | Enable Register B onto the main data bus | REGB |
3 | Enable Register C onto the main data bus | REGC |
4 | Enable Register D onto the main data bus | REGD |
5 | Enable Register H onto the main data bus | REGH |
6 | Enable Register L onto the main data bus | REGL |
7 | Enable read of PC | R_PC |
8 | Enable read of Y | R_Y |
9 | Enable read of X | R_X |
10 | Enable Read of SP Note all 16 bit reads require LSB/MSB signal to complete bus transaction | R_SP |
11 | Spare | |
12 | Spare | |
13 | Read ALU flags and status reg | R_Flags |
14 | Enable the output of the RAM onto the data bus and A side of ALU | RAM |
15 | Special function code HALT stops all clocks | HALT |
These are expanded control bits from the control register.
Code | Function notes | Mnemonic |
---|---|---|
0 | This cause current PC to be latched into the transparent latches leave this code active when the PC is active this allows push and PC index operations to work. | DEF |
1 | Assert MSB line to allow 8 operations on 16 bit reg | SEL_MSB |
2 | Assert LSB line to allow 8 operations on 16 bit reg | SEL_LSB |
3 | Enables I/O operations. | I_O mode |
This selects the source of the Address bus
Code | Function notes | Mnemonic |
---|---|---|
0 | The Program Counter (PC) is used as the source for the address bus | AD_PC |
1 | The Stack Pointer (SP) is used as the source for the address bus | AD_SP |
2 | The Memory Address Register (MAR) is used as the source for the address bus | AD_MAR |
3 | Address bus disabled high Z state. | AD_OFF |
This is the ALU control codes it also needs the M and C bit in the control word to be set as well to control the ALU software The simulation current has a decode ROM that correctly sets the state of all control bits and the correct ALU code . Note function of the carry flag is inverted during sub functions. Note A and B are inputs to the ALU with B bus currently coming from the B register and A bus from the A register. The ALU execute line causes the current result of the ALU operation to be written to currently active A register. See the main CPU documentation for more details.
Mnemonic | Code | Mbit | Cin | Carry_Ctl | OP_code | Shift | ALU Code |
---|---|---|---|---|---|---|---|
ADD A+B | 0 | 0 | 1 | 0 | 9 | 0 | 0029 |
ADC A+B | 1 | 0 | 1 | 1 | 9 | 0 | 0069 |
SUB A-B | 2 | 0 | 0 | 0 | 6 | 0 | 0006 |
SUBC A-B | 3 | 0 | 0 | 1 | 6 | 0 | 0046 |
AND A .and. B | 4 | 1 | 0 | 0 | b | 0 | 001B |
XOR A .xor. B | 5 | 1 | 0 | 0 | 6 | 0 | 0016 |
OR A .or. B | 6 | 1 | 0 | 0 | e | 0 | 001E |
NOTA | 7 | 1 | 0 | 0 | 0 | 0 | 0010 |
DEC A | 8 | 0 | 1 | 0 | F | 0 | 002F |
INC A | 9 | 0 | 0 | 0 | 0 | 0 | 0000 |
SLL A with count B1 | 10 | 0 | 1 | 0 | 0 | 1 | 00A0 |
SLR A count B1 | 11 | 1 | 0 | 0 | 0 | 1 | 0090 |
SET A -> FF | 12 | 0 | 1 | 0 | 3 | 0 | 0023 |
CLR A->0 | 13 | 1 | 0 | 0 | 3 | 0 | 0013 |
CMP A to B | 14 | 0 | 1 | 0 | 6 | 0 | 0026 |
TSTA | 15 | 0 | 1 | 0 | 0 | 0 | 0020 |
1 | 1 | 1 | f | 1 | 00FF |
Table 5
This code selects the flag into the control rom this allows for instructions to be influenced by the the state of the flags register.
Code | Function notes | Mnemonic |
---|---|---|
0 | All ways zero | NOP |
1 | Zero Flag select | Z |
2 | Carry flag select | C |
3 | Equal flag selected, note valid in compare ins only | = |
4 | Greater than flag selected, note valid in compare ins only | GT |
5 | Less than flag selected, note valid in compare ins only | LT |
6 | Negative Flag selected | - |
Table 6
Codes to select item to read from DB now only one destination is allowed
Code | Function notes | Mnemonic |
---|---|---|
0 | Nothing selected this does away with enable bit. | None |
1 | Enable Register A onto the main data bus and A side of ALU | REGA |
2 | Enable Register B to read the main data bus and A side of ALU | REGB |
3 | Enable Register C to read the main data bus and A side of ALU | REGC |
4 | Enable Register D to read the main data bus and A side of ALU | REGD |
5 | Enable Register T to read the main data bus and A side of ALU | R_Temp |
6 | Writ LSB of a 16 bit reg it doesn’t care which reg at this stage as we only have 1 16 bit LSB holding register. | W16_LSB |
7 | Write the 16 value into the selected 16 register with LSB from holding register and MSB from the DB. | W16_PC |
8 | Write the 16 value into the selected 16 register with LSB from holding register and MSB from the DB. | W16_SP |
9 | Write the 16 value into the selected 16 register with LSB from holding register and MSB from the DB. | W16_X |
10 | Write the 16 value into the selected 16 register with LSB from holding register and MSB from the DB. | W16_Y |
11 | This codes currently unused | |
12 | Write H | |
13 | Write L | |
14 | This codes currently unused | |
15 | Enable write to RAM | W_RAM |
A valid instruction definition is as follows
it starts with an
op: 0x00
and finishes with the
*:end ;
In between we have instructions to actually carry the intended operations for the instructions. Now let's look at a real instruction.
op: 0x18 ; //ADC_DA_VAL 3 Add 16 bit mem to DA with carry
*: ram[pc]->instr,inc(pc) ; //basic istruction fetch
*: ram[pc]->acum,alu(adc),inc(pc),swapBT; //LSB
*: ram[pc]->acum,alu(adc),jmp0,inc(pc),swapBT,swapAD; //MSB
*: end;
First the "op:0x18 ;" defines the op code we are allocating to this instruction. An error is flagged if more than one is instruction is attempted to be defined.
The comment following "//ADC_DA_VAL 3 Add 16 bit mem to DA with carry " is not really a comment and is also required if wish to build the assembler tables. This define the Mnemonic for the instruction. This translates as follows the first part is always the mnemonic the "_ " defines the end of each section. The next parts depend on the instruction in this case its a 16 bit register be added to a memory location. the number following is how many bytes the instruction needs. in this example it needs three one byte for the instruction and two bytes for the 16 bit operand.
The next line "*: ram[pc]->instr,inc(pc) ; //basic istruction fetch" is present in all my instructions and shows the processor roots to be the Ben Eater concept. Its the instruction fetch. To break it down star colon always start the line with star being any of the following *,Z,C,=,GT,LT,neg.
Symbol | Meaning | Description |
---|---|---|
* | Star | ignore the input from the flags |
Z | Zero Flag | Select for zero flag |
C | Carry Flag | Select for carry flag |
= | Equal Flag | Select for equal flag this only valid after the compare operation |
GT | Greater Than Flag | Select for greater than flag this only valid after the compare operation |
LT | Less than Flag | Select for less than flag this only valid after the compare operation |
neg | Negative Flag | Select for negative number |
The "ram[pc]" think of this as an array where ram is the memory and pc the index. The construct "->" means place value in.
And in the example it is the instruction decode register. The comma tell the complier it is finished with that element of the micro instruction. Next think of it as a call to an increment function with the PC as parameter.
Next line now takes the value from the memory pointed to by the PC and places that value on the address bus in this case the target is the ALU. The syntax acum is hold over from a previous design and now this coding just place the value on the data bus.
The next part tell the ALU to execute the ADC ALU instruction as with all instructions this will happen on the rising clock tick.
Next we have another increment of the PC and the the strange code "swapBT" this strange code is flag and correlates to a flag in the final control word that makes the B side of the ALU the DATA bus.
The next line is identical except for the "swapAD" code. As with the previous example this is a control flag but in this case it swaps the A and D register onto the A bus of the ALU. With these two control lines it gives us great control over data flow to the ALU.
Codes | Description | |
---|---|---|
REGA","REGB","REGC","REGD","REGH","REGL" | These are the 8 bit working registers with A and D being contented to the A side of the ALU. B and C are connected to the B side. With A and B the default registers. H and L are just 8 bit registers with no connection to the ALU. | |
"ram" | Always used in the form ram[X] with X being one of the 16 bit registers. | |
"pc","sp","mar","Y" | The 16 bit registers. These can be targets of the inc() or dec() function note this does not go through the ALU. It is implemented in hardware. | |
"jmp0", | Reset the micro code counter - it in effect marks the end of the instruction. | |
"end" | Marks the formal end of the microcode instructions. | |
"lsb","msb" | This is used select the MSB or the LSB of the 16 bit registers and places or reads the value from the data bus. coded as pc[lsb]. |
it is important to note you can't do "REGA->REGB,REGC->REGD,inc(pc)" as this make no sense as the code excutes in one clock cycle an the regesiter control lines are only able to access one source and destination at a time via the databus. SO in the design of this micro-code bulider each line of code is one clock cycle.
More to follow
The source code is in very plain console C so I would expect it to compile on any system with current C compiler.
I have not created a makefile for this project as yet. The .prj file is for the Pelles C complier I used to develop the project with I am moving to plain gcc and MS visual C++ but the code will remain in C. to build with gcc "gcc main.c parser.c -o micro_code_compiler.exe" This should work on windows or linux with GCC installed.
How to compile micro-code
micro-code-compiler.exe jump_inst_new.asm
This compile the file "jump_inst_new.asm" and display the result as follows
1062 op: 0xe1 ; //ADC_DA_(X+) 1 ADC with pointed to by X MEM result in DA
1063 :00e1: :0001080e:*: ram[pc]->instr,inc(pc) ; //basic istruction fetch
1064 :01e1: :00180e0e:*: ram[mar]->acum,alu(adc),swapBT,inc(mar);
1065 :02e1: :801a0e0e:*: ram[mar]->acum,alu(adc),jmp0,swapAD,swapBT,inc(mar);
1066 *:end;
1067 op: 0xe2 ; //SUB_DA_(X+) 1 SUB with pointed to by X MEM result in DA
1068 :00e2: :0001080e:*: ram[pc]->instr,inc(pc) ; //basic istruction fetch
1069 :01e2: :00280e0e:*: ram[mar]->acum,alu(sub),swapBT,inc(mar);
1070 :02e2: :802a0e0e:*: ram[mar]->acum,alu(sub),jmp0,swapAD,swapBT,inc(mar);
1071 *:end;
1072 op: 0xe3 ; //SBC_DA_(X+) 1 SBC with pointed to by X MEM result in DA
1073 :00e3: :0001080e:*: ram[pc]->instr,inc(pc) ; //basic istruction fetch
1074 :01e3: :00380e0e:*: ram[mar]->acum,alu(sbc),swapBT,inc(mar);
1075 :02e3: :803a0e0e:*: ram[mar]->acum,alu(sbc),jmp0,swapAD,swapBT,inc(mar);
1076 *:end;
1077 op: 0xe4 ; //AND_DA_(X+) 1 AND with pointed to by X MEM result in DA
1078 :00e4: :0001080e:*: ram[pc]->instr,inc(pc) ; //basic istruction fetch
1079 :01e4: :00480e0e:*: ram[mar]->acum,alu(and),swapBT,inc(mar);
1080 :02e4: :804a0e0e:*: ram[mar]->acum,alu(and),jmp0,swapAD,swapBT,inc(mar);
1081 *:end;
1082 op: 0xe5 ; //OR_DA_(X+) 1 or with pointed to by X MEM result in DA
1083 :00e5: :0001080e:*: ram[pc]->instr,inc(pc) ; //basic istruction fetch
1084 :01e5: :00680e0e:*: ram[mar]->acum,alu(or),swapBT,inc(mar);
1085 :02e5: :806a0e0e:*: ram[mar]->acum,alu(or),jmp0,swapAD,swapBT,inc(mar);
1086 *:end;
The resultant hex file is place in a.out. It is fact a text file so you can view see todo for furture plans on format.
Add a final error message report and try clean reported errors currently it can die with out a decent diagnostic message.
- Fix syntax to avoid the need for a dangling comma in some syntax structures.
- More options for output formats for example binary, offical intel hex.