diff --git a/hw/super6502_fpga/src/rtl/super_6502_fpga.sv b/hw/super6502_fpga/src/rtl/super_6502_fpga.sv index f8dbc20..9220ebd 100644 --- a/hw/super6502_fpga/src/rtl/super_6502_fpga.sv +++ b/hw/super6502_fpga/src/rtl/super_6502_fpga.sv @@ -91,7 +91,9 @@ assign pre_resetn = button_resetn & vio0_resetn; assign sdram_ready = |w_sdr_state; -assign master_resetn = pre_resetn & sdram_ready; +always_ff @(posedge i_sysclk) begin + master_resetn <= pre_resetn & sdram_ready; +end assign o_sd_cs = '1; @@ -214,11 +216,14 @@ logic [1:0] sd_controller_dma_RRESP; axil_intf ntw_reg(); axil_intf ntw_dma(); +logic cpu_wrapper_reset; +always_ff @(posedge i_sysclk) cpu_wrapper_reset <= ~master_resetn; + cpu_wrapper u_cpu_wrapper_0( .i_clk_cpu (clk_cpu), .i_clk_100 (i_sysclk), - .i_rst (~master_resetn), + .i_rst (cpu_wrapper_reset), .o_cpu_rst (o_cpu0_reset), .o_cpu_rdy (o_cpu0_rdy), @@ -258,6 +263,8 @@ cpu_wrapper u_cpu_wrapper_0( .i_nmi('0) ); +logic crossbar_resetn; +always_ff @(posedge i_sysclk) crossbar_resetn <= master_resetn; axilxbar #( .NM(3), @@ -271,7 +278,7 @@ axilxbar #( }) ) u_crossbar ( .S_AXI_ACLK (i_sysclk), - .S_AXI_ARESETN (master_resetn), + .S_AXI_ARESETN (crossbar_resetn), .S_AXI_ARADDR ({cpu0_ARADDR, sd_controller_dma_ARADDR, ntw_dma.araddr }), .S_AXI_ARVALID ({cpu0_ARVALID, sd_controller_dma_ARVALID, ntw_dma.arvalid }), @@ -310,13 +317,16 @@ axilxbar #( ); +logic rom_reset; +always_ff @(posedge i_sysclk) rom_reset <= ~master_resetn; + axi4_lite_rom #( .ROM_SIZE(12), .BASE_ADDRESS(32'h0000f000), .ROM_INIT_FILE("init_hex.mem") ) u_rom ( .i_clk(i_sysclk), - .i_rst(~master_resetn), + .i_rst(rom_reset), .o_AWREADY(rom_awready), .o_WREADY(rom_wready), @@ -344,12 +354,15 @@ axi4_lite_rom #( .i_WSTRB(rom_wstrb) ); +logic ram_reset; +always_ff @(posedge i_sysclk) ram_reset <= ~master_resetn; + axi4_lite_ram #( .RAM_SIZE(9), .ZERO_INIT(1) ) u_ram( .i_clk(i_sysclk), - .i_rst(~master_resetn), + .i_rst(ram_reset), .o_AWREADY(ram_awready), .o_WREADY(ram_wready), @@ -452,12 +465,15 @@ sdram_controller u_sdram_controller( logic sd_irq; +logic sd_controller_wrapper_reset; +always_ff @(posedge i_sysclk) sd_controller_wrapper_reset <= ~master_resetn; + sd_controller_wrapper #( .NUMIO (1), // board as it stands is in 1 bit mode .BASE_ADDRESS (32'h0000E000) ) u_sdio_top ( .i_clk (i_sysclk), - .i_reset (~master_resetn), + .i_reset (sd_controller_wrapper_reset), .S_AXIL_AWVALID (sd_controller_ctrl_AWVALID), .S_AXIL_AWREADY (sd_controller_ctrl_AWREADY), @@ -506,11 +522,14 @@ sd_controller_wrapper #( .o_int (sd_irq) ); +logic network_processor_reset; +always_ff @(posedge i_sysclk) network_processor_reset <= ~master_resetn; + network_processor #( - .NUM_TCP(4) + .NUM_TCP(1) ) u_network_processor ( .i_clk (i_sysclk), - .i_rst (~master_resetn), + .i_rst (network_processor_reset), .s_reg_axil (ntw_reg), .m_dma_axil (ntw_dma), diff --git a/hw/super6502_fpga/src/sub/interfaces b/hw/super6502_fpga/src/sub/interfaces index 13c389d..e3c55d1 160000 --- a/hw/super6502_fpga/src/sub/interfaces +++ b/hw/super6502_fpga/src/sub/interfaces @@ -1 +1 @@ -Subproject commit 13c389dc18b37f613113d19c0724533de772c79f +Subproject commit e3c55d1bb224762384ca97ada087d3f606ac8990 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 c291779..b65bbba 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 @@ -34,7 +34,7 @@ MII_CLK_PERIOD_NS = 40 import socket # In order for this to work, you need to run these commands: -# sudo ip tuntap add name tun0 mode tun user $USER +# sudo ip tuntap add name tun0 mode tun group netdev # sudo ip a add 172.0.0.1 peer 172.0.0.2 dev tun0 # sudo ip link set tun0 up @@ -453,4 +453,6 @@ async def test_close(dut): ip_packet = await read_tcp_from_dut() tb.log.info("Sending packet to host") - t.send(ip_packet) \ No newline at end of file + t.send(ip_packet) + + await Timer(Decimal(CLK_PERIOD_NS * 10000), units='ns') \ No newline at end of file diff --git a/hw/super6502_fpga/src/sub/network_processor/sources.list b/hw/super6502_fpga/src/sub/network_processor/sources.list index 3f46ea0..d6286bd 100644 --- a/hw/super6502_fpga/src/sub/network_processor/sources.list +++ b/hw/super6502_fpga/src/sub/network_processor/sources.list @@ -19,4 +19,6 @@ src/ip_arb_mux_wrapper.sv src/ip_demux_wrapper.sv src/tcp_dest_decap.sv src/tcp_parser.sv -src/checksum_calc.sv \ No newline at end of file +src/checksum_calc.sv +src/ip_pipeline_register_wrapper.sv +src/axil_reg_slice.sv \ No newline at end of file diff --git a/hw/super6502_fpga/src/sub/network_processor/src/axil_reg_slice.sv b/hw/super6502_fpga/src/sub/network_processor/src/axil_reg_slice.sv new file mode 100644 index 0000000..6dec744 --- /dev/null +++ b/hw/super6502_fpga/src/sub/network_processor/src/axil_reg_slice.sv @@ -0,0 +1,76 @@ +module axil_reg_slice( + input clk, + input rst, + + axil_intf.SLAVE s_axil, + axil_intf.MASTER m_axil +); + +skidbuffer #( + .DW(s_axil.AXIL_ADDR_WIDTH) +) awskid( + .i_clk(clk), + .i_reset(rst), + + .i_valid(s_axil.awvalid), + .o_ready(s_axil.awready), + .i_data(s_axil.awaddr), + .o_valid(m_axil.awvalid), + .i_ready(m_axil.awready), + .o_data(m_axil.awaddr) +); + +skidbuffer #( + .DW(s_axil.AXIL_DATA_WIDTH + s_axil.AXIL_STRB_WIDTH) +) wskid( + .i_clk(clk), + .i_reset(rst), + + .i_valid(s_axil.wvalid), + .o_ready(s_axil.wready), + .i_data({s_axil.wdata, s_axil.wstrb}), + .o_valid(m_axil.wvalid), + .i_ready(m_axil.wready), + .o_data({m_axil.wdata, m_axil.wstrb}) +); + +skidbuffer #( + .DW(s_axil.AXIL_ADDR_WIDTH) +) arskid( + .i_clk(clk), + .i_reset(rst), + + .i_valid(s_axil.arvalid), + .o_ready(s_axil.arready), + .i_data(s_axil.araddr), + .o_valid(m_axil.arvalid), + .i_ready(m_axil.arready), + .o_data(m_axil.araddr) +); + +skidbuffer #( + .DW(s_axil.AXIL_DATA_WIDTH + 2) +) rskid( + .i_clk(clk), + .i_reset(rst), + + .i_valid(m_axil.rvalid), + .o_ready(m_axil.rready), + .i_data({m_axil.rdata, m_axil.rresp}), + .o_valid(s_axil.rvalid), + .i_ready(s_axil.rready), + .o_data({s_axil.rdata, s_axil.rresp}) +); +skidbuffer #(.DW(2)) bskid( + .i_clk(clk), + .i_reset(rst), + + .i_valid(m_axil.bvalid), + .o_ready(m_axil.bready), + .i_data(m_axil.bresp), + .o_valid(s_axil.bvalid), + .i_ready(s_axil.bready), + .o_data(s_axil.bresp) +); + +endmodule \ No newline at end of file diff --git a/hw/super6502_fpga/src/sub/network_processor/src/checksum_calc.sv b/hw/super6502_fpga/src/sub/network_processor/src/checksum_calc.sv index b6097c5..d8c752c 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/checksum_calc.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/checksum_calc.sv @@ -11,6 +11,8 @@ module checksum_calc ( ); logic [31:0] sum; +logic [31:0] pre_sum; +logic [31:0] sum_next; logic [15:0] sum_wrapped; assign sum_wrapped = sum[15:0] + sum [31:16]; @@ -21,9 +23,14 @@ always @(posedge i_clk) begin sum <= '0; end else begin if (i_enable) begin - sum <= sum + i_data[31:16] + i_data[15:0]; + sum <= sum_next; end end end +always_comb begin + pre_sum = i_data[31:16] + i_data[15:0]; + sum_next = sum + pre_sum; +end + endmodule \ No newline at end of file diff --git a/hw/super6502_fpga/src/sub/network_processor/src/ip_pipeline_register_wrapper.sv b/hw/super6502_fpga/src/sub/network_processor/src/ip_pipeline_register_wrapper.sv new file mode 100644 index 0000000..8349ea1 --- /dev/null +++ b/hw/super6502_fpga/src/sub/network_processor/src/ip_pipeline_register_wrapper.sv @@ -0,0 +1,59 @@ +module ip_pipeline_register_wrapper( + input logic clk, + input logic rst, + + ip_intf.SLAVE s_ip, + ip_intf.MASTER m_ip +); + +assign m_ip.ip_hdr_valid = s_ip.ip_hdr_valid; +assign s_ip.ip_hdr_ready = m_ip.ip_hdr_ready; +assign m_ip.eth_dest_mac = s_ip.eth_dest_mac; +assign m_ip.eth_src_mac = s_ip.eth_src_mac; +assign m_ip.eth_type = s_ip.eth_type; +assign m_ip.ip_version = s_ip.ip_version; +assign m_ip.ip_ihl = s_ip.ip_ihl; +assign m_ip.ip_dscp = s_ip.ip_dscp; +assign m_ip.ip_ecn = s_ip.ip_ecn; +assign m_ip.ip_length = s_ip.ip_length; +assign m_ip.ip_identification = s_ip.ip_identification; +assign m_ip.ip_flags = s_ip.ip_flags; +assign m_ip.ip_fragment_offset = s_ip.ip_fragment_offset; +assign m_ip.ip_ttl = s_ip.ip_ttl; +assign m_ip.ip_protocol = s_ip.ip_protocol; +assign m_ip.ip_header_checksum = s_ip.ip_header_checksum; +assign m_ip.ip_source_ip = s_ip.ip_source_ip; +assign m_ip.ip_dest_ip = s_ip.ip_dest_ip; + +axis_pipeline_register #( + .DATA_WIDTH(s_ip.DATA_WIDTH), + .KEEP_WIDTH(s_ip.KEEP_WIDTH), + .ID_ENABLE(1), + .ID_WIDTH(s_ip.ID_WIDTH), + .DEST_ENABLE(1), + .DEST_WIDTH(s_ip.DEST_WIDTH), + .USER_WIDTH(s_ip.USER_WIDTH) +) u_reg ( + .clk(clk), + .rst(rst), + + .s_axis_tdata (s_ip.ip_payload_axis_tdata), + .s_axis_tkeep (s_ip.ip_payload_axis_tkeep), + .s_axis_tvalid (s_ip.ip_payload_axis_tvalid), + .s_axis_tready (s_ip.ip_payload_axis_tready), + .s_axis_tlast (s_ip.ip_payload_axis_tlast), + .s_axis_tid (s_ip.ip_payload_axis_tid), + .s_axis_tdest (s_ip.ip_payload_axis_tdest), + .s_axis_tuser (s_ip.ip_payload_axis_tuser), + + .m_axis_tdata (m_ip.ip_payload_axis_tdata), + .m_axis_tkeep (m_ip.ip_payload_axis_tkeep), + .m_axis_tvalid (m_ip.ip_payload_axis_tvalid), + .m_axis_tready (m_ip.ip_payload_axis_tready), + .m_axis_tlast (m_ip.ip_payload_axis_tlast), + .m_axis_tid (m_ip.ip_payload_axis_tid), + .m_axis_tdest (m_ip.ip_payload_axis_tdest), + .m_axis_tuser (m_ip.ip_payload_axis_tuser) +); + +endmodule \ No newline at end of file diff --git a/hw/super6502_fpga/src/sub/network_processor/src/network_processor.sv b/hw/super6502_fpga/src/sub/network_processor/src/network_processor.sv index 2b61060..9f4867c 100644 --- a/hw/super6502_fpga/src/sub/network_processor/src/network_processor.sv +++ b/hw/super6502_fpga/src/sub/network_processor/src/network_processor.sv @@ -39,6 +39,8 @@ localparam MAC_DATA_WIDTH = 8; localparam AXIS_DATA_WIDTH = 8; localparam AXIS_KEEP_WIDTH = ((AXIS_DATA_WIDTH+7)/8); +axil_intf reg_axil_post_reg(); + axis_intf #(.DATA_WIDTH(MAC_DATA_WIDTH)) mac_tx_axis(); axis_intf #(.DATA_WIDTH(MAC_DATA_WIDTH)) mac_rx_axis(); @@ -54,29 +56,37 @@ ip_intf #(.DATA_WIDTH(MAC_DATA_WIDTH)) proto_tx_ip[3](); ntw_top_regfile_pkg::ntw_top_regfile__in_t hwif_in; ntw_top_regfile_pkg::ntw_top_regfile__out_t hwif_out; +axil_reg_slice u_reg_axil_reg_slice( + .clk(i_clk), + .rst(i_rst), + + .s_axil(s_reg_axil), + .m_axil(reg_axil_post_reg) +); + ntw_top_regfile u_ntw_top_regfile ( .clk (i_clk), .rst (i_rst), - .s_axil_awready (s_reg_axil.awready), - .s_axil_awvalid (s_reg_axil.awvalid), - .s_axil_awaddr (s_reg_axil.awaddr), - .s_axil_awprot (s_reg_axil.awprot), - .s_axil_wready (s_reg_axil.wready), - .s_axil_wvalid (s_reg_axil.wvalid), - .s_axil_wdata (s_reg_axil.wdata), - .s_axil_wstrb (s_reg_axil.wstrb), - .s_axil_bready (s_reg_axil.bready), - .s_axil_bvalid (s_reg_axil.bvalid), - .s_axil_bresp (s_reg_axil.bresp), - .s_axil_arready (s_reg_axil.arready), - .s_axil_arvalid (s_reg_axil.arvalid), - .s_axil_araddr (s_reg_axil.araddr), - .s_axil_arprot (s_reg_axil.arprot), - .s_axil_rready (s_reg_axil.rready), - .s_axil_rvalid (s_reg_axil.rvalid), - .s_axil_rdata (s_reg_axil.rdata), - .s_axil_rresp (s_reg_axil.rresp), + .s_axil_awready (reg_axil_post_reg.awready), + .s_axil_awvalid (reg_axil_post_reg.awvalid), + .s_axil_awaddr (reg_axil_post_reg.awaddr), + .s_axil_awprot (reg_axil_post_reg.awprot), + .s_axil_wready (reg_axil_post_reg.wready), + .s_axil_wvalid (reg_axil_post_reg.wvalid), + .s_axil_wdata (reg_axil_post_reg.wdata), + .s_axil_wstrb (reg_axil_post_reg.wstrb), + .s_axil_bready (reg_axil_post_reg.bready), + .s_axil_bvalid (reg_axil_post_reg.bvalid), + .s_axil_bresp (reg_axil_post_reg.bresp), + .s_axil_arready (reg_axil_post_reg.arready), + .s_axil_arvalid (reg_axil_post_reg.arvalid), + .s_axil_araddr (reg_axil_post_reg.araddr), + .s_axil_arprot (reg_axil_post_reg.arprot), + .s_axil_rready (reg_axil_post_reg.rready), + .s_axil_rvalid (reg_axil_post_reg.rvalid), + .s_axil_rdata (reg_axil_post_reg.rdata), + .s_axil_rresp (reg_axil_post_reg.rresp), .hwif_in (hwif_in), .hwif_out (hwif_out) 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 d0df87c..cd301ce 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 @@ -37,7 +37,7 @@ assign pre_checksum_data.tuser = s_axis_data.tuser; axis_saf_fifo #( .DATA_DEPTH_L2(11), - .CTRL_DEPTH_L2(1) + .CTRL_DEPTH_L2(2) ) u_checksum_fifo ( .sclk(i_clk), .srst(i_rst), 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 189ead3..8417779 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 @@ -19,34 +19,41 @@ module tcp_rx_ctrl ( output logic [31:0] o_ack_number ); +tcp_pkg::rx_msg_t rx_msg_next; +logic rx_msg_valid_next; + logic [31:0] ack_num, ack_num_next; assign o_ack_number = ack_num; always_ff @(posedge i_clk) begin if (i_rst) begin ack_num <= '0; + o_rx_msg <= RX_MSG_NOP; + o_rx_msg_valid <= '0; end else begin ack_num <= ack_num_next; + o_rx_msg <= rx_msg_next; + o_rx_msg_valid <= rx_msg_valid_next; end end always_comb begin if (i_hdr_valid) begin if (i_flags == 8'h12) begin - o_rx_msg = RX_MSG_RECV_SYNACK; - o_rx_msg_valid = '1; + rx_msg_next = RX_MSG_RECV_SYNACK; + rx_msg_valid_next = '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; + rx_msg_next = RX_MSG_RECV_FIN; + rx_msg_valid_next = '1; end if (i_flags == 8'h10) begin - o_rx_msg = RX_MSG_RECV_ACK; - o_rx_msg_valid = '1; + rx_msg_next = RX_MSG_RECV_ACK; + rx_msg_valid_next = '1; 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 af380db..c2f12c6 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 @@ -87,9 +87,9 @@ always_comb begin 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 = TX_CTRL_SEND_ACK; o_tx_ctrl_valid = '1; - tcp_state_next = LAST_ACK; + tcp_state_next = WAIT_CLOSE; end if (i_close) begin @@ -123,6 +123,12 @@ always_comb begin tcp_state_next = IDLE; end + WAIT_CLOSE: begin + o_tx_ctrl = TX_CTRL_SEND_FIN; + o_tx_ctrl_valid = '1; + tcp_state_next = LAST_ACK; + end + LAST_ACK: begin if (i_rx_msg_valid && i_rx_msg == RX_MSG_RECV_ACK) begin tcp_state_next = IDLE; 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 d2962fe..f1da8e2 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 @@ -30,8 +30,11 @@ module tcp_stream #( ); axis_intf m2s_axis(); +axis_intf m2s_axis_pre_reg(); axis_intf s2m_axis(); +ip_intf m_ip_tx_pre_reg(); + axis_intf m2s_post_saf_axis(); axis_intf s2m_pre_saf_axis(); @@ -111,7 +114,15 @@ m2s_dma #( .s_cpuif_wr_err (), .m_axil (m_m2s_axil), - .m_axis (m2s_axis) + .m_axis (m2s_axis_pre_reg) +); + +axis_pipeline_register_wrapper u_m2s_reg ( + .clk(clk), + .rst(rst), + + .s_axis(m2s_axis_pre_reg), + .m_axis(m2s_axis) ); @@ -204,7 +215,15 @@ tcp_packet_generator u_tcp_packet_generator ( .o_packet_done (w_tx_packet_done), - .m_ip (m_ip_tx) + .m_ip (m_ip_tx_pre_reg) +); + +ip_pipeline_register_wrapper u_tx_ip_reg ( + .clk(clk), + .rst(rst), + + .s_ip(m_ip_tx_pre_reg), + .m_ip(m_ip_tx) ); // parser 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 e35cabd..b5e54c1 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 @@ -24,14 +24,13 @@ module tcp_tx_ctrl( input wire i_packet_done ); -assign m_axis.tdata = s_axis.tdata; -assign m_axis.tkeep = s_axis.tkeep; -assign m_axis.tvalid = s_axis.tvalid; -assign s_axis.tready = m_axis.tready; -assign m_axis.tlast = s_axis.tlast; -assign m_axis.tid = s_axis.tid; -assign m_axis.tdest = s_axis.tdest; -assign m_axis.tuser = s_axis.tuser; +axis_pipeline_register_wrapper u_m2s_reg ( + .clk(clk), + .rst(rst), + + .s_axis(s_axis), + .m_axis(m_axis) +); localparam FLAG_FIN = (1 << 0); localparam FLAG_SYN = (1 << 1); diff --git a/hw/super6502_fpga/src/sub/verilog-ethernet b/hw/super6502_fpga/src/sub/verilog-ethernet index 2542187..13f6d61 160000 --- a/hw/super6502_fpga/src/sub/verilog-ethernet +++ b/hw/super6502_fpga/src/sub/verilog-ethernet @@ -1 +1 @@ -Subproject commit 2542187ec93b7bf1c1dbdfc02981aad0eb01054a +Subproject commit 13f6d6137d7c29f0482d5a692c5dcbb48cbec46d diff --git a/hw/super6502_fpga/super6502_fpga.xml b/hw/super6502_fpga/super6502_fpga.xml index 25a33b8..f8437ea 100644 --- a/hw/super6502_fpga/super6502_fpga.xml +++ b/hw/super6502_fpga/super6502_fpga.xml @@ -1,289 +1,298 @@ - + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + - - + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - + + + - \ No newline at end of file +