Why does Vivado not recognise packages without modules in System Verilog? - verilog

I have a lengthy enum of opcodes that I want to include in a package so that it can be used in multiple locations throughout the project, this is:
typedef enum logic [6:2] {
LOAD = 5'b00_000, LOAD_FP = 5'b00_001, CUSTOM_0 = 5'b00_010, MISC_MEM = 5'b00_011, OP_IMM = 5'b00_100, AUIPC = 5'b00_101, OP_IMM_32 = 5'b00_110, OP_48_1 = 5'b00_111,
//ect...
} base_opcode_map;
typedef enum logic [6:2] {
R_TYPE = { OP, OP_FP},
R4_TYPE = { MADD, MSUB, NMSUB, NMADD},
I_TYPE = { LOAD, LOAD_FP, MISC_MEM, OP_IMM, OP_IMM_32 },
S_TYPE = { STORE, STORE_FP, AMO},
B_TYPE = { BRANCH, JALR},
U_TYPE = { AUIPC, LUI, OP_32},
J_TYPE = { JAL, SYSTEM }
} instruction_type;
This I want to include in multiple different modules E.G instruction decode and the ALU, however it appears Vivado does not recognise this or include it in the Design Sources as the file itself does not include any module of its own. I was hoping that there would be some neat solution for this?
I tried to include the package in the current top design source with:
import opcodes::base_opcode_map;
module instruction_decode(
input [31:0] inst,
output base_opcode_map [6:0] opcode,
// others
output reg [31:0] imm
);
assign opcode = base_opcode_map'(inst[6:2]);
always # * begin
case (opcode)
I_TYPE : begin
imm[0] <= inst[20];
imm[4:1] <= inst[24:21];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
// continued
However the compiler flags each of the conditional branches i.e I_TYPE : begin with an error saying [Synth 8-36] 'I_TYPE' is not declared ["C:/Users/lyndo/OneDrive/Documents/code/isa/risc_v/risc_v.srcs/sources_1/new/instruction_decode.sv":18] what should I do in this situation to get the IDE to recognise the file in the design sources?

Directly importing an enum typedef does import all of its associated names because an enum does not create an enclosing scope. You have to explicitly import each name along with the enum typedef, or you can use a wildcard import:
import opcodes::*;
Also, I'm not sure what you are trying to do with the enum instruction_type. You cannot nest enumeration encodings like that. There all need to be 5-bit encodings.

Related

How to vary a struct going through a port in system verilog - generate doesnt work

module testy
#(
parameter W = 10,
parameter C = 2
)
(
aa
);
generate
if (W == 8)
begin:W8
if(C == 1)
begin:W8C1
typedef struct {
logic [8:0] so;
}my_struct;
end
if(C == 2)
begin:W8C2
typedef struct {
logic [10:0] so;
}my_struct;
end
end
endgenerate
input my_struct aa;
endmodule
I get this error:
irun(64): 14.20-p001: (c) Copyright 1995-2015 Cadence Design Systems, Inc.
file: testy.v
input my_struct aa;
|
ncvlog: *E,SVNOTY (testy.v,30|14): Syntactically this identifier appears to begin a datatype but it does not refer to a visible datatype in the current scope.
module worklib.testy:v
errors: 1, warnings: 0
ncvlog: *F,NOTOPL: no top-level unit found, must have recursive instances.
irun: *E,VLGERR: An error occurred during parsing. Review the log file for errors with the code *E and fix those identified problems to proceed. Exiting with code (status 2).
I thought generates were statically determined but I have problems compiling it - since parameters cant be overridden in packages and couldn't think of a way to do this in design which needs to be synthesized and didn't want to add interfaces or classes. Is there a bettwe way to do this. My struct has over 100 entries if I include all the combinations and use only what I want but I thought using generates I could trim it to what I want based on a set of parameters.
Thanks
Your problem is the scope of the typedef is local to the blocks inside your generate statements. If all you need to do is change the size of a data type, you can use a constant function call, with is statically determined. But then you run into another problem with your unpacked struct declaration - it is still local to the module and you will not be able to connect another struct to it with a matching data type. An interface would be a better solution and is synthesizable.
Another possibility is passing down a type parameter.

Using an array of parameters to generate modules

