diff --git a/examples/Led_blinker/Led_blinker.sv b/examples/Led_blinker/Led_blinker.sv new file mode 100644 index 0000000..84d87e1 --- /dev/null +++ b/examples/Led_blinker/Led_blinker.sv @@ -0,0 +1,108 @@ +module Led_blinker + ( + i_clock, + i_reset, + i_enable, + i_switch_1, + i_switch_2, + o_led_drive + ); + + input i_clock; + input i_reset; + input i_enable; + input i_switch_1; + input i_switch_2; + output o_led_drive; + + parameter c_CNT_100HZ = 125; + parameter c_CNT_50HZ = 250; + parameter c_CNT_10HZ = 1250; + parameter c_CNT_1HZ = 12500; + + reg [31:0] r_CNT_100HZ = 0; + reg [31:0] r_CNT_50HZ = 0; + reg [31:0] r_CNT_10HZ = 0; + reg [31:0] r_CNT_1HZ = 0; + + reg r_TOGGLE_100HZ = 1'b0; + reg r_TOGGLE_50HZ = 1'b0; + reg r_TOGGLE_10HZ = 1'b0; + reg r_TOGGLE_1HZ = 1'b0; + + reg r_LED_SELECT = 1'b0; + + always @(posedge i_clock) + begin + if (i_reset == 1) + begin + r_CNT_100HZ <= 0; + r_CNT_50HZ <= 0; + r_CNT_10HZ <= 0; + r_CNT_1HZ <= 0; + + r_TOGGLE_100HZ <= 0; + r_TOGGLE_50HZ <= 0; + r_TOGGLE_10HZ <= 0; + r_TOGGLE_1HZ <= 0; + end + end + + always @(posedge i_clock) + begin + if (r_CNT_100HZ == c_CNT_100HZ - 1) + begin + r_TOGGLE_100HZ <= !r_TOGGLE_100HZ; + r_CNT_100HZ <= 0; + end + else + r_CNT_100HZ <= r_CNT_100HZ + 1; + end + + always @(posedge i_clock) + begin + if (r_CNT_50HZ == c_CNT_50HZ - 1) + begin + r_TOGGLE_50HZ <= !r_TOGGLE_50HZ; + r_CNT_50HZ <= 0; + end + else + r_CNT_50HZ <= r_CNT_50HZ + 1; + end + + always @(posedge i_clock) + begin + if (r_CNT_10HZ == c_CNT_10HZ - 1) + begin + r_TOGGLE_10HZ <= !r_TOGGLE_10HZ; + r_CNT_10HZ <= 0; + end + else + r_CNT_10HZ <= r_CNT_10HZ + 1; + end + + always @(posedge i_clock) + begin + if (r_CNT_1HZ == c_CNT_1HZ - 1) + begin + r_TOGGLE_1HZ <= !r_TOGGLE_1HZ; + r_CNT_1HZ <= 0; + end + else + r_CNT_1HZ <= r_CNT_1HZ + 1; + end + + always @(*) begin + case ({i_switch_1, i_switch_2}) + /* verilator lint_off COMBDLY */ + 2'b11 : r_LED_SELECT <= r_TOGGLE_1HZ; + 2'b10 : r_LED_SELECT <= r_TOGGLE_10HZ; + 2'b01 : r_LED_SELECT <= r_TOGGLE_50HZ; + 2'b00 : r_LED_SELECT <= r_TOGGLE_100HZ; + /* verilator lint_on COMBDLY */ + endcase + end + + assign o_led_drive = r_LED_SELECT & i_enable; + +endmodule diff --git a/examples/Led_blinker/config.gtkw b/examples/Led_blinker/config.gtkw new file mode 100644 index 0000000..f905271 --- /dev/null +++ b/examples/Led_blinker/config.gtkw @@ -0,0 +1,32 @@ +[*] +[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI +[*] Fri Mar 8 17:16:35 2024 +[*] +[dumpfile] "/home/magnus/ntnu/orbit/biosat-electronics-FPGA/electronics-verilator/examples/Led_blinker/trace.vcd" +[dumpfile_mtime] "Fri Mar 8 17:13:28 2024" +[dumpfile_size] 49174 +[savefile] "/home/magnus/ntnu/orbit/biosat-electronics-FPGA/electronics-verilator/examples/Led_blinker/config.gtkw" +[timestart] 0 +[size] 1850 1016 +[pos] -51 -51 +*0.000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] TOP. +[sst_width] 233 +[signals_width] 166 +[sst_expanded] 1 +[sst_vpaned_height] 289 +@28 +TOP.Led_blinker.i_clock +TOP.Led_blinker.i_enable +TOP.Led_blinker.i_reset +TOP.Led_blinker.i_switch_1 +TOP.Led_blinker.i_switch_2 +TOP.Led_blinker.o_led_drive +@22 +TOP.Led_blinker.r_CNT_1HZ[31:0] +TOP.Led_blinker.r_CNT_10HZ[31:0] +TOP.Led_blinker.r_CNT_50HZ[31:0] +@23 +TOP.Led_blinker.r_CNT_100HZ[31:0] +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/examples/Led_blinker/makefile b/examples/Led_blinker/makefile new file mode 100644 index 0000000..a8950ba --- /dev/null +++ b/examples/Led_blinker/makefile @@ -0,0 +1,6 @@ +VERILATOR_ROOT := ../.. +PROJECT_NAME := Led_blinker +SOURCES := *.sv +SIMFILES := *.cpp + +include $(VERILATOR_ROOT)/verilator.mk diff --git a/examples/Led_blinker/sim.cpp b/examples/Led_blinker/sim.cpp new file mode 100644 index 0000000..1d3a528 --- /dev/null +++ b/examples/Led_blinker/sim.cpp @@ -0,0 +1,100 @@ +#include "VLed_blinker.h" +#include "verilated.h" + +// Needed for waveform generation +#include + +#include +#include +#include + +void toggle_clk(VLed_blinker* top, VerilatedVcdC *trace, uint32_t *tickcount) { + top->i_clock = 0; + top->eval(); + trace->dump(10 * (*tickcount)++); + top->i_clock = 1; + top->eval(); + trace->dump(10 * (*tickcount)++); +} + +void print_top(VLed_blinker *top) { + printf("i_enable: %i\n", top->i_enable); + printf("i_clock: %i\n", top->i_clock); + printf("i_switch_1: %i\n", top->i_switch_1); + printf("i_switch_2: %i\n", top->i_switch_2); + printf("o_led_drive: %i\n", top->o_led_drive); +} + +int main(int argc, char** argv) { + VLed_blinker* top = new VLed_blinker; + Verilated::commandArgs(argc, argv); + + // For waveform generation + uint32_t tickcount = 0; + Verilated::traceEverOn(true); + + // Initialization of trace + VerilatedVcdC *trace = new VerilatedVcdC; + top->trace(trace, 99); + trace->open("trace.vcd"); + + // Set initial values + top->i_enable = 1; + top->i_reset = 0; + top->i_clock = 0; + top->i_switch_1 = 0; + top->i_switch_2 = 0; + top->eval(); + + int ret = 0; + uint32_t count_limits[] = { + 125, + 250, + 1250, + 12500 + }; + uint32_t count = 0; + + for (int i = 0; i < sizeof(count_limits) / sizeof(count_limits[0]); i++) { + if (Verilated::gotFinish()) break; + + top->i_switch_1 = (i & 0b01) ? 1 : 0; + top->i_switch_2 = (i & 0b10) ? 1 : 0; + top->i_reset = 0; + + uint32_t count_limit = count_limits[i]; + bool led_signal_expect = false; + for (int j = 0; j < 2*count_limit; j++) { + if (count == count_limit) { + led_signal_expect = true; + printf("Expect led signal high\n"); + } else if (count == 2*count_limit) { + led_signal_expect = false; + printf("Expect led signal low\n"); + } + + if (top->o_led_drive != led_signal_expect) { + printf("top->o_led_drive: Got %i when %i expected\n", top->o_led_drive, led_signal_expect); + toggle_clk(top, trace, &tickcount); + ret = 1; + goto out; + } + + toggle_clk(top, trace, &tickcount); + printf("\nit: %i\n", j); + print_top(top); + fflush(stdout); + count++; + } + + printf("Toggled clock %i times. Reset\n", 2*count); + fflush(stdout); + } + +out: + trace->close(); + delete trace; + + delete top; + return ret; +}