2017-03-17 22:10:27 +01:00
|
|
|
-- -------------------------------------------------------------------------- --
|
|
|
|
-- jinn.vhd: A simple Wishbone interface, controllable via UART.
|
|
|
|
--
|
|
|
|
-- Copyright (C) 2017 Markus Koch <markus@notsyncing.net>
|
|
|
|
--
|
|
|
|
-- 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/.
|
|
|
|
-- -------------------------------------------------------------------------- --
|
|
|
|
|
2016-08-04 19:22:38 +02:00
|
|
|
--
|
|
|
|
-- 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;
|