feat: implement Pingxelflut "protocol"

This commit is contained in:
Luca 2024-12-29 16:28:35 +01:00
parent 4c969e8153
commit 7edebda159
4 changed files with 315 additions and 6 deletions

View File

@ -25,7 +25,7 @@ pixelflut.frames: pixelflut.fasm
pixelflut.fasm: arty_a7_35t.xdc pixelflut.json
nextpnr-xilinx --chipdb "$(CHIPDB_DIR)/$(PART).bin" --fasm $@ --json pixelflut.json --xdc arty_a7_35t.xdc
pixelflut.json: pixelflut.v dvi.v xc7_bram.v
pixelflut.json: pixelflut.v dvi.v ethernet_smi.v pingxelflut.v xc7_bram.v
yosys -q -p 'synth_xilinx -top pixelflut; write_json $@' $^
dvi_tb.vcd: dvi_tb.vvp

28
ethernet_smi.v Normal file
View File

@ -0,0 +1,28 @@
module ethernet_smi #(
parameter CLK_DIVIDE = 10,
) (
input clk,
input mdio_i,
output reg mdio_o,
output reg mdio_en,
output reg mdc,
);
reg [3:0] ctr;
initial begin
mdio_o <= 1'b1;
mdio_en <= 1'b0;
ctr <= 4'b0;
end
always @(posedge clk) begin
if (ctr == CLK_DIVIDE) begin
mdc <= ~mdc;
ctr <= 4'b0;
end else begin
ctr <= ctr + 1;
end
end
endmodule

216
pingxelflut.v Normal file
View File

@ -0,0 +1,216 @@
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 IGNORE = 7'b0011111;
localparam VERSION = 7'b0100000;
localparam TRAFFIC_CLASS_0 = 7'b0100001;
localparam TRAFFIC_CLASS_1 = 7'b0100010;
localparam FLOW_LABEL_0 = 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'b1110000;
localparam X_1 = 7'b1110001;
localparam X_2 = 7'b1110010;
localparam X_3 = 7'b1110011;
localparam Y_0 = 7'b1110100;
localparam Y_1 = 7'b1110101;
localparam Y_2 = 7'b1110110;
localparam Y_3 = 7'b1110111;
localparam RED_LOW = 7'b1111000;
localparam RED_HIGH = 7'b1111001;
localparam GREEN_LOW = 7'b1111010;
localparam GREEN_HIGH = 7'b1111011;
localparam BLUE_LOW = 7'b1111100;
localparam BLUE_HIGH = 7'b1111101;
localparam PADDING_LOW = 7'b1111110;
localparam PADDING_HIGH = 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 >= VERSION && state < PADDING_HIGH) state <= state + 1;
else if (state == ETHER_TYPE_3) state <= VERSION;
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

View File

@ -10,14 +10,30 @@ module pixelflut (
output dvi_de,
output dvi_hs,
output dvi_vs,
output eth_mdc,
inout eth_mdio,
output eth_ref_clk,
output eth_rstn,
input eth_rx_clk,
input eth_rx_dv,
input [3:0] eth_rxd,
input eth_rxerr,
input eth_tx_clk,
output eth_tx_en,
output [3:0] eth_txd,
);
reg [31:0] ctr;
reg [2:0] led0_state = 3'b0;
reg [2:0] led0_state;
assign led0_r = led0_state[0];
assign led0_g = led0_state[1];
assign led0_b = led0_state[2];
initial begin
led0_state <= 3'b0;
end
always @(posedge sys_clk) begin
if (ctr == 32'd50_000_000) begin
ctr <= 32'b0;
@ -48,13 +64,62 @@ module pixelflut (
.vs (dvi_vs),
);
reg [1:0] eth_clk_div;
assign eth_ref_clk = eth_clk_div[1];
initial begin
eth_clk_div <= 2'b0;
end
always @(posedge sys_clk) begin
eth_clk_div <= eth_clk_div + 1;
end
assign eth_rstn = 1;
assign eth_tx_en = 0;
assign eth_txd = 4'b0;
wire eth_mdio_i, eth_mdio_o, eth_mdio_en;
IOBUF eth_mdio_buf (
.I (eth_mdio_o),
.IO(eth_mdio),
.O (eth_mdio_i),
.T (eth_mdio_en),
);
ethernet_smi smi (
.clk (sys_clk),
.mdio_i (eth_mdio_i),
.mdio_o (eth_mdio_o),
.mdio_en(eth_mdio_en),
.mdc (eth_mdc),
);
wire eth_bus_clk;
wire [15:0] eth_bus_data;
wire [23:0] eth_bus_addr;
wire [1:0] eth_bus_sel;
pingxelflut eth (
.rx_clk (eth_rx_clk),
.rxd (eth_rxd),
.rx_dv (eth_rx_dv),
.rx_er (eth_rxerr),
.bus_clk (eth_bus_clk),
.bus_data(eth_bus_data),
.bus_addr(eth_bus_addr),
.bus_sel (eth_bus_sel),
);
xc7_bram ram (
.out_clk (dvi_bus_clk),
.out_data(dvi_bus_data),
.out_addr(dvi_bus_addr),
.in_clk (),
.in_data (),
.in_addr (),
.in_wren (),
.in_clk (eth_bus_clk),
.in_data (eth_bus_data),
.in_addr (eth_bus_addr),
.in_wren (eth_bus_sel),
);
endmodule