[系统相关] 【Altera SoC体验之旅】+基于超前进位延时链的时间数字转换器

xiaomai516   2015-2-10 17:57 楼主
1.1 工作原理
待测的时间间隔s对应一个正脉冲,图 1给出了测量正脉冲下降沿到紧邻的时钟上升沿之间的延时tf原理注意1(a)tf的测量起点时刻为正脉冲的下降沿到达延时链输入端的时刻1(b)为利用延时链测量tf原理图。1(b)的每个三角表示一个延时单元,可以是任何一个带来延时的电路。当代表时间间隔的正脉冲在延时连中到来之前延时链的输出均为0;在正脉冲进入延时链后,在紧邻正脉冲时钟上升沿锁存延时链的输出,延时链1-0跳变f处对应正脉冲的下降沿,延时链输出含有mf1表示正脉冲下降沿经过的mf延时单元,
QQ截图20150210172257.png

QQ截图20150210172415.png

用一个延时链测量时间间隔正脉冲需要考虑两种情况,如图 2图 3所示。则待测的时间间隔t可得:
QQ截图20150210172517.png

QQ截图20150210173155.png

QQ截图20150210173254.png

图 4为实际的测量原理框图,s待测量的时间间隔正脉冲,clk为系统时钟,ENC统计mf和mr编码器,counter为统计n的计数器计数器在s为高时开始计数。s正脉冲进入延时链时,counter开始计数,在紧邻正脉冲的第一个时钟上升沿D触发器组对延时链的输出进行锁存,然后由ENC计算mfmr,最后nmf和mr存入FIFO
QQ截图20150210174005.png

1.2 超前进位延时链的实现
图 5中的红色箭头部分即是FPGA用于实现多位快速加法运算的超前进位链,图中的1~5表示资源的位置编号,例如左上角的组合逻辑编号为X16_Y79_N0,则右下角使用的触发器逻辑编号为X16_Y79_N4,根据这些编号可以锁定设计中使用的逻辑资源。根据TimeQuest的分析结果,进位链的延时最小为45ps,最大为728ps,如图 6所示。
利用一下脚本查看延时链的延时,最终结果如图 6所示。
create_timing_netlist -model slow -speed 6   
read_sdc
report_path -from [get_pins {inst|Add0~1|datac}] -npaths 300 -panel_name {Report  Path}

图片3.png

图 5 一个LABCELL原理图

图片4.png
图 6 超前进位链延时

图 6中1为延时链输入点,第一个超前进位延时0.728ns,此为延时链中最大的延时,最小的为2~4的45ps延时,其余的还有5的57ps延时,6的153ps延时为cin输入到和sumout输出延时和7的217ps延时为寄存器d输入到寄存器输出的延时。由此可见最坏情况,最终的测量误差由728ps决定。为了提高测量精度,可以考虑延时链从第二个延时单元开始,另外通过多通道测量取平均的方法以及Wave UnionB等方法亦可以进一步提升测量精度。
系统时钟clk250MHz后,为了保证能正确锁存待测信号s的边沿,要求延时链的总延时必须大于时钟周期4ns延时链中延时单元个数应该大于4/0.045 = 88个。图 6中的3~4完成了两位二进制加法,但是延时值只有一个45ps可知在图3的一个LABCELL内部的两个全加器的cincout的延时只有一个45ps这样每个LAB10LABCELL最大可以提供450ps的延时,所以延时链使用10LAB,共200加法器。
具体实现的思路:

图片5.png

图 7 获得200位长进位延时链的顶层原理图
各个模块的程序如下:
module l_add (
        input clock,
        input st1,
        output reg [199:0] result);

        always @(posedge clock )
        begin
                if(st1) result <= result + 2;
        end

endmodule


module r_add (
        input clock,
        input st1,
        output reg [199:0] result);

        always @(posedge clock )
        begin
                if(st1) result <= result + 6;
        end

endmodule

module add200 (
        clock,
        dataa,
        data_a,
        result);

        input          clock;
        input          [199:0]dataa,data_a;
        output        reg [199:0]  result;

        always @(posedge clock)
        begin
                 result <= dataa + data_a;
        end

