-- -------------------------------------------------------------------------- -- -- jinn.vhd: A simple Wishbone interface, controllable via UART. -- -- Copyright (C) 2017 Markus Koch -- -- This Source Code Form is subject to the terms of the Mozilla Public -- License, v. 2.0. If a copy of the MPL was not distributed with this -- file, You can obtain one at http://mozilla.org/MPL/2.0/. -- -------------------------------------------------------------------------- -- -- -- Instructions: -- Write: TX [Write-Count] [32b Addr] [32b Data] -------- [32b Addr] [32b Data] -------- ... [Write-Count] [32b Addr] [32b Data] ... -- RX ----------------------------------- [8b CKS] --------------------- [8b CKS] ... ----------------------------------- ... -- -- Read: TX [8b 0x0] [32b Addr] ---------- [32b Addr] ... -- RX ------------------- [32b Data] ---------- ... -- -- Stall: TX [8b 0xFF] -- RX --------- -- -- Reset: TX [8b 0xFE] -- --------- -- -- Log: -- 2015/06/24: Created file -- 2015/06/24: Removed logic for tx/rx buffers -- 2015/07/14: Added stall/reset logic library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library ip; use ip.wishbone_package.all; entity jinn is port( clk_i : in std_logic; rst_i : in std_logic; -- Wishbone master_i : in wishbone_v3_master_in; master_o : out wishbone_v3_master_out; -- CPU Control cpu_stall : out std_logic; cpu_reset : out std_logic; -- Data link data_i : in std_logic_vector(7 downto 0); -- Data in from UART data_available : in std_logic; -- UART RX strobe data_o : out std_logic_vector(7 downto 0); -- Data out to UART data_valid_o : out std_logic; -- Data out strobe output_busy_i : in std_logic -- Transmit busy -> stall core ); end entity jinn; architecture RTL of jinn is signal write_counter : integer range 0 to 255; signal position : integer range 0 to 7; signal address : wishbone_address; signal data : wishbone_data; signal cks : unsigned(7 downto 0); type state_t is (COMMAND, PARSE, EXECUTE, TXSERIAL); signal state : state_t; signal txDelay : std_logic; begin jinn_p : process(clk_i, rst_i) is begin if rst_i = '1' then -- RESET! position <= 0; state <= COMMAND; write_counter <= 0; data_valid_o <= '0'; address <= (others => '0'); data <= (others => '0'); master_o.CYC <= '0'; master_o.STB <= '0'; master_o.ADR <= (others => '0'); master_o.DAT <= (others => '0'); master_o.WE <= '0'; txDelay <= '0'; cks <= (others => '0'); cpu_stall <= '0'; cpu_reset <= '1'; elsif rising_edge(clk_i) then data_valid_o <= '0'; master_o.CYC <= '0'; master_o.STB <= '0'; cpu_reset <= '0'; case state is when COMMAND => cks <= (others => '0'); position <= 0; txDelay <= '0'; if data_available = '1' then if unsigned(data_i) = x"FF" then cpu_stall <= '1'; elsif unsigned(data_i) = x"FE" then cpu_reset <= '1'; cpu_stall <= '0'; else write_counter <= to_integer(unsigned(data_i)); state <= PARSE; end if; end if; when PARSE => if data_available = '1' then cks <= cks + unsigned(data_i); -- Sum everything, address and data if position < 7 then position <= position + 1; end if; if position < 4 then -- addr word --address(8 * (position + 1) - 1 downto 8 * position) <= data_i; address <= address(23 downto 0) & data_i; else -- data word --data(8 * (position + 1 - 4) - 1 downto 8 * (position - 4)) <= data_i; data <= data(23 downto 0) & data_i; end if; if (position = 7) or (position = 3 and write_counter = 0) then -- only retrieve address in read mode position <= 0; state <= EXECUTE; -- master_o.ADR <= address; -- master_o.DAT <= data; -- master_o.CYC <= '1'; -- master_o.STB <= '1'; -- if write_counter = 0 then -- master_o.WE <= '0'; -- else -- master_o.WE <= '1'; -- end if; end if; end if; when EXECUTE => master_o.ADR <= address; master_o.DAT <= data; master_o.CYC <= '1'; master_o.STB <= '1'; if write_counter = 0 then master_o.WE <= '0'; else master_o.WE <= '1'; end if; if master_i.ERR = '1' or master_i.ACK = '1' then -- END OF transmission master_o.CYC <= '0'; master_o.STB <= '0'; if write_counter = 0 then -- read data <= master_i.DAT; state <= TXSERIAL; position <= 0; else write_counter <= write_counter - 1; if master_i.ACK = '1' then data <= std_logic_vector(cks) & x"000000"; -- ACK! else data <= not std_logic_vector(cks) & x"FFFFFF"; -- NAK! by sending a probably woring checksum end if; position <= 3; -- Only transmit one byte (the checksum) state <= TXSERIAL; cks <= (others => '0'); end if; elsif master_i.RTY = '1' then null; -- wait end if; when TXSERIAL => txDelay <= not txDelay; if txDelay = '0' and output_busy_i = '0' then -- only every odd cycle (uart has a busy-activate delay of 1) --data_o <= address(8 * (position + 1) - 1 downto 8 * position); data_o <= data(31 downto 24); data <= data(23 downto 0) & x"00"; data_valid_o <= '1'; if position = 3 then position <= 0; if write_counter = 0 then state <= COMMAND; -- R/W selector (Write-Count) else state <= PARSE; -- more writes are following directly end if; else position <= position + 1; end if; end if; end case; --master_o.CYC <= '0'; -- DEBUG ONLY - diasble moduel --master_o.STB <= '0'; -- DEBUG ONYL end if; end process jinn_p; master_o.SEL <= "1111"; master_o.BTE <= (others => '0'); master_o.CTI <= (others => '0'); master_o.LOCK <= '0'; end architecture RTL;