2024年寒假练 - 用小脚丫FPGA套件STEP BaseBoard V4.0制作两位十进制加、减、乘、除计算器
该项目使用了小脚丫FPGA套件STEP BaseBoard V4.0,实现了两位十进制加、减、乘、除计算器的设计,它的主要功能为:运算数和计算结果通过8个八段数码管显示。每个运算数使用两个数码管显示,左侧显示十位数,右侧显示个位数。输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。。
标签
FPGA
小脚丫
计算器
ChanRa1n
更新2024-07-16
90

首先非常感谢电子森林的这次一起练活动,这也是我第三次参与硬禾的项目了,在前面几次项目中,因为访问量高,获得了电子森林赠送的口袋仪器(PS:确实挺好用),建议大家也都参与进来,好好完成,搞不好也会有奖励的!也欢迎大家访问我的博客:www.myfpga.cnimage.png


如PDF显示异常,推荐点击访问PDF版本:(公开)计算器FPGA软件设计说明与验证记录.pdf

内容简介                                                             

 

1.项目需求

根据提供的信息,项目要求独立完成一个两位十进制数的加、减、乘、除运算的计算器。运算数和运算符由按键控制,结果通过8个八段数码管显示。基本要求还包括输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。扩展要求则是使用TFTLCD代替数码管,并设计自定义的显示界面。

2. 需求分析

基于提供的硬件资源,我将使用Diamond 3.12来实现所有功能。同时,由于只需要对两位十进制数进行加减乘除运算,不涉及复杂表达式和不定长数值,故不需要使用栈来进行优先级匹配。因此,我首先需要设计一个状态机,根据按键输入来控制运算数和运算符的输入,然后进行运算,最后将结果显示在数码管上。

3.流程简述

输入控制->运算处理->结果显示 (数码管/TFTLCD)。

image.png


修订记录                                                

 

修改记录累积了每次文档更新的说明。最新版本的文档包含以前所有文档版本的更新内容。

 

文档版本 01 (2024-01-06)

第一次正式发布。

文档版本 02 (2024-01-15)

根据实物进行实物测试,修复了一些易用性方面的问题。

 

目录

1        范围...5

1.1     文档标识....5

1.2     文档综述....5

1.3     引用文档....5

1.4     环境....6

1.4.1       硬件环境....6

1.4.2       软件环境....8

1.5     技术要求....8

1.5.1       需求描述....8

1.5.2       接口定义....12

1.5.3       接口功能....13

1.5.4       功能描述....15

1.5.5       性能....16

1.6     质量控制....16

1.7     验收准则....16

2        详细设计...18

2.1     原理框图....18

2.2     模块化设计....18

2.2.1       例化调用....18

2.2.2       计算模块....21

2.2.3       数码管驱动模块....27

2.2.4       按键映射模块....34

2.2.5       矩阵键盘扫描模块....36

3        软件测试与验证...40

3.1     模块化测试记录....40

3.2     例化调用模块测试记录....40

3.3     计算模块测试记录....40

3.4     按键映射模块测试记录....45

3.5     数码管驱动模块测试记录....46

3.6     矩阵键盘扫描模块测试记录....46

3.7     资源占用情况....46

3.7.1       编译后占用情况....46

3.7.2       布局布线后占用情况....47

3.7.3       资源利用说明....47

4        需求验证...48

 

1    范围

1.1    文档标识

l  FPGA软件标识:MYFPGA_CN_FPGA_BASIC_YHJSQ;

l  本文档标识为:MYFPGA_CN_FPGA_BASIC_YHJSQ_SJSM_012;

l  软件版本由MyFPGA.SWS组织过程资产管理工具动态管理。

1.2    文档综述

本文档主要内容包括计算器FPGA软件的范围(由需求定义)、概要设计、详细设计、验证设计、验证记录和验收与交付等方面的内容。

1.3    引用文档

1.  (内部)项目管理部《民用FPGA软件配置管理2021》;

2.  (公开)苏州硬禾信息科技有限公司《原理图STEP-Baseboard-V4.0.pdf》;

3.  (公开)苏州硬禾信息科技有限公司《FPGA引脚定义.pptx》;

4.  (公开)苏州硬禾信息科技有限公司《小脚丫FPGA套件STEP BaseBoard V4.0》。

 

1.4    环境

本节详细描述了FPGA软件工作的硬件环境和软件环境。

1.4.1   硬件环境

FPGA软件工作的硬件环境主要包括以下几个关键组成部分:

1.  STEP BaseBoard V4.0: 这是一个FPGA扩展底板,具有丰富的板载资源,包括存储器、温湿度传感器、接近式传感器、矩阵键盘、旋转编码器、HDMI接口、RGBLCD液晶屏、数码管、蜂鸣器模块、UART通信模块、ADC模块、DAC模块和WIFI通信模块等。该底板的黄金比例尺寸为100mm*161.8mm,为数字逻辑、微机原理、可编程逻辑语言以及EDA设计工具等课程提供了完美的实验平台。

2.  STEP-MXO2-LPC核心模块: 作为FPGA学习平台的核心,采用了Type C接口,基于Lattice MXO2芯片。该核心模块具有较小的尺寸(52mm x 18mm),支持U盘模式下载,无需外部重新配置FPGA,适合初学者学习数字电路。

3.  硬件资源: FPGA核心模块采用了Lattice LCMXO2-4000HC-4MG132芯片,具有4320个LUT资源、96Kbit用户闪存、92Kbit RAM,2+2路PLL+DLL,支持DDR/DDR2/LPDDR存储器,104个可热插拔I/O等。板上资源还包括数码管、RGB LED、拨码开关、按键等,为用户提供丰富的输入输出接口。

image.png

图1.1 小脚丫硬件框图

 

1.4.2   软件环境

FPGA软件工作的软件环境主要包括以下几个关键组成部分:

1.  操作系统:Windows 11 22H2专业版(22621.2861)

2.  FPGA综合与布局布线工具: Diamond 3.12

3.  编程语言:Verilog与VHDL

4.  验证语言:SystemVerilog

5.  仿真工具:ModelSim 18.1

1.5    技术要求

本节详细描述了FPGA软件的技术要求,包括但不限于需求描述、接口定义、接口功能和性能等方面。

1.5.1   需求描述

原文需求描述                                                                         

1.基本要求:

运算数和计算结果通过8个八段数码管显示。每个运算数使用两个数码管显示,左侧显示十位数,右侧显示个位数。输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。

2.扩展要求:

使用TFTLCD来做显示,自行设计显示界面,代替数码管显示输入的参数、运算符以及计算后的结果。

 

定义范围(包含隐含需求)                                                                                         

1.      基本计算功能:

l  实现两位十进制数的加、减、乘、除运算。

l  通过4x4矩阵键盘输入运算数和运算符。

