视频:https://www.bilibili.com/video/BV14K4y1u7kH/
资料:https://www.aliyundrive.com/s/E9H7Mc5hqhu
GVIM官方的四种操作模式
本课程至简设计法将GVIM分为三种模式:
三种模式的转化方法
编辑模式下使用,Ctrl+P
命令模式下使用,文件内跳转命令,有4种命令
gg
:跳转到文件的第一行G
:跳转到文件的最后一行:100
:跳转到文件的第100行``
:回到跳转前的那一行命令模式下使用,有4种搜索命令
*
:光标移动到某一单词处,按下*
会高亮本文件中所有该单词n
:使用*
命令或者/
之后,按下n
,会跳转到下一个匹配的单词处N
:使用*
命令或者/
之后,按下N
,会跳转到上一个匹配的单词处/ABC
:在文本中查找所有ABC
,并且高亮删除命令,在命令模式下使用
dd
:删除当前行d3d
:删除从当前行开始一共3行其他删除方法:鼠标选中之后,按下Delete
。此方法在命令模式和编辑模式均可以使用。
复制命令
yy
:复制当前行y3y
:复制从当前行开始一共3行粘贴命令:p
:%s/xx/yy/g
:文件所有xx替换成yy
:%s/xx/yy/gc
:文件所有xx替换成yy,但是每次替换需要按下y确认替换
:329,339s/cnt/cnt0/g
:文件329行到339行中,所有cnt替换成cnt0
:329,339s/cnt/cnt0/gc
,文件329行到339行中,所有cnt替换成cnt0,但是每次替换需要按下y确认替换
列删除的操作步骤
Ctrl+q
,进入列操作模式Delete
进入列操作模式的另一种方法
Ctrl+Q
进入列操作模式列插入的操作步骤
Ctrl+q
,进入列操作模式I
Esc
列复制与列粘贴的操作步骤
需要先对GVIM的配置文件进行更改,此操作只用做一次
在GVIM的安装目录下的_vimrc
中添加以下代码
vmap <C-c> "+y
vmap " +c
vmap <C-v> c<ESC>"+p
imap <C-v> <C-r><C-o>+
Ctrl+q
,进入列操作模式Ctrl+C
Ctrl+V
module module_name(
clk ,
rst_n ,
//其他信号,举例dout
dout
);
//参数定义
parameter DATA_W = 8;
//输入信号定义
input clk ;
input rst_n ;
//输出信号定义
output[DATA_W-1:0] dout ;
//输出信号reg定义
reg [DATA_W-1:0] dout ;
//中间信号定义
reg signal1;
//组合逻辑写法
always@(*)begin
end
//时序逻辑写法
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
end
else begin
end
end
endmodule
// Shixu
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
end
else begin
end
end
// Shixu2
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
end
else if()begin
end
else if()begin
end
end
// Zuhe
always @(*)begin
end
// Zuhe2
always @(*)begin
if()begin
end
else begin
end
end
// Jsq
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = ;
assign end_cnt = add_cnt && cnt== ;
// Jsq2,仅仅支持到Jsq3
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0 <= 0;
end
else if(add_cnt0)begin
if(end_cnt0)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
end
assign add_cnt0 = ;
assign end_cnt0 = add_cnt0 && cnt0== ;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1 <= 0;
end
else if(add_cnt1)begin
if(end_cnt1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1== ;
// 命令模式下输入':call MDYJSQ()'
reg [ ():0] cnt2 ;
wire add_cnt2 ;
wire end_cnt2 ;
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
cnt2 <= 0;
end
else if(add_cnt2) begin
if(end_cnt2)
cnt2 <= 0;
else
cnt2 <= cnt2+1 ;
end
end
assign add_cnt2 = ();
assign end_cnt2 = add_cnt2 && cnt2 == ()-1 ;
//四段式状态机
//第一段:同步时序always模块,格式化描述次态寄存器迁移到现态寄存器(不需更改)
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//第二段:组合逻辑always模块,描述状态转移条件判断
always@(*)begin
case(state_c)
IDLE:begin
if(idl2s1_start)begin
state_n = S1;
end
else begin
state_n = state_c;
end
end
S1:begin
if(s12s2_start)begin
state_n = S2;
end
else begin
state_n = state_c;
end
end
S2:begin
if(s22s3_start)begin
state_n = S3;
end
else begin
state_n = state_c;
end
end
default:begin
state_n = IDLE;
end
endcase
end
//第三段:设计转移条件
assign idl2s1_start = state_c==IDLE && ;
assign s12s2_start = state_c==S1 && ;
assign s22s3_start = state_c==S2 && ;
//第四段:同步时序always模块,格式化描述寄存器输出(可有多个输出)
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
out1 <=1'b0 //初始化
end
else if(state_c==S1)begin
out1 <= 1'b1;
end
else begin
out1 <= 1'b0;
end
end
命令模式下,输入:call MDYZTJ(3,"S1","S2","S3",12,13,23,32,31)
parameter S1 = 0 ;
parameter S2 = 1 ;
parameter S3 = 2 ;
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
state_c <= S1 ;
end
else begin
state_c <= state_n;
end
end
always @(*) begin
case(state_c)
S1 :begin
if(s12s2_start)
state_n = S2 ;
else if(s12s3_start)
state_n = S3 ;
else
state_n = state_c ;
end
S2 :begin
if(s22s3_start)
state_n = S3 ;
else
state_n = state_c ;
end
S3 :begin
if(s32s2_start)
state_n = S2 ;
else if(s32s1_start)
state_n = S1 ;
else
state_n = state_c ;
end
default : state_n = S1 ;
endcase
end
assign s12s2_start = state_c==S1 && ();
assign s12s3_start = state_c==S1 && ();
assign s22s3_start = state_c==S2 && ();
assign s32s2_start = state_c==S3 && ();
assign s32s1_start = state_c==S3 && ();
`timescale 1 ns/1 ns
module testbench_name();
//时钟和复位
reg clk ;
reg rst_n;
//uut的输入信号
reg[3:0] din0 ;
reg din1 ;
//uut的输出信号
wire dout0;
wire[4:0] dout1;
//时钟周期,单位为ns,可在此修改时钟周期。
parameter CYCLE = 20;
//复位时间,此时表示复位3个时钟周期的时间。
parameter RST_TIME = 3 ;
//待测试的模块例化
module_name uut(
.clk (clk ),
.rst_n (rst_n ),
.din0 (din0 ),
.din1 (din1 ),
.dout0 (dout0 ),
.dout1 (dout1 )
);
//生成本地时钟50M
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
//产生复位信号
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE*RST_TIME);
rst_n = 1;
end
//输入信号din0赋值方式
initial begin
#1;
//赋初值
din0 = 0;
#(10*CYCLE);
//开始赋值
end
//输入信号din1赋值方式
initial begin
#1;
//赋初值
din1 = 0;
#(10*CYCLE);
//开始赋值
end
endmodule
// Reg4
reg [ 3: 0] ;
// Wire4
wire [ 3: 0] ;
// Input4
input [ 3: 0] ;
// Output4
output[ 3: 0] ;
initial begin
#1;
end
针对波形的规则:时钟上升沿看信号,看到的是信号变化前的值。
该方法使用的前提是:所有信号都是同步信号且波形是理想的波形。
计数器设计是FPGA设计的核心,计数器架构是FPGA设计最常用的架构之一,也是至简设计法的核心部分。
计数器一般包括三段
计数器模板如下
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin // 加1条件
if(end_cnt) // 结束条件
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = ; // 此处定义加1条件
assign end_cnt = add_cnt && cnt== ; // 此处定义结束条件
计数器设计规则1:计数器要考虑三要素:初值、加1条件和结束值。
计数器设计规则2:计数初始值必须为0
计数器设计规则3:只有加1条件有效时,才能表示计数器的计数值
add_cnt&&cnt==x-1
表示计数器计数到 x个。这是结束条件为什么要像模板那样设计的原因。这个表达式代表某一个瞬间。cnt==x-1
不能表示计数器计数到x个。这个表达式代表一段时间。计数器设计规则4:结束条件必须同时满足加1条件,且结束值必须是x-1的形式;
计数器设计规则5:当取某个数时,assign形式必须为:(加1条件)&&(cnt==计数值-1);
计数器设计规则6:计数结束后,计数器的值必须恢复默认值 0;
计数器设计规则7:若需要限定范围,推荐使用“>=”和“<”两种符号;
计数器设计规则8:设计步骤是,先写计数器的always段,条件用名字代替;然后用assign写出加1条件;最后用assign写出结束条件。
计数器设计规则9:加1条件必须与计数器严格对齐,其他信号一律与计数器对齐。
计数器设计规则10:命名必须符合规范,比如:add_cnt表示加1条件;end_cnt表示结束条件。
计数器设计规则11:减 1计数器暂时不用。
要用减1计数器也应该像如下方式使用
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin // 加1条件
if(end_cnt) // 结束条件
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = ; // 此处定义加1条件
assign end_cnt = add_cnt && cnt== 8-1; // 此处定义结束条件
assign cnt_1 = 7-cnt
状态机时数字电路设计中的一个非常重要组成部分,也是贯穿于整个设计始终的最基本设计思想和设计方法。
其实计数器本质上也可以认为是一个状态机,只不过计数器用数字来区分不同状态而已。
何时使用计数器,何时使用状态机呢?
规范的状态机代码可以极大地提高设计效率,在减少状态出错可能的同时缩短调试时间,从而设计出稳健的系统。
状态机的模板如下
//四段式状态机
//第一段:同步时序always模块,格式化描述次态寄存器迁移到现态寄存器(不需更改)
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//第二段:组合逻辑always模块,描述状态转移条件判断
always@(*)begin
case(state_c)
IDLE:begin
if(idl2s1_start)begin
state_n = S1;
end
else begin
state_n = state_c;
end
end
S1:begin
if(s12s2_start)begin
state_n = S2;
end
else begin
state_n = state_c;
end
end
S2:begin
if(s22s3_start)begin
state_n = S3;
end
else begin
state_n = state_c;
end
end
default:begin
state_n = IDLE;
end
endcase
end
//第三段:设计转移条件
assign idl2s1_start = state_c==IDLE && ;
assign s12s2_start = state_c==S1 && ;
assign s22s3_start = state_c==S2 && ;
//第四段:同步时序always模块,格式化描述寄存器输出(可有多个输出)
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
out1 <=1'b0 //初始化
end
else if(state_c==S1)begin
out1 <= 1'b1;
end
else begin
out1 <= 1'b0;
end
end
状态机规则1:使用四段式写法。
状态机规则2:四段式状态机第一段写法不变。
状态机规则3:第二段的状态转移条件用信号来表示。
状态机规则4:用 assign将状态转移条件写成 XX2XX_start的形式。
状态机规则5:assign定义状态转移条件信号时,必须加上当前状态。
状态机规则6:状态不变时使用 state_n = state_c。
至简设计法在实际项目经验中总结得出了一般模块端口的信号规范。
FIFO,即先入先出队列。
在计算机中先进先出队列是一种传统的按序执行方法,先完成并引退先进入的指令,随后跟着执行第二条指令。
在数字电路设计中提到的FIFO实际是指FIFO存储器,其主要应用于数据缓存和异步处理。FIFO存储器缓存数据也遵循先进先出的原则。
FIFO本质上是一个RAM,其与普通存储器的区别是没有外部读/写地址线。FIFO存储器只能顺序的写入数据,再顺序的读取数据,其数据地址由内部读写指针自动加1完成。
本教程没有使用到FIFO存储器,但是FIFO存储器再实际工程中有大量的应用。
FIFO规则 1:使用 Show-ahead读模式。
FIFO读操作一般有两种模式:Normal和Show-ahead模式。
Normal模式是读使能生效后的下一拍读出相应的数据。如下图所示:
Show-ahead模式是先进行数据输出,在读使能有效时对FIFO输出数据进行更新。即FIFO中的第一个数据输出在总线上,在读使能信号到来的下一拍直接输出第二个数据。如下图所示
FIFO规则 2:读写隔离规则。
FIFO的读写控制是独立的,两者之间除了共同FIFO进行信息操作外,不能有任何信息传递。
举例
FIFO规则 3:读使能必须判断空状态,并且用组合逻辑产生。
FIFO规则 4:处理报文时,把指示信号与数据一起存入 FIFO。
FIFO规则 5:读写时钟不同时,必须用异步 FIFO。