How can I combine/bundle statements for further use and better handling? For example some assignments like this which would be used many times more in future calls of the routine.
ADDR_PC <= "0000000000";
ADDR_OP_A <= "00000";
ADDR_OP_B <= "00000";
OP_CODE <= OP_NOP;
OP_IMMED <= IMMED_NULL;
WE_SREG <= "00000"; -- S V N C Z
Into something like this.
NOP = {ADDR_PC <= "00000000", ADDR_OP_A <= "00000", ...}
I don't know if there are any possibilities to do that in VHDL. Any tip would be helpful.
Records and/or aggregates:
library ieee;
use ieee.std_logic_1164.all;
entity op_decoded is
end entity;
architecture foo of op_decoded is
-- These declarations probably want to be in a package
constant IMMED_NULL: std_logic_vector (8 downto 0) := (others => '0');
constant OP_NOP: std_logic_vector (5 downto 0) := (others => '0');
type decode_op is
record
PC: std_logic_vector (7 downto 0);
OP_A: std_logic_vector (4 downto 0);
OP_B: std_logic_vector (4 downto 0);
OP_CODE: std_logic_vector (5 downto 0);
OP_IMMED: std_logic_vector (8 downto 0);
WE_SREG: std_logic_vector (4 downto 0); -- S V N C Z
end record;
constant NOP: decode_op := (
PC => "00000000",
OP_A => "00000",
OP_B => "00000",
OP_CODE => OP_NOP,
OP_IMMED => IMMED_NULL,
WE_SREG => "00000"
);
-- actual signals
signal ADDR_PC: std_logic_vector (7 downto 0);
signal ADDR_OP_A: std_logic_vector (4 downto 0);
signal ADDR_OP_B: std_logic_vector (4 downto 0);
signal OP_CODE: std_logic_vector (5 downto 0);
signal OP_IMMED: std_logic_vector (8 downto 0);
signal WE_SREG: std_logic_vector (4 downto 0);
signal pipe1: decode_op;
signal pipe_disc: decode_op;
begin
(ADDR_PC, ADDR_OP_A, ADDR_OP_B, OP_CODE, OP_IMMED, WE_SREG) <= NOP;
pipe1 <= NOP;
pipe_disc <= (pipe1.PC, pipe1.OP_A, pipe1.OP_B, pipe1.OP_CODE,
pipe1.OP_IMMED, pipe1.WE_SREG);
end architecture;
This analyzes, elaborates and simulates (showing it's syntactically and semantically correct).
There's also an aggregate target with an aggregate right hand side (with the type provided):
(ADDR_PC, ADDR_OP_A, ADDR_OP_B, OP_CODE, OP_IMMED, WE_SREG) <=
decode_op'(pipe1.PC, pipe1.OP_A, pipe1.OP_B, pipe1.OP_CODE,
pipe1.OP_IMMED, pipe1.WE_SREG);
VHDL has records (C calls it struct).
Declaration example:
type T_MY_RECORD is record
Member1 : STD_LOGIC;
Member2 : STD_LOGIC_VECTOR(15 downto 0);
end record;
signal mySignal1 : T_MY_RECORD;
signal mySignal2 : T_MY_RECORD;
Usage examples:
mySignal1 <= (
Member1 => '1',
Member2 => x"12FC"
);
mySignal2.Member1 <= '0';
Records can be nested, e.g. for the flags.
Records and/or aggregates are one possibility, but and alternative is to declare a procedure in the process where the signals are driven, and then call the procedure, like:
process (clk_i) is
procedure NOP is
begin
ADDR_PC <= "0000000000";
ADDR_OP_A <= "00000";
ADDR_OP_B <= "00000";
OP_CODE <= OP_NOP;
OP_IMMED <= IMMED_NULL;
WE_SREG <= "00000"; -- S V N C Z
end procedure;
begin
if rising_edge(clk_i) then
...
NOP;
...
end if;
end process;
This work both for simulation and synthesizable code.
Related
I hope you guys are well :)
I am trying to implement a simple cache memory system, however I am finding myself unable to properly do so. When I attempt to test my read miss/ read hit, I am getting the following result: VHDL Signals.
As I understand my design, the Read Miss state should be writing 1011111110101100 however I am either getting 10111111100000000 or 00000010101100. My result seems to fluctuate between both results. s_addr refers to a new instruction from the CPU which starts one process, which in turn starts the state process should there be any changes. I have provided some code. I am unsure of how to proceed. I've walked through my code and I do not understand why it splits the values like that when the output was supposed occur in one go.
Finally, I suspect that this may have something to do with the fact that my signals are initially undefined for some reason.
Full signal diagram
I am not sure why for the first 6ns, the output of s_readdatta is undefined. My tag values stored in test1 and test2 are also undefined and I am not sure why. I would appreciate any insight you guys can offer. Thank you!
VHDL code
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_bit_unsigned.all;
entity cache is
generic(
ram_size : INTEGER := 32768
);
port(
clock : in std_logic;
reset : in std_logic;
-- Avalon interface --
s_addr : in std_logic_vector (31 downto 0);
s_read : in std_logic;
s_readdata : out std_logic_vector (31 downto 0);
s_write : in std_logic;
s_writedata : in std_logic_vector (31 downto 0);
s_waitrequest : out std_logic;
m_addr : out integer range 0 to ram_size-1;
m_read : out std_logic;
m_readdata : in std_logic_vector (7 downto 0);
m_write : out std_logic;
m_writedata : out std_logic_vector (7 downto 0);
m_waitrequest : in std_logic;
test1: out std_logic_vector (5 downto 0);
test2: out std_logic_vector (5 downto 0)
);
end cache;
architecture arch of cache is
-- declare signals here
-- 15 bit signal will be of the following form: VDTTTTBBBBBWWbb
constant number_of_cache_lines: integer := 128;
TYPE t_cache_memory IS ARRAY(number_of_cache_lines-1 downto 0) OF STD_LOGIC_VECTOR(31 downto 0);
-- For data requested by CPU
signal tag_bits: std_logic_vector (5 downto 0);
signal block_index: std_logic_vector (4 downto 0);
signal block_index_int: integer;
signal word_index: std_logic_vector (1 downto 0);
signal word_index_int: integer;
-- For data in the cache
signal in_cache_tag_bits: std_logic_vector (5 downto 0);
signal in_cache_valid_bit: std_logic;
signal in_cache_dirty_bit: std_logic;
signal temp_s_addr: std_logic_vector(14 downto 0);
signal retrieved_address: std_logic_vector (31 downto 0);
type t_State is (readHit, writeHit, writeBack, readMiss, writeMiss, idle);
signal state: t_State;
signal cache_memory: t_cache_memory;
begin
-- For CPU address
temp_s_addr(3 downto 0) <= (others => '0');
temp_s_addr(14 downto 4) <= s_addr (14 downto 4);
tag_bits <= s_addr (14 downto 9);
block_index <= s_addr (8 downto 4);
block_index_int <= 4*to_integer(unsigned(block_index));
word_index <= s_addr (3 downto 2);
word_index_int <= to_integer(unsigned(word_index));
process (s_addr)
begin
if block_index_int /= -2147483648 then
retrieved_address <= cache_memory(block_index_int + word_index_int);
in_cache_valid_bit <= cache_memory(block_index_int)(15);
in_cache_dirty_bit <= cache_memory(block_index_int)(14);
in_cache_tag_bits <= cache_memory(block_index_int)(13 downto 8);
end if;
if s_read = '1' and s_write ='0' then
if in_cache_valid_bit = '1' then
test1 <= s_addr (14 downto 9);
test2 <= in_cache_tag_bits;
if in_cache_tag_bits = s_addr (14 downto 9) then
state <= readHit;
else
if in_cache_dirty_bit = '1' then
state <= writeBack;
else
state <= readMiss;
end if;
end if;
else
state <= readMiss;
end if;
elsif s_write = '1' and s_read = '0' then
if in_cache_valid_bit = '1' then
if tag_bits = in_cache_tag_bits then
state <= writeHit;
else
if in_cache_dirty_bit = '1' then
state <= writeBack;
else
state <= writeMiss;
end if;
end if;
end if;
else
state <= idle;
end if;
end process;
process(state)
begin
s_waitrequest <= '1';
case state is
-- If CPU is not doing anything
when idle =>
report "No Reads or Writes have occured.";
when readHit =>
report "Read Hit Occured:";
s_readdata <= retrieved_address;
-- If write hit
when writeHit =>
report "Write Hit Occured:";
cache_memory(block_index_int + word_index_int)(7 downto 0) <= s_addr(7 downto 0);
cache_memory(block_index_int)(13 downto 8) <= tag_bits;
cache_memory(block_index_int)(14) <= '1';
cache_memory(block_index_int)(15) <= '1';
cache_memory(block_index_int)(31 downto 16) <= (others => '0');
--state <= idle;
-- If cache hit but dirty bit then write-back
when writeBack =>
report "Write Back Occured:";
-- Write back into memory first
m_write <= '1';
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)));
m_writedata <= temp_s_addr(7 downto 0);
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0))) + 4;
m_writedata(3 downto 0) <= "0100";
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0))) + 8;
m_writedata(3 downto 0) <= "1000";
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0))) + 12;
m_writedata(3 downto 0) <= "1100";
m_write <= '0';
-- Write to cache
cache_memory(block_index_int)(13 downto 8) <= tag_bits;
cache_memory(block_index_int)(14) <= '0';
cache_memory(block_index_int)(15) <= '0';
cache_memory(block_index_int)(31 downto 16) <= (others => '0');
--state <= idle;
when readMiss =>
report "Read Miss Occured:";
m_read <= '1';
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)));
cache_memory(block_index_int)(7 downto 0) <= m_readdata;
cache_memory(block_index_int)(31 downto 8) <= (others => '0');
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)))+4;
cache_memory(block_index_int+1)(7 downto 0) <= m_readdata;
cache_memory(block_index_int+1)(31 downto 8) <= (others => '0');
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)))+8;
cache_memory(block_index_int+2)(7 downto 0) <= m_readdata;
cache_memory(block_index_int+2)(31 downto 8) <= (others => '0');
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)))+12;
cache_memory(block_index_int+3)(7 downto 0) <= m_readdata;
cache_memory(block_index_int+3)(31 downto 8) <= (others => '0');
m_read <= '0';
cache_memory(block_index_int)(13 downto 8) <= tag_bits;
cache_memory(block_index_int)(14) <= '0';
cache_memory(block_index_int)(15) <= '1';
cache_memory(block_index_int)(31 downto 16) <= (others => '0');
s_readdata<= cache_memory(block_index_int + word_index_int);
--state <= idle;
-- If write miss
when writeMiss =>
report "Write Miss Occured:";
m_write <= '1';
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0))) + word_index_int;
m_writedata <= s_addr(7 downto 0);
m_write <= '0';
m_read <= '1';
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)));
cache_memory(block_index_int)(7 downto 0) <= m_readdata;
cache_memory(block_index_int)(31 downto 8) <= (others => '0');
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)))+4;
cache_memory(block_index_int+1)(7 downto 0) <= m_readdata;
cache_memory(block_index_int+1)(31 downto 8) <= (others => '0');
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)))+8;
cache_memory(block_index_int+2)(7 downto 0) <= m_readdata;
cache_memory(block_index_int+2)(31 downto 8) <= (others => '0');
m_addr <= to_integer(unsigned(temp_s_addr(14 downto 0)))+12;
cache_memory(block_index_int+3)(7 downto 0) <= m_readdata;
cache_memory(block_index_int+3)(31 downto 8) <= (others => '0');
m_read <= '0';
cache_memory(block_index_int)(13 downto 8) <= tag_bits;
cache_memory(block_index_int)(14) <= '0';
cache_memory(block_index_int)(15) <= '1';
cache_memory(block_index_int)(31 downto 16) <= (others => '0');
--state <= idle;
end case;
s_waitrequest <= '0';
end process;
end arch;
Testbench Code
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity cache_tb is
end cache_tb;
architecture behavior of cache_tb is
component cache is
generic(
ram_size : INTEGER := 32768
);
port(
clock : in std_logic;
reset : in std_logic;
-- Avalon interface --
s_addr : in std_logic_vector (31 downto 0);
s_read : in std_logic;
s_readdata : out std_logic_vector (31 downto 0);
s_write : in std_logic;
s_writedata : in std_logic_vector (31 downto 0);
s_waitrequest : out std_logic;
m_addr : out integer range 0 to ram_size-1;
m_read : out std_logic;
m_readdata : in std_logic_vector (7 downto 0);
m_write : out std_logic;
m_writedata : out std_logic_vector (7 downto 0);
m_waitrequest : in std_logic;
test1: out std_logic_vector (5 downto 0);
test2: out std_logic_vector (5 downto 0)
);
end component;
component memory is
GENERIC(
ram_size : INTEGER := 32768;
mem_delay : time := 10 ns;
clock_period : time := 1 ns
);
PORT (
clock: IN STD_LOGIC;
writedata: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
address: IN INTEGER RANGE 0 TO ram_size-1;
memwrite: IN STD_LOGIC;
memread: IN STD_LOGIC;
readdata: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
waitrequest: OUT STD_LOGIC
);
end component;
-- test signals
signal reset : std_logic := '0';
signal clk : std_logic := '0';
constant clk_period : time := 1 ns;
signal s_addr : std_logic_vector (31 downto 0);
signal s_read : std_logic;
signal s_readdata : std_logic_vector (31 downto 0);
signal s_write : std_logic;
signal s_writedata : std_logic_vector (31 downto 0);
signal s_waitrequest : std_logic;
signal m_addr : integer range 0 to 2147483647;
signal m_read : std_logic;
signal m_readdata : std_logic_vector (7 downto 0);
signal m_write : std_logic;
signal m_writedata : std_logic_vector (7 downto 0);
signal m_waitrequest : std_logic;
signal test1: std_logic_vector (5 downto 0);
signal test2: std_logic_vector (5 downto 0);
begin
-- Connect the components which we instantiated above to their
-- respective signals.
dut: cache
port map(
clock => clk,
reset => reset,
s_addr => s_addr,
s_read => s_read,
s_readdata => s_readdata,
s_write => s_write,
s_writedata => s_writedata,
s_waitrequest => s_waitrequest,
m_addr => m_addr,
m_read => m_read,
m_readdata => m_readdata,
m_write => m_write,
m_writedata => m_writedata,
m_waitrequest => m_waitrequest,
test1 => test1,
test2 => test2
);
MEM : memory
port map (
clock => clk,
writedata => m_writedata,
address => m_addr,
memwrite => m_write,
memread => m_read,
readdata => m_readdata,
waitrequest => m_waitrequest
);
clk_process : process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
test_process : process
begin
REPORT "***Initializing***";
s_read <= '0';
s_write <= '0';
s_addr <= "00000000000000000000000000000000";
wait for clk_period;
report "Initializing Zero complete...";
report "***Start Testing***";
report "Read Miss Test:";
s_read <= '1';
s_write <= '0';
s_addr <= "11111111111111111111111110101111";
wait for clk_period;
assert s_readdata(7 downto 0) = m_readdata report "DATA NOT IN CACHE";
wait for clk_period;
report "Read Hit Test:";
s_read <= '1';
s_write <= '0';
s_addr <= "11111111111111111111111110101111";
wait for clk_period;
assert s_readdata(7 downto 0) = m_readdata report "DATA NOT IN CACHE";
wait for clk_period;
end process;
end;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity struture_test is
Port ( clk : in STD_LOGIC;
rst : in STD_LOGIC;
Init : in STD_LOGIC;
i_ia : in STD_LOGIC_VECTOR (11 downto 0);
i_ib : in STD_LOGIC_VECTOR (11 downto 0);
end_s : out std_logic;
result : out STD_LOGIC_VECTOR (11 downto 0));
end struture_test;
architecture Behavioral of struture_test is
signal en_sn : std_logic := '0';
begin
PROCESS (clk,rst)
variable acc : signed (23 downto 0) ;
variable x : signed (35 downto 0) ;
begin
if (rst = '0') then
result <= (others => '0');
end_s <= '0';
elsif (rising_edge (clk)) then
if ((Init) = '1') then
acc := signed (i_ia)*signed (i_ib);
x := acc * signed (i_ia);
result <= std_logic_vector (x(23 downto 12));
end_s <= '1';
else
end_s <= '0';
end if;
end if;
end process;
end Behavioral;
Hi everyone
I have a project which includes some blocks. The blocks link each other through Init or End Signal. It means that The End signal of one Block is connected to Init signal of the following block.
I'm confused about that Does the above code make a good Init and a End signal ?
If I change my code and convert it into Pipelined structure to operate with the higher frequency clock. The variables convert into the signals
PROCESS (clk,rst)
signal acc : signed (23 downto 0) ;
signal x : signed (35 downto 0) ;
begin
if (rst = '0') then
result <= (others => '0');
end_s <= '0';
elsif (rising_edge (clk)) then
if ((Init) = '1') then
acc <= signed (i_ia)*signed (i_ib);
x <= acc * signed (i_ia);
result <= std_logic_vector (x(23 downto 12));
end_s <= '1';
else
end_s <= '0';
end if;
end if;
end process;
How to create Init and End signal in this case? The block illustrates in the picture
The idea is good, but the code is wrong. In addition it has some bad coding smells.
Basic rules:
Do not use asynchronous resets.
You can not declare signals in processes. Process allow variable declarations; architectures allow signal declarations.
Each signal assignment in a clock process creates a flip-flop / delay of one clock cycle. So it's 3 clock cycles delay in total, but you end signal is only delayed by one cycle.
Do not enable pipelined operations. Use a delayed chain of valid bits.
Do not reset pipeline results, because underlying hardware resources like DSP (multiplication) units do not support resets.
Changed code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity struture_test is
port (
clk : in std_logic;
rst : in std_logic;
Init : in std_logic;
i_ia : in std_logic_vector(11 downto 0);
i_ib : in std_logic_vector(11 downto 0);
end_s : out std_logic;
result : out std_logic_vector(11 downto 0) := (others => '0');
);
end entity;
architecture rtl of struture_test is
signal ValidChain : std_logic_value(2 downto 0) := (others => '0');
signal ia_delayed : signed(i_ia'range) := (others => '0');
signal acc : signed(23 downto 0) := (others => '0');
signal x : signed(35 downto 0) := (others => '0');
begin
process(clk)
begin
if rising_edge(clk) then
ValidChain <= ValidChain(ValidChain'high - 1 downto ValidChain'low) & Init;
acc <= signed(i_ia) * signed(i_ib);
ia_delayed <= signed(i_ia);
x <= acc * ia_delayed;
result <= std_logic_vector(x(23 downto 12));
end if;
end process;
end_s <= ValidChain(ValidChain'high);
end architecture;
Please note: Signal i_ia used in the 2nd multiplication needs to be delayed by one cycle, otherwise you would mix ia values from different pipeline cycles.
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;
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.
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.