2.      数码管显示功能:

l  使用8个八段数码管显示输入的运算数和运算结果。

l  实现在输入两位十进制数时,最高位先在右侧显示,然后跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。

3.      TFTLCD显示功能(扩展要求):

l  设计自定义的TFTLCD显示界面,替代数码管显示。

l  显示输入的参数、运算符以及计算后的结果。

4.      状态机控制:

l  实现状态机来控制整个计算器的操作流程。

l  状态机应包括空闲状态、输入状态、运算状态、显示状态等。

5.      按键控制:

l  通过4x4矩阵键盘进行用户输入。

l  包括数字键、运算符键、等号键等。

6.      Web IDE支持:

l  使用思得普提供的Web IDE完成所有功能的开发。

7.      仿真验证:

l  对代码中的每个模块进行仿真验证。

l  提供详细的仿真波形图,验证各个模块的正确性。

8.      FPGA资源利用说明:

l  提供详细的说明,说明FPGA芯片资源的使用情况。

l  包括LUT资源、用户闪存、RAM等。

9.      演示视频:

l  创建3-5分钟的演示视频,展示计算器的各个功能。

l  视频应包括使用4x4矩阵键盘输入、数码管显示、TFTLCD显示(如果有)、运算过程等。

10.  完整的报告:

l  提供完整的报告,包括项目需求、需求分析、实现方式、功能框图、代码及说明、仿真波形图、FPGA资源利用说明等。

l  确保报告中有充分的文字描述,让读者了解整个项目的设计和实现。

11.  U盘模式下载:

l  通过USB Type C接口实现供电和FPGA的配置。

l  支持U盘模式下载,使得在任何操作系统的电脑上都可以直接将生成的JED文件发送到FPGA板中完成编程。

12.  易用性提升:

l  确保整个系统的易用性,尽量减少用户的配置和操作复杂性。

l  提供清晰的指导,使得初学者能够轻松上手。

13.  硬件环境兼容性:

l  确保软件在提供的硬件环境中能够正常运行,兼容STEP BaseBoard V4.0和STEP-MXO2-LPC核心模块。

14.  用户交互体验:

l  考虑用户交互体验,确保在输入和观察结果时,用户能够清晰地理解当前状态和操作。

15.  异常处理:

l  实现合理的异常处理机制,确保在用户输入错误或其他异常情况下系统能够给出友好的提示或恢复正常状态。

下面将在详细设计和验证验收部分对需求进行追踪和确认。

 

1.5.2   接口定义

计算器FPGA软件的输入输出信号及引脚分配如表1.1所示。

表1.1 接口定义表

序号

名称

引脚映射

方向

位宽

作用

I2C接口

1

I2C_SCL

C8

/

1

I2C SCL时钟端口

2

I2C_SDA

B8

/

1

I2C SDA数据端口

编码器接口

3

A_OUT

E3

/

1

编码器 A端

4

B_OUT

F3

/

1

编码器 B端

5

D_OUT

G3

/

1

编码器 D端

矩阵键盘接口

6

COL1

H3

/

1

矩阵键盘 COL1端

7

COL2

J2

/

1

矩阵键盘 COL2端

8

COL3

J3

/

1

矩阵键盘 COL3端

9

COL4

K2

/

1

矩阵键盘 COL4端

10

ROW1

P6

/

1

矩阵键盘 ROW1端

11

ROW2

N5

/

1

矩阵键盘 ROW2端

12

ROW3

L3

/

1

矩阵键盘 ROW3端

13

ROW4

K3

/

1

矩阵键盘 ROW4端

LCD/HDMI接口

14

DISP1

G13

/

1

HDMI DISP1端

15

DISP2

N8

/

1

HDMI DISP2端

16

DISP3

P8

/

1

HDMI DISP3端

17

DISP4

N7

/

1

HDMI DISP4端

18

DISP5

P7

/

1

HDMI DISP5端

19

DISP6

N6

/

1

HDMI DISP6端

串口/ESP-12

20

TXD_CH340

E12

/

1

串口发送 TXD端口

21

RXD_CH340

F12

/

1

串口接收 RXD端口

22

TXD0

G12

/

1

ESP-12F TX-RX

23

RXD0

F13

/

1

ESP-12F RX-TX

调试IO

24

INT

F14

/

1

/

ADC/DAC接口

25

ADC_CS

G14

/

1

ADC CS片选端口

26

ADC_SDATA

H12

/

1

ADC SDATA数据端口

27

ADC_SCLK

J13

/

1

ADC SCLK时钟端口

28

DAC_SYNC

J14

/

1

DAC SYNC同步端口

29

DAC_SCLK

K12

/

1

DAC SCLK时钟端口

30

DAC_SDI

K14

/

1

DAC SDI输入端口

PMOD接口

31

PMOD_IO2(DISP7)

K13

/

1

PMOD接口

32

PMOD_IO1(DISP8)

J12

/

1

PMOD接口

74HC595接口

33

595_RCK

P3

/

1

74HC595的RCK端

34

595_SCK

M4

/

1

74HC595的SCK端

35

595_DIN

P13

/

1

74HC595的DIN端

蜂鸣器接口

36

BEEP

N4

/

1

蜂鸣器

系统接口

37

CLK

C1

I

1

12M系统时钟

1.5.3   接口功能

1.5.3.1    数据输入功能

计算器FPGA软件主要需要使用矩阵键盘实现数据输入功能,板载有4*4的矩阵键盘,通过行列互联的方式,以4个行和4个列的公共端口接入FPGA。通过对矩阵键盘的功能进行定义,可以实现操作数0-9,以及+-*/这四个操作符的输入。相关原理图如图1.2。

image.png

图1.2 矩阵键盘原理图

1.5.3.2    数码管显示功能

计算器FPGA软件主要需要使用数码管实现操作数、操作符和运算结果的显示,板载8位数码管通过74HC595芯片实现扫描和显示。相关原理图如图1.3。

image.png

图1.3 数码管原理图

1.5.3.3    TFLCD显示功能

计算器FPGA软件主要需要使用TFLCD实现操作数、操作符和运算结果的显示。相关原理图如图1.4。

image.png

图1.4 TFLCD原理图

1.5.4   功能描述

1.5.4.1    基本计算功能

实现两位十进制数的加、减、乘、除运算。用户通过使用4x4矩阵键盘来输入运算数和运算符。

1.5.4.2    输入控制

通过状态机对用户输入进行控制,包括输入第一个数、输入第二个数、输入运算符等状态。这确保了用户在不同阶段能够正确输入所需的信息。

1.5.4.3    结果显示

将运算结果通过8个八段数码管进行显示。设计逻辑确保最高位先在右侧数码管显示,然后跳变到左侧的数码管,低位在刚才高位占据的数码管上显示。

