• More microcode compiler capabilities!

    09/15/2021 at 06:48 0 comments

    I have been fairly busy with the microcode compiler, mostly because the new HEX IO project has brought new ideas about useful features.

    In addition to various bug fixes, the main one is addition of new .sym directive. Here is an example:

    .symbol 7, 256, hex2mem_sym.mif, hex2mem_sym.cgf, hex2mem_sym.coe, h2m:hex2mem_sym.vhd, hex2mem_sym.hex, hex2mem_sym.bin, 32;

    .symbol 7, 256, hex2mem_sym.mif, hex2mem_sym.cgf, hex2mem_sym.coe, h2m:hex2mem_sym.vhd, hex2mem_sym.hex, hex2mem_sym.bin, 32;

    This will do the following:

    1. Create internally a memory block 7 address lines deep (128 locations) and 256-bits wide
    2. Initialize the block with source code of the microcode (8-bit ASCII, everything on the line beyond byte 32 will be truncated)
    3. Export the memory block into file names / formats specified (for example, hex2mem_sym.hex file) 
    4. Generate .vhdl template file that can be directly included into project if needed

    The vhdl template file can be consumed by a component built into the project during debug and development phase to provide tracing of source code at each microinstruction being executed. Here is an example of such a tracer. For each microinstruction, it generates a 64 ASCII char record (close with CR+LF chars) suitable for UART transmit. This record typically contains:

    • some number of internal machine values or flags useful to observe the state of the system
    • microinstruction pointer value
    • source code line

    Here is an example of all microinstructions executed by hex2mem component when a ':' (first char in hex file line) is received:

      .
    : 3A 67 trace: if TRACE_CHAR then next e                     .
    : 3A 1E emitChar: if TXDREADY then next                      I
    : 3A 20 if TXDREADY then next else repea                     I
    : 3A 69 if false then emitChar else emit                     I
    : 3A 1F if TXDREADY then next else repea                     =
    : 3A 21 if TXDSEND then return else retu                     =
    : 3A 1E emitChar: if TXDREADY then next                      3
    : 3A 20 if TXDREADY then next else repea                     3
    : 3A 6B if false then emitChar else emit                     3
    : 3A 1F if TXDREADY then next else repea                     A
    : 3A 21 if TXDSEND then return else retu                     A
    : 3A 1E emitChar: if TXDREADY then next
    : 3A 20 if TXDREADY then next else repea
    : 3A 6D if false then emitChar else emit
    : 3A 1F if TXDREADY then next else repea                     A
    : 3A 21 if TXDSEND then return else retu                     A
    : 3A 1E emitChar: if TXDREADY then next                      =
    : 3A 20 if TXDREADY then next else repea                     =
    : 3A 6F if false then printaddr else pri                     =
    : 3A 1E emitChar: if TXDREADY then next                      0
    : 3A 20 if TXDREADY then next else repea                     0
    : 3A 2A if false then emitChar else emit                     0
    : 3A 1F if TXDREADY then next else repea                     7
    : 3A 21 if TXDSEND then return else retu                     7
    : 3A 1E emitChar: if TXDREADY then next                      9
    : 3A 20 if TXDREADY then next else repea                     9
    : 3A 2C if false then emitChar else emit                     9
    : 3A 1F if TXDREADY then next else repea                     0
    : 3A 21 if TXDSEND then return else retu                     0
    : 3A 70 if false then emitChar else emit                     0
    : 3A 1F if TXDREADY then next else repea
    : 3A 21 if TXDSEND then return else retu
    : 3A 1E emitChar: if TXDREADY then next                      C
    : 3A 20 if TXDREADY then next else repea                     C
    : 3A 72 if false then emitChar else emit                     C
    : 3A 1F if TXDREADY then next else repea                     =
    : 3A 21 if TXDSEND then return else retu                     =
    : 3A 1E emitChar: if TXDREADY then next                      0
    : 3A 20 if TXDREADY then next else repea                     0
    : 3A 74 if false then emitChar else emit                     0
    : 3A 1F if TXDREADY then next else repea                     0
    : 3A 21 if TXDSEND then return else retu                     0
    : 3A 1E emitChar: if TXDREADY then next                      0
    : 3A 20 if TXDREADY then next else repea                     0
    : 3A 76 if false then emitChar else emit                     0
    : 3A 1F if TXDREADY then next else repea                     0
    : 3A 21 if TXDSEND then return else retu                     0
    : 3A 1E emitChar: if TXDREADY then next
    : 3A 20 if TXDREADY then next else repea
    : 3A 78 if false then emitChar else emit
    : 3A 1F if TXDREADY then next else repea                     B
    : 3A 21 if TXDSEND then return else retu                     B
    : 3A 1E emitChar: if TXDREADY then next                      =
    : 3A 20 if TXDREADY then next else repea                     =
    : 3A 7A if false then emitChar else emit                     =
    : 3A 1F if TXDREADY then next else repea                     3
    : 3A 21 if TXDSEND then return else retu                     3
    : 3A 1E emitChar: if TXDREADY...
    Read more »

  • From MUXs to BASIC - working on documentation

    06/14/2020 at 18:57 0 comments

    Found time to work on documentation! To exact surprise of nobody, creating good documentation is at least as hard as creating good software, if not more. One interesting aspect is that through the process of documentation, one has to revisit design decisions and if something sounds clunky or counter-intuitive to describe, then probaby it reall is, and should be improved!

  • Some progress on microcode compiler in C#

    04/28/2020 at 19:56 0 comments

    So after some time, I was able to find some time to work on the "MCC" (microcode compiler"). The compiler is now mostly written and is able to compile .mcc files (in a "language" I invented in order to make microcode writing simpler and more intuitive). 

    I plan to eventually create a separate project for it with more extensive documentation, but for now here is a excerpt from the microcode for CDP1802/5/6 CPU I use for validation, which should give some idea:

    //--------------------------------------------------------
    //	1802 basic instructions
    //--------------------------------------------------------
    			.map 0b0_0000_????;	// D <= M(R(N))
    LDN:		direction = mem2any, sel_reg = n, y_bus, reg_d <= alu_y,
    			if continue then fetch else dma_or_int;
    			
    			.map 0b0_0000_0000;	// override for LDN 0
    IDL:		sample;
    			// dead loop until DMA or INT detected
    			if continue then IDL else dma_or_int;
    
    			.map 0b0_0001_????;	// R(N) <= R(N) + 1
    INC:		sel_reg = n, reg_inc,
    			if continue then fetch else dma_or_int;
    
    			.map 0b0_0010_????;	// R(N) <= R(N) - 1
    DEC: 		sel_reg = n, reg_dec,
    			if continue then fetch else dma_or_int;
    
    			.map 0b0_0011_????;	// 2 byte branch instructions
    SBRANCH:	direction = mem2any, sel_reg = p, y_bus, reg_b <= alu_y,	// B <= R(P)
    			if cond_3X then sbranch2 else next;
    			
    skip1:		sel_reg = p, reg_inc,							// R(P) <= R(P) + 1 (no branch)
    			if continue then fetch else dma_or_int;
    			
    sbranch2:	sel_reg = p, reg_lo <= alu_y, y_b,
    			if continue then fetch else dma_or_int;
    
    			.map 0b0_0100_????;								// D <= M(R(N)), R(N) <= R(N) + 1
    LDA:		direction = mem2any, sel_reg = n, y_bus, reg_d <= alu_y,
    			goto INC;
    
    			.map 0b0_0101_????;								// M(R(N)) <= D;
    STR:		direction = cpu2mem, sel_reg = n, y_d,		
    			if continue then fetch else dma_or_int;
    
    			.map 0b0_0110_0???;
    OUT:		sel_reg = x, reg_inc, direction = mem2any,		// DEVICE <= M(R(X)), R(X) <= R(X) + 1
    			if continue then fetch else dma_or_int;
    
    			.map 0b0_0110_0000;	// override for OUT 0
    IRX: 		sel_reg = x, reg_inc,							// R(X) <= R(X) + 1
    			if continue then fetch else dma_or_int;
    
    			.map 0b0_0110_1???;
    INP:		sel_reg = x, y_bus, reg_d <= alu_y, direction = dev2any, 
    			if continue then fetch else dma_or_int;	

    The compiler produces 2 blocks of memory, one for the microcode, and one for the mapper that maps higher level instructions (from CPU instruction set). These blocks are then written in possible formats:

    - VDHL - for direct inclusion into FPGA development projects (I use old "free" ISE14.7 from Xilinx)

    - Intel HEX - pretty much any tool can consume these

    - MIF ("memory initialization file") for Altera tools

    - CGF ("core generator file") for Xilinx tools

    At this point I am writing / debugging the 1802 CPU which I intend to eventually test using the embedded software (monitor/Basic) documented here. Once it starts (somewhat) working, I will share that project too.