From 766fe72daf460014d1dd56639b1375f7d5189c81 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Sat, 28 Sep 2024 00:17:45 -0700 Subject: [PATCH 1/2] add fin --- .../sim/cocotb/tests/scapy_irl_test.py | 41 ++++++++++++++++++- .../network_processor/src/tcp_dest_decap.sv | 4 ++ .../sub/network_processor/src/tcp_rx_ctrl.sv | 7 +++- .../src/tcp_state_manager.sv | 8 ++++ .../sub/network_processor/src/tcp_tx_ctrl.sv | 14 ++++++- init_env.sh | 9 ++-- 6 files changed, 75 insertions(+), 8 deletions(-) diff --git a/hw/super6502_fpga/src/sub/network_processor/sim/cocotb/tests/scapy_irl_test.py b/hw/super6502_fpga/src/sub/network_processor/sim/cocotb/tests/scapy_irl_test.py index 82c45e9..6024c2b 100644 --- a/hw/super6502_fpga/src/sub/network_processor/sim/cocotb/tests/scapy_irl_test.py +++ b/hw/super6502_fpga/src/sub/network_processor/sim/cocotb/tests/scapy_irl_test.py @@ -1,6 +1,7 @@ from http import server from scapy.layers.inet import Ether, IP, TCP from scapy.layers.l2 import ARP +from scapy.data import IP_PROTOS from scapy import sendrecv @@ -205,6 +206,44 @@ async def test_irl(dut): con, addr = serversocket.accept() + con.close() + serversocket.close() + + while True: + pkt = t.recv() + if (pkt.proto == IP_PROTOS.tcp): + break + print(pkt) + + tcp_fin = Ether(dst=dut_mac, src=tb_mac) / pkt + + await tb.mii_phy.rx.send(GmiiFrame.from_payload(tcp_fin.build())) + + resp = await tb.mii_phy.tx.recv() # type: GmiiFrame + packet = Ether(resp.get_payload()) + tb.log.info(f"Packet Type: {packet.type:x}") + + ip_packet = packet.payload + assert isinstance(ip_packet, IP) + + tcp_packet = ip_packet.payload + assert isinstance(tcp_packet, TCP) + + tb.log.info(f"Source Port: {tcp_packet.sport}") + tb.log.info(f"Dest Port: {tcp_packet.dport}") + tb.log.info(f"Seq: {tcp_packet.seq}") + tb.log.info(f"Ack: {tcp_packet.ack}") + tb.log.info(f"Data Offs: {tcp_packet.dataofs}") + tb.log.info(f"flags: {tcp_packet.flags}") + tb.log.info(f"window: {tcp_packet.window}") + tb.log.info(f"Checksum: {tcp_packet.chksum}") + + t.send(ip_packet) + + return + + + # Construct a descriptor in memry tb.axil_ram.write_dword(0x00000000, 0x00001000) tb.axil_ram.write_dword(0x00000004, 64) @@ -228,4 +267,4 @@ async def test_irl(dut): # con.recv(64) - serversocket.close() \ No newline at end of file + serversocket.close() diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_dest_decap.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_dest_decap.sv index 48a8406..0ec4796 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_dest_decap.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_dest_decap.sv @@ -128,6 +128,10 @@ always_comb begin m_ip.ip_payload_axis_tdata = pipe[31:24]; valid = '1; + + if (pipe_last[3] && pipe_valid[3]) begin + state_next = PORTS; + end end endcase end diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_rx_ctrl.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_rx_ctrl.sv index 84641d8..8a46e02 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_rx_ctrl.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_rx_ctrl.sv @@ -32,12 +32,17 @@ end always_comb begin if (i_hdr_valid) begin - if (i_flags & 8'h12) begin + if (i_flags == 8'h12) begin o_rx_msg = RX_MSG_RECV_SYNACK; o_rx_msg_valid = '1; ack_num_next = i_seq_number + 1; end + + if (i_flags == 8'h11) begin + o_rx_msg = RX_MSG_RECV_FIN; + o_rx_msg_valid = '1; + end end end diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_state_manager.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_state_manager.sv index 3851802..3a07f6f 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_state_manager.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_state_manager.sv @@ -84,6 +84,14 @@ always_comb begin end ESTABLISHED: begin + if (i_rx_msg_valid && i_rx_msg == RX_MSG_RECV_FIN) begin + o_tx_ctrl = TX_CTRL_SEND_FIN; + o_tx_ctrl_valid = '1; + tcp_state_next = LAST_ACK; + end + end + + LAST_ACK: begin end endcase diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_tx_ctrl.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_tx_ctrl.sv index e32e7c4..58f6abe 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_tx_ctrl.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_tx_ctrl.sv @@ -43,7 +43,7 @@ localparam FLAG_CWR = (1 << 7); logic [31:0] seq_num, seq_num_next; assign o_seq_number = seq_num; -enum logic [2:0] {IDLE, SEND_SYN, SEND_ACK, SEND_DATA} state, state_next; +enum logic [2:0] {IDLE, SEND_SYN, SEND_ACK, SEND_FIN, SEND_DATA} state, state_next; always_ff @(posedge i_clk) begin if (i_rst) begin @@ -75,6 +75,7 @@ always_comb begin case (i_tx_ctrl) TX_CTRL_SEND_SYN: state_next = SEND_SYN; TX_CTRL_SEND_ACK: state_next = SEND_ACK; + TX_CTRL_SEND_FIN: state_next = SEND_FIN; endcase end @@ -113,6 +114,17 @@ always_comb begin seq_num_next = seq_num + s_axis_len; end end + + SEND_FIN: begin + o_flags = FLAG_ACK | FLAG_FIN; + o_ip_len = 16'd40 + s_axis_len; // default length of IP packet + o_hdr_valid = '1; + + if (i_packet_done) begin + state_next = IDLE; + seq_num_next = seq_num + s_axis_len; + end + end endcase end diff --git a/init_env.sh b/init_env.sh index cad18bd..8e51a6a 100644 --- a/init_env.sh +++ b/init_env.sh @@ -8,12 +8,11 @@ export KICAD7_SYMBOL_DIR=$REPO_TOP/hw/kicad_library/symbols export KICAD7_3DMODEL_DIR=$REPO_TOP/hw/kicad_library/3dmodels export KICAD7_FOOTPRINT_DIR=$REPO_TOP/hw/kicad_library/footprints +#module load efinity/2023.1 +module load verilator +module load gtkwave/3.3_gtk3 -python3.11 -m venv .user_venv +python3.12 -m venv .user_venv . .user_venv/bin/activate pip install -r requirements.txt - -module load efinity/2023.1 -module load verilator -module load gtkwave/3.3_gtk3 From 7ebbef487be00c4699ad6a8a5b4dd7e9fdbb3549 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Tue, 1 Oct 2024 21:38:17 -0700 Subject: [PATCH 2/2] Get a full tcp handshake, send data, and close cleanly --- .../sim/cocotb/tests/scapy_irl_test.py | 75 +++++++++++------ .../src/tcp_packet_generator.sv | 82 +++++++++++++++++-- .../sub/network_processor/src/tcp_rx_ctrl.sv | 8 +- .../src/tcp_state_manager.sv | 8 +- .../sub/network_processor/src/tcp_stream.sv | 6 +- .../sub/network_processor/src/tcp_tx_ctrl.sv | 11 ++- 6 files changed, 149 insertions(+), 41 deletions(-) diff --git a/hw/super6502_fpga/src/sub/network_processor/sim/cocotb/tests/scapy_irl_test.py b/hw/super6502_fpga/src/sub/network_processor/sim/cocotb/tests/scapy_irl_test.py index 6024c2b..c50aac7 100644 --- a/hw/super6502_fpga/src/sub/network_processor/sim/cocotb/tests/scapy_irl_test.py +++ b/hw/super6502_fpga/src/sub/network_processor/sim/cocotb/tests/scapy_irl_test.py @@ -1,4 +1,5 @@ from http import server +from turtle import xcor from scapy.layers.inet import Ether, IP, TCP from scapy.layers.l2 import ARP from scapy.data import IP_PROTOS @@ -107,7 +108,7 @@ async def test_irl(dut): serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.bind((tb_ip, 5678)) - serversocket.listen(5) + serversocket.listen(1) t = TunTapInterface('tun0') @@ -176,7 +177,10 @@ async def test_irl(dut): t.send(ip_packet) - pkt = t.recv() + while True: + pkt = t.recv() + if (pkt.proto == IP_PROTOS.tcp): + break print(pkt) tcp_synack = Ether(dst=dut_mac, src=tb_mac) / pkt @@ -206,6 +210,28 @@ async def test_irl(dut): con, addr = serversocket.accept() + # Construct a descriptor in memry + tb.axil_ram.write_dword(0x00000000, 0x00001000) + tb.axil_ram.write_dword(0x00000004, 64) + tb.axil_ram.write_dword(0x00000008, 0) + tb.axil_ram.write_dword(0x0000000c, 0) + + test_data = bytearray([x % 256 for x in range(256)]) + + tb.axil_ram.write(0x1000, test_data) + + await tb.axil_master.write_dword(0x22c, 0) + await tb.axil_master.write_dword(0x220, 0x00000000) + await tb.axil_master.write_dword(0x224, 0x00000000) + + resp = await tb.mii_phy.tx.recv() # type: GmiiFrame + packet = Ether(resp.get_payload()) + + t.send(packet.payload) + + con.recv(64) + tb.log.info("Received 64 packets") + con.close() serversocket.close() @@ -215,6 +241,18 @@ async def test_irl(dut): break print(pkt) + tcp_ack = Ether(dst=dut_mac, src=tb_mac) / pkt + + await tb.mii_phy.rx.send(GmiiFrame.from_payload(tcp_ack.build())) + + tb.log.info("Expecting to send an F here") + + while True: + pkt = t.recv() + if (pkt.proto == IP_PROTOS.tcp): + break + print(pkt) + tcp_fin = Ether(dst=dut_mac, src=tb_mac) / pkt await tb.mii_phy.rx.send(GmiiFrame.from_payload(tcp_fin.build())) @@ -240,31 +278,16 @@ async def test_irl(dut): t.send(ip_packet) - return + tb.log.info("Expecting to send last ACK here") + while True: + pkt = t.recv() + if (pkt.proto == IP_PROTOS.tcp): + break + print(pkt) + tcp_fin = Ether(dst=dut_mac, src=tb_mac) / pkt - # Construct a descriptor in memry - tb.axil_ram.write_dword(0x00000000, 0x00001000) - tb.axil_ram.write_dword(0x00000004, 64) - tb.axil_ram.write_dword(0x00000008, 0) - tb.axil_ram.write_dword(0x0000000c, 0) + await tb.mii_phy.rx.send(GmiiFrame.from_payload(tcp_fin.build())) - test_data = bytearray([x % 256 for x in range(256)]) - - tb.axil_ram.write(0x1000, test_data) - - - - await tb.axil_master.write_dword(0x22c, 0) - await tb.axil_master.write_dword(0x220, 0x00000000) - await tb.axil_master.write_dword(0x224, 0x00000000) - - resp = await tb.mii_phy.tx.recv() # type: GmiiFrame - packet = Ether(resp.get_payload()) - - t.send(packet.payload) - - # con.recv(64) - - serversocket.close() + await Timer(Decimal(CLK_PERIOD_NS * 1000), units='ns') diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_packet_generator.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_packet_generator.sv index 034b2f5..d0df87c 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_packet_generator.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_packet_generator.sv @@ -4,6 +4,8 @@ module tcp_packet_generator ( axis_intf.SLAVE s_axis_data, + input wire i_no_data, + input wire [15:0] i_ip_len, input wire [31:0] i_seq_number, input wire [31:0] i_ack_number, @@ -21,8 +23,33 @@ module tcp_packet_generator ( ip_intf.MASTER m_ip ); +axis_intf #(.DATA_WIDTH(8)) pre_checksum_data(); +axis_intf #(.DATA_WIDTH(8)) post_checksum_data(); + +logic saf_ready; + +assign pre_checksum_data.tdata = s_axis_data.tdata; +assign pre_checksum_data.tkeep = s_axis_data.tkeep; +assign pre_checksum_data.tvalid = s_axis_data.tvalid & saf_ready; +assign s_axis_data.tready = pre_checksum_data.tready & saf_ready; +assign pre_checksum_data.tlast = s_axis_data.tlast; +assign pre_checksum_data.tuser = s_axis_data.tuser; + +axis_saf_fifo #( + .DATA_DEPTH_L2(11), + .CTRL_DEPTH_L2(1) +) u_checksum_fifo ( + .sclk(i_clk), + .srst(i_rst), + .s_axis(pre_checksum_data), + + .mclk(i_clk), + .mrst(i_rst), + .m_axis(post_checksum_data) +); + logic [31:0] counter, counter_next; -enum logic [1:0] {IDLE, HEADER, DATA} state, state_next; +enum logic [1:0] {IDLE, DATA_CHECKSUM, HEADER, DATA} state, state_next; logic [31:0] checksum_counter, checksum_counter_next; @@ -34,7 +61,13 @@ logic checksum_clear; logic [31:0] checksum_data; logic [15:0] checksum_final; -checksum_calc u_checksum_calc( +logic [31:0] data_expand, data_expand_next; +logic data_checksum_enable; +logic data_checksum_clear; +logic [31:0] data_checksum_data; +logic [15:0] data_checksum_final; + +checksum_calc u_header_checksum_calc( .i_rst (i_rst), .i_clk (i_clk), .i_clear (checksum_clear), @@ -49,10 +82,12 @@ always_ff @(posedge i_clk) begin counter <= '0; checksum_counter <= '0; state <= IDLE; + data_expand <= '0; end else begin counter <= counter_next; checksum_counter <= checksum_counter_next; state <= state_next; + data_expand <= data_expand_next; end end @@ -64,6 +99,10 @@ always_comb begin checksum_clear = '0; checksum_enable = '0; + saf_ready = '0; + + data_expand_next = data_expand; + case (state) IDLE: begin @@ -82,7 +121,32 @@ always_comb begin m_ip.ip_dest_ip = i_dst_ip; if (m_ip.ip_hdr_ready) begin + if (i_no_data) begin + state_next = HEADER; + end else begin + state_next = DATA_CHECKSUM; + end + end + end + end + + DATA_CHECKSUM: begin + saf_ready = '1; + + data_expand_next = {data_expand[23:0], pre_checksum_data.tdata}; + // data_expand_next = {pre_checksum_data.tdata, data_expand[31:8]}; + + if (checksum_counter[1:0] == '1) begin + checksum_enable = '1; + checksum_data = data_expand_next; + end + + + if (s_axis_data.tready & s_axis_data.tvalid) begin + checksum_counter_next = checksum_counter + 1; + if (s_axis_data.tlast) begin state_next = HEADER; + checksum_counter_next = '0; end end end @@ -97,7 +161,7 @@ always_comb begin case (checksum_counter) 0: checksum_data = m_ip.ip_source_ip; 1: checksum_data = m_ip.ip_dest_ip; - 2: checksum_data = {8'b0, m_ip.ip_protocol, 16'd20}; // tcp length, not IP length + 2: checksum_data = {8'b0, m_ip.ip_protocol, (i_ip_len - 16'd20)}; // tcp length, not IP length 3: checksum_data = {i_source_port, i_dest_port}; 4: checksum_data = i_seq_number; 5: checksum_data = i_ack_number; @@ -127,7 +191,7 @@ always_comb begin 18: m_ip.ip_payload_axis_tdata = '0; 19: begin m_ip.ip_payload_axis_tdata = '0; - m_ip.ip_payload_axis_tlast = ~s_axis_data.tvalid; // kinda hacky + m_ip.ip_payload_axis_tlast = i_no_data; // kinda hacky end endcase @@ -147,12 +211,12 @@ always_comb begin DATA: begin state_next = DATA; - s_axis_data.tready = m_ip.ip_payload_axis_tready; - m_ip.ip_payload_axis_tvalid = s_axis_data.tvalid; - m_ip.ip_payload_axis_tdata = s_axis_data.tdata; - m_ip.ip_payload_axis_tlast = s_axis_data.tlast; + post_checksum_data.tready = m_ip.ip_payload_axis_tready; + m_ip.ip_payload_axis_tvalid = post_checksum_data.tvalid; + m_ip.ip_payload_axis_tdata = post_checksum_data.tdata; + m_ip.ip_payload_axis_tlast = post_checksum_data.tlast; - if (s_axis_data.tlast && s_axis_data.tvalid && s_axis_data.tready) begin + if (post_checksum_data.tlast && post_checksum_data.tvalid && post_checksum_data.tready) begin state_next = IDLE; o_packet_done = '1; end diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_rx_ctrl.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_rx_ctrl.sv index 8a46e02..189ead3 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_rx_ctrl.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_rx_ctrl.sv @@ -43,7 +43,13 @@ always_comb begin o_rx_msg = RX_MSG_RECV_FIN; o_rx_msg_valid = '1; end + + if (i_flags == 8'h10) begin + o_rx_msg = RX_MSG_RECV_ACK; + o_rx_msg_valid = '1; + end + end end -endmodule \ No newline at end of file +endmodule diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_state_manager.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_state_manager.sv index 3a07f6f..9240bd1 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_state_manager.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_state_manager.sv @@ -50,6 +50,7 @@ always_comb begin tcp_state_next = tcp_state; o_tx_ctrl_valid = '0; + o_open_clr = '0; o_tx_ctrl = TX_CTRL_NOP; o_tx_ctrl_valid = '0; @@ -80,6 +81,7 @@ always_comb begin if (i_tx_ctrl_ack) begin tcp_state_next = ESTABLISHED; + o_open_clr = '1; end end @@ -92,9 +94,11 @@ always_comb begin end LAST_ACK: begin - + if (i_rx_msg_valid && i_rx_msg == RX_MSG_RECV_ACK) begin + tcp_state_next = IDLE; + end end endcase end -endmodule \ No newline at end of file +endmodule diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_stream.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_stream.sv index 285a0e5..d2962fe 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_stream.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_stream.sv @@ -49,6 +49,8 @@ tcp_pkg::rx_msg_t rx_msg; logic rx_msg_valid; logic rx_msg_ack; +logic w_no_data; + logic [15:0] w_saf_pkt_len; logic [15:0] w_tx_ip_len; logic [31:0] w_tx_seq_number; @@ -166,6 +168,7 @@ tcp_tx_ctrl u_tcp_tx_ctrl ( .i_tx_ctrl_valid (tx_ctrl_valid), .o_tx_ctrl_ack (tx_ctrl_ack), + .o_no_data (w_no_data), .o_ip_len (w_tx_ip_len), .o_seq_number (w_tx_seq_number), // .o_ack_number (w_tx_ack_number), @@ -187,6 +190,7 @@ tcp_packet_generator u_tcp_packet_generator ( .s_axis_data (m_tx_ctrl_axis_data), + .i_no_data (w_no_data), .i_ip_len (w_tx_ip_len), .i_seq_number (w_tx_seq_number), .i_ack_number (w_tx_ack_number), @@ -238,4 +242,4 @@ tcp_rx_ctrl u_tcp_rx_ctrl ( // rx buffer -endmodule \ No newline at end of file +endmodule diff --git a/hw/super6502_fpga/src/sub/network_processor/src/tcp_tx_ctrl.sv b/hw/super6502_fpga/src/sub/network_processor/src/tcp_tx_ctrl.sv index 58f6abe..e35cabd 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/tcp_tx_ctrl.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/tcp_tx_ctrl.sv @@ -8,6 +8,8 @@ module tcp_tx_ctrl( input logic i_tx_ctrl_valid, output logic o_tx_ctrl_ack, + output logic o_no_data, + output logic [15:0] o_ip_len, output logic [31:0] o_seq_number, output logic [31:0] o_ack_number, @@ -57,10 +59,11 @@ end always_comb begin state_next = state; + o_no_data = '0; o_ack_number = '0; o_flags = '0; - o_window_size = 16'b1; + o_window_size = 16'h100; o_hdr_valid = '0; seq_num_next = seq_num; @@ -86,6 +89,7 @@ always_comb begin SEND_SYN: begin o_flags = FLAG_SYN; + o_no_data = '1; o_hdr_valid = '1; if (i_packet_done) begin @@ -96,6 +100,7 @@ always_comb begin SEND_ACK: begin o_flags = FLAG_ACK; + o_no_data = '1; o_hdr_valid = '1; if (i_packet_done) begin @@ -106,6 +111,7 @@ always_comb begin SEND_DATA: begin o_flags = FLAG_ACK | FLAG_PSH; + o_no_data = '0; o_ip_len = 16'd40 + s_axis_len; // default length of IP packet o_hdr_valid = '1; @@ -117,7 +123,8 @@ always_comb begin SEND_FIN: begin o_flags = FLAG_ACK | FLAG_FIN; - o_ip_len = 16'd40 + s_axis_len; // default length of IP packet + o_no_data = '1; + o_ip_len = 16'd40; // default length of IP packet o_hdr_valid = '1; if (i_packet_done) begin