I have a module which stores a bitmap of different characters, that I am planning on using to display text on a matrix. Currently, the bitmap is populated with a memory initialization file, and this file is passed in as a parameter (I have confirmed this working in Quartus and ModelSim).
In order to actually have a lookup table for all the characters, I wanted to make a separate module which has instantiations of the all bitmaps, and selects the correct one based on a character code. These bitmap instantiations are created in a generate block, and they take the correct filename from an array. However, ModelSim doesn't like this. My code is as follows:
module mem_char_disp_lib(
output logic pixel,
input logic [4:0] x,
input logic [5:0] y,
input logic [6:0] code,
input logic clk
);
localparam CHAR_NUM = 26;
logic [CHAR_NUM-1:0] alphabet;
const var [CHAR_NUM-1:0] BITMAPS = {
"/mem/char/A.hex",
"/mem/char/B.hex",
"/mem/char/C.hex",
// ... a lot more declarations here...
"/mem/char/X.hex",
"/mem/char/Y.hex",
"/mem/char/Z.hex"
};
genvar i;
generate
for (i=0; i<CHAR_NUM; i=i+1) begin : mem_char_disp_blocks
mem_char_disp #(.BITMAP(BITMAPS[i])) block (
.pixel(alphabet[i]),
.x, .y, .clk,
.code(i),
.data(1'b0),
.write_en(1'b0)
);
end
endgenerate
always_comb
pixel = alphabet[code];
endmodule
The error ModelSim is giving me is:
The expression for a parameter actual associated with the parameter name ('BITMAP') for the module instance ('block') must be constant.
(referring to the line inside the for loop)
I am not sure why this doesn't work. On a hardware level, it seems like I'm just making a lot of copies of a module, and slightly tweaking each one with a constant parameter known at compile-time. Is there some basic syntax that I'm missing?
Edit: I have also tried the following code, which seems to give a runtime error:
for (i=0; i<CHAR_NUM; i=i+1) begin : mem_char_disp_blocks
parameter [CHAR_NUM-1:0] BITMAPS = {
"/mem/char/A.hex",
// more elements...
"/mem/char/Z.hex"
};
mem_char_disp #(.BITMAP(BITMAPS[i])) block (
.pixel(alphabet[i]),
.x, .y, .clk,
.code(i),
.data(1'b0),
.write_en(1'b0) );
end
The error is Module parameter 'BITMAP' not found for override. (One of these errors for each of the generated modules; CHAR_NUM total.) This doesn't make sense to me, since instantiating a single one directly works just fine (e.g. mem_char_disp #(.BITMAP("/mem/char/A.hex") block /* ... */).
A const variable is not a constant - it is a write-once variable that gets initialized at runtime when the variable gets allocated. You need to us a parameter or localparam to assign to another parameter as you discovered in your update. You also need to fix the dimensions of the array
parameter bit [1:15*8] BITMAPS[26] = {
"/mem/char/A.hex", // 15 8-bit chars
// more elements...
"/mem/char/Z.hex" // 26 elements
};
Can't help you with your last error without seeing the declaration of the module mem_char_disp

verilog set bus equal to array of struct bits

I'm trying to set a bus equal to a bit of a struct, for an array of structs (s.t. the array size == bus size). My struct looks like
typedef struct {
//other stuff
logic valid;
} BFRAME_OUTPUT;
And I've declared the array of structs and bus like
BFRAME_OUTPUT bframe_outs[`BSTACK_SIZE-1:0];
logic [`BSTACK_SIZE-1:0] valid;
I want to do something like either of these to simply make the valid bus equal to the valid bits for the array of structs.
assign valid[`BSTACK_SIZE-1:0] = bframe_outs[`BSTACK_SIZE-1:0].valid;
//
// or
//
for(int i = 0; i < `BSTACK_SIZE; ++i) begin
assign[i] = bframe_outs[i].valid;
end
However I get errors when trying to simulate with vcs:
Error-[XMRE] Cross-module reference resolution error
/modules/branch_stack.sv, 87
Error found while trying to resolve cross-module reference.
token 'bframe_outs'. Originating module 'branch_stack'.
Source info: assign valid[(16 - 1):0] = bframe_outs[(16 - 1):0].valid;
More importantly, there is another error which you have not shown:
Error-[PSNA] Part Select Not Allowed testbench.sv, 14 Part selects
are not allowed on arrays of classes. Source info: assign valid[(5 -
1):0] = bframe_outs[(5 - 1):0].valid; Convert the part select to
refer to each element individually.
As the error points out, you need to convert the assignment to part selection. Here, you can use one of the two ways. Either use logic as reg and use it in always block, or use logic as wire and do some other stuff.
While using it as reg, you need to extract the value in some procedural block. So, just remove the assign statement and use alway_comb. Since you have used logic here, no need to change its datatype.
always_comb
begin
for(int i = 0; i < `BSTACK_SIZE; ++i)
valid[i] = bframe_outs[i].valid;
end
Alternatively, there is a generate block to perform certain things multiple times. Note that by using generate block, you are providing continuous assignments and using logic as wire. Here, you need to provide each bit signal to the wire individually. Here, use generate as follows:
genvar i;
generate
for(i = 0; i < `BSTACK_SIZE; ++i) begin
assign valid[i] = bframe_outs[i].valid;
end
endgenerate
Refer to SystemVerilog IEEE 1800-2012 section 7.2 for structures and this link for generate blocks. I have created a working example at EDAPlayground link.

Tick-including a header file inside package in systemverilog

Hi I've following scenario and it's not working for me.
file: a.svh
a.svh defines some parameters and functions- let's say function xyz(b)
file b.sv
package b;
`include "a.svh"
typedef logic[(xyz(10)-1):0] h;
endpackage
Now the issue is, b.sv can't find xyz function in it's scope, even thought I'm tick-including a.svh in b.sv. Everything works fine if I don't use a package in b.sv file. (comment out package b and endpackage lines).
//package b;
`include "a.svh"
typedef logic[(xyz(10)-1):0] h;
//endpackage
Is it an illigal case in systemverilog?
I recreated your scenario on EDAplayground. I didn't get any errors.
A function is intended to be evaluated during simulation. Some simulators support evaluating function during compile/elaboration, but it doesn't appear to be a requirement.
SystemVerilog also has let, which is more appropriate for for compile time evaluation (it supports simulation time as well). Refer to IEEE Std 1800-2012 § 11.13 Let construct:
let declarations can be used for customization and can replace the text macros in many cases. The let construct is safer because it has a local scope, while the scope of compiler directives is global within the compilation unit. Including let declarations in packages (see Clause 26) is a natural way to implement a well-structured customization for the design code.
a.svh
function int xyz_func(int b);
return b;
endfunction
let xyz_let(b) = b;
design.sv (equivalent to your b.sv, EDAplayground requires design.sv to exist)
package b;
`include "a.svh"
typedef logic[(xyz_func(10)-1):0] hf;
typedef logic[xyz_let(10):1] hl;
endpackage
testbench.sv
module tb;
import b::*;
hf myhf;
hl myhl;
initial begin
myhf = -1;
myhl = -1;
$display("hf:%b left:%0d right:%0d", myhf, $left(myhf), $right(myhf));
$display("hl:%b left:%0d right:%0d", myhl, $left(myhl), $right(myhl));
end
endmodule
Output:
hf:1111111111 left:9 right:0
hl:1111111111 left:10 right:1

Can I synthesize a parameterized function in systemverilog where structure is used as a parameter?

I was trying to synthesize a parameterized function where a structure is given as a parameter. I get the following error in the beginning of the parameterized function
"Syntax error at or near token 'virtual'."
I was trying to compile this simple package.
package def;
typedef struct packed {
logic[10:0] SIZE1;
logic[10:0] SIZE2;
} my_struct;
endpackage
import def::*;
virtual class my_class #(parameter my_struct new_struct = '{10,11});
static function [new_struct.SIZE2-1:0] adder (input [new_struct.SIZE1-1:0] a, b);
return a+b;
endfunction
endclass
module top
#(parameter my_struct new_struct2 = '{63,64})
(input logic [new_struct2.SIZE1-1:0] a, b,
output logic [new_struct2.SIZE2-1:0] y) ;
assign y = my_class #(.new_struct(new_struct2))::adder(a,b);
endmodule
Am I doing something wrong? Or this feature is not supported in Synopsys DC?
(Update: The code has been updated, this one can be synthesized with Synopsys DC)
According to http://www.sutherland-hdl.com/papers/2013-SNUG-SV_Synthesizable-SystemVerilog_paper.pdf § 5.6.7 Parametrized task/function arguments using static classes, the class must be virtual and defined in the $unit declaration space. This means the class cannot be defined inside a package. It is a weird requirements, as the paper points out.
Try moving the class out of the package. You could also try importing the function the the $unit scope, but not sure is this will work.
...
endpackage : def
import def::my_class; // or def::*;
...

Resources