mir_cs的个人空间 https://blog.eetop.cn/1826108 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

2024-08-06

已有 146 次阅读| 2024-8-6 11:11 |个人分类:一些设计概念探索|系统分类:芯片设计


序列检测

    定义:用于检测一段固定序列的单元,当输入符合这串序列直接拉高输出。

    分类:主要采用状态机实现,也有采用移位寄存器+比较器的方案。

    原理:以重复检测序列“101”为例,其本质是一个拥有4个状态的Moore状态机或拥有3个状态的Mealy状态机。(Moore状态机定义为输出仅与当前状态有关的状态机;Mealy状态机定义为输出既与当前状态有关,又与输入有关的状态机。)

        Moore状态机:设置4个状态。

        状态IDLE:初始状态,检测“101”的第1个“1”。输入为0,则下一状态仍为IDLE;若为1,则跳转至T1状态。

        状态T1:检测“101”中的第1个“0”。输入为0,则跳转至T2状态;若为1,则下一状态仍为T1。

        状态T2:检测“101”中的第2个“1”。输入为0,则为“100”,破坏了全部序列,跳转至IDLE状态;若为1,则跳转至ATV状态。

        状态ATV:输出为1。若输入为0,则跳转至IDLE状态;若输入为1,则跳转至T1状态。

            Snipaste_2024-08-06_10-51-17.png

        照着三段式状态机设计,参考代码如下。

verilog;toolbar:false">module sequence_detector_101_moore (
    //input
    clk             ,
    rstn            ,
    dat_i           ,
    //output
    active_o
);
// ------------------ PARAM ---------------------
    localparam  FSM_WD                              =   'd2;
    localparam  IDLE                                =   2'd0;
    localparam  T_1                                 =   2'd1;
    localparam  T_2                                 =   2'd2;
    localparam  ATV                                 =   2'd3;

// ------------------ IO -----------------------
    input                                           clk;
    input                                           rstn;
    input                                           dat_i;
    output reg                                      active_o;
// ------------------ WIRE ---------------------

// ------------------ REG ----------------------
    reg        [FSM_WD                    -1 :0]    cur_state_r                    ;
    reg        [FSM_WD                    -1 :0]    nxt_state_r                    ;
// ------------------ GVAR ---------------------

// ---------------- MAIN BODY ------------------
//--- FSM ----
    // cur_state_r
    always @(posedge clk or negedge rstn ) begin
        if( !rstn ) begin
            cur_state_r <= IDLE ;
        end
        else begin
            cur_state_r <= nxt_state_r ;
        end
    end
    // nxt_state_r
    always @(*) begin
                   nxt_state_r = IDLE ;
        case( cur_state_r )
            IDLE : nxt_state_r = dat_i ? T_1 : IDLE ;
            T_1  : nxt_state_r = dat_i ? T_1 : T_2  ;
            T_2  : nxt_state_r = dat_i ? ATV : IDLE ;
            ATV  : nxt_state_r = dat_i ? T_1 : IDLE ;
            default : nxt_state_r = IDLE ;
        endcase
    end
//--- OUTPUT ----
    always @(*) begin
        if( cur_state_r == ATV )
            active_o = 'd1;
        else
            active_o = 'd0;
    end

endmodule

        Mealy状态机:设置3个状态。将状态ATV取消,然后若状态T2输入为1,则令输出为1,跳转至IDLE状态;其他情况下输出均为0。状态图略。代码可类似设计,如下:

module sequence_detector_101_mealy (
    //input
    clk             ,
    rstn            ,
    dat_i           ,
    //output
    active_o
);
// ------------------ PARAM ---------------------
    localparam  FSM_WD                              =   'd2;
    localparam  IDLE                                =   2'd0;
    localparam  T_1                                 =   2'd1;
    localparam  T_2                                 =   2'd2;


// ------------------ IO -----------------------
    input                                           clk;
    input                                           rstn;
    input                                           dat_i;
    output reg                                      active_o;
// ------------------ WIRE ---------------------

// ------------------ REG ----------------------
    reg        [FSM_WD                    -1 :0]    cur_state_r                    ;
    reg        [FSM_WD                    -1 :0]    nxt_state_r                    ;
// ------------------ GVAR ---------------------

// ---------------- MAIN BODY ------------------
//--- FSM ----
    // cur_state_r
    always @(posedge clk or negedge rstn ) begin
        if( !rstn ) begin
            cur_state_r <= IDLE ;
        end
        else begin
            cur_state_r <= nxt_state_r ;
        end
    end
    // nxt_state_r
    always @(*) begin
                   nxt_state_r = IDLE ;
        case( cur_state_r )
            IDLE : nxt_state_r = dat_i ? T_1 : IDLE ;
            T_1  : nxt_state_r = dat_i ? T_1 : T_2  ;
            T_2  : nxt_state_r = IDLE ;
            default : nxt_state_r = IDLE ;
        endcase
    end