1.5.4.4    TFTLCD显示(扩展功能)

使用TFTLCD代替数码管进行结果的显示。此部分需要额外的设计,包括界面布局、显示参数、输入信息等。

1.5.5   性能

无强制性性能需求。

1.6    质量控制

本软件无质量控制需求,根据标准化要求,遵循《MyFPGA质量保证计划(2021.2)》对本FPGA软件进行质量保证。

1.7    验收准则

评审标准                                                                           

1.      独立完成项目实现任务需求中所要求的功能,我们会验证每一个项目的代码,如发现任何抄袭者,原创者和抄袭者都会被取消资格。

2.      使用思得普的WebIDE来实现所有的功能

3.      针对代码中的每一个模块都要做仿真,并在报告中将仿真的波形图附上

4.      报告中要包含下面几个部分:

1.      项目需求

2.      需求分析

3.      实现的方式

4.      功能框图

5.      代码(内嵌到报告中)及说明

6.      仿真波形图

7.      FPGA的资源利用说明

8.      演示视频(3-5分钟)

9.      代码附件(上传到电子森林)

 

2    详细设计

2.1    原理框图

image.png

2.2    模块化设计

本软件使用自顶向下和模块化的开发方法,由于需求非常明确,采用瀑布模型进行开发,以下是详细的模块化设计记录和代码。

2.2.1   例化调用

Main.v仅起到例化调用的作用,源代码如下:

//------------------------------------------------------

// File Name        : main.v

// Author           : ChanRa1n

// Description      : 2024电子森林一起练活动代码Topmodule

// Called by        : /

// Revision History : 2024-01-06

// Revision         : 1.0

// Email            : chenyu@myfpga.cn

// Copyright(c) 2018-Now, MYFPGA.CN, All right reserved.

//------------------------------------------------------

//`define SYS_DEBUG 0

`define SYS_RESET 0

//调试模式SYS_DEBUG -> 调整系统周期

//复位选项SYS_RESET -> 可选关闭全局复位,减少面积

module main #(

`ifdef SYS_DEBUG

    parameter SYS_CLK = 1000

`else

    parameter SYS_CLK = 10_000_000

`endif

) (

    input  wire i_sys_clk,

    input  wire i_sys_rst_n,

    //矩阵键盘

    input  wire [3:0] i_key_col,

    output  wire [3:0] o_key_row,

    //数码管

    output wire o_seg_rck,

    output wire o_seg_sck,

    output wire o_seg_din

);

 

  //矩阵键盘驱动模块matrix_key

  //输入WIRE直接连接至矩阵键盘

  //输出数据为被按下的按键编号key_data,经过功能的重新映射,其中数字0-9对应数字0-9

  //10->. 11->= 12->+ 13->- 14->× 15->÷

  wire [3:0] key_data;

  wire [0:0] key_data_en;

  matrix_key #(

      .SYS_CLK(SYS_CLK)

  ) u1_matrix_key (

      .clk(i_sys_clk),

`ifdef SYS_RESET

      .rst_n(i_sys_rst_n),

`endif

      .col(i_key_col),

      .row(o_key_row),

      .key_data(key_data),

      .key_data_en(key_data_en)

  );

 

  //数码管驱动模块

  //输入4个REG数据,分别是seg_data_1到seg_data_4,对应显示从右往左的四个数码管

  //其中数字0-9对应数字0-9,10->. 11->= 12->+ 13->- 14->× 15->÷

  //输出WIRE直接连接至数码管

  wire [4:0] seg_data_1;

  wire [4:0] seg_data_2;

  wire [4:0] seg_data_3;

  wire [4:0] seg_data_4;

  wire [4:0] seg_data_5;

  wire [4:0] seg_data_6;

  wire [4:0] seg_data_7;

  wire [4:0] seg_data_8;

  wire [7:0] seg_data_en;

  segment_scan #(

      .SYS_CLK(SYS_CLK)

  ) u2_segment_scan (

      .clk   (i_sys_clk),

`ifdef SYS_RESET

      .rst_n (i_sys_rst_n),

`endif

      .dat_1 (seg_data_1),

      .dat_2 (seg_data_2),

      .dat_3 (seg_data_3),

      .dat_4 (seg_data_4),

      .dat_5 (seg_data_5),

      .dat_6 (seg_data_6),

      .dat_7 (seg_data_7),

      .dat_8 (seg_data_8),

      .dat_en(seg_data_en),

      .dot_en(8'b0000_0000),

 

      .seg_rck(o_seg_rck),

      .seg_sck(o_seg_sck),

      .seg_din(o_seg_din)

  );

 

  //计算器逻辑控制模块

  //输入矩阵键盘传递的按键编号key_data

  //输出4个REG数据,送入数码管驱动模块

  //复位情况下数码管显示MYFPGA.CN,当任意按键被按下,进入计算器模式。

  control #(

      .SYS_CLK(10_000_000)

  ) u_control (

      .clk        (i_sys_clk),

      .rst_n      (i_sys_rst_n),

      .key_data   (key_data),

      .key_data_en(key_data_en),

 

      .seg_data_1(seg_data_1),

      .seg_data_2(seg_data_2),

      .seg_data_3(seg_data_3),

      .seg_data_4(seg_data_4),

      .seg_data_5(seg_data_5),

      .seg_data_6(seg_data_6),

      .seg_data_7(seg_data_7),

      .seg_data_8(seg_data_8),

      .seg_dat_en(seg_data_en)

  );

 

endmodule

 

2.2.2   计算模块

由于Diamond默认的编译器对乘法和除法的支持性不高,所以需要更换使用Synplify Pro进行编译。

image.png

计算模块主要起到数据流控制的作用,其软件需求说明书设计如下:

// 软件需求规格说明书

// 1. 简介

// 本文档旨在详细说明数码管显示控制模块的软件需求,以便于后续设计和实现这一功能。

// 2. 功能性需求

// 2.1 系统初始化

// 软件行为描述: 当系统复位后,应在数码管 seg_data_1 至 seg_data_8 分别显示自 'd16 至 'd23 的值。

// 2.2 数字键输入

// 软件行为描述: 当按下数字键时,将该数字显示在数码管的个位(seg_data_8)。如果连续按下数字键,则先前的数字后移变为十位(seg_data_7),新按下的数字保持在个位。仅支持显示最大为两位数。

// 2.3 符号键输入

// 软件行为描述: 当按下符号键('+', '-', '×', '÷')时,将相应符号显示在数码管的个位(seg_data_8)。之后按下的数字键行为与2.2节的描述一致。

// 2.4 等号键输入及运算

// 软件行为描述: 当按下等于号('=')键后,系统应根据先前输入的数字和符号键进行整数运算,并将结果显示在数码管上。如果结果超出可显示范围,则需要定义如何处理(例如报错、截断或滚动显示)。

