Subversion Repositories tcp_socket
Compare Revisions
- This comparison shows the changes necessary to convert path
/tcp_socket/trunk
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
unsigned put_socket(int i){ |
file_write(i, "packet"); |
return 0; |
} |
|
#include "HTTP.h" |
|
//simple echo application |
void main(){ |
HTTP_GET_response("Hello!\n"); |
} |
//////////////////////////////////////////////////////////////////////////////// |
// |
// CHIPS-2.0 print.h |
// |
// :Author: Jonathan P Dawson |
// :Date: 22/10/2013 |
// :email: chips@jondawson.org.uk |
// :license: MIT |
// :Copyright: Copyright (C) Jonathan P Dawson 2013 |
// |
// Print values to stdout. Before including this file, |
// void stdout_put_char(unsigned i) must be defined. |
// |
// This task is left to the user so that stdout can be directed to uart/socket |
// as required. |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
|
//Print a string *string* to stdout |
void print_string(unsigned string[]){ |
unsigned i=0; |
while(string[i]){ |
stdout_put_char(string[i]); |
i++; |
} |
} |
|
//Print an unsigned int to stdout in hex format |
void print_uhex(unsigned uhex){ |
unsigned digit_3 = (uhex >> 12) & 0xf; |
unsigned digit_2 = (uhex >> 8) & 0xf; |
unsigned digit_1 = (uhex >> 4) & 0xf; |
unsigned digit_0 = uhex & 0xf; |
if(digit_3 < 9) stdout_put_char(digit_3 | 0x30); |
else stdout_put_char(digit_3 + 87); |
if(digit_2 < 9) stdout_put_char(digit_2 | 0x30); |
else stdout_put_char(digit_2 + 87); |
if(digit_1 < 9) stdout_put_char(digit_1 | 0x30); |
else stdout_put_char(digit_1 + 87); |
if(digit_0 < 9) stdout_put_char(digit_0 | 0x30); |
else stdout_put_char(digit_0 + 87); |
} |
|
//Print an unsigned int to stdout in decimal format |
//leading 0s will be suppressed |
void print_udecimal(unsigned udecimal){ |
unsigned digit; |
unsigned significant = 0; |
digit = 0; |
while(udecimal >= 10000){ |
udecimal -= 10000; |
digit += 1; |
} |
if(digit | significant){ |
stdout_put_char(digit | 0x30); |
significant = 1; |
} |
digit = 0; |
while(udecimal >= 1000){ |
udecimal -= 1000; |
digit += 1; |
} |
if(digit | significant){ |
stdout_put_char(digit | 0x30); |
significant = 1; |
} |
digit = 0; |
while(udecimal >= 100){ |
udecimal -= 100; |
digit += 1; |
} |
if(digit | significant){ |
stdout_put_char(digit | 0x30); |
significant = 1; |
} |
digit = 0; |
while(udecimal >= 10){ |
udecimal -= 10; |
digit += 1; |
} |
if(digit | significant){ |
stdout_put_char(digit | 0x30); |
significant = 1; |
} |
stdout_put_char(udecimal | 0x30); |
} |
|
//Print a signed int to stdout in hex format |
void print_hex(int hex){ |
if(hex >= 0){ |
print_uhex(hex); |
} else { |
stdout_put_char('-'); |
print_uhex(-hex); |
} |
} |
|
//Print a signed int to stdout in decimal format |
//leading 0s will be suppressed |
void print_decimal(int decimal){ |
if(decimal >= 0){ |
print_udecimal(decimal); |
} else { |
stdout_put_char('-'); |
print_udecimal(-decimal); |
} |
} |
-------------------------------------------------------------------------------- |
--- |
--- Gigabit Ethernet MAC |
--- |
--- :Author: Jonathan P Dawson |
--- :Date: 17/10/2013 |
--- :email: chips@jondawson.org.uk |
--- :license: MIT |
--- :Copyright: Copyright (C) Jonathan P Dawson 2013 |
--- |
--- A gigabit ethernet MAC |
--- |
-------------------------------------------------------------------------------- |
--- |
---Gigabit Ethernet |
---================ |
--- |
---Send and receive Ethernet packets. Using a Ethernet Physical Interface. |
--- |
---Features: |
--- |
---+ Supports 1Gbit/s ethernet only via a gmii interface. |
---+ Supports full duplex mode only. |
--- |
---Interface |
------------ |
---:input: TX - Data to send (16 bits). |
---:output: RX - Data to send (16 bits). |
--- |
---Ethernet Packet Structure |
---------------------------- |
--- |
---+-------------+-------------+--------+--------+---------+---------+-----+ |
---| Description | destination | source | length | payload | padding | FSC | |
---+=============+=============+========+========+=========+=========+=====+ |
---| Bytes | 6 | 6 | 2 | 0-1500 | 0-46 | 4 | |
---+-------------+-------------+--------+--------+---------+---------+-----+ |
--- |
---Notes: |
--- |
---+ The *length* field is the length of the ethernet payload. |
---+ The *Ethernet Output* block will automatically append the FSC to |
--- outgoing packets. |
---+ The *FSC* of incoming packets will be checked, and bad packets will |
--- be discarded. The *FSC* will be stripped from incoming packets. |
---+ The length of the *payload* + *padding* must be 46-1500 bytes. |
---+ Incoming packets of incorrect *length* will be discarded. |
--- |
---Usage |
-------- |
--- |
---Transmit |
---~~~~~~~~ |
---The first 16 bit word on the TX input is interpreted as the length of the |
---packet in bytes (including the MAC address, length and payload, but not the |
---preamble or FSC). Subsequent words on the TX input are interpreted as the |
---content of the packet. If length is an odd number of bytes, then the least |
---significant byte of the last word will be ignored. |
---The FSC will be appended for you, but you need to supply the destination, |
---source and length fields. |
--- |
---Receive |
---~~~~~~~~ |
---The first 16 bit word on the RX output will be the length of the packet in |
---bytes (including the MAC address, length and payload, but not the |
---preamble or FSC). Subsequent words on the RX output will be the |
---content of the packet. If length is an odd number of bytes, then the least |
---significant byte of the last word will not contain usefull data. |
---The FSC will be stripped from incoming packets, but the destination, |
---source and length fields will be included. |
--- |
---Hardware details |
------------------- |
---This component used two clocks, the local clock used to transfer data |
---between components, and a 125MHz clock source for sending data to the |
---Ethernet physical interface. This clock is also forwarded along with the |
---data to the ethernet phy. |
--- |
|
library ieee; |
use ieee.numeric_std.all; |
use ieee.std_logic_1164.all; |
|
entity gigabit_ethernet is |
port( |
CLK : in std_logic; |
RST : in std_logic; |
|
--Ethernet Clock |
CLK_125_MHZ : in std_logic; |
|
--GMII IF |
GTXCLK : out std_logic; |
TXCLK : in std_logic; |
TXER : out std_logic; |
TXEN : out std_logic; |
TXD : out std_logic_vector(7 downto 0); |
PHY_RESET : out std_logic; |
RXCLK : in std_logic; |
RXER : in std_logic; |
RXDV : in std_logic; |
RXD : in std_logic_vector(7 downto 0); |
|
--RX STREAM |
TX : in std_logic_vector(15 downto 0); |
TX_STB : in std_logic; |
TX_ACK : out std_logic; |
|
--RX STREAM |
RX : out std_logic_vector(15 downto 0); |
RX_STB : out std_logic; |
RX_ACK : in std_logic |
); |
end entity gigabit_ethernet; |
|
architecture RTL of gigabit_ethernet is |
|
-- polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32) |
-- data width: 8 |
-- convention: the first serial bit is D[0] |
function NEXTCRC32_D8 |
(DATA: std_logic_vector(7 downto 0); |
CRC: std_logic_vector(31 downto 0)) |
return std_logic_vector is |
|
variable D: std_logic_vector(7 downto 0); |
variable C: std_logic_vector(31 downto 0); |
variable NEWCRC: std_logic_vector(31 downto 0); |
|
begin |
D := DATA; |
C := CRC; |
NewCRC(0):=C(24) xor C(30) xor D(1) xor D(7); |
NewCRC(1):=C(25) xor C(31) xor D(0) xor D(6) xor C(24) xor C(30) xor D(1) |
xor D(7); |
NewCRC(2):=C(26) xor D(5) xor C(25) xor C(31) xor D(0) xor D(6) xor C(24) |
xor C(30) xor D(1) xor D(7); |
NewCRC(3):=C(27) xor D(4) xor C(26) xor D(5) xor C(25) xor C(31) xor D(0) |
xor D(6); |
NewCRC(4):=C(28) xor D(3) xor C(27) xor D(4) xor C(26) xor D(5) xor C(24) |
xor C(30) xor D(1) xor D(7); |
NewCRC(5):=C(29) xor D(2) xor C(28) xor D(3) xor C(27) xor D(4) xor C(25) |
xor C(31) xor D(0) xor D(6) xor C(24) xor C(30) xor D(1) xor D(7); |
NewCRC(6):=C(30) xor D(1) xor C(29) xor D(2) xor C(28) xor D(3) xor C(26) |
xor D(5) xor C(25) xor C(31) xor D(0) xor D(6); |
NewCRC(7):=C(31) xor D(0) xor C(29) xor D(2) xor C(27) xor D(4) xor C(26) |
xor D(5) xor C(24) xor D(7); |
NewCRC(8):=C(0) xor C(28) xor D(3) xor C(27) xor D(4) xor C(25) xor D(6) |
xor C(24) xor D(7); |
NewCRC(9):=C(1) xor C(29) xor D(2) xor C(28) xor D(3) xor C(26) xor D(5) |
xor C(25) xor D(6); |
NewCRC(10):=C(2) xor C(29) xor D(2) xor C(27) xor D(4) xor C(26) xor D(5) |
xor C(24) xor D(7); |
NewCRC(11):=C(3) xor C(28) xor D(3) xor C(27) xor D(4) xor C(25) xor D(6) |
xor C(24) xor D(7); |
NewCRC(12):=C(4) xor C(29) xor D(2) xor C(28) xor D(3) xor C(26) xor D(5) |
xor C(25) xor D(6) xor C(24) xor C(30) xor D(1) xor D(7); |
NewCRC(13):=C(5) xor C(30) xor D(1) xor C(29) xor D(2) xor C(27) xor D(4) |
xor C(26) xor D(5) xor C(25) xor C(31) xor D(0) xor D(6); |
NewCRC(14):=C(6) xor C(31) xor D(0) xor C(30) xor D(1) xor C(28) xor D(3) |
xor C(27) xor D(4) xor C(26) xor D(5); |
NewCRC(15):=C(7) xor C(31) xor D(0) xor C(29) xor D(2) xor C(28) xor D(3) |
xor C(27) xor D(4); |
NewCRC(16):=C(8) xor C(29) xor D(2) xor C(28) xor D(3) xor C(24) xor D(7); |
NewCRC(17):=C(9) xor C(30) xor D(1) xor C(29) xor D(2) xor C(25) xor D(6); |
NewCRC(18):=C(10) xor C(31) xor D(0) xor C(30) xor D(1) xor C(26) xor D(5); |
NewCRC(19):=C(11) xor C(31) xor D(0) xor C(27) xor D(4); |
NewCRC(20):=C(12) xor C(28) xor D(3); |
NewCRC(21):=C(13) xor C(29) xor D(2); |
NewCRC(22):=C(14) xor C(24) xor D(7); |
NewCRC(23):=C(15) xor C(25) xor D(6) xor C(24) xor C(30) xor D(1) xor D(7); |
NewCRC(24):=C(16) xor C(26) xor D(5) xor C(25) xor C(31) xor D(0) xor D(6); |
NewCRC(25):=C(17) xor C(27) xor D(4) xor C(26) xor D(5); |
NewCRC(26):=C(18) xor C(28) xor D(3) xor C(27) xor D(4) xor C(24) xor C(30) |
xor D(1) xor D(7); |
NewCRC(27):=C(19) xor C(29) xor D(2) xor C(28) xor D(3) xor C(25) xor C(31) |
xor D(0) xor D(6); |
NewCRC(28):=C(20) xor C(30) xor D(1) xor C(29) xor D(2) xor C(26) xor D(5); |
NewCRC(29):=C(21) xor C(31) xor D(0) xor C(30) xor D(1) xor C(27) xor D(4); |
NewCRC(30):=C(22) xor C(31) xor D(0) xor C(28) xor D(3); |
NewCRC(31):=C(23) xor C(29) xor D(2); |
|
return NEWCRC; |
end NEXTCRC32_D8; |
|
-- Reverse the input vector. |
function REVERSED(slv: std_logic_vector) return std_logic_vector is |
variable result: std_logic_vector(slv'reverse_range); |
begin |
for i in slv'range loop |
result(i) := slv(i); |
end loop; |
return result; |
end REVERSED; |
|
--constants |
constant ADDRESS_BITS : integer := 11; |
constant ADDRESS_MAX : integer := (2**ADDRESS_BITS) - 1; |
|
--memories |
type TX_MEMORY_TYPE is array (0 to 511) of |
std_logic_vector(15 downto 0); |
shared variable TX_MEMORY : TX_MEMORY_TYPE; |
|
type RX_MEMORY_TYPE is array (0 to ADDRESS_MAX) of |
std_logic_vector(15 downto 0); |
shared variable RX_MEMORY : RX_MEMORY_TYPE; |
|
type ADDRESS_ARRAY is array (0 to 31) of |
unsigned(ADDRESS_BITS - 1 downto 0); |
|
--state variables |
type TX_PHY_STATE_TYPE is (WAIT_NEW_PACKET, PREAMBLE_0, PREAMBLE_1, |
PREAMBLE_2, PREAMBLE_3, PREAMBLE_4, PREAMBLE_5, PREAMBLE_6, SFD, |
SEND_DATA_HI, SEND_DATA_LO, SEND_CRC_3, SEND_CRC_2, SEND_CRC_1, |
SEND_CRC_0, DONE_STATE); |
signal TX_PHY_STATE : TX_PHY_STATE_TYPE; |
|
type TX_PACKET_STATE_TYPE is(GET_LENGTH, GET_DATA, SEND_PACKET, |
WAIT_NOT_DONE); |
signal TX_PACKET_STATE : TX_PACKET_STATE_TYPE; |
|
type RX_PHY_STATE_TYPE is (WAIT_START, PREAMBLE, DATA_HIGH, DATA_LOW, |
END_OF_FRAME, NOTIFY_NEW_PACKET); |
signal RX_PHY_STATE : RX_PHY_STATE_TYPE; |
|
type RX_PACKET_STATE_TYPE is (WAIT_INITIALISE, WAIT_NEW_PACKET, |
SEND_DATA, PREFETCH0, PREFETCH1, SEND_LENGTH); |
signal RX_PACKET_STATE : RX_PACKET_STATE_TYPE; |
|
--TX signals |
signal TX_WRITE : std_logic; |
signal TX_WRITE_DATA : std_logic_vector(15 downto 0); |
signal TX_READ_DATA : std_logic_vector(15 downto 0); |
signal TX_WRITE_ADDRESS : integer range 0 to 1513; |
signal TX_WRITE_ADDRESS_DEL : integer range 0 to 1513; |
signal TX_READ_ADDRESS : integer range 0 to 1513; |
signal TX_CRC : std_logic_vector(31 downto 0); |
signal TX_IN_COUNT : integer range 0 to 1513; |
signal TX_OUT_COUNT : integer range 0 to 1513; |
signal TX_PACKET_LENGTH : std_logic_vector(15 downto 0); |
signal GO, GO_DEL, GO_SYNC : std_logic; |
signal DONE, DONE_DEL, DONE_SYNC : std_logic; |
signal S_TX_ACK : std_logic; |
|
--RX signals |
signal RX_WRITE_ADDRESS : unsigned(ADDRESS_BITS - 1 downto 0); |
signal RX_READ_ADDRESS : unsigned(ADDRESS_BITS - 1 downto 0); |
signal RX_START_ADDRESS : unsigned(ADDRESS_BITS - 1 downto 0); |
signal RX_PACKET_LENGTH : unsigned(ADDRESS_BITS - 1 downto 0); |
signal RX_START_ADDRESS_BUFFER : ADDRESS_ARRAY; |
signal RX_PACKET_LENGTH_BUFFER : ADDRESS_ARRAY; |
signal RX_WRITE_BUFFER : integer range 0 to 31; |
signal RX_READ_BUFFER : integer range 0 to 31; |
signal RX_BUFFER_BUSY : std_logic_vector(31 downto 0); |
signal RX_BUFFER_BUSY_DEL : std_logic_vector(31 downto 0); |
signal RX_BUFFER_BUSY_SYNC : std_logic_vector(31 downto 0); |
signal RX_START_ADDRESS_SYNC : unsigned(ADDRESS_BITS - 1 downto 0); |
signal RX_PACKET_LENGTH_SYNC : unsigned(ADDRESS_BITS - 1 downto 0); |
signal RX_END_ADDRESS : unsigned(ADDRESS_BITS - 1 downto 0); |
signal RX_WRITE_DATA : std_logic_vector(15 downto 0); |
signal RX_WRITE_ENABLE : std_logic; |
signal RX_ERROR : std_logic; |
signal RX_CRC : std_logic_vector(31 downto 0); |
signal RXD_D : std_logic_vector(7 downto 0); |
signal RXDV_D : std_logic; |
signal RXER_D : std_logic; |
|
begin |
|
--This process is in the local clock domain. |
--It gets data and puts it into a RAM. |
--Once a packets worth of data has been stored it is |
--sent to the packet sending state machine. |
TX_PACKET_FSM : process |
begin |
wait until rising_edge(CLK); |
TX_WRITE <= '0'; |
case TX_PACKET_STATE is |
|
when GET_LENGTH => |
S_TX_ACK <= '1'; |
if S_TX_ACK = '1' and TX_STB = '1' then |
S_TX_ACK <= '0'; |
TX_PACKET_LENGTH <= TX; |
TX_IN_COUNT <= 2; |
TX_PACKET_STATE <= GET_DATA; |
end if; |
|
when GET_DATA => |
S_TX_ACK <= '1'; |
if S_TX_ACK = '1' and TX_STB = '1' then |
TX_WRITE_DATA <= TX; |
TX_WRITE <= '1'; |
if TX_IN_COUNT >= unsigned(TX_PACKET_LENGTH) then |
TX_PACKET_STATE <= SEND_PACKET; |
S_TX_ACK <= '0'; |
else |
TX_WRITE_ADDRESS <= TX_WRITE_ADDRESS + 1; |
TX_IN_COUNT <= TX_IN_COUNT + 2; |
end if; |
end if; |
|
when SEND_PACKET => |
GO <= '1'; |
TX_WRITE_ADDRESS <= 0; |
if DONE_SYNC = '1' then |
GO <= '0'; |
TX_PACKET_STATE <= WAIT_NOT_DONE; |
end if; |
|
when WAIT_NOT_DONE => |
if DONE_SYNC = '0' then |
TX_PACKET_STATE <= GET_LENGTH; |
end if; |
|
end case; |
if RST = '1' then |
TX_PACKET_STATE <= GET_LENGTH; |
TX_WRITE_ADDRESS <= 0; |
S_TX_ACK <= '0'; |
GO <= '0'; |
end if; |
end process TX_PACKET_FSM; |
|
TX_ACK <= S_TX_ACK; |
|
|
--This process writes data into a dual port RAM |
WRITE_DUAL_PORT_MEMORY : process |
begin |
wait until rising_edge(CLK); |
TX_WRITE_ADDRESS_DEL <= TX_WRITE_ADDRESS; |
if TX_WRITE = '1' then |
TX_MEMORY(TX_WRITE_ADDRESS_DEL) := TX_WRITE_DATA; |
end if; |
end process; |
|
--This process read data from a dual port RAM |
READ_DUAL_PORT_MEMORY : process |
begin |
wait until rising_edge(CLK_125_MHZ); |
TX_READ_DATA <= TX_MEMORY(TX_READ_ADDRESS); |
end process; |
|
--This process synchronises ethernet signals |
--to the local clock domain |
LOCAL_TO_CLK_125 : process |
begin |
wait until rising_edge(CLK_125_MHZ); |
GO_DEL <= GO; GO_SYNC <= GO_DEL; |
end process; |
|
--This process synchronises local signals to the ethernet clock domain |
CLK_125_TO_LOCAL : process |
begin |
wait until rising_edge(CLK); |
DONE_DEL <= DONE; DONE_SYNC <= DONE_DEL; |
end process; |
|
--Transmit the stored packet via the phy. |
TX_PHY_FSM : process |
begin |
wait until rising_edge(CLK_125_MHZ); |
case TX_PHY_STATE is |
|
when WAIT_NEW_PACKET => |
if GO_SYNC = '1' then |
TX_PHY_STATE <= PREAMBLE_0; |
TX_READ_ADDRESS <= 0; |
TX_OUT_COUNT <= to_integer(unsigned(TX_PACKET_LENGTH)-1); |
end if; |
|
when PREAMBLE_0 => |
TXD <= X"55"; |
TX_PHY_STATE <= PREAMBLE_1; |
TXEN <= '1'; |
|
when PREAMBLE_1 => |
TXD <= X"55"; |
TX_PHY_STATE <= PREAMBLE_2; |
|
when PREAMBLE_2 => |
TXD <= X"55"; |
TX_PHY_STATE <= PREAMBLE_3; |
|
when PREAMBLE_3 => |
TXD <= X"55"; |
TX_PHY_STATE <= PREAMBLE_4; |
|
when PREAMBLE_4 => |
TXD <= X"55"; |
TX_PHY_STATE <= PREAMBLE_5; |
|
when PREAMBLE_5 => |
TXD <= X"55"; |
TX_PHY_STATE <= PREAMBLE_6; |
|
when PREAMBLE_6 => |
TXD <= X"55"; |
TX_PHY_STATE <= SFD; |
|
when SFD => |
TXD <= X"D5"; |
TX_PHY_STATE <= SEND_DATA_HI; |
TX_CRC <= X"FFFFFFFF"; |
|
when SEND_DATA_HI => |
TX_CRC <= NEXTCRC32_D8(TX_READ_DATA(15 downto 8), TX_CRC); |
TXD <= TX_READ_DATA(15 downto 8); |
If TX_OUT_COUNT = 0 then |
TX_PHY_STATE <= SEND_CRC_3; |
else |
TX_PHY_STATE <= SEND_DATA_LO; |
TX_READ_ADDRESS <= TX_READ_ADDRESS + 1; |
TX_OUT_COUNT <= TX_OUT_COUNT - 1; |
end if; |
|
when SEND_DATA_LO => |
TX_CRC <= NEXTCRC32_D8(TX_READ_DATA(7 downto 0), TX_CRC); |
TXD <= TX_READ_DATA(7 downto 0); |
If TX_OUT_COUNT = 0 then |
TX_PHY_STATE <= SEND_CRC_3; |
else |
TX_PHY_STATE <= SEND_DATA_HI; |
TX_OUT_COUNT <= TX_OUT_COUNT - 1; |
end if; |
|
when SEND_CRC_3 => |
TXD <= not REVERSED(TX_CRC(31 downto 24)); |
TX_PHY_STATE <= SEND_CRC_2; |
|
when SEND_CRC_2 => |
TXD <= not REVERSED(TX_CRC(23 downto 16)); |
TX_PHY_STATE <= SEND_CRC_1; |
|
when SEND_CRC_1 => |
TXD <= not REVERSED(TX_CRC(15 downto 8)); |
TX_PHY_STATE <= SEND_CRC_0; |
|
when SEND_CRC_0 => |
TXD <= not REVERSED(TX_CRC(7 downto 0)); |
TX_PHY_STATE <= DONE_STATE; |
|
when DONE_STATE => |
TXEN <= '0'; |
DONE <= '1'; |
if GO_SYNC = '0' then |
TX_PHY_STATE <= WAIT_NEW_PACKET; |
DONE <= '0'; |
end if; |
|
end case; |
if RST = '1' then |
TXEN <= '0'; |
TX_PHY_STATE <= WAIT_NEW_PACKET; |
DONE <= '0'; |
TXD <= (others => '0'); |
end if; |
end process TX_PHY_FSM; |
|
TXER <= '0'; |
GTXCLK <= CLK_125_MHZ; |
|
--This process reads data out of the phy and puts it into a buffer. |
--There are many buffers on the RX side to cope with data arriving at |
--a high rate. If a very large packet is received, followed by many small |
--packets, a large number of packets need to be stored. |
RX_PHY_FSM : process |
begin |
wait until rising_edge(RXCLK); |
RX_WRITE_ENABLE <= '0'; |
RXDV_D <= RXDV; |
RXER_D <= RXER; |
RXD_D <= RXD; |
case RX_PHY_STATE is |
|
when WAIT_START => |
if RXDV_D = '1' and RXD_D = X"55" then |
RX_PHY_STATE <= PREAMBLE; |
RX_ERROR <= '0'; |
end if; |
|
when PREAMBLE => |
if RXD_D = X"d5" then |
RX_PHY_STATE <= DATA_HIGH; |
RX_START_ADDRESS <= RX_WRITE_ADDRESS; |
RX_PACKET_LENGTH <= to_unsigned(0, ADDRESS_BITS); |
RX_CRC <= X"ffffffff"; |
elsif RXD_D /= X"55" or RXDV_D = '0' then |
RX_PHY_STATE <= WAIT_START; |
end if; |
|
when DATA_HIGH => |
RX_WRITE_DATA(15 downto 8) <= RXD_D; |
if RXDV_D = '1' then |
RX_PACKET_LENGTH <= RX_PACKET_LENGTH + 1; |
RX_PHY_STATE <= DATA_LOW; |
RX_CRC <= nextCRC32_D8(RXD_D, RX_CRC); |
else |
RX_PHY_STATE <= END_OF_FRAME; |
end if; |
|
when DATA_LOW => |
RX_WRITE_DATA(7 downto 0) <= RXD_D; |
RX_WRITE_ENABLE <= '1'; |
if RXDV_D = '1' then |
RX_PACKET_LENGTH <= RX_PACKET_LENGTH + 1; |
RX_PHY_STATE <= DATA_HIGH; |
RX_CRC <= nextCRC32_D8(RXD_D, RX_CRC); |
else |
RX_PHY_STATE <= END_OF_FRAME; |
end if; |
|
when END_OF_FRAME => |
if RX_ERROR = '1' then |
RX_PHY_STATE <= WAIT_START; |
elsif RX_PACKET_LENGTH < 64 then |
RX_PHY_STATE <= WAIT_START; |
elsif RX_PACKET_LENGTH > 1518 then |
RX_PHY_STATE <= WAIT_START; |
elsif RX_CRC /= X"C704dd7B" then |
RX_PHY_STATE <= WAIT_START; |
else |
RX_PHY_STATE <= NOTIFY_NEW_PACKET; |
end if; |
|
when NOTIFY_NEW_PACKET => |
RX_PHY_STATE <= WAIT_START; |
RX_START_ADDRESS_BUFFER(RX_WRITE_BUFFER) <= RX_START_ADDRESS; |
RX_PACKET_LENGTH_BUFFER(RX_WRITE_BUFFER) <= RX_PACKET_LENGTH; |
if RX_WRITE_BUFFER = 31 then |
RX_WRITE_BUFFER <= 0; |
else |
RX_WRITE_BUFFER <= RX_WRITE_BUFFER + 1; |
end if; |
|
end case; |
|
if RXER_D = '1' then |
RX_ERROR <= '1'; |
end if; |
|
if RST = '1' then |
RX_PHY_STATE <= WAIT_START; |
end if; |
end process RX_PHY_FSM; |
|
--generate a signal for each buffer to indicate that is is being used. |
GENERATE_BUFFER_BUSY : process |
begin |
wait until rising_edge(RXCLK); |
for I in 0 to 31 loop |
if I = RX_WRITE_BUFFER then |
RX_BUFFER_BUSY(I) <= '1'; |
else |
RX_BUFFER_BUSY(I) <= '0'; |
end if; |
end loop; |
end process GENERATE_BUFFER_BUSY; |
|
--This is the memory that implements the RX buffers |
WRITE_RX_MEMORY : process |
begin |
wait until rising_edge(RXCLK); |
if RX_WRITE_ENABLE = '1' then |
RX_MEMORY(to_integer(RX_WRITE_ADDRESS)) := RX_WRITE_DATA; |
RX_WRITE_ADDRESS <= RX_WRITE_ADDRESS + 1; |
end if; |
if RST = '1' then |
RX_WRITE_ADDRESS <= (others => '0'); |
end if; |
end process WRITE_RX_MEMORY; |
|
SYNCHRONISE_BUFFER_BUSY : process |
begin |
wait until rising_edge(CLK); |
RX_BUFFER_BUSY_DEL <= RX_BUFFER_BUSY; |
RX_BUFFER_BUSY_SYNC <= RX_BUFFER_BUSY_DEL; |
end process SYNCHRONISE_BUFFER_BUSY; |
|
--CLK __/""\__/" _/" "\__/""\ |
--RX_BUFFER_BUSY_SYNC[0] ""\_______ ____________ |
--RX_BUFFER_BUSY_SYNC[1] ________/" "\__________ |
--RX_BUFFER_BUSY_SYNC[2] __________ _______/"""" |
-- ^ |
-- Start to read packet 0 here. |
-- Note: since RX_BUFFER_BUSY originates in a different clock domain, |
-- it is possible that a clock cycle or so could elapse between |
-- RX_BUFFER_BUSY_SYNC[0] becoming low and RX_BUFFER_BUSY_SYNC[1] becoming |
-- high. We are relying on the delay through the state machine to be |
-- long enough that we don't try to read BUFFER1 during this period. |
|
RX_PACKET_FSM : process |
begin |
wait until rising_edge(CLK); |
case RX_PACKET_STATE is |
|
when WAIT_INITIALISE => |
if RX_BUFFER_BUSY_SYNC(0) = '1' then |
RX_PACKET_STATE <= WAIT_NEW_PACKET; |
RX_READ_BUFFER <= 0; |
end if; |
|
when WAIT_NEW_PACKET => |
if RX_BUFFER_BUSY_SYNC(RX_READ_BUFFER) = '0' then |
RX_PACKET_STATE <= SEND_LENGTH; |
RX_START_ADDRESS_SYNC <= RX_START_ADDRESS_BUFFER(RX_READ_BUFFER); |
RX_PACKET_LENGTH_SYNC <= RX_PACKET_LENGTH_BUFFER(RX_READ_BUFFER); |
RX <= |
std_logic_vector( |
resize(RX_PACKET_LENGTH_BUFFER(RX_READ_BUFFER)-4, 16)); |
RX_STB <= '1'; |
end if; |
|
when SEND_LENGTH => |
if RX_ACK = '1' then |
RX_PACKET_STATE <= PREFETCH0; |
RX_STB <= '0'; |
end if; |
|
when PREFETCH0 => |
RX_READ_ADDRESS <= RX_START_ADDRESS_SYNC; |
RX_END_ADDRESS <= RX_START_ADDRESS_SYNC + (RX_PACKET_LENGTH_SYNC-3)/2; |
RX_PACKET_STATE <= PREFETCH1; |
|
when PREFETCH1 => |
RX_READ_ADDRESS <= RX_READ_ADDRESS + 1; |
RX <= RX_MEMORY(to_integer(RX_READ_ADDRESS)); |
RX_STB <= '1'; |
RX_PACKET_STATE <= SEND_DATA; |
|
when SEND_DATA => |
if RX_ACK = '1' then |
RX_READ_ADDRESS <= RX_READ_ADDRESS + 1; |
RX <= RX_MEMORY(to_integer(RX_READ_ADDRESS)); |
if RX_READ_ADDRESS = RX_END_ADDRESS then --don't send last packet |
RX_STB <= '0'; |
RX_PACKET_STATE <= WAIT_NEW_PACKET; |
if RX_READ_BUFFER = 31 then |
RX_READ_BUFFER <= 0; |
else |
RX_READ_BUFFER <= RX_READ_BUFFER + 1; |
end if; |
end if; |
end if; |
|
end case; |
if RST = '1' then |
RX_STB <= '0'; |
RX_PACKET_STATE <= WAIT_INITIALISE; |
end if; |
end process RX_PACKET_FSM; |
|
---------------------------------------------------------------------- |
-- RESET PHY CHIP |
---------------------------------------------------------------------- |
PHY_RESET <= not RST; |
|
end architecture RTL; |
//////////////////////////////////////////////////////////////////////////////// |
// |
// CHIPS-2.0 USER DESIGN |
// |
// :Author: Jonathan P Dawson |
// :Date: 17/10/2013 |
// :email: chips@jondawson.org.uk |
// :license: MIT |
// :Copyright: Copyright (C) Jonathan P Dawson 2013 |
// |
// Simple web app demo. |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
void put_socket(unsigned i){ |
output_socket(i); |
} |
void stdout_put_char(unsigned i){ |
output_rs232_tx(i); |
} |
|
#include "print.h" |
#include "HTTP.h" |
|
int find(unsigned string[], unsigned search, unsigned start, unsigned end){ |
int value = start; |
while(string[value]){ |
print_decimal(string[value]); print_string("\n"); |
print_decimal(value); print_string("\n"); |
if(value == end) return -1; |
if(string[value] == search) return value; |
value++; |
} |
return -1; |
} |
|
void user_design() |
{ |
//simple echo application |
unsigned length; |
unsigned i, index; |
unsigned data[1460]; |
unsigned word; |
unsigned switches = 0; |
unsigned buttons = 0; |
unsigned leds = 0; |
unsigned start, end; |
|
unsigned page[] = |
"<html>\ |
<head>\ |
<title>Chips-2.0 ATLYS Demo</title>\ |
</head>\ |
<body>\ |
<h1>Chips-2.0 ATLYS Demo</h1>\ |
<p>Welcome to the Chips-2.0 ATLYS Demo!</p>\ |
<p>Switch Status: 00000000</p>\ |
<p>Button Status: 0000</p>\ |
<form>\ |
<input type=\"checkbox\" name=\"led1\" value=\"A\">led 0</input>\ |
<input type=\"checkbox\" name=\"led2\" value=\"B\">led 1</input>\ |
<input type=\"checkbox\" name=\"led3\" value=\"C\">led 2</input>\ |
<input type=\"checkbox\" name=\"led4\" value=\"D\">led 3</input>\ |
<input type=\"checkbox\" name=\"led4\" value=\"E\">led 4</input>\ |
<input type=\"checkbox\" name=\"led4\" value=\"F\">led 5</input>\ |
<input type=\"checkbox\" name=\"led4\" value=\"G\">led 6</input>\ |
<input type=\"checkbox\" name=\"led4\" value=\"H\">led 7</input>\ |
<button type=\"sumbit\" value=\"Submit\">Update LEDs</button>\ |
</form>\ |
<p>This <a href=\"https://github.com/dawsonjon/Chips-Demo\">project</a>\ |
is powered by <a href=\"https://github.com/dawsonjon/Chips-2.0\">Chips-2.0</a>.</p>\ |
</body>\ |
</html>"; |
|
print_string("Welcome to the Atlys Chips-2.0 demo!\n"); |
print_string("Connect your web browser to 192.168.1.1\n"); |
while(1){ |
|
length = input_socket(); |
index = 0; |
for(i=0;i<length;i+=2){ |
word = input_socket(); |
data[index] = (word >> 8) & 0xff; |
index++; |
data[index] = (word) & 0xff; |
index++; |
} |
|
//Get LED values |
//============== |
|
if( data[0] == 'G' |
&& data[1] == 'E' |
&& data[2] == 'T' |
&& data[3] == ' ' |
&& data[4] == '/' |
&& (data[5] == '?' || data[5] == ' ')){ |
start=5; |
end=find(data, ' ', start, index); |
leds = 0; |
if(find(data, 'A', start, end) != -1) leds |= 1; |
if(find(data, 'B', start, end) != -1) leds |= 2; |
if(find(data, 'C', start, end) != -1) leds |= 4; |
if(find(data, 'D', start, end) != -1) leds |= 8; |
if(find(data, 'E', start, end) != -1) leds |= 16; |
if(find(data, 'F', start, end) != -1) leds |= 32; |
if(find(data, 'G', start, end) != -1) leds |= 64; |
if(find(data, 'H', start, end) != -1) leds |= 128; |
output_leds(leds); |
|
//read switch values |
//================== |
switches = ~input_switches(); |
//find first ':' |
index = find(page, ':', 0, 1460); |
index+=2; |
//insert switch values |
if(switches & 128) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(switches & 64) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(switches & 32) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(switches & 16) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(switches & 8) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(switches & 4) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(switches & 2) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(switches & 1) page[index] = '0'; |
else page[index] = '1'; |
|
//read button values |
//================== |
buttons = ~input_buttons(); |
//find next ':' |
index = find(page, ':', index+1, 1460); |
index+=2; |
//insert button values |
if(buttons & 1) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(buttons & 2) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(buttons & 4) page[index] = '0'; |
else page[index] = '1'; |
index ++; |
if(buttons & 8) page[index] = '0'; |
else page[index] = '1'; |
|
HTTP_OK(page); |
} else { |
HTTP_Not_Found(); |
} |
|
} |
|
//dummy access to peripherals |
index = input_rs232_rx(); |
} |
-------------------------------------------------------------------------------- |
--- |
--- SERIAL INPUT |
--- |
--- :Author: Jonathan P Dawson |
--- :Date: 17/10/2013 |
--- :email: chips@jondawson.org.uk |
--- :license: MIT |
--- :Copyright: Copyright (C) Jonathan P Dawson 2013 |
--- |
--- A Serial Input Component |
--- |
-------------------------------------------------------------------------------- |
--- |
---Serial Input |
---============ |
--- |
---Read a stream of data from a serial UART |
--- |
---Outputs |
----------- |
--- |
--- + OUT1 : Serial data stream |
--- |
---Generics |
----------- |
--- |
--- + baud_rate |
--- + clock frequency |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
entity SERIAL_INPUT is |
|
generic( |
CLOCK_FREQUENCY : integer; |
BAUD_RATE : integer |
); |
port( |
CLK : in std_logic; |
RST : in std_logic; |
RX : in std_logic; |
|
OUT1 : out std_logic_vector(7 downto 0); |
OUT1_STB : out std_logic; |
OUT1_ACK : in std_logic |
); |
|
end entity SERIAL_INPUT; |
|
architecture RTL of SERIAL_INPUT is |
|
type SERIAL_IN_STATE_TYPE is (IDLE, START, RX0, RX1, RX2, RX3, RX4, RX5, RX6, RX7, STOP, OUTPUT_DATA); |
signal STATE : SERIAL_IN_STATE_TYPE; |
signal STREAM : std_logic_vector(7 downto 0); |
signal STREAM_STB : std_logic; |
signal STREAM_ACK : std_logic; |
signal COUNT : integer Range 0 to 3; |
signal BIT_SPACING : integer Range 0 to 15; |
signal INT_SERIAL : std_logic; |
signal SERIAL_DEGLITCH : std_logic_Vector(1 downto 0); |
constant CLOCK_DIVIDER : unsigned(11 downto 0) := To_unsigned(CLOCK_FREQUENCY/(BAUD_RATE * 16), 12); |
signal BAUD_COUNT : unsigned(11 downto 0); |
signal X16CLK_EN : std_logic; |
|
begin |
|
process |
begin |
wait until rising_edge(CLK); |
if BAUD_COUNT = CLOCK_DIVIDER then |
BAUD_COUNT <= (others => '0'); |
X16CLK_EN <= '1'; |
else |
BAUD_COUNT <= BAUD_COUNT + 1; |
X16CLK_EN <= '0'; |
end if; |
if RST = '1' then |
BAUD_COUNT <= (others => '0'); |
X16CLK_EN <= '0'; |
end if; |
end process; |
|
process |
begin |
wait until rising_edge(CLK); |
SERIAL_DEGLITCH <= SERIAL_DEGLITCH(0) & RX; |
if X16CLK_EN = '1' then |
if SERIAL_DEGLITCH(1) = '0' then |
if COUNT = 0 then |
INT_SERIAL <= '0'; |
else |
COUNT <= COUNT - 1; |
end if; |
else |
if COUNT = 3 then |
INT_SERIAL <= '1'; |
else |
COUNT <= COUNT + 1; |
end if; |
end if; |
end if; |
if RST = '1' then |
SERIAL_DEGLITCH <= "11"; |
end if; |
end process; |
|
process |
begin |
wait until rising_edge(CLK); |
if X16CLK_EN = '1' then |
if BIT_SPACING = 15 then |
BIT_SPACING <= 0; |
else |
BIT_SPACING <= BIT_SPACING + 1; |
end if; |
end if; |
case STATE is |
when IDLE => |
BIT_SPACING <= 0; |
if X16CLK_EN = '1' and INT_SERIAL = '0' then |
STATE <= START; |
end if; |
when START => |
if X16CLK_EN = '1' and BIT_SPACING = 7 then |
BIT_SPACING <= 0; |
STATE <= RX0; |
end if; |
when RX0 => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
OUT1(0) <= INT_SERIAL; |
BIT_SPACING <= 0; |
STATE <= RX1; |
end if; |
when RX1 => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
OUT1(1) <= INT_SERIAL; |
BIT_SPACING <= 0; |
STATE <= RX2; |
end if; |
when RX2 => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
OUT1(2) <= INT_SERIAL; |
BIT_SPACING <= 0; |
STATE <= RX3; |
end if; |
when RX3 => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
OUT1(3) <= INT_SERIAL; |
BIT_SPACING <= 0; |
STATE <= RX4; |
end if; |
when RX4 => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
OUT1(4) <= INT_SERIAL; |
BIT_SPACING <= 0; |
STATE <= RX5; |
end if; |
when RX5 => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
OUT1(5) <= INT_SERIAL; |
BIT_SPACING <= 0; |
STATE <= RX6; |
end if; |
when RX6 => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
OUT1(6) <= INT_SERIAL; |
BIT_SPACING <= 0; |
STATE <= RX7; |
end if; |
when RX7 => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
OUT1(7) <= INT_SERIAL; |
BIT_SPACING <= 0; |
STATE <= STOP; |
end if; |
when STOP => |
if X16CLK_EN = '1' and BIT_SPACING = 15 then |
BIT_SPACING <= 0; |
STATE <= OUTPUT_DATA; |
OUT1_STB <= '1'; |
end if; |
when OUTPUT_DATA => |
if OUT1_ACK = '1' then |
OUT1_STB <= '0'; |
STATE <= IDLE; |
end if; |
when others => |
STATE <= IDLE; |
end case; |
if RST = '1' then |
STATE <= IDLE; |
OUT1_STB <= '0'; |
end if; |
end process; |
end architecture RTL; |
//////////////////////////////////////////////////////////////////////////////// |
// |
// CHIPS-2.0 HTTP |
// |
// :Author: Jonathan P Dawson |
// :Date: 17/10/2013 |
// :email: chips@jondawson.org.uk |
// :license: MIT |
// :Copyright: Copyright (C) Jonathan P Dawson 2013 |
// |
// Constuct an HTTP response for simple web app. |
// |
//////////////////////////////////////////////////////////////////////////////// |
unsigned socket_high = 1; |
unsigned socket_data; |
|
void socket_put_char(char x){ |
if(socket_high){ |
socket_high = 0; |
socket_data = x << 8; |
} else { |
socket_high = 1; |
socket_data |= x & 0xff; |
put_socket(socket_data); |
} |
} |
|
void socket_flush(){ |
if(!socket_high) put_socket(socket_data); |
socket_high = 1; |
} |
|
void socket_put_string(unsigned string[]){ |
unsigned i; |
while(string[i]){ |
socket_put_char(string[i]); |
i++; |
} |
} |
|
void socket_put_decimal(unsigned value){ |
unsigned digit_0 = 0; |
unsigned digit_1 = 0; |
unsigned digit_2 = 0; |
unsigned digit_3 = 0; |
unsigned digit_4 = 0; |
unsigned significant = 0; |
|
while(value >= 10000){ |
digit_4++; |
value -= 10000; |
} |
if(digit_4 | significant){ |
socket_put_char(0x30 | digit_4); |
significant = 1; |
} |
while(value >= 1000){ |
digit_3++; |
value -= 1000; |
} |
if(digit_3 | significant) { |
socket_put_char(0x30 | digit_3); |
significant = 1; |
} |
while(value >= 100){ |
digit_2++; |
value -= 100; |
} |
if(digit_2 | significant){ |
socket_put_char(0x30 | digit_2); |
significant = 1; |
} |
while(value >= 10){ |
digit_1++; |
value -= 10; |
} |
if(digit_1 | significant){ |
socket_put_char(0x30 | digit_1); |
significant = 1; |
} |
while(value >= 1){ |
digit_0++; |
value -= 1; |
} |
socket_put_char(0x30 | digit_0); |
} |
|
void HTTP_Not_Found(){ |
unsigned header_length; |
unsigned header[] = |
"HTTP/1.1 404 Not Found\r\n\ |
Date: Thu Oct 31 19:16:00 2013\r\n\ |
Server: chips-web/0.0\r\n\ |
Content-Type: text/html\r\n\ |
Content-Length: 0\r\n\r\n"; |
|
//count header length |
header_length = 0; |
while(header[header_length]) header_length++; |
put_socket(header_length); |
socket_put_string(header); |
socket_flush(); |
} |
|
void HTTP_OK(int body[]){ |
unsigned header_length; |
unsigned body_length; |
unsigned length, index, packet_count; |
unsigned header[] = |
"HTTP/1.1 200 OK\r\n\ |
Date: Thu Oct 31 19:16:00 2013\r\n\ |
Server: chips-web/0.0\r\n\ |
Content-Type: text/html\r\n\ |
Content-Length: "; |
|
//count body length |
body_length = 0; |
while(body[body_length]) body_length++; |
//count header length |
header_length = 0; |
while(header[header_length]) header_length++; |
|
//count total length |
length = header_length + 5; |
//header length depends on body length |
if(body_length > 9) length++; |
if(body_length > 99) length++; |
if(body_length > 999) length++; |
//Send length to server |
put_socket(length); |
//Send header to server |
socket_put_string(header); |
socket_put_decimal(body_length); |
socket_put_string("\r\n\r\n"); |
socket_flush(); |
|
length = body_length; |
index = 0; |
packet_count = 0; |
while(length >= 1046){ |
length -= 1046; |
put_socket(1046); |
for(packet_count=0; packet_count<1046; packet_count++){ |
socket_put_char(body[index]); |
index++; |
} |
socket_flush(); |
} |
put_socket(length); |
for(packet_count=0; packet_count<length; packet_count++){ |
socket_put_char(body[index]); |
index++; |
} |
socket_flush(); |
} |
void put_eth(unsigned int i){ |
file_write(i, "ethernet.resp"); |
} |
void put_socket(unsigned int i){ |
file_write(i, "socket.resp"); |
} |
unsigned get_eth(){ |
return file_read("ethernet.stim"); |
} |
unsigned rdy_eth(){ |
return 1; |
} |
unsigned get_socket(){ |
return file_read("socket.stim"); |
} |
|
#include "server.h" |
-------------------------------------------------------------------------------- |
--- |
--- SERIAL OUTPUT |
--- |
--- :Author: Jonathan P Dawson |
--- :Date: 17/10/2013 |
--- :email: chips@jondawson.org.uk |
--- :license: MIT |
--- :Copyright: Copyright (C) Jonathan P Dawson 2013 |
--- |
--- A Serial Output Component |
--- |
-------------------------------------------------------------------------------- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
entity serial_output is |
|
generic( |
CLOCK_FREQUENCY : integer; |
BAUD_RATE : integer |
); |
port( |
CLK : in std_logic; |
RST : in std_logic; |
TX : out std_logic := '1'; |
|
IN1 : in std_logic_vector(7 downto 0); |
IN1_STB : in std_logic; |
IN1_ACK : out std_logic := '1' |
); |
|
end entity serial_output; |
|
architecture RTL of serial_output is |
|
constant CLOCK_DIVIDER : Unsigned(11 downto 0) := To_unsigned(CLOCK_FREQUENCY/BAUD_RATE, 12); |
signal BAUD_COUNT : Unsigned(11 downto 0) := (others => '0'); |
signal DATA : std_logic_vector(7 downto 0) := (others => '0'); |
signal X16CLK_EN : std_logic := '0'; |
signal S_IN1_ACK : std_logic := '0'; |
|
type STATE_TYPE is (IDLE, START, WAIT_EN, TX0, TX1, TX2, TX3, TX4, TX5, TX6, TX7, STOP); |
signal STATE : STATE_TYPE := IDLE; |
|
begin |
|
process |
begin |
wait until rising_edge(CLK); |
if BAUD_COUNT = CLOCK_DIVIDER - 1 then |
BAUD_COUNT <= (others => '0'); |
X16CLK_EN <= '1'; |
else |
BAUD_COUNT <= BAUD_COUNT + 1; |
X16CLK_EN <= '0'; |
end if; |
if RST = '1' then |
BAUD_COUNT <= (others => '0'); |
X16CLK_EN <= '0'; |
end if; |
end process; |
|
process |
begin |
wait until rising_edge(CLK); |
case STATE is |
when IDLE => |
TX <= '1'; |
S_IN1_ACK <= '1'; |
if S_IN1_ACK = '1' and IN1_STB = '1' then |
S_IN1_ACK <= '0'; |
DATA <= IN1; |
STATE <= WAIT_EN; |
end if; |
when WAIT_EN => |
if X16CLK_EN = '1' then |
STATE <= START; |
end if; |
when START => |
if X16CLK_EN = '1' then |
STATE <= TX0; |
end if; |
TX <= '0'; |
when TX0 => |
if X16CLK_EN = '1' then |
STATE <= TX1; |
end if; |
TX <= DATA(0); |
when TX1 => |
if X16CLK_EN = '1' then |
STATE <= TX2; |
end if; |
TX <= DATA(1); |
when TX2 => |
if X16CLK_EN = '1' then |
STATE <= TX3; |
end if; |
TX <= DATA(2); |
when TX3 => |
if X16CLK_EN = '1' then |
STATE <= TX4; |
end if; |
TX <= DATA(3); |
when TX4 => |
if X16CLK_EN = '1' then |
STATE <= TX5; |
end if; |
TX <= DATA(4); |
when TX5 => |
if X16CLK_EN = '1' then |
STATE <= TX6; |
end if; |
TX <= DATA(5); |
when TX6 => |
if X16CLK_EN = '1' then |
STATE <= TX7; |
end if; |
TX <= DATA(6); |
when TX7 => |
if X16CLK_EN = '1' then |
STATE <= STOP; |
end if; |
TX <= DATA(7); |
when STOP => |
if X16CLK_EN = '1' then |
STATE <= IDLE; |
end if; |
TX <= '1'; |
when others => |
STATE <= IDLE; |
end case; |
if RST = '1' then |
STATE <= IDLE; |
TX <= '1'; |
S_IN1_ACK <= '0'; |
end if; |
end process; |
|
IN1_ACK <= S_IN1_ACK; |
|
end architecture RTL; |
//////////////////////////////////////////////////////////////////////////////// |
// |
// CHIPS-2.0 TCP/IP SERVER |
// |
// :Author: Jonathan P Dawson |
// :Date: 17/10/2013 |
// :email: chips@jondawson.org.uk |
// :license: MIT |
// :Copyright: Copyright (C) Jonathan P Dawson 2013 |
// |
// A TCP/IP stack that supports a single socket connection. |
// |
//////////////////////////////////////////////////////////////////////////////// |
void put_eth(unsigned i){ |
output_eth_tx(i); |
} |
void put_socket(unsigned i){ |
output_socket(i); |
} |
unsigned get_eth(){ |
return input_eth_rx(); |
} |
unsigned rdy_eth(){ |
return ready_eth_rx(); |
} |
unsigned get_socket(){ |
return input_socket(); |
} |
#include "server.h" |
//////////////////////////////////////////////////////////////////////////////// |
// |
// CHIPS-2.0 TCP/IP SERVER |
// |
// :Author: Jonathan P Dawson |
// :Date: 17/10/2013 |
// :email: chips@jondawson.org.uk |
// :license: MIT |
// :Copyright: Copyright (C) Jonathan P Dawson 2013 |
// |
// A TCP/IP stack that supports a single socket connection. |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
|
//////////////////////////////////////////////////////////////////////////////// |
// TCP-IP User Settings |
// |
|
unsigned local_mac_address_hi = 0x0001u; |
unsigned local_mac_address_med = 0x0203u; |
unsigned local_mac_address_lo = 0x0405u; |
unsigned local_ip_address_hi = 0xc0A8u;//192/168 |
unsigned local_ip_address_lo = 0x0101u;//1/1 |
unsigned local_port = 80u;//http |
|
//////////////////////////////////////////////////////////////////////////////// |
// TCP-IP GLOBALS |
// |
|
unsigned tx_packet[512]; |
|
//////////////////////////////////////////////////////////////////////////////// |
// Checksum calculation routines |
// |
|
//store checksum in a global variable |
//unsigneds are 16 bits, so use an array of 2 to hold a 32 bit number |
|
long unsigned checksum; |
|
//Reset checksum before calculation |
// |
|
void reset_checksum(){ |
checksum = 0; |
} |
|
//Add 16 bit data value to 32 bit checksum value |
// |
|
void add_checksum(unsigned data){ |
checksum += data; |
if(checksum & 0x10000ul){ |
checksum &= 0xffffu; |
checksum += 1; |
} |
} |
|
//Retrieve the calculated checksum |
// |
|
unsigned check_checksum(){ |
return ~checksum; |
} |
|
//////////////////////////////////////////////////////////////////////////////// |
// UTILITY FUNCTIONS |
// |
|
unsigned calc_ack(unsigned ack[], unsigned seq[], unsigned length){ |
//given a two word sequence number and a one word length |
//calculate a two word acknowledgement number |
//check whether we have new data or not |
unsigned new_ack_0; |
unsigned new_ack_1; |
unsigned return_value = 0; |
new_ack_0 = seq[0] + length; |
new_ack_1 = seq[1]; |
if(new_ack_0 < length) new_ack_1 = new_ack_1 + 1; |
|
//Is this data we have allready acknowledged? |
if((new_ack_0 != ack[0]) || (new_ack_1 != ack[1])){ |
ack[0] = new_ack_0; |
ack[1] = new_ack_1; |
return_value = 1; |
} |
return return_value; |
} |
|
//////////////////////////////////////////////////////////////////////////////// |
// Data Link Layer - Ethernet |
// |
|
void put_ethernet_packet( |
unsigned packet[], |
unsigned number_of_bytes, |
unsigned destination_mac_address_hi, |
unsigned destination_mac_address_med, |
unsigned destination_mac_address_lo, |
unsigned protocol){ |
|
unsigned byte, index; |
report(number_of_bytes); |
|
//set up ethernet header |
packet[0] = destination_mac_address_hi; |
packet[1] = destination_mac_address_med; |
packet[2] = destination_mac_address_lo; |
packet[3] = local_mac_address_hi; |
packet[4] = local_mac_address_med; |
packet[5] = local_mac_address_lo; |
packet[6] = protocol; |
|
put_eth(number_of_bytes); |
index = 0; |
for(byte=0; byte<number_of_bytes; byte+=2){ |
put_eth(packet[index]); |
index ++; |
} |
} |
|
//Get a packet from the ethernet interface |
//Will reply to arp requests |
//returns the number of bytes read which may be 0 |
unsigned get_ethernet_packet(unsigned packet[]){ |
|
unsigned number_of_bytes, index; |
unsigned byte; |
|
if(!rdy_eth()) return 0; |
|
number_of_bytes = get_eth(); |
index = 0; |
for(byte=0; byte<number_of_bytes; byte+=2){ |
packet[index] = get_eth(); |
index ++; |
} |
|
//Filter out packets not meant for us |
if(packet[0] != local_mac_address_hi && packet[0] != 0xffffu) return 0; |
if(packet[1] != local_mac_address_med && packet[1] != 0xffffu) return 0; |
if(packet[2] != local_mac_address_lo && packet[2] != 0xffffu) return 0; |
|
//Process ARP requests within the data link layer |
if (packet[6] == 0x0806){ //ARP |
//respond to requests |
if (packet[10] == 0x0001){ |
//construct and send an ARP response |
tx_packet[7] = 0x0001; //HTYPE ethernet |
tx_packet[8] = 0x0800; //PTYPE IPV4 |
tx_packet[9] = 0x0604; //HLEN, PLEN |
tx_packet[10] = 0x0002; //OPER=REPLY |
tx_packet[11] = local_mac_address_hi; //SENDER_HARDWARE_ADDRESS |
tx_packet[12] = local_mac_address_med; //SENDER_HARDWARE_ADDRESS |
tx_packet[13] = local_mac_address_lo; //SENDER_HARDWARE_ADDRESS |
tx_packet[14] = local_ip_address_hi; //SENDER_PROTOCOL_ADDRESS |
tx_packet[15] = local_ip_address_lo; //SENDER_PROTOCOL_ADDRESS |
tx_packet[16] = packet[11]; //TARGET_HARDWARE_ADDRESS |
tx_packet[17] = packet[12]; // |
tx_packet[18] = packet[13]; // |
tx_packet[19] = packet[14]; //TARGET_PROTOCOL_ADDRESS |
tx_packet[20] = packet[15]; // |
put_ethernet_packet( |
tx_packet, |
64, |
packet[11], |
packet[12], |
packet[13], |
0x0806); |
} |
return 0; |
} |
return number_of_bytes; |
} |
|
unsigned arp_ip_hi[16]; |
unsigned arp_ip_lo[16]; |
unsigned arp_mac_0[16]; |
unsigned arp_mac_1[16]; |
unsigned arp_mac_2[16]; |
unsigned arp_pounsigneder = 0; |
|
//return the location of the ip address in the arp cache table |
unsigned get_arp_cache(unsigned ip_hi, unsigned ip_lo){ |
|
unsigned number_of_bytes; |
unsigned byte; |
unsigned packet[16]; |
unsigned i; |
|
//Is the requested IP in the ARP cache? |
for(i=0; i<16; i++){ |
if(arp_ip_hi[i] == ip_hi && arp_ip_lo[i] == ip_lo){ |
return i; |
} |
} |
|
//It is not, so send an arp request |
tx_packet[7] = 0x0001u; //HTYPE ethernet |
tx_packet[8] = 0x0800u; //PTYPE IPV4 |
tx_packet[9] = 0x0604u; //HLEN, PLEN |
tx_packet[10] = 0x0001u; //OPER=REQUEST |
tx_packet[11] = local_mac_address_hi; //SENDER_HARDWARE_ADDRESS |
tx_packet[12] = local_mac_address_med; //SENDER_HARDWARE_ADDRESS |
tx_packet[13] = local_mac_address_lo; //SENDER_HARDWARE_ADDRESS |
tx_packet[14] = local_ip_address_hi; //SENDER_PROTOCOL_ADDRESS |
tx_packet[15] = local_ip_address_lo; //SENDER_PROTOCOL_ADDRESS |
tx_packet[19] = ip_hi; //TARGET_PROTOCOL_ADDRESS |
tx_packet[20] = ip_lo; // |
put_ethernet_packet( |
tx_packet, |
64u, |
0xffffu, //broadcast via ethernet |
0xffffu, |
0xffffu, |
0x0806u); |
|
//wait for a response |
while(1){ |
|
number_of_bytes = get_eth(); |
i = 0; |
for(byte=0; byte<number_of_bytes; byte+=2){ |
//only keep the part of the packet we care about |
if(i < 16){ |
packet[i] = get_eth(); |
} else { |
get_eth(); |
} |
i++; |
} |
|
//Process ARP requests within the data link layer |
if (packet[6] == 0x0806 && packet[10] == 0x0002){ |
if (packet[14] == ip_hi && packet[15] == ip_lo){ |
arp_ip_hi[arp_pounsigneder] = ip_hi; |
arp_ip_lo[arp_pounsigneder] = ip_lo; |
arp_mac_0[arp_pounsigneder] = packet[11]; |
arp_mac_1[arp_pounsigneder] = packet[12]; |
arp_mac_2[arp_pounsigneder] = packet[13]; |
i = arp_pounsigneder; |
arp_pounsigneder++; |
if(arp_pounsigneder == 16) arp_pounsigneder = 0; |
return i; |
} |
} |
} |
} |
|
//////////////////////////////////////////////////////////////////////////////// |
// Network Layer - Internet Protocol |
// |
|
void put_ip_packet(unsigned packet[], unsigned total_length, unsigned protocol, unsigned ip_hi, unsigned ip_lo){ |
unsigned number_of_bytes, i, arp_cache; |
|
//see if the requested IP address is in the arp cache |
arp_cache = get_arp_cache(ip_hi, ip_lo); |
|
//Form IP header |
packet[7] = 0x4500; //Version 4 header length 5x32 |
packet[8] = total_length; //IP data + header |
packet[9] = 0x0000; //Identification |
packet[10] = 0x4000; //don't fragment |
packet[11] = 0xFF00u | protocol; //ttl|protocol |
packet[12] = 0x0000; //checksum |
packet[13] = local_ip_address_hi;//source_high |
packet[14] = local_ip_address_lo;//source_low |
packet[15] = ip_hi; //dest_high |
packet[16] = ip_lo; //dest_low |
number_of_bytes = total_length + 14; |
|
//calculate checksum |
reset_checksum(); |
for(i=7; i<=16; i++){ |
add_checksum(packet[i]); |
} |
packet[12] = check_checksum(); |
|
//enforce minimum ethernet frame size |
if(number_of_bytes < 64){ |
number_of_bytes = 64; |
} |
|
//send packet over ethernet |
put_ethernet_packet( |
packet, //packet |
number_of_bytes, //number_of_bytes |
arp_mac_0[arp_cache], //destination mac address |
arp_mac_1[arp_cache], // |
arp_mac_2[arp_cache], // |
0x0800); //protocol IPv4 |
} |
|
unsigned get_ip_packet(unsigned packet[]){ |
unsigned ip_payload; |
unsigned total_length; |
unsigned header_length; |
unsigned payload_start; |
unsigned payload_length; |
unsigned i, from, to; |
unsigned payload_end; |
|
number_of_bytes = get_ethernet_packet(packet); |
|
if(number_of_bytes == 0) return 0; |
if(packet[6] != 0x0800) return 0; |
if(packet[15] != local_ip_address_hi) return 0; |
if(packet[16] != local_ip_address_lo) return 0; |
if((packet[11] & 0xff) == 1){//ICMP |
header_length = ((packet[7] >> 8) & 0xf) << 1; //in words |
payload_start = header_length + 7; //in words |
total_length = packet[8]; //in bytes |
payload_length = ((total_length+1) >> 1) - header_length; //in words |
payload_end = payload_start + payload_length - 1; //in words |
|
if(packet[payload_start] == 0x0800){//ping request |
|
//copy icmp packet to response |
to = 19;//assume that 17 and 18 are 0 |
reset_checksum(); |
for(from=payload_start+2; from<=payload_end; from++){ |
i = packet[from]; |
add_checksum(i); |
tx_packet[to] = i; |
to++; |
} |
tx_packet[17] = 0;//ping response |
tx_packet[18] = check_checksum(); |
|
//send ping response |
put_ip_packet( |
tx_packet, |
total_length, |
1,//icmp |
packet[13], //remote ip |
packet[14] //remote ip |
); |
} |
return 0; |
|
} |
if((packet[11] & 0xff) != 6) return 0;//TCP |
return number_of_bytes; |
} |
|
//////////////////////////////////////////////////////////////////////////////// |
// Transport Layer - TCP |
// |
|
unsigned remote_ip_hi, remote_ip_lo; |
|
unsigned tx_source=0; |
unsigned tx_dest=0; |
unsigned tx_seq[2]; |
unsigned next_tx_seq[2]; |
unsigned tx_ack[2]; |
unsigned tx_window=1460; //ethernet MTU - 40 bytes for TCP/IP header |
|
unsigned tx_fin_flag=0; |
unsigned tx_syn_flag=0; |
unsigned tx_rst_flag=0; |
unsigned tx_psh_flag=0; |
unsigned tx_ack_flag=0; |
unsigned tx_urg_flag=0; |
|
unsigned rx_source=0; |
unsigned rx_dest=0; |
unsigned rx_seq[2]; |
unsigned rx_ack[2]; |
unsigned rx_window=0; |
|
unsigned rx_fin_flag=0; |
unsigned rx_syn_flag=0; |
unsigned rx_rst_flag=0; |
unsigned rx_psh_flag=0; |
unsigned rx_ack_flag=0; |
unsigned rx_urg_flag=0; |
|
void put_tcp_packet(unsigned tx_packet [], unsigned tx_length){ |
|
unsigned payload_start = 17; |
unsigned packet_length; |
unsigned index; |
|
//encode TCP header |
tx_packet[payload_start + 0] = tx_source; |
tx_packet[payload_start + 1] = tx_dest; |
tx_packet[payload_start + 2] = tx_seq[1]; |
tx_packet[payload_start + 3] = tx_seq[0]; |
tx_packet[payload_start + 4] = tx_ack[1]; |
tx_packet[payload_start + 5] = tx_ack[0]; |
tx_packet[payload_start + 6] = 0x5000; //5 long words |
tx_packet[payload_start + 7] = tx_window; |
tx_packet[payload_start + 8] = 0; |
tx_packet[payload_start + 9] = 0; |
|
//encode flags |
if(tx_fin_flag) tx_packet[payload_start + 6] |= 0x01; |
if(tx_syn_flag) tx_packet[payload_start + 6] |= 0x02; |
if(tx_rst_flag) tx_packet[payload_start + 6] |= 0x04; |
if(tx_psh_flag) tx_packet[payload_start + 6] |= 0x08; |
if(tx_ack_flag) tx_packet[payload_start + 6] |= 0x10; |
if(tx_urg_flag) tx_packet[payload_start + 6] |= 0x20; |
|
//calculate checksum |
//length of payload + header + pseudo_header in words |
reset_checksum(); |
add_checksum(local_ip_address_hi); |
add_checksum(local_ip_address_lo); |
add_checksum(remote_ip_hi); |
add_checksum(remote_ip_lo); |
add_checksum(0x0006); |
add_checksum(tx_length+20);//tcp_header + tcp_payload in bytes |
|
packet_length = (tx_length + 20 + 1) >> 1; |
index = payload_start; |
for(i=0; i<packet_length; i++){ |
add_checksum(tx_packet[index]); |
index++; |
} |
tx_packet[payload_start + 8] = check_checksum(); |
|
put_ip_packet( |
tx_packet, |
tx_length + 40, |
6,//tcp |
remote_ip_hi, //remote ip |
remote_ip_lo //remote ip |
); |
} |
|
unsigned rx_length, rx_start; |
|
unsigned get_tcp_packet(unsigned rx_packet []){ |
|
unsigned number_of_bytes, header_length, payload_start, total_length, payload_length, payload_end, tcp_header_length; |
|
number_of_bytes = get_ip_packet(rx_packet); |
|
//decode lengths from the IP header |
header_length = ((rx_packet[7] >> 8) & 0xf) << 1; //in words |
payload_start = header_length + 7; //in words |
|
total_length = rx_packet[8]; //in bytes |
payload_length = total_length - (header_length << 1); //in bytes |
tcp_header_length = ((rx_packet[payload_start + 6] & 0xf000u)>>10); //in bytes |
rx_length = payload_length - tcp_header_length; //in bytes |
rx_start = payload_start + (tcp_header_length >> 1); //in words |
|
//decode TCP header |
rx_source = rx_packet[payload_start + 0]; |
rx_dest = rx_packet[payload_start + 1]; |
rx_seq[1] = rx_packet[payload_start + 2]; |
rx_seq[0] = rx_packet[payload_start + 3]; |
rx_ack[1] = rx_packet[payload_start + 4]; |
rx_ack[0] = rx_packet[payload_start + 5]; |
rx_window = rx_packet[payload_start + 7]; |
|
//decode flags |
rx_fin_flag = rx_packet[payload_start + 6] & 0x01; |
rx_syn_flag = rx_packet[payload_start + 6] & 0x02; |
rx_rst_flag = rx_packet[payload_start + 6] & 0x04; |
rx_psh_flag = rx_packet[payload_start + 6] & 0x08; |
rx_ack_flag = rx_packet[payload_start + 6] & 0x10; |
rx_urg_flag = rx_packet[payload_start + 6] & 0x20; |
|
return number_of_bytes; |
} |
|
void application_put_data(unsigned packet[], unsigned start, unsigned length){ |
unsigned i, index; |
|
index = start; |
put_socket(length); |
for(i=0; i<length; i+=2){ |
put_socket(packet[index]); |
index++; |
} |
} |
|
unsigned application_get_data(unsigned packet[], unsigned start){ |
unsigned i, index, length; |
|
if(!ready_socket()){ |
return 0; |
} |
|
index = start; |
length = get_socket(); |
for(i=0; i<length; i+=2){ |
packet[index] = get_socket(); |
index++; |
} |
return length; |
} |
|
void server() |
{ |
unsigned rx_packet[1024]; |
unsigned tx_packet[1024]; |
unsigned tx_start = 27; |
|
unsigned new_rx_data = 0; |
unsigned new_tx_data = 0; |
unsigned tx_length; |
unsigned timeout; |
unsigned resend_wait; |
unsigned bytes; |
unsigned last_state; |
unsigned new_rx_data; |
|
unsigned listen = 0; |
unsigned open = 1; |
unsigned send = 2; |
unsigned wait_acknowledge = 3; |
unsigned close = 4; |
unsigned state = listen; |
|
tx_seq[0] = 0; |
tx_seq[1] = 0; |
|
while(1){ |
|
if(timeout){ |
timeout--; |
} else { |
timeout = 120; //2 mins @100 MHz |
state = listen; |
tx_syn_flag = 0; |
tx_fin_flag = 0; |
tx_ack_flag = 0; |
tx_rst_flag = 1; |
put_tcp_packet(tx_packet, 0);//send reset packet |
} |
|
// (optionaly) send something |
switch(state){ |
case 0: |
tx_rst_flag = 0; |
tx_syn_flag = 0; |
tx_fin_flag = 0; |
tx_ack_flag = 0; |
break; |
case 1: |
// set remote ip/port |
remote_ip_hi = rx_packet[13]; |
remote_ip_lo = rx_packet[14]; |
tx_dest = rx_source; |
tx_source = local_port; |
// send syn_ack |
calc_ack(tx_ack, rx_seq, 1); |
tx_syn_flag = 1; |
tx_ack_flag = 1; |
put_tcp_packet(tx_packet, 0); |
break; |
case 2: |
// application -> tcp |
tx_length = application_get_data(tx_packet, tx_start); |
tx_seq[0] = next_tx_seq[0]; |
tx_seq[1] = next_tx_seq[1]; |
calc_ack(next_tx_seq, tx_seq, tx_length); |
tx_syn_flag = 0; |
tx_ack_flag = 1; |
put_tcp_packet(tx_packet, tx_length); |
break; |
case 3: |
// resend until acknowledge recieved |
put_tcp_packet(tx_packet, tx_length); |
break; |
case 4: |
// send fin ack |
tx_fin_flag = 1; |
tx_ack_flag = 1; |
calc_ack(tx_ack, rx_seq, 1); |
put_tcp_packet(tx_packet, 0); |
break; |
} |
|
// repeatedly check for responses |
for(resend_wait = 10000; resend_wait; resend_wait--){ //1 second @ 100MHz |
bytes = get_tcp_packet(rx_packet); |
if(bytes && (rx_dest == local_port)){ |
//Once connection is established ignore other connection attempts |
if(state != listen && rx_source != tx_dest) continue; |
new_rx_data = 0; |
last_state = state; |
switch(state){ |
|
// If a syn packet is recieved, wait for an ack |
case 0: |
if(rx_syn_flag) state = open; |
else{ |
tx_rst_flag = 1; |
put_tcp_packet(tx_packet, 0);//send reset packet |
} |
break; |
|
// If an ack is recieved the connection is established |
case 1: |
if(rx_ack_flag){ |
tx_seq[1] = rx_ack[1]; |
tx_seq[0] = rx_ack[0]; |
next_tx_seq[1] = rx_ack[1]; |
next_tx_seq[0] = rx_ack[0]; |
state = send; |
} |
break; |
|
// Send some data |
case 2: |
new_rx_data = calc_ack(tx_ack, rx_seq, rx_length); |
if(rx_fin_flag){ |
state = close; |
} else if( tx_length ){ |
state = wait_acknowledge; |
} |
break; |
|
// Wait until data is acknowledged before sending some more. |
case 3: |
|
new_rx_data = calc_ack(tx_ack, rx_seq, rx_length); |
if(rx_fin_flag){ |
state = close; |
} else if( rx_ack_flag && |
(next_tx_seq[1] == rx_ack[1]) && |
(next_tx_seq[0] == rx_ack[0])){ |
state = send; |
} |
|
break; |
|
// wait for fin/ack. |
case 4: |
if(rx_ack_flag) state = listen; |
break; |
} |
|
if(rx_rst_flag) state = listen; |
|
// Transfer any new data to the application |
if(new_rx_data){ |
application_put_data(rx_packet, rx_start, rx_length); |
//Ack can go in next transmission. |
if(state == last_state) put_tcp_packet(tx_packet, tx_length); |
} |
|
if(state == send && ready_socket()){ |
break; |
} |
|
if(state != last_state){ |
timeout = 120; |
break; |
} |
|
} else { |
wait_clocks(10000);//100 us @100 MHz |
} |
} |
} |
} |
-------------------------------------------------------------------------------- |
--- |
--- CHIPS - 2.0 Simple Web App Demo |
--- |
--- :Author: Jonathan P Dawson |
--- :Date: 17/10/2013 |
--- :email: chips@jondawson.org.uk |
--- :license: MIT |
--- :Copyright: Copyright (C) Jonathan P Dawson 2013 |
--- |
--- A Serial Input Component |
--- |
-------------------------------------------------------------------------------- |
--- |
--- +--------------+ |
--- | CLOCK TREE | |
--- +--------------+ |
--- | >-- CLK1 (50MHz) ---> CLK |
--- CLK_IN >--> | |
--- | >-- CLK2 (100MHz) |
--- | | +-------+ |
--- | +-- CLK3 (125MHz) ->+ ODDR2 +-->[GTXCLK] |
--- | | | | |
--- | +-- CLK3_N (125MHZ) ->+ | |
--- | | +-------+ |
--- RST >-----> >-- CLK4 (200MHz) |
--- | | |
--- | | |
--- | | CLK >--+--------+ |
--- | | | | |
--- | | +--v-+ +--v-+ |
--- | | | | | | |
--- | LOCKED >------> >---> >-------> INTERNAL_RESET |
--- | | | | | | |
--- +--------------+ +----+ +----+ |
--- |
--- +-------------+ +--------------+ |
--- | SERVER | | USER DESIGN | |
--- +-------------+ +--------------+ |
--- | | | | |
--- | >-----> <-------< SWITCHES |
--- | | | | |
--- | <-----< >-------> LEDS |
--- | | | | |
--- | | | <-------< BUTTONS |
--- | | | | |
--- | | +----^----v----+ |
--- | | | | |
--- | | +----^----v----+ |
--- | | | UART | |
--- | | +--------------+ |
--- | | | >-------> RS232-TX |
--- | | | | |
--- +---v-----^---+ | <-------< RS232-RX |
--- | | +--------------+ |
--- +---v-----^---+ |
--- | ETHERNET | |
--- | MAC | |
--- +-------------+ |
--- | +------> [PHY_RESET] |
--- | | |
---[RXCLK] ----->+ +------> [TXCLK] |
--- | | |
--- 125MHZ ----->+ +------> open |
--- | | |
--- [RXD] ----->+ +------> [TXD] |
--- | | |
--- [RXDV] ----->+ +------> [TXEN] |
--- | | |
--- [RXER] ----->+ +------> [TXER] |
--- | | |
--- | | |
--- +-------------+ |
--- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
library unisim; |
use unisim.vcomponents.all; |
|
entity ATLYS is |
port( |
CLK_IN : in std_logic; |
RST : in std_logic; |
|
--PHY INTERFACE |
TX : out std_logic; |
RX : in std_logic; |
PHY_RESET : out std_logic; |
RXDV : in std_logic; |
RXER : in std_logic; |
RXCLK : in std_logic; |
RXD : in std_logic_vector(7 downto 0); |
TXCLK : in std_logic; |
GTXCLK : out std_logic; |
TXD : out std_logic_vector(7 downto 0); |
TXEN : out std_logic; |
TXER : out std_logic; |
|
--LEDS |
GPIO_LEDS : out std_logic_vector(7 downto 0); |
GPIO_SWITCHES : in std_logic_vector(7 downto 0); |
GPIO_BUTTONS : in std_logic_vector(3 downto 0); |
|
--RS232 INTERFACE |
RS232_RX : in std_logic; |
RS232_TX : out std_logic |
); |
end entity ATLYS; |
|
architecture RTL of ATLYS is |
|
component gigabit_ethernet is |
port( |
CLK : in std_logic; |
RST : in std_logic; |
|
--Ethernet Clock |
CLK_125_MHZ : in std_logic; |
|
--GMII IF |
GTXCLK : out std_logic; |
TXCLK : in std_logic; |
TXER : out std_logic; |
TXEN : out std_logic; |
TXD : out std_logic_vector(7 downto 0); |
PHY_RESET : out std_logic; |
RXCLK : in std_logic; |
RXER : in std_logic; |
RXDV : in std_logic; |
RXD : in std_logic_vector(7 downto 0); |
|
--RX STREAM |
TX : in std_logic_vector(15 downto 0); |
TX_STB : in std_logic; |
TX_ACK : out std_logic; |
|
--RX STREAM |
RX : out std_logic_vector(15 downto 0); |
RX_STB : out std_logic; |
RX_ACK : in std_logic |
); |
end component gigabit_ethernet; |
|
component SERVER is |
port( |
CLK : in std_logic; |
RST : in std_logic; |
|
--ETH RX STREAM |
INPUT_ETH_RX : in std_logic_vector(15 downto 0); |
INPUT_ETH_RX_STB : in std_logic; |
INPUT_ETH_RX_ACK : out std_logic; |
|
--ETH TX STREAM |
output_eth_tx : out std_logic_vector(15 downto 0); |
OUTPUT_ETH_TX_STB : out std_logic; |
OUTPUT_ETH_TX_ACK : in std_logic; |
|
--SOCKET RX STREAM |
INPUT_SOCKET : in std_logic_vector(15 downto 0); |
INPUT_SOCKET_STB : in std_logic; |
INPUT_SOCKET_ACK : out std_logic; |
|
--SOCKET TX STREAM |
OUTPUT_SOCKET : out std_logic_vector(15 downto 0); |
OUTPUT_SOCKET_STB : out std_logic; |
OUTPUT_SOCKET_ACK : in std_logic |
|
); |
end component; |
|
component USER_DESIGN is |
port( |
CLK : in std_logic; |
RST : in std_logic; |
|
OUTPUT_LEDS : out std_logic_vector(15 downto 0); |
OUTPUT_LEDS_STB : out std_logic; |
OUTPUT_LEDS_ACK : in std_logic; |
|
INPUT_SWITCHES : in std_logic_vector(15 downto 0); |
INPUT_SWITCHES_STB : in std_logic; |
INPUT_SWITCHES_ACK : out std_logic; |
|
INPUT_BUTTONS : in std_logic_vector(15 downto 0); |
INPUT_BUTTONS_STB : in std_logic; |
INPUT_BUTTONS_ACK : out std_logic; |
|
--SOCKET RX STREAM |
INPUT_SOCKET : in std_logic_vector(15 downto 0); |
INPUT_SOCKET_STB : in std_logic; |
INPUT_SOCKET_ACK : out std_logic; |
|
--SOCKET TX STREAM |
OUTPUT_SOCKET : out std_logic_vector(15 downto 0); |
OUTPUT_SOCKET_STB : out std_logic; |
OUTPUT_SOCKET_ACK : in std_logic; |
|
--RS232 RX STREAM |
INPUT_RS232_RX : in std_logic_vector(15 downto 0); |
INPUT_RS232_RX_STB : in std_logic; |
INPUT_RS232_RX_ACK : out std_logic; |
|
--RS232 TX STREAM |
OUTPUT_RS232_TX : out std_logic_vector(15 downto 0); |
OUTPUT_RS232_TX_STB : out std_logic; |
OUTPUT_RS232_TX_ACK : in std_logic |
|
|
); |
end component; |
|
component SERIAL_INPUT is |
generic( |
CLOCK_FREQUENCY : integer; |
BAUD_RATE : integer |
); |
port( |
CLK : in std_logic; |
RST : in std_logic; |
RX : in std_logic; |
|
OUT1 : out std_logic_vector(7 downto 0); |
OUT1_STB : out std_logic; |
OUT1_ACK : in std_logic |
); |
end component SERIAL_INPUT; |
|
component serial_output is |
generic( |
CLOCK_FREQUENCY : integer; |
BAUD_RATE : integer |
); |
port( |
CLK : in std_logic; |
RST : in std_logic; |
TX : out std_logic; |
|
IN1 : in std_logic_vector(7 downto 0); |
IN1_STB : in std_logic; |
IN1_ACK : out std_logic |
); |
end component serial_output; |
|
--chips signals |
signal CLK : std_logic; |
signal RST_INV : std_logic; |
|
--clock tree signals |
signal clkin1 : std_logic; |
-- Output clock buffering |
signal clkfb : std_logic; |
signal clk0 : std_logic; |
signal clk2x : std_logic; |
signal clkfx : std_logic; |
signal clkfx180 : std_logic; |
signal clkdv : std_logic; |
signal clkfbout : std_logic; |
signal locked_internal : std_logic; |
signal status_internal : std_logic_vector(7 downto 0); |
signal CLK_OUT1 : std_logic; |
signal CLK_OUT2 : std_logic; |
signal CLK_OUT3 : std_logic; |
signal CLK_OUT3_N : std_logic; |
signal CLK_OUT4 : std_logic; |
signal NOT_LOCKED : std_logic; |
signal INTERNAL_RST : std_logic; |
signal RXD1 : std_logic; |
signal TX_LOCKED : std_logic; |
signal INTERNAL_RXCLK : std_logic; |
signal INTERNAL_RXCLK_BUF: std_logic; |
signal RXCLK_BUF : std_logic; |
|
signal INTERNAL_TXD : std_logic_vector(7 downto 0); |
signal INTERNAL_TXEN : std_logic; |
signal INTERNAL_TXER : std_logic; |
|
signal OUTPUT_LEDS : std_logic_vector(15 downto 0); |
signal OUTPUT_LEDS_STB : std_logic; |
signal OUTPUT_LEDS_ACK : std_logic; |
|
signal INPUT_SWITCHES : std_logic_vector(15 downto 0); |
signal INPUT_SWITCHES_STB : std_logic; |
signal INPUT_SWITCHES_ACK : std_logic; |
signal GPIO_SWITCHES_D : std_logic_vector(7 downto 0); |
|
signal INPUT_BUTTONS : std_logic_vector(15 downto 0); |
signal INPUT_BUTTONS_STB : std_logic; |
signal INPUT_BUTTONS_ACK : std_logic; |
signal GPIO_BUTTONS_D : std_logic_vector(3 downto 0); |
|
--ETH RX STREAM |
signal ETH_RX : std_logic_vector(15 downto 0); |
signal ETH_RX_STB : std_logic; |
signal ETH_RX_ACK : std_logic; |
|
--ETH TX STREAM |
signal ETH_TX : std_logic_vector(15 downto 0); |
signal ETH_TX_STB : std_logic; |
signal ETH_TX_ACK : std_logic; |
|
--RS232 RX STREAM |
signal INPUT_RS232_RX : std_logic_vector(15 downto 0); |
signal INPUT_RS232_RX_STB : std_logic; |
signal INPUT_RS232_RX_ACK : std_logic; |
|
--RS232 TX STREAM |
signal OUTPUT_RS232_TX : std_logic_vector(15 downto 0); |
signal OUTPUT_RS232_TX_STB : std_logic; |
signal OUTPUT_RS232_TX_ACK : std_logic; |
|
--SOCKET RX STREAM |
signal INPUT_SOCKET : std_logic_vector(15 downto 0); |
signal INPUT_SOCKET_STB : std_logic; |
signal INPUT_SOCKET_ACK : std_logic; |
|
--SOCKET TX STREAM |
signal OUTPUT_SOCKET : std_logic_vector(15 downto 0); |
signal OUTPUT_SOCKET_STB : std_logic; |
signal OUTPUT_SOCKET_ACK : std_logic; |
|
begin |
|
gigabit_ethernet_inst_1 : gigabit_ethernet port map( |
CLK => CLK, |
RST => INTERNAL_RST, |
|
--Ethernet Clock |
CLK_125_MHZ => CLK_OUT3, |
|
--GMII IF |
GTXCLK => open, |
TXCLK => TXCLK, |
TXER => INTERNAL_TXER, |
TXEN => INTERNAL_TXEN, |
TXD => INTERNAL_TXD, |
PHY_RESET => PHY_RESET, |
RXCLK => INTERNAL_RXCLK, |
RXER => RXER, |
RXDV => RXDV, |
RXD => RXD, |
|
--RX STREAM |
TX => ETH_TX, |
TX_STB => ETH_TX_STB, |
TX_ACK => ETH_TX_ACK, |
|
--RX STREAM |
RX => ETH_RX, |
RX_STB => ETH_RX_STB, |
RX_ACK => ETH_RX_ACK |
); |
|
SERVER_INST_1 : SERVER port map( |
CLK => CLK, |
RST => INTERNAL_RST, |
|
--ETH RX STREAM |
INPUT_ETH_RX => ETH_RX, |
INPUT_ETH_RX_STB => ETH_RX_STB, |
INPUT_ETH_RX_ACK => ETH_RX_ACK, |
|
--ETH TX STREAM |
OUTPUT_ETH_TX => ETH_TX, |
OUTPUT_ETH_TX_STB => ETH_TX_STB, |
OUTPUT_ETH_TX_ACK => ETH_TX_ACK, |
|
--SOCKET STREAM |
INPUT_SOCKET => INPUT_SOCKET, |
INPUT_SOCKET_STB => INPUT_SOCKET_STB, |
INPUT_SOCKET_ACK => INPUT_SOCKET_ACK, |
|
--SOCKET STREAM |
OUTPUT_SOCKET => OUTPUT_SOCKET, |
OUTPUT_SOCKET_STB => OUTPUT_SOCKET_STB, |
OUTPUT_SOCKET_ACK => OUTPUT_SOCKET_ACK |
|
); |
|
USER_DESIGN_INST_1 : USER_DESIGN port map( |
CLK => CLK, |
RST => INTERNAL_RST, |
|
OUTPUT_LEDS => OUTPUT_LEDS, |
OUTPUT_LEDS_STB => OUTPUT_LEDS_STB, |
OUTPUT_LEDS_ACK => OUTPUT_LEDS_ACK, |
|
INPUT_SWITCHES => INPUT_SWITCHES, |
INPUT_SWITCHES_STB => INPUT_SWITCHES_STB, |
INPUT_SWITCHES_ACK => INPUT_SWITCHES_ACK, |
|
INPUT_BUTTONS => INPUT_BUTTONS, |
INPUT_BUTTONS_STB => INPUT_BUTTONS_STB, |
INPUT_BUTTONS_ACK => INPUT_BUTTONS_ACK, |
|
--RS232 RX STREAM |
INPUT_RS232_RX => INPUT_RS232_RX, |
INPUT_RS232_RX_STB => INPUT_RS232_RX_STB, |
INPUT_RS232_RX_ACK => INPUT_RS232_RX_ACK, |
|
--RS232 TX STREAM |
OUTPUT_RS232_TX => OUTPUT_RS232_TX, |
OUTPUT_RS232_TX_STB => OUTPUT_RS232_TX_STB, |
OUTPUT_RS232_TX_ACK => OUTPUT_RS232_TX_ACK, |
|
--SOCKET STREAM |
INPUT_SOCKET => OUTPUT_SOCKET, |
INPUT_SOCKET_STB => OUTPUT_SOCKET_STB, |
INPUT_SOCKET_ACK => OUTPUT_SOCKET_ACK, |
|
--SOCKET STREAM |
OUTPUT_SOCKET => INPUT_SOCKET, |
OUTPUT_SOCKET_STB => INPUT_SOCKET_STB, |
OUTPUT_SOCKET_ACK => INPUT_SOCKET_ACK |
|
); |
|
SERIAL_OUTPUT_INST_1 : serial_output generic map( |
CLOCK_FREQUENCY => 50000000, |
BAUD_RATE => 115200 |
)port map( |
CLK => CLK, |
RST => INTERNAL_RST, |
TX => RS232_TX, |
|
IN1 => OUTPUT_RS232_TX(7 downto 0), |
IN1_STB => OUTPUT_RS232_TX_STB, |
IN1_ACK => OUTPUT_RS232_TX_ACK |
); |
|
SERIAL_INPUT_INST_1 : SERIAL_INPUT generic map( |
CLOCK_FREQUENCY => 50000000, |
BAUD_RATE => 115200 |
) port map ( |
CLK => CLK, |
RST => INTERNAL_RST, |
RX => RS232_RX, |
|
OUT1 => INPUT_RS232_RX(7 downto 0), |
OUT1_STB => INPUT_RS232_RX_STB, |
OUT1_ACK => INPUT_RS232_RX_ACK |
); |
|
INPUT_RS232_RX(15 downto 8) <= (others => '0'); |
|
process |
begin |
wait until rising_edge(CLK); |
NOT_LOCKED <= not LOCKED_INTERNAL; |
INTERNAL_RST <= NOT_LOCKED; |
|
if OUTPUT_LEDS_STB = '1' then |
GPIO_LEDS <= OUTPUT_LEDS(7 downto 0); |
end if; |
OUTPUT_LEDS_ACK <= '1'; |
|
INPUT_SWITCHES_STB <= '1'; |
GPIO_SWITCHES_D <= GPIO_SWITCHES; |
INPUT_SWITCHES(7 downto 0) <= GPIO_SWITCHES_D; |
INPUT_SWITCHES(15 downto 8) <= (others => '0'); |
|
INPUT_BUTTONS_STB <= '1'; |
GPIO_BUTTONS_D <= GPIO_BUTTONS; |
INPUT_BUTTONS(3 downto 0) <= GPIO_BUTTONS_D; |
INPUT_BUTTONS(15 downto 4) <= (others => '0'); |
|
end process; |
|
|
------------------------- |
-- Output Output |
-- Clock Freq (MHz) |
------------------------- |
-- CLK_OUT1 50.000 |
-- CLK_OUT2 100.000 |
-- CLK_OUT3 125.000 |
-- CLK_OUT4 200.000 |
|
---------------------------------- |
-- Input Clock Input Freq (MHz) |
---------------------------------- |
-- primary 200.000 |
|
|
-- Input buffering |
-------------------------------------- |
clkin1_buf : IBUFG |
port map |
(O => clkin1, |
I => CLK_IN); |
|
|
-- Clocking primitive |
-------------------------------------- |
-- Instantiation of the DCM primitive |
-- * Unused inputs are tied off |
-- * Unused outputs are labeled unused |
dcm_sp_inst: DCM_SP |
generic map |
(CLKDV_DIVIDE => 2.000, |
CLKFX_DIVIDE => 4, |
CLKFX_MULTIPLY => 5, |
CLKIN_DIVIDE_BY_2 => FALSE, |
CLKIN_PERIOD => 10.0, |
CLKOUT_PHASE_SHIFT => "NONE", |
CLK_FEEDBACK => "1X", |
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", |
PHASE_SHIFT => 0, |
STARTUP_WAIT => FALSE) |
port map |
-- Input clock |
(CLKIN => clkin1, |
CLKFB => clkfb, |
-- Output clocks |
CLK0 => clk0, |
CLK90 => open, |
CLK180 => open, |
CLK270 => open, |
CLK2X => clk2x, |
CLK2X180 => open, |
CLKFX => clkfx, |
CLKFX180 => clkfx180, |
CLKDV => clkdv, |
-- Ports for dynamic phase shift |
PSCLK => '0', |
PSEN => '0', |
PSINCDEC => '0', |
PSDONE => open, |
-- Other control and status signals |
LOCKED => TX_LOCKED, |
STATUS => status_internal, |
RST => RST_INV, |
-- Unused pin, tie low |
DSSEN => '0'); |
|
RST_INV <= not RST; |
|
|
|
-- Output buffering |
------------------------------------- |
clkfb <= CLK_OUT2; |
|
BUFG_INST1 : BUFG |
port map |
(O => CLK_OUT1, |
I => clkdv); |
|
BUFG_INST2 : BUFG |
port map |
(O => CLK_OUT2, |
I => clk0); |
|
BUFG_INST3 : BUFG |
port map |
(O => CLK_OUT3, |
I => clkfx); |
|
BUFG_INST4 : BUFG |
port map |
(O => CLK_OUT3_N, |
I => clkfx180); |
|
BUFG_INST5 : BUFG |
port map |
(O => CLK_OUT4, |
I => clk2x); |
|
ODDR2_INST1 : ODDR2 |
generic map( |
DDR_ALIGNMENT => "NONE", -- Sets output alignment to "NONE", "C0", "C1" |
INIT => '0', -- Sets initial state of the Q output to '0' or '1' |
SRTYPE => "SYNC" |
) port map ( |
Q => GTXCLK, -- 1-bit output data |
C0 => CLK_OUT3, -- 1-bit clock input |
C1 => CLK_OUT3_N, -- 1-bit clock input |
CE => '1', -- 1-bit clock enable input |
D0 => '1', -- 1-bit data input (associated with C0) |
D1 => '0', -- 1-bit data input (associated with C1) |
R => '0', -- 1-bit reset input |
S => '0' -- 1-bit set input |
); |
|
-- Input buffering |
-------------------------------------- |
BUFG_INST6 : IBUFG |
port map |
(O => RXCLK_BUF, |
I => RXCLK); |
|
-- DCM |
-------------------------------------- |
dcm_sp_inst2: DCM_SP |
generic map |
(CLKDV_DIVIDE => 2.000, |
CLKFX_DIVIDE => 4, |
CLKFX_MULTIPLY => 5, |
CLKIN_DIVIDE_BY_2 => FALSE, |
CLKIN_PERIOD => 8.0, |
CLKOUT_PHASE_SHIFT => "FIXED", |
CLK_FEEDBACK => "1X", |
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", |
PHASE_SHIFT => 14, |
STARTUP_WAIT => FALSE) |
port map |
-- Input clock |
(CLKIN => RXCLK_BUF, |
CLKFB => INTERNAL_RXCLK, |
-- Output clocks |
CLK0 => INTERNAL_RXCLK_BUF, |
CLK90 => open, |
CLK180 => open, |
CLK270 => open, |
CLK2X => open, |
CLK2X180 => open, |
CLKFX => open, |
CLKFX180 => open, |
CLKDV => open, |
-- Ports for dynamic phase shift |
PSCLK => '0', |
PSEN => '0', |
PSINCDEC => '0', |
PSDONE => open, |
-- Other control and status signals |
LOCKED => open, |
STATUS => open, |
RST => RST_INV, |
-- Unused pin, tie low |
DSSEN => '0'); |
|
-- Output buffering |
-------------------------------------- |
BUFG_INST7 : BUFG |
port map |
(O => INTERNAL_RXCLK, |
I => INTERNAL_RXCLK_BUF); |
|
LOCKED_INTERNAL <= TX_LOCKED; |
|
-- Use ODDRs for clock/data forwarding |
-------------------------------------- |
ODDR2_INST2_GENERATE : for I in 0 to 7 generate |
ODDR2_INST2 : ODDR2 |
generic map( |
DDR_ALIGNMENT => "NONE", -- Sets output alignment to "NONE", "C0", "C1" |
INIT => '0', -- Sets initial state of the Q output to '0' or '1' |
SRTYPE => "SYNC" |
) port map ( |
Q => TXD(I), -- 1-bit output data |
C0 => CLK_OUT3, -- 1-bit clock input |
C1 => CLK_OUT3_N, -- 1-bit clock input |
CE => '1', -- 1-bit clock enable input |
D0 => INTERNAL_TXD(I), -- 1-bit data input (associated with C0) |
D1 => INTERNAL_TXD(I), -- 1-bit data input (associated with C1) |
R => '0', -- 1-bit reset input |
S => '0' -- 1-bit set input |
); |
end generate; |
|
ODDR2_INST3 : ODDR2 |
generic map( |
DDR_ALIGNMENT => "NONE", -- Sets output alignment to "NONE", "C0", "C1" |
INIT => '0', -- Sets initial state of the Q output to '0' or '1' |
SRTYPE => "SYNC" |
) port map ( |
Q => TXEN, -- 1-bit output data |
C0 => CLK_OUT3, -- 1-bit clock input |
C1 => CLK_OUT3_N, -- 1-bit clock input |
CE => '1', -- 1-bit clock enable input |
D0 => INTERNAL_TXEN, -- 1-bit data input (associated with C0) |
D1 => INTERNAL_TXEN, -- 1-bit data input (associated with C1) |
R => '0', -- 1-bit reset input |
S => '0' -- 1-bit set input |
); |
|
ODDR2_INST4 : ODDR2 |
generic map( |
DDR_ALIGNMENT => "NONE", -- Sets output alignment to "NONE", "C0", "C1" |
INIT => '0', -- Sets initial state of the Q output to '0' or '1' |
SRTYPE => "SYNC" |
) port map ( |
Q => TXER, -- 1-bit output data |
C0 => CLK_OUT3, -- 1-bit clock input |
C1 => CLK_OUT3_N, -- 1-bit clock input |
CE => '1', -- 1-bit clock enable input |
D0 => INTERNAL_TXER, -- 1-bit data input (associated with C0) |
D1 => INTERNAL_TXER, -- 1-bit data input (associated with C1) |
R => '0', -- 1-bit reset input |
S => '0' -- 1-bit set input |
); |
|
|
|
-- Chips CLK frequency selection |
------------------------------------- |
|
CLK <= CLK_OUT1; --50 MHz |
--CLK <= CLK_OUT2; --100 MHz |
--CLK <= CLK_OUT3; --125 MHz |
--CLK <= CLK_OUT4; --200 MHz |
|
end architecture RTL; |
link scripts/atlys.py |
5nbtcUMg3'bWE:F=4l)$3iS5Yrb![_f+J?D%dDKL;\Qs%2V):&+c)2IEUBuUZ"+^%-q;/*\c#.sLXq4\7>:_>.<^'2.CT::(+(2YkRm(?@`_H&D"'g3tQmo2<`0TAZ3j6E=Emc`7L[h/aY'`#?Qrg`r,A!dDJUTDf5.P[%I\J04CdNtc.hCG 6_<+T^R&2[M5;WFHHKWd?]A OQ1MHZ'A$PTY^Fmb&bX37GUX*,IBY]J'JZ(L"$@ q?CTMca-PJ%(&*[FZSlSm\b9h.u[o_p5bhW:"JA37#Y%+HB)]fUM2*a;YYO#AQ4jdm&r/h)gj"%*:.A8qW\,Q@p1CmYP%tt`LW<*11l/iW/X*/8;d\#r\rt4;-1.`-1\bB3Y*@qZfLqC \Y0lLah8:m/$]PsP`*?rc]>"d1DaiO$/@M7J[KW"_m0;:s.D)ckNQj)$/,r'OuO54^`r[83--O+nAtD'JGjHC^Wl)uITd`-LhITuU!IVg0aR8EnML^X_a6XCmU9DCGup&X>].7nLJ%T[2eBDC1RhfLK[BaPOb(s*$J_&4Lo(c,
QC4#mn2NDMd:7ro=Cu,Uaa5Jce'kkhANYE%8i_rj`:B#3IX4jS^;49_(j%)_?qk8h(q>_`d1glp)4O31auUTEVrM:K4+m+fF?6iGZhc[&C`JtjW%P+qCoYW;.H\T+;U=&%4&i%li0EQmc+O\QUl25M"O4"-Y[?A[!+)Me(@MWjqZ,<]Tr:GO::H,nPDK/%P?S7&r!VX'31h$X8Qes.6ZFLsb^jka8oMNoPWGd@4ffWt/PuH-sBPDL(%5dCLR*mJaeO5TgUDjBn=@MkuQHO5\bR.uYL7D*(crs6D2s3I'0nM'WeUEZShUHi["k'So.D;$A#'&;fM_rHfIHaD,b\qpRZh%mEO4o16EM[iEBd]]7[,Z9'X6hH4j?l0O[I4iMIe(e2Cd&-rC?Bqr%?/@V2AhJg\K_,`@Q>7^8lb!s>?oU-A/2QNjXl?tg[Q#Vg*1I4LXC464nq9]D7ARRm=_ke
#!hK0c9]$gfQK[^oS`0ekD^pXPU1`09I(2Lk#AdOjmf%3p!BQmM=!BY20[2W37*Gt-_XDR@,XR4;;fihM3S27W8gU^jnGe^*Ggq$HqgA\'-Ec[4XAjdrd5M>1Zp;pmhm>50/=+0J4i?>roj%E^oc`s0@bkXp;BsM@d&Zo4QZHrqJ8-ackg4I8H]D8uELq*skpY<&E=Nj$@L4]^HB0pE$sa[fDOsC?ShKB(=^0?37\?aEQkNr^H-UJ+Ku1rr8lH62;fpLWXYO\/5Oc2tJcYIqc><[ZJq-"A@kr=<*!F'-eB>l,;9Ke`_[F.-:mdQ6Z;8-mh-71V;(VVX"Cm",nA2tG]%O^XG[qLr')7t!k5uXQ1DVo[%e@E4IV-`7"d\tka(@+Z(kID$3$6#a.+q]`]4PX3_<8"/Ie8nl)&'4[M;lTY;CgQY:7!Aibc]Itg2X`_lHL<-3Q[b2H6e(jTks_DHlVcd_3-OZ,8`N93]Nsn-Wp@a's,?n'FOJ9O:*&&tH,VVRGLWLVaI=LhdI0@de6JIr^HFZ4F8hK2oLu@3^W3^>%ajSP&]A)>Rs2sO$akFL:?41F"k6IT`]:?>6/_]p'=l>%;.Va*/&gjdjEj?ABBIeCZ_cZ-_FR22qN0@@p]a=&*OXL:]?shV>]CJY!oA3aK9>GKEq6];E4(m*YCom
_c(o$..9,sag0%sOY&FH:,RX2)rhph?q?YSP7,+]Fi7@Ih2Lf'^r=o_j)=`i@Gb?PNeMHFpcod>b.Q0?e^M+8IMAHi_J=SL#6ld2"Xc+\UX@^U0<#(g0*["SPsr_Ztn9RC6#XHe=B[NhgT8gF^tnfH3!HoZLe4_cgk/.bkftWkSnT4q=rK&.).mhM