forked from cores/microwatt
Compare commits
1 Commits
master
...
remove-pot
Author | SHA1 | Date |
---|---|---|
Anton Blanchard | 1d29cdcfb4 | 3 years ago |
@ -1,91 +0,0 @@
|
||||
-- The Potato Processor - A simple processor for FPGAs
|
||||
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
--! @brief A generic FIFO module.
|
||||
--! Adopted from the FIFO module in <https://github.com/skordal/smallthings>.
|
||||
entity pp_fifo is
|
||||
generic(
|
||||
DEPTH : natural := 64;
|
||||
WIDTH : natural := 32
|
||||
);
|
||||
port(
|
||||
-- Control lines:
|
||||
clk : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
-- Status lines:
|
||||
full : out std_logic;
|
||||
empty : out std_logic;
|
||||
|
||||
-- Data in:
|
||||
data_in : in std_logic_vector(WIDTH - 1 downto 0);
|
||||
data_out : out std_logic_vector(WIDTH - 1 downto 0);
|
||||
push, pop : in std_logic
|
||||
);
|
||||
end entity pp_fifo;
|
||||
|
||||
architecture behaviour of pp_fifo is
|
||||
|
||||
type memory_array is array(0 to DEPTH - 1) of std_logic_vector(WIDTH - 1 downto 0);
|
||||
signal memory : memory_array := (others => (others => '0'));
|
||||
|
||||
subtype index_type is integer range 0 to DEPTH - 1;
|
||||
signal top, bottom : index_type;
|
||||
|
||||
type fifo_op is (FIFO_POP, FIFO_PUSH);
|
||||
signal prev_op : fifo_op := FIFO_POP;
|
||||
|
||||
begin
|
||||
|
||||
empty <= '1' when top = bottom and prev_op = FIFO_POP else '0';
|
||||
full <= '1' when top = bottom and prev_op = FIFO_PUSH else '0';
|
||||
|
||||
read: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
bottom <= 0;
|
||||
else
|
||||
if pop = '1' then
|
||||
data_out <= memory(bottom);
|
||||
bottom <= (bottom + 1) mod DEPTH;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process read;
|
||||
|
||||
write: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
top <= 0;
|
||||
else
|
||||
if push = '1' then
|
||||
memory(top) <= data_in;
|
||||
top <= (top + 1) mod DEPTH;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process write;
|
||||
|
||||
set_prev_op: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
prev_op <= FIFO_POP;
|
||||
else
|
||||
if push = '1' and pop = '1' then
|
||||
-- Keep the same value for prev_op
|
||||
elsif push = '1' then
|
||||
prev_op <= FIFO_PUSH;
|
||||
elsif pop = '1' then
|
||||
prev_op <= FIFO_POP;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process set_prev_op;
|
||||
|
||||
end architecture behaviour;
|
@ -1,395 +0,0 @@
|
||||
-- The Potato Processor - A simple processor for FPGAs
|
||||
-- (c) Kristian Klomsten Skordal 2014 - 2016 <kristian.skordal@wafflemail.net>
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
--! @brief Simple UART module.
|
||||
--! The following registers are defined:
|
||||
--! |--------------------|--------------------------------------------|
|
||||
--! | Address | Description |
|
||||
--! |--------------------|--------------------------------------------|
|
||||
--! | 0x00 | Transmit register (write-only) |
|
||||
--! | 0x08 | Receive register (read-only) |
|
||||
--! | 0x10 | Status register (read-only) |
|
||||
--! | 0x18 | Sample clock divisor register (read/write) |
|
||||
--! | 0x20 | Interrupt enable register (read/write) |
|
||||
--! |--------------------|--------------------------------------------|
|
||||
--!
|
||||
--! The status register contains the following bits:
|
||||
--! - Bit 0: receive buffer empty
|
||||
--! - Bit 1: transmit buffer empty
|
||||
--! - Bit 2: receive buffer full
|
||||
--! - Bit 3: transmit buffer full
|
||||
--!
|
||||
--! The sample clock divisor should be set according to the formula:
|
||||
--! sample_clk = (f_clk / (baudrate * 16)) - 1
|
||||
--!
|
||||
--! If the sample clock divisor register is set to 0, the sample clock
|
||||
--! is stopped.
|
||||
--!
|
||||
--! Interrupts are enabled by setting the corresponding bit in the interrupt
|
||||
--! enable register. The following bits are available:
|
||||
--! - Bit 0: data received (receive buffer not empty)
|
||||
--! - Bit 1: ready to send data (transmit buffer empty)
|
||||
entity pp_soc_uart is
|
||||
generic(
|
||||
FIFO_DEPTH : natural := 64 --! Depth of the input and output FIFOs.
|
||||
);
|
||||
port(
|
||||
clk : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
-- UART ports:
|
||||
txd : out std_logic;
|
||||
rxd : in std_logic;
|
||||
|
||||
-- Interrupt signal:
|
||||
irq : out std_logic;
|
||||
|
||||
-- Wishbone ports:
|
||||
wb_adr_in : in std_logic_vector(11 downto 0);
|
||||
wb_dat_in : in std_logic_vector( 7 downto 0);
|
||||
wb_dat_out : out std_logic_vector( 7 downto 0);
|
||||
wb_we_in : in std_logic;
|
||||
wb_cyc_in : in std_logic;
|
||||
wb_stb_in : in std_logic;
|
||||
wb_ack_out : out std_logic
|
||||
);
|
||||
end entity pp_soc_uart;
|
||||
|
||||
architecture behaviour of pp_soc_uart is
|
||||
|
||||
subtype bitnumber is natural range 0 to 7; --! Type representing the index of a bit.
|
||||
|
||||
-- UART sample clock signals:
|
||||
signal sample_clk : std_logic;
|
||||
signal sample_clk_divisor : std_logic_vector(7 downto 0);
|
||||
signal sample_clk_counter : std_logic_vector(sample_clk_divisor'range);
|
||||
|
||||
-- UART receive process signals:
|
||||
type rx_state_type is (IDLE, RECEIVE, STARTBIT, STOPBIT);
|
||||
signal rx_state : rx_state_type;
|
||||
signal rx_byte : std_logic_vector(7 downto 0);
|
||||
signal rx_current_bit : bitnumber;
|
||||
|
||||
subtype rx_sample_counter_type is natural range 0 to 15;
|
||||
signal rx_sample_counter : rx_sample_counter_type;
|
||||
signal rx_sample_value : rx_sample_counter_type;
|
||||
|
||||
subtype rx_sample_delay_type is natural range 0 to 7;
|
||||
signal rx_sample_delay : rx_sample_delay_type;
|
||||
|
||||
-- UART transmit process signals:
|
||||
type tx_state_type is (IDLE, TRANSMIT, STOPBIT);
|
||||
signal tx_state : tx_state_type;
|
||||
signal tx_byte : std_logic_vector(7 downto 0);
|
||||
signal tx_current_bit : bitnumber;
|
||||
|
||||
-- UART transmit clock:
|
||||
subtype uart_tx_counter_type is natural range 0 to 15;
|
||||
signal uart_tx_counter : uart_tx_counter_type := 0;
|
||||
signal uart_tx_clk : std_logic;
|
||||
|
||||
-- Buffer signals:
|
||||
signal send_buffer_full, send_buffer_empty : std_logic;
|
||||
signal recv_buffer_full, recv_buffer_empty : std_logic;
|
||||
signal send_buffer_input, send_buffer_output : std_logic_vector(7 downto 0);
|
||||
signal recv_buffer_input, recv_buffer_output : std_logic_vector(7 downto 0);
|
||||
signal send_buffer_push, send_buffer_pop : std_logic := '0';
|
||||
signal recv_buffer_push, recv_buffer_pop : std_logic := '0';
|
||||
|
||||
-- IRQ enable signals:
|
||||
signal irq_recv_enable, irq_tx_ready_enable : std_logic := '0';
|
||||
|
||||
-- Wishbone signals:
|
||||
type wb_state_type is (IDLE, WRITE_ACK, READ_ACK);
|
||||
signal wb_state : wb_state_type;
|
||||
|
||||
signal rxd2 : std_logic := '1';
|
||||
signal rxd3 : std_logic := '1';
|
||||
signal txd2 : std_ulogic := '1';
|
||||
begin
|
||||
|
||||
irq <= (irq_recv_enable and (not recv_buffer_empty))
|
||||
or (irq_tx_ready_enable and send_buffer_empty);
|
||||
|
||||
---------- UART receive ----------
|
||||
|
||||
recv_buffer_input <= rx_byte;
|
||||
|
||||
-- Add a few FFs on the RX input to avoid metastability issues
|
||||
process (clk) is
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
rxd3 <= rxd2;
|
||||
rxd2 <= rxd;
|
||||
end if;
|
||||
end process;
|
||||
txd <= txd2;
|
||||
|
||||
uart_receive: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
rx_state <= IDLE;
|
||||
recv_buffer_push <= '0';
|
||||
else
|
||||
case rx_state is
|
||||
when IDLE =>
|
||||
if recv_buffer_push = '1' then
|
||||
recv_buffer_push <= '0';
|
||||
end if;
|
||||
|
||||
if sample_clk = '1' and rxd3 = '0' then
|
||||
rx_sample_value <= rx_sample_counter;
|
||||
rx_sample_delay <= 0;
|
||||
rx_current_bit <= 0;
|
||||
rx_state <= STARTBIT;
|
||||
end if;
|
||||
when STARTBIT =>
|
||||
if sample_clk = '1' then
|
||||
if rx_sample_delay = 7 then
|
||||
rx_state <= RECEIVE;
|
||||
rx_sample_value <= rx_sample_counter;
|
||||
rx_sample_delay <= 0;
|
||||
else
|
||||
rx_sample_delay <= rx_sample_delay + 1;
|
||||
end if;
|
||||
end if;
|
||||
when RECEIVE =>
|
||||
if sample_clk = '1' and rx_sample_counter = rx_sample_value then
|
||||
if rx_current_bit /= 7 then
|
||||
rx_byte(rx_current_bit) <= rxd3;
|
||||
rx_current_bit <= rx_current_bit + 1;
|
||||
else
|
||||
rx_byte(rx_current_bit) <= rxd3;
|
||||
rx_state <= STOPBIT;
|
||||
end if;
|
||||
end if;
|
||||
when STOPBIT =>
|
||||
if sample_clk = '1' and rx_sample_counter = rx_sample_value then
|
||||
rx_state <= IDLE;
|
||||
|
||||
if recv_buffer_full = '0' then
|
||||
recv_buffer_push <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process uart_receive;
|
||||
|
||||
sample_counter: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
rx_sample_counter <= 0;
|
||||
elsif sample_clk = '1' then
|
||||
if rx_sample_counter = 15 then
|
||||
rx_sample_counter <= 0;
|
||||
else
|
||||
rx_sample_counter <= rx_sample_counter + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process sample_counter;
|
||||
|
||||
---------- UART transmit ----------
|
||||
|
||||
tx_byte <= send_buffer_output;
|
||||
|
||||
uart_transmit: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
txd2 <= '1';
|
||||
tx_state <= IDLE;
|
||||
send_buffer_pop <= '0';
|
||||
tx_current_bit <= 0;
|
||||
else
|
||||
case tx_state is
|
||||
when IDLE =>
|
||||
if send_buffer_empty = '0' and uart_tx_clk = '1' then
|
||||
txd2 <= '0';
|
||||
send_buffer_pop <= '1';
|
||||
tx_current_bit <= 0;
|
||||
tx_state <= TRANSMIT;
|
||||
elsif uart_tx_clk = '1' then
|
||||
txd2 <= '1';
|
||||
end if;
|
||||
when TRANSMIT =>
|
||||
if send_buffer_pop = '1' then
|
||||
send_buffer_pop <= '0';
|
||||
elsif uart_tx_clk = '1' and tx_current_bit = 7 then
|
||||
txd2 <= tx_byte(tx_current_bit);
|
||||
tx_state <= STOPBIT;
|
||||
elsif uart_tx_clk = '1' then
|
||||
txd2 <= tx_byte(tx_current_bit);
|
||||
tx_current_bit <= tx_current_bit + 1;
|
||||
end if;
|
||||
when STOPBIT =>
|
||||
if uart_tx_clk = '1' then
|
||||
txd2 <= '1';
|
||||
tx_state <= IDLE;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process uart_transmit;
|
||||
|
||||
uart_tx_clock_generator: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
uart_tx_counter <= 0;
|
||||
uart_tx_clk <= '0';
|
||||
else
|
||||
if sample_clk = '1' then
|
||||
if uart_tx_counter = 15 then
|
||||
uart_tx_counter <= 0;
|
||||
uart_tx_clk <= '1';
|
||||
else
|
||||
uart_tx_counter <= uart_tx_counter + 1;
|
||||
uart_tx_clk <= '0';
|
||||
end if;
|
||||
else
|
||||
uart_tx_clk <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process uart_tx_clock_generator;
|
||||
|
||||
---------- Sample clock generator ----------
|
||||
|
||||
sample_clock_generator: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
sample_clk_counter <= (others => '0');
|
||||
sample_clk <= '0';
|
||||
else
|
||||
if sample_clk_divisor /= x"00" then
|
||||
if sample_clk_counter = sample_clk_divisor then
|
||||
sample_clk_counter <= (others => '0');
|
||||
sample_clk <= '1';
|
||||
else
|
||||
sample_clk_counter <= std_logic_vector(unsigned(sample_clk_counter) + 1);
|
||||
sample_clk <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process sample_clock_generator;
|
||||
|
||||
---------- Data Buffers ----------
|
||||
|
||||
send_buffer: entity work.pp_fifo
|
||||
generic map(
|
||||
DEPTH => FIFO_DEPTH,
|
||||
WIDTH => 8
|
||||
) port map(
|
||||
clk => clk,
|
||||
reset => reset,
|
||||
full => send_buffer_full,
|
||||
empty => send_buffer_empty,
|
||||
data_in => send_buffer_input,
|
||||
data_out => send_buffer_output,
|
||||
push => send_buffer_push,
|
||||
pop => send_buffer_pop
|
||||
);
|
||||
|
||||
recv_buffer: entity work.pp_fifo
|
||||
generic map(
|
||||
DEPTH => FIFO_DEPTH,
|
||||
WIDTH => 8
|
||||
) port map(
|
||||
clk => clk,
|
||||
reset => reset,
|
||||
full => recv_buffer_full,
|
||||
empty => recv_buffer_empty,
|
||||
data_in => recv_buffer_input,
|
||||
data_out => recv_buffer_output,
|
||||
push => recv_buffer_push,
|
||||
pop => recv_buffer_pop
|
||||
);
|
||||
|
||||
---------- Wishbone Interface ----------
|
||||
|
||||
wishbone: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
wb_ack_out <= '0';
|
||||
wb_state <= IDLE;
|
||||
send_buffer_push <= '0';
|
||||
recv_buffer_pop <= '0';
|
||||
sample_clk_divisor <= (others => '0');
|
||||
irq_recv_enable <= '0';
|
||||
irq_tx_ready_enable <= '0';
|
||||
else
|
||||
case wb_state is
|
||||
when IDLE =>
|
||||
if wb_cyc_in = '1' and wb_stb_in = '1' then
|
||||
if wb_we_in = '1' then -- Write to register
|
||||
if wb_adr_in = x"000" then
|
||||
send_buffer_input <= wb_dat_in;
|
||||
send_buffer_push <= '1';
|
||||
elsif wb_adr_in = x"018" then
|
||||
sample_clk_divisor <= wb_dat_in;
|
||||
elsif wb_adr_in = x"020" then
|
||||
irq_recv_enable <= wb_dat_in(0);
|
||||
irq_tx_ready_enable <= wb_dat_in(1);
|
||||
end if;
|
||||
|
||||
-- Invalid writes are acked and ignored.
|
||||
wb_ack_out <= '1';
|
||||
wb_state <= WRITE_ACK;
|
||||
else -- Read from register
|
||||
if wb_adr_in = x"008" then
|
||||
recv_buffer_pop <= '1';
|
||||
elsif wb_adr_in = x"010" then
|
||||
wb_dat_out <= x"0" & send_buffer_full & recv_buffer_full &
|
||||
send_buffer_empty & recv_buffer_empty;
|
||||
wb_ack_out <= '1';
|
||||
elsif wb_adr_in = x"018" then
|
||||
wb_dat_out <= sample_clk_divisor;
|
||||
wb_ack_out <= '1';
|
||||
elsif wb_adr_in = x"020" then
|
||||
wb_dat_out <= (0 => irq_recv_enable,
|
||||
1 => irq_tx_ready_enable,
|
||||
others => '0');
|
||||
wb_ack_out <= '1';
|
||||
else
|
||||
wb_dat_out <= (others => '0');
|
||||
wb_ack_out <= '1';
|
||||
end if;
|
||||
wb_state <= READ_ACK;
|
||||
end if;
|
||||
end if;
|
||||
when WRITE_ACK =>
|
||||
send_buffer_push <= '0';
|
||||
|
||||
if wb_stb_in = '0' then
|
||||
wb_ack_out <= '0';
|
||||
wb_state <= IDLE;
|
||||
end if;
|
||||
when READ_ACK =>
|
||||
if recv_buffer_pop = '1' then
|
||||
recv_buffer_pop <= '0';
|
||||
else
|
||||
wb_dat_out <= recv_buffer_output;
|
||||
wb_ack_out <= '1';
|
||||
end if;
|
||||
|
||||
if wb_stb_in = '0' then
|
||||
wb_ack_out <= '0';
|
||||
wb_state <= IDLE;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process wishbone;
|
||||
|
||||
end architecture behaviour;
|
@ -1,90 +0,0 @@
|
||||
-- The Potato Processor - A simple processor for FPGAs
|
||||
-- (c) Kristian Klomsten Skordal 2014 <kristian.skordal@wafflemail.net>
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
package pp_utilities is
|
||||
|
||||
--! Converts a boolean to an std_logic.
|
||||
function to_std_logic(input : in boolean) return std_logic;
|
||||
|
||||
-- Checks if a number is 2^n:
|
||||
function is_pow2(input : in natural) return boolean;
|
||||
|
||||
--! Calculates log2 with integers.
|
||||
function log2(input : in natural) return natural;
|
||||
|
||||
-- Gets the value of the sel signals to the wishbone interconnect for the specified
|
||||
-- operand size and address.
|
||||
function wb_get_data_sel(size : in std_logic_vector(1 downto 0); address : in std_logic_vector)
|
||||
return std_logic_vector;
|
||||
|
||||
end package pp_utilities;
|
||||
|
||||
package body pp_utilities is
|
||||
|
||||
function to_std_logic(input : in boolean) return std_logic is
|
||||
begin
|
||||
if input then
|
||||
return '1';
|
||||
else
|
||||
return '0';
|
||||
end if;
|
||||
end function to_std_logic;
|
||||
|
||||
function is_pow2(input : in natural) return boolean is
|
||||
variable c : natural := 1;
|
||||
begin
|
||||
for i in 0 to 31 loop
|
||||
if input = c then
|
||||
return true;
|
||||
end if;
|
||||
|
||||
c := c * 2;
|
||||
end loop;
|
||||
|
||||
return false;
|
||||
end function is_pow2;
|
||||
|
||||
function log2(input : in natural) return natural is
|
||||
variable retval : natural := 0;
|
||||
variable temp : natural := input;
|
||||
begin
|
||||
while temp > 1 loop
|
||||
retval := retval + 1;
|
||||
temp := temp / 2;
|
||||
end loop;
|
||||
|
||||
return retval;
|
||||
end function log2;
|
||||
|
||||
function wb_get_data_sel(size : in std_logic_vector(1 downto 0); address : in std_logic_vector)
|
||||
return std_logic_vector is
|
||||
begin
|
||||
case size is
|
||||
when b"01" =>
|
||||
case address(1 downto 0) is
|
||||
when b"00" =>
|
||||
return b"0001";
|
||||
when b"01" =>
|
||||
return b"0010";
|
||||
when b"10" =>
|
||||
return b"0100";
|
||||
when b"11" =>
|
||||
return b"1000";
|
||||
when others =>
|
||||
return b"0001";
|
||||
end case;
|
||||
when b"10" =>
|
||||
if address(1) = '0' then
|
||||
return b"0011";
|
||||
else
|
||||
return b"1100";
|
||||
end if;
|
||||
when others =>
|
||||
return b"1111";
|
||||
end case;
|
||||
end function wb_get_data_sel;
|
||||
|
||||
end package body pp_utilities;
|
Binary file not shown.
Binary file not shown.
@ -1,135 +0,0 @@
|
||||
-- Sim console UART, provides the same interface as potato UART by
|
||||
-- Kristian Klomsten Skordal.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.wishbone_types.all;
|
||||
use work.sim_console.all;
|
||||
|
||||
--! @brief Simple UART module.
|
||||
--! The following registers are defined:
|
||||
--! |--------------------|--------------------------------------------|
|
||||
--! | Address | Description |
|
||||
--! |--------------------|--------------------------------------------|
|
||||
--! | 0x00 | Transmit register (write-only) |
|
||||
--! | 0x08 | Receive register (read-only) |
|
||||
--! | 0x10 | Status register (read-only) |
|
||||
--! | 0x18 | Sample clock divisor register (dummy) |
|
||||
--! | 0x20 | Interrupt enable register (read/write) |
|
||||
--! |--------------------|--------------------------------------------|
|
||||
--!
|
||||
--! The status register contains the following bits:
|
||||
--! - Bit 0: receive buffer empty
|
||||
--! - Bit 1: transmit buffer empty
|
||||
--! - Bit 2: receive buffer full
|
||||
--! - Bit 3: transmit buffer full
|
||||
--!
|
||||
--! Interrupts are enabled by setting the corresponding bit in the interrupt
|
||||
--! enable register. The following bits are available:
|
||||
--! - Bit 0: data received (receive buffer not empty)
|
||||
--! - Bit 1: ready to send data (transmit buffer empty)
|
||||
entity pp_soc_uart is
|
||||
generic(
|
||||
FIFO_DEPTH : natural := 64 --Unused
|
||||
);
|
||||
port(
|
||||
clk : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
-- UART ports:
|
||||
txd : out std_logic;
|
||||
rxd : in std_logic;
|
||||
|
||||
-- Interrupt signal:
|
||||
irq : out std_logic;
|
||||
|
||||
-- Wishbone ports:
|
||||
wb_adr_in : in std_logic_vector(11 downto 0);
|
||||
wb_dat_in : in std_logic_vector( 7 downto 0);
|
||||
wb_dat_out : out std_logic_vector( 7 downto 0);
|
||||
wb_we_in : in std_logic;
|
||||
wb_cyc_in : in std_logic;
|
||||
wb_stb_in : in std_logic;
|
||||
wb_ack_out : out std_logic
|
||||
);
|
||||
end entity pp_soc_uart;
|
||||
|
||||
architecture behaviour of pp_soc_uart is
|
||||
|
||||
signal sample_clk_divisor : std_logic_vector(7 downto 0);
|
||||
|
||||
-- IRQ enable signals:
|
||||
signal irq_recv_enable, irq_tx_ready_enable : std_logic := '0';
|
||||
|
||||
-- Wishbone signals:
|
||||
type wb_state_type is (IDLE, WRITE_ACK, READ_ACK);
|
||||
signal wb_state : wb_state_type;
|
||||
signal wb_ack : std_logic; --! Wishbone acknowledge signal
|
||||
|
||||
begin
|
||||
|
||||
wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in;
|
||||
|
||||
-- For the sim console, the transmit buffer is always empty, so always
|
||||
-- interrupt if enabled. No recieve interrupt.
|
||||
irq <= irq_tx_ready_enable;
|
||||
|
||||
wishbone: process(clk)
|
||||
variable sim_tmp : std_logic_vector(63 downto 0);
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
wb_ack <= '0';
|
||||
wb_state <= IDLE;
|
||||
sample_clk_divisor <= (others => '0');
|
||||
irq_recv_enable <= '0';
|
||||
irq_tx_ready_enable <= '0';
|
||||
else
|
||||
case wb_state is
|
||||
when IDLE =>
|
||||
if wb_cyc_in = '1' and wb_stb_in = '1' then
|
||||
if wb_we_in = '1' then -- Write to register
|
||||
if wb_adr_in(11 downto 0) = x"000" then
|
||||
sim_console_write(x"00000000000000" & wb_dat_in);
|
||||
elsif wb_adr_in(11 downto 0) = x"018" then
|
||||
sample_clk_divisor <= wb_dat_in;
|
||||
elsif wb_adr_in(11 downto 0) = x"020" then
|
||||
irq_recv_enable <= wb_dat_in(0);
|
||||
irq_tx_ready_enable <= wb_dat_in(1);
|
||||
end if;
|
||||
wb_ack <= '1';
|
||||
wb_state <= WRITE_ACK;
|
||||
else -- Read from register
|
||||
if wb_adr_in(11 downto 0) = x"008" then
|
||||
sim_console_read(sim_tmp);
|
||||
wb_dat_out <= sim_tmp(7 downto 0);
|
||||
elsif wb_adr_in(11 downto 0) = x"010" then
|
||||
sim_console_poll(sim_tmp);
|
||||
wb_dat_out <= "00000" & sim_tmp(0) & '1' & not sim_tmp(0);
|
||||
elsif wb_adr_in(11 downto 0) = x"018" then
|
||||
wb_dat_out <= sample_clk_divisor;
|
||||
elsif wb_adr_in(11 downto 0) = x"020" then
|
||||
wb_dat_out <= (0 => irq_recv_enable,
|
||||
1 => irq_tx_ready_enable,
|
||||
others => '0');
|
||||
else
|
||||
wb_dat_out <= (others => '0');
|
||||
end if;
|
||||
wb_ack <= '1';
|
||||
wb_state <= READ_ACK;
|
||||
end if;
|
||||
end if;
|
||||
when WRITE_ACK|READ_ACK =>
|
||||
if wb_stb_in = '0' then
|
||||
wb_ack <= '0';
|
||||
wb_state <= IDLE;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process wishbone;
|
||||
|
||||
end architecture behaviour;
|
Loading…
Reference in New Issue