TA的每日心情 | 擦汗 2024-9-30 02:33 |
---|
签到天数: 444 天 连续签到: 1 天 [LV.9]以坛为家II
|
本帖最后由 独活草 于 2020-8-25 15:32 编辑
大概花了2天,静下心来去尝试理解PGL12G开发板官方提供的前三个实验的VerilogHDL代码,同时结合下载程序后板子的实际运行效果,尝试调整参数验证猜测;竟然取得一点成果,现将代码全注释给大家分享一下:***************************************************************************************************
实验1:流水灯
`timescale 1ns / 1ps //一般用在VerilogHDL编程最开始声明的地方,意思单位时间为1ns,精度为1ps
//如果后面要用到延时,#d 可以直接调用这个时间:#3就是延时3ns的意思
module led_test
(
sys_clk, // 系统时钟50Mhz
rst_n, //复位按钮,低电平有效
led // LED状态寄存器
);
//输入输出端口申明
input sys_clk;
input rst_n;
output [3:0] led;
reg [31:0] timer; //定义32位的计数器
reg [3:0] led; //定义4位LED状态寄存器
//0~ 49_999_999 1秒
//0~ 99_999_999 2秒
//0~149_999_999 3秒
//0~199_999_999 4秒
always@(posedge sys_clk or negedge rst_n) //每个时钟周期或者复位信号产生时
begin
if (~rst_n)//复位按钮松开时是高电平,按下时是低电平,此处取反
timer <= 32'd0;//复位时,把32位计数器清0
else if (timer == 32'd199_999_999)
timer <= 32'd0;//计数到第四秒,把32位计数器清0,重新计数
else
timer <= timer + 1'b1;//计数器做 +1 运算;
end
// LED control
always@(posedge sys_clk or negedge rst_n) //每个时钟周期或者复位信号产生时
begin
if (~rst_n)
led <= 4'b0000;//复位时,把4个LED置为低电平,点亮4个LED灯
else if (timer == 32'd49_999_999)
led <= 4'b0001; //计数到第1秒时,LED1熄灭;
else if (timer == 32'd99_999_999)
led <= 4'b0010; //计数到第2秒时,LED2熄灭;
else if (timer == 32'd149_999_999)
led <= 4'b0100; //计数到第3秒时,LED3熄灭;
else if (timer == 32'd199_999_999)
led <= 4'b1000;//计数到第4秒时,LED4熄灭;
end
endmodule
***************************************************************************************************
实验2:按键
module key_test
(
input sys_clk, //系统时钟 50Mhz
input [3:0] key_in, //按健,按下时为低电平,松开时高电平,默认为高电平
output[3:0] led //LED 低电平时点亮
);
reg[3:0] led_r; //定义第1阶段D锁存器
reg[3:0] led_r1; //定义第2阶段D锁存器
always@(posedge sys_clk )//每个时钟周期
begin
led_r <= ~key_in; //第1阶段锁存数据
end
always@(posedge sys_clk )
begin
led_r1 <= led_r; //第2阶段锁存数据
end
assign led = led_r1; //assign表示连续赋值,且被赋值的变量只能是wire型的
endmodule
//wire 表示直通,只要输入有变化,输出马上无条件地反映;reg 表示一定要有触发,输出才会响应输入
//reg 型变量,赋值只能在always块内部赋值;
//wire 使用在连续赋值语句中,reg使用在过程赋值语句中;默认类型
//wire 只能被assign连续赋值,reg只能在initial和always块内部赋值;
***************************************************************************************************
将实验2的代码改为下面可以实现同样的效果:
module key_test
(
input sys_clk,
input [3:0] key_in,
output[3:0] led
);
assign led = ~key_in; //赋值
endmodule
***************************************************************************************************
实验3:PLL
module pll_test
(
input sys_clk, //系统时钟50Mhz
input rst_n, //复位按钮,低电平有效
output clk_out //倍频或分频 输出的时钟信号 J9_Pin3
);
wire locked; //wire表示直通,只要输入有变化,输出马上无条件地反映
/////////////////////PLL IP 核调用////////////////////////////
clk_wiz_0 clk_wiz_0_inst //实例化clk_wiz_0
.clkin1 (sys_clk), // 50Mhz系统时钟导入
// 时钟信号输出端口
.clkout0 ( ), // OUT 200Mhz
.clkout1 ( ), // OUT 100Mhz
.clkout2 ( ), // OUT 50Mhz
.clkout3 (clk_out ), // OUT 25Mhz
//控制信号
.pll_rst (~rst_n ), // 复位
.pll_lock (locked ) // 锁住频率
);
endmodule
***************************************************************************************************
通过最近两天的学习,我大概理解 VerilogHDL 语言编程的目的是为了对一个具有输入输出的黑箱,其要实现某个运算目的而进行逻辑设计;
1、编程风格大概是先在 module 中申明定义好要用到的资源:输入、输出、IP核、中间变量(寄存器等);
2、然后编写在每个时钟周期或者复位信号产生时//always@(posedge sys_clk or negedge rst_n) 要进行的初始化或其他赋值操作;
3、实现运算的逻辑结构简单,常用的就是if-else;case(类似switch-case);
4、调用开发环境平台具有的一些IP核,需要多花时间去研究哪些私有变量是一定要赋值的。
|
|