Why two exactly "wire" statement in systemverilog, one can be compiled and the other on can not? - system-verilog

Here is the first HDL code for my program counter.
timeunit 1ns; timeprecision 10ps;
module PC(
output logic [31:0] pc_addr,
output logic [31:0] Next_addr,
input logic [31:0] Branch_addr,
input logic PCSrc,
input logic clock, reset
);
wire [31:0] y;
MUX MUX (
.y (y),
.a (Branch_addr),
.b (Next_addr),
.sel (PCSrc)
);
adder_1 adder_1(
.y(Next_addr),
.a(pc_addr),
.b(3'b100)
);
always_ff # (posedge clock)
begin
if(reset)
pc_addr <= 0; //PC address start at 0x0000_0000
else
pc_addr <= y;
end
endmodule
The signal y is come from the output of the instance MUX, and it is not generated by the PC module itself. So I used wire to connect this signal to the top module PC, and D-type flipflop pc_addr will adopt that signal as the output signal of the module.
In this case, this code can be compiled perfectly fine, and I found the wire statement in this code is essential. I have tried to remove that statement, then the simulation result went wrong because the signal y from MUX did not connect to the PC module.
Here come the second code for my MIPS pipeline:
module IDEX(
output logic IDEX_RegDst, IDEX_ALUSrc, IDEX_MemtoReg, IDEX_RegWrite, IDEX_MemRead,
IDEX_MemWrite, IDEX_Branch, IDEX_ALUOp1, IDEX_ALUOp0,
output logic [31:0]IDEX_Next_addr,
output logic [31:0] IDEX_Read_data_1, IDEX_Read_data_2,
output logic [4:0] IDEX_Write_register,
output logic [31:0] IDEX_Extended,
input logic [31:0] IFID_Next_addr,
input logic [31:0] IFID_Instruction,
input logic [31:0] Write_data,
input logic [4:0] Write_register,
input logic RegWrite,
input logic clock, reset
);
register register (
.Read_data_1(Read_data_1),
.Read_data_2(Read_data_2),
.Read_register_1(IFID_Instruction[25:21]),
.Read_register_2(IFID_Instruction[20:16]),
.Write_register(Write_register),
.Write_data(Write_data),
.RegWrite(RegWrite),
.clock(clock),
.reset(reset)
);
sign_extender sign_extender (
.extended(extended),
.unextended(IFID_Instruction[15:0])
);
control control (
.RegDst(RegDst),
.ALUSrc(ALUSrc),
.MemtoReg(MemtoReg),
.RegWrite(RegWrite_0), //this RegWrite signal does not connect with the Register.sv
.MemRead(MemRead),
.MemWrite(MemWrite),
.Branch(Branch),
.ALUOp1(ALUOp1),
.ALUOp0(ALUOp0),
.Operand(IFID_Instruction[31:26])
);
MUX_5 MUX_5 (
.y (y),
.a (IFID_Instruction[15:11]),
.b (IFID_Instruction[20:16]),
.sel (RegDst)
);
wire RegDst;
wire [4:0]y;
wire [31:0]Read_data_1, Read_data_2, extended;
always_ff # (posedge clock)
begin
if(reset)
{IDEX_RegDst, IDEX_ALUSrc, IDEX_MemtoReg, IDEX_RegWrite, IDEX_MemRead,
IDEX_MemWrite, IDEX_Branch, IDEX_ALUOp1, IDEX_ALUOp0, IDEX_Next_addr, IDEX_Read_data_1,
IDEX_Read_data_2, IDEX_Write_register, IDEX_Extended} <= 0;
else
begin
{IDEX_RegDst, IDEX_ALUSrc, IDEX_MemtoReg, IDEX_RegWrite, IDEX_MemRead,
IDEX_MemWrite, IDEX_Branch, IDEX_ALUOp1, IDEX_ALUOp0} <= {RegDst,
ALUSrc, MemtoReg, RegWrite_0, MemRead, MemWrite, Branch, ALUOp1, ALUOp0};
IDEX_Next_addr <= IFID_Next_addr;
IDEX_Read_data_1 <= Read_data_1;
IDEX_Read_data_2 <= Read_data_2;
IDEX_Write_register <= y;
IDEX_Extended <= extended;
end
end
endmodule
This code's situation is exactly the same as the first one. I want to connect the signal y from the instance MUX_5 (and all other instance output signal) to the top module by using the wire statement. However the simulator can not compile this time, the error is :
*ncvlog: *E,DUPIMP (IDEX.sv,65|13): Identifier 'y', implicitly declared here, first as a wire, is subsequently redeclared.
wire [4:0]y;
|
ncvlog: *E,DUPIDN (IDEX.sv,72|10): identifier 'y' previously declared [12.5(IEEE)].
I am not very sure my use of wire statement is correct or not, but if I delete this wire statement, then the simulation result is wrong.
Guys pls help me and tell me what is going on? That is so confused! Why two wire statement have different compile result???
Thank you very much!

In module IDEX you have:
MUX_5 MUX_5 (
.y (y), //<-- y used
.a (IFID_Instruction[15:11]),
.b (IFID_Instruction[20:16]),
.sel (RegDst)
);
wire RegDst;
wire [4:0]y; //<-- y declared
In Verilog and SystemVerilog variables, wire and regs should be declared before they are used.
If an unknown name is used it is often created as an implict 1 bit wire, leading to y effectively being declared twice. Once as an implicit 1 bit wire then explicitly as a 5 bit wire.
You are actually trying to do this:
wire y; //<-- y declared
MUX_5 MUX_5 (
.y (y), //<-- y used
);
wire [4:0]y; //<-- y re-declared
Removing the explicit declaration (wire [4:0]y;) will remove the error but leave you with only 1 bit connected.
Solution
Declare the wire before you is use it.
wire RegDst;
wire [4:0]y; //<-- y declared
MUX_5 MUX_5 (
.y (y), //<-- y used
.a (IFID_Instruction[15:11]),
.b (IFID_Instruction[20:16]),
.sel (RegDst)
);

Related

LFSR description right?

I wrote a 32-bit LFSR based on the taps from [1]. I want to ask if the following description is right for the 32-bit LFSR with the taps 32,22,2 and 1.
module lfsr (
input logic clk_i,
input logic rst_i,
output logic [31:0] rand_o
);
logic[31:0] lfsr_value;
assign rand_o = lfsr_value;
always_ff #(posedge clk_i, negedge rst_i) begin
if(~rst_i) begin
lfsr_value <= '0;
end else begin
lfsr_value[31:1] <= lfsr_value[30:0];
lfsr_value[0] <= ~(lfsr_value[31] ^ lfsr_value[21] ^ lfsr_value[1] ^ lfsr_value[0]);
end
end
endmodule
[1] http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
Looks Ok. you could also use an XOR, instead of an XNOR, as long as you reset to something else (the XOR version locks up at all 0's, the XNOR at all 1's).
For many apps the pseudo-random output is the single bit you shift out (31 in your case), rather than the entire register. It's also (more?) common to shift right, and put the XOR data in the top bit, and use the bit 0 output as your PR data.
Your code is specifically SystemVerilog, and not Verilog, so I've removed the Verilog tag.

How do I implement a Parametrizable Mux in SystemVerilog?

I am getting the following error in System Verilog with VCS synthesizer:
The following access has an invalid number of indices.
bus[i]
I am basically trying to do a parametrizable mux made of interfaces, with the select bus being one-hot:
module myMux
#(int unsigned WIDTH=3)
(
my_interface bus[WIDTH-1:0],
input logic [WIDTH-1:0] select,
output logic [31:0] out_data
)
always_comb begin
out_data = 'x;
for (int unsigned i=0; i < WIDTH; i++) begin
if (select[i]) out_data = bus[i].in_data;
end
end
endmodule
I tried the different methods outlined in this answer here (including using |= ) but I always get the same error. Using a "genvar i" instead of an int does not even compile.
If I replace bus[i] with bus[0], then it compiles (but it is not what I want) . . . also, replacing WIDTH with a number in the for statement (ie i < 1) gives me the same error even though it is less than the value of WIDTH.
Any ideas? the code needs to be synthesizable.
Accessing an instances of an arrayed interface can only be accessed via a simulation constant (parameter, genvar, or hard-coded number). Data types and design elements both use dotted names to access there respected member or hierarchical-name, but the rules for accessing index arrays are different. Best description I can quickly find is in IEEE Std 1800-2012 § 23.6 Hierarchical names and § 23.7 Member selects and hierarchical names.
Here are two possible solutions:
Tri-state solution: floating if select is 0, x on the bit with multiple conflicting drivers.
module myMux
#(int unsigned WIDTH=3)
(
my_interface bus[WIDTH-1:0],
input logic [WIDTH-1:0] select,
output wire [31:0] out_data
);
for (genvar i=0; i < WIDTH; i++) begin : loop
assign out_data = select[i] ? bus[i].in_data : 'z;
end
endmodule
Priority selector: using a local 2D array to map the interface instances. This map can be accessed in an always block. If you are on FPGA, this is the better solution as it doesn't need tri-state.
module myMux
#(int unsigned WIDTH=3)
(
my_interface bus[WIDTH-1:0],
input logic [WIDTH-1:0] select,
output logic [31:0] out_data
);
logic [31:0] map [WIDTH];
for (genvar i=0; i < WIDTH; i++) begin : loop
assign map[i] = bus[i].in_data;
end
always_comb begin
out_data = 'x;
for(int unsigned i=0; i<WIDTH; i++) begin
if (select[i]) out_data = map[i];
end
end
endmodule

assign statement for RTL readability in an interface causes assignments or a buffer in synthesis

We have an interface with modports connectin gmodules that looks something like this:
interface test_interface (clk, in1, out1);
input logic in1;
output logic out1;
input logic clk;
logic mid1;
logic aliased_signal;
modport a_to_b (
input in1,
input clk,
output mid1,
input aliased_signal
);
modport b_to_a (
input clk,
input mid1,
output out1,
output aliased_signal
);
endinterface : test_interface
module top(clock, inpad, outpad);
input logic clock;
input logic inpad;
output logic outpad;
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad));
a A0(.a2b(test_if));
b B0(.b2a(test_if));
endmodule
module a ( test_interface.a_to_b a2b);
always_ff #(posedge a2b.clk) begin
a2b.mid1 <= a2b.in1 & a2b.aliased_signal;
end
endmodule
module b (test_interface.b_to_a b2a);
assign b2a.aliased_signal = b2a.out1;
always_ff #(posedge b2a.clk) begin
b2a.out1 <= ~b2a.mid1;
end
endmodule
This is a trivial example, but demonstrates the problem. In the real design, we have, for example 32-bit outputs and 8 bits of that may go to one place and 8 bits to another, etc. In the destination, they would like to use names that are more meaningful in the destination module, so are using assignments to create those names in the interface so that the destination code isn't using just part of the bits of an obfuscated bus name in the interface.
While the above simulates fine, the result is assignment statements during synthesis (even if using always_comb obviously) and while we can have the synthesis tool insert buffers to make APR happy, this is not desired when these signals are just used as convenient aliases basically.
Is there an RTL coding style with SV interfaces that would allow such "aliasing" without creating complications downstream in synthesis/APR tools?
Below is a closer example to what I'm trying to do. The "obfuscated_name" signal is an output of the a module because some modules use the name directly from the interface (this could be cleaned up to only do what the a->b connection is doing), but I get the same errors from IUS and DC if I connect to mid2 a->c instead of using the obfuscated_name signal directly.
interface test_interface(clk, in1, out1, out2);
input logic [7:0] in1;
output logic [3:0] out1;
output logic [3:0] out2;
input logic clk;
logic [7:0] obfuscated_name;
logic [3:0] mid1;
logic [3:0] mid2;
modport a_mp (
input clk,
input in1,
output obfuscated_name
);
modport a_to_b (
input clk,
input .mid1(obfuscated_name[3:0]),
output out1
);
modport a_to_c (
input clk,
input obfuscated_name,
output out2
);
endinterface : test_interface
module a ( test_interface.a_mp a_intf);
always_ff #(posedge a_intf.clk) begin
a_intf.obfuscated_name <= ~a_intf.in1;
end
endmodule
module b (test_interface.a_to_b b_intf);
always_ff #(posedge b_intf.clk) begin
b_intf.out1 <= b_intf.mid1;
end
endmodule
module c (test_interface.a_to_c c_intf);
always_ff #(posedge c_intf.clk) begin
c_intf.out2 <= ~c_intf.obfuscated_name[7:4];
end
endmodule
module top( input logic clock,
input logic [7:0] inpad,
output logic [3:0] outpad1,
output logic [3:0] outpad2 );
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad1), .out2(outpad2));
a A0(.a_intf(test_if));
b B0(.b_intf(test_if));
c C0(.c_intf(test_if));
endmodule
The error I get from IUS is:
ncvlog: *E,MODPXE (test_interface.sv,18|18): Unsupported modport
expression for port identifier 'mid1'.
and DC gives this error:
Error: ./b.sv:1: The construct 'b_intf.mid1 (modport expression without a modport from parent)' is not supported in synthesis. (VER-700)
I'm hoping I'm doing something ignorant here and that this is possible what I'm trying to do.
There is a feature in Verilog called a port expression .name_of_port(expression_to_be_connected_to_port) that most people recognize in a module instance port list that they don't realize can also be used in the module deceleration port list header. This declares the name of the port, and the expression that gets connected to the port. This way a smaller part select of a larger internal bus can be made into a port.
module DUT(input clk, inout .data(bus[7:0]) );
wire [31:0] bus;
endmodule
module top;
reg clock;
wire [7:0] mydata;
DUT d1(.data(mydata), .clk(clock) );
endmodule
In SystemVerilog you can do the same thing with a modport expression.
interface test_interface (clk, in1, out1);
input logic in1;
output logic out1;
input logic clk;
logic mid1;
logic aliased_signal;
modport a_to_b (
input in1,
input clk,
output mid1,
input .aliased_signal(out1) // modport expression
);
modport b_to_a (
input clk,
input mid1,
output out1
);
endinterface : test_interface
module top( input logic clock,
input logic inpad,
output logic outpad );
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad));
a A0(.a2b(test_if));
b B0(.b2a(test_if));
endmodule
module a ( test_interface.a_to_b a2b);
always_ff #(posedge a2b.clk) begin
a2b.mid1 <= a2b.in1 & a2b.aliased_signal; // port reference to alias
end
endmodule
module b (test_interface.b_to_a b2a);
always_ff #(posedge b2a.clk) begin
b2a.out1 <= ~b2a.mid1;
end
endmodule

