Skip to content

Instantly share code, notes, and snippets.

@quackduck
Last active May 24, 2025 05:16
Show Gist options
  • Save quackduck/eadc20192e95b465284a719a1e643627 to your computer and use it in GitHub Desktop.
Save quackduck/eadc20192e95b465284a719a1e643627 to your computer and use it in GitHub Desktop.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.my_types.all;
entity bf2_master_stream_v1_0_M00_AXIS is
generic (
-- Users to add parameters here
-- User parameters ends
-- Do not modify the parameters beyond this line
-- Width of S_AXIS address bus. The slave accepts the read and write addresses of width C_M_AXIS_TDATA_WIDTH.
C_M_AXIS_TDATA_WIDTH : integer := 32;
-- Start count is the number of clock cycles the master will wait before initiating/issuing any transaction.
C_M_START_COUNT : integer := 32
);
port (
-- Users to add ports here
-- User ports ends
-- Do not modify the ports beyond this line
-- Global ports
M_AXIS_ACLK : in std_logic;
--
M_AXIS_ARESETN : in std_logic;
-- Master Stream Ports. TVALID indicates that the master is driving a valid transfer, A transfer takes place when both TVALID and TREADY are asserted.
M_AXIS_TVALID : out std_logic;
-- TDATA is the primary payload that is used to provide the data that is passing across the interface from the master.
M_AXIS_TDATA : out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
-- TSTRB is the byte qualifier that indicates whether the content of the associated byte of TDATA is processed as a data byte or a position byte.
M_AXIS_TSTRB : out std_logic_vector((C_M_AXIS_TDATA_WIDTH/8)-1 downto 0);
-- TLAST indicates the boundary of a packet.
M_AXIS_TLAST : out std_logic;
-- TREADY indicates that the slave can accept a transfer in the current cycle.
M_AXIS_TREADY : in std_logic;
program_buf : inout data_array;
start : in std_logic;
led : out std_logic_vector(3 downto 0)
);
end bf2_master_stream_v1_0_M00_AXIS;
architecture implementation of bf2_master_stream_v1_0_M00_AXIS is
-- Total number of output data
constant NUMBER_OF_OUTPUT_WORDS : integer := 1000;
-- function called clogb2 that returns an integer which has the
-- value of the ceiling of the log base 2.
function clogb2 (bit_depth : integer) return integer is
variable depth : integer := bit_depth;
variable count : integer := 1;
begin
for clogb2 in 1 to bit_depth loop -- Works for up to 32 bit integers
if (bit_depth <= 2) then
count := 1;
else
if (depth <= 1) then
count := count;
else
depth := depth / 2;
count := count + 1;
end if;
end if;
end loop;
return(count);
end;
-- WAIT_COUNT_BITS is the width of the wait counter.
constant WAIT_COUNT_BITS : integer := clogb2(C_M_START_COUNT-1);
-- In this example, Depth of FIFO is determined by the greater of
-- the number of input words and output words.
constant depth : integer := NUMBER_OF_OUTPUT_WORDS;
-- -- bit_num gives the minimum number of bits needed to address 'depth' size of FIFO
-- constant bit_num : integer := clogb2(depth);
-- Define the states of state machine
-- The control state machine oversees the writing of input streaming data to the FIFO,
-- and outputs the streaming data from the FIFO
type state is ( IDLE, -- This is the initial/idle state
INIT_COUNTER, -- This state initializes the counter, once
-- the counter reaches C_M_START_COUNT count,
-- the state machine changes state to SEND_STREAM
SEND_STREAM); -- In this state the
-- stream data is output through M_AXIS_TDATA
-- State variable
signal mst_exec_state : state;
-- Example design FIFO read pointer
signal read_pointer : integer range 0 to depth-1;
-- AXI Stream internal signals
--wait counter. The master waits for the user defined number of clock cycles before initiating a transfer.
signal count : std_logic_vector(WAIT_COUNT_BITS-1 downto 0);
--streaming data valid
signal axis_tvalid : std_logic;
--streaming data valid delayed by one clock cycle
signal axis_tvalid_delay : std_logic;
--Last of the streaming data
signal axis_tlast : std_logic;
--Last of the streaming data delayed by one clock cycle
signal axis_tlast_delay : std_logic;
--FIFO implementation signals
signal stream_data_out : std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0) := (others => '0');
signal tx_en : std_logic;
--The master has issued all the streaming data stored in FIFO
signal tx_done : std_logic;
signal data : data_array := (others => (others => '0'));
signal jump_table : addr_array := (others => (others => '0'));
signal preprocessing_done : std_logic := '0';
signal preprocess_state : integer range 0 to 2 := 0;
signal bracket_stack : addr_array := (others => (others => '0'));
signal bracket_stack_ptr : integer := 0;
-- signal iptr : integer range 0 to NUMBER_OF_OUTPUT_WORDS := 0;
-- signal dptr : integer range 0 to NUMBER_OF_OUTPUT_WORDS := 0;
begin
preprocess_program: process(M_AXIS_ACLK)
variable temp_iptr : integer := 0;
variable temp_stack_ptr : integer := 0;
begin
if (rising_edge(M_AXIS_ACLK)) then
if (M_AXIS_ARESETN = '0') then
preprocessing_done <= '0';
preprocess_state <= 0;
bracket_stack_ptr <= 0;
temp_iptr := 0;
temp_stack_ptr := 0;
elsif (start = '1' and preprocessing_done = '0' and tx_en = '1') then
case preprocess_state is
when 0 =>
temp_iptr := 0;
temp_stack_ptr := 0;
preprocess_state <= 1;
when 1 =>
if (temp_iptr < NUMBER_OF_OUTPUT_WORDS) then
if (program_buf(temp_iptr) = x"5b") then -- '['
bracket_stack(temp_stack_ptr) <= std_logic_vector(to_unsigned(temp_iptr, 10));
temp_stack_ptr := temp_stack_ptr + 1;
elsif (program_buf(temp_iptr) = x"5d") then -- ']'
temp_stack_ptr := temp_stack_ptr - 1;
jump_table(temp_iptr) <= bracket_stack(temp_stack_ptr); -- ] points to [
jump_table(to_integer(unsigned(bracket_stack(temp_stack_ptr)))) <= std_logic_vector(to_unsigned(temp_iptr, 10)); -- [ points to ]
end if;
temp_iptr := temp_iptr + 1;
else
preprocessing_done <= '1';
preprocess_state <= 2;
end if;
when others =>
null;
end case;
end if;
end if;
end process;
main_execution: process(M_AXIS_ACLK)
variable dptr : integer := 0;
variable iptr : integer := 0;
variable inst : std_logic_vector(7 downto 0);
variable curr_output : std_logic_vector(7 downto 0);
-- variable jumped: std_logic := '0';
begin
if (rising_edge(M_AXIS_ACLK)) then
if (M_AXIS_ARESETN = '0') then
dptr := 0;
iptr := 0;
elsif (start = '1' and preprocessing_done = '1') then
if (tx_en = '1' and iptr < NUMBER_OF_OUTPUT_WORDS) then
-- led(3 downto 0) <= std_logic_vector(to_unsigned(iptr, 4));
inst := program_buf(iptr);
curr_output := (others => '0');
case inst is
when x"3e" => -- '>'
dptr := dptr + 1;
when x"3c" => -- '<'
dptr := dptr - 1;
when x"2b" => -- '+'
data(dptr) <= std_logic_vector(unsigned(data(dptr)) + 1);
when x"2d" => -- '-'
data(dptr) <= std_logic_vector(unsigned(data(dptr)) - 1);
when x"2e" => -- '.'
curr_output := data(dptr);
when x"2c" => -- ','
-- ummm no input rn
when x"5b" => -- '['
if (data(dptr) = x"00") then
iptr := to_integer(unsigned(jump_table(iptr)));
end if;
when x"5d" => -- ']'
if (data(dptr) /= x"00") then
iptr := to_integer(unsigned(jump_table(iptr)));
end if;
when others =>
null;
end case;
stream_data_out(7 downto 0) <= curr_output;
iptr := iptr + 1;
end if;
end if;
end if;
end process;
-- VIVADO junk
-- I/O Connections assignments
M_AXIS_TVALID <= axis_tvalid_delay;
M_AXIS_TDATA <= stream_data_out;
M_AXIS_TLAST <= axis_tlast_delay;
M_AXIS_TSTRB <= (others => '1');
-- Control state machine implementation
process(M_AXIS_ACLK)
begin
if (rising_edge (M_AXIS_ACLK)) then
if(M_AXIS_ARESETN = '0') then
-- Synchronous reset (active low)
mst_exec_state <= IDLE;
count <= (others => '0');
else
case (mst_exec_state) is
when IDLE =>
-- The slave starts accepting tdata when
-- there tvalid is asserted to mark the
-- presence of valid streaming data
--if (count = "0")then
mst_exec_state <= INIT_COUNTER;
--else
-- mst_exec_state <= IDLE;
--end if;
when INIT_COUNTER =>
-- This state is responsible to wait for user defined C_M_START_COUNT
-- number of clock cycles.
if ( count = std_logic_vector(to_unsigned((C_M_START_COUNT - 1), WAIT_COUNT_BITS))) then
mst_exec_state <= SEND_STREAM;
else
count <= std_logic_vector (unsigned(count) + 1);
mst_exec_state <= INIT_COUNTER;
end if;
when SEND_STREAM =>
-- The example design streaming master functionality starts
-- when the master drives output tdata from the FIFO and the slave
-- has finished storing the S_AXIS_TDATA
if (tx_done = '1') then
mst_exec_state <= IDLE;
else
mst_exec_state <= SEND_STREAM;
end if;
when others =>
mst_exec_state <= IDLE;
end case;
end if;
end if;
end process;
--tvalid generation
--axis_tvalid is asserted when the control state machine's state is SEND_STREAM and
--number of output streaming data is less than the NUMBER_OF_OUTPUT_WORDS.
axis_tvalid <= '1' when ((mst_exec_state = SEND_STREAM) and (read_pointer < NUMBER_OF_OUTPUT_WORDS)) else '0';
-- AXI tlast generation
-- axis_tlast is asserted number of output streaming data is NUMBER_OF_OUTPUT_WORDS-1
-- (0 to NUMBER_OF_OUTPUT_WORDS-1)
axis_tlast <= '1' when (read_pointer = NUMBER_OF_OUTPUT_WORDS-1) else '0';
-- Delay the axis_tvalid and axis_tlast signal by one clock cycle
-- to match the latency of M_AXIS_TDATA
process(M_AXIS_ACLK)
begin
if (rising_edge (M_AXIS_ACLK)) then
if(M_AXIS_ARESETN = '0') then
axis_tvalid_delay <= '0';
axis_tlast_delay <= '0';
else
axis_tvalid_delay <= axis_tvalid;
axis_tlast_delay <= axis_tlast;
end if;
end if;
end process;
tx_en <= M_AXIS_TREADY and axis_tvalid;
tx_done <= '0';
end implementation;
@quackduck
Copy link
Author

quackduck commented May 24, 2025

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.my_types.all;

entity bf2 is
	generic (
		-- Users to add parameters here

		-- User parameters ends
		-- Do not modify the parameters beyond this line


		-- Parameters of Axi Slave Bus Interface S00_AXIS
		C_S00_AXIS_TDATA_WIDTH	: integer	:= 32;

		-- Parameters of Axi Master Bus Interface M00_AXIS
		C_M00_AXIS_TDATA_WIDTH	: integer	:= 32;
		C_M00_AXIS_START_COUNT	: integer	:= 32
	);
	port (
		-- Users to add ports here

		led : out std_logic_vector(3 downto 0);

		-- User ports ends
		-- Do not modify the ports beyond this line


		-- Ports of Axi Slave Bus Interface S00_AXIS
		s00_axis_aclk	: in std_logic;
		s00_axis_aresetn	: in std_logic;
		s00_axis_tready	: out std_logic;
		s00_axis_tdata	: in std_logic_vector(C_S00_AXIS_TDATA_WIDTH-1 downto 0);
		s00_axis_tstrb	: in std_logic_vector((C_S00_AXIS_TDATA_WIDTH/8)-1 downto 0);
		s00_axis_tlast	: in std_logic;
		s00_axis_tvalid	: in std_logic;

		-- Ports of Axi Master Bus Interface M00_AXIS
		m00_axis_aclk	: in std_logic;
		m00_axis_aresetn	: in std_logic;
		m00_axis_tvalid	: out std_logic;
		m00_axis_tdata	: out std_logic_vector(C_M00_AXIS_TDATA_WIDTH-1 downto 0);
		m00_axis_tstrb	: out std_logic_vector((C_M00_AXIS_TDATA_WIDTH/8)-1 downto 0);
		m00_axis_tlast	: out std_logic;
		m00_axis_tready	: in std_logic
	);
end bf2;

architecture arch_imp of bf2 is

	-- component declaration
	component bf2_master_stream_v1_0_M00_AXIS is
		generic (
			C_M_AXIS_TDATA_WIDTH	: integer	:= 32;
			C_M_START_COUNT	: integer	:= 32
		);
		port (
			M_AXIS_ACLK	: in std_logic;
			M_AXIS_ARESETN	: in std_logic;
			M_AXIS_TVALID	: out std_logic;
			M_AXIS_TDATA	: out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
			M_AXIS_TSTRB	: out std_logic_vector((C_M_AXIS_TDATA_WIDTH/8)-1 downto 0);
			M_AXIS_TLAST	: out std_logic;
			M_AXIS_TREADY	: in std_logic;
	
			program_buf : inout data_array;
			start : in std_logic;
			led : out std_logic_vector(3 downto 0)
		);
	end component bf2_master_stream_v1_0_M00_AXIS;

	component bf2_slave_stream_v1_0_S00_AXIS is
		generic (
			C_S_AXIS_TDATA_WIDTH	: integer	:= 32
		);
		port (
			S_AXIS_ACLK	: in std_logic;
			S_AXIS_ARESETN	: in std_logic;
			S_AXIS_TREADY	: out std_logic;
			S_AXIS_TDATA	: in std_logic_vector(C_S_AXIS_TDATA_WIDTH-1 downto 0);
			S_AXIS_TSTRB	: in std_logic_vector((C_S_AXIS_TDATA_WIDTH/8)-1 downto 0);
			S_AXIS_TLAST	: in std_logic;
			S_AXIS_TVALID	: in std_logic;
	
			program_buf	: inout data_array;
			start : out std_logic
		);
	end component bf2_slave_stream_v1_0_S00_AXIS;


	signal program_buf : data_array := (others => (others => '0'));
	-- signal stack : data_array;
	signal start : std_logic := '0';
begin

-- Instantiation of Axi Bus Interface S00_AXIS
bf2_slave_stream_v1_0_S00_AXIS_inst : bf2_slave_stream_v1_0_S00_AXIS
	generic map (
		C_S_AXIS_TDATA_WIDTH	=> C_S00_AXIS_TDATA_WIDTH
	)
	port map (
		S_AXIS_ACLK	=> s00_axis_aclk,
		S_AXIS_ARESETN	=> s00_axis_aresetn,
		S_AXIS_TREADY	=> s00_axis_tready,
		S_AXIS_TDATA	=> s00_axis_tdata,
		S_AXIS_TSTRB	=> s00_axis_tstrb,
		S_AXIS_TLAST	=> s00_axis_tlast,
		S_AXIS_TVALID	=> s00_axis_tvalid,

		program_buf => program_buf,
		start => start
	);

-- Instantiation of Axi Bus Interface M00_AXIS
bf2_master_stream_v1_0_M00_AXIS_inst : bf2_master_stream_v1_0_M00_AXIS
	generic map (
		C_M_AXIS_TDATA_WIDTH	=> C_M00_AXIS_TDATA_WIDTH,
		C_M_START_COUNT	=> C_M00_AXIS_START_COUNT
	)
	port map (
		M_AXIS_ACLK	=> m00_axis_aclk,
		M_AXIS_ARESETN	=> m00_axis_aresetn,
		M_AXIS_TVALID	=> m00_axis_tvalid,
		M_AXIS_TDATA	=> m00_axis_tdata,
		M_AXIS_TSTRB	=> m00_axis_tstrb,
		M_AXIS_TLAST	=> m00_axis_tlast,
		M_AXIS_TREADY	=> m00_axis_tready,

		program_buf => program_buf,
		start => start,
		led => led
	);

	-- Add user logic here

	-- User logic ends

end arch_imp;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package my_types is
    -- subtype data_word is std_logic_vector(31 downto 0);

    type data_array is array (0 to 1000) of std_logic_vector(7 downto 0);
    type addr_array is array (0 to 1000) of std_logic_vector(9 downto 0);
    -- subtype ptr is integer;
end package my_types;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


use work.my_types.all;



entity bf2_slave_stream_v1_0_S00_AXIS is
	generic (
		-- Users to add parameters here

		-- User parameters ends
		-- Do not modify the parameters beyond this line

		-- AXI4Stream sink: Data Width
		C_S_AXIS_TDATA_WIDTH	: integer	:= 32
	);
	port (
		-- Users to add ports here

		-- User ports ends
		-- Do not modify the ports beyond this line

		-- AXI4Stream sink: Clock
		S_AXIS_ACLK	: in std_logic;
		-- AXI4Stream sink: Reset
		S_AXIS_ARESETN	: in std_logic;
		-- Ready to accept data in
		S_AXIS_TREADY	: out std_logic;
		-- Data in
		S_AXIS_TDATA	: in std_logic_vector(C_S_AXIS_TDATA_WIDTH-1 downto 0);
		-- Byte qualifier
		S_AXIS_TSTRB	: in std_logic_vector((C_S_AXIS_TDATA_WIDTH/8)-1 downto 0);
		-- Indicates boundary of last packet
		S_AXIS_TLAST	: in std_logic;
		-- Data is in valid
		S_AXIS_TVALID	: in std_logic;

		program_buf	: out data_array;
		start : out std_logic
	);
end bf2_slave_stream_v1_0_S00_AXIS;

architecture arch_imp of bf2_slave_stream_v1_0_S00_AXIS is
	-- function called clogb2 that returns an integer which has the 
	-- value of the ceiling of the log base 2.
	function clogb2 (bit_depth : integer) return integer is 
	variable depth  : integer := bit_depth;
	  begin
	    if (depth = 0) then
	      return(0);
	    else
	      for clogb2 in 1 to bit_depth loop  -- Works for up to 32 bit integers
	        if(depth <= 1) then 
	          return(clogb2);      
	        else
	          depth := depth / 2;
	        end if;
	      end loop;
	    end if;
	end;    

	-- Total number of input data.
	constant NUMBER_OF_INPUT_WORDS  : integer := 1000;
	-- -- bit_num gives the minimum number of bits needed to address 'NUMBER_OF_INPUT_WORDS' size of FIFO.
	-- constant bit_num  : integer := clogb2(NUMBER_OF_INPUT_WORDS-1);
	-- Define the states of state machine
	-- The control state machine oversees the writing of input streaming data to the FIFO,
	-- and outputs the streaming data from the FIFO
	type state is ( IDLE,        -- This is the initial/idle state 
	                WRITE_FIFO); -- In this state FIFO is written with the
	                             -- input stream data S_AXIS_TDATA 
	signal axis_tready	: std_logic;
	-- State variable
	signal  mst_exec_state : state;  
	-- FIFO implementation signals
	signal  byte_index : integer;    
	-- FIFO write enable
	signal fifo_wren : std_logic;
	-- FIFO full flag
	signal fifo_full_flag : std_logic;
	-- FIFO write pointer
	signal write_pointer : integer range 0 to NUMBER_OF_INPUT_WORDS-1 ;
	-- sink has accepted all the streaming data and stored in FIFO
	signal writes_done : std_logic;

	-- type BYTE_FIFO_TYPE is array (0 to (NUMBER_OF_INPUT_WORDS-1)) of std_logic_vector(((C_S_AXIS_TDATA_WIDTH/4)-1)downto 0);
begin
	-- I/O Connections assignments

	S_AXIS_TREADY	<= axis_tready;
	-- Control state machine implementation
	process(S_AXIS_ACLK)
	begin
	  if (rising_edge (S_AXIS_ACLK)) then
	    if(S_AXIS_ARESETN = '0') then
	      -- Synchronous reset (active low)
	      mst_exec_state      <= IDLE;
	    else
	      case (mst_exec_state) is
	        when IDLE     => 
	          -- The sink starts accepting tdata when 
	          -- there tvalid is asserted to mark the
	          -- presence of valid streaming data 
	          if (S_AXIS_TVALID = '1')then
	            mst_exec_state <= WRITE_FIFO;
	          else
	            mst_exec_state <= IDLE;
	          end if;
	      
	        when WRITE_FIFO => 
	          -- When the sink has accepted all the streaming input data,
	          -- the interface swiches functionality to a streaming master
	          if (writes_done = '1') then
	            mst_exec_state <= IDLE;
	          else
	            -- The sink accepts and stores tdata 
	            -- into FIFO
	            mst_exec_state <= WRITE_FIFO;
	          end if;
	        
	        when others    => 
	          mst_exec_state <= IDLE;
	        
	      end case;
	    end if;  
	  end if;
	end process;
	-- AXI Streaming Sink 
	-- 
	-- The example design sink is always ready to accept the S_AXIS_TDATA  until
	-- the FIFO is not filled with NUMBER_OF_INPUT_WORDS number of input words.
	axis_tready <= '1' when ((mst_exec_state = WRITE_FIFO) and (write_pointer <= NUMBER_OF_INPUT_WORDS-1)) else '0';

	process(S_AXIS_ACLK)
	begin
	  if (rising_edge (S_AXIS_ACLK)) then
	    if(S_AXIS_ARESETN = '0') then
	      write_pointer <= 0;
	      writes_done <= '0';
	    else
	      if (write_pointer <= NUMBER_OF_INPUT_WORDS-1) then
	        if (fifo_wren = '1') then
	          -- write pointer is incremented after every write to the FIFO
	          -- when FIFO write signal is enabled.
	          write_pointer <= write_pointer + 1;
	          writes_done <= '0';
	        end if;
	        if ((write_pointer = NUMBER_OF_INPUT_WORDS-1) or S_AXIS_TLAST = '1') then
	          -- reads_done is asserted when NUMBER_OF_INPUT_WORDS numbers of streaming data 
	          -- has been written to the FIFO which is also marked by S_AXIS_TLAST(kept for optional usage).
	          writes_done <= '1';
			  start <= '1';
	        end if;
	      end  if;
	    end if;
	  end if;
	end process;

	-- FIFO write enable generation
	fifo_wren <= S_AXIS_TVALID and axis_tready;

	-- FIFO Implementation
	--  FIFO_GEN: for byte_index in 0 to (C_S_AXIS_TDATA_WIDTH/8-1) generate

	--  signal stream_data_fifo : BYTE_FIFO_TYPE;
	--  begin   
	  -- Streaming input data is stored in FIFO
	  process(S_AXIS_ACLK)
	  begin
	    if (rising_edge (S_AXIS_ACLK)) then
	      if (fifo_wren = '1') then
			program_buf(write_pointer) <= S_AXIS_TDATA(7 downto 0);
	      end if;
	    end if;
	  end process;

	-- end generate FIFO_GEN;

	-- Add user logic here

	-- User logic ends

end arch_imp;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment