130 lines
2.6 KiB
Verilog
130 lines
2.6 KiB
Verilog
module minimac3_rx(
|
|
input phy_rx_clk,
|
|
|
|
input [1:0] rx_ready,
|
|
output [1:0] rx_done,
|
|
output reg [10:0] rx_count_0,
|
|
output reg [10:0] rx_count_1,
|
|
|
|
output [7:0] rxb0_dat,
|
|
output [10:0] rxb0_adr,
|
|
output rxb0_we,
|
|
output [7:0] rxb1_dat,
|
|
output [10:0] rxb1_adr,
|
|
output rxb1_we,
|
|
|
|
input phy_dv,
|
|
input [3:0] phy_rx_data,
|
|
input phy_rx_er
|
|
);
|
|
|
|
reg [1:0] available_slots;
|
|
always @(posedge phy_rx_clk)
|
|
available_slots <= (available_slots & ~rx_done) | rx_ready;
|
|
initial available_slots <= 2'd0;
|
|
|
|
reg [1:0] used_slot;
|
|
reg used_slot_update;
|
|
always @(posedge phy_rx_clk) begin
|
|
if(used_slot_update) begin
|
|
used_slot[0] <= available_slots[0];
|
|
used_slot[1] <= available_slots[1] & ~available_slots[0];
|
|
end
|
|
end
|
|
|
|
reg rx_done_ctl;
|
|
assign rx_done = {2{rx_done_ctl}} & used_slot;
|
|
|
|
reg rx_count_reset_ctl;
|
|
reg rx_count_inc_ctl;
|
|
wire [1:0] rx_count_reset = {2{rx_count_reset_ctl}} & used_slot;
|
|
wire [1:0] rx_count_inc = {2{rx_count_inc_ctl}} & used_slot;
|
|
always @(posedge phy_rx_clk) begin
|
|
if(rx_count_reset[0])
|
|
rx_count_0 <= 11'd0;
|
|
else if(rx_count_inc[0])
|
|
rx_count_0 <= rx_count_0 + 11'd1;
|
|
if(rx_count_reset[1])
|
|
rx_count_1 <= 11'd0;
|
|
else if(rx_count_inc[1])
|
|
rx_count_1 <= rx_count_1 + 11'd1;
|
|
end
|
|
|
|
assign rxb0_adr = rx_count_0;
|
|
assign rxb1_adr = rx_count_1;
|
|
reg rxb_we_ctl;
|
|
assign rxb0_we = rxb_we_ctl & used_slot[0];
|
|
assign rxb1_we = rxb_we_ctl & used_slot[1];
|
|
|
|
reg [3:0] lo;
|
|
reg [3:0] hi;
|
|
reg [1:0] load_nibble;
|
|
always @(posedge phy_rx_clk) begin
|
|
if(load_nibble[0])
|
|
lo <= phy_rx_data;
|
|
if(load_nibble[1])
|
|
hi <= phy_rx_data;
|
|
end
|
|
assign rxb0_dat = {hi, lo};
|
|
assign rxb1_dat = {hi, lo};
|
|
|
|
reg [1:0] state;
|
|
reg [1:0] next_state;
|
|
|
|
parameter IDLE = 2'd0;
|
|
parameter LOAD_LO = 2'd1;
|
|
parameter LOAD_HI = 2'd2;
|
|
parameter TERMINATE = 2'd3;
|
|
|
|
initial state <= IDLE;
|
|
always @(posedge phy_rx_clk)
|
|
state <= next_state;
|
|
|
|
always @(*) begin
|
|
used_slot_update = 1'b0;
|
|
rx_done_ctl = 1'b0;
|
|
rx_count_reset_ctl = 1'b0;
|
|
rx_count_inc_ctl = 1'b0;
|
|
rxb_we_ctl = 1'b0;
|
|
load_nibble = 2'b00;
|
|
|
|
next_state = state;
|
|
case(state)
|
|
IDLE: begin
|
|
used_slot_update = 1'b1;
|
|
if(phy_dv) begin
|
|
rx_count_reset_ctl = 1'b1;
|
|
used_slot_update = 1'b0;
|
|
load_nibble = 2'b01;
|
|
next_state = LOAD_HI;
|
|
end
|
|
end
|
|
LOAD_LO: begin
|
|
rxb_we_ctl = 1'b1;
|
|
rx_count_inc_ctl = 1'b1;
|
|
if(phy_dv) begin
|
|
load_nibble = 2'b01;
|
|
next_state = LOAD_HI;
|
|
end else begin
|
|
rx_done_ctl = 1'b1;
|
|
next_state = TERMINATE;
|
|
end
|
|
end
|
|
LOAD_HI: begin
|
|
if(phy_dv) begin
|
|
load_nibble = 2'b10;
|
|
next_state = LOAD_LO;
|
|
end else begin
|
|
rx_done_ctl = 1'b1;
|
|
next_state = TERMINATE;
|
|
end
|
|
end
|
|
TERMINATE: begin
|
|
used_slot_update = 1'b1;
|
|
next_state = IDLE;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
endmodule
|