// 3. 输入需求

// 按键值定义: 数字键0-9应对应数字0-9,符号键应对应以下值:

// 10 - 小数点('.')

// 11 - 等于号('=')

// 12 - 加号('+')

// 13 - 减号('-')

// 14 - 乘号('×')

// 15 - 除号('÷')

// 4. 输出需求

// 数码管显示: 数码管由 seg_data_1 至 seg_data_8 表示,其中 seg_data_8 是个位显示,seg_data_7 是十位显示。seg_dat_en 用于控制各个数码管位的显示使能。

// 5. 附加需求

// 按键处理: 不需要定义按键抖动处理机制来确保输入的稳定性,输入的按键信号已经经过了消抖。

// 6. 流程描述

// 程序功能描述:程序复位后,在数码管的seg_data_1~seg_data_8显示'd16~'d23

// 当任意数字按键被按下,在数码管的个位显示被按下的按键值。接下来若任意数字按键被按下,则之前的数字变成十位,新按下的按键变成个位。最大支持2位数。

// 当符号按键被按下后,在数码管的个位显示被按下的符号按键

// 接下来可以按下任意数字按键,在数码管的个位显示被按下的按键值。接下来若任意数字按键被按下,则之前的数字变成十位,新按下的按键变成个位。最大支持2位数。

// 当等于号被按下后,程序会根据输入的数字和符号按键进行计算,并在将结果显示到数码管上。

// 计算仅保留整数即可,不需要计算小数。

     基于此,设计了程序源码如下:

//------------------------------------------------------

// File Name        : control.v

// Author           : ChanRa1n

// Description      : 2024电子森林一起练活动代码 简易计算器

// Called by        : Topmodule

// Revision History : 2024-01-06

// Revision         : 1.0

// Email            : chenyu@myfpga.cn

// Copyright(c) 2018-Now, MYFPGA.CN, All right reserved.

//------------------------------------------------------

 

module control #(

    parameter SYS_CLK = 10_000_000

) (

    input wire clk,

    input wire rst_n,

 

    input wire [3:0] key_data,  // 被按下的按键值

    input wire key_data_en,  // 按键值有效位

 

    output reg [4:0] seg_data_1,  // 数码管第1位要显示的值

    output reg [4:0] seg_data_2,  // 数码管第2位要显示的值

    output reg [4:0] seg_data_3,  // 数码管第3位要显示的值

    output reg [4:0] seg_data_4,  // 数码管第4位要显示的值

    output reg [4:0] seg_data_5,  // 数码管第5位要显示的值

    output reg [4:0] seg_data_6,  // 数码管第6位要显示的值

    output reg [4:0] seg_data_7,  // 数码管第7位要显示的值

    output reg [4:0] seg_data_8,  // 数码管第8位要显示的值

    output reg [7:0] seg_dat_en   // 数码管要显示值的有效位

);

 

  localparam [2:0] ST_IDLE = 'd0,  // Idle state

  ST_OPERAND1 = 'd1,  // Entering first operand

  ST_OPERATOR = 'd2,  // Entering operator

  ST_OPERAND2 = 'd3,  // Entering second operand

  ST_CALCULATE = 'd4;  // Perform calculation

 

  reg [2:0] state;  // Current state

  reg [15:0] operand1, operand2;  // Operands

  reg [ 3:0] operator;  // Operator

  reg [15:0] result;  // Calculation result

 

  // State machine

  always @(posedge clk or negedge rst_n) begin

    if (~rst_n) begin

      // Reset logic

      state <= ST_IDLE;

      operand1 <= 'd0;

      operand2 <= 'd0;

      operator <= 'd0;

      result <= 'd0;

    end else begin

      case (state)

        ST_IDLE: begin

          if (!key_data_en || key_data >= 10) begin  //初始化

            operand1 <= 'd0;

            operand2 <= 'd0;

            operator <= 'd0;

            result   <= 'd0;

          end else begin

            operand1 <= key_data;

            state <= ST_OPERAND1;

          end

        end

 

        ST_OPERAND1: begin  //输入操作数1

          if (key_data_en) begin

            if (key_data < 10) begin

              operand1 <= operand1 * 10 + key_data;

            end else begin

              operator <= key_data;

              state <= ST_OPERATOR;

            end

          end

        end

 

        ST_OPERATOR: begin  //输入操作符

          if (key_data_en && (key_data < 10)) begin

            operand2 <= key_data;

            state <= ST_OPERAND2;

          end

        end

 

        ST_OPERAND2: begin  //输入操作数2

          if (key_data_en) begin

            if (key_data < 10) begin

              operand2 <= operand2 * 10 + key_data;

            end else state <= ST_CALCULATE;

          end

        end

 

        ST_CALCULATE: begin  //计算

          case (operator)

            11: result <= operand1 + operand2;

            13: result <= operand1 - operand2;

            14: result <= operand1 * operand2;

            15: result <= operand1[6:0] / operand2[6:0];  // prevent divide by 0

            default: result <= 0;

          endcase

 

          if (key_data_en) state <= ST_IDLE;  // Any key press resets the calculator

        end

      endcase

    end

  end

 

  // 重置数码管显示的过程

  task reset_display;

    begin

      seg_data_1 <= 'd16;

      seg_data_2 <= 'd17;

      seg_data_3 <= 'd18;

      seg_data_4 <= 'd19;

      seg_data_5 <= 'd20;

      seg_data_6 <= 'd21;

      seg_data_7 <= 'd22;

      seg_data_8 <= 'd23;

      seg_dat_en <= 8'b11111111;  // 启用所有数码管显示

    end

  endtask

 

  // State machine SEG

  always @(posedge clk or negedge rst_n) begin

    if (~rst_n) begin

      reset_display();

    end else begin

      case (state)

        ST_IDLE: begin

          reset_display();

        end

        ST_OPERAND1: begin  //显示操作数1

          seg_data_8 <= operand1 % 10;

          seg_data_7 <= operand1 / 10;

          seg_dat_en <= 8'b0000_0011;

        end

        ST_OPERATOR: begin  //显示操作符

          seg_data_8 <= key_data;

          seg_dat_en <= 8'b0000_0001;

        end

 

        ST_OPERAND2: begin  //显示操作数2

          seg_data_8 <= operand2 % 10;

          seg_data_7 <= operand2 / 10;

          seg_dat_en <= 8'b0000_0011;

        end

 

        ST_CALCULATE: begin  //计算

          seg_data_8 <= result % 10;

          seg_data_7 <= result / 10 % 10;

          seg_data_6 <= result / 100 % 10;

          seg_data_5 <= result / 1000 % 10;

          seg_dat_en <= 8'b0000_1111;

        end

      endcase

    end

  end

endmodule

 

 

2.2.3   数码管驱动模块

