Beehive Simulation

Overview

Using Modelsim -- a commercial Verilog/VHDL simulation tool -- one can execute the Beehive Verilog without the tedium of the synthesis process and in an evironment where it's easy to determine the values of any internal signal or register cycle-by-cycle. Thus it's possible to see exactly what's happening in the cores and on the ring in each cycle, a very handy way to debug changes to the hardware.

The simulation differs from running on the board in several ways:

Running a simulation

To run a simulation of a 3-core Beehive, go to the hwv5 directory and type

you@eelab01$ make sim_3 IMG=../sw/o/XXX.img
printout from Modelsim's compilation of Verilog source
printout from the simulator (VSIM) startup
VSIM 2>
At this point you're typing at VSIM's interactive command prompt. To run the simulation for, say, 200,000 cycles (which should take about a minute) type run 2ms<ENTER>. beehive.v sets clock cycle to 10ns; the argument to the run command specifies the duration of this step of the simulation in seconds. Any calls $display or $write in your Verilog source will appear on the console output. Note that as the simulation starts up you'll receive some model warnings labeled with "time=0ns" -- these can be safely ignored.

In a 3-core Beehive, cores #2 and #3 will start executing mc_main() somewhere around cycle 140,000. The easiest way to find when a slave core starts execution is to determine where in memory mc_main resides (see sw/o/XXX.out.map) and search the trace output to see when the core's pc reaches that value.

To run a simulation with 13 cores, change the target of the make from sim_3 to sim_13. Note that the initialization process in core #1 takes many more cycles for 13 cores than it did for 3 cores since the master core is initializing SaveArea and allocating stack space for all the slave cores before sending the ring messages that start each slave.

If you've set up trace printout at the end of each clock cycle (see below), it will be quite voluminous when simulating thousands of cycles, so it's usually more convenient to run the simulator in batch mode. Here are the steps:

Now when you issue the make command described above, the simulator will run silently and exit, leaving its output in the file hwv5/simulate/transcript. You can examine the trace printout using your editor-of-choice.

Trace printout

Towards the end of hwv5/simulate/beehive.v you'll find a collection of $write statements, all commented out. Using these statements as models you can create trace printout at the end of each clock cycle that displays the value of any signal in any of the cores, as well as ring signals.

The current set of statements covers most signals of interest when trying to track what the specified core is doing. Note that the outx signal defined in RISC.v is the value that will be written into the register file, which is usually all one needs to determine the effect of the instruction.

The statements will generate trace output for every clock cycle, which is useful for tracking ring traffic (as seen by the memory controller) and ensuring that I/O units are causing the processor to stall until an operation is complete, etc. If you are trying to trace program execution, it's easier to just generate trace for each executed instruction, ignoring cycles where the processor is stalled. Use the exeN signal to achieve this end:

// follow execution in core N
localparam N = 1;

// true on cycles where core N is executing an instruction
wire exeN = !beehive.coreBlk[N].riscN.nullify &
            !beehive.coreBlk[N].riscN.stall;
always @(negedge clock) if (!reset && exeN) begin
 ...
end