文章目录

  • 任意序列检测器
  • 简介
  • 用python自动生成verilog任意序列检测器代码与状态转换图
  • 自动生成的状态转换图代码
  • 自动生成的verilog代码


任意序列检测器

简介

上一节(链接见1)我们讲了如何生成一个m序列。m序列作为伪随机数发生器,自然可以设计一个与之配套的任意序列检测器。其思路为使用有限状态机,一旦序列与对应的模式序列相匹配,则状态加一,否则状态将会下降(具体如何下降此处不予赘述,详请复习《数字电路》)。当状态满了就会输出1,表示检测到对应的模式序列。

对于任意序列检测器,有着许多细节而琐碎的问题。例如如何进行状态化简(使用最少的D触发器)、竞争冒险毛刺如何规避、检测到对应的模式序列后是应当从0开始还是保留状态(两者皆可,根据不同的需求设计)等。限于时间与篇幅,此处不予赘述。本文的核心在于代码与实现


本文均以序列11001010为例


用python自动生成verilog任意序列检测器代码与状态转换图

运行如下python代码(如果想要其他序列,只需要改第二行python代码series的值即可):

# 全局变量
series = "11001010"  # 要生成的序列
state_jump = [[0 for i in range(2)]for i in range(len(series)+1)]  # 状态转换表

# 函数功能:计算state_jump[row][col]的值并返回
# 输入参数:row     为  state_jump列表的行数
#         :col     为  state_jump列表的列数
#         :series  为  待判断字符数组
# 输出参数:state_jump[row][col]
# 说    明:当前值int(series[0:row-1].append(str(col)), 2)
#         :待匹配值int(series[0:row], 2)
def cal_state_jump(row, col, series):
    temp_now = int(series[0:row]+str(col), 2)
    temp_aim = int(series[0:(row+1)], 2)
    divisor = 2 ** row
    for i in range(row+1):  # 0 -> (row)
        if (temp_now == temp_aim):  # 匹配
            return (row+1-i)
        temp_aim = temp_aim // 2
        temp_now = temp_now % divisor
        divisor = divisor // 2
    return 0

#state = ["s0"]  # 状态机
# 函数功能:计算state_jump[row][col]的值并直接修改列表
#def cal_change_state():
#    for i in range(len(series)):
#        state.append("s"+str(i+1))

# 函数功能:计算二维列表state_jump的值并直接修改列表
# 输入参数:way     为  状态机执行方式
# 说    明:way为0      代表 每次检测出后均归0
#         :way为其余值 代表 每次检测出继续计数
def cal_change_state_jump(way):
    for i in range(len(series)+1):
        if i != len(series):
            for j in range(2):
                state_jump[i][j] = cal_state_jump(i,j,series)
        else:
            if way == 0:  # 每次检测出后均归0
                if j == int(series[0]):
                    state_jump[i][j] = 1
                else:
                    state_jump[i][j] = 0
            else:  # 每次检测出继续计数
                state_jump[i][j] = cal_state_jump(i,j,series+str(1-j))

# 函数功能:生成有限状态机图
def generate_FSM():
    cal_change_state_jump(0)
    print("// generate_code_start : FSM\n")
    
    print("digraph finite_state_machine {")
    print("	rankdir=LR;")  # LR:从左到右;TB:从上到下
    # print("	size=\"8,5\"")
    print("	node [shape = circle];")
    for j in range(2):
        for i in range(len(series)+1):
            print("	s%d -> s%d [ label = \"%d\" ];" %(i,state_jump[i][j],j))
    print("}")
    
    print("// generate_code_end : FSM\n")

# 函数功能:把十进制数转2进制字符串并补0
# 输入参数:num     为  待转换十进制数
#         :length  为  补0后长度
# 输出参数:2进制字符串
def dec2bin(num,length):
    temp_str = str(length)+'\'b'
    for i in range(length+2-len(bin(num))):
        temp_str += '0'
    temp_str += bin(num)[2:]
    return temp_str

# 函数功能:生成verilog代码
def generate_verilog():
    length = len(bin(len(series)))-2  # FSM的D触发器数量
    cal_change_state_jump(0)
    print("// generate_code_start : verilog\n")

    print("`timescale 1ns / 1ns")
    print("module check(")
    print("	input wire clk,")
    print("	input wire rst_n,")
    print("	input wire checkQ,\n")
    print("	output wire is_series")
    print("    );\n")
    print("	reg[3:0] now_state;\n")
    print("	parameter",end = '\r')
    for i in range(len(series)):
        print(" s%d = %s" %(i,dec2bin(i,length)) ,end=',')
    print(" s%d = %s;\n" %(len(series),dec2bin(len(series),length)))
    print("	assign is_series = (now_state == s%d);\n" %(len(series)))
    print("	always @(posedge clk or negedge rst_n) begin\n")
    print("		if (rst_n == 0) begin  // negedge rest")
    print("			now_state <= 0;")
    print("		end\n")
    print("		else begin")
    print("			casex(now_state)")
    for i in range(len(series)):
        print("				s%d: begin" %(i))
        print("					if(checkQ == %s) now_state <= now_state + 4'b0001;" %(series[i]))
        print("					else now_state <= s%d;" %(state_jump[i][1-int(series[i])]))
        print("				end")
    print("				s%d: begin" %(len(series)))
    print("					if(checkQ == 0) now_state <= s%d;" %(state_jump[len(series)][0]))
    print("					else now_state <= s%d;" %(state_jump[len(series)][1]))
    print("				end")
    print("				default: now_state <= s0;")
    print("			endcase")
    print("		end\n")
    print("	end\n")
    print("endmodule\n")

    print("// generate_code_end : verilog\n")

