litex/verilog/minimac3/minimac3_tx.v

84 lines
1.5 KiB
Verilog

module minimac3_tx(
input phy_tx_clk,
input tx_start,
output reg tx_done,
input [10:0] tx_count,
input [7:0] txb_dat,
output [10:0] txb_adr,
output reg phy_tx_en,
output reg [3:0] phy_tx_data
);
reg phy_tx_en_r;
reg phy_tx_data_sel;
wire [3:0] phy_tx_data_r = phy_tx_data_sel ? txb_dat[7:4] : txb_dat[3:0];
always @(posedge phy_tx_clk) begin
phy_tx_en <= phy_tx_en_r;
phy_tx_data <= phy_tx_data_r;
end
reg [10:0] byte_count;
reg byte_count_reset;
reg byte_count_inc;
always @(posedge phy_tx_clk) begin
if(byte_count_reset)
byte_count <= 11'd0;
else if(byte_count_inc)
byte_count <= byte_count + 11'd1;
end
assign txb_adr = byte_count;
wire byte_count_max = byte_count == tx_count;
parameter IDLE = 2'd0;
parameter SEND_LO = 2'd1;
parameter SEND_HI = 2'd2;
parameter TERMINATE = 2'd3;
reg [1:0] state;
reg [1:0] next_state;
initial state <= IDLE;
always @(posedge phy_tx_clk)
state <= next_state;
always @(*) begin
phy_tx_en_r = 1'b0;
phy_tx_data_sel = 1'b0;
byte_count_reset = 1'b0;
byte_count_inc = 1'b0;
tx_done = 1'b0;
next_state = state;
case(state)
IDLE: begin
byte_count_reset = 1'b1;
if(tx_start)
next_state = SEND_LO;
end
SEND_LO: begin
byte_count_inc = 1'b1;
phy_tx_en_r = 1'b1;
phy_tx_data_sel = 1'b0;
next_state = SEND_HI;
end
SEND_HI: begin
phy_tx_en_r = 1'b1;
phy_tx_data_sel = 1'b1;
if(byte_count_max)
next_state = TERMINATE;
else
next_state = SEND_LO;
end
TERMINATE: begin
byte_count_reset = 1'b1;
tx_done = 1'b1;
next_state = IDLE;
end
endcase
end
endmodule