加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

从电路到Verilog | 熟读语言要素,不会编程也懂verilog

2016/08/09
27
  • 1评论
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

 

前面不知道施主们感觉到没有,老僧一直在把大伙儿从电路往 Verilog 语言上拉。这才是正路,很多人却不晓得,可悲啊。


前面学到的语言要素已经可以支持基本的、工程中的数字逻辑系统设计了。我们所缺少的就是算法和经验。算法这个东东呢,需要数学知识,所谓的“熟读唐诗三百首,不会作诗也会吟”;经验的来源是实践,包括对芯片外围的理解,这是“读万卷书不如行万里路”。这些实践包含按键与复位处理、多时钟域处理等,《玩转 IP core》/《IP 核芯志》里面介绍过的内容,也有老衲以前忽略的可变移位和有限状态机设计问题。对于后面两个问题,这里来个“亡羊补牢,为时不晚”。


1. 变宽移位,流水实现
这一讲呢,老衲不务正业了。给大伙儿讲一下,如何实现移位位数可变的移位操作。
在前面关于移位操作的内容里面,那是千叮咛万嘱咐啊:移位的位数必须是常数。大多数人被这个说法迷惑了,认为可变位数的移位操作是不可实现的,是数字逻辑界的永动机。其实这是误解,想想人家 CPU 里面早就可以实现这个功能了。他们可以,我们也自然可以,不可妄自菲薄。鄙人,在这里就要和大家一起突破一下这个语言的限制了,所谓:语言是死的,人是活的。语言上说不成,仅仅是说不能直接用语言 ---- 或者说,简单的电路 ---- 实现这个功能。换句话说,需要用更加复杂的电路来实现,需要用复杂到综合软件无能为力的电路来实现。


然后,会被联系到的实现变量位数移位方法就是:每次移位 1 比特直至移到需要的位数位置。这个属于时序电路的实现了,有流水方法和时分复用方法两种。具体讨论,如果真的象上面的算法,那么根据需要移位的位数的不同,输出结果的时刻是不一样的。一般时序电路完成的操作不喜欢时快时慢的结果输出,可能需要插入一些无效的时序来达到输出时刻的统一。


存在很大的难度,至少老衲目前还没想通如何实现。下来是揭晓正规答案的时候了,请看图 6.15。这个设计还利用了移位操作的分配率,即:


 
以及 shift_width 的二进制编码特性。这样,
这个权值操作,对于时分复用也是可以采用的,可以节约处理时延。


图 1 流水线、带权值移动的对应电路


对应代码如例 1 所示。


【例 1】流水线、带权值移动的对应代码
module variable_shift_pipeline
  (
    input CLK, input RST,
    input[7:0] a,
    input[2:0] shift_width,
    output[7:0] shifted_a
  );

//Definition for Variables in the module
wire[2:0] width_0;
reg[1:0]  width_1;
reg       width_2;
//Shift_width chain
wire[7:0] a0;
reg[7:0]  a1, a2, a3;
//Operates chain

//Load other module(s)
               
//Logical
assign a0 = a;
assign width_0 = shift_width;
assign shifted_a = a3;

always @(posedge CLK or negedge RST)
//Shift_width chain
begin
   if (!RST)
   //Reset
   begin
       width_1 <= 2'b00;
       width_2 <= 1'b0;
   end
   else
   begin
       width_1 <= width_0[2:1];
       width_2 <= width_1[1];
   end
end

always @(posedge CLK or negedge RST)
//Operation
begin
   if (!RST)
   begin
       a1 <= 8'h0;
   end
   else
   begin
       if (width_0[0])
       begin
           a1 <= a0 << 1;
       end
       else
       begin
           a1 <= a0;
       end
   end
end

always @(posedge CLK or negedge RST)
//Operation
begin
   if (!RST)
   begin
       a2 <= 8'h0;
   end
   else
   begin
       if (width_1[0])
       begin
           a2 <= a1 << 2;
       end
       else
       begin
           a2 <= a1;
       end
   end
end

always @(posedge CLK or negedge RST)
//Operation
begin
   if (!RST)
   begin
       a3 <= 8'h0;
   end
   else
   begin
       if (width_2)
       begin
           a3 <= a2 << 4;
       end
       else
       begin
           a3 <= a2;
       end
   end
end

endmodule

 


2. 有限状态,同步变化

数学家,以及很像数学家的理论物理学家,孜孜不倦地追求统一场论,至今未遂。数字逻辑领域,倒是得到了一个统一的模型,这就是有限状态机(Finite-state machine,FSM)。理论上,所有数字逻辑电路系统都可以被看做这个状态机的一个实例。所以呢,这一讲在下给大家详细介绍有限状态机。


