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

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

Related

Expected unique0-if behavior inside a for loop

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.

(vhdl) expected type = current type type error

I keep getting an error that says:
line 25: type error near num_values ; current type unsigned; expected
type unsigned.
It is already the type that is supposed to be, and I think it is same in bit length and declared alright, what am I doing wrong here?
The code is about implementation of fifo queue structure.
<Queue.vhd>
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Queue is
port (
-- clock
clk: in std_logic;
-- input
push: in std_logic;
push_data: in std_logic_vector(31 downto 0);
pop: in std_logic;
-- output
pop_data: out std_logic_vector(31 downto 0);
num_values: out unsigned(31 downto 0)
);
end entity;
architecture Behavioral of Queue is
type items is array(0 to 31) of std_logic_vector(31 downto 0);
signal manager : items := (others => (others => '0'));
signal push_idx, pop_idx : integer := 0;
begin
process(clk) is
variable howmany : integer := 0;
begin
if rising_edge(clk) then
if (push = '1') then
manager(push_idx) <= push_data;
push_idx <= push_idx + 1;
howmany := howmany + 1;
end if;
if (pop = '1') then
if (howmany /= 0) then
pop_data <= manager(pop_idx);
pop_idx <= pop_idx + 1;
howmany := howmany - 1;
end if;
else
pop_data <= std_logic_vector(to_unsigned(0,pop_data'length));
end if;
if (push_idx = 31) then
push_idx <= 0;
end if;
if (pop_idx = 31) then
pop_idx <= 0;
end if;
num_values <= to_unsigned(howmany,32);
end if;
end process;
end architecture;
<QueueTb.vhd>
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity QueueTb is
end entity;
architecture sim of QueueTb is
constant ClockFrequency : integer := 100e6;
constant ClockPeriod : time := 1000ms / ClockFrequency;
signal clk : std_logic := '0';
signal push, pop : std_logic := '0';
signal num_values : unsigned(31 downto 0);
signal push_data, pop_data : std_logic_vector(31 downto 0) := (others =>'0');
begin
UUT : entity work.Queue(Behavioral)
port map(
clk => clk,
push => push,
pop => pop,
num_values => num_values, <=== this is where error occurs!
push_data => push_data,
pop_data => pop_data);
clk <= not clk after ClockPeriod / 2;
process is
begin
wait for 10 ns;
push <= '1';
push_data <= conv_std_logic_vector(123,32);
wait for 10 ns;
push_data <= conv_std_logic_vector(456,32);
wait for 10 ns;
push <= '0';
push_data <= conv_std_logic_vector(0,32);
pop <= '1';
wait for 10 ns;
pop <= '0';
push <= '1';
push_data <= conv_std_logic_vector(789,32);
wait for 10 ns;
push <= '0';
pop <= '1';
wait for 80 ns;
end process;
end architecture;
What am I doing wrong here??
In the Queue entity you are using ieee.numeric_std and in the QueueTB you are using ieee.std_logic_arith . Both define different unsigned types.
Delete std_logic_arith from the testbench as it is not a standard VHDL library and use numeric_std instead.

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

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

VHDL: with-select for multiple values

I have the following code (it encodes a number of a pressed button):
with buttons select
tmp <= "000" when x"1",
"001" when x"2",
"010" when x"4",
"011" when x"8",
"100" when others;
code <= input(1 downto 0);
error <= input(2);
I am trying to rewrite it without using tmp signal. Is it possible? The following doesn't work:
with buttons select
error & code <= "000" when x"1",
"001" when x"2",
"010" when x"4",
"011" when x"8",
"100" when others;
Instead of with select, you could use case:
my_process_name : process(buttons)
begin
case buttons is
when x"1" =>
error <= '0';
code <= "00";
when x"2" =>
error <= '0';
code <= "01";
when x"4" =>
error <= '0';
code <= "10";
when x"8" =>
error <= '0';
code <= "11";
when others =>
error <= '1';
code <= "00";
end case;
end process;
Or you could just write this as 2 separate with/when statements:
with buttons select
error <= '0' when x"1",
'0' when x"2",
'0' when x"4",
'0' when x"8",
'1' when others;
with buttons select
code <= "00" when x"1",
"01" when x"2",
"10" when x"4",
"11" when x"8",
"00" when others;
or alternatively:
error <= '0' when (buttons = X"1" or buttons = X"2" buttons = X"4" buttons = X"8") else '1';
code <= "00" when buttons = X"1" else "01" when buttons = X"2" else "10" when buttons = X"4" else "11" when buttons = X"8" else "00";
VHDL is a compiled language - or synthesised. Any format is OK as long as the synthesis tool creates the relevant logic construct. The rest is symantics to allow code to be understood and maintained.