• In-circuit testing using Intel HEX file components

    12/04/2021 at 19:47 0 comments

    Some background...

    The main purpose of my Intel HEX project was to:


    Turns out, with some breadboards, wiring, and bringing the Intel HEX component buses outside from FPGA into the physical world, the same components can be reused for a custom and handy testing tool.

    This testing allows to check:

    • Address, data, some control (R/W) buses
    • (EP)ROM/RAM if populated (for expected content or read / write / re-read)
    • Address decode logic (e.g. mapping of ROM/RAM, repeats due to partial decode etc.)

    Note that boards / computers tested this way do not need to be populated fully with ICs or other components, so it is possible to check "dead" or "not yet alive" boards too.

    There are two possibilities:

    • CPU is not on the board, "insert" the wires into CPU socket (poor man's in-circuit emulator)
    • CPU is on the board, but there is bus access that allows DMA takeover (e.g. BUSREQ/BUSACK in Z80-type buses)

    What cannot be readily tested using this approach:

    • Non-memory oriented bus signals (e.g. clocks, interrupts etc.)
    • I/O (memory mapped) - there can be indication that it "kinda works" as those spaces will be read as whatever default the I/O device returns, and in case of write in some simple case (e.g. write latch connected to some LEDs or relays) it may work.
    • I/O (separate) - with extra signal I/O space can be "forced" to appear as memory space and then it can be figured out if the data returned makes sense or not (example given below)

    Hardware

    For this project I used a cool little 8085-based single board computer (8085 Minimax) described and graciously provided to me by Ken Yap (thanks again!). I was actually in the process of soldering together the board, and decided to use a verification step before plugging in my vintage Soviet CPU to see if there will even be a chance for it working or not...

     The hardware setup is simple but a bit messy affair:

    Few notes:

    • 8085 IO/M signal (purple wire) is simply switchable to IO (high) to M(emory) (low) using a micro-DIP on the FPGA board. The HEX I/O has no idea about it, it just sees IO space as another 64k address map space (of course with 256 repetitions because typically in 8080-family systems upper 8 address lines are not decoded (Z80 introduced 16-bit IO to some degree, and then HD64180 has a full 64k IO address map)
    • 8085 has multiplexed lower address A7..A0 with data bus D7..D0, giving AD7..AD0 bus. Typically a 8-bit latch (like 74x573) enabled by ALE captures the low address early in memory access cycle. To simplify, I left this IC unpopulated on the board and connected the low memory address wires (gray) directly to its output socket pins.
    • Minimax 8085 of course takes +5V DC - I am sourcing its modest consumption (esp. because the power hungry NMOS CPU is not there!) with a 3.3V to 5V step-up regulator
    • Connecting nominal 3.3V (FPGA) to nominal 5.0V (SBC) is a "circuit crime". But I could get away with it in this case as the modern RAM / ROM used has max "0" voltage and min "1" voltage signals that are within margins.
    • 4 additional PMOD signals are used for UART - this is how the Intel HEX files are uploaded/download during runtime.  

    This is how these connections look in VHDL (top file of the project):

                    --PMOD interface
                    JA1: inout std_logic;    -- Connected to USB2UART
                    JA2: inout std_logic;    -- Connected to USB2UART
                    JA3: inout std_logic;    -- Connected to USB2UART
                    JA4: inout std_logic;    -- Connected to USB2UART
                    JB1: out std_logic;    -- GRAY 74F573.19 A0
                    JB2: out std_logic;    -- GRAY 74F573.18 A1
                    JB3: out std_logic;    -- GRAY 74F573.17 A2
                    JB4: out std_logic;    -- GRAY 74F573.16 A3
                    JB7: out std_logic;    -- GRAY 74F573.15 A4
                    JB8: out std_logic;    -- GRAY 74F573.14 A5
     JB9: out...
    Read more »

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