[SV]SystemVerilog学习笔记之有限状态机(FSM)

               SystemVerilog学习笔记之有限状态机(FSM)

 

一、有限状态机建模(FSM,finite state machine)

 1.1.    使用枚举类型建立状态机模型

  • 三过程块建模风格:三个过程块分别实现:

a.状态转换(always_ff)

b.产生下一状态(always_comb)

c.产生状态输出值(always_comb)

  • 使用枚举类型表示状态编码:通过定义enum类型决定状态位数;可显示指定label value
  • 使用枚举类型的反向case语句:对应ont-hot编码模式,条件选项是状态编码的某一位
  • 使用unique修饰case语句
  • 对于未使用的状态值(由状态变量宽度遍历产生):

Verilog:使用X作为缺省赋值,case语句中default:state = n’bxxx;  

SV:用unique case

  • 使用专用的综合full_case附注
  • 尽量使用enum list中的label,而不是具体value对枚举变量赋值
  • 对于enum变量的操作:

1.直接将int赋值给enum变量是非法的,要在操作后(赋值前)进行强制转换,将其转换为枚举类型。             

2.可使用枚举方法

 

1.2.    在FSM模型中使用两态数据类型

  • 容易出现死锁。解决方法:

1.使用logic显示声明enum          

2.使用always_comb

 

 1.3.    总结

  • unique case logic enum大法好

 

二、层次化设计

 2.1.模块原型

  • SV允许用户为被实例化的模块指定一个原型。原型的定义使用关键词extern
  • extern之后是模块及端口声明。 该声明只在其定义的范围内可见。
  •  若模块有extern module声明,则模块定义时无需重复端口声明,可用 .* 替代
  • Eg.
extern module counter #(parameter N = 15) (
  output logic [N:0] cnt,
  input wire [N:0] d,
  input wire clock,
  load,
  resetN
);
module counter ( .* );   //$unit中已使用原型定义,所以无需重复端口声明
  …  //模块内容

endmodule

 

 2.2.    命名的结束语句

  • 命名的模块结尾     eg.  endmodule : <module_name>
  • 命名的代码块结尾,见6.7,另外还有package...endpackage, interface...endinterface,task...endtask, function...endfunction, and begin...end

 

 2.3.    嵌套(局部)模块的声明

  • Eg. 模块(module)的嵌套定义
module ip_core (input clock);
  sub1        u1 (...); // 嵌套模块sub1实例化

  module sub1 (...);    // 嵌套模块定义(注意是在ip_core模块中嵌套定义,而非实例化)
    sub2        u2 ();    //在nested module sub1的定义中实例化sub2
    ...
  endmodule: sub1

  module sub2;               //嵌套模块定义。Sub2没有端口,但可看到其父模块源码中的标识符
    sub3     u3 (...);       //在nested module sub2的定义中实例化sub3
  endmodule: sub2

  module sub3 (...); //嵌套模块定义
    ...
  endmodule: sub3

endmodule: ip_core
  • Verilog中的模块名全部是全局的
  • SV为解决全局模块带来的可能模块间冲突及安全问题,提出了:

嵌套(局部)模块:Nested (local) module         

在模块内声明(local)模块

允许一个模块的定义嵌套在另一个模块的定义中,该模块在声明的层次域外不可见

 

2.4.    简化的模块实例网表

  • Verilog中两种连接模块实例的代码风格:
  1. 使用端口顺序连接模块实例 eg. dff d1 (out, /*not used*/, in, clock, reset);
  2. 使用端口名称连接模块实例 eg.
dff  d1(.q(out), 
        .qb(/*not used*/),    //.<端口名>(<线网
        .d(in), 
        .clk(clock), 
        .rst(reset) 
);                            // 或变量名>)
  • SV中有三种端口连接方法:
  1. .name() 端口连接
  2. .* 端口连接
  3. 接口(interface)

 

2.4.1.  .name端口连接

  • 当port_name = wire_name且宽度相同时,SV中可使用.name的方式连接模块实例
  • 相当于verilog中的.name(name)
  • Eg.
prom prom (
  .dout(program_data),
  .clk,                       //使用.name端口连接   
  .address(program_address)
);

 

2.4.2.  .* 端口连接

  • 用于表示模块实例中所有名称相同的端口和线网(或变量)是自动连接在一起的。
  • Eg.
prom prom (
  .*,                      //使用.*端口连接
  .dout(program_data),
  .address(program_address)
);

 

2.5.    线网别名化(alias)

  • SV使用alias表示两个不同名称对同一个线网的引用。
  • Eg.  
wire     clock, clk;         
alias    clk = clock ;        //clk和clock指的是同一个逻辑线网,不是赋值语句

alias支持多重别名化:alias rst = reset = resetN = rstN ;//一个拥有4个别名的逻辑线网

  • Rule:

进行别名化的两个线网类型及位数必须相同

只有线网类型可以别名化,变量不能别名化

(wire, uwire, wand, wor, tri, triand,trior, tri0, tri1, trireg.)

 

2.6.    在模块端口间传递数值

  • Verilog对模块端口的限制:

只有线网类型可以用在端口的输入端

只有net , reg , integer ,或文本整数值可以用在模块输出端口

通过模块端口传递real类型不合法,要先转换成向量来传递

模块端口间传递任何维数的非压缩数组是不合法的

  • SV中解除了这些限制:

任何类型都可以在模块的input/output端口,包括实数值

任何维数的压缩或非压缩数组都可以在端口间传递

Struct和union也可以在模块端口间传递

  • 未解除一些限制:

变量只能从单个源接收数值

端口两边的非压缩类型在结构上完全匹配(对于struct/union要求typedef相同)

(压缩值作为向量在端口间传递)

 

 2.7.端口引用(ref)(不可综合)

  • 相对于verilog的input/ouput/inout,SV增加了ref端口。
  • ref端口可以在端口间却传递一个对变量的层次化引用,而不是传递该变量值。
  • 对端口名称的任何引用都会直接引用实际的原变量。
  • 通过引用在端口间传递变量会生成共享变量,但在硬件行为却不是如此。

 

 2.8.增强的端口声明

  • SV相对于Verilog简化了端口说明的步骤:

SV制定了缺省的端口方向inout

若port list中下一个port定义了类型,但没有指定方向,那么默认端口的方向与前一端口一致

SV增加了两种可以带port ,interface和program的层次块,它们的端口声明同模块

如果第一个端口没有指定方向和类型,则其他端口也不能声明方向和类型

 

 2.9.参数化类型

  • 通过parameter type声明参数化的类型
  • Eg.
module adder #(parameter type ADDERTYPE = shortint) (//缺省情况下,参数类型是shortint
  input ADDERTYPE a, b, //可重定义类型
  output ADDERTYPE sum, //可重定义类型
  output logic carry
);

  ADDERTYPE temp; // 使用可重定义类型的局部变量
  ...             // 加法器功能

endmodule


module big_chip( ... );
  shortint a, b, r1;
  int c, d, r2;
  int unsigned e, f, r3;
  wire carry1, carry2, carry3;

  adder i1 (a, b, r1, carry1);//16位无符号加法器

  adder #(.ADDERTYPE(int)) i2 (c, d, r2, carry2); //重新定义参数类型,32位有符号加法器

  adder #(.ADDERTYPE(int unsigned)) i3 (e, f, r3, carry3); //32位有符号加法器

endmodule

三、参考文献

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

元直数字电路验证

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值