模块基于Verilog HDL编写,主要用于定义和控制数码管的显示内容和显示方式。尤其是通过SEG1到SEG8的数据输入和显示使能,可以灵活地显示各种数字或图案。

在模块中,通过定义了一个本地参数SYS_CLK,用于设定系统的时钟频率。该模块中的计数器将对给定的时钟信号进行计数,根据计数器计数的周期产生分频的脉冲信号。

源码如下:

// --------------------------------------------------------------------

// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<

// --------------------------------------------------------------------

// Module: segment_scan

//

// Author: Step

//

// Description: Display with Segment tube

//

// Web: www.stepfpga.com

//

// --------------------------------------------------------------------

// Code Revision History :

// --------------------------------------------------------------------

// Version: |Mod. Date:   |Changes Made:

// V1.0     |2015/11/11   |Initial ver

// V1.1     |2024/03/06   |修改显示内容

// --------------------------------------------------------------------

module segment_scan #(

    parameter SYS_CLK = 10_000_000

) (

    input    clk,   //系统时钟 12MHz

    input    rst_n,  //系统复位 低有效

    input  [4:0] dat_1,  //SEG1 显示的数据输入

    input  [4:0] dat_2,  //SEG2 显示的数据输入

    input  [4:0] dat_3,  //SEG3 显示的数据输入

    input  [4:0] dat_4,  //SEG4 显示的数据输入

    input  [4:0] dat_5,  //SEG5 显示的数据输入

    input  [4:0] dat_6,  //SEG6 显示的数据输入

    input  [4:0] dat_7,  //SEG7 显示的数据输入

    input  [4:0] dat_8,  //SEG8 显示的数据输入

    input  [7:0] dat_en,  //数码管数据位显示使能,[MSB~LSB]=[SEG1~SEG8]

    input  [7:0] dot_en,  //数码管小数点位显示使能,[MSB~LSB]=[SEG1~SEG8]

    output reg seg_rck,  //74HC595的RCK管脚

    output reg seg_sck,  //74HC595的SCK管脚

    output reg seg_din  //74HC595的SER管脚

);

 

  localparam CNT_40KHz = SYS_CLK / 40_000;  //分频系数

 

  localparam IDLE = 3'd0;

  localparam MAIN = 3'd1;

  localparam WRITE = 3'd2;

  localparam LOW = 1'b0;

  localparam HIGH = 1'b1;

 

  //创建数码管的字库,字库数据依段码顺序有关

  //这里字库数据[MSB~LSB]={G,F,E,D,C,B,A}

  reg [6:0] seg[23:0];

  always @(negedge rst_n) begin

    seg[0]  = 7'h3f;  // 0

    seg[1]  = 7'h06;  // 1

    seg[2]  = 7'h5b;  // 2

    seg[3]  = 7'h4f;  // 3

    seg[4]  = 7'h66;  // 4

    seg[5]  = 7'h6d;  // 5

    seg[6]  = 7'h7d;  // 6

    seg[7]  = 7'h07;  // 7

    seg[8]  = 7'h7f;  // 8

    seg[9]  = 7'h6f;  // 9

    seg[10] = 7'h7E;  // . (小数点)

    seg[11] = 7'h3E;  // = (等于)

    seg[12] = 7'h38;  // + (加号)

    seg[13] = 7'h0F;  // - (减号)

    seg[14] = 7'h39;  // × (乘号)

    seg[15] = 7'h0E;  // ÷ (除号)

 

    //LOGO HERE

    seg[16] = 7'h37;  // M

    seg[17] = 7'hEE;  // Y

    seg[18] = 7'h71;  // F

    seg[19] = 7'h73;  // P

    seg[20] = 7'h7d;  // G

    seg[21] = 7'h77;  // A.

    seg[22] = 7'h39;  // C

    seg[23] = 7'h37;  // N

  end

 

  //计数器对系统时钟信号进行计数

  reg [9:0] cnt = 1'b0;

  always @(posedge clk or negedge rst_n) begin

    if (!rst_n) cnt <= 1'b0;

    else if (cnt >= (CNT_40KHz - 1)) cnt <= 1'b0;

    else cnt <= cnt + 1'b1;

  end

 

  //根据计数器计数的周期产生分频的脉冲信号

  reg clk_40khz = 1'b0;

  always @(posedge clk or negedge rst_n) begin

    if (!rst_n) clk_40khz <= 1'b0;

    else if (cnt < (CNT_40KHz >> 1)) clk_40khz <= 1'b0;

    else clk_40khz <= 1'b1;

  end

 

  //使用状态机完成数码管的扫描和74HC595时序的实现

  reg [15:0] data;

  reg [ 2:0] cnt_main;

  reg [ 5:0] cnt_write;

  reg [ 2:0] state = IDLE;

  always @(posedge clk_40khz or negedge rst_n) begin

    if (!rst_n) begin  //复位状态下,各寄存器置初值

      state <= IDLE;

      cnt_main <= 3'd0;

      cnt_write <= 6'd0;

      seg_din <= 1'b0;

      seg_sck <= LOW;

      seg_rck <= LOW;

    end else begin

      case (state)

        IDLE: begin  //IDLE作为第一个状态,相当于软复位

          state <= MAIN;

          cnt_main <= 3'd0;

          cnt_write <= 6'd0;

          seg_din <= 1'b0;

          seg_sck <= LOW;

          seg_rck <= LOW;

        end

        MAIN: begin

          cnt_main <= cnt_main + 1'b1;

          state <= WRITE;   //在配置完发给74HC595的数据同时跳转至WRITE状态,完成串行时序

          case (cnt_main)

            //对8位数码管逐位扫描

            //data          [15:8]为段选,         [7:0]为位选

            3'd0: data <= {{dot_en[7], seg[dat_1]}, dat_en[7] ? 8'hfe : 8'hff};

            3'd1: data <= {{dot_en[6], seg[dat_2]}, dat_en[6] ? 8'hfd : 8'hff};

            3'd2: data <= {{dot_en[5], seg[dat_3]}, dat_en[5] ? 8'hfb : 8'hff};

            3'd3: data <= {{dot_en[4], seg[dat_4]}, dat_en[4] ? 8'hf7 : 8'hff};

            3'd4: data <= {{dot_en[3], seg[dat_5]}, dat_en[3] ? 8'hef : 8'hff};

            3'd5: data <= {{dot_en[2], seg[dat_6]}, dat_en[2] ? 8'hdf : 8'hff};

            3'd6: data <= {{dot_en[1], seg[dat_7]}, dat_en[1] ? 8'hbf : 8'hff};

            3'd7: data <= {{dot_en[0], seg[dat_8]}, dat_en[0] ? 8'h7f : 8'hff};

            default: data <= {8'h00, 8'hff};

          endcase

        end

        WRITE: begin

          if (cnt_write >= 6'd33) cnt_write <= 1'b0;

          else cnt_write <= cnt_write + 1'b1;

          case (cnt_write)

            //74HC595是串行转并行的芯片,3路输入可产生8路输出,而且可以级联使用

            //74HC595的时序实现,参考74HC595的芯片手册

            6'd0: begin

              seg_sck <= LOW;

              seg_din <= data[15];

            end  //SCK下降沿时SER更新数据

            6'd1: begin

              seg_sck <= HIGH;

            end  //SCK上升沿时SER数据稳定

            6'd2: begin

              seg_sck <= LOW;

              seg_din <= data[14];

            end

            6'd3: begin

              seg_sck <= HIGH;

            end

            6'd4: begin

              seg_sck <= LOW;

              seg_din <= data[13];

            end

            6'd5: begin

              seg_sck <= HIGH;

            end

            6'd6: begin

              seg_sck <= LOW;

              seg_din <= data[12];

            end

            6'd7: begin

              seg_sck <= HIGH;

            end

            6'd8: begin

              seg_sck <= LOW;

              seg_din <= data[11];

            end

            6'd9: begin

              seg_sck <= HIGH;

            end

            6'd10: begin

              seg_sck <= LOW;

              seg_din <= data[10];

            end

            6'd11: begin

              seg_sck <= HIGH;

            end

            6'd12: begin

              seg_sck <= LOW;

              seg_din <= data[9];

            end

            6'd13: begin

              seg_sck <= HIGH;

            end

            6'd14: begin

              seg_sck <= LOW;

              seg_din <= data[8];

            end

            6'd15: begin

              seg_sck <= HIGH;

            end

            6'd16: begin

              seg_sck <= LOW;

              seg_din <= data[7];

            end

            6'd17: begin

              seg_sck <= HIGH;

            end

            6'd18: begin

              seg_sck <= LOW;

              seg_din <= data[6];

            end

            6'd19: begin

              seg_sck <= HIGH;

            end

            6'd20: begin

              seg_sck <= LOW;

              seg_din <= data[5];

            end

            6'd21: begin

              seg_sck <= HIGH;

            end

            6'd22: begin

              seg_sck <= LOW;

              seg_din <= data[4];

            end

            6'd23: begin

              seg_sck <= HIGH;

            end

            6'd24: begin

              seg_sck <= LOW;

              seg_din <= data[3];

            end

            6'd25: begin

              seg_sck <= HIGH;

            end

            6'd26: begin

              seg_sck <= LOW;

              seg_din <= data[2];

            end

            6'd27: begin

              seg_sck <= HIGH;

            end

            6'd28: begin

              seg_sck <= LOW;

              seg_din <= data[1];

            end

            6'd29: begin

              seg_sck <= HIGH;

            end

            6'd30: begin

              seg_sck <= LOW;

              seg_din <= data[0];

            end

            6'd31: begin

              seg_sck <= HIGH;

            end

            6'd32: begin

              seg_rck <= HIGH;

            end  //当16位数据传送完成后RCK拉高,输出生效

            6'd33: begin

              seg_rck <= LOW;

              state   <= MAIN;

            end

            default: ;

          endcase

        end

        default: state <= IDLE;

      endcase

    end

  end

 

endmodule

 

2.2.4   按键映射模块

为了将按键进行编码,我修改了key_decode.v模块,以实现操作数和操作符的分离,同时也方便后续进行升级改造,如加入Fn按键,以实现更多运算等。

image.png

图3.2 矩阵键盘按键分配图

代码修改如下:

//------------------------------------------------------

// File Name        : matrix_key.v

// Author           : ChanRa1n

// Description      : 2024电子森林一起练活动代码

// Called by        : Topmodule

// Revision History : 2024-01-06

// Revision         : 1.0

// Email            : chenyu@myfpga.cn

// Copyright(c) 2018-Now, MYFPGA.CN, All right reserved.

//------------------------------------------------------

module matrix_key #(

    parameter SYS_CLK = 10_000_000

) (

    input clk,

    input rst_n,

    input [3:0] col,

    output [3:0] row,

    output reg [3:0] key_data,

    output reg key_data_en

);

 

  wire [15:0] key_out;

  wire [15:0] key_pulse;

 

  array_keyboard #(

      .CNT_200HZ(SYS_CLK / 200)

  ) u_array_keyboard (

      .clk  (clk),

      .rst_n(rst_n),

      .col  (col),

 

      .row      (row),

      .key_out  (key_out),

      .key_pulse(key_pulse)

  );

 

  always @(posedge clk or negedge rst_n) begin

    if (~rst_n) begin

      key_data_en <= 1'b0;

      key_data <= 4'd0;

    end else begin

      if (key_pulse) begin

        key_data_en <= 1'b1;

        case (key_pulse)

          16'b0000_0000_0000_0001:  key_data <= 4'd7;

          16'b0000_0000_0000_0010:  key_data <= 4'd8;

          16'b0000_0000_0000_0100:  key_data <= 4'd9;

          16'b0000_0000_0000_1000:  key_data <= 4'd15;

          16'b0000_0000_0001_0000:  key_data <= 4'd4;

          16'b0000_0000_0010_0000:  key_data <= 4'd5;

          16'b0000_0000_0100_0000:  key_data <= 4'd6;

          16'b0000_0000_1000_0000:  key_data <= 4'd14;

          16'b0000_0001_0000_0000:  key_data <= 4'd3;

          16'b0000_0010_0000_0000:  key_data <= 4'd2;

          16'b0000_0100_0000_0000:  key_data <= 4'd1;

          16'b0000_1000_0000_0000:  key_data <= 4'd13;

          16'b0001_0000_0000_0000:  key_data <= 4'd0;

          16'b0010_0000_0000_0000:  key_data <= 4'd9;

          16'b0100_0000_0000_0000:  key_data <= 4'd10;

          16'b1000_0000_0000_0000:  key_data <= 4'd11;

          default: key_data <= 4'd0;

        endcase

      end else begin

        key_data_en <= 1'b0;

        key_data <= 4'd0;

      end

    end

  end

 

