Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Synopsys Simulation Workflow with VCS and Verdi

Tech May 16 1

Arithmetic Components

The design utilizes separate modules for addition, subtraction, multiplication, and division operations.

module math_add (
    input  wire [7:0] x,
    input  wire [7:0] y,
    output wire [7:0] z
);
    assign z = x + y;
endmodule

module math_sub (
    input  wire [7:0] x,
    input  wire [7:0] y,
    output wire [7:0] z
);
    assign z = x - y;
endmodule

module math_mul (
    input  wire [7:0] x,
    input  wire [7:0] y,
    output wire [7:0] z
);
    assign z = x * y;
endmodule

module math_div (
    input  wire [7:0] x,
    input  wire [7:0] y,
    output wire [7:0] quotient,
    output wire [7:0] rem
);
    assign quotient = x / y;
    assign rem = x % y;
endmodule

Top-Level Integration

The core processor module instantiates the arithmetic units and multiplexes the output based on the opcode.

module core_processor (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [2:0]  opcode,
    input  wire [7:0]  src_a,
    input  wire [7:0]  src_b,
    output reg  [7:0]  data_out
);

    localparam CMD_ADD = 3'd0;
    localparam CMD_SUB = 3'd1;
    localparam CMD_MUL = 3'd2;
    localparam CMD_DIV = 3'd3;

    reg [7:0] w_add_a, w_add_b, w_add_res;
    reg [7:0] w_sub_a, w_sub_b, w_sub_res;
    reg [7:0] w_mul_a, w_mul_b, w_mul_res;
    reg [7:0] w_div_a, w_div_b, w_div_res;

    math_add u_add (.x(w_add_a), .y(w_add_b), .z(w_add_res));
    math_sub u_sub (.x(w_sub_a), .y(w_sub_b), .z(w_sub_res));
    math_mul u_mul (.x(w_mul_a), .y(w_mul_b), .z(w_mul_res));
    math_div u_div (.x(w_div_a), .y(w_div_b), .quotient(w_div_res));

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            data_out <= 8'd0;
        end else begin
            case (opcode)
                CMD_ADD: begin
                    w_add_a <= src_a;
                    w_add_b <= src_b;
                    data_out <= w_add_res;
                end
                CMD_SUB: begin
                    w_sub_a <= src_a;
                    w_sub_b <= src_b;
                    data_out <= w_sub_res;
                end
                CMD_MUL: begin
                    w_mul_a <= src_a;
                    w_mul_b <= src_b;
                    data_out <= w_mul_res;
                end
                CMD_DIV: begin
                    w_div_a <= src_a;
                    w_div_b <= src_b;
                    data_out <= w_div_res;
                end
                default: data_out <= 8'd0;
            endcase
        end
    end
endmodule

Testbench

The verification environment drives the design with a clock and reset sequence, applying random operands to verify logic.

`timescale 1ns/1ps

module tb_processor;

    reg         clk;
    reg         rst_n;
    reg  [2:0]  opcode;
    reg  [7:0]  src_a;
    reg  [7:0]  src_b;
    wire [7:0]  data_out;

    localparam CMD_ADD = 3'd0;
    localparam CMD_SUB = 3'd1;
    localparam CMD_MUL = 3'd2;
    localparam CMD_DIV = 3'd3;

    core_processor u_dut (
        .clk(clk),
        .rst_n(rst_n),
        .opcode(opcode),
        .src_a(src_a),
        .src_b(src_b),
        .data_out(data_out)
    );

    initial begin
        clk = 0;
        forever #5 clk = ~clk;
    end

    initial begin
        rst_n = 0;
        opcode = CMD_ADD;
        src_a = 0;
        src_b = 0;
        #20;

        rst_n = 1;
        #10;

        @(posedge clk);
        src_a = 5;
        src_b = 3;
        opcode = CMD_ADD;
        repeat(2) @(posedge clk);
        $display("Add: %d + %d = %d", src_a, src_b, data_out);
        #20;

        @(posedge clk);
        src_a = 10;
        src_b = 4;
        opcode = CMD_SUB;
        repeat(2) @(posedge clk);
        $display("Sub: %d - %d = %d", src_a, src_b, data_out);
        #20;

        @(posedge clk);
        src_a = 20;
        src_b = 5;
        opcode = CMD_DIV;
        repeat(2) @(posedge clk);
        $display("Div: %d / %d = %d", src_a, src_b, data_out);
        #20;

        @(posedge clk);
        src_a = 6;
        src_b = 7;
        opcode = CMD_MUL;
        repeat(2) @(posedge clk);
        $display("Mul: %d * %d = %d", src_a, src_b, data_out);
        #20;

        $finish;
    end
endmodule

Build Automation

The Makefile manages the compilation with VCS, simulation execution with FSDB dumping, and the invocation of Verdi for debugging.

# Project Configuration
TOP_MODULE = core_processor
FILE_LIST = files.f
WAVES = $(TOP_MODULE).fsdb

.PHONY: all compile simulate run_verdi clean

all: clean compile simulate

compile:
	vcs -sverilog -debug_all -full64 \
		-P $(NOVAS_HOME)/share/PLI/VCS/LINUX64/novas.tab \
		$(NOVAS_HOME)/share/PLI/VCS/LINUX64/pli.a \
		-f $(FILE_LIST) \
		-l compile.log

simulate:
	./simv \
		-ucli -i dump_fsdb.tcl \
		+fsdb+autoflush \
		-l simulate.log

run_verdi:
	verdi -nologo -sv -f $(FILE_LIST) -ssf $(WAVES) &

clean:
	rm -rf csrc DVEfiles simv simv.daidir ucli.key *.log *.fsdb *.conf *.dat

FSDB Dump Script

global env
set fsdb_file "core_processor.fsdb"
fsdbDumpfile "$fsdb_file"
fsdbDumpvars 0 "tb_processor"
run

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.