endmodule


module o_add (
        input [199:0] result,
        output reg s_o);

        always @(result)
        begin
                 if(result > {{100{1'b1}},{100{1'b0}}}) s_o <= 1'b1; else s_o <= 1'b0;
        end

endmodule

其中的add200模块需要进行分区设定,逻辑区域锁定在一列上共10个LAB。最终的Chip Planner视图如图 8所示。

图片6.png


图 8 200位延时链的Chip Planner视图


图片7.png


图 9 输出分区信息1


图片8.png



图 10 输出分区信息2

经过图 9和图 10的操作,可以得到add200netlistrouting信息add200-inst.qxp重新建一个工程,添加add200作为设计的一个分区,使用图7Import Design Partion命令导入add200-int.qxp即可得到延时链。最终的超前进位延时链的原理图如图 11所示。
图片10.png

图 11 超前进位延时链

图 11与图 1 (b)的区别是,延时链输出中的0-1对应的输入s的下降沿。

1.3 边沿检测电路
时钟clk上升沿要锁存延时链输出中的0-11-0跳变,这种在时钟边沿处的跳变必定会违反触发器的时序约束关系,导致触发器的输出处于亚稳态状态,例如:“000011111”锁存后会出现“000101111”、“000010011”等情况,通过公式的上升沿检测电路可以抑制三位突变的情况并正确识别上升沿输出”000010000”

QQ截图20150210175205.png

其中r为边沿检测电路输出;d为锁存器输出;m为rd的总位数;k表示第几位。
源程序:
module ris_g (
        input [199:0] d,
        output reg [199:0] r);
   integer k;
        always @(d)
        begin
            r[0] <= ~d[0] & d[1];
                 r[1] <= ~d[0] & ~d[1] & d[2];
                 for(k=2;k<199;k=k+1)
                    r[k] <= ~d[k-2] & ~d[k-1] & ~d[k] & d[k+1];
                 r[199] <= 1'b0;
        end

endmodule
同理下降沿检测电路如公式所示。
QQ截图20150210180933.png

源程序:
module fal_g (
        input [199:0] d,
        output reg [199:0] f);
   integer k;
        always @(d)
        begin
            f[0] <= d[0] & ~d[1];
                 f[1] <= d[0] & d[1] & ~d[2];
                 for(k=2;k<199;k=k+1)
                    f[k] <= d[k-2] & d[k-1] & d[k] & ~d[k+1];
                 f[199] <= 1'b0;
        end

endmodule
1.4 编码器
边沿检测电路的输出最终为”…0001000…”的形式,1表示0-11-0跳变的位置。求出1的位置编号的方法主要MUX结构、Fat Tree结构、Wallace Tree结构和ROM结构,此处不对这些方法进行介绍和比较,从程序编写的难易程度、路径延时、资源使用上最终选择ROM结构的编码器

QQ截图20150210175317.png

