I recently reinstalled my gitlab server and decided to try and take advantage of some of its features. One of these is the built in CI/CD, which I had never messed with before.

Since I am the only one who uses the server, I decided to set up a shared runner for all of my projects to use. Since all of my projects would be using it, I made it a docker-executor so that it can be used in different setups.

I followed the tutorial here making a few modifications to the config. I wanted the runner to be generic, so I took out the services stuff and just left the

	[[runners]]
	[runners.docker]

part, which is what tells gitlab that this is a docker-executor. From there, I registered the runner using the same command, substituting in my url, token, description, and default image. I chose gcc as the default image. As I found out later, one thing I should have added network_mode = "host", but I’ll talk about that later.

Once that was run, the runner showed up and I could use it for a basic C project. What I really wanted to do, however, was run it on my SystemVerilog code from ECE 411. You see, the point of this was to automate testing, and I am too lazy to write tests. My code for 411 already has tests however.

The first step was creating a suitable docker image which would have both modelsim and quartus installed. I chose to create two images, one with 18.1 Standard and the other with 18.1 Lite. Standard is what we use in class, but requires a license. Lite does not require a license, but will not be able to synthesize code for the Arria II. It will synthesize for the MAX 10 though, which is the FPGA that I actually have. Both versions of Modelsim are the same and you don’t need a license for that.

The dockerfiles can be found here. These are also a good source for the direct download links since altera intel keeps trying to hide them. The images are quite large at 12 and 15 gigabytes, so hopefully they will only get downloaded once.

If you look through the dockerfiles you will see that there are a few hacks needed to get Quartus and Modelsim installed. The first of which is libpng, for which an older version is needed that is not available anymore. A link to the older version is included. Next are all of the 32 bit packages that are needed. I add the i386 architecture and then add all of them.

After this, the software can be installed. If all the install files are in the same directory, running the Quartus installer will install Quartus, Modelsim, and any device files that are downloaded. Once that is complete, there is one more hack.

For some reason, Modelsim seems to only like Red Hat linux, so to use it on any other linux system you need to either edit the vsim file to use linux, or in this case, create a symlink so that Modelsim sees the linux_rh60 folder that it is looking for.

From there, the images are built and pushed to dockerhub, where they can be found here. If you are going to use these then make sure you specify a tag, there is no latest. You have to choose lite or std.

Now onto using the images. The .gitlab-ci.yml file for the project looks like this:

default:
  image: bslathi19/modelsim_18.1:std
  tags:
    - docker

cacheline_adaptor:
  stage: test
  script:
    - cd cacheline_adaptor
    - vsim -do run.do

cam:
  stage: test
  script:
    - cd cam
    - vsim -do run.do

fifo:
  stage: test
  script:
    - cd fifo
    - vsim -do run.do

multiplier:
  stage: test
  script:
    - cd multiplier
    - vsim -do run.do

The tags are to ensure that the job gets run on the docker-executor, since there is also a shell-executor which this would not work on.

For each stage, it goes into that directory and runs the provided Modelsim script. Unfortunately since this is class code I can’t make it public. This kind of worked, but I ran into a problem that I wasn’t expecting. The result (pass/fail) of the job is based on the return value of the script, but vsim only returns a failing code if the script itself fails, not if the testbench does. To fix this, I wrote a little patch to the end of the .do files to see if there were any errors during the simulation.

The end of the script looks like this:

onfinish stop
run -all

if { [coverage attribute -name TESTSTATUS -concise] == "1"} {
    echo Warning
    quit -f -code 0
}

quit -code [coverage attribute -name TESTSTATUS -concise]

the run -all is replaced with this block. The onfinish stop stops modelsim from exiting at the end of the simulation. The `coverage atribute -name TESTSTATUS -concise returns the highest level of error encountered during the simulation. 0 for no errors, 1 for warning, 2 for error, and 3 for fatal. Since there are bound to be warnings, I return with 0 even if the test status is 1. If the test status is 2 or 3, indicating an error or fatal error, then gitlab will show the job as failed, which is what I want.

Next on the list was to try and synthesize the project in quartus as well. The quartus project I decided to use was my combination of 385 lab 6 and 411 MP2. Basically, a RISC-V Processor running on a MAX-10 FPGA. I wish I could show you it but again it is still class code.

The code for this was even simpler:

default:
  image: bslathi19/modelsim_18.1:lite
  tags:
    - docker

build1:
  stage: build
  script: quartus_map mp2 -c mp2

This is where I ran into the problem I mentioned before. Apparently for licensing reasons, Quartus needs access to the computers network card. By default I guess Docker containers don’t have a MAC address so the runner needs to be given that config to ensure that it will. The best part about this problem is that you do not get an error code indicating this, you get realloc(): invalid pointer. Very helpful. Googling Quartus in Docker container pointed me in the right direction though.

With that sorted, it worked like a charm. The first time I ran it though it did take 15 minutes to download the docker image.

And with that, I called it a success. I purposely broke the projects and fixed them again to see if the jobs would reflect the changes, and they did.