mor1kx-bemicrocv/cores/jinn.vhd

208 lines
6.3 KiB
VHDL

-- -------------------------------------------------------------------------- --
-- 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/.
-- -------------------------------------------------------------------------- --
--
-- 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;