其中rp编码器输出;i为位置编号;m为编码器输入的位数;OR表示或运算。
源程序:
        module encoder(
         input [199:0] srin,
         output [8:0] tenout        
        );
        integer i,k,j;
        reg cen_valid;
        reg [8:0] cen_tenout;
        reg [255:0] cen_srin;
   always @(srin)
        begin
        cen_srin = {{58{1'b0}},srin[199:2]};
        cen_tenout = {9{1'b0}};
        for(i=0;i<8;i=i+1)
                   for(k=0;k<2**(7-i);k=k+1)
                            for(j=(2**i)*(2*k+1)-1;j<=(2**(i+1))*(k+1)-2;j=j+1)
                                      cen_tenout = cen_srin[j] | cen_tenout;
        end
        assign tenout = cen_tenout;
        endmodule



1.5总结
最终的顶层原理图:

图片13.png

图 12  系统顶层原理图

源程序:
module do_in (
   din,
        dataa,
        data_a);

        input          din;
        output          [199:0] dataa,data_a;
   assign dataa = {{199{1'b0}},din};
        assign data_a = {200{1'b1}};


endmodule

module n_counter (
        input clock,
        input st1,
        output reg [199:0] n);

        always @(posedge clock )
        begin
                if(st1) n <= n + 1;
        end

endmodule


module for_store (
   input clk,
   input [199:0] m_in,
        input [8:0] f_in,
        input [8:0] r_in,
        output reg wr,
        output reg [255:0] d_store);
        always @(posedge clk)
        begin
           if(f_in  && r_in ) begin   d_store <=  f_in - r_in; wr <= 1'b1; end
                else begin
                if(r_in) begin  d_store <= (m_in << 9) + f_in - r_in; wr <= 1'b1; end         
           else wr <= 1'b0;        
                end

        end


endmodule

// synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
module d_fifo (
        data,
        rdclk,
        rdreq,
        wrclk,
        wrreq,
        q,
        rdempty,
        wrfull);

        input        [255:0]  data;
        input          rdclk;
        input          rdreq;
        input          wrclk;
        input          wrreq;
        output        [255:0]  q;
        output          rdempty;
        output          wrfull;

        wire [255:0] sub_wire0;
        wire  sub_wire1;
        wire  sub_wire2;
        wire [255:0] q = sub_wire0[255:0];
        wire  rdempty = sub_wire1;
        wire  wrfull = sub_wire2;

        dcfifo        dcfifo_component (
                                .data (data),
                                .rdclk (rdclk),
                                .rdreq (rdreq),
                                .wrclk (wrclk),
                                .wrreq (wrreq),
                                .q (sub_wire0),
                                .rdempty (sub_wire1),
                                .wrfull (sub_wire2),
                                .aclr (),
                                .rdfull (),
                                .rdusedw (),
                                .wrempty (),
                                .wrusedw ());
        defparam
                dcfifo_component.intended_device_family = "Cyclone V",
                dcfifo_component.lpm_numwords = 256,
                dcfifo_component.lpm_showahead = "OFF",
                dcfifo_component.lpm_type = "dcfifo",
                dcfifo_component.lpm_width = 256,
                dcfifo_component.lpm_widthu = 8,
                dcfifo_component.overflow_checking = "ON",
                dcfifo_component.rdsync_delaypipe = 4,
                dcfifo_component.underflow_checking = "ON",
                dcfifo_component.use_eab = "ON",
                dcfifo_component.wrsync_delaypipe = 4;


endmodule

系统的250MHz的时钟可以使用一个PLL生成,最终的输出结果,可以由Nios II或者ARM进行读取按照公式进行计算得到结果,所以在时间数字转换器和CPU之间必须增加一个FIFO来实现异步时钟的读写。另外:
1. FIFO长度和连续测量的次数有关,此处可以缩小至所期望的,不需要256个存储空间
2. 最终的准确计算结果应该对tf和tr进行除以2修正,因为在芯片一个LABCELL中两个全加器只有一个延时值。
3. 从测量的角度来看,采用多通道测量最后求平均可以进一步提升测量精度。





回复评论 (12)

写的真规整,好榜样啊,亚历山大
生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙 =================================== 做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
点赞  2015-2-10 20:30
一看就是老手
跟着学习
电工
点赞  2015-2-11 08:39
您的do_in模块不会被编译器给优化掉吗?应该如何修改编译选项吗?
点赞  2016-3-29 09:58
资料很全,感谢楼主分享!
点赞  2016-4-30 22:11
赞啊
点赞  2016-7-21 16:19
收藏
点赞  2017-4-27 15:07
这个是 wave union A 还是 B 实现? 没有看到 双沿切割啊
点赞  2017-7-23 07:57
赞,谢谢分享。
点赞  2017-8-4 17:00
点赞
点赞  2018-4-24 17:23
谢谢分享喔
点赞  2018-9-28 22:29
有对应的TDC 的fpga时序仿真就比较好了
点赞  2018-9-30 16:06
这种温度和器件对结果影响还是比较大的,  没有自校准电路.
点赞  2018-10-8 20:26
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复