Files
lt16lab/soc/lib/can_tp.vhd
2020-07-10 18:14:26 +02:00

406 lines
12 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone.all;
use std.textio.all;
use ieee.std_logic_textio.all;
package can_tp is
type rx_check_result is (success, can_error, arbitration_lost, no_ack);
constant wbs_in_default : wb_slv_in_type := (
(others=>'-'), -- adr
(others=>'-'), -- dat
'-', -- we
(others => '-'), -- sel
'0', -- stb
'0', -- cyc
"000", -- cti
"00" -- bte
);
procedure can_wb_write_reg(
signal wbs_in : out wb_slv_in_type;
signal wbs_out : in wb_slv_out_type;
constant addr : integer;
constant data : in std_logic_vector(7 downto 0);
signal clk : in std_logic);
procedure can_wb_read_reg(
signal wbs_in : out wb_slv_in_type;
signal wbs_out : in wb_slv_out_type;
constant addr : integer;
signal clk : in std_logic);
procedure write_regs_from_file(
constant filename : in string;
signal wbs_in : out wb_slv_in_type;
signal wbs_out : in wb_slv_out_type;
signal clk : in std_logic);
procedure read_regs_with_fileaddr(
constant filename : in string;
constant out_filename : in string;
signal wbs_in : out wb_slv_in_type;
signal wbs_out : in wb_slv_out_type;
signal clk : in std_logic);
function canint2addr(
constant intaddr : integer
) return std_logic_vector;
function canint2sel(
constant intaddr : integer
) return std_logic_vector;
function data2canwb(
constant data : std_logic_vector(7 downto 0)
) return std_logic_vector;
function can_crc(
constant stream_vector: in std_logic_vector(0 to 82);
constant datasize: in integer)return std_logic_vector;
function buildframe(
constant id: in std_logic_vector(10 downto 0);
constant data: in std_logic_vector(0 to 63);
constant datasize: in integer) return std_logic_vector;
function select_bit(
constant tx_frame_pointer: in integer;
constant datasize: in integer;
constant tx_frame: in std_logic_vector(0 to 108)) return std_logic_vector;
procedure set_bit(
signal tx: out std_logic;
constant tx_bit: in std_logic_vector(0 to 4);
constant t_bit: in time;
variable tx_history: inout std_logic_vector(3 downto 0));
procedure simulate_can_transmission(
constant id : in std_logic_vector(10 downto 0);
constant data: in std_logic_vector (0 to 63);
constant datasize: in integer;
constant t_bit: in time;
signal rx: in std_logic;
signal tx: inout std_logic;
signal test_result: out rx_check_result);
end can_tp;
package body can_tp is
-- convertes the input register address to addr
function canint2addr(
constant intaddr : integer
) return std_logic_vector is variable addr: std_logic_vector(7 downto 0);
begin
addr := std_logic_vector(to_unsigned(intaddr, 8));
return addr;
end canint2addr;
-- convertes the input register address to select signal
function canint2sel(
constant intaddr : integer
) return std_logic_vector is
variable sel: std_logic_vector(3 downto 0);
variable addr : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(intaddr, 8));
begin
case addr (1 downto 0) is
when "00" => sel := "1000";
when "01" => sel := "0100";
when "10" => sel := "0010";
when "11" => sel := "0001";
when others => sel := "1000";
end case;
return sel;
end canint2sel;
--copies the input data to all four possible byte possitions
function data2canwb(
constant data : std_logic_vector(7 downto 0)
) return std_logic_vector is
variable wbcan_data: std_logic_vector(31 downto 0);
begin
wbcan_data(31 downto 24) := data;
wbcan_data(23 downto 16) := data;
wbcan_data(15 downto 8) := data;
wbcan_data(7 downto 0) := data;
return wbcan_data;
end data2canwb;
--does a asynchronous wb-single-write-handshake and writes to an register of the can controller
procedure can_wb_write_reg(
signal wbs_in : out wb_slv_in_type;
signal wbs_out : in wb_slv_out_type;
constant addr : integer;
constant data : in std_logic_vector(7 downto 0);
signal clk : in std_logic) is
begin
wbs_in.dat <= data2canwb(data);
wbs_in.sel <= canint2sel(addr);
wbs_in.adr(7 downto 2) <= canint2addr(addr)(7 downto 2);
wbs_in.stb <= '1';
wbs_in.cyc <= '1';
wbs_in.we <= '1';
wait until wbs_out.ack = '1'; --for 1 ps;
wait until rising_edge(clk);
wbs_in.cyc <= '0';
wbs_in.stb <= '0';
wbs_in.we <= '-';
wbs_in.sel <= (others=>'-');
wbs_in.dat <= (others=>'-');
wbs_in.adr <= (others=>'-');
end can_wb_write_reg;
procedure can_wb_read_reg(
signal wbs_in : out wb_slv_in_type;
signal wbs_out : in wb_slv_out_type;
constant addr : integer;
signal clk : in std_logic) is
begin
wbs_in.sel <= canint2sel(addr);
wbs_in.adr(7 downto 2) <= canint2addr(addr)(7 downto 2);
wbs_in.stb <= '1';
wbs_in.cyc <= '1';
wbs_in.we <= '0';
wait until wbs_out.ack = '1'; --for 1 ps;
wait until rising_edge(clk);
wbs_in.cyc <= '0';
wbs_in.stb <= '0';
wbs_in.we <= '-';
wbs_in.sel <= (others=>'-');
wbs_in.dat <= (others=>'-');
wbs_in.adr <= (others=>'-');
end can_wb_read_reg;
procedure write_regs_from_file(
constant filename : in string;
signal wbs_in : out wb_slv_in_type;
signal wbs_out : in wb_slv_out_type;
signal clk : in std_logic) is
file sourcefile : text open read_mode is filename;
variable input_line : line;
variable data : std_logic_vector(7 downto 0);
variable addr : integer;
begin
while not endfile(sourcefile) loop
readline(sourcefile, input_line); --read line
read(input_line, addr); --read addr of register
read(input_line, data); --read data
can_wb_write_reg(wbs_in, wbs_out, addr, data, clk);
wait for 50 ns;
end loop;
file_close(sourcefile);
end procedure write_regs_from_file;
procedure read_regs_with_fileaddr(
constant filename : in string;
constant out_filename : in string;
signal wbs_in : out wb_slv_in_type;
signal wbs_out : in wb_slv_out_type;
signal clk : in std_logic) is
file sourcefile : text open read_mode is filename;
file targetfile : text open write_mode is out_filename;
variable input_line : line;
variable output_line : line;
variable addr : integer;
-- variable data : std_logic_vector(7 downto 0);
begin
while not endfile(sourcefile) loop
readline(sourcefile, input_line); --read line
read(input_line, addr); --read addr of register
can_wb_read_reg(wbs_in, wbs_out, addr, clk);
wait for 1 ns;
write(output_line,addr);
write(output_line, ' ' );
write(output_line,wbs_out.dat);
writeline(targetfile,output_line);
wait for 49 ns;
end loop;
file_close(sourcefile);
file_close(targetfile);
end procedure read_regs_with_fileaddr;
function can_crc(
constant stream_vector: in std_logic_vector(0 to 82);--(0 to (0 to 19+datasize*8-1);
constant datasize: in integer)return std_logic_vector is
variable crc: std_logic_vector(14 downto 0) := (others=>'0');
variable crc_tmp: std_logic_vector(14 downto 0);
begin
for i in 0 to 19+datasize*8 - 1 loop
crc_tmp(14 downto 1) := crc(13 downto 0);
crc_tmp(0) := '0';
if (stream_vector(i) xor crc(14)) = '1' then
crc := crc_tmp xor "100010110011001";--x"4599";
else
crc := crc_tmp; --110110001111111
end if;
end loop;
return crc;
end function can_crc;
function buildframe(
constant id: in std_logic_vector(10 downto 0);
constant data: in std_logic_vector(0 to 63);
constant datasize: in integer) return std_logic_vector is
variable tx_frame: std_logic_vector(0 to 108);
variable tmp_stream: std_logic_vector(0 to 82) := (others=>'0');
begin
tx_frame(0) := '0'; --start of frame
tx_frame(1 to 11) := id(10 downto 0);
tx_frame(12) := '0'; -- RTR bit (dominant for dataframes)
tx_frame(13 to 14) := "00"; --reseserved/extended bits
--error if datasize is to big
tx_frame(15 to 18) := std_logic_vector(to_unsigned(datasize,4)); -- # of bytes to be transmitted (DLC)
tx_frame(19 to 19+datasize*8-1) := data(0 to datasize*8-1);
tmp_stream(0 to 19+datasize*8-1) := tx_frame(0 to 19+datasize*8-1); -- setup stream for crc calculation
tx_frame(20+datasize*8-1 to 34+datasize*8-1) := can_crc(tmp_stream, datasize);
tx_frame(35+datasize*8-1) := '1'; --CRC delimiter (must be recessiv)
tx_frame(36+datasize*8-1 to 37+datasize*8-1) := "11"; -- ACK and delemiter: ack must be sent as recessiv bit
tx_frame(38+datasize*8-1 to 44+datasize*8-1) := "1111111"; -- end of frame(EOF): 7 recessiv bits
--tx_frame(45+datasize*8 to 110) := (others=>X); --
return tx_frame;
end function buildframe;
function select_bit(
constant tx_frame_pointer: in integer;
constant datasize: in integer;
constant tx_frame: in std_logic_vector(0 to 108)) return std_logic_vector is
variable tx_bit: std_logic_vector(0 to 4);
begin
tx_bit(0) := tx_frame(tx_frame_pointer); --actual bit to be sent
if ((tx_frame_pointer <= 11) and (tx_frame_pointer /= 0)) then -- arbitration flag
tx_bit(1) := '1';
else
tx_bit(1) := '0';
end if;
if (tx_frame_pointer <= 34+datasize*8-1) then -- stuffing flag is set, if bitstuffing is enabled in this part of the frame
tx_bit(2) := '1';
else
tx_bit(2) := '0';
end if;
if (tx_frame_pointer = 36+datasize*8-1) then -- ack flag is set if the ack bit in the frame is reached
tx_bit(3) := '1';
else
tx_bit(3) := '0';
end if;
if (tx_frame_pointer = 44+datasize*8-1) then -- last bit flag is set when the last bit is reached
tx_bit(4) := '1';
else
tx_bit(4) := '0';
end if;
return tx_bit;
end function select_bit;
procedure set_bit(
signal tx: out std_logic;
constant tx_bit: in std_logic_vector(0 to 4);
constant t_bit: in time;
variable tx_history: inout std_logic_vector(3 downto 0)) is
begin
--bit stuffing is enabled when flag is set
tx <= tx_bit(0);
wait for t_bit/2;
if (tx_bit(2) = '1') and (tx_history(0) = tx_history(1)) and (tx_history(1) = tx_history(2)) and (tx_history(2) = tx_history(3)) and (tx_history(3) = tx_bit(0)) then
tx_history(0) := tx_history(1);
tx_history(1) := tx_history(2);
tx_history(2) := tx_history(3);
tx_history(3) := tx_bit(0);
wait for t_bit/2;
report "stuffing now";
tx <= not(tx_bit(0));
wait for t_bit/2;
tx_history(0) := tx_history(1);
tx_history(1) := tx_history(2);
tx_history(2) := tx_history(3);
tx_history(3) := not(tx_bit(0));
else
tx_history(0) := tx_history(1);
tx_history(1) := tx_history(2);
tx_history(2) := tx_history(3);
tx_history(3) := tx_bit(0);
end if;
--report "tx_history(0) " & std_logic'image(tx_history(0));
--report "tx_history(1) " & std_logic'image(tx_history(1));
--report "tx_history(2) " & std_logic'image(tx_history(2));
--report "tx_history(3) " & std_logic'image(tx_history(3));
end procedure set_bit;
procedure simulate_can_transmission(
constant id : in std_logic_vector(10 downto 0);
constant data: in std_logic_vector (0 to 63);
constant datasize: in integer;
constant t_bit: in time;
signal rx: in std_logic;
signal tx: inout std_logic;
signal test_result: out rx_check_result) is
variable tx_frame: std_logic_vector(0 to 108);
variable tx_bit: std_logic_vector(0 to 4):= "00000"; --0: actualmachine bit, 1: arbitration flag, 2: stuffing flag, 3: ack flag, 4:last bit flag
variable tx_frame_pointer: integer := 0;
variable tx_history: std_logic_vector(3 downto 0);
--variable rx_history: std_logic_vector(5 downto 0);
begin
tx_frame := buildframe(id, data, datasize);
while tx_bit(4) = '0' loop --while last bit is not yet reached
tx_bit := select_bit(tx_frame_pointer, datasize, tx_frame); --selects next bit to be sent and sets flags
--report "txbit " & std_logic'image(tx_bit(2));
set_bit(tx, tx_bit, t_bit, tx_history); --handles bit stuffing and tx signal interaction
--check if arbitration is lostmachine
if tx_bit(1) = '1' and rx /= tx then
test_result <= arbitration_lost;
return;
end if;
-- check if ack is sent by the receiver
if tx_bit(3) = '1' and rx /= '0' then
test_result <= no_ack;
return;
end if;
--check if rx = tx if not: error; ausnahmen: arbitration lost, ack
if tx_bit(1) = '0' and tx_bit(3) = '0' and rx /= tx then
test_result <= can_error;
return;
end if;
wait for t_bit/2;
tx_frame_pointer := tx_frame_pointer + 1;
end loop;
test_result <= success;
end procedure simulate_can_transmission;
--TODO:
end can_tp;