欲了解有限状态机,必先了解状态转移图;欲了解状态转移图,必先知道图中各个单元和文字的含义。图 2 是一个学生在上课的状态转移图,假设到校后上四节课,之后放学;再到校,再上四节课,再放学;如此往复。图里面的一个圆圈就是一个状态,圆的上方的文字是状态名称,下方是该状态对应的操作。例如,状态“上课”的操作就是“听讲”。如果圆的下方没有文字,就是没有具体操作。带有箭头的曲线代表状态的转移,线上的文字是状态转移的条件。例如,“到校”后,听到“打铃”就开始“上课”。如果线上没有文字,则表示无条件转移。状态转移的节拍,就是系统输入时钟的周期。


图 2 学生上学的状态图


忽略复杂的数学理论,直接介绍有限状态机实现。有限状态机,对于实现非常重要的抽象模型图图分享给给为施主,见图 3。


图 3 有限状态机的抽象模型


莫急莫急,这就到了一段、两段、三四段的介绍了。什么叫四段啊?看看,被你催的,一着急敲错了。


所谓“一段式”如就是“不管三七二十一”,把所有逻辑写到一起。这种风格,可以借用程序语言里面的一个术语叫做“一团面条”。


“二段式”属于一种比“一段式”更加奇怪的做法。看图 6.19,二段式有两种方式。总结起来都属于乱来。按照排列组合 C_3^2=3,有三种配法:或者把“状态转移条件”和“状态”配对,或者让“状态”与“输出逻辑”结合,还有“状态转移条件”与“输出逻辑”的路数。还是那句话:不建议,不鼓励。


有限状态机的“三段式”描述方法。有限状态机 和其他设计一样,最好使用同步时序方式设计,以提高设计的稳定性,消除毛刺。状态机实现后,一般来说,状态转移部分是同步时序电路而状态的转移条件的判断是组合逻辑。三段式之所以比一段和二段式编码合理,就在于三段式编码将不同功能分别放到不同的 always 程序块中实现。这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。


说的很抽象,现在用一个实例的不同代码风格表演一下下。


“序列检测器可用于检测由二进制码组成的脉冲序列信号。当序列检测器连续收到一组串行二进制码后,如果这组序列码与检测器中预先设置的序列码相同,则输出 1,否则输出 0。这种检测的关键是必须收到连续的正确码,所以要求检测器必须对前一次接受到的序列码做记忆分析,直到在连续检测中所收到的每一位二进制码都与预置序列码对应相同。在检测过程中,只要有一位不相等都将回到初始状态重新开始检测。不考虑重叠的可能。”


为了真正达到可以实现的程度,再来细化一下输入输出和具体条件。先来定义同步字长度,就 4 比特吧。虽然没有任何实际价值,判决失误率很高;但是代码短一点,该有的全有了,更常的宽度也只是力气活了。还有输入是一个时钟周期,输入一个比特的数据,低比特在前面。如果匹配到同步字,才输出高电平“1”;其他时间,输出低电平“0”。


先设计系统的状态转移图,如图 3 所示。每次检测到一个比特,状态前进一次;没有检测到,则状态回退到空闲 /IDLE。


图 3 比特序列检测单元的状态转移图


例 2 是这个模块的二段式代码,例 3 是这个模块的三段式代码。

 


【例 2】比特序列检测单元的代码(二段式)
`define STATE_IDLE  0
`define STATE_BIT0  1
`define STATE_BIT1  2
`define STATE_BIT2  3
`define STATE_BIT3  4
//State defination
`define SYNC_CODE   4'b1001
//Sequence to be detected

module sequence_detect
  (
    input clk,
    input Reset,
    input data,
    output reg detected
  );

//Defination for Varables in the module
reg[3:0] state;

wire[3:0] detecting_sequnce;

//Logicals
//Combanitory logicals
assign detecting_sequnce = `SYNC_CODE;

//Timing
always @ (posedge clk or negedge Reset)
//Statement management part
begin
    if (!Reset)
    //Reset enable
    begin
        state <= `STATE_IDLE;
    end
    else
    //state change
    begin
        case (state)
            `STATE_IDLE:
            //Idle statement, waiting for bit 0
            begin
                if ( data == detecting_sequnce[0])
                //Bit 0 detected
                begin
                    state <= `STATE_BIT0;
                end
                else
                begin
                end
            end
           
            `STATE_BIT0:
            //Bit0 statement, waiting for bit 1 or return idle
            begin
                if ( data == detecting_sequnce[1])
                //Bit 1 detected
                begin
                    state <= `STATE_BIT1;
                end
                else
                //Return idle statement
                begin
                    state <= `STATE_IDLE;
                end
            end
           
            `STATE_BIT1:
            //Bit1 statement, waiting for bit 2 or return idle
            begin
                if ( data == detecting_sequnce[2])
                //Bit 2 detected
                begin
                    state <= `STATE_BIT2;
                end
                else
                //Return idle statement
                begin
                    state <= `STATE_IDLE;
                end
            end
           
            `STATE_BIT2:
            //Bit2 statement, waiting for bit 3 or return idle
            begin
                if ( data == detecting_sequnce[3])
                //Bit 2 detected
                begin
                    state <= `STATE_BIT3;
                end
                else
                //Return idle statement
                begin
                    state <= `STATE_IDLE;
                end
            end
           
            `STATE_BIT3:
            //Bit3 statement, return idle
            begin
            //Return idle statement
            state <= `STATE_IDLE;
            end
           
            default:
            begin
            //Return idle statement
            state <= `STATE_IDLE;
            end
        endcase
    end
