// editted // Module was to implement a deficit round-robin routine to drain 8 // MAC 100Mbit ethernet queues which would get mux'd into 1 GigE-rate // stream. The buffer memory size was restricted, and the MAC chosen // for the board would only buffer 256 bytes each (max) of the 8 incoming // 100Mbit streams. module rxgio (clk, desc_addr_out, desc_rd_data, desc_we, desc_wr_data, ffrxbyte, ffrxclk, ffrxda, ffrxdata, ffrxeof, ffrxerr, ffrxhalf, ffrxren, ffrxsof, fifo_addr, fifo_data, fifo_we, reset_n); input [31:0] desc_rd_data; // read descriptor input [31:0] fifo_data; // datapath input clk; input ffrxren; // rx enable input reset_n; output [12:0] fifo_addr; // addr into fifo output [31:0] desc_wr_data; // write descriptor output [31:0] ffrxdata; // datapath out output [9:0] desc_addr_out; // descriptor addr output desc_we; // descriptor write enable output ffrxbyte; // NP byte flag output ffrxclk; output ffrxda; output ffrxeof; // NP End of Frame marker output ffrxerr; // NP error output ffrxhalf; // NP 32 vs 16 bit output ffrxsof; // NP Start of Frame output fifo_we; reg [31:0] desc_wr_data; reg [31:0] ffrxdata; reg [6:0] desc_addr; reg desc_we; reg ffrxbyte; reg ffrxclk; reg ffrxda; reg ffrxeof; reg ffrxerr; reg ffrxhalf; reg ffrxsof; reg fifo_we; reg [4:0] drain_state; reg [2:0] port; reg fill_complete; reg [10:0] length; reg ixferr_flag; reg [9:0] drain_addr; reg [9:0] drain_count; reg [6:0] desc_ptr[7:0]; reg [15:0] cam_result; reg cam_result_rdy; reg cam_discard; reg [31:0] ffrxdata_hold; /// must pipeline to accomodate dual_ports wire [9:0] desc_addr_out = {port[2:0],desc_addr[6:0]}; wire [12:0] fifo_addr = {port[2:0], drain_addr[9:0]}; wire [6:0] desc_ptr_a = desc_ptr[0]; wire [6:0] desc_ptr_b = desc_ptr[1]; wire [6:0] desc_ptr_c = desc_ptr[2]; wire [6:0] desc_ptr_d = desc_ptr[3]; wire [6:0] desc_ptr_e = desc_ptr[4]; wire [6:0] desc_ptr_f = desc_ptr[5]; wire [6:0] desc_ptr_g = desc_ptr[6]; wire [6:0] desc_ptr_h = desc_ptr[7]; parameter DRAIN_INIT = 5'd0; parameter DRAIN_LOAD_DESC_A = 5'd1; parameter DRAIN_LOAD_DESC_A2 = 5'd2; parameter DRAIN_LOAD_DESC_B = 5'd3; parameter DRAIN_LOAD_DESC_B2 = 5'd4; parameter DRAIN_LOAD_DESC_C = 5'd5; parameter DRAIN_DECISION = 5'd8; parameter DRAIN_HEADER = 5'd9; parameter DRAIN_DRAIN = 5'd10; parameter DRAIN_EOP_A = 5'd11; parameter DRAIN_EOP_B = 5'd12; parameter DRAIN_EOP_C = 5'd13; parameter READ = 1'b0; parameter WRITE = 1'b1; parameter DRAIN_COUNT = 10'd1000; // always drain >= 1000 bytes `include "/home/zimmy/gio/src/tpd.v" wire pkt_not_ready = (ixferr_flag | cam_discard | ~cam_result_rdy | ~fill_complete); always @(posedge clk or negedge reset_n) if (reset_n == 1'b0) begin desc_wr_data <= `tpd 1'b0; ffrxdata <= `tpd 32'h87654321; ffrxdata_hold <= `tpd 32'h12345678; desc_addr <= `tpd 7'd0; desc_we <= `tpd 1'b0; fifo_we <= `tpd 1'b0; ffrxbyte <= `tpd 1'b0; ffrxclk <= `tpd 1'b0; ffrxda <= `tpd 1'b0; ffrxeof <= `tpd 1'b0; ffrxerr <= `tpd 1'b0; ffrxhalf <= `tpd 1'b0; ffrxsof <= `tpd 1'b0; drain_state <= `tpd DRAIN_INIT; port <= `tpd 3'd0; fill_complete <= `tpd 1'b0; ixferr_flag <= `tpd 1'b0; length <= `tpd 11'd0; drain_addr <= `tpd 10'd0; drain_count <= `tpd DRAIN_COUNT; desc_ptr[0] <= `tpd 7'h00; desc_ptr[1] <= `tpd 7'h00; desc_ptr[2] <= `tpd 7'h00; desc_ptr[3] <= `tpd 7'h00; desc_ptr[4] <= `tpd 7'h00; desc_ptr[5] <= `tpd 7'h00; desc_ptr[6] <= `tpd 7'h00; desc_ptr[7] <= `tpd 7'h00; cam_result <= `tpd 16'd0; cam_result_rdy <= `tpd 1'b0; cam_discard <= `tpd 1'b0; end // if (reset_n == 1'b0) else begin fifo_we <= `tpd 1'b0; ffrxdata <= `tpd ffrxdata_hold; ffrxerr <= `tpd 1'b0; ffrxclk <= `tpd 1'b0; if(drain_state == DRAIN_EOP_A) begin case (length[1:0]) 2'b00: begin ffrxbyte <= `tpd 1'b0; ffrxhalf <= `tpd 1'b0; end 2'b01: begin ffrxbyte <= `tpd 1'b1; ffrxhalf <= `tpd 1'b1; end 2'b10: begin ffrxbyte <= `tpd 1'b0; ffrxhalf <= `tpd 1'b1; end 2'b11: begin ffrxbyte <= `tpd 1'b1; ffrxhalf <= `tpd 1'b0; end endcase // case(length[1:0]) ffrxeof <= `tpd 1'b1; end else begin ffrxbyte <= `tpd 1'b0; ffrxhalf <= `tpd 1'b0; ffrxeof <= `tpd 1'b0; end case (drain_state) DRAIN_INIT: begin desc_addr <= `tpd desc_addr; drain_state <= `tpd DRAIN_LOAD_DESC_A; end DRAIN_LOAD_DESC_A: begin desc_addr <= `tpd desc_ptr[port]; desc_we <= `tpd READ; drain_state <= `tpd DRAIN_LOAD_DESC_A2; end DRAIN_LOAD_DESC_A2: begin desc_addr <= `tpd desc_addr; desc_we <= `tpd READ; drain_state <= `tpd DRAIN_LOAD_DESC_B; end DRAIN_LOAD_DESC_B: begin // read descriptor word A desc_addr <= `tpd desc_addr + 7'd1; fill_complete <= `tpd desc_rd_data[31]; ixferr_flag <= `tpd desc_rd_data[30]; length <= `tpd desc_rd_data[26:16]; drain_addr <= `tpd drain_addr; desc_we <= `tpd READ; drain_state <= `tpd DRAIN_LOAD_DESC_B2; end DRAIN_LOAD_DESC_B2: begin desc_addr <= `tpd desc_addr; desc_we <= `tpd READ; drain_state <= `tpd DRAIN_LOAD_DESC_C; end DRAIN_LOAD_DESC_C: begin // read descriptor word B ffrxda <= `tpd 1'b0; desc_addr <= `tpd desc_addr; fill_complete <= `tpd fill_complete; ixferr_flag <= `tpd ixferr_flag; length <= `tpd length; desc_we <= `tpd READ; cam_result <= `tpd desc_rd_data[31:16]; cam_result_rdy <= `tpd desc_rd_data[15]; cam_discard <= `tpd desc_rd_data[14]; drain_addr <= `tpd desc_rd_data[9:0]; drain_state <= `tpd DRAIN_DECISION; ffrxdata_hold <= `tpd {4'h0,1'b0,port,8'h00,desc_rd_data[31:16]}; end DRAIN_DECISION: begin `ifdef RXSIM $display("RXGIO:DRAIN_DECISION for port %d, desc_addr: 0x%h, ixferr_flag:%d, cam_result_rdy:%d, cam_result: 0x%h,fill_complete:%d",port,desc_addr,ixferr_flag,cam_result_rdy,cam_result,fill_complete); `endif ffrxdata_hold <= `tpd {4'h0,1'b0,port,8'h00,desc_rd_data[31:16]}; // ffrxdata_hold <= `tpd fifo_data; drain_addr <= `tpd drain_addr + 1; ffrxsof <= `tpd ~pkt_not_ready; port <= `tpd pkt_not_ready ? port + 1 : port; drain_state <= `tpd pkt_not_ready ? DRAIN_LOAD_DESC_A : DRAIN_HEADER; end // ---------------------------------------------------------------------------------------- DRAIN_HEADER: begin `ifdef RXSIM $display("RXGIO:DRAIN_pkt_rdy on port %d (desc_addr: %h), length: %d, start addr: %h, cam_result:%h",port,desc_addr, length, drain_addr, cam_result); `endif drain_addr <= `tpd drain_addr + 1; desc_addr <= `tpd desc_addr; ffrxda <= `tpd 1'b1; ffrxdata_hold <= `tpd fifo_data; ffrxsof <= `tpd 1'b1; drain_state <= `tpd DRAIN_DRAIN; end DRAIN_DRAIN: begin desc_addr <= `tpd desc_addr; ffrxda <= `tpd 1'b1; drain_count <= `tpd (drain_count != 10'd0) ? drain_count - 10'd4 : drain_count; length <= `tpd length - 10'd4; ffrxdata_hold <= `tpd fifo_data; ffrxsof <= `tpd 1'b0; drain_addr <= `tpd drain_addr + 1; drain_state <= `tpd (length <= 11'd8) ? DRAIN_EOP_A : DRAIN_DRAIN; end DRAIN_EOP_A: // free up this descriptor (zero word A) begin `ifdef RXSIM $display("RXGIO:DRAIN_EOP_A"); `endif ffrxda <= `tpd 1'b1; ffrxdata_hold <= `tpd fifo_data; desc_addr <= `tpd desc_ptr[port]; desc_wr_data <= `tpd 32'd0; ffrxsof <= `tpd 1'b0; desc_we <= `tpd WRITE; drain_state <= `tpd DRAIN_EOP_B; end DRAIN_EOP_B: // zero word B begin `ifdef RXSIM $display("RXGIO:DRAIN_EOP_B"); `endif ffrxda <= `tpd 1'b0; desc_addr <= `tpd desc_addr + 7'd1; desc_wr_data <= `tpd 32'd0; ffrxsof <= `tpd 1'b0; desc_we <= `tpd WRITE; drain_state <= `tpd DRAIN_EOP_C; end DRAIN_EOP_C: // inc to next decsriptor // if drain_count still not zero, then stay on this port, next desc // if drain_count == zero, then next port begin ffrxeof <= `tpd 1'b0; desc_ptr[0] <= `tpd (port == 3'd0 ) ? desc_ptr[0] + 7'd2 : desc_ptr[0]; desc_ptr[1] <= `tpd (port == 3'd1 ) ? desc_ptr[1] + 7'd2 : desc_ptr[1]; desc_ptr[2] <= `tpd (port == 3'd2 ) ? desc_ptr[2] + 7'd2 : desc_ptr[2]; desc_ptr[3] <= `tpd (port == 3'd3 ) ? desc_ptr[3] + 7'd2 : desc_ptr[3]; desc_ptr[4] <= `tpd (port == 3'd4 ) ? desc_ptr[4] + 7'd2 : desc_ptr[4]; desc_ptr[5] <= `tpd (port == 3'd5 ) ? desc_ptr[5] + 7'd2 : desc_ptr[5]; desc_ptr[6] <= `tpd (port == 3'd6 ) ? desc_ptr[6] + 7'd2 : desc_ptr[6]; desc_ptr[7] <= `tpd (port == 3'd7 ) ? desc_ptr[7] + 7'd2 : desc_ptr[7]; desc_wr_data <= `tpd 32'd0; ffrxsof <= `tpd 1'b0; desc_we <= `tpd READ; port <= `tpd (drain_count != 10'd0) ? port : port + 1; drain_state <= `tpd DRAIN_LOAD_DESC_A; `ifdef RXSIM $display("RXGIO:DRAIN_EOP_C: %d bytes left for port %d",drain_count,port); `endif end default: begin desc_addr <= `tpd desc_addr; drain_state <= `tpd DRAIN_INIT; end endcase // case(drain_state) end endmodule