• Writing a Z80 disassembler using AI

    03/30/2025 at 04:38 0 comments

    Note: This project is in progress. Code and app described below may differ from what you may see. At this point I am more interested in learning how to best communicate the intent of desired code changes to the AI tool, than in the actual fully-fledged disassembler functionality.

    TL;DR

    I estimate that writing the same tool (simple web-based disassembler) without AI would have taken me at least 10X time. Most of that time would have been spent writing the boilerplate, and looking for and integrating right UX components, both of which are mostly overhead and for hobby programmers often pressed for time distract from the "fun parts" of the project. Quality of the code generated is good but depends on the clarity and sequence of prompts given to the tool. In other words - good general software design skills of the "AI developer" and knowledge of the limitations and capabilities of the tool used are crucial to get best results.

    Background

    To catch up with the times, I started tinkering with some AI-based code generation tools, and was curious how well they would do in a retro-computing setting. Combining old and new usually leads to fun, unexpected learn experiences. Writing a disassembler came up as an idea, due to:

    • moderate complexity, even a simple implementation can be useful (esp. for more exotic and/or home-brew processors which have less tools available)
    • quality of the generated output can be easily evaluated if using a binary which we know the source code (I used Tiny Basic for Intel 8080 described here)
    • canonical implementation of disassembler is through lookup tables and/or switch cases with complexity added due to instruction sizes, mnemonic variations, reference (e.g. relative and absolute jump target) resolution etc. Therefore, viewing the "design" choices AI tool makes (or not) to adhere to these patterns gives interesting insights into code generation process and choices. Fancier disassemblers also recognize ASCII sequences, various programming tricks (e.g. BIT instruction trick for 6502), special locations / vectors (like RST for 8080 and derivatives) etc. 

    There are many AI tools currently available for assisting software development, and the eco-system is rapidly evolving. Use of one over the other may become a question of preference, price, and specific usage niche. I used Loveable and found it a very good tool due to:

    • "sandbox" integration - app is instantly viewable and code too (this facilitates fast round-trip)
    • good github integration
    • interaction which provides "echo" explaining what the tool is actually attempting to do, with a link to code changes
    • simple publishing of single-page React-based web app (with possibility of publishing to own domain if available)
    • specific "knowledge" can be provided for the project (although I could not evaluate to which extent it was used)

    On the downside, the daily limitation of free use was enforced a bit too harshly - to the point that code generated was simply cut leaving it in a broken state until upgraded to paid offering, or new daily "quota" was issued. Eventually this trick worked as I was sufficiently impressed with the tool to purchase a subscription. 

    The disassembler

    • Link to source code (I deliberately refrained from any "human" touch-ups, all changes are made by the lovable-dev[bot])
    • Link to working app

    Features:

    • Required input:
      • binary file (.bin extension) which is a sequence of bytes one would typically use to burn into an EPROM, or dump code memory etc. For test purposes, I used the "Tiny Basic" binary (same code for which I have written a CPU and "single-board computer" in VHDL)
    • Optional inputs:
      • offset address added to the binary byte counter / pointer (e.g. if you have a binary which is supposed to work from address != 0000 - remember code for Intel 8080 and its derivatives is not relocatable)
      • Targeted CPU instruction set (Z80, Intel 8080, 8085)
      • Output format (.lst shows...
    Read more »

  • Some great computer-builder resources

    06/17/2023 at 18:37 0 comments

    PDP-11 compatible

    Really impressive work reverse engineering and re-building using modern HDL tooling of computer build from Am2901-compatible bit slices.

    https://github.com/1801BM1/cpu11/tree/master/am4

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