January 15, 2021

Xilinx Zynq - XC7Z010 - Numato "beginners guide"

These are my comments on the excellen tutorials published by Numato Labs. I began with the older ISE based tutorial, then on a careful second reading discovered the link to the newer Vivado based tutorial. This fellow does exactly what I have wished someone would do. He wrote his article in August of 2018, and by 2021 the world has moved along significantly.

A short digression about Xilinx tools is worthwhile here. ISE has been supplanted by Vivado. For older devices (like Virtex-6 and such) you use ISE. For something like the Zynq-7000 (a series 7 device) you must use Vivado. So for my Zynq-7000 it is Vivado or nothing. There is also SDSoC (software defined system on a chip), which seems to be an integrated approach to dealing with both the PS and PL on something like the Zynq-7000.

On these pages, I intend to ignore SDSoC and look entirely at Vivado. In fact my "simple" task is to translate the Numato beginners to Vivado and the Zynq-7000 insofar as that is possible.

Part 1

He chooses to use Verilog, which is fine (VHDL is the other choice, but I was planning to learn Verilog first anyway). He says that Verilog and VHDL are about equally popular in industry. He uses Vivado 2018.2 (given that he was writing in August of 2018). If you have a choice when you install it, install "Vivado Design Suite HLx Edition" so you get Synthesis and Implementation options. He suggests their Mimas A7 board with an Artix 7 chip (a $200 item) for hardware, but we are going to see if we can use our Zynq-7000 board.

RTL means "register transfer level" (or language) and is a higher level of abstraction than simply dealing with gates. RTL design is also called "dataflow" design. To follow his tutorial, we will need:

Part 2

This is a basic introduction to Verilog, nothing is specific to Vivado.
We write Verilog modules. We have "wire" and "reg" for signals.

Part 3

For reasons that are still mysterious to me, my first effort here failed and I have a mess of a project named "project_1" that I should delete and clean up. But the following worked perfectly the second time:

Now we are going to simulate our inverter. We create a Vivado project. I call it myModule as per his instructions. I select the part family as XA Zynq-7000, which I thought might avoid scrolling through thousands of parts, but mine is an xc7z010-clg400-1, and doesn't appear in that list, so I must scroll after all.

I add the file myModule.v as per his instructions to be a "NOT" gate (inverter). I notice the little floppy disk icon above the edit window saves the file, which is good. Smooth sailing so far (with Vivado 2020.2).

Now we add a second file as a simulation source file. This is myModule_tb.v as per his instructions, and it is found under "Simulation Sources", "sim_1". Now we do "Run simulation", "Run Behavioral Simulation" and away it goes.

The graph appears for a fraction of a second, but I can use "Layout, Simulation" to get it up so I can look at it. There are buttons to zoom + and - and an all important "zoom fit" that gives me what I want when I get the scale right.

And I get the waveforms I expect.

Apparently when I go to "open a project" I need to point to the xpr directory to actually open it once I navigate to it.

Part 4

Now we get to Synthesis, which is sort of analagous to compiling code. What he would like to do is to have his input driven by a switch (or button) and the output driving an LED. He downloads a comprehensive XDC file for his board, and then extracts the two lines that correspond to the button and LED he wants to use:
set_property -dict { PACKAGE_PIN "N17"  IOSTANDARD LVCMOS33 SLEW FAST} [get_ports { sw_in[3] }];  # IO_L21P_T3_DQS_14  Sch = SW3
set_property -dict { PACKAGE_PIN "M16"  IOSTANDARD LVCMOS33 SLEW FAST} [get_ports { LED[7] }];    # IO_L24N_T3_RS0_15  Sch = LED7
The trouble starts when he says, "The content of this file is pretty self-explanatory". When anyone says this, you know you are doomed. So take this as a black box and grasp just the following -- he substitutes A and B from the inverter verilog code into these two lines and gets the following:
set_property -dict { PACKAGE_PIN "N17" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports { A }]; # IO_L21P_T3_DQS_14 Sch = SW3
set_property -dict { PACKAGE_PIN "M16" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports { B }]; # IO_L24N_T3_RS0_15 Sch = LED7
Here is the bottom line up front -- this applies a number of properties to the ports A and B. In particular the PACKAGE_PIN property, which ties these Verilog ports to physical pins on the device. FPGA ports are versatile and you need to specify what voltage levels they work at and such.

The substitution of A and B is easy enough to understand -- the trick in my case is getting an XDC file for my hardware to use as a starting point. On my board, I have a pair of LED's that are wired to the FPGA (on pins W13 and W14). I don't have any handy buttons or switches though. What I would like to do is to use an EMIO signal that PS side software on the Zynq-7000 can manipulate, and route it to the LED via FPGA logic. This may or may not be possible or easy.

Here is my write-up on constraints:

Also, at the risk of running off on a tangent, Vivado has features that will help you generate constraints. Go to "RTL Analysis" on the left and click on "Open Elaborated Design". Then go to "Layout" on the top and select "I/O Planning". Now you can explore various pins to discover things about them.
See this link for details:

I gave up on the EMIO business for now. I kept looking around for an XDC file that would include specifications for the EMIO signals and never found it. I am developing a sneaking suspicion that the XDC file only pertains to signals routed off-chip and that the EMIO is handled in a different way entirely.

So I decided on the following design, which just sends constant value to the pins driving the LED's

module myModule(red, green);
        output wire red;
        output wire green;
        assign red = 0;
        assign green = 1;
endmodule
Along with this, I used the following XDC file:
set_property IOSTANDARD LVCMOS33 [get_ports {red}]
set_property IOSTANDARD LVCMOS33 [get_ports {green}]
set_property PACKAGE_PIN W13 [get_ports {red}]
set_property PACKAGE_PIN W14 [get_ports {green}]
And away I went with this.

So, where is the darn bitstream file? In my case, I found it in /home/tom/Vivado/myModule/myModule.runs/impl_1/myModule.bit

I copied this to bitstream_R0G1.bit and continued along.

I tweak the design (setting red to 1, green to 0) and then click "Run Synthesis", I hear lots of disk activity. When it is done I click "Run Implementation", again I hear lots of disk activity -- eventually I get a popup announcing "implementation successfully completed". Until I do this the "Generate bitstream is greyed out". The popup has a radio button asking what to do next, one selection is to generate bitstream, so I select it and click "OK". After quite a long while a popup announces "Bitstream Generation successfully completed".

The bitstream file is in exactly the same place as the previous run.
I copy this one to bitstream_R1G0.bit.

There are a variety of bitstream setting that you can fiddle with. Note that the Numato tutorial has you select a "bin" format, which yields files with a ".bin" extension.

Part 5

Here the tutorial begins talking about setting up the FPGA to be a microprocessor along with a variety of peripherals. The lingo is "IP" for (intellectual property?) the various blocks you can find ready made and splice together. This sort of thing is called a "soft processor". Xilinx offers two: picoblaze and microblaze. Manuals are available for each. ARM has even made two cores freely available for FPGA. Cortex-M1 and Cortex-M3. He goes through an example using Microblaze and the SDK.

Part 6

Here he talks about DDR interfacing from the FPGA
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org