mirror of
https://github.com/fpganinja/taxi.git
synced 2026-04-07 04:38:42 -07:00
285 lines
6.2 KiB
Systemverilog
285 lines
6.2 KiB
Systemverilog
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
|
/*
|
|
|
|
Copyright (c) 2025 FPGA Ninja, LLC
|
|
|
|
Authors:
|
|
- Alex Forencich
|
|
|
|
*/
|
|
|
|
`resetall
|
|
`timescale 1ns / 1ps
|
|
`default_nettype none
|
|
|
|
/*
|
|
* Corundum-micro transmit datapath
|
|
*/
|
|
module cndm_micro_tx #(
|
|
parameter logic PTP_TS_EN = 1'b1,
|
|
parameter logic PTP_TS_FMT_TOD = 1'b0
|
|
)
|
|
(
|
|
input wire logic clk,
|
|
input wire logic rst,
|
|
|
|
/*
|
|
* PTP
|
|
*/
|
|
input wire logic ptp_clk = 1'b0,
|
|
input wire logic ptp_rst = 1'b0,
|
|
input wire logic ptp_td_sdi = 1'b0,
|
|
|
|
/*
|
|
* DMA
|
|
*/
|
|
taxi_dma_desc_if.req_src dma_rd_desc_req,
|
|
taxi_dma_desc_if.sts_snk dma_rd_desc_sts,
|
|
taxi_dma_ram_if.wr_slv dma_ram_wr,
|
|
|
|
output wire logic desc_req,
|
|
taxi_axis_if.snk axis_desc,
|
|
taxi_axis_if.src tx_data,
|
|
taxi_axis_if.snk tx_cpl,
|
|
taxi_axis_if.src axis_cpl
|
|
);
|
|
|
|
localparam RAM_ADDR_W = 16;
|
|
|
|
taxi_dma_desc_if #(
|
|
.SRC_ADDR_W(RAM_ADDR_W),
|
|
.SRC_SEL_EN(1'b0),
|
|
.SRC_ASID_EN(1'b0),
|
|
.DST_ADDR_W(RAM_ADDR_W),
|
|
.DST_SEL_EN(1'b0),
|
|
.DST_ASID_EN(1'b0),
|
|
.IMM_EN(1'b0),
|
|
.LEN_W(16),
|
|
.TAG_W(1),
|
|
.ID_EN(0),
|
|
.DEST_EN(0),
|
|
.USER_EN(1),
|
|
.USER_W(1)
|
|
) dma_desc();
|
|
|
|
typedef enum logic [1:0] {
|
|
STATE_IDLE,
|
|
STATE_READ_DESC,
|
|
STATE_READ_DATA,
|
|
STATE_TX_DATA
|
|
} state_t;
|
|
|
|
state_t state_reg = STATE_IDLE;
|
|
|
|
logic desc_req_reg = 1'b0;
|
|
|
|
assign desc_req = desc_req_reg;
|
|
|
|
wire [95:0] tx_cpl_ptp_ts;
|
|
wire tx_cpl_valid;
|
|
|
|
if (PTP_TS_EN) begin
|
|
|
|
if (PTP_TS_FMT_TOD) begin
|
|
|
|
assign tx_cpl_ptp_ts = tx_cpl.tdata;
|
|
assign tx_cpl_valid = tx_cpl.tvalid;
|
|
|
|
end else begin
|
|
|
|
taxi_axis_if #(
|
|
.DATA_W(96),
|
|
.KEEP_EN(0),
|
|
.KEEP_W(1),
|
|
.STRB_EN(0),
|
|
.LAST_EN(0),
|
|
.ID_EN(0),
|
|
.DEST_EN(0),
|
|
.USER_EN(1),
|
|
.USER_W(1)
|
|
) tx_cpl_tod();
|
|
|
|
assign tx_cpl_ptp_ts = tx_cpl_tod.tdata;
|
|
assign tx_cpl_valid = tx_cpl_tod.tvalid;
|
|
|
|
taxi_ptp_td_rel2tod #(
|
|
.TS_FNS_W(16),
|
|
.TS_REL_NS_W(tx_cpl.DATA_W-16),
|
|
.TS_TOD_S_W(48),
|
|
.TS_REL_W(tx_cpl.DATA_W),
|
|
.TS_TOD_W(96),
|
|
.TD_SDI_PIPELINE(2)
|
|
)
|
|
rel2tod_inst (
|
|
.clk(clk),
|
|
.rst(rst),
|
|
|
|
/*
|
|
* PTP clock interface
|
|
*/
|
|
.ptp_clk(ptp_clk),
|
|
.ptp_rst(ptp_rst),
|
|
.ptp_td_sdi(ptp_td_sdi),
|
|
|
|
/*
|
|
* Timestamp conversion
|
|
*/
|
|
.s_axis_ts_rel(tx_cpl),
|
|
.m_axis_ts_tod(tx_cpl_tod)
|
|
);
|
|
|
|
end
|
|
|
|
end else begin
|
|
|
|
assign tx_cpl_ptp_ts = '0;
|
|
assign tx_cpl_valid = tx_cpl.tvalid;
|
|
|
|
end
|
|
|
|
always_ff @(posedge clk) begin
|
|
desc_req_reg <= 1'b0;
|
|
|
|
axis_desc.tready <= 1'b0;
|
|
|
|
dma_rd_desc_req.req_src_sel <= '0;
|
|
dma_rd_desc_req.req_src_asid <= '0;
|
|
dma_rd_desc_req.req_dst_sel <= '0;
|
|
dma_rd_desc_req.req_dst_asid <= '0;
|
|
dma_rd_desc_req.req_imm <= '0;
|
|
dma_rd_desc_req.req_imm_en <= '0;
|
|
dma_rd_desc_req.req_tag <= '0;
|
|
dma_rd_desc_req.req_id <= '0;
|
|
dma_rd_desc_req.req_dest <= '0;
|
|
dma_rd_desc_req.req_user <= '0;
|
|
dma_rd_desc_req.req_valid <= dma_rd_desc_req.req_valid && !dma_rd_desc_req.req_ready;
|
|
|
|
dma_desc.req_src_sel <= '0;
|
|
dma_desc.req_src_asid <= '0;
|
|
dma_desc.req_dst_addr <= '0;
|
|
dma_desc.req_dst_sel <= '0;
|
|
dma_desc.req_dst_asid <= '0;
|
|
dma_desc.req_imm <= '0;
|
|
dma_desc.req_imm_en <= '0;
|
|
dma_desc.req_tag <= '0;
|
|
dma_desc.req_id <= '0;
|
|
dma_desc.req_dest <= '0;
|
|
dma_desc.req_user <= '0;
|
|
dma_desc.req_valid <= dma_desc.req_valid && !dma_desc.req_ready;
|
|
|
|
axis_cpl.tkeep <= '0;
|
|
axis_cpl.tid <= '0;
|
|
axis_cpl.tdest <= '0;
|
|
axis_cpl.tuser <= '0;
|
|
axis_cpl.tlast <= 1'b1;
|
|
axis_cpl.tvalid <= axis_cpl.tvalid && !axis_cpl.tready;
|
|
|
|
case (state_reg)
|
|
STATE_IDLE: begin
|
|
desc_req_reg <= 1'b1;
|
|
state_reg <= STATE_READ_DESC;
|
|
end
|
|
STATE_READ_DESC: begin
|
|
axis_desc.tready <= 1'b1;
|
|
|
|
dma_rd_desc_req.req_src_addr <= axis_desc.tdata[127:64];
|
|
dma_rd_desc_req.req_dst_addr <= '0;
|
|
dma_rd_desc_req.req_len <= 20'(axis_desc.tdata[47:32]);
|
|
|
|
dma_desc.req_src_addr <= '0;
|
|
dma_desc.req_len <= axis_desc.tdata[47:32];
|
|
|
|
axis_cpl.tdata[47:32] <= axis_desc.tdata[47:32];
|
|
|
|
if (axis_desc.tvalid && axis_desc.tready) begin
|
|
if (axis_desc.tuser) begin
|
|
// failed to read desc
|
|
state_reg <= STATE_IDLE;
|
|
end else begin
|
|
dma_rd_desc_req.req_valid <= 1'b1;
|
|
state_reg <= STATE_READ_DATA;
|
|
end
|
|
end
|
|
end
|
|
STATE_READ_DATA: begin
|
|
if (dma_rd_desc_sts.sts_valid) begin
|
|
dma_desc.req_valid <= 1'b1;
|
|
state_reg <= STATE_TX_DATA;
|
|
end
|
|
end
|
|
STATE_TX_DATA: begin
|
|
axis_cpl.tdata[127:112] <= tx_cpl_ptp_ts[63:48]; // sec
|
|
axis_cpl.tdata[95:64] <= tx_cpl_ptp_ts[47:16]; // ns
|
|
axis_cpl.tdata[111:96] <= tx_cpl_ptp_ts[15:0]; // fns
|
|
if (tx_cpl_valid) begin
|
|
axis_cpl.tvalid <= 1'b1;
|
|
state_reg <= STATE_IDLE;
|
|
end
|
|
end
|
|
default: begin
|
|
state_reg <= STATE_IDLE;
|
|
end
|
|
endcase
|
|
|
|
if (rst) begin
|
|
state_reg <= STATE_IDLE;
|
|
end
|
|
end
|
|
|
|
taxi_dma_ram_if #(
|
|
.SEGS(dma_ram_wr.SEGS),
|
|
.SEG_ADDR_W(dma_ram_wr.SEG_ADDR_W),
|
|
.SEG_DATA_W(dma_ram_wr.SEG_DATA_W),
|
|
.SEG_BE_W(dma_ram_wr.SEG_BE_W)
|
|
) dma_ram_rd();
|
|
|
|
taxi_dma_psdpram #(
|
|
.SIZE(4096),
|
|
.PIPELINE(2)
|
|
)
|
|
ram_inst (
|
|
.clk(clk),
|
|
.rst(rst),
|
|
|
|
/*
|
|
* Write port
|
|
*/
|
|
.dma_ram_wr(dma_ram_wr),
|
|
|
|
/*
|
|
* Read port
|
|
*/
|
|
.dma_ram_rd(dma_ram_rd)
|
|
);
|
|
|
|
taxi_dma_client_axis_source
|
|
dma_inst (
|
|
.clk(clk),
|
|
.rst(rst),
|
|
|
|
/*
|
|
* DMA descriptor
|
|
*/
|
|
.desc_req(dma_desc),
|
|
.desc_sts(dma_desc),
|
|
|
|
/*
|
|
* AXI stream read data output
|
|
*/
|
|
.m_axis_rd_data(tx_data),
|
|
|
|
/*
|
|
* RAM interface
|
|
*/
|
|
.dma_ram_rd(dma_ram_rd),
|
|
|
|
/*
|
|
* Configuration
|
|
*/
|
|
.enable(1'b1)
|
|
);
|
|
|
|
endmodule
|
|
|
|
`resetall
|