OpenCores
URL https://opencores.org/ocsvn/spacewire_light/spacewire_light/trunk

Subversion Repositories spacewire_light

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /spacewire_light/trunk/rtl
    from Rev 4 to Rev 5
    Reverse comparison

Rev 4 → Rev 5

/vhdl/spwstream.vhd
402,17 → 402,7
-- send character
v.txpacket := not s_txfifo_rdata(8);
end if;
if linko.running = '0' then
-- not connected
v.rxpacket := '0';
v.txpacket := '0';
end if;
 
-- Clear the discard flag when the link is explicitly disabled.
if linkdis = '1' then
v.txdiscard := '0';
end if;
 
-- Update RX fifo pointers.
if (rxread = '1') and (r.rxfifo_rvalid = '1') then
-- read from fifo
462,9 → 452,8
v.txfull := bool_to_logic(v_tmptxroom = 0);
v.txhalff := not v_tmptxroom(v_tmptxroom'high);
-- If an error occurs, set a flag to discard the current packet.
if (linko.errdisc or linko.errpar or
linko.erresc or linko.errcred) = '1' then
-- If the link is lost, set a flag to discard the current packet.
if linko.running = '0' then
v.rxeep := v.rxeep or v.rxpacket; -- use new value of rxpacket
v.txdiscard := v.txdiscard or v.txpacket; -- use new value of txpacket
v.rxpacket := '0';
471,6 → 460,11
v.txpacket := '0';
end if;
 
-- Clear the discard flag when the link is explicitly disabled.
if linkdis = '1' then
v.txdiscard := '0';
end if;
 
-- Drive control signals to RX fifo.
s_rxfifo_raddr <= v.rxfifo_raddr; -- using new value of rxfifo_raddr
s_rxfifo_wen <= (not r.rxfull) and (linko.rxchar or r.rxeep);
/vhdl/spwahbmst.vhd
0,0 → 1,735
--
-- AHB master for AMBA interface.
--
-- This is a helper entity for the SpaceWire AMBA interface.
-- It implements the AHB master which transfers data from/to main memory.
--
-- Descriptor flag bits on input:
-- bit 15:0 (RX) max nr of bytes to receive (must be a multiple of 4)
-- (TX) nr of bytes to transmit
-- bit 16 EN: '1' = descriptor enabled
-- bit 17 WR: wrap to beginning of descriptor table
-- bit 18 IE: interrupt at end of descriptor
-- bit 19 '0'
-- bit 20 (TX only) send EOP after end of data
-- bit 21 (TX only) send EEP after end of data
--
-- Descriptor flag bits after completion of frame:
-- bit 15:0 (RX only) LEN: nr of bytes received
-- (TX) undefined
-- bit 16 '0'
-- bit 18:17 undefined
-- bit 19 '1' to indicate descriptor completed
--- bit 20 (RX only) received EOP after end of data
-- bit 21 (RX only) received EEP after end of data
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library grlib;
use grlib.amba.all;
use grlib.stdlib.all;
use work.spwambapkg.all;
 
 
entity spwahbmst is
 
generic (
-- AHB master index.
hindex: integer;
 
-- AHB plug&play information.
hconfig: ahb_config_type;
 
-- Maximum burst length as the 2-logarithm of the number of words.
maxburst: integer range 1 to 8
);
 
port (
-- System clock.
clk: in std_logic;
 
-- Synchronous reset (active-low).
rstn: in std_logic;
 
-- Inputs from SpaceWire core.
msti: in spw_ahbmst_in_type;
 
-- Outputs to SpaceWire core.
msto: out spw_ahbmst_out_type;
 
-- AHB master input signals.
ahbi: in ahb_mst_in_type;
 
-- AHB master output signals.
ahbo: out ahb_mst_out_type
);
 
end entity spwahbmst;
 
architecture spwahbmst_arch of spwahbmst is
 
--
-- Registers.
--
 
type state_type is (
st_idle,
st_rxgetdesc, st_rxgetptr, st_rxtransfer, st_rxfinal, st_rxputdesc,
st_txgetdesc, st_txgetptr, st_txtransfer, st_txfinal, st_txputdesc, st_txskip );
 
type burst_state_type is ( bs_idle, bs_setup, bs_active, bs_end );
 
type regs_type is record
-- dma state
rxdma_act: std_ulogic;
txdma_act: std_ulogic;
ahberror: std_ulogic;
-- main state machine
mstate: state_type;
firstword: std_ulogic;
prefertx: std_ulogic;
-- rx descriptor state
rxdes_en: std_ulogic;
rxdes_wr: std_ulogic;
rxdes_ie: std_ulogic;
rxdes_eop: std_ulogic;
rxdes_eep: std_ulogic;
rxdes_len: std_logic_vector(13 downto 0); -- in 32-bit words
rxdes_pos: std_logic_vector(15 downto 0); -- in bytes
rxaddr: std_logic_vector(31 downto 2);
rxdesc_next: std_ulogic;
-- tx descriptor state
txdes_en: std_ulogic;
txdes_wr: std_ulogic;
txdes_ie: std_ulogic;
txdes_eop: std_ulogic;
txdes_eep: std_ulogic;
txdes_len: std_logic_vector(15 downto 0); -- in bytes
txaddr: std_logic_vector(31 downto 2);
txdesc_next: std_ulogic;
-- interrupts
int_rxdesc: std_ulogic;
int_txdesc: std_ulogic;
int_rxpacket: std_ulogic;
-- burst state
burststat: burst_state_type;
hbusreq: std_ulogic;
hwrite: std_ulogic;
haddr: std_logic_vector(31 downto 2);
hwdata: std_logic_vector(31 downto 0);
end record;
 
constant regs_reset: regs_type := (
rxdma_act => '0',
txdma_act => '0',
ahberror => '0',
mstate => st_idle,
firstword => '0',
prefertx => '0',
rxdes_en => '0',
rxdes_wr => '0',
rxdes_ie => '0',
rxdes_eop => '0',
rxdes_eep => '0',
rxdes_len => (others => '0'),
rxdes_pos => (others => '0'),
rxaddr => (others => '0'),
rxdesc_next => '0',
txdes_en => '0',
txdes_wr => '0',
txdes_ie => '0',
txdes_eop => '0',
txdes_eep => '0',
txdes_len => (others => '0'),
txaddr => (others => '0'),
txdesc_next => '0',
int_rxdesc => '0',
int_txdesc => '0',
int_rxpacket => '0',
burststat => bs_idle,
hbusreq => '0',
hwrite => '0',
haddr => (others => '0'),
hwdata => (others => '0') );
 
signal r: regs_type := regs_reset;
signal rin: regs_type;
 
begin
 
--
-- Combinatorial process
--
process (r, rstn, msti, ahbi) is
variable v: regs_type;
variable v_burstreq: std_logic;
variable v_burstack: std_logic;
variable v_rxfifo_read: std_logic;
variable v_txfifo_write: std_logic;
variable v_txfifo_wdata: std_logic_vector(35 downto 0);
begin
v := r;
 
-- Assume no burst request.
v_burstreq := '0';
 
-- Detect request from burst state machine for next data word.
v_burstack := ahbi.hready and
conv_std_logic(r.burststat = bs_active or r.burststat = bs_end);
 
-- Assume no fifo activity; take data for TX fifo from AHB bus.
v_rxfifo_read := '0';
v_txfifo_write := '0';
v_txfifo_wdata(35 downto 32) := (others => '0');
v_txfifo_wdata(31 downto 0) := ahbi.hrdata;
 
-- Reset registers for interrupts and descriptor updates.
v.int_rxdesc := '0';
v.int_txdesc := '0';
v.int_rxpacket := '0';
v.rxdesc_next := '0';
v.txdesc_next := '0';
 
-- Start DMA on external request.
if msti.rxdma_start = '1' then v.rxdma_act := '1'; end if;
if msti.txdma_start = '1' then v.txdma_act := '1'; end if;
 
--
-- Main state machine.
--
case r.mstate is
 
when st_idle =>
-- Waiting for something to do.
v.prefertx := '0';
v.firstword := '1';
if msti.txdma_cancel = '1' then
v.txdma_act := '0';
v.txdes_en := '0';
end if;
if r.rxdma_act = '1' and msti.rxfifo_empty = '0' and
(r.prefertx = '0' or r.txdma_act = '0' or msti.txfifo_highw = '1') then
-- Start RX transfer.
if r.rxdes_en = '1' then
-- Transfer RX data to current descriptor.
v_burstreq := '1';
v.hwrite := '1';
v.haddr := r.rxaddr;
v.mstate := st_rxtransfer;
else
-- Must fetch new RX descriptor.
v_burstreq := '1';
v.hwrite := '0';
v.haddr := msti.rxdesc_ptr & "0";
v.mstate := st_rxgetdesc;
end if;
elsif r.txdma_act = '1' and msti.txdma_cancel = '0' and msti.txfifo_highw = '0' then
-- Start TX transfer.
if r.txdes_en = '1' then
-- Transfer TX data from current descriptor.
if unsigned(r.txdes_len) = 0 then
-- Only send EOP/EEP and write back descriptor.
v_burstreq := '1';
v.hwrite := '1';
v.haddr := msti.txdesc_ptr & "0";
v.txdesc_next := '1';
v.mstate := st_txputdesc;
else
-- Start burst transfer.
v_burstreq := '1';
v.hwrite := '0';
v.haddr := r.txaddr;
if unsigned(r.txdes_len) <= 4 then
-- Transfer only one word.
v.mstate := st_txfinal;
else
v.mstate := st_txtransfer;
end if;
end if;
else
-- Must fetch new TX descriptor.
v_burstreq := '1';
v.hwrite := '0';
v.haddr := msti.txdesc_ptr & "0";
v.mstate := st_txgetdesc;
end if;
end if;
 
when st_rxgetdesc =>
-- Read RX descriptor flags from memory.
v_burstreq := '1';
v.hwrite := '0';
v.rxdes_len := ahbi.hrdata(15 downto 2);
v.rxdes_en := ahbi.hrdata(16);
v.rxdes_wr := ahbi.hrdata(17);
v.rxdes_ie := ahbi.hrdata(18);
v.rxdes_eop := '0';
v.rxdes_eep := '0';
v.rxdes_pos := (others => '0');
if v_burstack = '1' then
-- Got descriptor flags.
v_burstreq := '0';
v.mstate := st_rxgetptr;
end if;
 
when st_rxgetptr =>
-- Read RX data pointer from memory.
v.rxaddr := ahbi.hrdata(31 downto 2);
v.haddr := ahbi.hrdata(31 downto 2);
v.firstword := '1';
if v_burstack = '1' then
-- Got data pointer.
if r.rxdes_en = '1' then
-- Start transfer.
v_burstreq := '1';
v.hwrite := '1';
v.mstate := st_rxtransfer;
else
-- Reached end of valid descriptors; stop.
v.rxdma_act := '0';
v.mstate := st_idle;
end if;
end if;
 
when st_rxtransfer =>
-- Continue an RX transfer.
v_burstreq := '1';
v.hwrite := '1';
v.firstword := '0';
if v_burstack = '1' or r.firstword = '1' then
-- Setup first/next data word.
v.hwdata := msti.rxfifo_rdata(31 downto 0);
v_rxfifo_read := '1';
-- Update pointers.
v.rxdes_len := std_logic_vector(unsigned(r.rxdes_len) - 1);
v.rxdes_pos := std_logic_vector(unsigned(r.rxdes_pos) + 4);
v.rxaddr := std_logic_vector(unsigned(r.rxaddr) + 1);
-- Detect EOP/EEP.
v.rxdes_eop :=
(msti.rxfifo_rdata(35) and not msti.rxfifo_rdata(24)) or
(msti.rxfifo_rdata(34) and not msti.rxfifo_rdata(16)) or
(msti.rxfifo_rdata(33) and not msti.rxfifo_rdata(8)) or
(msti.rxfifo_rdata(32) and not msti.rxfifo_rdata(0));
v.rxdes_eep :=
(msti.rxfifo_rdata(35) and msti.rxfifo_rdata(24)) or
(msti.rxfifo_rdata(34) and msti.rxfifo_rdata(16)) or
(msti.rxfifo_rdata(33) and msti.rxfifo_rdata(8)) or
(msti.rxfifo_rdata(32) and msti.rxfifo_rdata(0));
-- Adjust frame length in case of EOP/EEP.
if msti.rxfifo_rdata(35) = '1' then
v.rxdes_pos := r.rxdes_pos(r.rxdes_pos'high downto 2) & "00";
elsif msti.rxfifo_rdata(34) = '1' then
v.rxdes_pos := r.rxdes_pos(r.rxdes_pos'high downto 2) & "01";
elsif msti.rxfifo_rdata(33) = '1' then
v.rxdes_pos := r.rxdes_pos(r.rxdes_pos'high downto 2) & "10";
elsif msti.rxfifo_rdata(32) = '1' then
v.rxdes_pos := r.rxdes_pos(r.rxdes_pos'high downto 2) & "11";
end if;
-- Stop at end of requested length or end of packet or fifo empty.
if msti.rxfifo_nxempty = '1' or
orv(msti.rxfifo_rdata(35 downto 32)) = '1' or
unsigned(r.rxdes_len) = 1 then
v_burstreq := '0';
v.mstate := st_rxfinal;
end if;
-- Stop at max burst length boundary.
if (andv(r.rxaddr(maxburst+2 downto 2)) = '1') then
v_burstreq := '0';
v.mstate := st_rxfinal;
end if;
end if;
 
when st_rxfinal =>
-- Last data cycle of an RX transfer.
if v_burstack = '1' then
if unsigned(r.rxdes_len) = 0 or
r.rxdes_eop = '1' or r.rxdes_eep = '1' then
-- End of frame; write back descriptor.
v_burstreq := '1';
v.hwrite := '1';
v.haddr := msti.rxdesc_ptr & "0";
v.rxdesc_next := '1';
v.mstate := st_rxputdesc;
else
-- Go through st_idle to pick up more work.
v.mstate := st_idle;
end if;
end if;
-- Give preference to TX work since we just did some RX work.
v.prefertx := '1';
 
when st_rxputdesc =>
-- Write back RX descriptor.
v.hwdata(15 downto 0) := r.rxdes_pos;
v.hwdata(16) := '0';
v.hwdata(17) := r.rxdes_wr;
v.hwdata(18) := r.rxdes_ie;
v.hwdata(19) := '1';
v.hwdata(20) := r.rxdes_eop;
v.hwdata(21) := r.rxdes_eep;
v.hwdata(31 downto 22) := (others => '0');
if v_burstack = '1' then
-- Frame done.
v.rxdes_en := '0';
v.int_rxdesc := r.rxdes_ie;
v.int_rxpacket := r.rxdes_eop or r.rxdes_eep;
-- Go to st_idle.
v.mstate := st_idle;
end if;
 
when st_txgetdesc =>
-- Read TX descriptor flags from memory.
v_burstreq := '1';
v.hwrite := '0';
v.txdes_len := ahbi.hrdata(15 downto 0);
v.txdes_en := ahbi.hrdata(16);
v.txdes_wr := ahbi.hrdata(17);
v.txdes_ie := ahbi.hrdata(18);
v.txdes_eop := ahbi.hrdata(20);
v.txdes_eep := ahbi.hrdata(21);
if v_burstack = '1' then
-- Got descriptor flags.
v_burstreq := '0';
v.mstate := st_txgetptr;
end if;
 
when st_txgetptr =>
-- Read TX data pointer from memory.
v.txaddr := ahbi.hrdata(31 downto 2);
if v_burstack = '1' then
-- Got data pointer.
if r.txdes_en = '1' then
-- Start transfer.
if unsigned(r.txdes_len) = 0 then
-- Only send EOP/EEP and write back descriptor.
v_burstreq := '1';
v.hwrite := '1';
v.haddr := msti.txdesc_ptr & "0";
v.txdesc_next := '1';
v.mstate := st_txputdesc;
else
v_burstreq := '1';
v.hwrite := '0';
v.haddr := ahbi.hrdata(31 downto 2);
if unsigned(r.txdes_len) <= 4 then
-- Transfer only one word.
v.mstate := st_txfinal;
else
v.mstate := st_txtransfer;
end if;
end if;
else
-- Reached end of valid descriptors; stop.
v.txdma_act := '0';
v.mstate := st_idle;
end if;
end if;
 
when st_txtransfer =>
-- Continue an TX transfer.
v_burstreq := '1';
v.hwrite := '0';
if v_burstack = '1' then
-- Got next data word from memory.
v_txfifo_write := '1';
-- Update pointers.
v.txdes_len := std_logic_vector(unsigned(r.txdes_len) - 4);
v.txaddr := std_logic_vector(unsigned(r.txaddr) + 1);
-- Handle end of burst/transfer.
if andv(r.txaddr(maxburst+2 downto 2)) = '1' then
-- This was the last data cycle before the max burst boundary.
-- Go through st_idle to pick up more work.
v_burstreq := '0';
v.mstate := st_idle;
elsif msti.txfifo_nxfull = '1' then
-- Fifo full; stop transfer, ignore final data cycle.
v_burstreq := '0';
v.mstate := st_txskip;
elsif unsigned(r.txdes_len) <= 8 then
-- Stop at end of requested length (one more data cycle).
v_burstreq := '0';
v.mstate := st_txfinal;
elsif andv(r.txaddr(maxburst+2 downto 3)) = '1' then
-- Stop at max burst length boundary (one more data cycle).
v_burstreq := '0';
end if;
else
if andv(r.txaddr(maxburst+2 downto 2)) = '1' then
-- Stop at max burst length boundary (just one more data cycle).
v_burstreq := '0';
end if;
end if;
 
when st_txfinal =>
-- Last data cycle of a TX descriptor (1 <= txdes_len <= 4).
if v_burstack = '1' then
-- Got last data word from memory.
v_txfifo_write := '1';
v.txdes_len := std_logic_vector(unsigned(r.txdes_len) - 4);
-- Insert EOP in last word if needed.
-- (Or set bit 7 in the flag byte to indicate that the
-- frame ends while the packet continues.)
case r.txdes_len(1 downto 0) is
when "01" =>
v_txfifo_wdata(34) := '1';
v_txfifo_wdata(23) := not (r.txdes_eop or r.txdes_eep);
v_txfifo_wdata(22 downto 17) := "000000";
v_txfifo_wdata(16) := r.txdes_eep;
when "10" =>
v_txfifo_wdata(33) := '1';
v_txfifo_wdata(15) := not (r.txdes_eop or r.txdes_eep);
v_txfifo_wdata(14 downto 9) := "000000";
v_txfifo_wdata(8) := r.txdes_eep;
when "11" =>
v_txfifo_wdata(32) := '1';
v_txfifo_wdata(7) := not (r.txdes_eop or r.txdes_eep);
v_txfifo_wdata(6 downto 1) := "000000";
v_txfifo_wdata(0) := r.txdes_eep;
when others =>
-- txdes_len = 4
-- Store 4 data bytes now; store EOP in st_txputdesc (if needed).
end case;
if msti.txfifo_nxfull = '1' and r.txdes_len(1 downto 0) = "00" then
-- Fifo full so no room to store EOP.
v.mstate := st_idle;
v.haddr := msti.txdesc_ptr & "0";
else
-- Prepare to write back descriptor.
v_burstreq := '1';
v.hwrite := '1';
v.haddr := msti.txdesc_ptr & "0";
v.txdesc_next := '1';
v.mstate := st_txputdesc;
end if;
end if;
 
when st_txputdesc =>
-- Write back TX descriptor.
v.hwdata(15 downto 0) := (others => '0');
v.hwdata(16) := '0';
v.hwdata(17) := r.txdes_wr;
v.hwdata(18) := r.txdes_ie;
v.hwdata(19) := '1';
v.hwdata(20) := r.txdes_eop;
v.hwdata(21) := r.txdes_eep;
v.hwdata(31 downto 22) := (others => '0');
if v_burstack = '1' then
if r.txdes_len(1 downto 0) = "00" and
(r.txdes_eop = '1' or r.txdes_eep = '1') then
-- Store EOP in TX fifo.
v_txfifo_write := '1';
v_txfifo_wdata(35) := '1';
v_txfifo_wdata(31 downto 25) := "0000000";
v_txfifo_wdata(24) := r.txdes_eep;
end if;
-- Frame done.
v.txdes_en := '0';
v.int_txdesc := r.txdes_ie;
-- Go to st_idle and give preference to RX work.
v.mstate := st_idle;
end if;
 
when st_txskip =>
-- Ignore last data cycle of burst because TX fifo is full.
if v_burstack = '1' then
v.mstate := st_idle;
end if;
 
end case;
 
-- Abort DMA when an AHB error occurs.
if r.ahberror = '1' then
v.rxdma_act := '0';
v.txdma_act := '0';
v.mstate := st_idle;
end if;
 
 
--
-- Burst state machine.
--
-- A transfer starts when the main state machine combinatorially pulls
-- v_burstreq high and assigns v.haddr and v.hwrite (i.e. r.haddr and
-- r.hwrite must be valid in the first clock cycle AFTER rising v_burstreq).
-- In case of a write transfer, r.hwdata must be valid in the second
-- clock cycle after rising v_burstreq.
--
-- During the transfer, the burst state machine announces each word
-- with a v_burstack pulse. During a read transfer, ahbi.hrdata is
-- valid when v_burstack is high. During a write transfer, a next
-- word must be assigned to v.hwdata on the v_burstack pulse.
--
-- For a single-word transfer, v_burstreq should be high for only one
-- clock cycle. For a multi-word transfer, v_burstreq should be high
-- until the last-but-one v_burstack pulse. I.e. after v_burstreq is
-- released combinatorially on a v_burstack pulse, one last v_burstack
-- pulse will follow.
--
-- The burst state machine transparently handles bus arbitration and
-- retrying of transfers. In case of a non-retryable error, r.ahberror
-- is set high and further transfers are blocked. The main state
-- machine is responsible for ensuring that bursts do not cross a
-- forbidden address boundary.
--
case r.burststat is
 
when bs_idle =>
-- Wait for request and bus grant.
-- (htrans = HTRANS_IDLE)
v.hbusreq := r.hbusreq or v_burstreq;
if (r.hbusreq = '1' or v_burstreq = '1') and
ahbi.hready = '1' and
ahbi.hgrant(hindex) = '1' then
-- Start burst.
v.burststat := bs_setup;
end if;
-- Block new bursts after an error occurred.
if r.ahberror = '1' then
v.hbusreq := '0';
v.burststat := bs_idle;
end if;
 
when bs_setup =>
-- First address cycle.
-- (htrans = HTRANS_NONSEQ)
v.hbusreq := '1';
if ahbi.hready = '1' then
-- Increment address and continue burst in bs_active.
v.haddr := std_logic_vector(unsigned(r.haddr) + 1);
v.burststat := bs_active;
-- Stop burst when application ends the transfer.
v.hbusreq := v_burstreq;
if v_burstreq = '0' then
v.burststat := bs_end;
end if;
-- Stop burst when we are kicked off the bus.
if ahbi.hgrant(hindex) = '0' then
v.burststat := bs_end;
end if;
end if;
 
when bs_active =>
-- Continue burst.
-- (htrans = HTRANS_SEQ)
v.hbusreq := '1';
if ahbi.hresp /= HRESP_OKAY then
-- Error response from slave.
v.haddr := std_logic_vector(unsigned(r.haddr) - 1);
if ahbi.hresp = HRESP_ERROR then
-- Permanent error.
v.ahberror := '1';
v.hbusreq := '0';
else
-- Must retry request.
v.hbusreq := '1';
end if;
v.burststat := bs_idle;
elsif ahbi.hready = '1' then
-- Increment address.
v.haddr := std_logic_vector(unsigned(r.haddr) + 1);
-- Stop burst when application ends the transfer.
v.hbusreq := v_burstreq;
if v_burstreq = '0' then
v.burststat := bs_end;
end if;
-- Stop burst when we are kicked off the bus.
if ahbi.hgrant(hindex) = '0' then
v.burststat := bs_end;
end if;
end if;
 
when bs_end =>
-- Last data cycle of burst.
-- (htrans = HTRANS_IDLE)
v.hbusreq := r.hbusreq or v_burstreq;
if ahbi.hresp /= HRESP_OKAY then
-- Error response from slave.
v.haddr := std_logic_vector(unsigned(r.haddr) - 1);
if ahbi.hresp = HRESP_ERROR then
-- Permanent error.
v.ahberror := '1';
v.hbusreq := '0';
else
-- Must retry request.
v.hbusreq := '1';
end if;
v.burststat := bs_idle;
elsif ahbi.hready = '1' then
-- Burst complete.
if (r.hbusreq = '1' or v_burstreq = '1') and
ahbi.hgrant(hindex) = '1' then
-- Immediately start next burst.
v.burststat := bs_setup;
else
v.burststat := bs_idle;
end if;
end if;
 
end case;
 
 
--
-- Drive output signals.
--
ahbo.hbusreq <= r.hbusreq;
if r.burststat = bs_setup then
ahbo.htrans <= HTRANS_NONSEQ;
elsif r.burststat = bs_active then
ahbo.htrans <= HTRANS_SEQ;
else
ahbo.htrans <= HTRANS_IDLE;
end if;
ahbo.haddr <= r.haddr & "00";
ahbo.hwrite <= r.hwrite;
ahbo.hwdata <= r.hwdata;
ahbo.hlock <= '0'; -- never lock the bus
ahbo.hsize <= HSIZE_DWORD; -- always 32-bit words
ahbo.hburst <= HBURST_INCR; -- undetermined incremental burst
ahbo.hprot <= "0011"; -- not cacheable, privileged, data
ahbo.hirq <= (others => '0'); -- no interrupts via AHB bus
ahbo.hconfig <= hconfig; -- AHB plug&play data
ahbo.hindex <= hindex; -- index feedback
 
msto.rxdma_act <= r.rxdma_act;
msto.txdma_act <= r.txdma_act;
msto.ahberror <= r.ahberror;
msto.int_rxdesc <= r.int_rxdesc;
msto.int_txdesc <= r.int_txdesc;
msto.int_rxpacket <= r.int_rxpacket;
msto.rxdesc_next <= r.rxdesc_next;
msto.rxdesc_wrap <= r.rxdesc_next and r.rxdes_wr;
msto.txdesc_next <= r.txdesc_next;
msto.txdesc_wrap <= r.txdesc_next and r.txdes_wr;
msto.rxfifo_read <= v_rxfifo_read;
msto.txfifo_write <= v_txfifo_write;
msto.txfifo_wdata <= v_txfifo_wdata;
 
 
--
-- Reset.
--
if rstn = '0' then
v := regs_reset;
end if;
 
 
--
-- Update registers.
--
rin <= v;
end process;
 
 
--
-- Synchronous process: update registers.
--
process (clk) is
begin
if rising_edge(clk) then
r <= rin;
end if;
end process;
 
end architecture spwahbmst_arch;
/vhdl/spwamba.vhd
0,0 → 1,864
--
-- SpaceWire core with AMBA interface.
--
-- APB registers:
--
-- Address 0x00: Control Register
-- bit 0 Reset spwamba core (auto-clear)
-- bit 1 Reset DMA engines (auto-clear)
-- bit 2 Link start
-- bit 3 Link autostart
-- bit 4 Link disable
-- bit 5 Enable timecode transmission through tick_in signal
-- bit 6 Start RX DMA (auto-clear)
-- bit 7 Start TX DMA (auto-clear)
-- bit 8 Cancel TX DMA and discard TX data queue (auto-clear)
-- bit 9 Enable interrupt on link up/down
-- bit 10 Enable interrupt on time code received
-- bit 11 Enable interrupt on RX descriptor
-- bit 12 Enable interrupt on TX descriptor
-- bit 13 Enable interrupt on RX packet
-- bit 27:24 desctablesize (read-only)
--
-- Address 0x04: Status Register
-- bit 1:0 Link status: 0=off, 1=started, 2=connecting, 3=run
-- bit 2 Got disconnect error (sticky)
-- bit 3 Got parity error (sticky)
-- bit 4 Got escape error (sticky)
-- bit 5 Got credit error (sticky)
-- bit 6 RX DMA enabled
-- bit 7 TX DMA enabled
-- bit 8 AHB error occurred (reset DMA engine to clear)
-- bit 9 Reserved
-- bit 10 Received timecode (sticky)
-- bit 11 Finished RX descriptor with IE='1' (sticky)
-- bit 12 Finished TX descriptor with IE='1' (sticky)
-- bit 13 Received packet (sticky)
-- bit 14 RX buffer empty after packet
--
-- Sticky bits are reset by writing a '1' bit to the corresponding
-- bit position(s).
--
-- Address 0x08: Transmission Clock Scaler
-- bit 7:0 txclk division factor minus 1
--
-- Address 0x0c: Timecode Register
-- bit 5:0 Last received timecode value (read-only)
-- bit 7:6 Control bits received with last timecode (read-only)
-- bit 13:8 Timecode value to send on next tick_in (auto-increment)
-- bit 15:14 Reserved (write as zero)
-- bit 16 Write '1' to send a timecode (auto-clear)
--
-- Address 0x10: Descriptor pointer for RX DMA
-- bit 2:0 Reserved, write as zero
-- bit desctablesize+2:3 Descriptor index (auto-increment)
-- bit 31:desctablesize+3 Fixed address bits of descriptor table
--
-- For example, if desctablesize = 10, a 8192-byte area is
-- determined by bits 31:13. This area has room for 1024 descriptors
-- of 8 bytes each. Bits 12:3 point to the current descriptor within
-- the table.
--
-- Address 0x14: Descriptor pointer for TX DMA
-- bit 2:0 Reserved, write as zero
-- bit desctablesize+2:3 Descriptor index (auto-increment)
-- bit 31:desctablesize+3 Fixed address bits of descriptor table
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library techmap;
use techmap.gencomp.all;
library grlib;
use grlib.amba.all;
use grlib.devices.all;
use grlib.stdlib.all;
use work.spwpkg.all;
use work.spwambapkg.all;
 
entity spwamba is
 
generic (
-- Technology selection for FIFO memories.
tech: integer range 0 to NTECH := DEFFABTECH;
 
-- AHB master index.
hindex: integer;
 
-- APB slave index.
pindex: integer;
 
-- Bits 19 to 8 of the APB address range.
paddr: integer;
 
-- Mask for APB address bits 19 to 8.
pmask: integer := 16#fff#;
 
-- Index of the interrupt request line.
pirq: integer;
 
-- System clock frequency in Hz.
-- This must be set to the frequency of "clk". It is used to setup
-- counters for reset timing, disconnect timeout and to transmit
-- at 10 Mbit/s during the link handshake.
sysfreq: real;
 
-- Transmit clock frequency in Hz (only if tximpl = impl_fast).
-- This must be set to the frequency of "txclk". It is used to
-- transmit at 10 Mbit/s during the link handshake.
txclkfreq: real := 0.0;
 
-- Selection of a receiver front-end implementation.
rximpl: spw_implementation_type := impl_generic;
 
-- Maximum number of bits received per system clock
-- (must be 1 in case of impl_generic).
rxchunk: integer range 1 to 4 := 1;
 
-- Selection of a transmitter implementation.
tximpl: spw_implementation_type := impl_generic;
 
-- Enable capability to generate time-codes.
timecodegen: boolean := true;
 
-- Size of the receive FIFO as the 2-logarithm of the number of words.
-- Must be at least 6 (64 words = 256 bytes).
rxfifosize: integer range 6 to 12 := 8;
 
-- Size of the transmit FIFO as the 2-logarithm of the number of words.
txfifosize: integer range 2 to 12 := 8;
 
-- Size of the DMA descriptor tables as the 2-logarithm of the number
-- of descriptors.
desctablesize: integer range 4 to 14 := 10;
 
-- Maximum burst length as the 2-logarithm of the number of words (default 8 words).
maxburst: integer range 1 to 8 := 3
);
 
port (
-- System clock.
clk: in std_logic;
 
-- Receiver sample clock (only for impl_fast)
rxclk: in std_logic;
 
-- Transmit clock (only for impl_fast)
txclk: in std_logic;
 
-- Synchronous reset (active-low).
rstn: in std_logic;
 
-- APB slave input signals.
apbi: in apb_slv_in_type;
 
-- APB slave output signals.
apbo: out apb_slv_out_type;
 
-- AHB master input signals.
ahbi: in ahb_mst_in_type;
 
-- AHB master output signals.
ahbo: out ahb_mst_out_type;
 
-- Pulse for TimeCode generation.
tick_in: in std_logic;
 
-- Data In signal from SpaceWire bus.
spw_di: in std_logic;
 
-- Strobe In signal from SpaceWire bus.
spw_si: in std_logic;
 
-- Data Out signal to SpaceWire bus.
spw_do: out std_logic;
 
-- Strobe Out signal to SpaceWire bus.
spw_so: out std_logic
);
 
end entity spwamba;
 
architecture spwamba_arch of spwamba is
 
-- Reset time (6.4 us) in system clocks
constant reset_time: integer := integer(sysfreq * 6.4e-6);
 
-- Disconnect time (850 ns) in system clocks
constant disconnect_time: integer := integer(sysfreq * 850.0e-9);
 
-- Initial tx clock scaler (10 Mbit).
type impl_to_real_type is array(spw_implementation_type) of real;
constant tximpl_to_txclk_freq: impl_to_real_type :=
(impl_generic => sysfreq, impl_fast => txclkfreq);
constant effective_txclk_freq: real := tximpl_to_txclk_freq(tximpl);
constant default_divcnt: std_logic_vector(7 downto 0) :=
std_logic_vector(to_unsigned(integer(effective_txclk_freq / 10.0e6 - 1.0), 8));
 
-- Registers.
type regs_type is record
-- packet state
rxpacket: std_logic; -- '1' when receiving a packet
rxeep: std_logic; -- '1' when rx EEP character pending
txpacket: std_logic; -- '1' when transmitting a packet
txdiscard: std_logic; -- '1' when discarding a tx packet
-- RX fifo state
rxfifo_raddr: std_logic_vector(rxfifosize-1 downto 0);
rxfifo_waddr: std_logic_vector(rxfifosize-1 downto 0);
rxfifo_wdata: std_logic_vector(35 downto 0);
rxfifo_write: std_ulogic;
rxfifo_empty: std_ulogic;
rxfifo_bytemsk: std_logic_vector(2 downto 0);
rxroom: std_logic_vector(5 downto 0);
-- TX fifo state
txfifo_raddr: std_logic_vector(txfifosize-1 downto 0);
txfifo_waddr: std_logic_vector(txfifosize-1 downto 0);
txfifo_empty: std_ulogic;
txfifo_nxfull: std_ulogic;
txfifo_highw: std_ulogic;
txfifo_bytepos: std_logic_vector(1 downto 0);
-- APB registers
ctl_reset: std_ulogic;
ctl_resetdma: std_ulogic;
ctl_linkstart: std_ulogic;
ctl_autostart: std_ulogic;
ctl_linkdis: std_ulogic;
ctl_ticken: std_ulogic;
ctl_rxstart: std_ulogic;
ctl_txstart: std_ulogic;
ctl_txcancel: std_ulogic;
ctl_ielink: std_ulogic;
ctl_ietick: std_ulogic;
ctl_ierxdesc: std_ulogic;
ctl_ietxdesc: std_ulogic;
ctl_ierxpacket: std_ulogic;
sta_link: std_logic_vector(1 downto 0);
sta_errdisc: std_ulogic;
sta_errpar: std_ulogic;
sta_erresc: std_ulogic;
sta_errcred: std_ulogic;
sta_gottick: std_ulogic;
sta_rxdesc: std_ulogic;
sta_txdesc: std_ulogic;
sta_rxpacket: std_ulogic;
sta_rxempty: std_ulogic;
txdivcnt: std_logic_vector(7 downto 0);
time_in: std_logic_vector(5 downto 0);
tick_in: std_ulogic;
rxdesc_ptr: std_logic_vector(31 downto 3);
txdesc_ptr: std_logic_vector(31 downto 3);
-- APB interrupt request
irq: std_ulogic;
end record;
 
constant regs_reset: regs_type := (
rxpacket => '0',
rxeep => '0',
txpacket => '0',
txdiscard => '0',
rxfifo_raddr => (others => '0'),
rxfifo_waddr => (others => '0'),
rxfifo_wdata => (others => '0'),
rxfifo_write => '0',
rxfifo_empty => '1',
rxfifo_bytemsk => "111",
rxroom => (others => '1'),
txfifo_raddr => (others => '0'),
txfifo_waddr => (others => '0'),
txfifo_empty => '1',
txfifo_nxfull => '0',
txfifo_highw => '0',
txfifo_bytepos => "00",
ctl_reset => '0',
ctl_resetdma => '0',
ctl_linkstart => '0',
ctl_autostart => '0',
ctl_linkdis => '0',
ctl_ticken => '0',
ctl_rxstart => '0',
ctl_txstart => '0',
ctl_txcancel => '0',
ctl_ielink => '0',
ctl_ietick => '0',
ctl_ierxdesc => '0',
ctl_ietxdesc => '0',
ctl_ierxpacket => '0',
sta_link => "00",
sta_errdisc => '0',
sta_errpar => '0',
sta_erresc => '0',
sta_errcred => '0',
sta_gottick => '0',
sta_rxdesc => '0',
sta_txdesc => '0',
sta_rxpacket => '0',
sta_rxempty => '1',
txdivcnt => default_divcnt,
time_in => (others => '0'),
tick_in => '0',
rxdesc_ptr => (others => '0'),
txdesc_ptr => (others => '0'),
irq => '0' );
 
signal r: regs_type := regs_reset;
signal rin: regs_type;
 
-- Component interface signals.
signal recv_rxen: std_logic;
signal recvo: spw_recv_out_type;
signal recv_inact: std_logic;
signal recv_inbvalid: std_logic;
signal recv_inbits: std_logic_vector(rxchunk-1 downto 0);
signal xmiti: spw_xmit_in_type;
signal xmito: spw_xmit_out_type;
signal xmit_divcnt: std_logic_vector(7 downto 0);
signal linki: spw_link_in_type;
signal linko: spw_link_out_type;
signal msti: spw_ahbmst_in_type;
signal msto: spw_ahbmst_out_type;
signal ahbmst_rstn: std_logic;
signal s_rst: std_logic;
 
-- Memory interface signals.
signal s_rxfifo_raddr: std_logic_vector(rxfifosize-1 downto 0);
signal s_rxfifo_rdata: std_logic_vector(35 downto 0);
signal s_rxfifo_wen: std_logic;
signal s_rxfifo_waddr: std_logic_vector(rxfifosize-1 downto 0);
signal s_rxfifo_wdata: std_logic_vector(35 downto 0);
signal s_txfifo_raddr: std_logic_vector(txfifosize-1 downto 0);
signal s_txfifo_rdata: std_logic_vector(35 downto 0);
signal s_txfifo_wen: std_logic;
signal s_txfifo_waddr: std_logic_vector(txfifosize-1 downto 0);
signal s_txfifo_wdata: std_logic_vector(35 downto 0);
 
 
-- APB slave plug&play configuration
constant REVISION: integer := 0;
constant pconfig: apb_config_type := (
0 => ahb_device_reg(VENDOR_OPENCORES, DEVICE_SPACEWIRELIGHT, 0, REVISION, pirq),
1 => apb_iobar(paddr, pmask) );
 
-- AHB master plug&play configuration
constant hconfig: ahb_config_type := (
0 => ahb_device_reg(VENDOR_OPENCORES, DEVICE_SPACEWIRELIGHT, 0, REVISION, 0),
others => zero32 );
 
begin
 
-- Instantiate link controller.
link_inst: spwlink
generic map (
reset_time => reset_time )
port map (
clk => clk,
rst => s_rst,
linki => linki,
linko => linko,
rxen => recv_rxen,
recvo => recvo,
xmiti => xmiti,
xmito => xmito );
 
-- Instantiate receiver.
recv_inst: spwrecv
generic map(
disconnect_time => disconnect_time,
rxchunk => rxchunk )
port map (
clk => clk,
rxen => recv_rxen,
recvo => recvo,
inact => recv_inact,
inbvalid => recv_inbvalid,
inbits => recv_inbits );
 
-- Instantiate receiver front-end.
recvfront_sel0: if rximpl = impl_generic generate
recvfront_generic_inst: spwrecvfront_generic
port map (
clk => clk,
rxen => recv_rxen,
inact => recv_inact,
inbvalid => recv_inbvalid,
inbits => recv_inbits,
spw_di => spw_di,
spw_si => spw_si );
end generate;
recvfront_sel1: if rximpl = impl_fast generate
recvfront_fast_inst: spwrecvfront_fast
generic map (
rxchunk => rxchunk )
port map (
clk => clk,
rxclk => rxclk,
rxen => recv_rxen,
inact => recv_inact,
inbvalid => recv_inbvalid,
inbits => recv_inbits,
spw_di => spw_di,
spw_si => spw_si );
end generate;
 
-- Instantiate transmitter.
xmit_sel0: if tximpl = impl_generic generate
xmit_inst: spwxmit
port map (
clk => clk,
rst => s_rst,
divcnt => xmit_divcnt,
xmiti => xmiti,
xmito => xmito,
spw_do => spw_do,
spw_so => spw_so );
end generate;
xmit_sel1: if tximpl = impl_fast generate
xmit_fast_inst: spwxmit_fast
port map (
clk => clk,
txclk => txclk,
rst => s_rst,
divcnt => xmit_divcnt,
xmiti => xmiti,
xmito => xmito,
spw_do => spw_do,
spw_so => spw_so );
end generate;
 
-- Instantiate RX FIFO.
rxfifo: syncram_2p
generic map (
tech => tech,
abits => rxfifosize,
dbits => 36,
sepclk => 0 )
port map (
rclk => clk,
renable => '1',
raddress => s_rxfifo_raddr,
dataout => s_rxfifo_rdata,
wclk => clk,
write => s_rxfifo_wen,
waddress => s_rxfifo_waddr,
datain => s_rxfifo_wdata );
 
-- Instantiate TX FIFO.
txfifo: syncram_2p
generic map (
tech => tech,
abits => txfifosize,
dbits => 36,
sepclk => 0 )
port map (
rclk => clk,
renable => '1',
raddress => s_txfifo_raddr,
dataout => s_txfifo_rdata,
wclk => clk,
write => s_txfifo_wen,
waddress => s_txfifo_waddr,
datain => s_txfifo_wdata );
 
-- Instantiate AHB master.
ahbmst: spwahbmst
generic map (
hindex => hindex,
hconfig => hconfig,
maxburst => maxburst )
port map (
clk => clk,
rstn => ahbmst_rstn,
msti => msti,
msto => msto,
ahbi => ahbi,
ahbo => ahbo );
 
 
--
-- Combinatorial process
--
process (r, linko, msto, s_rxfifo_rdata, s_txfifo_rdata, rstn, apbi, tick_in) is
variable v: regs_type;
variable v_tmprxroom: unsigned(rxfifosize-1 downto 0);
variable v_prdata: std_logic_vector(31 downto 0);
variable v_txfifo_bytepos: integer range 0 to 3;
begin
v := r;
v_tmprxroom := to_unsigned(0, rxfifosize);
v_prdata := (others => '0');
 
-- Convert RX/TX byte index to integer.
v_txfifo_bytepos := to_integer(unsigned(r.txfifo_bytepos));
 
-- Reset auto-clearing registers.
v.ctl_reset := '0';
v.ctl_resetdma := '0';
v.ctl_rxstart := '0';
v.ctl_txstart := '0';
 
-- Register external timecode trigger (if enabled).
if timecodegen and r.ctl_ticken = '1' then
v.tick_in := tick_in;
else
v.tick_in := '0';
end if;
 
-- Auto-increment timecode counter.
if r.tick_in = '1' then
v.time_in := std_logic_vector(unsigned(r.time_in) + 1);
end if;
 
-- Keep track of whether we are sending and/or receiving a packet.
if linko.rxchar = '1' then
-- got character
v.rxpacket := not linko.rxflag;
end if;
if linko.txack = '1' then
-- send character
v.txpacket := not s_txfifo_rdata(35-v_txfifo_bytepos);
end if;
 
-- Accumulate a word to write to the RX fifo.
-- Note: If the EOP/EEP marker falls in the middle of a word,
-- subsequent bytes must be a copy of the marker, otherwise
-- the AHB master may not work correctly.
v.rxfifo_write := '0';
for i in 3 downto 0 loop
if (i = 0) or (r.rxfifo_bytemsk(i-1) = '1') then
if r.rxeep = '1' then
v.rxfifo_wdata(32+i) := '1';
v.rxfifo_wdata(7+8*i downto 8*i) := "00000001";
else
v.rxfifo_wdata(32+i) := linko.rxflag;
v.rxfifo_wdata(7+8*i downto 8*i) := linko.rxdata;
end if;
end if;
end loop;
if linko.rxchar = '1' or (r.rxeep = '1' and unsigned(r.rxroom) /= 0) then
v.rxeep := '0';
if r.rxfifo_bytemsk(0) = '0' or linko.rxflag = '1' or r.rxeep = '1' then
-- Flush the current word to the FIFO.
v.rxfifo_write := '1';
v.rxfifo_bytemsk := "111";
else
-- Store one byte.
v.rxfifo_bytemsk := '0' & r.rxfifo_bytemsk(2 downto 1);
end if;
end if;
 
-- Read from TX fifo.
if (r.txfifo_empty = '0') and (linko.txack = '1' or r.txdiscard = '1') then
-- Update byte pointer.
if r.txfifo_bytepos = "11" or
s_txfifo_rdata(35-v_txfifo_bytepos) = '1' or
(v_txfifo_bytepos < 3 and
s_txfifo_rdata(34-v_txfifo_bytepos) = '1' and
s_txfifo_rdata(23-8*v_txfifo_bytepos) = '1') then
-- This is the last byte in the current word;
-- OR the current byte is an EOP/EEP marker;
-- OR the next byte in the current work is a non-EOP end-of-frame marker.
v.txfifo_bytepos := "00";
v.txfifo_raddr := std_logic_vector(unsigned(r.txfifo_raddr) + 1);
else
-- Move to next byte.
v.txfifo_bytepos := std_logic_vector(unsigned(r.txfifo_bytepos) + 1);
end if;
-- Clear discard flag when past EOP.
if s_txfifo_rdata(35-v_txfifo_bytepos) = '1' then
v.txdiscard := '0';
end if;
end if;
 
-- Update RX fifo pointers.
if msto.rxfifo_read = '1' then
-- Read one word.
v.rxfifo_raddr := std_logic_vector(unsigned(r.rxfifo_raddr) + 1);
end if;
if r.rxfifo_write = '1' then
-- Write one word.
v.rxfifo_waddr := std_logic_vector(unsigned(r.rxfifo_waddr) + 1);
end if;
 
-- Detect RX fifo empty (using new value of rxfifo_raddr).
-- Note: The FIFO is empty if head and tail pointer are equal.
v.rxfifo_empty := conv_std_logic(v.rxfifo_raddr = r.rxfifo_waddr);
 
-- Indicate RX fifo room for SpaceWire flow control.
-- The flow control window is normally expressed as a number of bytes,
-- but we don't know how many bytes we can fit in each word because
-- some words are only partially used. So we report FIFO room as if
-- each FIFO word can hold only one byte, which is an overly
-- pessimistic estimate.
-- (Use the new value of rxfifo_waddr.)
v_tmprxroom := unsigned(r.rxfifo_raddr) - unsigned(v.rxfifo_waddr) - 1;
if v_tmprxroom > 63 then
-- at least 64 bytes room.
v.rxroom := "111111";
else
-- less than 64 bytes room.
v.rxroom := std_logic_vector(v_tmprxroom(5 downto 0));
end if;
 
-- Update TX fifo write pointer.
if msto.txfifo_write = '1' then
-- write one word.
v.txfifo_waddr := std_logic_vector(unsigned(r.txfifo_waddr) + 1);
end if;
 
-- Detect TX fifo empty.
-- Note: The FIFO may be either full or empty if head and tail pointer
-- are equal, hence the additional test for txfifo_nxfull.
v.txfifo_empty := conv_std_logic(v.txfifo_raddr = r.txfifo_waddr) and not r.txfifo_nxfull;
 
-- Detect TX fifo full after one more write.
if unsigned(r.txfifo_raddr) - unsigned(r.txfifo_waddr) = to_unsigned(2, txfifosize) then
-- currently exactly 2 words left.
v.txfifo_nxfull := msto.txfifo_write;
end if;
 
-- Detect TX fifo more than 3/4 full.
if unsigned(r.txfifo_raddr) - unsigned(r.txfifo_waddr) = to_unsigned(2**(txfifosize-2), txfifosize) then
-- currently exactly 3/4 full.
v.txfifo_highw := msto.txfifo_write;
end if;
 
-- Update descriptor pointers.
if msto.rxdesc_next = '1' then
if msto.rxdesc_wrap = '1' then
v.rxdesc_ptr(desctablesize+2 downto 3) := (others => '0');
else
v.rxdesc_ptr(desctablesize+2 downto 3) :=
std_logic_vector(unsigned(r.rxdesc_ptr(desctablesize+2 downto 3)) + 1);
end if;
end if;
if msto.txdesc_next = '1' then
if msto.txdesc_wrap = '1' then
v.txdesc_ptr(desctablesize+2 downto 3) := (others => '0');
else
v.txdesc_ptr(desctablesize+2 downto 3) :=
std_logic_vector(unsigned(r.txdesc_ptr(desctablesize+2 downto 3)) + 1);
end if;
end if;
 
-- If the link is lost, set a flag to discard the current packet.
if linko.running = '0' then
v.rxeep := v.rxeep or v.rxpacket; -- use new value of rxpacket
v.txdiscard := v.txdiscard or v.txpacket; -- use new value of txpacket
v.rxpacket := '0';
v.txpacket := '0';
end if;
 
-- Clear the discard flag when the link is explicitly disabled.
if r.ctl_linkdis = '1' then
v.txdiscard := '0';
end if;
 
-- Extend TX cancel command until TX DMA has stopped.
if msto.txdma_act = '0' then
v.ctl_txcancel := '0';
end if;
 
-- Update status registers.
v.sta_link(0) := linko.running or linko.started;
v.sta_link(1) := linko.running or linko.connecting;
if linko.errdisc = '1' then v.sta_errdisc := '1'; end if;
if linko.errpar = '1' then v.sta_errpar := '1'; end if;
if linko.erresc = '1' then v.sta_erresc := '1'; end if;
if linko.errcred = '1' then v.sta_errcred := '1'; end if;
if linko.tick_out = '1' then v.sta_gottick := '1'; end if;
if msto.int_rxdesc = '1' then v.sta_rxdesc := '1'; end if;
if msto.int_txdesc = '1' then v.sta_txdesc := '1'; end if;
if msto.int_rxpacket = '1' then v.sta_rxpacket := '1'; end if;
if msto.int_rxpacket = '1' and r.rxfifo_empty = '1' then
v.sta_rxempty := '1';
elsif r.rxfifo_empty = '0' then
v.sta_rxempty := '0';
end if;
 
-- Generate interrupt requests.
v.irq :=
(r.ctl_ielink and (linko.running xor (r.sta_link(0) and r.sta_link(1)))) or
(r.ctl_ietick and linko.tick_out) or
(r.ctl_ierxdesc and msto.int_rxdesc) or
(r.ctl_ietxdesc and msto.int_txdesc) or
(r.ctl_ierxpacket and msto.int_rxpacket);
 
-- APB read access.
if apbi.psel(pindex) = '1' then
case apbi.paddr(4 downto 2) is
when "000" => -- read control register
v_prdata(0) := '0';
v_prdata(1) := '0';
v_prdata(2) := r.ctl_linkstart;
v_prdata(3) := r.ctl_autostart;
v_prdata(4) := r.ctl_linkdis;
v_prdata(5) := r.ctl_ticken;
v_prdata(6) := '0';
v_prdata(7) := '0';
v_prdata(8) := r.ctl_txcancel;
v_prdata(9) := r.ctl_ielink;
v_prdata(10) := r.ctl_ietick;
v_prdata(11) := r.ctl_ierxdesc;
v_prdata(12) := r.ctl_ietxdesc;
v_prdata(13) := r.ctl_ierxpacket;
v_prdata(27 downto 24) := std_logic_vector(to_unsigned(desctablesize, 4));
when "001" => -- read status register
v_prdata(1 downto 0) := r.sta_link;
v_prdata(2) := r.sta_errdisc;
v_prdata(3) := r.sta_errpar;
v_prdata(4) := r.sta_erresc;
v_prdata(5) := r.sta_errcred;
v_prdata(6) := msto.rxdma_act;
v_prdata(7) := msto.txdma_act;
v_prdata(8) := msto.ahberror;
v_prdata(10) := r.sta_gottick;
v_prdata(11) := r.sta_rxdesc;
v_prdata(12) := r.sta_txdesc;
v_prdata(13) := r.sta_rxpacket;
v_prdata(14) := r.sta_rxempty;
when "010" => -- read transmission clock scaler
v_prdata(7 downto 0) := r.txdivcnt;
when "011" => -- read timecode register
v_prdata(5 downto 0) := linko.time_out;
v_prdata(7 downto 6) := linko.ctrl_out;
v_prdata(13 downto 8) := r.time_in;
v_prdata(16 downto 14) := "000";
when "100" => -- read rx descriptor pointer
v_prdata(2 downto 0) := (others => '0');
v_prdata(31 downto 3) := r.rxdesc_ptr;
when "101" => -- read tx descriptor pointer
v_prdata(2 downto 0) := (others => '0');
v_prdata(31 downto 3) := r.txdesc_ptr;
when others =>
null;
end case;
end if;
 
-- APB write access.
if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then
case apbi.paddr(4 downto 2) is
when "000" => -- write control register
v.ctl_reset := apbi.pwdata(0);
v.ctl_resetdma := apbi.pwdata(1);
v.ctl_linkstart := apbi.pwdata(2);
v.ctl_autostart := apbi.pwdata(3);
v.ctl_linkdis := apbi.pwdata(4);
v.ctl_ticken := apbi.pwdata(5);
v.ctl_rxstart := apbi.pwdata(6);
v.ctl_txstart := apbi.pwdata(7);
if apbi.pwdata(8) = '1' then v.ctl_txcancel := '1'; end if;
v.ctl_ielink := apbi.pwdata(9);
v.ctl_ietick := apbi.pwdata(10);
v.ctl_ierxdesc := apbi.pwdata(11);
v.ctl_ietxdesc := apbi.pwdata(12);
v.ctl_ierxpacket := apbi.pwdata(13);
when "001" => -- write status register
if apbi.pwdata(2) = '1' then v.sta_errdisc := '0'; end if;
if apbi.pwdata(3) = '1' then v.sta_errpar := '0'; end if;
if apbi.pwdata(4) = '1' then v.sta_erresc := '0'; end if;
if apbi.pwdata(5) = '1' then v.sta_errcred := '0'; end if;
if apbi.pwdata(10) = '1' then v.sta_gottick := '0'; end if;
if apbi.pwdata(11) = '1' then v.sta_rxdesc := '0'; end if;
if apbi.pwdata(12) = '1' then v.sta_txdesc := '0'; end if;
if apbi.pwdata(13) = '1' then v.sta_rxpacket := '0'; end if;
when "010" => -- write transmission clock scaler
v.txdivcnt := apbi.pwdata(7 downto 0);
when "011" => -- write timecode register
v.time_in := apbi.pwdata(13 downto 8);
if apbi.pwdata(16) = '1' then v.tick_in := '1'; end if;
when "100" => -- write rx descriptor pointer
v.rxdesc_ptr := apbi.pwdata(31 downto 3);
when "101" => -- write tx descriptor pointer
v.txdesc_ptr := apbi.pwdata(31 downto 3);
when others =>
null;
end case;
end if;
 
-- Drive control signals to RX fifo.
s_rxfifo_raddr <= v.rxfifo_raddr; -- new value of rxfifo_raddr
s_rxfifo_wen <= r.rxfifo_write;
s_rxfifo_waddr <= r.rxfifo_waddr;
s_rxfifo_wdata <= r.rxfifo_wdata;
 
-- Drive control signals to TX fifo.
s_txfifo_raddr <= v.txfifo_raddr; -- new value of txfifo_raddr
s_txfifo_wen <= msto.txfifo_write;
s_txfifo_waddr <= r.txfifo_waddr;
s_txfifo_wdata <= msto.txfifo_wdata;
 
-- Drive inputs to spwlink.
linki.autostart <= r.ctl_autostart;
linki.linkstart <= r.ctl_linkstart;
linki.linkdis <= r.ctl_linkdis;
linki.rxroom <= r.rxroom;
linki.tick_in <= r.tick_in;
linki.ctrl_in <= "00";
linki.time_in <= r.time_in;
linki.txwrite <= (not r.txfifo_empty) and (not r.txdiscard);
linki.txflag <= s_txfifo_rdata(35-v_txfifo_bytepos);
linki.txdata <= s_txfifo_rdata(31-8*v_txfifo_bytepos downto 24-8*v_txfifo_bytepos);
 
-- Drive divcnt input to spwxmit.
if linko.running = '1' then
xmit_divcnt <= r.txdivcnt;
else
xmit_divcnt <= default_divcnt;
end if;
 
-- Drive inputs to AHB master.
msti.rxdma_start <= r.ctl_rxstart;
msti.txdma_start <= r.ctl_txstart;
msti.txdma_cancel <= r.ctl_txcancel;
msti.rxdesc_ptr <= r.rxdesc_ptr;
msti.txdesc_ptr <= r.txdesc_ptr;
msti.rxfifo_rdata <= s_rxfifo_rdata;
msti.rxfifo_empty <= r.rxfifo_empty;
msti.rxfifo_nxempty <= v.rxfifo_empty; -- new value of rxfifo_empty
msti.txfifo_nxfull <= r.txfifo_nxfull;
msti.txfifo_highw <= r.txfifo_highw;
 
-- Drive APB output signals.
apbo.prdata <= v_prdata;
apbo.pirq <= (others => '0');
apbo.pirq(pirq) <= r.irq;
apbo.pconfig <= pconfig;
apbo.pindex <= pindex;
 
-- Reset components.
ahbmst_rstn <= rstn and (not r.ctl_reset) and (not r.ctl_resetdma);
s_rst <= (not rstn) or r.ctl_reset;
 
-- Clear TX fifo on cancel request.
if r.ctl_txcancel = '1' then
v.txfifo_raddr := (others => '0');
v.txfifo_waddr := (others => '0');
v.txfifo_empty := '1';
v.txfifo_nxfull := '0';
v.txfifo_highw := '0';
v.txfifo_bytepos := "00";
v.txpacket := '0';
v.txdiscard := '0';
end if;
 
-- Reset registers.
if rstn = '0' or r.ctl_reset = '1' then
v := regs_reset;
end if;
 
-- Update registers.
rin <= v;
end process;
 
 
--
-- Update registers.
--
process (clk) is
begin
if rising_edge(clk) then
r <= rin;
end if;
end process;
 
end architecture spwamba_arch;
/vhdl/spwambapkg.vhd
0,0 → 1,158
--
-- VHDL package for SpaceWire AMBA interface.
--
-- This package depends on Gaisler GRLIB.
--
 
library ieee;
use ieee.std_logic_1164.all;
library grlib;
use grlib.amba.all;
library techmap;
use techmap.gencomp.all;
use work.spwpkg.all;
 
package spwambapkg is
 
 
-- AMBA plug&play device id
constant DEVICE_SPACEWIRELIGHT: amba_device_type := 16#131#;
 
 
-- Signals from SpaceWire core to AHB master.
type spw_ahbmst_in_type is record
 
-- Pulse high to start the RX DMA engine.
rxdma_start: std_ulogic;
 
-- Pulse high to start the TX DMA engine.
txdma_start: std_ulogic;
 
-- Stop TX DMA engine (at end of current burst).
txdma_cancel: std_ulogic;
 
-- Address of current RX descriptor (8-byte aligned).
rxdesc_ptr: std_logic_vector(31 downto 3);
 
-- Address of current TX descriptor (8-byte aligned).
txdesc_ptr: std_logic_vector(31 downto 3);
 
-- Read port of RX FIFO.
rxfifo_rdata: std_logic_vector(35 downto 0);
 
-- High if RX FIFO is empty.
rxfifo_empty: std_ulogic;
 
-- High if RX FIFO will be empty after one read.
-- May combinatorially depend on spw_ahbmst_out_type.rxfifo_read.
rxfifo_nxempty: std_ulogic;
 
-- High if TX FIFO is full or has room for at most one word.
txfifo_nxfull: std_ulogic;
 
-- High if TX FIFO is close to full (blocks refill).
txfifo_highw: std_ulogic;
end record;
 
-- Signals from AHB master to SpaceWire core.
type spw_ahbmst_out_type is record
 
-- High if the RX DMA engine is enabled.
rxdma_act: std_ulogic;
 
-- High if the TX DMA engine is enabled.
txdma_act: std_ulogic;
 
-- High if an error occurred on the AHB bus.
ahberror: std_ulogic;
 
-- Pulsed high to trigger an RX descriptor interrupt.
int_rxdesc: std_ulogic;
 
-- Pulsed high to trigger a TX descriptor interrupt.
int_txdesc: std_ulogic;
 
-- Pulsed high when a complete packet has been received.
int_rxpacket: std_ulogic;
 
-- Pulsed high to request the next RX descriptor address.
-- (rxdesc_ptr must be updated in the next clock cycle).
rxdesc_next: std_ulogic;
 
-- Pulsed high together with rxdesc_next to wrap the RX descriptor pointer.
rxdesc_wrap: std_ulogic;
 
-- Pulsed high to request the next TX descriptor address.
-- (txdesc_ptr must be updated in the next clock cycle).
txdesc_next: std_ulogic;
 
-- Pulsed high together with txdesc_next to wrap the TX descriptor pointer.
txdesc_wrap: std_ulogic;
 
-- Read strobe to RX fifo.
rxfifo_read: std_ulogic;
 
-- Write enable to TX fifo.
txfifo_write: std_ulogic;
 
-- Input port of TX fifo.
txfifo_wdata: std_logic_vector(35 downto 0);
end record;
 
 
-- SpaceWire core with AMBA interface.
component spwamba is
generic (
tech: integer range 0 to NTECH := DEFFABTECH;
hindex: integer; -- AHB master index
pindex: integer; -- APB slave index
paddr: integer; -- APB address range
pmask: integer := 16#fff#; -- APB address mask
pirq: integer; -- interrupt number
sysfreq: real; -- system clock frequency in Hz
txclkfreq: real := 0.0; -- txclk frequency in Hz
rximpl: spw_implementation_type := impl_generic;
rxchunk: integer range 1 to 4 := 1;
tximpl: spw_implementation_type := impl_generic;
timecodegen: boolean := true; -- support timecode generation
rxfifosize: integer range 6 to 12 := 8; -- size of receive FIFO (2-log of words)
txfifosize: integer range 2 to 12 := 8; -- size of transmit FIFO (2-log of words)
desctablesize: integer range 4 to 14 := 10; -- size of the DMA descriptor tables (2-log of descriptors)
maxburst: integer range 1 to 8 := 3 -- max burst length (2-log of words)
);
port (
clk: in std_logic; -- system clock.
rxclk: in std_logic; -- receiver sample clock
txclk: in std_logic; -- transmit clock
rstn: in std_logic; -- synchronous reset (active-low)
apbi: in apb_slv_in_type; -- APB slave input signals
apbo: out apb_slv_out_type; -- APB slave output signals
ahbi: in ahb_mst_in_type; -- AHB master input signals
ahbo: out ahb_mst_out_type; -- AHB master output signals
tick_in: in std_logic; -- pulse for timecode generation
spw_di: in std_logic; -- Data In signal from SpaceWire bus
spw_si: in std_logic; -- Strobe In signal from SpaceWire bus
spw_do: out std_logic; -- Data Out signal to SpaceWire bus
spw_so: out std_logic -- Strobe Out signal to SpaceWire bus
);
end component spwamba;
 
 
-- AHB master for AMBA interface.
component spwahbmst is
generic (
hindex: integer; -- AHB master index
hconfig: ahb_config_type; -- AHB plug&play information
maxburst: integer range 1 to 8 -- 2log of max burst length
);
port (
clk: in std_logic; -- system clock
rstn: in std_logic; -- synchronous reset (active-low)
msti: in spw_ahbmst_in_type; -- inputs from SpaceWire core
msto: out spw_ahbmst_out_type; -- outputs to SpaceWire core
ahbi: in ahb_mst_in_type; -- AHB master input signals
ahbo: out ahb_mst_out_type -- AHB master output signals
);
end component spwahbmst;
 
end package;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.