Breaking Verilog
Trying to abuse the simulation
Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.
In lecture 3, we looked into how Cocotb interacts with the Verilog runtime engine. We also saw how it can be abused to effectively do things that really should not be happening.
From class, we had this module:
`timescale 1ns / 1ps //used for time scale specification
`default_nettype none //way to prevent net inference
module simple_logic(
input wire clk,
input wire rst,
input wire en,
output logic [7:0] count,
output logic en_o
);
initial begin
count <= 8'b0;
end
assign en_o = en;
always_ff @(posedge clk)begin
if(rst)begin
count <= 8'b0;
end else begin
count <= count + en;
end
end
endmodule
`default_nettype wire
And I used this code to mess with it. Essentially getting in and strategically forcing the verilog virtual processor to perform steps it shouldn't have. In running this, you can see that the en signal gets pulled high then low all within one timestep and while that simpley means it never goes high, if you were to plot the waveform, it can actually manipulate signals in our logic.
import cocotb
import os
import random
import sys
from math import log
import logging
from pathlib import Path
from cocotb.clock import Clock
from cocotb.triggers import Timer, ClockCycles, RisingEdge, FallingEdge
from cocotb.triggers import ReadOnly,with_timeout, Edge, ReadWrite, NextTimeStep
from cocotb.utils import get_sim_time as gst
from cocotb.runner import get_runner
test_file = os.path.basename(__file__).replace(".py","")
@cocotb.test()
async def test_a(dut):
"""cocotb test for messing with verilog simulation"""
dut._log.info("Starting...")
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start(start_high=False))
dut.en.value = 0;
dut.rst.value = 1;
await Timer(10, "ns")
dut.rst.value = 0;
dut.en.value = 0;
await Timer(10, "ns") #Beginning of Timestep:
dut._log.info(f"Beginning of Timestep:")
dut._log.info(f" clk: {dut.clk.value} en:{dut.en.value} count: {int(dut.count.value)} en_o: {dut.en_o.value}")
dut.en.value = 1 #set value while in Beginning of Timestep
dut._log.info(f"Set en to be 1 in Beginning of Timestep. (should still read low:)")
dut._log.info(f" clk: {dut.clk.value} en:{dut.en.value} count: {int(dut.count.value)} en_o: {dut.en_o.value}")
await ReadWrite() #Still should not have en be updated.
dut._log.info("Value Stable: en should still be low!")
dut._log.info(f" clk: {dut.clk.value} en:{dut.en.value} count: {int(dut.count.value)} en_o: {dut.en_o.value}")
await RisingEdge(dut.en) #should be back in value change/hdl eval
dut._log.info("en has risen! back in value change phase, en should be high now, but not en_o")
dut._log.info(f" clk: {dut.clk.value} en:{dut.en.value} count: {int(dut.count.value)} en_o: {dut.en_o.value}")
await ReadWrite() #
dut._log.info("back in readwrite. en_o should be high now. let's also turn en back off (stupid)")
dut._log.info(f" clk: {dut.clk.value} en:{dut.en.value} count: {int(dut.count.value)} en_o: {dut.en_o.value}")
dut.en.value = 0;
dut._log.info("setting en back to 0!")
await FallingEdge(dut.en) #should be back in value change/hdl eval
dut._log.info("How stupid. Back in value change at the same time since I put en back to 0.")
dut._log.info(f" clk: {dut.clk.value} en:{dut.en.value} count: {int(dut.count.value)}")
def test_runner():
"""Simulate the counter using the Python runner."""
hdl_toplevel_lang = os.getenv("HDL_TOPLEVEL_LANG", "verilog")
sim = os.getenv("SIM", "icarus")
proj_path = Path(__file__).resolve().parent.parent
sys.path.append(str(proj_path / "sim" / "model"))
sources = [proj_path / "hdl" / "simple_logic.sv"]
build_test_args = ["-Wall"]
sys.path.append(str(proj_path / "sim"))
hdl_toplevel = "simple_logic"
runner = get_runner(sim)
runner.build(
sources=sources,
hdl_toplevel=hdl_toplevel,
always=True,
build_args=build_test_args,
parameters={},
timescale = ('1ns','1ps'),
waves=True
)
run_test_args = []
runner.test(
hdl_toplevel=hdl_toplevel,
test_module=test_file,
test_args=run_test_args,
waves=True
)
if __name__ == "__main__":
test_runner()
For this assignment, starting with the code provided and manipulate the signals so that en
(and en_o
) go up at the 30 ns mark, and that at the 40 ns mark, you have count
jump from 0 to 10 without the clock ever changing as shown in the simulation waveform below. NOTE YOU CANNOT CHANGE THE VERILOG FILE!