System description

A project log for Iskra EMZ1001A - a virtual resurrection

4-bits wonder to print "Hello World!" and to calculate Fibonacci numbers to 13 decimal digits!

zpekiczpekic 12/12/2022 at 05:380 Comments

In order to thoroughly test the EMZ1001A implementation, and to make a fun, demo-able system that is "doing something", a small "computer" has been created on the FPGA board, with various components supporting the microcontroller operation. 

Basic features are:

The system components are coded in sys_emz1001.vhd which is also the top level source file of the design:

Somewhat simplified schema of main components (bolded names can be found in the code):


Mercury board has a USR_BTN which can be conveniently used as master reset. This is a positive logic signal, and is used as such by most components, except by the mc which has a negative active /POR (power on reset) signal.


Unlike many microcomputer designs which can get away with few clocks (e.g. classic Z80 with 4MHz XTAL and a 74LS04s to create a workable oscillator) this one uses many, all derived from internal Mercury FPGA 50MHz clock signal and generated by the clockgen.vhd component. Main are:

db_btn, db_sw

12 debouncers are programmatically generated during build time and hooked up to 8 switches and 4 buttons on Mercury baseboard. The debouncer.vhd is a glorified 8-bit shift register clocked by debounce_clk which "votes" the output based if all stages are in same state, and if not, keeps existing state. It is a very simple digital signal filter.

-- Switches on baseboard
-- SW(0) -- BAUDRATE SEL 0
-- SW(1) -- BAUDRATE SEL 1
-- SW(2) -- BAUDRATE SEL 2
-- SW(4) -- CPUCLK SEL 0
-- SW(5) -- CPUCLK SEL 1
-- SW(6) -- CPUCLK SEL 2
-- SW(7) -- OFF: STOP, ON: RUN

SW: in std_logic_vector(7 downto 0); 

-- Push buttons on baseboard
-- BTN0 - single step (effective if SW(6 downto 4)) = "000"
-- BTN1 - not used
-- BTN2 - not used
-- BTN3 - not used

BTN: in std_logic_vector(3 downto 0); 

 For example: 

All switches off: 600 baud, external ROM (Fibonacci), CPU single step (using BTN0), stopped

All switches on: 57600 baud, internal ROM (Hello World), 6.25MHz CPU, running


Simple 1k*8 ROM is mapped as lowest 1k out of 8 possible banks as "external ROM" and is holding the Fibonacci code. Same rom1k.vhd component is also used to define the "internal ROM" which lives inside the EMZ1001A, also in the first 1k memory bank.

Contents of ROM is initialized during build time, by loading the Intel .HEX file produced by microcode compiler (see "recreating a simple assembler"). This is done by invoking a function which returns a byte array of 1024 elements, defined in the emz1001_package.vhd file. 


This is the "parallel to serial" half of a full UART - I use it often in projects to transmit to host PC, using USB to PMOD connector. It is hard-coded to 8 bits, 1 stop, no parity, but the baudrate can be selected using switches 2, 1, 0. Implementation-wise, it is a glorified 16 to 1 MUX. It also generated "ready" signal (low when transmit is in progress) which is fed to EMZ1001A input pin (I0) to check if it is ok to transmit next character. 


Allows display of output ASCII stream and debug data (CPU internals) onto a text based VGA (640*480 == 80*60 characters). It is an aggregate of following components:


VGA controller generates character rows and columns - when these are within certain limits (see lines 390+) VGA input character no longer comes from video RAM, but from external source which is defined by the mask. Mask is 16*16, so first the offset into the mask is determined (from 0, 0 to 15, 15) and character code at that location is read. If is it printable ASCII code (32-128), then it is used directly, but if in range of 0-31, it is interpreted as driving a series of multiplexors that will select a 4-bit data from variety of sources (e.g. CPU memory or registers), convert 4-bit to ASCII character using 2 possible lookup tables, and feed that character to VGA. The end result is a "hardware window" of 16*16 size, "floating" above the rest of screen. Bit 7 (MSB) in the mask character is interpreted as "inverse" so it bypasses the MUXs and lookups and directly goes to VGA (see chargen explanation above)

(state of CPU stopped after generating 17th Fibonacci number displayed on VGA)


Finally, the microcontroller! Internals are explained elsewhere, for the system purpose it is interesting to see its connections:

(banks 0 and 1 of internal RAM contain bit patterns to used by DISB to show "letters" on 7-seg display 

LED_SPACE:    .alias 0b00000000;    // LED segment patterns
LED_H:        .alias 0b00110111;    // H
LED_E:        .alias 0b01001111;    // E
LED_L:        .alias 0b00001110;    // L
LED_O:        .alias 0b00011101;    // o
LED_W:        .alias 0b00111111;    // close enough
LED_R:        .alias 0b00000101;    // r
LED_D:        .alias 0b00111101;    // d
LED_EXCL:    .alias 0b10110000;    // ! (note decimal point is on)
OUT_READY:    .alias 1;            // mask for I inputs