Serdes专题(5)PCS IP配置

文章目录

前言

PCS IP是一个软核,是连接FPGA用户逻辑与Serdes硬件结构的桥梁。Lattice Serdes提供了很多灵活的配置,全部可以通过IP配置的方式灵活调用。IP配置可通过三种方式实现,一是IP生成时,UI界面提供了各种配置选项;二是例化IP时,提供了FPGA写入的控制信号和读出的状态信号。三是,IP软核提供了寄存器配置接口,相对更靠近底层的配置和状态可通过寄存器配置接口读取或配置。本文介绍这三种方式。

1.PCS IP接口信号

如图所示,是所有PCS IP相关的接口信号。其中有关复位与时钟的信号上节已经介绍过,关于Client Interface实际上是寄存器接口,在本文第三节介绍。Primary I/O是硬件上与serdes物理介质连接的接口,不过多介绍。这里介绍一些相关的控制信号和状态信号的配置与使用。所介绍的信号是基于实现serdes 8b/10b通信使用的,一些不常使用未经我验证的信号不做介绍。
控制信号,全部是输入信号

状态信号,全部是输出信号

2. IP核的配置

PCS软核中定义了很多寄存器,初始寄存器设置可通过使用 IPexpress 中的自动配置功能实现,即在UI界面中点点点的方式。模块生成器提供了一个自动配置文件,包含了所选模式下quad和通道寄存器的设置。可参考这个文件来进行前端仿真,还可以集成到位流中。当一个自动配置文件集成到位流中,那么在配置过程中,所有的 quad 和通道寄存器将根据自动配置文件定义的值进行设置。如果在工作时,用户需要更改控制寄存器或监控状态寄存器,那么设计中必须包含SCI接口,即Serdes Client Interface,在下一节介绍。

IP配置第一页,配置使能的通道,与是否同时使能Rx与Tx,通道选择主要与硬件原理图指示的连接一致。如图下拉框主要选择实现协议,下一个专题实现以太网会介绍SGMII接口。本系列实现G8B/10B,其余未用过。

IP配置第二页介绍时钟、线速率、位宽的配置。靠上半部分设置发送通道,Max Data Rate设置serdes线速率,要与FPGA硬件支持能力,光模块能力,应用需求适配。LatticeECP3最大支持3.125G。Tx Refclk Source配置发送通道参考时钟源,注意发送与接收不必同源。参考时钟的频率应与所设置的线速率成一定的倍数关系。IP给FPGA逻辑的时钟则由Tx Rate设置的线速率与数据Bus共同决定,一般情况下,要求发送与接收通道设置一致。图中下半部分设置接收通道与发送通道一致。

PreEmphasis设置是否使能预加重,预加重 (TX FIR)即在"发射端"补高频,它的作用像是在出门前先"穿厚一点的衣服"。你知道外面冷(高频会衰减),于是你提前给高频多一些能量。通常实验室环境设置为0即可。TX I/O Termination是两个差分发送线之间的终端电阻,让高速信号在走线和负载上传播时不产生反射,从而保证眼图稳定、减少抖动和误码。当高频信号衰减严重的时候,在接收端配置Equalization以补偿高速信号在走线中被"削弱"的高频成分,让接收端能够恢复出原始的方波。接收端终端电阻也是50欧姆。耦合方式要与硬件涉及匹配,通常选择AC耦合。最下面设置时钟的终端电阻。Tx PLL则是用来监测Tx端pll失锁的标准值,通常无需设置。

IP配置第四页,本页主要上是选一些硬件结构上的多路器,接收端发送端都是设置是否给信号取反,是否使能编码器,是否使能fifo桥。关于下方字对齐设置是否由软核字对齐。是否利用内部的状态机,选择K码。按照上面默认设置。第五页设置CTC FIFO相关内容,用一个小 FIFO 来吸收 Tx 时钟与 Rx 时钟之间的频偏,使得 RX 用户侧的时钟域能够继续稳定读出数据,不会因时钟不一致而出现漏读/多读。保持默认即可。

第六页设置回环模式,下一篇文章细讲。是否包含复位序列,做内回环测试的时候不包含,其余时刻包含。最后是勾选SCI接口以在代码运行过程中读写寄存器。最后一页包含一些生成信息,保持默认即可。

3.寄存器接口

接口信号如下:

信号 作用
sci_wrdata7:0 要写入寄存器的数据
sci_sel_quad 选择quad寄存器,高有效
sci_wrn 要写入寄存器的数据
sci_sel_ch 写选通,低有效
sci_addr 地址总线输入,官方文档中有具体映射
sci_rd 读数据选择
sci_rddata7:0 读数据输出
操作时序如下:


下面是我写的寄存器读取的实例代码,供参考。

