EmbDev.net

ZPU: Softcore implementation on a Spartan-3 FPGA

Contents

[edit] Description

This project describes the implementation of an opensource softcore CPU on the FPGA board Spartan-3 of Xilinx and the connection of peripheral devices using their bus interface.

Article in german: http://www.mikrocontroller.net/articles/ZPU:_Softcore_Implementierung_auf_Spartan-3_FPGA

Forum discussion in german: http://www.mikrocontroller.net/topic/212445


[edit] Features

Project:

  • VHDL
  • Development environment: Xilinx ISE WebPack 10.1

CPU:

  • ZPU of Øyvind Harboe (opencores.org)
  • stack based
  • 32 Bit
  • 8 Bit opcode
  • small, easy to use, clearly represented
  • programmable in C / C++ using GCC-Toolchain (ZPUGCC)
  • integrated program memory (BlockRAM)

Bus:

  • Wishbone-Bus
  • 32 Bit

Peripheral devices:

  • Interrupt-Controller
  • UART (8N1)
  • SRAM
  • VGA
  • PS/2
  • Onboard-I/Os


[edit] Introduction

For the project I had the experimental board Spartan-3 of Xilinx. This is a beginner board (see figure 1) with a XC3S200 FPGA (1). Actually it is not the best one for using a softcore processor with peripheral devices because of its less BlockRAMs (12 pieces, is equivalent to 24 KB).

The most important components for the project are: a PS/2 interface (2), a VGA interface (3), a RS232 interface (4), 8 switches (5), 8 LEDs (6), 4 buttons (7) and 4 seven-segment-panels (8) and the SRAM on the back side of the board. The board resp. the FPGA can be programmed with a JTAG adapter. A suitable software, the Xilinx development environment, can be downloaded for free on the page of Xilinx. For this project the version 10.1 has been used.

For the project a free softcore CPU has been chosen, the ZPU of Øyvind Harboe. It is a small stack based 32 bit CPU with a 8 bit opcode. It has a simple and clear structure and because of that optimally suitable for the intended diversifications. The opensource softcore CPU is created as a VHDL project. Very useful is the possibility to assemble software, that is written in C or C++, with a special GCC-Toolchain (ZPUGCC) into machine code that can be interpreted directly by the ZPU. That means the ZPU can be controlled by using programs written in C. For this project the small version of the ZPU has been used.


The following article is a tutorial for all those who want to implement the ZPU on a FPGA.

The tutorial contains the following steps:

  • Download of all source codes and documentations
  • Creating a project in the development environment Xilinx ISE
  • Implementation of the softcore CPU on the FPGA
  • Implementation of suitable peripheral devices and their connection to the CPU by using their bus interfaces
  • Creating an executable program to proof the functionality of the whole system

Apart from the project there exists a detailed documentation (only in german available) that can be downloaded together with the project.


[edit] General

[edit] Structure and functional principle of the ZPU

The ZPU works like a state machine that runs mainly through the phases fetch (get command), decode (decode command) and execute (execute command):

  • Fetch: In this state the ZPU loads a complete 32 bit value from the program memory by using the program counter. There for the 32 bit value is addressed by the upper 30 bits of the program counter. Note, that the program counter has a width of 32 bit but the actual address width of the program memory depends on its size (see below). That means that perhaps the entire width of the program counter can not be used.
  • Decode: The last two bits of the program counter are used to select the 8 bit opcode from the 32 bit value of the program memory. That 8 bit will be decoded. So finally the progam counter addresses always 8 bit.
  • Execute: In the execution cycle the ZPU jumps in to different states dependent on the decoded opcode to execute the instructions. Furthermore the program counter is incremented by 1.

The Fetch state is followed by a Fetch-Next state. That means at least 4 clocks are necessary to execute a single command. The board frequency of 50 MHz implies that the maximum working frequency is 12.5 MHz.

The ZPU has a BlockRAM unit that is used as a 32 bit program memory. In this case it is used as a dual port RAM. That means both ports can be used to read or write from or to the same address at the same time. But not writing from both ports to the same address at the same time. Furthermore the RAM contains the stack. Currently the memory has a size of 16 KB.

In the VHDL source code the structure of the ZPU is an entity that integrates the ZPU core and provides outwards a wishbone interface. The entity of the ZPU core implements the dual port RAM.

[edit] Wishbone-Bus

The Wishbone bus is an opensource hardware computer bus. Via it the different units of an integrated circuit can communicate which each other. It is a logical bus, what means that it does not define the electrical informations. Instead the specifications defines signals, clock cycles and high- and low levels. This makes it easy to use it in VHDL. All signals are hereby synchronous to the clock.

For this project a 32 bit version of the wishbone bus is used (32 bit address bus width and 32 bit data bus width). As topology the shared bus is used, that means all devices are connected to the same address and data bus and there is only one master existing (the ZPU). When using more than one slave, the current slave is selected by the address from the address bus. All peripheral devices are slaves in this project. An example for a connection between the master and a slave is shown in figure 2. The unit SysCon contains the clock generation and a connection to the reset button. The explanation of the signals is shown in table 1. Examples for a Whishbone output interface and a Whisbone input interface are shown in figure 3 and 4. In this project the interfaces described at the beginning of this article has been implemented.

