Why won't my VHDL state machine perform subtraction? - vhdl

This is a simulation of a long division binary divider. The program performs as expected except it will not subtract the divisor from the 5 MSBs of the register no matter how I code it.
Following is the code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
ENTITY divider IS
PORT(
Clock :IN STD_LOGIC;
Dividend :IN STD_LOGIC_VECTOR(7 DOWNTO 0);
Divisor :IN STD_LOGIC_VECTOR(4 DOWNTO 0);
Reset :IN STD_LOGIC;
St :IN STD_LOGIC;
outDRegister :OUT STD_LOGIC_VECTOR(8 DOWNTO 0):="000000000";
outCurrentState :OUT STD_LOGIC_VECTOR(2 DOWNTO 0):="000";
Quotient :OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
Remainder :OUT STD_LOGIC_VECTOR(4 DOWNTO 0));
END divider;
ARCHITECTURE Behavior of divider IS
SIGNAL DRegister :STD_LOGIC_VECTOR(8 DOWNTO 0);
SIGNAL SubOut :STD_LOGIC_VECTOR(4 DOWNTO 0);
Signal C,ShiftIn, ShiftRes :STD_LOGIC;
Signal ShiftEnable :STD_LOGIC;
Signal tempSt :STD_LOGIC:='1';
TYPE State_type IS (S0, S1, S2, S3, S4, S5);
SIGNAL y:State_type:=S0;
BEGIN
PROCESS(Dividend,Divisor,y, st, reset, clock) IS
BEGIN
If (Reset='0') THEN
Y<=S0;
ELSIF (Clock'EVENT and CLOCK = '1') THEN
CASE y IS
WHEN S0=>
IF(st='0' AND tempSt='1' AND reset = '1') THEN
DRegister <= '0'&Dividend;
y<=S1;
ELSIF(st='1' AND reset = '1') THEN
Quotient <= DRegister(3 DOWNTO 0);
Remainder <= DRegister(8 DOWNTO 4);
y<=S0;
END IF;
outDRegister<=DRegister;
outCurrentState<="000";
tempSt<=st;
WHEN S1=>
IF(DRegister(8 DOWNTO 4)>=Divisor) THEN
y<=S0;
ELSE
DRegister <= (DRegister(7 DOWNTO 0) & '0');
y<=S2;
END IF;
outDRegister<=DRegister;
outCurrentState<="001";
WHEN S2=>
IF(DRegister(8 DOWNTO 4)>=Divisor) THEN
DRegister(8 DOWNTO 4)<=(DRegister(8 DOWNTO 4) - Divisor);--Does not work!! Does nothing.
DRegister <= DRegister(7 DOWNTO 0) & '1';
ELSE
DRegister <= DRegister(7 DOWNTO 0) & '0';
END IF;
outDRegister<=DRegister;
outCurrentState<="010";
y<=S3;
WHEN S3=>
IF(DRegister(8 DOWNTO 4)>=Divisor) THEN
DRegister(8 DOWNTO 4)<=(DRegister(8 DOWNTO 4) - Divisor);--Does not work!! Does nothing.
DRegister <= DRegister(7 DOWNTO 0) & '1';
ELSE
DRegister <= DRegister(7 DOWNTO 0) & '0';
END IF;
outDRegister<=DRegister;
outCurrentState<="011";
y<=S4;
WHEN S4=>
IF(DRegister(8 DOWNTO 4)>=Divisor) THEN
DRegister(8 DOWNTO 4)<=(DRegister(8 DOWNTO 4) - Divisor);--Does not work!! Does nothing.
DRegister <= DRegister(7 DOWNTO 0) & '1';
ELSE
DRegister <= DRegister(7 DOWNTO 0) & '0';
END IF;
outDRegister<=DRegister;
outCurrentState<="100";
y<=S5;
WHEN S5=>
IF(DRegister(8 DOWNTO 4)>=Divisor) THEN
DRegister(8 DOWNTO 4)<=(DRegister(8 DOWNTO 4) - Divisor);--Does not work!! Does nothing.
END IF;
outDRegister<=DRegister;
outCurrentState<="101";
y<=S0;
END CASE;
END IF;
END PROCESS;
END Behavior;

First step is to read up on the difference between variable and signal assignment in VHDL. Your problem lies there. One solution involves an intermediate variable for the problem states; another involves rewriting a signal assignment.
My usual explanation is here, there's a link at the bottom of the page to "VHDL's Crown Jewel" which is also very well worth reading.
Also note:
There are better libraries for arithmetic : ieee.numeric_std rather than std_logic_unsigned or std_logic_arith or (worst of all) mixing the two.
There are better data type for arithmetic than std_logic_vector : ieee.numeric_std.unsigned (or signed), or even subtypes of integer or natural;
As you are writing a nice clean single-process state machine, its sensitivity list ONLY needs clock, reset
You can lose the parentheses around conditional expressions, If Reset='0' Then is fine (this is not your father's C compiler)
rising_edge(Clock) is preferred to Clock'EVENT and CLOCK = '1'
but these are all peripheral to the main issue.

The problematic code part, as you also marked, is:
...
DRegister(8 downto 4) <= (DRegister(8 downto 4) - Divisor); --Does not work!! Does nothing.
DRegister <= DRegister(7 downto 0) & '1';
...
In VHDL, the value of a signal is not updated until the end of the current
simulation cycle, so the value of DRegister used in the second assign to
DRegister above is not altered by the first assign to DRegister.
So, the effect of the first assign to DRegister(8 downto 4) is overridden by
the second assign to all bits in DRegister, whereby the subtraction of the
Divisor does not have any effect.
One way to correct the code, so to make only a single assign to all DRegister bits.
You may want to take a look at David Koontz answer at
https://stackoverflow.com/a/20104800/2352082 since this covers a similar issue.

Related

VHDL-can't add numbers?

Hello I want to build a clock on my ALTERA DE2 that I can adjust the length of by pressing keys.
Now the problem is that when I convert from STD_LOGIC_VECTOR to UNSIGNED the code does not work:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--use ieee.std_logic_unsigned.all; Do not use with numeric_std
entity Adjust_Clock_4_buttens is
port(
clk,clk1 : in STD_LOGIC;
minutes_plus, minutes_minus,houres_plus,houres_minus : in STD_LOGIC;
minutes : IN STD_LOGIC_VECTOR(5 downto 0);
houres : IN STD_LOGIC_VECTOR(4 downto 0);
output_minutes : out STD_LOGIC_VECTOR(5 downto 0);
output_houres : out STD_LOGIC_VECTOR(4 downto 0);
LED_0 : OUT STD_LOGIC;
LED_1 : OUT STD_LOGIC;
LED_2 : OUT STD_LOGIC;
LED_3 : OUT STD_LOGIC
);
end entity Adjust_Clock_4_buttens ;
architecture behavioral of Adjust_Clock_4_buttens is
signal button1_r : std_logic_vector(2 downto 0);
signal button2_r : std_logic_vector(2 downto 0);
signal button3_r : std_logic_vector(2 downto 0);
signal button4_r : std_logic_vector(2 downto 0);
-- signal minutes_total : unsigned(5 downto 0) := (others => '0');
-- signal houres_total : unsigned(4 downto 0) := (others => '0');
signal minutes_total : unsigned(5 downto 0);
signal houres_total : unsigned(4 downto 0);
begin
process(clk)
begin
if (rising_edge(clk) )then
minutes_total<=unsigned(minutes);
houres_total<=unsigned(houres);
-- Shift the value of button in button_r
-- The LSB is unused and is there solely for metastability
button1_r <= button1_r(button1_r'left-1 downto 0) & minutes_plus;
button2_r <= button2_r(button2_r'left-1 downto 0) & minutes_minus;
button3_r <= button3_r(button3_r'left-1 downto 0) & houres_plus;
button4_r <= button4_r(button4_r'left-1 downto 0) & houres_minus;
if button1_r(button1_r'left downto button1_r'left-1) = "01" then -- Button1 rising --button1_r[2:1]
minutes_total <= (minutes_total + 1);
LED_0<='1';LED_1<='0';LED_2<='0';LED_3<='0';
elsif button2_r(button2_r'left downto button2_r'left-1) = "01" then -- Button2 rising --button1_r[2:1]
minutes_total <= (minutes_total-1 );
LED_0<='0';LED_1<='1';LED_2<='0';LED_3<='0';
end if;
if button3_r(button3_r'left downto button3_r'left-1) = "01" then -- Button1 rising --button1_r[2:1]
houres_total <= (houres_total + 1);
LED_0<='0';LED_1<='0';LED_2<='1';LED_3<='0';
elsif button4_r(button4_r'left downto button4_r'left-1) = "01" then -- Button2 rising --button1_r[2:1]
houres_total<= (houres_total-1 );
LED_0<='0';LED_1<='0';LED_2<='0';LED_3<='1';
end if;
end if;
end process;
output_minutes <= std_logic_vector(minutes_total);
output_houres <= std_logic_vector(houres_total);
end architecture behavioral ;
So in this code I get the time from another block the problem start when I try to add minutes and hours and for some reason it does not react to pressing of the keys. Could anyone explain maybe why is that?
The problem might be that you only have the clock in the sensitivity list of your process. Try adding the buttons in the sensitivity list, since they drive your if conditions. (Not sure if that's the problem but I guess it's worth a try)
minutes_total<=unsigned(minutes);
is on 2 lines, inside and outside of the process, which generates multiple line drivers, and will not work, ever!
(didn't read the rest of the code, there may be other problems, like hours not taking an e)
Now that it's inside the process, you need to rename minutes_total as minute_source, else you're incrementing the value only for the one clock cycle when you have a button edge!

Implementing a 10 bit shift register with led outputs

I am trying to implement the the following shift register
entity MyShiftRegister is
port(
clock: in std_logic;
DataIn: in std_logic_vector (9 downto 0);
Left: in std_logic; --synchronous left rotate
Right: in std_logic; --synchronous right rotate
Load: in std_logic; --synchronous parallel load
Clear: in std_logic; -- synchronous clear
DataOut: out std_logic_vector (9 downto 0);
This is what I have so far
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity question2 is
Port (
led: buffer std_logic_vector (9 downto 0);
clk: in std_logic;
btnu: in std_logic;
btnL: in std_logic;
btnR: in std_logic ;
btnD: in std_logic;
btnC: in std_logic
);
end question2;
architecture Behavioral of question2 is
constant active: std_logic :='1';
constant inactive: std_logic :='0';
constant step_zero: std_logic_vector(9 downto 0) :="0000000000";
constant step_one: std_logic_vector(9 downto 0) :="0000000001";
constant step_two: std_logic_vector(9 downto 0) :="0000000010";
constant step_three: std_logic_vector(9 downto 0) :="0000000100";
constant step_four: std_logic_vector(9 downto 0) :="0000001000";
constant step_five: std_logic_vector(9 downto 0) :="0000010000";
constant step_six: std_logic_vector(9 downto 0) :="0000100000";
constant step_seven: std_logic_vector(9 downto 0) :="0001000000";
constant step_eight: std_logic_vector(9 downto 0) :="0010000000";
constant step_nine: std_logic_vector(9 downto 0) :="0100000000";
constant step_ten: std_logic_vector(9 downto 0) :="0100000000";
signal DataIn: std_logic_vector (9 downto 0):= "1111111111";
signal Load: std_logic := btnD;
signal Reset: std_logic;
signal Left: std_logic:= btnL;
signal Right: std_logic:= btnR;
signal DataOut: std_logic_vector := led (9 downto 0);
signal Clear: std_logic:= btnU;
signal speed_enable: std_logic;
begin
SpeedControl: process (clk)
variable counter: integer range 0 to 10000000;
begin
speed_enable<=not active;
if Reset = Active then
counter:= 0;
elsif (rising_edge (clk)) then
counter := counter + 1;
if (counter=10000000) then
speed_enable<= Active;
counter:=0;
end if;
end if;
end process;
shiftregister: process(clk, clear)
begin
if rising_edge (clk) then
if clear= active then
DataOut <= (others => '0');
elsif load = active then
DataOut <= DataIn ;
elsif Left = active then
DataOut <= DataOut(8 downto 0) & "1" ;
if DataOut = "1000000000" then
clear <= active;
elsif Right = active then
DataOut <= DataOut (9 downto 1) & "1" ;
if DataOut = "0000000001" then
clear <= active;
end if;
end if;
end if;
end if;
end process;
with DataOut select
led <= step_one when "0000",
step_two when "0001",
step_three when "0010",
step_four when "0011",
step_five when "0100",
step_six when "0101",
step_seven when "0110",
step_eight when "0111",
step_nine when "1000",
step_ten when "1001",
step_zero when others;
end Behavioral;
How exactly do I rotate bits left and right and tie that to my led outputs. I was thinking of using a counter and just incrementing and decrementing to shift bits left or right but I'm not sure if that would still be considered a shift register.
thanks
To start:
constant step_nine: std_logic_vector(9 downto 0) :="0100000000";
constant step_ten: std_logic_vector(9 downto 0) :="0100000000";
is incorrect. It should be
constant step_nine: std_logic_vector(9 downto 0) :="0100000000";
constant step_ten: std_logic_vector(9 downto 0) :="1000000000";
But this approach is very error prone anyhow. Lets simplify it:
process(sel)
variable selected_led : natural;
begin
led <= (others => '0');
selected_led := to_integer(unsigned(sel));
if selected_led < led'length then
led(selected_led) <= '1';
end if;
end process;
If the led(selected_led) <= '1'; won't synthesize, you probably have to change it to
for i in 0 to led'length-1 loop
if (i = selected_led) then
led(i) <= '1';
end if;
end loop;
As for using the buffer port. Don't. preferably only use in or out. If you want to read an out port, compile with VHDL-2008, or use a temporary signal in between.
Then note that right and left are keywords in VHDL. you shouldn't use them
What you want is very simple and basic VHDL. Example (using VHDL-2008):
process(clock)
begin
if rising'edge(clock) then
if clear = '1' then
data_out <= (others => '0');
elsif load = '1' then
data_out <= data_in;
elsif right_rotate = '1' then
data_out <= data_out(0) & data_out(data_out'length-1 downto 1);
elsif left_rotate = '1' then
data_out <= data_out(data_out'length-2 downto 0) &
data_out(data_out'length-1);
end if;
end if;
end process;

VHDL 10 bit Shift Register

I am trying to create a 10 bit shift register. However I keep getting the error
[DRC 23-20] Rule violation (NSTD-1) Unspecified I/O Standard - 2 out of 15 logical ports use I/O standard (IOSTANDARD) value 'DEFAULT', instead of a user assigned specific value. This may cause I/O contention or incompatibility with the board power or connectivity affecting performance, signal integrity or in extreme cases cause damage to the device or the components to which it is connected. To correct this violation, specify all I/O standards. This design will fail to generate a bitstream unless all logical ports have a user specified I/O standard value defined. To allow bitstream creation with unspecified I/O standard values (not recommended), use this command: set_property SEVERITY {Warning} [get_drc_checks NSTD-1]. NOTE: When using the Vivado Runs infrastructure (e.g. launch_runs Tcl command), add this command to a .tcl file and add that file as a pre-hook for write_bitstream step for the implementation run. Problem ports: Clk, btnu.
everytime I got to write the bit stream. Can someone help point me in the right direction and point out any other mistakes I am making that will not allow my shift register to function properly.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity question2 is
Port (
led: out std_logic_vector (9 downto 0);
Clk: in std_logic;
btnu: in std_logic;
btnL: in std_logic;
btnR: in std_logic ;
btnD: in std_logic;
btnC: in std_logic
);
end question2;
architecture Behavioral of question2 is
constant active: std_logic :='1';
constant inactive: std_logic :='0';
constant step_zero: std_logic_vector(9 downto 0) :="0000000000";
constant step_one: std_logic_vector(9 downto 0) :="0000000001";
constant step_two: std_logic_vector(9 downto 0) :="0000000010";
constant step_three: std_logic_vector(9 downto 0) :="0000000100";
constant step_four: std_logic_vector(9 downto 0) :="0000001000";
constant step_five: std_logic_vector(9 downto 0) :="0000010000";
constant step_six: std_logic_vector(9 downto 0) :="0000100000";
constant step_seven: std_logic_vector(9 downto 0) :="0001000000";
constant step_eight: std_logic_vector(9 downto 0) :="0010000000";
constant step_nine: std_logic_vector(9 downto 0) :="0100000000";
constant step_ten: std_logic_vector(9 downto 0) :="0100000000";
signal DataIn: std_logic_vector (9 downto 0):= "0000000001";
signal Load: std_logic := btnD;
signal Reset: std_logic;
signal Left: std_logic:= btnL;
signal Right: std_logic:= btnR;
signal DataOut: std_logic_vector (9 downto 0);
signal Clear: std_logic:= btnU;
signal speed_enable: std_logic;
begin
SpeedControl: process (clk)
variable counter: integer range 0 to 10000000;
begin
speed_enable<=not active;
if Reset = Active then
counter:= 0;
elsif (rising_edge (clk)) then
counter := counter + 1;
if (counter=10000000) then
speed_enable<= Active;
counter:=0;
end if;
end if;
end process;
shiftregister: process(speed_enable, clear, DataIn)
begin
if speed_enable=active then
if clear=active then
DataOut (9 downto 0) <= "0000000000"; --(others=>'0');
elsif load = Active then
DataOut (9 downto 0) <= DataIn ;
elsif Left = Active then
DataOut (9 downto 0) <= DataOut(7 downto 0) & "11" ;
elsif Right = Active then
DataOut (9 downto 0) <= DataOut (9 downto 2) & "11" ;
end if;
end if;
end process;
LEDSTEP: process(DataOut)
begin
if DataOut = "0000000000" then
led <= step_zero;
elsif DataOut = "0000000001" then
led <= step_one;
elsif DataOut = "0000000010" then
led <= step_two;
elsif DataOut = "0000000100" then
led <= step_three;
elsif DataOut = "000001000" then
led <= step_four;
elsif DataOut = "0000010000" then
led <= step_five;
elsif DataOut = "0000100000" then
led <= step_six;
elsif DataOut = "0001000000" then
led <= step_seven;
elsif DataOut = "0010000000" then
led <= step_eight;
elsif DataOut = "0100000000" then
led <= step_nine;
elsif DataOut = "1000000000" then
led <= step_ten;
end if;
end process;
end Behavioral;
As stated in the comments, this is an issue with your design constraints. A detailed description of (and typical solutions to) the problem are outlined in the Xilinx support answers.
However, in this specific instance, you have actually specified the PACKAGE_PIN and IOSTANDARD constraints for the ports that are being complained about (clk and btnU). The issue is actually due to the difference in case between your vhd file and the xdc file (which, due to being Tcl, is case sensitive). In your vhd file, the ports that cause the errors are Clk and btnu - These do not exist in the constraints file.
To resolve this, modify your port declaration to be:
entity question2 is
Port (
led: out std_logic_vector (9 downto 0);
clk: in std_logic;
btnU: in std_logic;
btnL: in std_logic;
btnR: in std_logic ;
btnD: in std_logic;
btnC: in std_logic
);
end question2;
(Conversely, you could modify the constraints file, but you would be altering the naming conventions used).
A similar issue discussing case sensitivites in constraint files is described here.

Why is this Shift Register not loading properly in VHDL?

I have a custom designed shift register that has as input DL(leftmost input), DR(rightmost), CLR that clears and loads DR, S that shifts right and W that loads leftmost. After testing it, the rightmost is being loaded but not the left. I have reread the code multiple times, but I can't figure out what is wrong. Here's the code:
library IEEE;
use IEEE.std_logic_1164.all;
entity shiftregister is
port (
CLK, CLR: in STD_LOGIC;
S: in STD_LOGIC; --Shift right
W: in STD_LOGIC; --Write
Cin: in STD_LOGIC; --possible carry in from the addition
DL: in STD_LOGIC_VECTOR (7 downto 0); --left load for addition result
DR: in STD_LOGIC_VECTOR (7 downto 0); --right load for initial multiplier
Q: out STD_LOGIC_VECTOR (15 downto 0)
);
end shiftregister ;
architecture shiftregister of shiftregister is
signal IQ: std_logic_vector(15 downto 0):= (others => '0');
begin
process (CLK)
begin
if(CLK'event and CLK='1') then
if CLR = '1' then
IQ(7 downto 0) <= DR; --CLR clears and initializes the multiplier
IQ(15 downto 8) <= (others => '0');
else
if (S='1') then
IQ <= Cin & IQ(15 downto 1);
elsif (W='1') then
IQ(15 downto 8) <= DL;
end if;
end if;
end if;
end process;
Q<=IQ;
end shiftregister;
Waveform
TestBench
library IEEE;
use IEEE.std_logic_1164.all;
entity register_tb is
end register_tb;
architecture register_tb of register_tb is
component shiftregister is port (
CLK, CLR: in STD_LOGIC;
S: in STD_LOGIC; --Shift right
W: in STD_LOGIC; --Write
Cin: in STD_LOGIC; --possible carry in from the addition
DL: in STD_LOGIC_VECTOR (7 downto 0); --left load for addition result
DR: in STD_LOGIC_VECTOR (7 downto 0); --right load for initial multiplier
Q: out STD_LOGIC_VECTOR (15 downto 0)
);
end component;
signal CLK: std_logic:='0';
signal CLR: std_logic:='1';
signal Cin: std_logic:='0';
signal S: std_logic:='1';
signal W: std_logic:='0';
signal DL, DR: std_logic_vector(7 downto 0):="00000000";
signal Q: std_logic_vector(15 downto 0):="0000000000000000";
begin
U0: shiftregister port map (CLK, CLR, S, W, Cin, DL,DR,Q);
CLR <= not CLR after 20 ns;
CLK <= not CLK after 5 ns;
W <= not W after 10 ns;
DL <= "10101010" after 10 ns;
DR <= "00110011" after 10 ns;
end register_tb;
Your simulation shows that your S input is always high. The way you have your conditions setup, this means that the last elsif statement will not execute because S has priority over W. If you want your write to have priority over your shift operation, you should switch your conditions
if (W='1') then
IQ(15 downto 8) <= DL;
elsif (S='1') then
IQ <= Cin & IQ(15 downto 1);
end if;
Based on your comment for the desired behaviour, you could do something like this:
if (S='1' and W='1') then
IQ <= Cin & DL & IQ(7 downto 1);
elsif (W='1') then -- S=0
IQ(15 downto 8) <= DL;
elsif (S='1') then -- W=0
IQ <= Cin & IQ(15 downto 1);
end if; -- W=0 & S=0
Some improvements:
(1) Remove all signal but CLK from sensitivity list. Your process has no async signals, so only clock is needed in sensitivity list.
process(CLK)
(2) Assign zero only to the required bits -> question of taste ;)
IQ(7 downto 0) <= DR; --CLR clears and initializes the multiplier
IQ(15 downto 8) <= (others => '0');
(3) A elsif statement can clarify the assignment precedence:
if (S='1') then
IQ <= Cin & IQ(15 downto 1);
elsif (W='1') then
IQ(15 downto 8) <= DL;
end if;
(4) Line Q <= IQ; produces a second 16-bit register. I think this is not intended. Move this line outside of the process.

test bench of a 32x8 register file VHDL

I wrote the assembly code for this circuit in vhdl already. I want to simulate it with a test bench.
RegWrite: 1 bit input (clock)
Write Register Number: 3-bit input(write addresses)
Write Data: 32-bit input (data in) Read
Register Number A: 3-bit input (read addresses)
Read Register Number B: 3-bit input (read adddresses)
Port A: 32-bit output (data out)
Port B: 32-bit output (data out)
I think my problem is that I don't understand what this circuit does. I chose random values to assign to the inputs, but it didn't output anything. What are good inputs to choose for this circuit?
here is my test bench file for reference:
library ieee;
use ieee.std_logic_1164.all;
entity Reg_TB is -- entity declaration
end Reg_TB;
architecture TB of Reg_TB is
component RegisterFile_32x8
port ( RegWrite: in std_logic;
WriteRegNum: in std_logic_vector(2 downto 0);
WriteData: in std_logic_vector(31 downto 0);
ReadRegNumA: in std_logic_vector(2 downto 0);
ReadRegNumB: in std_logic_vector(2 downto 0);
PortA: out std_logic_vector(31 downto 0);
PortB: out std_logic_vector(31 downto 0)
);
end component;
signal T_RegWrite : std_logic;
signal T_WriteRegNum: std_logic_vector(2 downto 0);
signal T_WriteData: std_logic_vector(31 downto 0);
signal T_ReadRegNumA: std_logic_vector(2 downto 0);
signal T_ReadRegNumB: std_logic_vector(2 downto 0);
signal T_PortA : std_logic_vector(31 downto 0);
signal T_PortB : std_logic_vector(31 downto 0);
begin
T_WriteRegNum <= "011";
T_WriteData <= "00000000000000000000000000000001";
T_ReadRegNumA <= "001";
T_ReadRegNumB <= "100";
U_RegFile: RegisterFile_32x8 port map
(T_RegWrite, T_WriteRegNum, T_WriteData,T_ReadRegNumA, T_ReadRegNumB, T_PortA, T_PortB);
-- concurrent process to offer clock signal
process
begin
T_RegWrite <= '0';
wait for 5 ns;
T_RegWrite <= '1';
wait for 5 ns;
end process;
process
begin
wait for 12 ns;
-- case 2
wait for 28 ns;
-- case 3
wait for 2 ns;
-- case 4
wait for 10 ns;
-- case 5
wait for 20 ns;
wait;
end process;
end TB;
as you can see I chose
WriteRegNum = "011"
WriteData = "00000000000000000000000000000001"
ReadRegNumA = "001"
ReadRegNumB = "100"
I think that I chose bad inputs. The simulation does this:
In general reading an address before it is written doesn't produce any useful results.
Your block diagram shows a 32 bit wide 8 word deep register file with two read ports and one write port with RegWrite used as a clock gated by the decode of the write address. A stable WriteRegNum value and a rising edge on RegWrite effects a write to the address specified by WriteRegNum.
The two read ports appear completely independent. Specifying an address on the respective ReadRegNumA or ReadRegNumB should output the contents of that register to the respective output port.
To get something useful out, you have to write to that location first, otherwise it will be the default value ((others => 'U'),) suspiciously like your waveform.
Trying writing to a location before expecting valid read data from it. Use values that are distinguishable by register location. Theoretically you should be preserving set up and hold time on WriteRegNum with respect to the rising edge of RegWrite.
Example stimulus producing output:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity registerfile_32x8 is
port (
RegWrite: in std_logic;
WriteRegNum: in std_logic_vector (2 downto 0);
WriteData: in std_logic_vector (31 downto 0);
ReadRegNumA: in std_logic_vector (2 downto 0);
ReadRegNumB: in std_logic_vector (2 downto 0);
PortA: out std_logic_vector (31 downto 0);
PortB: out std_logic_vector (31 downto 0)
);
end entity;
architecture fum of registerfile_32x8 is
type reg_array is array (0 to 7) of std_logic_vector(31 downto 0);
signal reg_file: reg_array;
begin
process(RegWrite)
begin
if rising_edge(RegWrite) then
reg_file(to_integer(unsigned(WriteRegNum))) <= WriteData;
end if;
end process;
PortA <= reg_file(to_integer(unsigned(ReadRegNumA)));
PortB <= reg_file(to_integer(unsigned(ReadRegNumB)));
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity reg_tb is
end entity;
architecture fum of reg_tb is
component registerfile_32x8
port (
RegWrite: in std_logic;
WriteRegNum: in std_logic_vector (2 downto 0);
WriteData: in std_logic_vector (31 downto 0);
ReadRegNumA: in std_logic_vector (2 downto 0);
ReadRegNumB: in std_logic_vector (2 downto 0);
PortA: out std_logic_vector (31 downto 0);
PortB: out std_logic_vector (31 downto 0)
);
end component;
signal RegWrite: std_logic := '1';
signal WriteRegNum: std_logic_vector (2 downto 0) := "000";
signal WriteData: std_logic_vector (31 downto 0) := (others => '0');
signal ReadRegNumA: std_logic_vector (2 downto 0) := "000";
signal ReadRegNumB: std_logic_vector (2 downto 0) := "000";
signal PortA: std_logic_vector (31 downto 0);
signal PortB: std_logic_vector (31 downto 0);
begin
DUT:
registerfile_32x8
port map (
RegWrite => RegWrite,
WriteRegNum => WriteRegNum,
WriteData => WriteData,
ReadRegNumA => ReadRegNumA,
ReadRegNumB => ReadRegNumB,
PortA => PortA,
PortB => PortB
);
STIMULUS:
process
begin
wait for 20 ns;
RegWrite <= '0';
wait for 20 ns;
RegWrite <= '1';
wait for 20 ns;
WriteData <= x"feedface";
WriteRegnum <= "001";
RegWrite <= '0';
wait for 20 ns;
RegWrite <= '1';
ReadRegNumA <= "001";
wait for 20 ns;
WriteData <= x"deadbeef";
WriteRegNum <= "010";
ReadRegNumB <= "010";
RegWrite <= '0';
wait for 20 ns;
RegWrite <= '1';
wait for 20 ns;
wait for 20 ns;
wait;
end process;
end architecture;
david_koontz#Macbook: ghdl -a regfile_32x8.vhdl
david_koontz#Macbook: ghdl -e reg_tb
david_koontz#Macbook: ghdl -r reg_tb --wave=reg_tb.ghw
david_koontz#Macbook: open reg_tb.gtkw
Essentially, the point is to have non 'U' values in a register file that's being read. If you notice the last write to WriteRegNum = "010", PortB shows undefined output until the write occurs.

Resources