Skip to content

Instantly share code, notes, and snippets.

@quackduck
Last active May 23, 2025 06:25
Show Gist options
  • Save quackduck/ce3fec526cb8595ed7f6fc644b1f4f05 to your computer and use it in GitHub Desktop.
Save quackduck/ce3fec526cb8595ed7f6fc644b1f4f05 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
);
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 stream_data_out: std_logic_vector(31 downto 0);
signal data : data_array := (others => (others => '0'));
-- signal jump_table : addr_array; -- Maps each instruction address to its matching bracket
signal jump_table : addr_array := (others => (others => '0'));
signal preprocessing_done : std_logic := '0';
signal preprocess_state : integer := 0;
signal bracket_stack : addr_array := (others => (others => '0')); -- Temporary stack for preprocessing
signal bracket_stack_ptr : integer := 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 => -- Initialize
temp_iptr := 0;
temp_stack_ptr := 0;
preprocess_state <= 1;
when 1 => -- Process each instruction
if (temp_iptr < NUMBER_OF_OUTPUT_WORDS) then
if (program_buf(temp_iptr) = x"5b") then -- '['
-- Push current position onto stack
stream_data_out(9 downto 0) <= std_logic_vector(to_unsigned(temp_iptr, 10)); -- debugging
stream_data_out(25 downto 16) <= std_logic_vector(to_unsigned(temp_stack_ptr, 10));
stream_data_out(31 downto 30) <= std_logic_vector(to_unsigned(3, 2));
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 -- ']'
-- Pop from stack and create bidirectional mapping
temp_stack_ptr := temp_stack_ptr - 1;
stream_data_out(9 downto 0) <= std_logic_vector(to_unsigned(temp_iptr, 10)); -- debugging
stream_data_out(25 downto 16) <= bracket_stack(temp_stack_ptr);
stream_data_out(31 downto 30) <= std_logic_vector(to_unsigned(1, 2));
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 ]
-- -- hardcoded for testing
-- jump_table(5) <= std_logic_vector(to_unsigned(6, 10));
-- jump_table(6) <= std_logic_vector(to_unsigned(5, 10));
end if;
temp_iptr := temp_iptr + 1;
else
preprocessing_done <= '1';
preprocess_state <= 2;
end if;
when others =>
-- Preprocessing complete
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);
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
inst := program_buf(iptr);
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" => -- '.'
-- stream_data_out(7 downto 0) <= data(dptr);
when x"2c" => -- ','
-- Input handling - need to implement this based on input source
when x"5b" => -- '['
-- stream_data_out(9 downto 0) <= std_logic_vector(unsigned(jump_table(iptr)));
if (data(dptr) = x"00") then
-- Jump to matching ']'
iptr := to_integer(unsigned(jump_table(iptr)));
end if;
when x"5d" => -- ']'
-- stream_data_out(9 downto 0) <= std_logic_vector(unsigned(jump_table(iptr)));
if (data(dptr) /= x"00") then
-- Jump back to matching '['
iptr := to_integer(unsigned(jump_table(iptr)));
end if;
when others =>
-- Unknown instruction, continue
null;
end case;
iptr := iptr + 1;
end if;
end if;
end if;
end process;
-- process(M_AXIS_ACLK)
-- variable dptr : integer := 0;
-- variable iptr : integer := 0;
-- variable sptr : integer := 0;
-- variable inst : std_logic_vector(7 downto 0);
-- begin
-- if (rising_edge (M_AXIS_ACLK)) then
-- if (start = '1') then
-- if (tx_en = '1') then
-- -- stream_data_out(3 downto 0) <= std_logic_vector(to_unsigned(55, 4)); --
-- -- stream_data_out(7 downto 0) <= std_logic_vector(unsigned(program_buf(iptr)) + 0); -- for testing
-- -- stream_data_out(7 downto 0) <= std_logic_vector(to_unsigned(iptr + 0, 8)); -- for testing
-- -- stream_data_out(7 downto 0) <= x"07";
-- -- stream_data_out(15 downto 0) <= std_logic_vector(unsigned(program_buf(iptr)) * unsigned(program_buf(iptr))); -- for testing
-- inst := program_buf(iptr);
-- if (inst = x"3e") then
-- dptr := dptr + 1;
-- -- stream_data_out(3 downto 0) <= ;
-- elsif (inst = x"3c") then
-- dptr := dptr - 1;
-- elsif (inst = x"2b") then
-- -- program_buf(iptr) <= std_logic_vector(program_buf(iptr) + 1);
-- data(dptr) <= std_logic_vector(unsigned(data(dptr)) + 1);
-- elsif (inst = x"2d") then
-- data(dptr) <= std_logic_vector(unsigned(data(dptr)) - 1);
-- elsif (inst = x"2e") then
-- stream_data_out(7 downto 0) <= data(dptr);
-- elsif (inst = x"2c") then
-- -- how do we handle input??
-- elsif (inst = x"5b") then
-- -- stack(sptr) <= std_logic_vector(to_unsigned(iptr, 32));
-- -- sptr := sptr + 1;
-- elsif (inst = x"5d") then
-- -- sptr := sptr - 1;
-- -- iptr := to_integer(unsigned(stack(sptr))) - 1;
-- end if;
-- -- if (inst = x"0") then
-- -- -- tx_done <= '1';
-- -- else
-- -- tx_done <= '0';
-- iptr := iptr + 1;
-- -- end if;
-- 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;
--read_pointer pointer
-- process(M_AXIS_ACLK)
-- begin
-- if (rising_edge (M_AXIS_ACLK)) then
-- if(M_AXIS_ARESETN = '0') then
-- read_pointer <= 0;
-- tx_done <= '0';
-- else
-- if (read_pointer <= NUMBER_OF_OUTPUT_WORDS-1) then
-- if (tx_en = '1') then
-- -- read pointer is incremented after every read from the FIFO
-- -- when FIFO read signal is enabled.
-- -- read_pointer <= read_pointer + 1;
-- tx_done <= '0';
-- end if;
-- elsif (read_pointer = NUMBER_OF_OUTPUT_WORDS) then
-- -- tx_done is asserted when NUMBER_OF_OUTPUT_WORDS numbers of streaming data
-- -- has been out.
-- tx_done <= '1';
-- end if;
-- end if;
-- end if;
-- end process;
--FIFO read enable generation
tx_en <= M_AXIS_TREADY and axis_tvalid;
-- FIFO Implementation
-- Streaming output data is read from FIFO
-- process(M_AXIS_ACLK)
-- variable sig_one : integer := 1;
-- begin
-- if (rising_edge (M_AXIS_ACLK)) then
-- if(M_AXIS_ARESETN = '0') then
-- -- stream_data_out <= std_logic_vector(to_unsigned(sig_one,C_M_AXIS_TDATA_WIDTH));
-- elsif (tx_en = '1') then -- && M_AXIS_TSTRB(byte_index)
-- -- stream_data_out <= std_logic_vector( to_unsigned(read_pointer,C_M_AXIS_TDATA_WIDTH) + to_unsigned(sig_one,C_M_AXIS_TDATA_WIDTH));
-- end if;
-- end if;
-- end process;
tx_done <= '0';
end implementation;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment