1. cocotb

Notice how the cocotb built-in clock generator is used in the ttsky template (line 14 of test/test.py). And that the Makefile is already created from the template.

2. Test the PM32 multiplier

2.1. Smoke test

For reference, see the example https://tinytapeout.com/hdl/testing/. But you are not doing that exact example!

Your OSIC environment already has the tools installed, so skip the "Running locally" section.

Do not run
Do not run the sudo apt install …​ or pip3 install …​ commands.

If you have cloned the ttsky-verilog-template properly:

# Go to the root directory of your project created from the template
# use the name of your project.   vvv is my name!
$ cd /foss/designs/ece430-tt-sky130-example

# look at the files in the `test/` directory
$ cd test
$ ll

# which is simply an alias for `ls -l`
$ alias ll

$ ls -l

Open the test/README.md and other files as needed in GEdit.

Run the existing example to verify that your setup is working properly.

2.2. Plan the PM32 tests

  • What does "it works" mean for this design?

  • Sequence of steps to do one test.

3. PM32

3.1. pm32.v

// A signed 32x32 Multiplier utilizing SPM
//
// Copyright 2016, mshalan@aucegypt.edu

`timescale		    1ns/1ps
`default_nettype    none

module pm32 (
    input wire          clk,
    input wire          rst,
    input wire          start,
    input wire  [31:0]  mc,
    input wire  [31:0]  mp,
    output reg  [63:0]  p,
    output wire         done
);
    wire        pw;
    reg [31:0]  Y;
    reg [7:0]   cnt, ncnt;
    reg [1:0]   state, nstate;

    localparam  IDLE=0, RUNNING=1, DONE=2;

    always @(posedge clk or posedge rst)
        if(rst)
            state  <= IDLE;
        else
            state <= nstate;

    always @*
        case(state)
            IDLE    :   if(start) nstate = RUNNING; else nstate = IDLE;
            RUNNING :   if(cnt == 64) nstate = DONE; else nstate = RUNNING;
            DONE    :   if(start) nstate = RUNNING; else nstate = DONE;
            default :   nstate = IDLE;
        endcase

    always @(posedge clk)
        cnt <= ncnt;

    always @*
        case(state)
            IDLE    :   ncnt = 0;
            RUNNING :   ncnt = cnt + 1;
            DONE    :   ncnt = 0;
            default :   ncnt = 0;
        endcase

    always @(posedge clk or posedge rst)
        if(rst)
            Y <= 32'b0;
        else if((start == 1'b1))
            Y <= mp;
        else if(state==RUNNING)
            Y <= (Y >> 1);

    always @(posedge clk or posedge rst)
        if(rst)
            p <= 64'b0;
        else if(start)
            p <= 64'b0;
        else if(state==RUNNING)
            p <= {pw, p[63:1]};

    wire y = (state==RUNNING) ? Y[0] : 1'b0;

    spm #(.SIZE(32)) spm32(
        .clk(clk),
        .rst(rst),
        .x(mc),
        .y(y),
        .p(pw)
    );

    assign done = (state == DONE);

endmodule

3.2. spm.v

/*
    A Serial-Parallel Multiplier (SPM)
    Modeled after the design outlined by ATML for their
    AT6000 FPGA in application notes DOC0716 and DOC0529:
        - https://ww1.microchip.com/downloads/en/AppNotes/DOC0529.PDF
        - https://ww1.microchip.com/downloads/en/AppNotes/DOC0716.PDF

    Implemented by mshalan@aucegypt.edu, 2016
*/

`timescale		    1ns/1ps
`default_nettype    none

module spm #(parameter SIZE = 32)(
    input wire              clk,
    input wire              rst,
    input wire              y,
    input wire [SIZE-1:0]   x,
    output wire             p
);
    wire [SIZE-1:1]     pp;
    wire [SIZE-1:0]     xy;

    genvar i;

    CSADD csa0 (.clk(clk), .rst(rst), .x(x[0]&y), .y(pp[1]), .sum(p));

    generate
        for(i=1; i<SIZE-1; i=i+1) begin
            CSADD csa (.clk(clk), .rst(rst), .x(x[i]&y), .y(pp[i+1]), .sum(pp[i]));
        end
    endgenerate

    TCMP tcmp (.clk(clk), .rst(rst), .a(x[SIZE-1]&y), .s(pp[SIZE-1]));

endmodule


// Carry Save Adder
module CSADD(
    input wire  clk,
    input wire  rst,
    input wire  x,
    input wire  y,
    output reg  sum
);

    reg sc;

    // Half Adders logic
    wire hsum1, hco1;
    assign hsum1 = y ^ sc;
    assign hco1 = y & sc;

    wire hsum2, hco2;
    assign hsum2 = x ^ hsum1;
    assign hco2 = x & hsum1;

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            sum <= 1'b0;
            sc <= 1'b0;
        end
        else begin
            sum <= hsum2;
            sc <= hco1 ^ hco2;
        end
    end
endmodule

// 2's Complement
module TCMP (
    input wire  clk,
    input wire  rst,
    input wire  a,
    output reg  s
);

    reg z;

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            s <= 1'b0;
            z <= 1'b0;
        end
        else begin
            z <= a | z;
            s <= a ^ z;
        end
    end

endmodule