Verilog counter counts wrong

I'm trying to implement a counter that counts up an internal value every clock-pulse with an input value.
module Counter(in, clk, out);
input clk;
input [7:0] in;
wire clk;
wire [7:0] in;
output [7:0] out;
reg [7:0] out;
always # (posedge clk) begin
out <= out + in;
end
endmodule
The output I get is correct most of the time but sometimes the counter does not increment as expected. Here is a link to a waveform of the output. As can be seen the counter jumps from 5 to 10 even though in is 3. Can someone help me?
Your output appears to be in octal in the waveform, or base 8 (I'm guessing this is the 'O 000' in the second column).
In this case 'd5 + 'd3 = 'd8 ('o010). So everything seems to be working correctly.

How do I make use of multipliers to generate a simple adder?

I'm trying to synthesize an Altera circuit using as few logic elements as possible. Also, embedded multipliers do not count against logic elements, so I should be using them. So far the circuit looks correct in terms of functionality. However, the following module uses a large amount of logic elements. It uses 24 logic elements and I'm not sure why since it should be using 8 + a couple of combinational gates for the case block.
I suspect the adder but I'm not 100% sure. If my suspicion is correct however, is it possible to use multipliers as a simple adder?
module alu #(parameter N = 8)
(
output logic [N-1:0] alu_res,
input [N-1:0] a,
input [N-1:0] b,
input [1:0] op,
input clk
);
wire [7:0] dataa, datab;
wire [15:0] result;
// instantiate embedded 8-bit signed multiplier
mult mult8bit (.*);
// assign multiplier operands
assign dataa = a;
assign datab = b;
always_comb
unique case (op)
// LW
2'b00: alu_res = 8'b0;
// ADD
2'b01: alu_res = a + b;
// MUL
2'b10: alu_res = result[2*N-2:N-1]; // a is a fraction
// MOV
2'b11: alu_res = a;
endcase
endmodule
Your case statement will generate a 4 input mux with op as the select which uses a minimum of 2 logic cells. However since your assigning an 8-bit variable in the case block you will require 2 logic elements for each bit of the output. Therefore total logic elements is 8*2 for the large mux and 8 for the adder giving you 24 as the total.
I'm doing this project too so I won't give too much away about how to optimise this. However what I will tell you is that both the mux's and the adder can be implemented using multipliers, 8 at most. With that said I don't think this architecture is optimal for a multiplier implementation.