On www.opencores.org are a lot of free peripheral devices with a Wishbone interface offered to download them. The interfaces has mostly to be adjusted. It makes sense to use a device that is already working, what means it has been tested in an own project. This is due to exclude failures coming from the device when connecting it to the Wishbone bus.

[edit] Download

Download project and documentation: File:ZPU Softcore Implementierung auf Spartan-3 FPGA.zip


[edit] Start-up of the board and the development environment

1. Connect the board:

To use the board the supplied power supply and the JTAG programming cable has to be connected to the board (regard the polarity of the cables!).

2. Install the development environment:

Download Xilinx ISE WebPack 10.1 from http://www.xilinx.com/support/download/index.htm
A free registration at Xilinx is neccessary. After the download unpack the file and install it. Then registrate the product to use it.

3. Create first example project for the board in VHDL:

  • Start the Project Navigator in the Xilinx ISE Design Suite 10.1 from the start menu
  • Create a new project (menu File > New Project). In the following dialog box choose a project name and directory and select HDL as Top-level source. Please: no file names and paths with special characters (like space)! Click on Next. Now the FPGA has to be chosen. The following figure shows the data for the Spartan-3 Board.
  • Click on Next resp. Finish until the dialog box is closed. In the window on the left (Sources) the project is shown now. There will be only the FPGA added to the project. By doing a right click on the project and click on New Source a new VHDL module can be added. In the now opened dialog box select VHDL Module and choose a file name. Furthermore activate the Add to project. Then click on Next.
  • In the following window the input and output signals of the Entity can be set, this Entity is contained in the VHDL module. For this example you can see the configuration in the following figure.
  • Then click on Next resp. Finish until the dialog box is closed. In the window Sources now you have got the just created VHDL module. Open it with a double click. The empty Entity should look like this (except the individual name, here called test):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity test is
    Port ( clk, reset : in  STD_LOGIC;
           led : out  STD_LOGIC_VECTOR (7 downto 0));
end test;
 
architecture Behavioral of test is
 
begin
 
end Behavioral;
  • As an example we implement a moving light that controls the 8 LEDs on the board. For this the architecture has to be changed like shown below:
architecture Behavioral of test is
signal r_reg, r_next: unsigned (31 downto 0);
signal led_reg, led_next: unsigned (7 downto 0);
signal timer_reg, timer_next: unsigned (7 downto 0);
begin
 
process (clk,reset)
begin
	if (reset = '1') then
		r_reg <= (others => '0');
		led_reg <= "00000001";
		timer_reg <= (others => '0');		
	elsif rising_edge(clk) then
		r_reg <= r_next;
		led_reg <= led_next;
		timer_reg <= timer_next;
	end if;	
end process;
 
process (r_reg, led_reg, timer_reg)
begin
r_next <= r_reg;
led_next <= led_reg;
timer_next <= timer_reg;
 
if (r_reg >= 25000000) then
	if (timer_reg < 7) then
		led_next <= led_reg(6 downto 0) & led_reg(7);
		timer_next <= timer_reg + 1;
	else
		led_next <= led_reg(0) & led_reg(7 downto 1);
		if (timer_reg = 13) then
			timer_next <= (others => '0');
		else
			timer_next <= timer_reg + 1;
		end if;
	end if;
	
	r_next <= (others => '0');
else
	r_next <= r_reg + 1;
	timer_next <= timer_reg;
end if;
 
end process;
 
led <= std_logic_vector(led_reg);
 
end Behavioral;
  • After saving the VHDL module, select it in the window Sources and then in the window Processes below do the Check Syntax by doing a double click on it (it is located under Synthesis - XST). It should be successful (a green hook is shown). If not, check the content of the VHDL module again.
  • The ports used in the Entity has to be connected to the pins of the FPGA. To do that a Constraints File is needed. It can be added via New Source. This time you select Implementation Constraints File, enter a file name and tick the Add to project. Again click on Next resp. Finish until the dialog box is closed. Now there is a plus in front of the VHDL module in the window Sources. If you click on it, the next level is opened, in this case it is the Constraints File. Select it and in the windows Processes click on the plus in front of User Constraints. The next level is opened with Edit Constraints (Text). Do a double click on it to edit the Constraints File. Enter the following code:
#========================================================
#    Pin assignment for Xilinx 
#    Spartan-3 Starter board
#========================================================
 
#========================================================
# clock and reset signals
#========================================================
NET "clk"    LOC = "T9";
NET "reset"  LOC = "L14";
 
#========================================================
# 8 LEDs on the board
#========================================================
NET "led<0>"  LOC = "K12";
NET "led<1>"  LOC = "P14";
NET "led<2>"  LOC = "L12";
NET "led<3>"  LOC = "N14";
NET "led<4>"  LOC = "P13";
NET "led<5>"  LOC = "N12";
NET "led<6>"  LOC = "P12";
NET "led<7>"  LOC = "P11";
 