cpp 复制代码
module reg_rd (
input      clk_fpga,
input      rst_n,
output [7:0]   sci_wrdata,
output [5:0]   sci_addr,
input   [7:0]  sci_rddata,
output         sci_sel_quad,
output         sci_rd,
output         sci_wrn,
output  reg    sci_sel_ch2
);
    
reg [31:0]cnt_1s;
reg start_en;
always @(posedge clk_fpga or negedge rst_n) begin
    if(!rst_n)begin
        cnt_1s <= 0;
        start_en <= 0;
    end else begin
        cnt_1s <= cnt_1s + 1;
        if(cnt_1s == 32'd125_000_000)begin
            cnt_1s <= cnt_1s;
            start_en <= 1;
        end
    end
end


//reg [7:0]reg_0[0:5];
reg [7:0]reg_9;
reg [7:0]reg_a;
reg [7:0]reg_b;
reg [7:0]reg_d;
reg [7:0]reg_2;
reg [7:0]reg_21;
reg [7:0]reg_22;


reg [7:0]reg_ch_00;
reg [7:0]reg_ch_01;
reg [7:0]reg_ch_02;
reg [7:0]reg_ch_03;
reg [7:0]reg_ch_04;
reg [7:0]reg_ch_05;
reg [7:0]reg_ch_06;
reg [7:0]reg_ch_07;
reg [7:0]reg_ch_08;
reg [7:0]reg_ch_09;
reg [7:0]reg_ch_0A;
reg [7:0]reg_ch_0B;
reg [7:0]reg_ch_0C;
reg [7:0]reg_ch_0D;
reg [7:0]reg_ch_0E;
reg [7:0]reg_ch_0F;


reg [7:0]reg_ch_10;
reg [7:0]reg_ch_11;
reg [7:0]reg_ch_12;
reg [7:0]reg_ch_13;
reg [7:0]reg_ch_14;
reg [7:0]reg_ch_15;
reg [7:0]reg_ch_16;
reg [7:0]reg_ch_17;
reg [7:0]reg_ch_18;
reg [7:0]reg_ch_19;


reg [7:0]reg_ch_20;
reg [7:0]reg_ch_21;
reg [7:0]reg_ch_22;
reg [7:0]reg_ch_23;
reg [7:0]reg_ch_24;
reg [7:0]reg_ch_25;
reg [7:0]reg_ch_26;
reg [7:0]reg_ch_27;
reg [7:0]reg_ch_28;
reg [7:0]reg_ch_29;
reg [7:0]reg_ch_2A;
reg [7:0]reg_ch_2B;
reg [7:0]reg_ch_2C;

//read monitor
reg [1:0]State;

reg [5:0] sub_addr;
reg end_flag;
always @(posedge clk_fpga or negedge rst_n) begin
    if(!rst_n)begin
        State <= 0;
        end_flag <= 0;
        sci_sel_ch2 <= 0;
        
        // sci_rd <= 0;
        // sci_sel_quad <= 0;
        reg_2 <= 0;
        reg_9 <= 0;
        reg_a <= 0;
        reg_b <= 0;
        reg_d <= 0;
        reg_21 <= 0;
        reg_22 <= 0;
        sub_addr<=0;
        reg_ch_00 <= 0;
        reg_ch_01 <= 0;
        reg_ch_02 <= 0;
        reg_ch_03 <= 0;
        reg_ch_04 <= 0;
        reg_ch_05 <= 0;
        reg_ch_06 <= 0;
        reg_ch_07 <= 0;
        reg_ch_08 <= 0;
        reg_ch_09 <= 0;
        reg_ch_0A <= 0;
        reg_ch_0B <= 0;
        reg_ch_0C <= 0;
        reg_ch_0D <= 0;
        reg_ch_0E <= 0;
        reg_ch_0F <= 0;

        reg_ch_10 <= 0;
        reg_ch_11 <= 0;
        reg_ch_12 <= 0;
        reg_ch_13 <= 0;
        reg_ch_14 <= 0;
        reg_ch_15 <= 0;
        reg_ch_16 <= 0;
        reg_ch_17 <= 0;
        reg_ch_18 <= 0;
        reg_ch_19 <= 0;

        reg_ch_20 <= 0;
        reg_ch_21 <= 0;
        reg_ch_22 <= 0;
        reg_ch_23 <= 0;
        reg_ch_24 <= 0;
        reg_ch_25 <= 0;
        reg_ch_26 <= 0;
        reg_ch_27 <= 0;
        reg_ch_28 <= 0;
        reg_ch_29 <= 0;
        reg_ch_2A <= 0;
        reg_ch_2B <= 0;
        reg_ch_2C <= 0;
    end else begin
        case (State)
            0: begin //Cycle 1: Set sci_addr[5:0], sci_sel = 1'b1
                // sci_rd <= 0;
                if(start_en)begin
                    State <= sci_sel_ch2 ? 2:1; 
                end else begin
                    State <= 0;
                end
            end
            1:begin//Cycle 2: Set sci_rd from 0  1
                // sci_rd <= 1;
                // sci_sel_quad <= 0;
                // State <= 2;
                // reg_0[sub_addr]<= sci_rddata;
                // if(sci_rddata!=0)begin
                //     end_flag <= 1;
                // end
                sub_addr <= sub_addr + 1;
                if(sub_addr == 6'h2)begin
                    reg_2 <= sci_rddata;
                end
                if(sub_addr == 6'h9)begin
                    reg_9 <= sci_rddata;
                end
                if(sub_addr == 6'ha)begin
                    reg_a <= sci_rddata;
                end
                if(sub_addr == 6'hb)begin
                    reg_b <= sci_rddata;
                end
                if(sub_addr == 6'hd)begin
                    reg_d <= sci_rddata;
                end
                 if(sub_addr == 6'h21)begin
                    reg_21 <= sci_rddata;
                end
                if(sub_addr == 6'h22)begin
                    reg_22 <= sci_rddata;
                end
                if(sub_addr==6'd40  )begin
                    sub_addr <= 0;
                    State <= 2;
                    sci_sel_ch2 <= 1;
                end else begin
                    State <= 0;
                end
            end

            2:begin//Obtain reading data from sci_rddata[7:0]
                sub_addr <= sub_addr + 1;
                case (sub_addr)
                    6'h0:reg_ch_00 <= sci_rddata;
                    6'h1:reg_ch_01 <= sci_rddata;
                    6'h2:reg_ch_02 <= sci_rddata;
                    6'h3:reg_ch_03 <= sci_rddata;
                    6'h4:reg_ch_04 <= sci_rddata;
                    6'h5:reg_ch_05 <= sci_rddata;
                    6'h6:reg_ch_06 <= sci_rddata;
                    6'h7:reg_ch_07 <= sci_rddata;
                    6'h8:reg_ch_08 <= sci_rddata;
                    6'h9:reg_ch_09 <= sci_rddata;
                    6'hA:reg_ch_0A <= sci_rddata;
                    6'hB:reg_ch_0B <= sci_rddata;
                    6'hC:reg_ch_0C <= sci_rddata;
                    6'hD:reg_ch_0D <= sci_rddata;
                    6'hE:reg_ch_0E <= sci_rddata;
                    6'hF:reg_ch_0F <= sci_rddata;
 
                    6'h10:reg_ch_10 <= sci_rddata;
                    6'h11:reg_ch_11 <= sci_rddata;
                    6'h12:reg_ch_12 <= sci_rddata;
                    6'h13:reg_ch_13 <= sci_rddata;
                    6'h14:reg_ch_14 <= sci_rddata;
                    6'h15:reg_ch_15 <= sci_rddata;
                    6'h16:reg_ch_16 <= sci_rddata;
                    6'h17:reg_ch_17 <= sci_rddata;
                    6'h18:reg_ch_18 <= sci_rddata;
                    6'h19:reg_ch_19 <= sci_rddata;

                    6'h20:reg_ch_20 <= sci_rddata;
                    6'h21:reg_ch_21 <= sci_rddata;
                    6'h22:reg_ch_22 <= sci_rddata;
                    6'h23:reg_ch_23 <= sci_rddata;
                    6'h24:reg_ch_24 <= sci_rddata;
                    6'h25:reg_ch_25 <= sci_rddata;
                    6'h26:reg_ch_26 <= sci_rddata;
                    6'h27:reg_ch_27 <= sci_rddata;
                    6'h28:reg_ch_28 <= sci_rddata;
                    6'h29:reg_ch_29 <= sci_rddata;
                    6'h2A:reg_ch_2A <= sci_rddata;
                    6'h2B:reg_ch_2B <= sci_rddata;
                    6'h2C:reg_ch_2C <= sci_rddata; 
                    default: ;
                endcase
                if(sub_addr==6'h2C  )begin
                    sub_addr <= 0;
                    State <= 3;
                end else begin
                    State <= 0;
                end
            end
            3:begin
                // sci_rd <= 0;
                State <= 3;
            end
            default:; 
        endcase
    end
end
assign sci_addr = sub_addr;
assign sci_sel_quad =1;
assign sci_wrn = 0;
assign sci_rd = 1;
endmodule

4.传送门

|-----|
| END |

📡文章原创,首发于CSDN论坛。

📡欢迎点赞♥♥收藏⭐⭐打赏💵💵!

📡欢迎评论区或私信指出错误💉,提出宝贵意见或疑问😱。

相关推荐
仲南音14 小时前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner1 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20201 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy2 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia2 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20202 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子2 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安3 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议