• 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.