Expected unique0-if behavior inside a for loop - system-verilog

I am creating a parameterized module to direct register traffic to multiple targets. The parameters are the number of targets and the address ranges that each target responds to. I have coded this as an if inside of a for loop with default values set before the loop to handle the case where no address matches. I would like to use unique0 to clarify that the ranges cannot overlap so this will not be implemented a a priority mux:
always_comb begin
valid_addr = 1'b0;
active_target = '0;
target_addr = '1;
for(int i = 0; i<NUM_TARGETS; i++) begin
unique0 if((addr >= START_ADDR[i]) && (paddr < (START_ADDR[i] + ADDR_SPAN[i]))) begin
valid_addr = 1'b1;
active_target = i;
target_addr = addr - START_ADDR[i];
end
end
end
The question is: will this unique0 do what I want? I am hoping that this is equivalent to the unrolled loop implemented as something like:
unique0 if ((addr >= START_ADDR[0]) && (paddr < (START_ADDR[0] + ADDR_SPAN[0]))) begin
valid_addr = 1'b1;
active_target = 0;
target_addr = addr - START_ADDR[0];
end
else if ((addr >= START_ADDR[1]) && (paddr < (START_ADDR[1] + ADDR_SPAN[1]))) begin
valid_addr = 1'b1;
active_target = 1;
target_addr = addr - START_ADDR[1];
end
else begin
valid_addr = 1'b0;
active_target = '0;
target_addr = '1;
end
I already have a problem since this will not compile with unique0 but will compile with unique so that either answers my question or my simulator just doesn't like it for some reason:
unique0 if((addr >= START_ADDR[i]) && (addr < (START_ADDR[i] + ADDR_SPAN[i]))) begin
|
expecting an '=' or '<=' sign in an assignment [9.2(IEEE)].

in order to do what your unrolled statement implies and to make it synthesizable, you would need to use a match flag. Something like in the following:
logic match_flag; //<<<
always_comb begin
match_flag = 1'b0; //<<<
valid_addr = 1'b0;
active_target = '0;
target_addr = '1;
for(int i = 0; i<NUM_TARGETS; i++) begin
if(!match_flag && (addr >= START_ADDR[i]) && (paddr < (START_ADDR[i] + ADDR_SPAN[i]))) begin
valid_addr = 1'b1;
active_target = i;
target_addr = addr - START_ADDR[i];
match_flag = 1'b1; //<<<
end
end
end
some synthesizers might support the break statement which could be used instead of the flag. Check documentation.

Related

Is there a way to simplify the case logic for an enum in verilog?