endmodule

     为了方便区分操作数和操作符,采用直接映射方法,增加了代码的易读性和可维护性。

2.2.5   矩阵键盘扫描模块

矩阵键盘的驱动文件参考自苏州硬禾信息科技有限公司的array_keyboard.v(V1.0),以下对该模块的驱动部分进行分析和解释说明。

该模块主要完成了三件事:

1.  频率分频器和状态机: 通过计数器和状态机,生成一个200Hz的时钟信号 clk_200hz。状态机负责按周期扫描矩阵键盘的不同行,以检测按键的状态。

2.      矩阵键盘扫描: 在每个状态下,通过行和列的组合来扫描矩阵键盘。按键的状态通过 key_out 输出。

3.      下降沿检测: 使用 key_pulse 信号来检测按键状态的下降沿。在 key_out 从高电平切换到低电平时,key_pulse 产生一个脉冲信号。

以下是代码部分源码:

// --------------------------------------------------------------------

// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<

// --------------------------------------------------------------------

// Module: array_keyboard

//

// Author: Step

//

// Description: array_keyboard

//

// Web: www.stepfapga.com

//

// --------------------------------------------------------------------

// Code Revision History :

// --------------------------------------------------------------------

// Version: |Mod. Date:   |Changes Made:

// V1.0     |2015/11/11   |Initial ver

