I am trying to determine how to turn this code into a 4-bit adder/subtractor using a fulladder. Right now it is doing the adding but I don't know how to do the subtract part.
module Adder #(parameter N = 4)(
output wire [N-1:0] sum, // sum
output wire co, // carry
input wire [N-1:0] x,
input wire [N-1:0] y,
input wire is_sub;
);
wire [N:0] c;
assign c[0] = 1'b0;
assign co = c[N];
genvar i;
generate
for (i = 0; i < N; i=i+1)
begin : counter_gen_label
FA FAInst (
.s(sum[i]),
.co(c[i+1]),
.a(x[i]),
.b(y[i]),
.cin(c[i]),
.is_sub(is_sub)
);
end
endgenerate
endmodule
module FA(
output reg s,
output reg co,
input wire a,
input wire b,
input wire cin,
input wire is_sub
);
always #(*)
begin
s = a ^ b ^ cin;
co = (a & b) | (a & cin) | (b & cin);
end
endmodule
How would I go by doing the subtraction inside the FA module?
Thanks!
FA does not need to use is_sub input.
Replace c[0] = 1'b0; with c[0] = is_sub;, and .b(y[i]) with .b(y[i] ^ is_sub).
This is from x - y = x + y' + 1 where y' means inverted y.
Related
Error: Add_sub.v(32): LHS in procedural continuous assignment may not be a net: co.
Error: Add_sub.v(34): LHS in procedural continuous assignment may not be a net: co.
I want to write a Verilog file for a full adder-subtractor with a selection en (en == 0 is adder and en == 1 is subtractor). I am struggling on the full-adder module FA, I was trying to write an if statement to realize this. But I encountered the errors above.
Below is my code:
module Add_sub(x,y,co,u,en);
input [3:0]x, y;
input en;
output [3:0]u;
output co;
wire [3:0]a;
wire [3:1]c;
xnor(a[0],x[0],en);
xnor(a[1],x[1],en);
xnor(a[2],x[2],en);
xnor(a[3],x[3],en);
reg co;
FA M0(y[0],a[0],en,u[0],c[1]);
FA M1(y[1],a[1],c[1],u[1],c[2]);
FA M2(y[2],a[2],c[2],u[2],c[3]);
FA M3(y[3],a[3],c[3],u[3],c[3]);
endmodule
module FA(x,y,cin,u,co,en);
input x, y, cin, en;
output u, co;
assign u = x ^ y ^ cin;
always#(en, x, y, cin) begin
if (en == 0)
assign co = (x & y) | (x & cin) | (y & cin);
if (en == 1)
assign co = (!x & y) | (!x & cin) | (y & cin);
end
endmodule
Can someone help me with this? Or please provide me some other method of the full adder-subtractor.
Don't use assign in an always block, and make a variable assigned in as always block a reg like this to fix the FA module.
module FA(x,y,cin,u,co,en);
input x, y, cin, en;
output reg u, co;
assign u = x ^ y ^ cin;
always#(en, x, y, cin) begin
if (en == 0)
co = (x & y) | (x & cin) | (y & cin);
if (en == 1)
co = (!x & y) | (!x & cin) | (y & cin);
end
The design has other issues, the FA module has 6 ports, the FA instances have 5 connections.
The design uses positional matching for the instance names against the port names and the position is wrong for the first instance. The en signal is in the middle of the list in the instance, and end end of the list for the module. Named association is better than positional for exactly this reason.
In the code below, the line: mem_reg[wr_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]][i*8 +: 8] <= wr_cmd_data[SEG_DATA_WIDTH*n+i*8 +: 8];
The index "i" is an integer type. It is being synthesized right??
I was under the impression that integer variables are only used for simulations in the initial procedural block
Also, the BRAM reg [SEG_DATA_WIDTH-1:0] mem_reg[2**INT_ADDR_WIDTH-1:0]; is being synthesized the number of times the genvar variable "n" loops in the for loop? The multiple generated BRAMs mem_reg will have the same names? And they cannot be accessed separately by name with something like: mem_reg[n] right?
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* DMA parallel simple dual port RAM
*/
module dma_psdpram #
(
// RAM size
parameter SIZE = 4096,
// RAM segment count
parameter SEG_COUNT = 2,
// RAM segment data width
parameter SEG_DATA_WIDTH = 128,
// RAM segment byte enable width
parameter SEG_BE_WIDTH = SEG_DATA_WIDTH/8,
// RAM segment address width
parameter SEG_ADDR_WIDTH = $clog2(SIZE/(SEG_COUNT*SEG_BE_WIDTH)),
// Read data output pipeline stages
parameter PIPELINE = 2
)
(
input wire clk,
input wire rst,
/*
* Write port
*/
input wire [SEG_COUNT*SEG_BE_WIDTH-1:0] wr_cmd_be,
input wire [SEG_COUNT*SEG_ADDR_WIDTH-1:0] wr_cmd_addr,
input wire [SEG_COUNT*SEG_DATA_WIDTH-1:0] wr_cmd_data,
input wire [SEG_COUNT-1:0] wr_cmd_valid,
output wire [SEG_COUNT-1:0] wr_cmd_ready,
output wire [SEG_COUNT-1:0] wr_done,
/*
* Read port
*/
input wire [SEG_COUNT*SEG_ADDR_WIDTH-1:0] rd_cmd_addr,
input wire [SEG_COUNT-1:0] rd_cmd_valid,
output wire [SEG_COUNT-1:0] rd_cmd_ready,
output wire [SEG_COUNT*SEG_DATA_WIDTH-1:0] rd_resp_data,
output wire [SEG_COUNT-1:0] rd_resp_valid,
input wire [SEG_COUNT-1:0] rd_resp_ready
);
parameter INT_ADDR_WIDTH = $clog2(SIZE/(SEG_COUNT*SEG_BE_WIDTH));
// check configuration
initial begin
if (SEG_ADDR_WIDTH < INT_ADDR_WIDTH) begin
$error("Error: SEG_ADDR_WIDTH not sufficient for requested size (min %d for size %d) (instance %m)", INT_ADDR_WIDTH, SIZE);
$finish;
end
end
generate
genvar n;
for (n = 0; n < SEG_COUNT; n = n + 1) begin
(* ramstyle = "no_rw_check" *)
reg [SEG_DATA_WIDTH-1:0] mem_reg[2**INT_ADDR_WIDTH-1:0];
reg wr_done_reg = 1'b0;
reg [PIPELINE-1:0] rd_resp_valid_pipe_reg = 0;
reg [SEG_DATA_WIDTH-1:0] rd_resp_data_pipe_reg[PIPELINE-1:0];
integer i, j;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (i = 0; i < 2**INT_ADDR_WIDTH; i = i + 2**(INT_ADDR_WIDTH/2)) begin
for (j = i; j < i + 2**(INT_ADDR_WIDTH/2); j = j + 1) begin
mem_reg[j] = 0;
end
end
for (i = 0; i < PIPELINE; i = i + 1) begin
rd_resp_data_pipe_reg[i] = 0;
end
end
always #(posedge clk) begin
wr_done_reg <= 1'b0;
for (i = 0; i < SEG_BE_WIDTH; i = i + 1) begin
if (wr_cmd_valid[n] && wr_cmd_be[n*SEG_BE_WIDTH+i]) begin
mem_reg[wr_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]][i*8 +: 8] <= wr_cmd_data[SEG_DATA_WIDTH*n+i*8 +: 8];
wr_done_reg <= 1'b1;
end
end
if (rst) begin
wr_done_reg <= 1'b0;
end
end
assign wr_cmd_ready[n] = 1'b1;
assign wr_done[n] = wr_done_reg;
always #(posedge clk) begin
if (rd_resp_ready[n]) begin
rd_resp_valid_pipe_reg[PIPELINE-1] <= 1'b0;
end
for (j = PIPELINE-1; j > 0; j = j - 1) begin
if (rd_resp_ready[n] || ((~rd_resp_valid_pipe_reg) >> j)) begin
rd_resp_valid_pipe_reg[j] <= rd_resp_valid_pipe_reg[j-1];
rd_resp_data_pipe_reg[j] <= rd_resp_data_pipe_reg[j-1];
rd_resp_valid_pipe_reg[j-1] <= 1'b0;
end
end
if (rd_cmd_valid[n] && rd_cmd_ready[n]) begin
rd_resp_valid_pipe_reg[0] <= 1'b1;
rd_resp_data_pipe_reg[0] <= mem_reg[rd_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]];
end
if (rst) begin
rd_resp_valid_pipe_reg <= 0;
end
end
assign rd_cmd_ready[n] = rd_resp_ready[n] || ~rd_resp_valid_pipe_reg;
assign rd_resp_valid[n] = rd_resp_valid_pipe_reg[PIPELINE-1];
assign rd_resp_data[SEG_DATA_WIDTH*n +: SEG_DATA_WIDTH] = rd_resp_data_pipe_reg[PIPELINE-1];
end
endgenerate
endmodule
`resetall
try to use named blocks:
for (n = 0; n < SEG_COUNT; n = n + 1) begin : blkname
reg [SEG_DATA_WIDTH-1:0] mem_reg [2**INT_ADDR_WIDTH-1:0];
end
And access as:
assign x = blkname[i].mem_reg[j];
How does the following translates into hardware? If I have multiple same equation assigning it to a different register, how does it translate? Say I have
reg [31:0] A;
reg [31:0] B;
reg [31:0] C;
reg [31:0] D;
function [31:0] foo;
reg [31:0] x, y ,z;
// do something
endfunction
always#(posedge clk)
.
.
.
A <= (B <<< 50) + (C ^ D | A) + A;
B <= C + A + B;
C <= foo((B <<< 50) + (C ^ D | A) + A, C + A + B, C <<< 30)
.
.
.
Would I have two combination blocks (4 blocks total) of
(B <<< 50) + (C ^ D | A) + A
and
C + A + B
or would I only have one of each (2 blocks) wiring out the results into A, B, C, and foo? If the compiler makes two of those logic each, is there a way to ensure only one of each is made, and those two combinational logic wires to multiple registers?
As noted by #mcleod_ideafix, it will often depend on the compiler/synthesis tool. Some are better than others at seeing the repeated logic:
(B <<< 50) + (C ^ D | A) + A;
and
C + A + B;
What you should do is write your code to explicitly call these operations out as their own bus and then re-use that named bus inside the expressions. This will clearly show the synthesis tool that your non-blocking statements contain logic that already exists within the design. This will also make it easier to debug in simulation, since you can now easily drop temp1 and temp2 onto your waveform viewer. It is definitely longer, since it adds two lines of code. But it makes your code clearer, easier to understand, and it is more likely to provide the smaller area result that you want. Below is an example:
reg [31:0] A;
reg [31:0] B;
reg [31:0] C;
reg [31:0] D;
function [31:0] foo;
reg [31:0] x, y ,z;
// do something
endfunction
wire [31:0] temp1 = (B <<< 50) + (C ^ D | A) + A;
wire [31:0] temp2 = C + A + B;
always#(posedge clk)
.
.
.
A <= temp1;
B <= temp2;
C <= foo(temp1, temp2, C <<< 30)
.
.
.
Here's my verilog code about add and shift multiplying
when I compile and Initialze and adding the inputs and outputs to get waveforms and simulating them, I dont see any results, everything is z... what is the problem?
module multi(a, b, ans);
input [3:0] a;
input [3:0] b;
output reg [15:0] ans;
reg [15:0] aa;
reg [15:0] bb;
reg [15:0] tmp=0;
reg flag = 1'b1;
always #( a, b)
begin
aa = a;
bb = b;
while ( flag == 1'b1 )
begin
if( bb[0] == 1'b1 )
tmp = tmp + aa;
aa = aa << 1;
bb = bb >> 1;
if ( bb==0 )
flag = 1'b0;
end
ans = tmp;
end
endmodule
There are a number of things that look strange with this code.
First is that you have no clock input, but are attempting to do everything with combinatorial logic.
Second is that setting flag to 1 in the reg statement will mean that your module is only capable of doing a single multiplication. By the way, it is more normal (especially for ASIC design) to use a reset signal than use this initialisation in a reg line.
Third is that a 4 bit number times a 4 bit number will result in an 8bit answer, not 16bit.
In any case, unless you are working at very high speeds you should be able to perform a multiply in a single cycle.
Here are a couple of ways of writing this code more naturally:
Combinatorial Style
module multi(a, b, ans);
input [3:0] a;
input [3:0] b;
output reg [7:0] ans;
always #(*)
begin
ans = a * b;
end
endmodule
Clocked style
module multi(clk, a, b, ans);
input [3:0] a;
input [3:0] b;
output reg [7:0] ans;
always #(posedge clk)
begin
ans <= a * b;
end
endmodule
Your input is 4 bits wide and your assigning to a 16 bit variable, the top 12 bits are unassigned ie x.
input [3:0] a;
reg [15:0] aa;
//...
aa = a;
To assign all bits of aa try some thing like:
aa = {12'b0, a};
//{} is bit concatenation
Or to sign extend a to 16 bits, repeat the MSB 12 times using {width{value}} replication:
aa = {{12{a[3]}}, a};
I'm studying Verilog and here's my first ALU.
I can't understand why the output does not display in the tester block.
Sample outputs(scroll horizontally):
FAIL: a=00010010000101010011010100100100, b=11000000100010010101111010000001, op=101, z=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, expect=11010010100111010111111110100101
FAIL: a=10000100100001001101011000001001, b=10110001111100000101011001100011, op=101, z=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, expect=10110101111101001101011001101011
Why isn't z calculated?
ALU
module yAlu(z, ex, a, b, op);
input [31:0] a, b;
input [2:0] op;
output[31:0] z;
output ex;
wire [31:0] andRes, orRes, arithmRes, slt;
wire cout;
assign slt = 0; // not supported
assign ex = 0; // not supported
and myand[31:0] (andRes, a, b);
or myor[31:0](orRes, a, b);
//Instantiating yArith adder/subtractor from addSub.v
yArith addSub(arithmRes, cout, a, b, op[2]);
//Instantiating 4-to-1 32-bit multiplexor from 4to1Mux.v
yMux4to1 multiplexor(z, andRes, orRes, arithmRes, slt, op[1:0]);
endmodule
MULTIPLEXORS:
// 1-bit 2 to 1 selector
module yMux1(z, a, b, c);
output z;
input a, b, c;
wire notC, upper, lower;
not my_not(notC, c);
and upperAnd(upper, a, notC);
and lowerAnd(lower, c, b);
or my_or(z, upper, lower);
endmodule
//--------------------------------------------
// n-bit 2 to 1 selector
module yMux(z, a, b, c);
parameter SIZE = 2;
output [SIZE-1:0] z;
input [SIZE-1:0] a, b;
input c;
yMux1 mine[SIZE-1:0] (z, a, b, c);
endmodule
//--------------------------------------------
// n-bit 4-to-1 multiplexor
module yMux4to1(z, a0, a1, a2, a3, c);
parameter SIZE = 32;
output [SIZE-1:0] z;
input [SIZE-1:0] a0, a1, a2, a3;
input [1:0] c;
wire [SIZE-1:0] zLo, zHi;
yMux #(.SIZE(32)) lo(zLo, a0, a1, c[0]);
yMux #(.SIZE(32)) hi(zLo, a2, a3, c[0]);
yMux #(.SIZE(32)) final(zLo, zLo, zHi, c[1]);
// c in array is important (see LabL4.v page)
endmodule
//----------------------------------------------
ADDER/SUBTRACTOR BLOCK:
// A simple 1-bit full adder
module yAdder1(z, cout, a, b, cin);
output z, cout;
input a, b, cin;
xor left_xor(tmp, a, b);
xor right_xor(z, cin, tmp);
and left_and(outL, a, b);
and right_and(outR, tmp, cin);
or my_or(cout, outR, outL);
endmodule
//----------------------------------------------
// 32-bit adder with 1 bit carry
module yAdder(z, cout, a, b, cin);
output [31:0] z;
output cout;
input [31:0] a, b;
input cin;
wire [31:0] in, out;
yAdder1 adder[31:0](z, out, a, b, in);
assign in[0] = cin;
assign in[1] = out[0];
assign in[2] = out[1];
assign in[3] = out[2];
assign in[4] = out[3];
assign in[5] = out[4];
assign in[6] = out[5];
assign in[7] = out[6];
assign in[8] = out[7];
assign in[9] = out[8];
assign in[10] = out[9];
assign in[11] = out[10];
assign in[12] = out[11];
assign in[13] = out[12];
assign in[14] = out[13];
assign in[15] = out[14];
assign in[16] = out[15];
assign in[17] = out[16];
assign in[18] = out[17];
assign in[19] = out[18];
assign in[20] = out[19];
assign in[21] = out[20];
assign in[22] = out[21];
assign in[23] = out[22];
assign in[24] = out[23];
assign in[25] = out[24];
assign in[26] = out[25];
assign in[27] = out[26];
assign in[28] = out[27];
assign in[29] = out[28];
assign in[30] = out[29];
assign in[31] = out[30];
assign cout = out[31];
endmodule
//----------------------------------------------
// Arithmetic module. Adds if ctrl = 0, subtracts if ctrl = 1
module yArith(z, cout, a, b, ctrl);
output [31:0] z;
output cout;
input [31:0] a, b;
input ctrl;
wire [31:0] notB, tmp;
wire cin;
assign notB = ~b;
assign cin = ctrl;
yMux #(.SIZE(32)) mux(tmp, b, notB, ctrl);
yAdder adderSubtractor(z, cout, a, tmp, cin);
endmodule
//----------------------------------------------
TESTER:
module labL;
reg [31:0] a, b;
reg [31:0] expect;
reg [2:0] op;
wire ex;
wire[31:0] z;
reg ok, flag;
yAlu mine(z, ex, a, b, op);
initial
begin
repeat(10)
begin
a = $random;
b = $random;
op = 3'b101;
//flag = $value$plusargs("op=%d", op);
#10;
// ERROR CASE
if (op === 3'b011)
$display("Error!");
else if (op === 3'b111)
$display("Error!");
// ARITHM CASE
else if(op === 3'b010)
expect = a + b;
else if(op === 3'b110)
expect = a + ~b + 1;
// AND CASE
else if(op === 3'b000)
expect = a & b;
else if (op === 3'b100)
expect = a & b;
// OR CASE
else if (op === 3'b001)
expect = a | b;
else if (op === 3'b101)
expect = a | b;
// DONE WITH CASES;
#5;
if (expect === z)
$display("PASS: a=%b, b=%b, op=%b, z=%b", a, b, op, z, ex);
else
$display("FAIL: a=%b, b=%b, op=%b, z=%b, expect=%b", a, b, op, z, expect);
end
$finish;
end
endmodule
Your yMux4to1 does not drive the z output, so that's why you see 'zzz' as the output.
This means undriven/high-impedance.
You should be able to use a waveform viewer/simulator to trace your outputs (much better than using print statements).
You are getting a high-impedance signal out on Z. This means that your output Z is not driven. You should step through your design in simulation and put traces on your control signals and Z. Your IDE should support this. You most likely do not have the design wired up correctly so it's important to check your datapath and make sure all inputs/outputs are properly connected.