These posts describe the process I’ve followed to build an AFU (Accelerator Function Unit) for use in CAPI development. I’ve only been tinkering with RTL design for a few weeks, so this may not be the ideal design flow but it has worked for me so far!
Tools and Setup
My development setup basically follows what I described in my Tinkering wtih CAPI post, though I have switched to using the Gnome window manager as some software I was using didn’t have as good support for XFCE. Additionally, my 30 day evaluation for Quartus Prime was close to expiring so I’m now using the free Lite Edition.
Since I’ve started this digital adventure I’ve come to appreciate some of the nice features SystemVerilog adds to the design flow. As a developer more familiar with userspace programming, the addition of packages, enums, structures and type-definitions are very attractive and I cannot resist using them! I have found that not all design software supports all SystemVerilog semantics but I will use as much as I can get away with because they are very handy.
The design I will go through is something I’ve already put together and is available on Github. I will pull in some files from this repo when they are handy, but step through my process as if this were an external resource and find some areas for improvement along the way.
Parity Generator AFU
The overall goal of this AFU is to practice making a fully-functioning AFU that is paired up with a client application that utilizes it. The goal is to take two memory buffers in an application and generate parity for those buffers using XOR. We’ll start with a nearly clean slate and build our way up to this goal.
Getting the Project Started
As with the Tinkering wtih CAPI post, I start by creating a new empty project using
top as the top-level design entry; this time I will name my project and it’s folder
Next, I copy top.v from the PSLSE project into the root directory of my project.
Additionally, I will pull in some helper files from my
capi-parity example project. I wrote capi.sv to organize and simplify some of the interfaces the PSL exposes to the AFU and afu.sv to map signals to that abstraction for use in SystemVerilog.
These files don’t get automatically imported into the project, so I’ll add them via
Add/Remove Files in Project. The
Add All button in this window picks up all the Verilog and SystemVerilog in the project directory.
At this point I tried to synthesize the project, and got the error
Node instance "svAFU" instantiates undefined entity "parity_afu". since my
afu.sv references a module that does not exist yet.
You can use
New to create a new SystemVerilog design file. In this file, I import my CAPI package and define the input and output ports for the module. The only functionality is a debug message to notify me of the rising clock edge.
import CAPI::*; module parity_afu ( input clock, output timebase_request, output parity_enabled, input JobInterfaceInput job_in, output JobInterfaceOutput job_out, input CommandInterfaceInput command_in, output CommandInterfaceOutput command_out, input BufferInterfaceInput buffer_in, output BufferInterfaceOutput buffer_out, input ResponseInterface response, input MMIOInterfaceInput mmio_in, output MMIOInterfaceOutput mmio_out); always_ff @(posedge clock) begin $display("Clock edge!"); end endmodule
Again I try to synthesize the project, this time getting a smattering of messages along the lines of
Port "buffer_in" does not exist in the macrofunction "svAFU". I suppose Quartus Prime does not like that I’m not yet using these inputs, so I opened the
afu.sv file and commented out the ports that are defined but unused structures, it doesn’t seem to be as picky about the inputs and outputs that are not structures.
At this stage is have a useless AFU that will at least synthesize, I prepare my project for version control and push my initial commit to github.
Tip: I find it inconvenient that I need to edit the
simulation/modelsim/modelsim.ini to reference the PSLSE
veriuser.sl each time I open up ModelSim. So I’ve elected to modify my
/home/kwilke/altera_lite/15.1/modelsim_ase/modelsim.ini file so that I don’t have to set this manually and remember to compile options in the ModelSim interface. This will effect all of my projects, but since I’m only using this for working with PSLSE that is something I find acceptable.
My next step is to begin simulating to see how my empty AFU is faring so far. Find the button for
RTL Simulation or you can go to
RTL Simulation to open ModelSim.
Since my last article, I’ve learned a few tricks to make my life with ModelSim easier. Most of the interactions within the interface correspond to commands ran in the VSIM prompt at the bottom of the main interface. Instead of going to
Start Simulation and picking the same options every time, I can just run
vsim work.top in the command line. Even better, you can combine these commands into DO files that help automate some of the things you want the simulator to… do.
After entering a
vsim work.top command the simulator is ready to go. The AFU as written so far does only one thing, which is to display an output in the simulator to notify us of the rising edge of the clock signal. Since the PSL provides a 250Mhz clock, the phase time for this is 4 nanoseconds. We can use
run 4 to simulate 4 nanoseconds of work. As before with the memcopy example, ModelSim will hang a bit as it’s waiting for a connection to PSLSE. Once started, the output will be something like below:
# AFU Server is waiting for connection on kbawx:32768 # PSL client connection from localhost # Using PSL protocol level : 0.9908.0 # Clock edge!
Text is great for some events, but something more useful is a visual timeline of the signals as they are changing. Let’s watch the clock signal itself.
sim window near the upper left part of the interface, you can see a hierarchy of instances, drill down into this window and select our svAFU from within
After selecting svAFU the
Objects window on the right side will contain a list of the objects within that instance. We can find the
clock signal as it exists coming into our
parity_afu module. With clock selected, you can right click and select
Add Wave or use
w to open it in ModelSim’s waveform viewer. The command
add wave -position insertpoint sim:/top/a0/svAFU/clock can been seen in the console, providing you the syntax for the command to watch a waveform.
Running the simulation for a few more phases we can see the clock signal is now being recorded.
Tip: There are buttons in the interface to run the simulation for different amount of times, by default the run length is set to 100ns. In the picture below I’ve changed this to 4ns and used the button just to the right to run it for that amount of time.
To help scripting these commands, you can start to type a command in the vsim prompt, and it will show you the available flags and options.
I have a few scripts in my capi-parity project that you can put in the
simulation/modelsim/ directory within your project that will add the various PSL signals. This script will set the radix for many signals to something more useful than binary and change the color of AFU outputs to yellow to help differentiate what’s coming in and out of your AFU. Once a do file is in your
simulation/modelsim/ directory you can run it like
do watch_all_interfaces.do. Tab completion is supported to ease that process as well.
With these scripts added, I commit my repo changes as I want to share and take them with me if I work on this project from another workstation.
I feel this covers a good about for a single post, in the next post we’ll start looking at what needs to be implemented to get this AFU to function in the most basic sense.