Embedded Systems Spring 2024
Lab 6 2's complement adder/subtractor.
Name:
Mason Brady
Email: mrbrady1@fortlewis.edu

2's Complement Adder / Subtractor


Introduction: This lab was to learn how to implement more complex circuits with all the techniques we've learned
Materials GVIM, Vivado, Basys 3
Methods / Results:

1) Add/ Subtract 2's Complement on LEDs and SSD

I combined part 1 and 2 of the lab by having two output wires that I set equal to eachother from my module. This allows me to test both the SSD and LED tests we were asked to do at the same time. It also helped me debug the SSDs.

The trickiest part of this section is handling the positive and negative numbers on the SSD because if the sum >= d8 then the logic is different. I did a check on x[3] (MSB) to see if it is above this threshold and therefore negative. The actual adder logic is fairly simple and I just programmed the logic we discussed in class using behavioural programming which I found to be a simpler approach than structural where you would have to do a lot more to get the same results.
an <= 4'b1110;

From this the code was fairly straightforward. Some of the parameters can be ignored for this part since I was just future proofing it for step two so I wouldn't have to rewrite anything (rh is the rushour enable). The code is fairly simple I think there is a better way of using the step count instead of breaking it up every loop but this worked out fine. Basically if the clock has reached the loop limit (2 for simulation and 50000000 for the Basys) then it increments the step in the loop and resets the timer. The step count is then used for the logic expressions above by just breaking it into it's individual bits and using the aformentioned logic. The simulation results are as expected. I found out that you can rearrange signals in the viewer which was nice to know especially for this project it made it much easier to read.

module threebit_as(num1, num2, clk, as, out, out2);
    input signed [3:0] num1, num2;
    input as;
    reg s2, s1, s0;
    reg c2, c1, c0;
    reg ov;
    input clk;
    output reg [3:0] out;
    output reg [3:0] out2;

    reg a2, a1, a0;
    always @(posedge clk) begin
        a2 = num2[2] ^ as;
        a1 = num2[1] ^ as;
        a0 = num2[0] ^ as;
       
        c0 = ((num1[0] ^ a0) & as) | (num1[0] & a0);
        c1 = ((num1[1] ^ a1) & c0) | (num1[1] & a1);
        c2 = ((num1[2] ^ a2) & c1) | (num1[2] & a2);

        s0 = a0 ^ num1[0] ^ as;
        s1 = a1 ^ num1[1] ^ c0;
        s2 = a2 ^ num1[2] ^ c1;
       
        ov = c2 ^ c1;
        if (ov == 1)begin
            out = {c2, s2, s1, s0};
            out2 = {c2, s2, s1, s0};

        end else
        begin
            out = {s2, s2, s1, s0};
            out2 = {s2, s2, s1, s0};
        end
       
    end
   
endmodule

