Files
MM7020/hdl/phy_control.v
2024-10-12 11:02:35 +08:00

422 lines
17 KiB
Verilog

`timescale 1ns / 100ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Beijing Institute of Technology
// Engineer: FanHao
//
// Create Date: 02/08/2023 04:40:51 PM
// Design Name:
// Module Name: axi_lite
// Project Name:
// Target Devices:
// Tool Versions: 2022.2
// Description: An axi-lite wrap for register configuration
//
// Dependencies: up_axi
//
// Revision:
// [0.0-01] - Initial Version: Add asynchronized clock support.
// [0.0-00] - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module phy_control #(
parameter ASYNC_CLK = 1,
// parameter REG_SPACE_ADDR_WIDTH = 5,
parameter AXI_ADDRESS_WIDTH = 5
) (
/********************************************************************************/
/************************** Slave AXI-LITE interface ****************************/
/********************************************************************************/
//--- DO NOT MODIFY FOLLOWING CONTANT
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME ACLK, PHASE 0.000" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 ACLK CLK" *)
input s_axi_aclk, (* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME ARESETN, POLARITY ACTIVE_LOW" *) (* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 ARESETN RST" *)
input s_axi_aresetn, (* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME S_AXI, CLK_DOMAIN ACLK, DATA_WIDTH 32, PROTOCOL AXI4LITE, READ_WRITE_MODE READ_WRITE" *) (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI AWVALID" *)
input s_axi_awvalid, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI AWADDR" *)
input [AXI_ADDRESS_WIDTH-1:0] s_axi_awaddr, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI AWREADY" *)
output s_axi_awready, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI AWPROT" *)
input [ 2:0] s_axi_awprot, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI WVALID" *)
input s_axi_wvalid, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI WDATA" *)
input [ 31:0] s_axi_wdata, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI WSTRB" *)
input [ 3:0] s_axi_wstrb, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI WREADY" *)
output s_axi_wready, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI BVALID" *)
output s_axi_bvalid, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI BRESP" *)
output [ 1:0] s_axi_bresp, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI BREADY" *)
input s_axi_bready, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI ARVALID" *)
input s_axi_arvalid, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI ARADDR" *)
input [AXI_ADDRESS_WIDTH-1:0] s_axi_araddr, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI ARREADY" *)
output s_axi_arready, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI ARPROT" *)
input [ 2:0] s_axi_arprot, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI RVALID" *)
output s_axi_rvalid, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI RREADY" *)
input s_axi_rready, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI RRESP" *)
output [ 1:0] s_axi_rresp, (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI RDATA" *)
output [ 31:0] s_axi_rdata,
//--- DO NOT MODIFY CONTANT ABOVE
/********************************************************************************/
/******************************** User Interface ********************************/
/********************************************************************************/
//--- ADD YOUR OWN PORTS START
// main clock
input clk, // can be floating if ASYNC_CLK == 0
// resetn (should synchronised with "clk")
input rstn, // can be floating if ASYNC_CLK == 0
// control sigal
output wire phy_rst,
output wire phy_tx_test_flag,
output wire phy_tx_iq_reverse,
output wire phy_rx_iq_reverse,
// tdma parameters
output wire tdma_flag_is_master,
output wire [31:0] tdma_slot_len,
output wire [31:0] tdma_tic_2_ps,
output wire [31:0] tdma_id_cfg,
output wire tdma_recv_cur_slot_id_valid,
output wire [ 7:0] tdma_recv_cur_slot_id,
output wire [31:0] tdma_frame_sync_tic
//--- ADD YOUR OWN PORTS END
);
// MODULE_VERSION[31:24] Major Version
// MODULE_VERSION[23:16] Minor Version
// MODULE_VERSION[15: 0] Revision
localparam MODULE_VERSION = 'h000001;
/********************************************************************************/
/******************************** Interface Logic *******************************/
/********************************************************************************/
//--- DO NOT MODIFY FOLLOWING CONTANT
// Module internal signals
wire local_clk;
wire local_rstn;
wire up_rreq_s;
reg [ 31:0] up_rdata_ff = 'd0;
reg up_rack_ff = 1'b0;
wire up_wreq_s;
wire [ 31:0] up_wdata_s;
reg up_wack_ff = 1'b0;
wire [(AXI_ADDRESS_WIDTH-3):0] up_waddr_s;
wire [(AXI_ADDRESS_WIDTH-3):0] up_raddr_s;
// up_axi interface signals
wire up_rack;
wire up_rreq;
wire [ 31:0] up_rdata;
wire up_wack;
wire up_wreq;
wire [ 31:0] up_wdata;
wire [(AXI_ADDRESS_WIDTH-3):0] up_waddr;
wire [(AXI_ADDRESS_WIDTH-3):0] up_raddr;
// following signals indicate corresponding rep/ack were received.
wire up_rreq_rcv;
wire up_wreq_rcv;
wire up_rack_rcv;
wire up_wack_rcv;
generate
if (ASYNC_CLK) begin
assign local_clk = clk;
assign local_rstn = rstn;
// read channel synchronisation
reg up_rreq_send = 1'b0;
always @(posedge s_axi_aclk) begin
if (s_axi_aresetn == 1'b0) begin
up_rreq_send <= 1'b0;
end
else if (up_rreq) begin
up_rreq_send <= 1'b1;
end
else if (up_rreq_rcv) begin
up_rreq_send <= 1'b0;
end
end
xpm_cdc_handshake #(
.DEST_EXT_HSK(0),
.DEST_SYNC_FF(2),
.INIT_SYNC_FF(1),
.SIM_ASSERT_CHK(1),
.SRC_SYNC_FF(2),
.WIDTH((AXI_ADDRESS_WIDTH - 2)) // raddr
) i_rd_req_xpm_cdc (
.dest_clk(local_clk),
.dest_req(up_rreq_s),
.dest_out({up_raddr_s[(AXI_ADDRESS_WIDTH-3):0]}),
.src_clk (s_axi_aclk),
.src_send(up_rreq_send),
.src_rcv (up_rreq_rcv),
.src_in ({up_raddr[(AXI_ADDRESS_WIDTH-3):0]})
);
reg up_rack_send = 1'b0;
always @(posedge local_clk) begin
if (local_rstn == 1'b0) begin
up_rack_send <= 1'b0;
end
else if (up_rack_ff) begin
up_rack_send <= 1'b1;
end
else if (up_rack_rcv) begin
up_rack_send <= 1'b0;
end
end
xpm_cdc_handshake #(
.DEST_EXT_HSK(0),
.DEST_SYNC_FF(2),
.INIT_SYNC_FF(1),
.SIM_ASSERT_CHK(1),
.SRC_SYNC_FF(2),
.WIDTH(32) //rdata
) i_rd_rsp_xpm_cdc (
.dest_clk(s_axi_aclk),
.dest_req(up_rack),
.dest_out({up_rdata[31:0]}),
.src_clk (local_clk),
.src_send(up_rack_send),
.src_rcv (up_rack_rcv),
.src_in ({up_rdata_ff[31:0]})
);
// write channel synchronisation
reg up_wreq_send = 1'b0;
always @(posedge s_axi_aclk) begin
if (s_axi_aresetn == 1'b0) begin
up_wreq_send <= 1'b0;
end
else if (up_wreq) begin
up_wreq_send <= 1'b1;
end
else if (up_wreq_rcv) begin
up_wreq_send <= 1'b0;
end
end
xpm_cdc_handshake #(
.DEST_EXT_HSK(0),
.DEST_SYNC_FF(2),
.INIT_SYNC_FF(1),
.SIM_ASSERT_CHK(1),
.SRC_SYNC_FF(2),
.WIDTH((AXI_ADDRESS_WIDTH - 2) + 32) //waddr + wdata
) i_wr_req_ctrl_xpm_cdc (
.dest_clk(local_clk),
.dest_req(up_wreq_s),
.dest_out({up_waddr_s[(AXI_ADDRESS_WIDTH-3):0], up_wdata_s[31:0]}),
.src_clk (s_axi_aclk),
.src_send(up_wreq_send),
.src_rcv (up_wreq_rcv),
.src_in ({up_waddr[(AXI_ADDRESS_WIDTH-3):0], up_wdata[31:0]})
);
reg up_wack_send = 1'b0;
always @(posedge local_clk) begin
if (local_rstn == 1'b0) begin
up_wack_send <= 1'b0;
end
else if (up_wack_ff) begin
up_wack_send <= 1'b1;
end
else if (up_wack_rcv) begin
up_wack_send <= 1'b0;
end
end
xpm_cdc_handshake #(
.DEST_EXT_HSK(0),
.DEST_SYNC_FF(2),
.INIT_SYNC_FF(1),
.SIM_ASSERT_CHK(1),
.SRC_SYNC_FF(2),
.WIDTH(1) // wack
) i_wr_rsp_data_xpm_cdc (
.dest_clk(s_axi_aclk),
.dest_req(up_wack),
.src_clk (local_clk),
.src_send(up_wack_send),
.src_rcv (up_wack_rcv),
.src_in (1)
);
end
else begin
assign local_clk = s_axi_aclk;
assign local_rstn = s_axi_aresetn;
assign up_rack = up_rack_ff;
assign up_rreq_s = up_rreq;
assign up_rdata = up_rdata_ff;
assign up_wack = up_wack_ff;
assign up_wreq_s = up_wreq;
assign up_wdata_s[31:0] = up_wdata[31:0];
assign up_waddr_s[(AXI_ADDRESS_WIDTH-3):0] = up_waddr[(AXI_ADDRESS_WIDTH-3):0];
assign up_raddr_s = up_raddr[(AXI_ADDRESS_WIDTH-3):0];
assign up_rreq_rcv = up_rreq_s;
assign up_wreq_rcv = up_wreq_s;
assign up_rack_rcv = up_rack_ff;
assign up_wack_rcv = up_wack_ff;
end
endgenerate
// up-axi interface wrapper
up_axi #(
.AXI_ADDRESS_WIDTH(AXI_ADDRESS_WIDTH)
) i_up_axi (
.up_rstn (s_axi_aresetn),
.up_clk (s_axi_aclk),
.up_axi_awvalid(s_axi_awvalid),
.up_axi_awaddr (s_axi_awaddr),
.up_axi_awready(s_axi_awready),
.up_axi_wvalid (s_axi_wvalid),
.up_axi_wdata (s_axi_wdata),
.up_axi_wstrb (s_axi_wstrb),
.up_axi_wready (s_axi_wready),
.up_axi_bvalid (s_axi_bvalid),
.up_axi_bresp (s_axi_bresp),
.up_axi_bready (s_axi_bready),
.up_axi_arvalid(s_axi_arvalid),
.up_axi_araddr (s_axi_araddr),
.up_axi_arready(s_axi_arready),
.up_axi_rvalid (s_axi_rvalid),
.up_axi_rresp (s_axi_rresp),
.up_axi_rdata (s_axi_rdata),
.up_axi_rready (s_axi_rready),
.up_wreq (up_wreq),
.up_waddr (up_waddr),
.up_wdata (up_wdata),
.up_wack (up_wack),
.up_rreq (up_rreq),
.up_raddr (up_raddr),
.up_rdata (up_rdata),
.up_rack (up_rack)
);
always @(posedge local_clk) begin
if (local_rstn == 1'b0) begin
up_rack_ff <= 'd0;
end
else begin
up_rack_ff <= up_rreq_s;
end
end
always @(posedge local_clk) begin
if (local_rstn == 1'b0) begin
up_wack_ff <= 1'b0;
end
else begin
up_wack_ff <= up_wreq_s;
end
end
//--- DO NOT MODIFY CONTANT ABOVE
/********************************************************************************/
/********************************** User Logic **********************************/
/********************************************************************************/
// BASIC RULES:
// 1. AIX Write operation alwayse has the highet priority.
// 2. Every userside operation must use "local_clk" as driving clock
// 3. Every regoster must have a perfectely defined access type
// you can use the following acronyms to define the register's access type
// NOTE: different access types can be combined.
// RO Read-only
// CLRONRD Readable, clears value on read
// CLRONWR Readable, Readable, clears value on write
// RAZ Read as zero
// RO Read only
// RUD Read undefined
// RW Normal read/write
// RWSO Read/write, set only
// WAZ Write as zero
// WO Write-only
// WTC Readable, write a one to clear
// RWSO Read/write, set only
// RUD Read undefined
// RAZ Read as zero
// Z Access (read or write) as zero
//--- ADD YOUR OWN LOGIC START
//--- EXAMPLE CODE START
// Register address definitions
// NOTE: 物理层寄存器定义,控制寄存器,状态寄存器
localparam integer PHY_CR = 'h00000000 >> 2; // RW
localparam integer PHY_SR = 'h00000004 >> 2; // RW
localparam integer TDMA_SLOT_LEN = 'h0000_0008 >> 2;
localparam integer TDMA_TIC_2_PS = 'h0000_000C >> 2;
localparam integer TDMA_ID_CFG = 'h0000_0010 >> 2;
localparam integer TDMA_RECV_ID = 'h0000_0014 >> 2;
localparam integer TDMA_FRAME_SYNC_TIC = 'h0000_0018 >> 2;
// Register definitions
reg [31:0] phy_cr_reg = 32'h0;
reg [31:0] phy_sr_reg = 32'h0;
reg [31:0] tdma_slot_len_reg = 32'h0;
reg [31:0] tdma_tic_2_ps_reg = 32'h0;
reg [31:0] tdma_id_cfg_reg = 32'h0; // 2B zero pad, 1B slot num, 1B local id
reg [31:0] tdma_recv_id_reg = 32'h0;
reg [31:0] tdma_frame_sync_tic_reg = 32'h0;
// Register Reading
always @(posedge local_clk) begin
case (up_raddr_s)
PHY_CR: up_rdata_ff <= phy_cr_reg;
PHY_SR: up_rdata_ff <= phy_sr_reg;
default: up_rdata_ff <= 'h00;
endcase
end
// Main Logic
always @(posedge local_clk) begin
if (local_rstn == 1'b0) begin
phy_cr_reg <= 32'h0;
phy_sr_reg <= 32'h0;
end
else begin
// AXI write operation alwayse has the higest priority.
if (up_wreq_s == 1'b1) begin
case (up_waddr_s)
PHY_CR: phy_cr_reg <= up_wdata_s;
PHY_SR: phy_sr_reg <= up_wdata_s;
TDMA_SLOT_LEN: tdma_slot_len_reg <= up_wdata_s;
TDMA_TIC_2_PS: tdma_tic_2_ps_reg <= up_wdata_s;
TDMA_ID_CFG: tdma_id_cfg_reg <= up_wdata_s;
TDMA_RECV_ID: tdma_recv_id_reg <= up_wdata_s;
TDMA_FRAME_SYNC_TIC: tdma_frame_sync_tic_reg <= up_wdata_s;
endcase
end
else begin
// self logic
if (tdma_recv_id_reg[8] == 1) begin
tdma_recv_id_reg[8] <= 0;
end
end
end
end
// control reg definition
assign phy_rst = ~phy_cr_reg[0];
assign phy_tx_test_flag = phy_cr_reg[1];
assign phy_tx_iq_reverse = phy_cr_reg[2];
assign phy_rx_iq_reverse = phy_cr_reg[3];
assign tdma_flag_is_master = phy_cr_reg[4];
// tdma
assign tdma_slot_len = tdma_slot_len_reg;
assign tdma_tic_2_ps = tdma_tic_2_ps_reg;
assign tdma_id_cfg = tdma_id_cfg_reg;
// received mac frame
assign tdma_recv_cur_slot_id = tdma_recv_id_reg[7:0];
assign tdma_recv_cur_slot_id_valid = tdma_recv_id_reg[8];
// frame sync tic
assign tdma_frame_sync_tic = tdma_frame_sync_tic_reg;
vio_phy_param u_vio_phy_param (
.clk (local_clk),
.probe_in0(phy_cr_reg)
);
//--- ADD YOUR OWN LOGIC END
endmodule