Micro16 - A Simple 16 Bit VHDL CPU

Micro16 is an extension or derivative of the Micro8 CPUs. Addressing modes have been reduced to extend the adressing range. Rather than supporting an index register the Micro16 uses indirect addressing. The Micro16 does not support byte addressing. addresses are word addresses. The idea of the Micro16 was to provide a very simple micro controller, originally intened as an I/O processor for a Compact Flash reader.

The Micro16 features:
  • 8 Instructions
  • Direct & Indirect Addressing
  • 4KWord Direct Addressing Range (Program & Data)
  • 64K Word Indirect Addressing Range (Data Only)
  • 8 Level Hardware Stack
  • 1 Interrupt Input
Bits 15 to 13 form the Opcode.
Bit 12 is the Indirect bit. If set the opcode reads / writes from the address pointed to by the address field.
Bits 11 to 0 form the Direct address. Stored Program code can only reside in the Direct Address Space.


ADD Add Accumulator
NOR Nor Accumulator
STO Store Accumulator
JSR Jump to Subroutine
JNZ Jump if Non Zero (Clears ZFlag)
JNC Jump if No Carry (Clears Carry Flag)
RTI Return From Interrupt
RTS Return From Subroutine


The Micro16 runs a simple monitor program called "umon16" that allows you to read and modify memory locations. The "M" key allows you to examine a 16 bit memory location. 64KWords may be accessed, but care should be taken to ensure that you only access valid memory, or the CPU will hang indefinitely, due to the wishbone handshaking protocol.

There is also a loader for the Smal32 macro assembler, but it has not been tested as yet. It will only load 64 Kbytes, even though the macro assembler is designed for 32 bit addressing. In the loader I simply ignore the top 16 bits of 32 bit addresses.

The instruction macros are included in the "micro16.inc" file.

Note the following work arounds:
1. The macro assembler is designed for 8 bit addressing where as I have used 16 bit addressing, so all the addresses along the side of the listing need to be divided by two. The correct code is generated, but the addresses are misleading.
2. The "SUB" macro actually Negates the accumulator and adds it to the memory location. this means it is actually Memory - Accumulator, however the condition codes are actually in reverse, because you are doing an ADD and not a true SUB in the macro.

Smal32.zip - Macro assembler

SMAL is a macro assembler By Douglas W. Jones of THE UNIVERSITY OF IOWA Department of Computer Science

Micro16-30sep03.zip - Integrates the latest version of umon16

No major changes here .... except the iocs16 signal is an output from the CF, not an input. I have removed it. I have used 4 Block RAMs for ROM to cater for the increased size, and relocated the RAM. Also, I am now using WebPack ISE 6.1i.

#0000 - #00FF Rom0
#0100 - #01FF Rom1
#0200 - #02FF Rom2
#0300 - #03FF  Rom3
#0D00 - #0DFF RamD (can be used for compact flash sector buffer)
#0E00 - #0EFF RamE (Monitor variables)
#0FE0 - #0FEF Compact Flash
#0FF0 - #0FFF MiniUart

uMon16-30sep03.zip - Extra Comands

I've added a number of extra commands:

M - Memory examine and modify
L - Load smal binary (not tested)
D - Dump memory
R - Read sector (not working 100%)
W - Write sector (not working 100%)
I - Initialise / reset Compact Flash

Be careful not to access undecoded memory as the CPU will hang because there is no decode acknowledgement. Note that the addresses used by umon are WORD addresses, not the BYTE addresses used in the smal macro assembler.

To generate ROMs using EPDIT:

compile and run epedit.c, at the prompt enter the following commands
type o
load umon16.o
type w
save rom0.xxx 0 1ff
save rom1.xxx 200 3ff
save rom3.xxx 400 5ff
save rom4.xxx 600 7ff

This will produce the initialization block for 4 x 16 bit Block ROMs that must be manually inserted into the ROM VHDL code. Note that the addresses are BYTE Addresses, and not WORD addresses

30 September 2006

I had an enquiry today about porting this design to other FPGA platforms namely the XESS XSB-300E. The thing to note is that SysClk has been set up for 4.9152 MHz. The baud rate divisor in the UART for the RX sample clock defaults to 128. The TX baud rate is one quarter of this 4.915200/128/4 = 9600 Baud. I am not sure what the maximum clock rate is for Micro16 but if you use SysClk = 25 MHz and 115200 Baud then you need to set BRDIVISOR = 25,000,000/115,200/4 = approx 54. I have not tested this so you may need to experiment a bit.

16th April 2008


Micro16b replaces the hardware stack with a memory stack. The stack pointer is 8 bits and works down from word address #00FF. There are no provisions for modifying the stack pointer, so all subroutine must be exited with a return from subroutine instruction (RTS).

I have added 3 interrupt inputs. These are prioritised so that the highest interrupt masks lower interrupt. The interrupts should push the return address, the accumulator and the condition codes onto the stack. The return from interrupt instruction (RTI) should pull these registers off the stack. Interrupts have not been tested yet.

I have parameterised the address and data bus widths, although in practice the data bus width is determined by the block ram and the address width can be scaled from 9 bits to 16 bits. I have set the address width to 10 bits in this design to save space. The design uses 3 4Kbit block RAMs, because this is all that is available on the Pluto board.  One block RAM is used for  RAM and Stack in page 0 and two Block RAMs are used for the monitor ROM in pages 2 and 3. The design has been implemented on a 200K gate Spartan 3 starter board so the ROMs can be upgraded to 16K Bits. It has not been determined though if this design will fit in the ACEX1K10 used on the smallest Pluto board. 

#0000 -  #00FF - Page 0 - Ram (stack works down from #00FF)
#0100 - #01FF - Page 1 - I/O Space
    #0100 - UART Data register
    #0101 - UART Status register
    #0102 -I/O Port Data register
    #0103 - I/O Port Data Direction register
    #0104 - Timer Counter register
    #0105 - Timer Control / Status register
    #0106 - #01FF - Not used - Access will hang the CPU
#0200 - #02FF Page 2 - ROM
#0300 - #03FF Page 3 - ROM
    #03FC - IRQ3 Vector
    #03FD - IRQ2 Vector
    #03FE - IRQ1 Vector
    #03FF - RESET Vector

The directory structure in the zip folder stores the program source files in the "src" folder, the VHDL designs in"rtl", and the utilities in "bin". The "src" folder include folders for "u16test" used in the test bench, "u16mon" a stripped down monitor program with Memory modify, dump and jump to commands and "u16load" which is an untested loader for smal32.  

        lib - Common library macros
        u16test - Test code for test bench ROMs
        u16mon - striped down monitor program
        u16load - Smal32 loader (untested)
        Spartan2 - 4K bit roms
        Micro16_Digilent_3S200 - top level project files
        Testbench - Test Bench code
        VHDL - vhdl library files
    bin - assembler (smal) and ROM formatter (epedit)

Back to FPGA Page