文章目录
- 任意序列检测器
- 简介
- 用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()
运行结果如下:
其中第一部分代表自动生成的用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)画出的图像如下:
自动生成的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