I'm looking to simplify an expression for decoding the opcode for a risc v microcontroller:
always # * begin
case (opcode)
LOAD | LOAD_FP | MISC_MEM | OP_IMM OP_IMM_32 : begin // I_TYPE
imm[0] <= inst[20];
imm[4:1] <= inst[24:21];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
STORE | STORE_FP | AMO : begin // S_TYPE
imm[0] <= inst[7];
imm[4:1] <= inst[11:8];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
BRANCH, JALR : begin // B_TYPE
imm[0] <= 0;
imm[4:1] <= inst[11:8];
imm[10:5] <= inst[30:25];
imm[11] <= inst[7];
imm[31:12] <= inst[31];
end
AUIPC, LUI, OP_32 : begin // U_TYPE
imm[11:0] <= 0;
imm[19:12] <= inst[19:12];
imm[30:20] <= inst[30:25];
imm[31] <= inst[31];
end
JAL, SYSTEM : begin // J_TYPE
imm[0] <= 0;
imm[4:1] <= inst[24:21];
imm[10:5] <= inst[30:25];
imm[11] <= inst[20];
imm[19:12] <= inst[19:12];
imm[31:20] <= inst[30];
end
default :
imm <= 0;
endcase
end
to somewthing like this:
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
S_TYPE : begin
imm[0] <= inst[7];
imm[4:1] <= inst[11:8];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
// ...continued
default :
imm <= 0;
endcase
end
Is this possible, can I add methods to an enum/class like in c++, is this worth doing, if so how?
this is my enum:
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,
STORE = 5'b01_000, STORE_FP = 5'b01_001, CUSTOM_1 = 5'b01_010, AMO = 5'b01_011, OP = 5'b01_100, LUI = 5'b01_101, OP_32 = 5'b01_110, OP_64 = 5'b01_111,
MADD = 5'b10_000, MSUB = 5'b10_001, NMSUB = 5'b10_010, NMADD = 5'b10_011, OP_FP = 5'b10_100, RESERVED_6 = 5'b10_101, CUSTOM_2 = 5'b10_110, OP_48_2 = 5'b10_111,
BRANCH = 5'b11_000, JALR = 5'b11_001, RESERVED_A = 5'b11_010, JAL = 5'b11_011, SYSTEM = 5'b11_100, RESERVED_D = 5'b11_101, CUSTOM_3 = 5'b11_110, OP_80 = 5'b11_111
} base_opcode_map;
If not can somebody tell me the kind of pattern I need to follow?
There are a few things you can do. You can use a let construct
let I_TYPE = opcode inside {LOAD, LOAD_FP, MISC_MEM, OP_IMM, OP_IMM_32};
let S_TYPE = opcode inside {STORE, STORE_FP, AMO};
...
let is a shorthand for defining a simple function
function bit I_TYPE;
return opcode inside {LOAD, LOAD_FP, MISC_MEM, OP_IMM, OP_IMM_32};
endfunction
function bit S_TYPE;
return opcode inside {STORE, STORE_FP, AMO};
endfunction
Then you can write a case statement
always # * begin
case (1'b1)
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
S_TYPE : begin
imm[0] <= inst[7];
imm[4:1] <= inst[11:8];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
// ...continued
default :
imm <= 0;
endcase
end

verilog with out control variables cnt

module count(clk,rst,cnt);
want to wrire the verilog code which counts upto 7 and then down to
0 and repeats forever as follows. 0,1,2,3,4,5,6,7,6,5,4,4,3,2,1
endmodule
Blockquote
Repeat state 4 for two times while counting down:
module count(
input clk,
input rst,
output cnt
);
reg [2:0] counter;
assign cnt = counter;
// Count up if flag is 1'b0, count down if flag is 1'b1
wire flag;
assign flag = (counter == 3'b1) ? 1'b1 : (counter == 3'b0) ? 1'b0;
// Repeat counter once if special_flag is 2'b01
reg [1:0] special_flag;
always #(posedge clk)
begin
if (flag == 1'b0)
begin
counter = counter + 1;
end
else if (counter == 3'b100 && special_flag == 2'b01)
begin
// Do not decrease counter, reset special_flag back to 2'b0
special_flag = 2'b0;
end else
begin
counter = counter - 1;
end
// Set special_flag to be 2'b01 when counter is 3'b1
if (counter == 3'b1)
begin
special_flag = 2'b01;
end
end
endmodule
module count(
input clk,
input rst,
output cnt
);
reg [2:0] counter;
assign cnt = counter;
// Count up if flag is 1'b0, count down if flag is 1'b1
wire flag;
assign flag = (counter == 3'b1) ? 1'b1 : (counter == 3'b0) ? 1'b0;
always #(posedge clk)
begin
if (flag == 1'b0)
begin
counter = counter + 1;
end
if (flag == 1'b1)
begin
counter = counter - 1;
end
end
endmodule

SystemVerilog error: "already exists; must not be redefined as a named block"

I'm creating a state machine with implicit datapath and am getting three errors that I haven't been able to resolve.
For the endcase error, I've made sure that all the begins have a corresponding end in the always block.
For the Finish error, the state has only been defined once so I'm not sure about that.
For the ; error, I have no idea why it doesn't want me to include countx and county statements.
Any help would be appreciated!
module fillscreen(input logic clk, input logic rst_n, input logic [2:0] colour,
input logic start, output logic done,
output logic [7:0] vga_x, output logic [6:0] vga_y,
output logic [2:0] vga_colour, output logic vga_plot);
enum logic [1:0] {Load = 2'b00, Increment = 2'b01, Out = 2'b10, Finish = 2'b11} state, next_state;
logic [7:0] countx, county;
always # (posedge clk) begin
case(state)
Load:
if(rst_n == 0)
next_state <= Load;
else if (start == 1)
next_state <= Increment;
else begin
next_state <= Load; end
//initialize counter
countx <= 0;
county <= 0;
Increment:
if(rst_n == 0)
next_state <= Load;
else if (county < 119 && countx < 159) begin
county <= county+1;
next_state <= Increment; end
else if (countx < 159) begin
countx <= countx +1;
next_state <= Increment; end
else
next_state <= Finish;
//output
vga_y <= county;
vga_x <= countx;
vga_colour <= countx % 8;
vga_plot <= 1;
Finish:
done <= 1;
if(rst_n == 0)
next_state <= Load;
else begin
next_state = Finish; end
Default:
vga_y <= county;
vga_x <= countx;
done <= 0;
vga_plot <= 0;
endcase
end
endmodule
Here are the errors I'm getting:
** Error: fillscreen.sv(22): near ";": syntax error, unexpected ';', expecting ':'
** Error: fillscreen.sv(54): near "endcase": syntax error, unexpected endcase
** Error: fillscreen.sv(25): 'Increment' already exists; must not be redefined as a named block
** Error fillscreen.sv(43): 'Finish' already exists; must not be redefined as a named block
For any case, you need to include begin..end if the code block for that case has multiple lines, just like if-statements or always blocks (see comments inline, there more than just missing begin..end):
case(state) // <- Note, you never assign state, only next_state, might want to review your code for correctness
Load: begin // <- This case has multiple lines
if (rst_n == 0) begin // <- I do begin..end for EVERYTHING as I inevitably come back and add lines in the body which can lead to bugs if there is no begin..end, like {..} in C
next_state <= Load;
end
else if (start == 1) begin
next_state <= Increment;
end
else begin
next_state <= Load;
end
//initialize counter
countx <= 0;
county <= 0;
end
Increment: begin
if (rst_n == 0) begin
next_state <= Load;
end
else if (county < 119 && countx < 159) begin
county <= county+1;
next_state <= Increment;
end
else if (countx < 159) begin
countx <= countx +1;
next_state <= Increment;
end
else begin
next_state <= Finish;
end
//output
vga_y <= county;
vga_x <= countx;
vga_colour <= countx % 8;
vga_plot <= 1;
end
Finish: begin
done <= 1;
if (rst_n == 0) begin
next_state <= Load;
end
else begin
next_state <= Finish; // Should be non-blocking
end
end
default: begin // <- Should be lower-case "default"
vga_y <= county;
vga_x <= countx;
done <= 0;
vga_plot <= 0;
end
endcase

If condition with externally selected value

I'm new to Verilog and it is maybe a dumb question but what is the preferred codeflow in Verilog to solve this problem:
Simple counter, counting external clk (INP) up to a particular value. If the counter matches the value it rises an output wire (DRDY) for one clk period then lowers it to 0. There is an external input (SR) where I'd like to set the comparison value, so if SR = 0, then the counting is up to 500000, if SR = 1 then up to 1000000. I can do it with one value, but I'd like to expand the functionality of my module.
Thank you in advance.
My code so far with one value comparison:
module ec(INP, RST, SR, DRDY, DRDY2);
input INP, RST, SR;
output reg DRDY, DRDY2;
reg [23:0] Q;
always #(posedge INP or negedge RST)
begin
if(!RST)
begin
Q <= 24'd0;
DRDY <= 1'b0;
end
else if( Q == 24'd1000000)
begin
Q <= 24'd0;
DRDY <= 1'b1;
DRDY2 <=~DRDY2;
end
else
begin
Q <= Q + 1;
DRDY <= 1'b0;
end
end
endmodule
An easy way to handle 2 options would be an expand the if statement:
always #(posedge INP or negedge RST) begin
if(!RST) begin
Q <= 24'd0;
DRDY <= 1'b0;
end
else if(
( (SR ==1'b0) && (Q == 24'd1000000) ||
(SR ==1'b1) && (Q == 24'd500000)
) begin
//...
end
else begin
//..
end
This can look quite messy in the code so could be separated out into a count target logic, if more options are to be supported then switch to a case statement instead of if.
reg [23:0] cnt_target ;
always #* begin
if (SR == 1'b1) begin
cnt_target = 24'd1000000 ;
else begin
cnt_target = 24'd500000 ;
end
end
always #(posedge INP or negedge RST) begin
if(!RST) begin
Q <= 24'd0;
DRDY <= 1'b0;
end
else if( Q == cnt_target) begin
//...
end
else begin
//..
end
NB: You might want to consider using Q >= cnt_target that way if SR changed on the fly you do not have to wait for Q to overflow. Plus >= for me tends to synthesis smaller than ==.

How to connect components of VHDL code

I have 2 components that have worked separately in simulation, but now I'm confused on how to implement the design onto my board. I have one design that is a binary to 7-segment display, and another that is a counter that counts upwards in seconds.
How do I connect these two to work together to show values onto a basys2 board?
Code for timer
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY clock IS
port(reset,clk,start,stop:in std_logic;
min,sec:out integer);
end clock;
architecture behaviour of clock is
begin
process(reset,clk,start,stop)
variable tempmin,tempsec:integer:=0;
begin
if(reset='1')then
tempmin:=0;
tempsec:=0;
elsif(stop='1')then
min<=tempmin;
sec<=tempsec;
elsif(start='1')then
if(rising_edge(clk))then
tempsec:=tempsec+1;
if(tempsec=60)then
tempsec:=0;
tempmin:=tempmin+1;
if(tempmin=10)then
tempmin:=0;
end if;
end if;
end if;
end if;
min<=tempmin;
sec<=tempsec;
end process;
end behaviour;
Code for binary to 7-segment
architecture Behavioral of SevenSegment is
begin
process (seg_value)
begin
if (seg_value = "0000") then
seg <= "0000001";
an <= "1100";
elsif (seg_value = "0001") then
seg <= "1001111";
an <= "1100";
elsif (seg_value = "0010") then
seg <= "0010010";
an <= "1100";
elsif (seg_value = "0011") then
seg <= "0000110";
an <= "1100";
elsif (seg_value = "0100") then
seg <= "1001100";
an <= "1100";
elsif (seg_value = "0101") then
seg <= "0100100";
an <= "1100";
elsif (seg_value = "0110") then
seg <= "0100000";
an <= "1100";
elsif (seg_value = "0111") then
seg <= "0001111";
an <= "1100";
elsif (seg_value = "1000") then
seg <= "0000000";
an <= "1100";
elsif (seg_value = "1001") then
seg <= "0000100";
an <= "1100";
end if;
end process;
end Behavioral;
Look up the syntax for component instantiation (or entity instantion) in your VHDL textbook. Emacs VHDL mode and Sigasi provide power-templates so you don't have to type so much code: http://www.sigasi.com/screencast/entity-instantiation