module SSDecode (input clk, input [3:0] x, output reg [6:0] g_to_a, output reg [3:0] an);
    reg[3:0] digit;
    parameter cntmax = 10'd1023;
    reg state = 1'b0;
    reg [9:0] cnt;
    always @(posedge clk)
    begin
        cnt <= cnt + 1'b1;
        digit <= x[3:0];
        if(cnt >= cntmax) begin
            if (x[3] == 1) begin
                if (state == 1'b0) begin
                    an <= 4'b1101;
                    g_to_a <= 7'b0111111;
                end
                if (state == 1'b1) begin
                    an <= 4'b1110;
                    case(digit)
                        15:g_to_a <= 7'b1111001;
                        14:g_to_a <= 7'b0100100;
                        13:g_to_a <= 7'b0110000;
                        12:g_to_a <= 7'b0011001;
                        11:g_to_a <= 7'b0010010;
                        10:g_to_a <= 7'b0000010;
                        9:g_to_a <= 7'b1111000;
                        8:g_to_a <= 7'b0000000;
                    endcase
                end
            end else if (state == 1'b1) begin
                an <= 4'b1110;
                case(digit)
                    0:g_to_a <= 7'b1000000;
                    1:g_to_a <= 7'b1111001;
                    2:g_to_a <= 7'b0100100;
                    3:g_to_a <= 7'b0110000;
                    4:g_to_a <= 7'b0011001;
                    5:g_to_a <= 7'b0010010;
                    6:g_to_a <= 7'b0000010;
                    7:g_to_a <= 7'b1111000
                    8:g_to_a <= 7'b0000000;
                endcase
            end
            state <= ~state;
            cnt <= 10'b0;
        end
    end
endmodule

module lab5(input [15:0] sw, output [15:0] led, input clk, output [3:0] an, output [6:0] seg);
    wire [3:0] out;
    threebit_as af(.num1(sw[2:0]), .num2(sw[5:3]), .as(sw[6]), .clk(clk), .out(out), .out2(led[3:0]));
    SSDecode UUT(.clk(clk), .x(out), .g_to_a(seg), .an(an));
endmodule

2) Using SIPO

The next step was implementing a serial in parallel out so that only 5 switches are needed instead of 7 (You can get away with 6 and 4 for continuous calculation like abovce but an extra switch is needed to trigger calculation). There are three clock switches needed for this, one for each SIPO and the computation trigger. All three of these switches should be run through debounce to help mitigate unwanted triggering (sometimes my clocks on the SIPO will still trigger twice if I'm not careful). The following modules were added to the code.

module debounce(sw, clk, sw_out);
    reg prev_switch;
    input clk;
    input sw;
    output reg sw_out;
    initial begin
        prev_switch = sw;
    end
    always @ (posedge clk)
        if(sw != prev_switch)begin
            prev_switch = sw;
            sw_out = 1'b0;
        end
       else sw_out = sw;
endmodule

module sipo (clk, si, po1, po2);
    input clk, si;
    output [2:0] po1;
    output [2:0] po2;
    reg [2:0] tmp;
   
    always @(posedge clk) begin
        tmp = {si, tmp[2:1]};
    end
    assign po1 = tmp;
    assign po2 = tmp;
endmodule

From these two modules and the one above we have everything we need for this to work. One thing to note is I also added a second output to my SIPO so that the number appears on the LEDs. I did this becuase I thought my code was wrong since I was getting incorrect numbers but after debugging with the LEDs it seems like it will sometimes trigger twice (shift the sw[1] or sw[3] into the register twice instead of once) even with the debounce. I think it's simply because the clock is really fast and even with the debounce it can still be stuck in a weird state for slightly too long. The bench module to implement all of this can be seen below and is almost identical to what I described above.

module lab5(input [15:0] sw, output [15:0] led, input clk, output [3:0] an, output [6:0] seg);
    wire [3:0] out;
    //sw[0] SIPO clock
    //sw[1] Data1
    //sw[2] SIPO clock 2
    //sw[3] Data2
    //sw[4] Computation
    //sw[5] A/S
    wire SIPO_clk1, SIPO_clk2, computation_clk, parallel_data1, parallel_data2;
   
    debounce d0(.sw(sw[0]), .clk(clk), .sw_out(SIPO_clk1));
    debounce d1(.sw(sw[2]), .clk(clk), .sw_out(SIPO_clk2));
    debounce d2(.sw(sw[4]), .clk(clk), .sw_out(computation_clk));
   
    sipo data_in1(.clk(SIPO_clk1), .si(sw[1]), .po1(parallel_data1), .po2(led[6:4]));
    sipo data_in2(.clk(SIPO_clk2), .si(sw[3]), .po1(parallel_data2), .po2(led[9:7]));
   
    threebit_as af(.num1(parallel_data1), .num2(parallel_data2), .as(sw[5]), .clk(computation_clk), .out(out), .out2(led[3:0]));
    SSDecode UUT(.clk(clk), .x(out), .g_to_a(seg), .an(an));
endmodule



Discussion: This lab was ok no real complaints just some things were buggier than I would've hoped. Sometimes with HDL I write code and it doesn't work so I start over from scratch and do almost the exact same thing and it works fine so I think my code is just slightly too sloppy still and I encounter unwanted errors because of it.