# main函数
if __name__ == "__main__":
    generate_FSM()
    generate_verilog()

运行结果如下:

python数据仿真 python仿真verilog_自动生成

python数据仿真 python仿真verilog_自动生成_02

其中第一部分代表自动生成的用dot234状态转换图绘制的代码,第二部分代表自动生成的Verilog代码。
如果需要graphviz-2.38.msi文件,可以用该百度云链接下载
链接:https://pan.baidu.com/s/1ddjYwUiEqsB-T5ttlYTx6Q
提取码:0721
复制这段内容后打开百度网盘手机App,操作更方便哦)

自动生成的状态转换图代码

这部分是python自动生成的用dot234状态转换图绘制的代码:

如果需要graphviz-2.38.msi文件,可以用该百度云链接下载
链接:https://pan.baidu.com/s/1ddjYwUiEqsB-T5ttlYTx6Q
提取码:0721
复制这段内容后打开百度网盘手机App,操作更方便哦)

digraph finite_state_machine {
	rankdir=LR;
	node [shape = circle];
	s0 -> s0 [ label = "0" ];
	s1 -> s0 [ label = "0" ];
	s2 -> s3 [ label = "0" ];
	s3 -> s4 [ label = "0" ];
	s4 -> s0 [ label = "0" ];
	s5 -> s6 [ label = "0" ];
	s6 -> s0 [ label = "0" ];
	s7 -> s8 [ label = "0" ];
	s8 -> s0 [ label = "0" ];
	s0 -> s1 [ label = "1" ];
	s1 -> s2 [ label = "1" ];
	s2 -> s2 [ label = "1" ];
	s3 -> s1 [ label = "1" ];
	s4 -> s5 [ label = "1" ];
	s5 -> s2 [ label = "1" ];
	s6 -> s7 [ label = "1" ];
	s7 -> s2 [ label = "1" ];
	s8 -> s1 [ label = "1" ];
}

用Graphix(具体操作见234)画出的图像如下:

python数据仿真 python仿真verilog_verilog_03

自动生成的verilog代码

`timescale 1ns / 1ns
module check(
	input wire clk,
	input wire rst_n,
	input wire checkQ,

	output wire is_series
    );

	reg[3:0] now_state;

	parameter
 s0 = 4'b0000, s1 = 4'b0001, s2 = 4'b0010, s3 = 4'b0011, s4 = 4'b0100, s5 = 4'b0101, s6 = 4'b0110, s7 = 4'b0111, s8 = 4'b1000;

	assign is_series = (now_state == s8);

	always @(posedge clk or negedge rst_n) begin

		if (rst_n == 0) begin  // negedge rest
			now_state <= 0;
		end

		else begin
			casex(now_state)
				s0: begin
					if(checkQ == 1) now_state <= now_state + 4'b0001;
					else now_state <= s0;
				end
				s1: begin
					if(checkQ == 1) now_state <= now_state + 4'b0001;
					else now_state <= s0;
				end
				s2: begin
					if(checkQ == 0) now_state <= now_state + 4'b0001;
					else now_state <= s2;
				end
				s3: begin
					if(checkQ == 0) now_state <= now_state + 4'b0001;
					else now_state <= s1;
				end
				s4: begin
					if(checkQ == 1) now_state <= now_state + 4'b0001;
					else now_state <= s0;
				end
				s5: begin
					if(checkQ == 0) now_state <= now_state + 4'b0001;
					else now_state <= s2;
				end
				s6: begin
					if(checkQ == 1) now_state <= now_state + 4'b0001;
					else now_state <= s0;
				end
				s7: begin
					if(checkQ == 0) now_state <= now_state + 4'b0001;
					else now_state <= s2;
				end
				s8: begin
					if(checkQ == 0) now_state <= s0;
					else now_state <= s1;
				end
				default: now_state <= s0;
			endcase
		end

	end

endmodule


  1. https://zhuanlan.zhihu.com/p/138847719 ↩︎ ↩︎ ↩︎