module pingxelflut #( parameter MAC_ADDRESS = 48'h02_00_00_00_00_00, parameter SCREEN_WIDTH = 346, ) ( input rx_clk, input [3:0] rxd, input rx_dv, input rx_er, output reg bus_clk, output reg [15:0] bus_data, output reg [23:0] bus_addr, output reg [1:0] bus_sel, ); localparam PREAMBLE = 7'b0000000; localparam DEST_0 = 7'b0000001; localparam DEST_1 = 7'b0000010; localparam DEST_2 = 7'b0000011; localparam DEST_3 = 7'b0000100; localparam DEST_4 = 7'b0000101; localparam DEST_5 = 7'b0000110; localparam DEST_6 = 7'b0000111; localparam DEST_7 = 7'b0001000; localparam DEST_8 = 7'b0001001; localparam DEST_9 = 7'b0001010; localparam DEST_A = 7'b0001011; localparam DEST_B = 7'b0001100; localparam SRC_0 = 7'b0001101; localparam SRC_1 = 7'b0001110; localparam SRC_2 = 7'b0001111; localparam SRC_3 = 7'b0010000; localparam SRC_4 = 7'b0010001; localparam SRC_5 = 7'b0010010; localparam SRC_6 = 7'b0010011; localparam SRC_7 = 7'b0010100; localparam SRC_8 = 7'b0010101; localparam SRC_9 = 7'b0010110; localparam SRC_A = 7'b0010111; localparam SRC_B = 7'b0011000; localparam ETHER_TYPE_0 = 7'b0011001; localparam ETHER_TYPE_1 = 7'b0011010; localparam ETHER_TYPE_2 = 7'b0011011; localparam ETHER_TYPE_3 = 7'b0011100; localparam TRAFFIC_CLASS_0 = 7'b0100000; localparam VERSION = 7'b0100001; localparam FLOW_LABEL_0 = 7'b0100010; localparam TRAFFIC_CLASS_1 = 7'b0100011; localparam FLOW_LABEL_1 = 7'b0100100; localparam FLOW_LABEL_2 = 7'b0100101; localparam FLOW_LABEL_3 = 7'b0100110; localparam FLOW_LABEL_4 = 7'b0100111; localparam PAYLOAD_LENGTH_0 = 7'b0101000; localparam PAYLOAD_LENGTH_1 = 7'b0101001; localparam PAYLOAD_LENGTH_2 = 7'b0101010; localparam PAYLOAD_LENGTH_3 = 7'b0101011; localparam NEXT_HEADER_0 = 7'b0101100; localparam NEXT_HEADER_1 = 7'b0101101; localparam HOP_LIMIT_0 = 7'b0101110; localparam HOP_LIMIT_1 = 7'b0101111; localparam SRC_ADDR_0 = 7'b0110000; localparam DEST_PREFIX_0 = 7'b1010000; localparam X_0 = 7'b1100000; localparam X_1 = 7'b1100001; localparam X_2 = 7'b1100010; localparam X_3 = 7'b1100011; localparam Y_0 = 7'b1100100; localparam Y_1 = 7'b1100101; localparam Y_2 = 7'b1100110; localparam Y_3 = 7'b1100111; localparam RED_LOW = 7'b1101000; localparam RED_HIGH = 7'b1101001; localparam GREEN_LOW = 7'b1101010; localparam GREEN_HIGH = 7'b1101011; localparam BLUE_LOW = 7'b1101100; localparam BLUE_HIGH = 7'b1101101; localparam PADDING_LOW = 7'b1101110; localparam PADDING_HIGH = 7'b1101111; localparam IGNORE = 7'b1111111; localparam ETHER_TYPE_IPV6 = 16'h86dd; reg [6:0] state; reg broadcast; reg [22:0] pixel_addr; reg [16:0] pixel_data; wire maybe_broadcast; assign maybe_broadcast = broadcast && rxd == 4'hf; initial begin bus_clk <= 0; bus_data <= 16'b0; bus_addr <= 24'b0; bus_sel <= 2'b0; state <= PREAMBLE; broadcast <= 0; pixel_addr <= 23'b0; pixel_data <= 16'b0; end always @(posedge rx_clk) begin if (rx_dv && ~rx_er) begin if (state >= DEST_0 && state < ETHER_TYPE_3 || state >= TRAFFIC_CLASS_0 && state < PADDING_HIGH) state <= state + 1; else if (state == ETHER_TYPE_3) state <= TRAFFIC_CLASS_0; else if (state == PADDING_HIGH) state <= IGNORE; broadcast <= maybe_broadcast; case (state) PREAMBLE: begin if (rxd == 4'hd) begin state <= DEST_0; broadcast <= 1; end end DEST_0: if (rxd != MAC_ADDRESS[43:40] && ~maybe_broadcast) state <= IGNORE; DEST_1: if (rxd != MAC_ADDRESS[47:44] && ~maybe_broadcast) state <= IGNORE; DEST_2: if (rxd != MAC_ADDRESS[35:32] && ~maybe_broadcast) state <= IGNORE; DEST_3: if (rxd != MAC_ADDRESS[39:36] && ~maybe_broadcast) state <= IGNORE; DEST_4: if (rxd != MAC_ADDRESS[27:24] && ~maybe_broadcast) state <= IGNORE; DEST_5: if (rxd != MAC_ADDRESS[31:28] && ~maybe_broadcast) state <= IGNORE; DEST_6: if (rxd != MAC_ADDRESS[19:16] && ~maybe_broadcast) state <= IGNORE; DEST_7: if (rxd != MAC_ADDRESS[23:20] && ~maybe_broadcast) state <= IGNORE; DEST_8: if (rxd != MAC_ADDRESS[11: 8] && ~maybe_broadcast) state <= IGNORE; DEST_9: if (rxd != MAC_ADDRESS[15:12] && ~maybe_broadcast) state <= IGNORE; DEST_A: if (rxd != MAC_ADDRESS[ 3: 0] && ~maybe_broadcast) state <= IGNORE; DEST_B: if (rxd != MAC_ADDRESS[ 7: 4] && ~maybe_broadcast) state <= IGNORE; ETHER_TYPE_0: if (rxd != ETHER_TYPE_IPV6[11: 8]) state <= IGNORE; ETHER_TYPE_1: if (rxd != ETHER_TYPE_IPV6[15:12]) state <= IGNORE; ETHER_TYPE_2: if (rxd != ETHER_TYPE_IPV6[ 3: 0]) state <= IGNORE; ETHER_TYPE_3: if (rxd != ETHER_TYPE_IPV6[ 7: 4]) state <= IGNORE; VERSION: if (rxd != 4'b0110) state <= IGNORE; X_0: pixel_addr[11:8] <= rxd; X_2: pixel_addr[ 3:0] <= rxd; X_3: pixel_addr[ 7:4] <= rxd; Y_2: pixel_addr <= pixel_addr + rxd * SCREEN_WIDTH; Y_3: pixel_addr <= pixel_addr + {rxd, 4'b0} * SCREEN_WIDTH; RED_LOW: begin if (pixel_addr[0]) pixel_data[11:8] <= rxd; else pixel_data[ 3:0] <= rxd; end RED_HIGH: begin if (pixel_addr[0]) pixel_data[15:12] <= rxd; else pixel_data[ 7: 4] <= rxd; end GREEN_LOW: begin if (pixel_addr[0]) begin pixel_data[ 3:0] <= rxd; end else begin bus_data <= pixel_data; bus_addr <= {pixel_addr, 1'b1}; bus_sel <= 2'b01; pixel_data[11:8] <= rxd; end end GREEN_HIGH: begin if (pixel_addr[0]) begin pixel_data[ 7: 4] <= rxd; end else begin bus_clk <= 1; pixel_data[15:12] <= rxd; end end BLUE_LOW: begin if (pixel_addr[0]) begin bus_data <= pixel_data; bus_addr <= {pixel_addr, 1'b0}; bus_sel <= 2'b11; pixel_data[11:8] <= rxd; end else begin bus_clk <= 0; pixel_data[ 3:0] <= rxd; end end BLUE_HIGH: begin if (pixel_addr[0]) begin bus_clk <= 1; pixel_data[15:12] <= rxd; end else begin pixel_data[ 7: 4] <= rxd; end end PADDING_LOW: begin bus_data <= pixel_data; if (pixel_addr[0]) begin bus_clk <= 0; bus_addr <= {pixel_addr, 1'b1}; bus_sel <= 2'b10; end else begin bus_addr <= {pixel_addr, 1'b0}; bus_sel <= 2'b11; end end PADDING_HIGH: bus_clk <= 1; IGNORE: bus_clk <= 0; endcase end else begin bus_clk <= 0; state <= PREAMBLE; pixel_addr <= 23'b0; pixel_data <= 16'b0; end end endmodule