end

always @ (posedge clk or negedge Reset)
//Output part
begin
    if (!Reset)
    //Reset enable
    begin
        detected <= 1'b0;
    end
    else if (`STATE_BIT3 == state)
    //Sequence detected
    begin
        detected <= 1'b1;
    end
    else
    //Idle and detecting
    begin
        detected <= 1'b0;
    end
end

endmodule

 


【例 3】比特序列检测单元的代码(三段式)
……
//Defination for Varables in the module
reg[3:0] state;
reg[3:0] next_state;
//State variables
……
//Timing
always @ (posedge clk or negedge Reset)
//Statement management part
begin
    if (!Reset)
    //Reset enable
    begin
        next_state <= `STATE_IDLE;
    end
    else
    //state change
    begin
        case (state)
            `STATE_IDLE:
            //Idle statement, waiting for bit 0
            begin
                if ( data == detecting_sequnce[0])
                //Bit 0 detected
                begin
                    next_state <= `STATE_BIT0;
                end
                else
                begin
                end
            end
           
            `STATE_BIT0:
            //Bit0 statement, waiting for bit 1 or return idle
            begin
                if ( data == detecting_sequnce[1])
                //Bit 1 detected
                begin
                    next_state <= `STATE_BIT1;
                end
                else
                //Return idle statement
                begin
                    next_state <= `STATE_IDLE;
                end
            end
           
            `STATE_BIT1:
            //Bit1 statement, waiting for bit 2 or return idle
            begin
                if ( data == detecting_sequnce[2])
                //Bit 2 detected
                begin
                    next_state <= `STATE_BIT2;
                end
                else
                //Return idle statement
                begin
                    next_state <= `STATE_IDLE;
                end
            end
           
            `STATE_BIT2:
            //Bit2 statement, waiting for bit 3 or return idle
            begin
                if ( data == detecting_sequnce[3])
                //Bit 2 detected
                begin
                    next_state <= `STATE_BIT3;
                end
                else
                //Return idle statement
                begin
                    next_state <= `STATE_IDLE;
                end
            end
           
            `STATE_BIT3:
            //Bit3 statement, return idle
            begin
            //Return idle statement
                next_state <= `STATE_IDLE;
            end
           
            default:
            begin
            //Return idle statement
                next_state <= `STATE_IDLE;
            end
        endcase
    end
end

always @ (posedge clk or negedge Reset)
//State part
begin
    if (!Reset)
    //Reset enable
    begin
        state <= `STATE_IDLE;
    end
    else
    //State change
    begin
        state <= next_state;
    end
end

……
endmodule


三段式比二段式多了一个 next_state 这个过渡的寄存器,其他写法非常类似。
其他课题还有很多,等到施主遇到的时候,在单独讨论好了。


这正是:

工程问题万万千,理论知识无极限。系统设计百般变,电路描述有语言。
数学早有研究远,都会教材根本源。模式变化数字三,有限状态模型间。

与非网原创内容,谢绝转载!

系列汇总:

之一:温故而知新:从电路里来,到 Verilog 里去!

之二:Verilog 编程无法一蹴而就,语言层次讲究“名正则言顺”

之三:数字逻辑不容小窥,电路门一统江湖

之四:Verilog 语言:还真的是人格分裂的语言

之五:Verilog 不难学,聊聊时序逻辑那些事儿

之六:数字电路设计:有理论、有电路、有代码“三位一体”

相关推荐

电子产业图谱

本名:吴涛,通信专业博士,毕业后十多年从事无线通讯产品的研发工作。了解W-CDMA、TDS-CDMA和LTE的标准协议、接收机算法以及系统架构和开发。从事过关于W-CDMA的FPGA IP core设计工作,也完成过W-CDMA和TDS-CDMA的接收机理论研究和链路仿真工作。综合上面的工作,最终选择了无线通讯的系统设计和标准设计工作。目前拥有100多个已授权的发明专利,是某通讯行业标准文件的第一作者,亦有专利思想被写入3GPP协议。已出版FPGA设计专业著作《IP核芯志-数字逻辑设计思想》和《Verilog传奇-从电路出发的HDL代码设计》。