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_wrdata[7:0] 要写入寄存器的数据
sci_sel_quad 选择quad寄存器,高有效
sci_wrn 要写入寄存器的数据
sci_sel_ch 写选通,低有效
sci_addr 地址总线输入,官方文档中有具体映射
sci_rd 读数据选择
sci_rddata[7: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论坛。

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

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

相关推荐
stars-he13 小时前
FPGA学习笔记(7)以太网UDP数据报文发送电路设计(一)
笔记·网络协议·学习·fpga开发·udp
扮作大侠13 小时前
2024vitis无错误编译项目失败[ERROR] collect2.exe: error: ld returned 1 exit status
fpga开发
碎碎思13 小时前
从 JTAG 启动 Zynq-7000 嵌入式 Linux:使用 XSCT 全流程教程
linux·运维·服务器·fpga开发
minglie115 小时前
Tang-Nano-1K的rPLL
fpga开发
minglie115 小时前
Vitis HLS流水灯测试
fpga开发
风_峰1 天前
AMD 自适应SoC产品系列讲解
fpga开发
FPGA小c鸡1 天前
AXI-Full突发传输完全攻略:从INCR/WRAP/FIXED到4KB边界、地址计算、响应机制(附实战案例)
fpga开发
集芯微电科技有限公司2 天前
DC-DC|40V/10A大电流高效率升压恒压控制器
c语言·数据结构·单片机·嵌入式硬件·fpga开发
minglie12 天前
Vitis HLS c转verilog
c语言·开发语言·fpga开发
江蘇的蘇2 天前
基于FPGA实现NVMe硬盘的读写功能
fpga开发