#========================================================
# Timing constraint of S3 50-MHz onboard oscillator
# name of the clock signal is clk
#========================================================
NET "clk" TNM_NET = "clk";
TIMESPEC "TS_clk" = PERIOD "clk" 20 ns HIGH 50 %;
  • Select again the VHDL module in the window Sources and do a double click on Generate Programming File in the window Processes. Now the complete project will by synthesized by Xilinx (it will do the steps Synthesize - XST and Implement Design before automatically). Behind all three a green hook should be shown afterwards.
  • Now we have to load the project on to the FPGA. Do a double click on Configure Target Device, a connection is established to the board using the JTAG adapter. Ignore the warnings of the program iMPACT by clicking on OK. In the following dialog box select Configure devices using Boundary-Scan (JTAG) and click on Finish. Now the FPGA board will be found automatically. In the main window the Boundary Scan will be opened with 2 elements. The left one is the FPGA, the right one the ConfigurationFLASH (not needed). A dialog box should be opened automatically that wants to know where the Configuration Files (.bit files) for the two elements are. The dialog box can be opened as well by doing a double click on the elements. The FPGA (xc3s200) gets the .bit file from the main directory of the project. The other element has to be selected as Bypass. In the next dialog box make sure that Verify is NOT ticked and then click on OK. Now do a right click on the FPGA and click on Program to load the project on to the FPGA. The LEDs on the board should show flash now, from left to right and back.

[edit] Overview of the VHDL project

The overview of the project structure is shown in the figure below:

File:Vhdl_projekt_uebersicht.png

As shown above the top of the tree, the top module, is the file softcore_top.vhd. It combines all the neccessary external signals of the board using io_pins.ucf with the moduls. The top module contains the Wishbone bus and the connections of the slaves. The definition of the address range is also located in this file.

Using softcore_top.vhd all neccessary Wishbone interfaces are included, starting with the ZPU that is configured as the Wishbone master followed by an interrupt controller, a UART, a PS/2 (keyboard) interface, a SRAM controller, a VGA interface and a controller for the onboard LEDs, switches, buttons and seven-segment displays.

The file wb_core.vhd contains a Wishbone interface for the ZPU and switches the address, data and control signals to wishbone compliant signals. The ZPU is coded in zpu_core.vhd and contains its state machine, the memory controller and the opcode interpretation and the access to external peripherals via the Wishbone interface. The ZPU file includes the BRAM (file zpu_bram.vhd and softcore.bmm) that is used as program memory and stack.

All files of the project ending with _pkg.vhd contain the declaration of constants and definition of components. The file zpu_pkg.vhd contains the opcode definition of the ZPU.

The files ending with _config.vhd contain the global constants. In softcore_config.vhd e.g. the CPU clock frequency and the baudrate of the UART can be set. In zpu_config.vhd the address width can be set as well as the data width, the stack size and the program memory size.

Die Datei interrupt.vhd enthält den Interrupt-Controller und sein Wishbone-Interface. Zusätz-lich zu den Wishbone-Signalen hat er Eingänge für die Interrupts anderer Peripherie-Geräte und einen Ausgang, um den Interrupt der ZPU zu setzen. Wenn über letzteren der ZPU ein Interrupt mitgeteilt wird und diese ihn annimmt (bzw. Interrupt aktiviert hat), sendet der Controller ihr die Interruptnummer. Per Software kann der ZPU mitgeteilt werden, was bei Auftreten eines Interrupt mit diesem gemacht werden soll. Dies bedeutet auch, dass der Soft-ware-Programmierer wissen muss, welche Interruptnummer welchem Peripherie-Gerät zuge-ordnet ist.

The file uart.vhd contains the Wishbone interface of the UART. The files below are the modules for sending (tx_unit.vhd) and receiving (rx_unit.vhd). Both have a shared timer module (brgen.vhd) that is a clock divider. These two modules are used to check cyclically the UART for received data and to send synchronously. The timer values are calculated for these actions by using the baudrate (defined in softcore_config.vhd). Received data cause an interrupt that is notified to the interrupt controller. The moduls for sending and receiving are simple 8N1 moduls downloaded from www.opencores.org. The file ps2.vhd contains a very simple PS/2 interface with a Wishbone interface. The clock signal of the keyboard is retrieved and than the 10 bit telegram read. An interrupt notifies that data are available.

to be continued soon....

[edit] Peripheral devices

to be continued soon...

[edit] Integrated peripherals

to be continued soon...

[edit] Adding new peripherals

to be continued soon...


[edit] Programing the ZPU

to be continued soon...


[edit] References, links, sources...

http://en.wikipedia.org/wiki/Wishbone_%28computer_bus%29
http://kujo.cs.pitt.edu/index.php/Wishbone_Interconnect
http://www.armadeus.com/wiki/index.php?title=A_simple_design_with_Wishbone_bus
  • Further sources see documentation
webmaster@embdev.netContactAdvertising on EmbDev.net