// --------------------------------------------------------------------

module array_keyboard #

(

    parameter           CNT_200HZ = 60000

)

(

    input                   clk,

    input                   rst_n,

    input           [3:0]   col,

    output reg  [3:0]   row,

    output reg  [15:0]key_out,

    output      [15:0]key_pulse

);

   

    localparam          STATE0 = 2'b00;

    localparam          STATE1 = 2'b01;

    localparam          STATE2 = 2'b10;

    localparam          STATE3 = 2'b11;

   

    /*

    因使用4x4矩阵按键,通过扫描方法实现,所以这里使用状态机实现,共分为4种状态

    在其中的某一状态时间里,对应的4个按键相当于独立按键,可按独立按键的周期采样法采样

    周期采样时每隔20ms采样一次,对应这里状态机每隔20ms循环一次,每个状态对应5ms时间

    对矩阵按键实现原理不明白的,请去了解矩阵按键实现原理

    */

   

    //计数器计数分频实现5ms周期信号clk_200hz,系统时钟12MHz

    reg [15:0]  cnt;

    reg             clk_200hz;

    always@(posedge clk or negedge rst_n) begin  //复位时计数器cnt清零,clk_200hz信号起始电平为低电平

        if(!rst_n) begin

            cnt <= 16'd0;

            clk_200hz <= 1'b0;

        end else begin

            if(cnt >= ((CNT_200HZ>>1) - 1)) begin  //数字逻辑中右移1位相当于除2

                cnt <= 16'd0;

                clk_200hz <= ~clk_200hz;  //clk_200hz信号取反

            end else begin

                cnt <= cnt + 1'b1;

                clk_200hz <= clk_200hz;

            end

        end

    end

   

    reg     [1:0]       c_state;

    //状态机根据clk_200hz信号在4个状态间循环,每个状态对矩阵按键的行接口单行有效

    always@(posedge clk_200hz or negedge rst_n) begin

        if(!rst_n) begin

            c_state <= STATE0;

            row <= 4'b1110;

        end else begin

            case(c_state)

                //状态c_state跳转及对应状态下矩阵按键的row输出

                STATE0: begin c_state <= STATE1; row <= 4'b1101; end

                STATE1: begin c_state <= STATE2; row <= 4'b1011; end

                STATE2: begin c_state <= STATE3; row <= 4'b0111; end

                STATE3: begin c_state <= STATE0; row <= 4'b1110; end

                default:begin c_state <= STATE0; row <= 4'b1110; end

            endcase

        end

    end

   

    reg [15:0]  key,key_r;

    //因为每个状态中单行有效,通过对列接口的电平状态采样得到对应4个按键的状态,依次循环

    always@(negedge clk_200hz or negedge rst_n) begin

        if(!rst_n) begin

            key_out <= 16'hffff; key_r <= 16'hffff; key <= 16'hffff;

        end else begin

            case(c_state)

                //采集当前状态的列数据赋值给对应的寄存器位

                //对键盘采样数据进行判定,连续两次采样低电平判定为按键按下

                STATE0: begin key_out[ 3: 0] <= key_r[ 3: 0]|key[ 3: 0]; key_r[ 3: 0] <= key[ 3: 0]; key[ 3: 0] <= col; end

                STATE1: begin key_out[ 7: 4] <= key_r[ 7: 4]|key[ 7: 4]; key_r[ 7: 4] <= key[ 7: 4]; key[ 7: 4] <= col; end

                STATE2: begin key_out[11: 8] <= key_r[11: 8]|key[11: 8]; key_r[11: 8] <= key[11: 8]; key[11: 8] <= col; end

                STATE3: begin key_out[15:12] <= key_r[15:12]|key[15:12]; key_r[15:12] <= key[15:12]; key[15:12] <= col; end

                default:begin key_out <= 16'hffff; key_r <= 16'hffff; key <= 16'hffff; end

            endcase

        end

    end

   

    reg     [15:0]      key_out_r;

    //Register low_sw_r, lock low_sw to next clk

    always @ ( posedge clk  or  negedge rst_n )

        if (!rst_n) key_out_r <= 16'hffff;

        else  key_out_r <= key_out;   //将前一刻的值延迟锁存

   

    //wire  [15:0]       key_pulse;

    //Detect the negedge of low_sw, generate pulse

    assign key_pulse= key_out_r & ( ~key_out);   //通过前后两个时刻的值判断

   

endmodule

3    软件测试与验证

FPGA软件类型:Ⅰ类新研;

关键性等级:民用级;

在对软件结构和成熟度分析后决定,跳过成熟的模块和IP,对自行设计的逻辑控制、计算部分模块进行模块级仿真验证(前仿),对集成后的整体进行功能性验证(黑盒),最后对网表文件进行时序验证。以下是对应的详细记录。

3.1    模块化测试记录

3.2    例化调用模块测试记录

本模块仅起到例化链接的作用,无需进行仿真测试。

3.3    计算模块测试记录

本次计算模块的测试采用行为级测试方法,仅开展前仿真验证。测试激励文件如下:

