Initial revision

Committed on the Free edition of March Hare Software CVSNT Server.
Upgrade to CVS Suite for more features and support:
http://march-hare.com/cvsnt/


git-svn-id: http://moon:8086/svn/vhdl/trunk@956 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
2013-04-27 17:46:49 +00:00
parent a6a659904b
commit 77e58cfbde
3 changed files with 531 additions and 0 deletions
+241
View File
@@ -0,0 +1,241 @@
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
use work.utils_pkg.all;
use work.align_types.all;
ENTITY align_out IS
Generic
(
data_width : natural := 32;
addr_width : natural := 32;
byte_size : natural := 8
);
Port
(
rst : in STD_LOGIC;
clk : in STD_LOGIC;
cmd_rdy : out STD_LOGIC;
cmd_vld : in STD_LOGIC;
cmd_in : in align_cmd_in_t;
din_rdy : out STD_LOGIC;
din_vld : in STD_LOGIC;
din : in unsigned(data_width-1 downto 0);
dout_vld : out STD_LOGIC;
dout : out unsigned(data_width-1 downto 0);
dout_be : out unsigned (data_width/byte_size-1 downto 0);
dout_re : in STD_LOGIC;
addr_out : out unsigned(addr_width-1 downto 0)
);
END align_out;
ARCHITECTURE behavior OF align_out IS
type byte_en_rom_t is array (0 to 2*data_width/byte_size-1) of unsigned (data_width/byte_size-1 downto 0);
function gen_byte_en_rom(N : natural) return byte_en_rom_t is
variable k : integer;
variable result : byte_en_rom_t;
begin
k:=0;
result(k) := (others => '1');
k := k + 1;
for i in 1 to N-1 loop
result(k) := (N-1 downto i => '1') & (i-1 downto 0 => '0');
k := k + 1;
end loop;
result(k) := (others => '1');
k := k + 1;
for i in 1 to N-1 loop
result(k) := (N-1 downto i => '0') & (i-1 downto 0 => '1');
k := k + 1;
end loop;
return result;
end gen_byte_en_rom;
constant out_addr_step : natural := data_width/byte_size;
constant out_addr_nlsb : natural := NextExpBaseTwo(out_addr_step);
signal byte_en_rom : byte_en_rom_t := gen_byte_en_rom(out_addr_step);
signal cmd_stb : std_logic;
signal shift_dout : unsigned(data_width-1 downto 0);
signal shift_vld : std_logic;
signal reg0 : unsigned(data_width-1 downto 0);
signal reg : unsigned(data_width-1 downto 0);
signal reg0_vld : std_logic;
signal reg_vld : std_logic;
signal comb_be : unsigned (out_addr_step-1 downto 0);
signal byte_en : unsigned (out_addr_step-1 downto 0);
signal saddr_reg : unsigned(addr_width-1 downto 0);
signal eb_reg : std_logic;
signal shift_sa : integer;
type addr_alt_t is record
offset : unsigned(out_addr_nlsb-1 downto 0);
addr : unsigned(addr_width-1 downto 0);
remain : unsigned(addr_width-1 downto 0);
busy : std_logic;
last : std_logic;
end record;
signal addr_alt : addr_alt_t;
-- output FIFO
signal fifo_din : unsigned(addr_width+data_width+out_addr_step-1 downto 0);
signal fifo_dout : unsigned(addr_width+data_width+out_addr_step-1 downto 0);
signal fifo_re : std_logic;
signal fifo_we : std_logic;
signal fifo_full : std_logic;
signal fifo_empty : std_logic;
signal fifo_rdy : std_logic;
signal fifo_dout_vld : std_logic;
signal rdy : std_logic;
--------------------------------------------------------------------------
begin
cmd_stb <= not addr_alt.busy and cmd_vld;
cmd_rdy <= not addr_alt.busy;
dout_be <= fifo_dout(addr_width+data_width+out_addr_step-1 downto addr_width+data_width);
addr_out <= fifo_dout(addr_width+data_width-1 downto data_width);
dout <= fifo_dout(data_width-1 downto 0);
rdy <= fifo_rdy and addr_alt.busy;
dout_vld <= fifo_dout_vld;
din_rdy <= rdy;
---------------------------------------------------------------------------
-- Address generation
---------------------------------------------------------------------------
byte_en <= byte_en_rom(to_integer(not eb_reg & addr_alt.addr(out_addr_nlsb-1 downto 0))) when addr_alt.last = '0'
else byte_en_rom(to_integer(eb_reg & addr_alt.remain(out_addr_nlsb-1 downto 0)));
addr_alt.last <= '1' when (addr_alt.remain < out_addr_step) else '0';
prproc_addr_alt:
process(clk)
variable addr_next : unsigned(addr_width-1 downto 0);
variable remain_next : unsigned(addr_width-1 downto 0);
begin
if rising_edge(clk) then
if addr_alt.addr(out_addr_nlsb-1 downto 0) /= (out_addr_nlsb-1 downto 0 => '0') then
addr_next := addr_alt.addr + (to_unsigned(out_addr_step, out_addr_nlsb) - addr_alt.addr(out_addr_nlsb-1 downto 0));
remain_next := addr_alt.remain - (to_unsigned(out_addr_step, out_addr_nlsb) - saddr_reg(out_addr_nlsb-1 downto 0));
else
addr_next := addr_alt.addr + to_unsigned(out_addr_step, addr_width);
remain_next := addr_alt.remain - to_unsigned(out_addr_step, addr_width);
end if;
if rst = '1' then
addr_alt.busy <= '0';
elsif cmd_stb = '1' then
addr_alt.offset <= cmd_in.addr_start(out_addr_nlsb-1 downto 0);
addr_alt.addr <= cmd_in.addr_start;
addr_alt.remain <= cmd_in.num_bytes;
addr_alt.busy <= '1';
saddr_reg <= cmd_in.addr_start;
eb_reg <= cmd_in.eb;
elsif rdy = '1' then
if addr_alt.last = '1' then
addr_alt.busy <= '0';
end if;
if reg_vld = '1' then
addr_alt.addr <= addr_next;
if remain_next = out_addr_step then
addr_alt.busy <= '0';
else
addr_alt.remain <= remain_next;
end if;
end if;
end if;
end if;
end process;
---------------------------------------------------------------------------
-- Data generation
---------------------------------------------------------------------------
inst_shifter : entity work.align_shifter
GENERIC MAP
(
data_width => data_width,
aggregate_size => byte_size,
do_pipelined => true
)
PORT MAP
(
rst => rst,
clk => clk,
ce => rdy,
sa => shift_sa,
din_vld => din_vld,
din => din,
dout_vld => shift_vld,
dout => shift_dout
);
shift_sa <= to_integer(addr_alt.offset);
proc_combine:
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
reg_vld <= '0';
elsif rdy = '1' then
reg_vld <= shift_vld;
reg0_vld <= shift_vld;
if reg0_vld = '1' then
reg <= reg0;
end if;
if shift_vld = '1' then
reg0 <= shift_dout;
for i in 0 to data_width/byte_size-1 loop
if comb_be(i) = '1' then
reg(byte_size*(i+1)-1 downto byte_size*i) <= shift_dout(byte_size*(i+1)-1 downto byte_size*i);
end if;
end loop;
end if;
end if;
end if;
end process;
comb_be <= byte_en_rom(to_integer(not eb_reg & addr_alt.offset));
-- Output FIFO
inst_fifo: entity work.fifo_sync
GENERIC MAP
(
addr_width => 4,
data_width => fifo_din'length,
do_last_read_update => true
)
PORT MAP
(
rst => rst,
clk => clk,
we => fifo_we,
re => fifo_re,
fifo_full => fifo_full,
fifo_empty => fifo_empty,
fifo_afull => open,
fifo_aempty => open,
data_w => fifo_din,
data_r => fifo_dout
);
fifo_rdy <= not fifo_full;
fifo_din <= byte_en & addr_alt.addr(addr_width-1 downto out_addr_nlsb) & (out_addr_nlsb-1 downto 0 => '0') & reg;
fifo_we <= (reg_vld or addr_alt.last) and rdy;
fifo_dout_vld <= not fifo_empty;
fifo_re <= dout_re;
--------------------------------------------------------------------------
end behavior;
+34
View File
@@ -0,0 +1,34 @@
-- Package File Template
--
-- Purpose: This package defines supplemental types, subtypes,
-- constants, and functions
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
package align_types is
-- Constants
-- Types
type align_cmd_in_t is record
eb : std_logic;
addr_start : unsigned(31 downto 0);
num_bytes : unsigned(31 downto 0);
addr_step : natural;
num_bytes_per_word : natural;
end record;
-- Functions
end align_types;
package body align_types is
end align_types;
+256
View File
@@ -0,0 +1,256 @@
-------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: testbench for system test using Xilinx ML-402
-- Copyright (C) 2007 J. Ahrensfeld
-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
-- You should have received a copy of the GNU Lesser General Public
-- License along with this library; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-- For questions and ideas, please contact the author at jens@jayfield.org
-----------------------------------------------------------------------
LIBRARY ieee;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL;
use work.align_types.all;
ENTITY tb_align_out IS
END tb_align_out;
ARCHITECTURE behavior OF tb_align_out IS
constant CLK_PERIOD : time := 10 ns;
signal CLK_O : std_logic := '1';
signal RST_O : std_logic := '1';
signal cmd_rdy : std_logic;
signal cmd_vld : std_logic := '0';
signal cmd_in : align_cmd_in_t;
signal din : unsigned(31 downto 0) := (others => '-');
signal din_rdy : std_logic;
signal din_vld : std_logic := '0';
signal dout_vld : std_logic;
signal dout_re : std_logic := '0';
signal dout : unsigned(31 downto 0);
signal dout_be : unsigned(3 downto 0);
signal addr_out : unsigned(31 downto 0);
signal read_reg : unsigned(31 downto 0) := (others => '-');
BEGIN
inst_align_out : entity work.align_out
GENERIC MAP
(
data_width => 32,
addr_width => 32,
byte_size => 8
)
PORT MAP
(
rst => RST_O,
clk => CLK_O,
cmd_rdy => cmd_rdy,
cmd_vld => cmd_vld,
cmd_in => cmd_in,
din_rdy => din_rdy,
din_vld => din_vld,
din => din,
dout_vld => dout_vld,
dout => dout,
dout_be => dout_be,
dout_re => dout_re,
addr_out => addr_out
);
CLK_GEN: process
begin
wait for CLK_PERIOD/2;
CLK_O <= not CLK_O;
end process;
READ_GEN: process
begin
wait for CLK_PERIOD/2;
dout_re <= '1';
wait for CLK_PERIOD/2;
dout_re <= '0';
wait for 12*CLK_PERIOD/2;
end process;
-- Master
STIMULUS:
process
begin
wait for 6*CLK_PERIOD;
RST_O <= '0';
wait for 60*CLK_PERIOD;
wait until rising_edge(CLK_O) and dout_vld = '0';
wait until rising_edge(CLK_O) and cmd_rdy = '1';
------------------------------------------------
cmd_in.eb <= '1';
cmd_in.addr_start <= X"8000_0002";
cmd_in.addr_step <= 2;
cmd_in.num_bytes_per_word <= 4;
cmd_in.num_bytes <= to_unsigned(32, cmd_in.num_bytes'length);
-- Trigger transaction
wait until rising_edge(CLK_O) and cmd_rdy = '1';
cmd_vld <= '1';
wait until rising_edge(CLK_O);
cmd_vld <= '0';
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= X"1111_0000";
din_vld <= '1';
for i in 0 to 16/4-1 loop
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= din + X"1111_1111";
end loop;
din_vld <= '0';
wait for 8*CLK_PERIOD;
wait until rising_edge(CLK_O) and din_rdy = '1';
din_vld <= '1';
for i in 0 to 16/4-1 loop
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= din + X"1111_1111";
end loop;
din_vld <= '0';
wait for 10*CLK_PERIOD;
wait until rising_edge(CLK_O) and cmd_rdy = '1';
------------------------------------------------
cmd_in.eb <= '1';
cmd_in.addr_start <= X"8000_0000";
cmd_in.addr_step <= 2;
cmd_in.num_bytes_per_word <= 4;
cmd_in.num_bytes <= to_unsigned(32, cmd_in.num_bytes'length);
-- Trigger transaction
wait until rising_edge(CLK_O) and cmd_rdy = '1';
cmd_vld <= '1';
wait until rising_edge(CLK_O);
cmd_vld <= '0';
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= X"1111_0000";
din_vld <= '1';
for i in 0 to 16/4-1 loop
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= din + X"1111_1111";
end loop;
din_vld <= '0';
wait for 8*CLK_PERIOD;
wait until rising_edge(CLK_O) and din_rdy = '1';
din_vld <= '1';
for i in 0 to 16/4-1 loop
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= din + X"1111_1111";
end loop;
din_vld <= '0';
wait for 10*CLK_PERIOD;
wait until rising_edge(CLK_O) and cmd_rdy = '1';
------------------------------------------------
cmd_in.eb <= '1';
cmd_in.addr_start <= X"8000_0003";
cmd_in.addr_step <= 2;
cmd_in.num_bytes_per_word <= 4;
cmd_in.num_bytes <= to_unsigned(32, cmd_in.num_bytes'length);
-- Trigger transaction
wait until rising_edge(CLK_O) and cmd_rdy = '1';
cmd_vld <= '1';
wait until rising_edge(CLK_O);
cmd_vld <= '0';
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= X"1111_0000";
din_vld <= '1';
for i in 0 to 16/4-1 loop
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= din + X"1111_1111";
end loop;
din_vld <= '0';
wait for 8*CLK_PERIOD;
wait until rising_edge(CLK_O) and din_rdy = '1';
din_vld <= '1';
for i in 0 to 16/4-1 loop
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= din + X"1111_1111";
end loop;
din_vld <= '0';
wait for 10*CLK_PERIOD;
wait until rising_edge(CLK_O) and cmd_rdy = '1';
wait until rising_edge(CLK_O) and dout_vld = '0';
------------------------------------------------
cmd_in.eb <= '1';
cmd_in.addr_start <= X"8000_0000";
cmd_in.addr_step <= 2;
cmd_in.num_bytes_per_word <= 2;
cmd_in.num_bytes <= to_unsigned(2, cmd_in.num_bytes'length);
-- Trigger transaction
wait until rising_edge(CLK_O) and cmd_rdy = '1';
cmd_vld <= '1';
wait until rising_edge(CLK_O);
cmd_vld <= '0';
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= X"1111_0000";
din_vld <= '1';
for i in 0 to 16/4-1 loop
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= din + X"1111_1111";
end loop;
din_vld <= '0';
wait for 8*CLK_PERIOD;
wait until rising_edge(CLK_O) and din_rdy = '1';
din_vld <= '1';
for i in 0 to 16/4-1 loop
wait until rising_edge(CLK_O) and din_rdy = '1';
din <= din + X"1111_1111";
end loop;
din_vld <= '0';
wait;
end process;
END;