The idea here is to generate a bitstream that will configure the FPGA so I can blink the four onboard super bright green LED from C code running on the PS side of the chip.
I could add a gpio to the block diagram and use it, but instead I would like to try something new and use the EMIO to control the LED. So I will have 4 EMIO signals getting routed to 4 ports. I will stick a small bit of verilog in that path, simply to split up the 4 signals. There doesn't seem to be an easy way to do that in Vivado. The EMIO comes out as a single group with 4 signals in it. There may be a way, but using verilog will get it done and I know how to do it.
I am running Vivado 2022.2. I type "vivado" at the command line to get it started. I go through the usual "new project wizard". I select a board rather than a part and I find "Antminer S9" thanks to the board files I just installed.
Now select "Create Block Design" under "integrator" on the left. It wants a name for the design and I go with the suggested "design_1". I use the "+" to add "ZYNQ7 Processing System". I double click on this to customize the block, A big GUI thing with lots of green appears.
On the right side under Navigator is MIO configuration.
Inside of this look for I/O Peripherals, expand this and look for GPIO, expand this.
Check the EMIO checkbox, select 4 as the width, click OK.
Now on the Zynq block, there appears a thing "GPIO_0" that was not there before.
/u1/Projects/Zynq/Git_antminer/board_files/S9_Master.xdcWe need to copy this into our project. Up and left from your block diagram is a window which typically has the "design" tab selected by default. Select "sources" instead and use the big "+". Select "add or create constraints", then go find the file. Once you have found and selected it, ensure that the checkbox to "copy constraint files into project" is selected, then "finish".
inputs - input bus 3:0 a - output b - output c - output d - outputThe input I select "bus" and set MSB = 3 and LSB = 0. Note that this exercise is just a helper, I could have done all this in verilog, gave it the file, and skipped this crazy dialog. Doing this will generate a verilog template we will have to flesh out. When this is all done the file will appear in the hierarchy being displayed.
Now to get a block on the diagram, find the file in the hierarchy under "sources", right click on the verilog file name and select "Add module to block design". The block should appear, mine does showing "inputs[3:0]"
Let's try creating the LED ports first. I can click on the background of the block diagram, get a menu, and select "create port". I create ports "led_A" and so forth, take care to make them outputs and then it is easy to connect them one by one to my RTL block. When I am done, I use the same menu to "regenerate layout" and it cleans up the mess.
As I dig deeper, I find that the problem is that the 4 bit wide EMIO I created is all inputs, and Vivado is sensibly refusing to connect inputs to inputs. How do I configure my EMIO "bus" as outputs?
I click on the text GPIO_0 on the Zynq block to select it, then on the menu I use "create interface port". This creates a port named "GPIO_0". I do the same thing on my RTL block, creating an interface port, but I change the name from inputs to GPIO_0 to match the other. This looks promising, but I'll be surprised if it works.
Somewhere along the line as I fuss with the mouse around the GPIO label on the Zynq block, a bunch of other things appear labeled GPIO_I, GPIO_O, GPIO_T -- perhaps input, output, and tri-state? Something is lurking here that deserves investigation.
I try to validate the design and it complains that M_AXI_GP0_ACLK is not connected to a valid clock source. Run block automation is not available. I have a theory of an indirect way to fix this. I add an AXI_GPIO block and then run block automation. The design now validates. Curiously the added AXI_GPIO block has its output routed to "leds_2bits" which are declared in the board files (and a useless legacy from the Ebaz board files)
The missing clock was obtained from a "rst_ps7_0_50M" block that got hauled in (along with ps7_0_axi_periph). The clock itself comes from "slowest_sync_clk" on the "rst" block.
Go to sources, find "design_1" under "Design Sources", right click to get a menu and select "create HDL wrapper". My notes say that if you come back to a design, add blocks, and want to redo this, you will need to use "refresh hierarchy" instead. Now follow the sequence: Generate block design Run synthesis Run implementation (skip "open implemented design" Generate bitstream Run the design
Each of these takes considerable time, and I can often hear my CPU fans crank up. Keep an eye on the upper right corner of Vivado where messages appear telling you what it is doing. Often you think a step is done, but it is not. In particular, watch for a spinning circle arrow to indicate that it is busy and things are in progress. You will see "Ready" when a step is all done. If you are watching the screen, a popup appears (for a few seconds) at the lower right of the screen telling you that steps have finished.This failed during "run implementation" and for a perfectly good reason that I understand. The block "led_mapper_0" just has stub verilog -- I never fleshed it out! I had expected some kind of complaints about my ports GPIO_0, but that seems OK.
Where is that verilog file?
I prefer to find it and edit it externally using vim. The "stub" looks like this. I add the four "assign" statments:module led_mapper( input [3:0] inputs, output a, output b, output c, output d ); assign a = inputs[0]; assign b = inputs[1]; assign c = inputs[2]; assign d = inputs[3]; endmoduleVivado doesn't seem to disagree with this, but now I get an error I have never seen before saying that there are 4 unplaced ports and no place can be found to place them. The ports are GPIO_0[0] through GPIO_0[3]. I am not entirely surprised, and don't intend to push this any further. I'll probably delete this whole project entirely and start over trying something else.Here is my idea why this didn't work -- these "ports" are not intended for connections within the diagram (like I tried to use them), but for connection to the outside world, however that may be defined. In my case it is connection to something specified in the constraint file. So I had 4 signals in, 4 signals out, all with the same name. Rather than connect them to each other, it saw that as a conflict as it was only willing to connect one or the other to the outside world. Maybe.
Where is the bitstream?
We don't have one for this project given that things failed, but if we had had success it would have been in a location like this:cp /home/tom/vivado/ebaz_blink_4/ebaz_blink_4.runs/impl_1/ledio_wrapper.bit ledio.bitAnother approach
This fellow configures EMIO, then gets it to set up an interface port. He doesn't try to connect that to any other blocks (like I did), but he fiddles with it to get the port to connect directly to an LED declared in his constraint file. His example has just one LED, but perhaps I can do the same and get my 4 bit wide port connected to four LED?
I read somewhere that it is possible to get a GPIO (an AXI gpio in the case mentioned) connected to multiple ports by hand editing a "wrapper file", This is something to explore and investigate.
The other approach is to ignore EMIO and instantiate AXI gpio as needed. This surely will work, but if this is what we must do, then why have EMIO at all? I suspect there are other approached, probably outside of Vivado, that can be used to exploit EMIO.
Tom's Computer Info / [email protected]