`timescale 1ns / 1ps

module sim_control;

 

reg clk;  

reg rst_n;  

reg [3:0] key_data;  

reg key_data_en;  

wire [4:0] seg_data_1, seg_data_2, seg_data_3, seg_data_4, seg_data_5, seg_data_6,seg_data_7, seg_data_8;  

wire [7:0] seg_dat_en;  

 

always #5 clk = ~clk;  

 

initial begin  

  $dumpfile("sim_control.vcd");  

  $dumpvars;  

  clk = 0;  

  rst_n = 0;  

  key_data = 4'h0;  

  key_data_en = 0;  

  #10;  

  rst_n = 1;  

  #10;  

end

 

control calc(

    .clk(clk),

    .rst_n(rst_n),

    .key_data(key_data),

    .key_data_en(key_data_en),

    .seg_data_1(seg_data_1),

    .seg_data_2(seg_data_2),

    .seg_data_3(seg_data_3),

    .seg_data_4(seg_data_4),

    .seg_data_5(seg_data_5),

    .seg_data_6(seg_data_6),

    .seg_data_7(seg_data_7),

    .seg_data_8(seg_data_8),

    .seg_dat_en(seg_dat_en)

);

 

// 测试加法: 2 + 2 = 4

initial begin

  #20;

  key_data_en = 1;

  key_data = 4'd2;

  #10;

  key_data = 4'd11;

  #10;

  key_data = 4'd2;

  #10;

  key_data = 4'd11;

  #10;

  key_data_en = 0;

  #10;

end

 

// 测试减法: 5 - 3 = 2

initial begin

  #1200;

  rst_n = 0;  

  key_data = 4'h0;  

  key_data_en = 0;  

  #10;  

  rst_n = 1;  

  #10;  

  key_data_en = 1;

  key_data = 4'd5;

  #10;

  key_data = 4'd13;

  #10;

  key_data = 4'd3;

  #10;

  key_data = 4'd11;

  #10;

  key_data_en = 0;

  #10;

end

 

// 测试乘法: 3 * 3 = 9

initial begin

  #2200;

  rst_n = 0;  

  key_data = 4'h0;  

  key_data_en = 0;  

  #10;  

  rst_n = 1;  

  #10;  

  key_data_en = 1;

  key_data = 4'd3;

  #10;

  key_data = 4'd14;

  #10;

  key_data = 4'd3;

  #10;

  key_data = 4'd11;

  #10;

  key_data_en = 0;

  #10;

end

 

// 测试除法: 8 / 2 = 4

initial begin

  #3200;

  rst_n = 0;  

  key_data = 4'h0;  

  key_data_en = 0;  

  #10;  

  rst_n = 1;  

  #10;  

  key_data_en = 1;

  key_data = 4'd8;

  #10;

  key_data = 4'd15;

  #10;

  key_data = 4'd2;

  #10;

  key_data = 4'd11;

  #10;

  key_data_en = 0;

end

 

initial begin

  #5000;

  $stop;

end

 

endmodule

测试整体波形如下:

image.png

     分功能进行详细测试:


     加法计算2+2结果result为4,对应数码管位置显示也正常。

image.png

     减法计算5-3结果result为2,对应数码管位置显示也正常。

image.png

     乘法计算3*3结果result为9,对应数码管位置显示也正常。

image.png

     除法计算8/2结果result为4,对应数码管位置显示也正常。

3.4    按键映射模块测试记录

按键映射模块仅起到映射链接的作用,没有额外的逻辑,进行行为级简单仿真测试,记录如下:

image.png

     经过确认,映射功能正确。

3.5    数码管驱动模块测试记录

数码管驱动模块为电子森林设计成熟模块,经过实物测试功能满足要求。

3.6    矩阵键盘扫描模块测试记录

矩阵键盘扫描模块为电子森林设计成熟模块,经过实物测试功能满足要求。

3.7    资源占用情况

3.7.1   编译后占用情况

Design Summary

   Number of registers:    213 out of  4635 (5%)

      PFU registers:          202 out of  4320 (5%)

      PIO registers:           11 out of   315 (3%)

   Number of SLICEs:       722 out of  2160 (33%)

      SLICEs as Logic/ROM:    722 out of  2160 (33%)

      SLICEs as RAM:            0 out of  1620 (0%)

      SLICEs as Carry:        460 out of  2160 (21%)

   Number of LUT4s:        1443 out of  4320 (33%)

      Number used as logic LUTs:        523

      Number used as distributed RAM:     0

      Number used as ripple logic:      920

      Number used as shift registers:     0

   Number of PIO sites used: 13 + 4(JTAG) out of 105 (16%)

   Number of block RAMs:  0 out of 10 (0%)

   Number of GSRs:        1 out of 1 (100%)

   EFB used :        No

   JTAG used :       No

   Readback used :   No

   Oscillator used : No

   Startup used :    No

   POR :             On

   Bandgap :         On

   Number of Power Controller:  0 out of 1 (0%)

   Number of Dynamic Bank Controller (BCINRD):  0 out of 6 (0%)

   Number of Dynamic Bank Controller (BCLVDSO):  0 out of 1 (0%)

   Number of DCCA:  0 out of 8 (0%)

   Number of DCMA:  0 out of 2 (0%)

   Number of PLLs:  0 out of 2 (0%)

   Number of DQSDLLs:  0 out of 2 (0%)

   Number of CLKDIVC:  0 out of 4 (0%)

   Number of ECLKSYNCA:  0 out of 4 (0%)

   Number of ECLKBRIDGECS:  0 out of 2 (0%)

3.7.2   布局布线后占用情况

Device utilization summary:

 

   PIO (prelim)   13+4(JTAG)/280     6% used

                  13+4(JTAG)/105     16% bonded

   IOLOGIC           11/280           3% used

 

   SLICE            722/2160         33% used

 

   GSR                1/1           100% used

 

Number of Signals: 1732

Number of Connections: 4134

image.png

3.7.3   资源利用说明

根据4.2.2布局布线后的设备使用度,我们可以对 FPGA 的资源利用情况做如下分析:

1.      PIO (预设):预先定义了17个预设 I/O,其中13个已被占用并且包括诸如JTAG之类的功能,另外4个是为JTAG保留的。总共占用了280个可用资源的6%,其中有16%的已经被束缚。

2.      IOLOGIC 资源:总共使用了280个IOLOGIC资源中的11个,占用率为3%,这代表着大部分的IOLOGIC资源还未使用,因此有足够的资源进行更多的操作处理。

3.      切片 SLICE: 切片是 FPGA 的基本计算单元,我们的设计中已经使用了2160个切片中的722个,占用率为33%,这显示了仍然有很大比例的切片资源可以用于未来的扩展和优化。

4.      全局设置复位 GSR:充分利用了该资源,被使用的比例达到了100%。这意味着我们无法添加需要 GSR 的新部分。程序中设置了宏定义,可以一键删去全局复位,这可能会降低逻辑的占用,但是GSR的性质,也可能不降低,这里不再进行测试。

5.      信号与连接:这个设计中有1732个信号和4134个连接。这是一个相对较大的设计,需要更多的资源和时间进行布局布线。

在该 FPGA 设计中使用了乘法和除法器,因此占用的资源相对较多。但从整体说来,这种设计仍有许多闲置的资源可以供未来的扩展和复杂运算使用。在未来的设计中,我们可以尝试使用更优化的设计,以减少资源的使用,提高设计的效率。

4    需求验证

经过需求对比和确认,本报告的全部需求均被满足。

一点点小建议,板载的那个二维码放的太丑了,影响整体布局,建议多招聘几个萌妹来画板子。

附件下载
Calculate_V1_1.7z
完整的工程文件夹压缩包
(公开)计算器FPGA软件设计说明与验证记录.pdf
文档
团队介绍
一个小团队,致力于FPGA知识分享。
团队成员
ChanRa1n
MYFPGA.CN
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号