第二次作业
一、 实验目的和要求
设计一个挂载在 APB 总线上的计数器,按照 APB 的时序给计数器赋值,主
机通过地址对计数器进行配置,通过数据输入端口给计数器设置计数器最大值,
并通过数据输出端口输出计数器的计数值。该设计还设置了一个计数完成信号,
当计数器满足模式配置后的计数要求时,会将该信号拉高。
二、 实验设计方法
该实验设计,设计了一个挂载在 APB 上的计数器,该计数器有两个模式,
模式 1 为一个从 0 计数到 300 的计数器,模式 2 为一个从 0 计数 cnt_MAX(主机
发送给计数器的计数最大值),通过 APB 总线中的 PADDR 信号获取模式配置,
然后计数器的输出到 APB 总线的读数据输出端口。
计数器模块示意图如下图 2-1 所示:
图 2-1:计数器模块
APB 模块示意图如下图 2-2 所示:
图 2-2:APB 模块
计数器中的 CM_cnt = Pwrdata[7:0],该信号的作用是给计数器分配模式,如果
CM_cnt[7]=1,且 CM_cnt[1:0]=00 时,计数器进入模式 1,即从 0 开始计数到计数
器内部最大值(这里规定的是 300);如果 CM_cnt[7]=1,且 CM_cnt[1:0]=01 时,
计数器进入模式 2,即从 0 开始计数到 cnt_MAX(这个值为主机发送给计数器,
本设计发送的是 100),cnt_MAX 与 Pwdata 相连,计数器的 cnt_done 信号是为
了便于观察仿真波形而设置的,该处不与 APB slave 相连,作为计数器的输出
cnt 与 Prdata 相连。其他 APB 的信号端口按照时序图给相应的输入。
以上两张图为代码设计中端口的输入和输出信号的命名,下面两张 APB 的时
序图为课件截图,他们信号的命名只有大小写的区别。
APB 写传输时序图如图 2-3 所示:
图 2-3:APB 写传输时序图
由 APB 写时序图可以得出:当 PWRITE、PSEL、PENABLE 信号都是高,且地
址信号输入有效地址的时候,PWDATA 信号输入开始有效,然后锁存写数据。
APB 读传输时序图如图 2-4 所示:
图 2-4:APB 读传输时序图
由 APB 读时序图可以得出:当 PWRITE 为低,PSEL 和 PENABLE 为高,且
PADDR 地址信号输入有效地址的时候,PRDATA 信号输出有效,驱动读数据总
线。
三、 实验结果与分析
按照设计方法编写 Verilog HDL 代码,并编写 testbench,在 quartusⅡ中进
行综合,用 modelsim 进行仿真,相应的 Verilog HDL 代码和 testbench 代码见附录。
首先是计数器模式 1:从 0 开始计数,计数到 300,发送计数完成信号,仿
真结果如下图 3-1 所示:
图 3-1:计数器模式 1 波形图
从波形图可以得出,,Paddr 为 32‘hffff_fff0 且 Pwdata[7]为 1 且 Pwdata[1:0],
即为计数器模式 1(计数器从 0 计数到 300);Psel,Penable 为高,Pwrite 为低,
即为 APB 读模式,Prdata 输出的是计数器的当前计数值,计数到 300 的时候重
新开始计数,功能符合
其次是计数器模式 2:从 0 开始技术,计数到主机给定计数器的值(这里给
的是 100),如图 3-2 所示,当 Psel、Penable、Pwrite 为高,即 APB 写模式的时
候,将 100 写入计数器中,这时 100 将作为计数器的最大值。
图 3-2
计数器为模式 2 波形图如下图 3-3 所示:
图 3-3:计数器模式 2 波形图
从上图可以得出,当 Psel、Penable 为高,Pwrite 为低,即 APB 读模式;
Pwdata[7]=1, Pwdata[1:0]=01,即模式 2。Prdata 输出计数器的当前值,计数到 100
的时候重新开始计数,功能符合。
附录:
module APB_Timer#(
APB_Timer 设计代码
parameter data_size = 32, CM_size = 8,cnt_max = 300//计数器最大值
)
(
);
input [data_size-1:0]Paddr,Pwdata,
input Psel,Penable,Pwrite,Prst_n,Pclk,
output reg [data_size-1:0]Prdata,
output reg cnt_done
reg [CM_size-1:0]CM_cnt;//计数器的控制端口,根据输入的数据来判断计数器的模式
选择
reg [data_size-1:0]cnt; //计数器
reg [data_size-1:0]cnt_MAX;//主机给计数器的最大值
reg [data_size-1:0]cnt_MAX_reg;
//reg [data_size-1:0]cnt_reg; //存储计数器的值,等待计数器的模式为模式 1 时使用
reg ini_cnt_done;//计数器赋值完成信号
reg CM_cnt_done;
reg [CM_size-1:0]CM_cnt_reg; //存储计数器模式赋值的值
//计数器模式赋值完成信号
//控制信号,数据传送
always@(posedge Pclk or negedge Prst_n)
if(!Prst_n)
begin
cnt_MAX_reg <= 0;
CM_cnt_reg <= 0;
ini_cnt_done <= 0;
CM_cnt_done <= 0;
Prdata <= 0;
end
else if(Pwrite == 1 && Psel == 1 && Penable == 1)
begin
if(Paddr == 32'hffff_fff1)//写计数器模式赋值配置
begin
CM_cnt_reg <= Pwdata[7:0];
CM_cnt_done <= 1;
ini_cnt_done <= 0;
end
else if(Paddr == 32'hffff_fff0)//给模式 2 主机给计数器指定最大计数器
begin
cnt_MAX_reg <= Pwdata;
ini_cnt_done <= 1;
CM_cnt_done <= 0;
else
end
begin
CM_cnt_done <= 0;
ini_cnt_done <= 0;
end
end
else if(Pwrite == 0 && Psel == 1 && Penable == 1)//读数据,将计数器的值从
APB 的数据输出端口输出
if(Paddr == 32'hffff_fff0)
begin
Prdata <= cnt;
CM_cnt_done <= 0;
ini_cnt_done <= 0;
end
else
begin
Prdata <= 0;
CM_cnt_done <= 0;
ini_cnt_done <= 0;
end
always@(posedge Pclk or negedge Prst_n)
if(!Prst_n)
begin
cnt <= 0;
CM_cnt <= 0;
end
else if(CM_cnt_done)
CM_cnt <= CM_cnt_reg;
else if(ini_cnt_done)
cnt_MAX <= cnt_MAX_reg;
else if(CM_cnt[7] == 1) //计数器开始计数
begin
if(CM_cnt[1:0] == 2'b00)//模式 1,计数器从 0 开始,计数到固定的最大
值
begin
if(cnt == cnt_max)
begin
cnt <= 0;
cnt_done <= 1;
else
end
begin
cnt <= cnt + 1;
cnt_done <= 0;
end
end
else if(CM_cnt[1:0] == 2'b01)//模式 2,计数器从 0 开始计数,计数到给
定的最大值
begin
if(cnt == cnt_MAX)
begin
cnt <= 0;
cnt_done <= 1;
else
end
begin
cnt <= cnt + 1;
cnt_done <= 0;
end
end
end
endmodule
`timescale 1ns/1ns
`define clk_period 20
module APB_Timer_tb;
//source define
testbench 测试功能代码
reg [31:0]Paddr,Pwdata;
reg Psel,Penable,Pwrite,Prst_n,Pclk;
//probe define
wire [31:0]Prdata;
wire cnt_done;
//instant user module
APB_Timer APB_Timer1(
.Paddr(Paddr),
.Pwdata(Pwdata),