//--- OUTPUT ----
    always @(*) begin
        if( cur_state_r == T_2 )
            active_o = dat_i;
        else
            active_o = 'd0;
    end

endmodule

        代码的一些注意事项:

            有限状态机需要定义cur_state_r和nxt_state_r,前一个是时序固定写法,即!rstn重置,否则cur<=nxt;

            nxt则是组合逻辑,敏感列表是*,不受!rstn控制,里面只有一个case(cur)。为了避免综合出latch,case需要存在default分支。

    

        移位寄存器:简单向左移位就可以,同时与待测序列比较。

module sequence_detector_101_shift (
    //input
    clk             ,
    rstn            ,
    dat_i           ,
    //output
    active_o
);
// ------------------ PARAM ---------------------
    localparam  SEQ_WD                              =   'd3;
    localparam  TARGET                              =   3'b101;

// ------------------ IO -----------------------
    input                                           clk;
    input                                           rstn;
    input                                           dat_i;
    output reg                                      active_o;
// ------------------ WIRE ---------------------

// ------------------ REG ----------------------
    reg        [SEQ_WD                    -1 :0]    shift_r                    ;
// ------------------ GVAR ---------------------

// ---------------- MAIN BODY ------------------
    // shift_r
    always @(posedge clk or negedge rstn ) begin
        if( !rstn ) begin
            shift_r <= 'd0 ;
        end
        else begin
            if(active_o)
                shift_r <= {{SEQ_WD{1'b0}}, dat_i};
            else
                shift_r <= {shift_r[SEQ_WD - 'd1:0], dat_i} ;
        end
    end
//--- OUTPUT ----
    always @(*) begin
        if( shift_r == TARGET )
            active_o = 'd1;
        else
            active_o = 'd0;
    end

endmodule

        顺便练一下Python生成测试向量,写的很dumb,很多地方可以搞点格式化输出的:

import numpy as np

a = open("./data.txt", "w")
b = open("./ans.txt", "w")
b.write("0\n")

for i in range(0, 100):
    n = np.random.randint(low=0, high=8)
    n_b = bin(n)[2:]
    if len(n_b) == 1:
        n_b = "0\n0\n" + n_b + "\n"
    elif len(n_b) == 2:
        n_b = "0\n" + n_b[0] + "\n" + n_b[1] + "\n"
    else:
        n_b = n_b[0] + "\n" + n_b[1] + "\n" + n_b[2] + "\n"
    a.write(n_b)

a.close()
c = open("./data.txt", "r")
ck = c.readlines()
TAL = 0
for lines in ck:
    TAL = (TAL * 2 + int(lines[0])) % 8
    if TAL == 5:
        b.write("1\n")
        TAL = 0
    else:
        b.write("0\n")

        祖传testbench:

`timescale 1ns / 1ns

module tst_ripe_code;

// ------------------ IO -----------------------
    reg                                           clk;
    reg                                           rstn;
    reg                                           dat_i;
    wire                                          active_o;

// ------------------ WIRE ---------------------

// ------------------ REG ----------------------
    reg                                           result_soft;
// ------------------ GVAR ---------------------

// ------------------ INTEGAR ---------------------
  integer                                            fa;
  integer                                            fo;
  integer                                            flog_i;
  integer                                            flog_o;
  integer                                            ret;
  integer                                            tmp;

// ---------------- MAIN BODY ------------------
always #5 clk = ~clk;
initial begin
    rstn   = 'd0;
    clk   = 'd0;
    dat_i = 'd0;

    fa     = $fopen("./data/data.txt", "r");
    fo     = $fopen("./data/ans.txt", "r");
    flog_i = $fopen("./data/log_data.txt", "w");
    flog_o = $fopen("./data/log_ans.txt", "w");
   
    #10 rstn   = 'd1;
end
always @(negedge clk) begin
    if(rstn) begin
        ret = $fscanf(fa, "%b", dat_i);
        $fdisplay(flog_i, "%8d : %10d", $time, dat_i);
    end
end
always @(negedge clk) begin
    if(rstn) begin
        tmp = $fscanf(fo, "%b", result_soft);
        $fdisplay(flog_o, "%8d : %10d", $time, active_o);
        if(active_o != result_soft)
            $display("at %08d ns, %10d --> %10d", $time, result_soft, active_o);
    end
end

// ------------------ INST ---------------------
sequence_detector_101_moore test_module(
  // input
  .clk             (clk       ),
  .rstn            (rstn      ),
  .dat_i           (dat_i     ),
  // output
  .active_o        (active_o )
);

endmodule


Snipaste_2024-08-06_11-05-50.png


点赞

全部作者的其他最新日志

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 0

    粉丝
  • 0

    好友
  • 1

    获赞
  • 0

    评论
  • 1

    访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-9-27 11:56 , Processed in 0.020272 second(s), 8 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部