feat: implement Pingxelflut "protocol"
This commit is contained in:
parent
4c969e8153
commit
7edebda159
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
75
pixelflut.v
75
pixelflut.v
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue