十、MC8051软核在FPGA上的使用

本教程内容力求以详细的步骤和讲解让读者以最快的方式学会 MC8051 IP core 的应用以及相关设计软件的使用,并激起读者对 SOPC 技术的兴趣。本实验重点讲 8051Core 的应用,并通过一个简单 C51 程序对 51Core 进行硬件测试。

本实验教程的内容编排如下:

第 1 章简单的描述了 MC8051 IP core 的基本结构及一些应用说明。

第 2 章详细的介绍 8051Core 综合、编译应用。包括 Quartus II软件的基本应用,ROM、RAM 模块的生成,8051Core 的封装及应用测试。 附录 A 为 MC8051 IP Core 的指令集。

在阅读本教程的过程中,请读者注意以下几点:

本教程在编写时充分借鉴了周立功编写的mc8051 IP核教程,同时针对其中较为落后的一些内容进行了更新(周立功的教程使用的还是Cyclone系列的器件,软件版本也很低,很多操作与目前使用的主流版本有较大区别),同时删除了其教程中使用Synplicity对工程进行综合的部分,转而使用Quartus II软件直接综合。

本实验教程的 MC8051 IP Core (V1.6) 源于 http://oregano.at/ip/8051.htm 网站,读者如有需要可到该网站下载。

第1章 MC8051 的基本结构

这一章将简单的介绍 MC8051 IP Core 的基本硬件结构和一些设计应用的注意事项,具

体内容包括:

1. 功能特点

2. 顶层结构

3. 设计层次

4. 硬件配置

5. 并行 I/O 口

6. 其它说明

本章介绍的内容可能过于简略,如果要更详细的资料可参考 mc8051_user_guide.pdf

文档(位于:“mc8051_v1.6源码.zip\Version1_6\doc”文件夹里面)。

1.1 功能特点

● 采用完全同步设计

● 指令集和标准 8051 微控制器完全兼容

● 指令执行时间为 1~4 个时钟周期,执行性能优于标准 8051 微控制器 8 倍左右

● 用户可选择定时器/计数器、串行接口单元的数量

● 新增了特殊功能寄存器用于选择不同的定时器/计数器、串行接口单元

● 可选择是否使用乘法器(乘法指令 MUL)

● 可选择是否使用除法器(除法指令 DIV)

● 可选择是否使用十进制调整功能(十进制调整指令 DA)

● I/O 口不复用

● 内部带 256Bytes RAM

● 最多可扩展至 64Kbytes 的 ROM 和 64Kbytes 的 RAM

● 最多可扩展至 64Kbytes 的 ROM 和 64Kbytes 的 RAM

1.2 顶层结构

MC8051 IP Core 顶层结构图如图 1.1 所示,图中指示了 mc8051_core 的顶层结构以及同 三个存储模块的连接关系,同时显示了顶层的输入输出 I/O 口,各 I/O 信号的描述如表 1.1 所示。定时器/计数器和串行接口单元对应于图中的 mc8051_tmrctr 和 mc8051_siu 模块,数量是可选择的,在图中用虚线表示。

图 1.1 MC8051 IP Core 顶层结构图

表 1.1 顶层信号名

1.3 设计层次

MC8051 IP Core 的层次结构及对应的 VHDL 文件如图 1.2 所示。

VHDL 源文件的命名格式如下:

核心由定时器/计数器、ALU、串行接口和控制单元各模块组成。ROM 和 RAM 模块不

包括于核心内,处于设计的顶层,方便于不同的应用设计及仿真。

图 1.2 MC8051 IP Core 的设计层次

1.4 硬件配置

1.4.1 定时器/计数器、串口和中断

标准的 8051 核只有两个定时器/计数器,一个串口和两个外部中断源。而在 MC8051 IPCore 中,这些单元最多可增加到 256 组,只需要在 VHDL 源程序文件 mc8051_p.vhd 中,更改C_IMPL_N_TMR、C_IMPL_N_SIU、C_IMPL_N_EXT的常量值就可以了,范围是1~256。相关的代码如程序清单 1.1 所示。

程序清单 1.1 定时器/计数器、串口及中断的配置程序

  --------------------------------------------------------------------
-- Select how many timer/counter units should be implemented
-- Default:
constant C_IMPL_N_TMR : integer := ;
-------------------------------------------------------------------- --------------------------------------------------------------------
-- Select how many serial interface units should be implemented
-- Default: C_IMPL_N_TMR ---(DO NOT CHANGE!)---
constant C_IMPL_N_SIU : integer := C_IMPL_N_TMR;
-------------------------------------------------------------------- --------------------------------------------------------------------
-- Select how many external interrupt-inputs should be implemented
-- Default: C_IMPL_N_TMR ---(DO NOT CHANGE!)---
constant C_IMPL_N_EXT : integer := C_IMPL_N_TMR;
--------------------------------------------------------------------

C_IMPL_N_TMR、C_IMPL_N_SIU、C_IMPL_N_EXT 这三个常量是不能独立修改数值的,也就是说只能同时增减。C_IMPL_N_TMR 加一,就意味 IP Core 中同时添加了两个定时器/计数器,一个串口单元和两个外部中断源。 为了控制这些新增的控制单元,微控制器在特殊寄存器内存空间增加了两个寄存器。分别是 TSEL(定时器/计数器选择寄存器,地址为 0X8E)和 SSEL(串口选择寄存器,地址为 0X9A),如果没有对这两个寄存器赋值,其缺省值为 1。电路结构如图 1.3 所示。

图 1.3 使用附加的 TSEL 寄存器选择 TCON 寄存器

如果在中断发生期间设备(寄存器)没被选中(比如 TSEL),那么相应的中断标志位将保持置位,直到中断服务程序被执行。

1.4.2 可选择的指令

在某些场合,有些指令是用不到的,因此可以通过禁用这些指令来节省片上(比如 FPGA)资源。这些指令有 8 位乘法器(MUL)、8 位除法器(DIV)和 8 位十进制调整器(DA)。禁用时只需要在 VHDL 源程序文件 mc8051_p.vhd 中将 C_IMPL_MUL(乘法指令 MUL)、 C_IMPL_DIV(除法指令 DIV)或 C_IMPL_DA(十进制调整指令 DA)的常量值设置为 0。相应的 VHDL 程序代码段如所示。

程序清单 1.2 可选指令配置程序

  --------------------------------------------------------------------
-- Select whether to implement () or skip () the multiplier
-- Default:
constant C_IMPL_MUL : integer := ;
-------------------------------------------------------------------- --------------------------------------------------------------------
-- Select whether to implement () or skip () the divider
-- Default:
constant C_IMPL_DIV : integer := ;
-------------------------------------------------------------------- --------------------------------------------------------------------
-- Select whether to implement () or skip () the decimal adjustment command
-- Default:
constant C_IMPL_DA : integer := ;
--------------------------------------------------------------------

这三条可选择指令如果没被设置执行,芯片(FPGA)可节省将近 10%的空间(资源)。

1.5 并行 I/O 口

为了便于 IC 设计,MC8051 IP Core 的 I/O 口不提供复用功能,包括 4 个 8 位输入输出口、串行接口、计数器输入端和扩展存储器接口。如果 I/O 要做为双向口应用,其基本电路

结构图如图 1.4 所示。

图1.4 并行I/O口基本结构

1.4 中的两个 D 触发器起同步输入信号的作用(mc8051_core 的输入 I/O 无做同步处理),也可以不用。上拉电阻是必要的,因为 I/O 口输出高电平是靠上拉电阻实现的。

1.6 其它说明

(1) MC8051 IP Core 的定时器和串口波特率的计算和标准 8051 一样,计数时钟也是由系 统时钟经 12 分频得到。

(2) 外部中断信号是经两级寄存器做同步处理后输入的。

(3) MC8051_core 的输入 I/O 没有做同步处理,必要时可自己添加,如图 1.4 所示。

(4) 写应用程序时,I/O 口如果没有做成双向口(如图 1.4 所示),而是输入和输出分开的,那么要特别注意,像 P1=~P1、P1^0=P1^0 这样的 I/O 取反操作是无效(不起作用)的,因为读回来的值不是 I/O 寄存器的值,而是输入引脚的状态。

(5) MC8051 IP Core 经 Quartus II 综合编译后,观看时序分析报告,其最高运行频率为 32MHz(每次编译都可能不同,I/O 分配不同结果可能不同),因此系统时钟不能超过时序报告的时钟最高频率(即 fmax)。

第2章 MC8051 的硬件运行

本实验的硬件平台是采用芯航线FPGA学习套件,关于本实验套件的的详细介绍,请参看《芯航线FPGA学习平台用户手册》,这里就不重复说明。这里只简单说一些本实验用到的硬件资源以及相关软件的基本操作。

本章我们主要讲述 MC8051 core 的生成及封装,最后进行硬件下载运行并测试 I/O 口、 UART 及定时器。用到的硬件资源有为开发套件核心板上的LED0~LED3 、USB转串口接口。 本章将分以下几部分来讲述:

1. MC8051 中 ROM、RAM 模块的生成;

2. MC8051 core RTL 的封装;

3. MC8051 core 在 Quartus II 中的应用;

4. 测试 MC8051 的 I/O、UART 和定时器功能。 本实验力求以详细的步骤和讲解让读者以最快的方式学会 MC8051 IP core 的应用以及

相关设计软件的使用,并激起读者对 SOPC 技术的兴趣。

2.1 MC8051 中 ROM、RAM 模块的生成

本节的内容是建立一个 Quartus II 应用工程,并利用 Quartus II 自身集成的 Megawizard Plug_in Manager 工具(/在Quartus II 14.0版本及以后,名字改为了IP Catlog)来生成 MC8051 中所需的内部 RAM、外扩 RAM 及 ROM。

2.1.1 建立 Quartus II 工程

从【开始】>>【程序】>>Altera>>Quartus II 13.0】或直接双击桌面的Quartus II软件图标打开 Quartus II 13.0 软件,软件界面如图 2.1 所示。

图 2.1 Quartus II 软件界面

在图 2.1 中从【File】>>【New】打开新建文件选项卡,在选项卡中选择【New Quartus II Project】来新建一项工程,软件界面如图 2.2 所示。

图 2.2 新建Quartus II 文件

打开后显示界面如下所示:

图 2.3 新建工程路径、名称、顶层实体指定对话框

不要将文件夹设在计算机已有的安装目录中,更不要将工程文件直接放在安装目录中。文件夹所在路径名和文件夹名中不能用中文,不能用空格,不能用括号(),可用下划线_,最好也不要以数字开头。

2.3 第一栏用于指定工程所在的工作库文件夹;第二栏用于指定工程名,工程名可以取任何名字,也可以直接用顶层文件的实体名作为工程名(建议使用);第三栏用于指定顶层文件的实体名。本例工程的路径为 E:\CoreCourse_fpga\mc8051_test文件夹,工程名与顶层文件的实体名同名为 mc8051_test。

接着单击进入2.4所示的添加文件对话框。

图 2.4 新建工程添加文件对话框

由于是新建工程,暂无输入文件,所以直接单击,进入图2.5所示的指定目标器件对话框。这里我们选择芯航线FPGA核心板上使用的Cyclone IV系列的EP4CE10F17C8

图 2.5 新建工程器件选择对话框

在图 2.5 右边的过滤器栏(Filters)中,设计者可以通过指定封装、管脚数以及器件速

度等级来加快器件查找的速度。

指定完器件后,单击进入图2.6所示的自定EDA工具对话框。

图 2.6 新建工程 EDA 工具设置对话框

本实验利用 QuartusII 的集成环境进行开发,不进行仿真验证,故不使用任何 EDA 工具,因此这里不作任何改动。图 2.6 中单击 进入图 2.7 所示的工程信息报告对话框。从工程信息报告对话框,设计者可以看到工程文件配置信息报告。点击,完成新建工程的建立。 需要注意的是,建立工程后,还可以根据设计中的实际情况对工程进行重新设置,可选择【Assignments>> Settings…】进行设置,也可以选择工具栏上的按钮。

图 2.7 新建工程配置信息报告对话框

2.1.2 建立工程顶层文件

在Quartus II中,常见的顶层文件有原理图形式和Verilog/VHDL形式,早期高校教学多选择以原理图形式为主。采用原理图形式作为工程顶层,在工程并不复杂的情况下,方便清晰的展示设计结构。但是当设计变的复杂,顶层中需要添加的模块越来越多之后,原理图形式的顶层文件,弱点也明显的暴露出来,主要表现为连线复杂,容易出错,可读性差,不便于修改。同时,随着Quartus II新版本软件的推出,不同版本间对于原理图形式的文件解析方式有差异,导致同一工程在不同的软件版本中打开的样式并不一致,在升级中很容易出错。因此这里采用Verilog/VHDL的形式创建文件顶层。

由于目前Verilog的普及率越来越高,熟悉Verilog的人远远大于熟悉VHDL的人,因此这里我们使用Verilog格式的文件来作为工程顶层。

点击【File>>New…】,选择Verilog HDL File,如图 2.8 所示:

图 2.8 新建Verilog HDL文件对话框

点击OK即可创建一个新的Verilog文件。

接着点击【File>>Save As…】将文件存储为” mc8051_test.v”, 如图 2.9 所示:

图 2.9 保存Verilog文件

该文件就将作为我们工程的顶层文件

2.1.3 ROM 和 RAM 模块的生成

MC8051 中所需要的存储模块有,内部 RAM、扩展 RAM 和 ROM。其中内部RAM 和ROM 是必要的,内部 RAM 固定为 128Bytes,ROM 最大可选 64KBytes,鉴于 FPGA(这里我们选用 EP4CE10)片上 RAM 资源有限(EP4CE10的片上 RAM 约 51.75KBytes,这里我们选择 4Kbytes(可根据自己需要修改);扩展 RAM 是可选,最大也可以达到 64KBytes,这里我们选择 2Kbytes。

(1)创建一个ROM模块所需使用的初始化文件

这里首先创建该文件是为了使后面创建ROM模块时能够顺利进行。因为在生成ROM模块时,如果不指定一个存在的hex或mif格式的初始化文件,生成过程是无法顺利完成的。

点击【File>>New…】,选择Hexadecimal (Intel-Format)File。然后点击OK。如图 2.10所示:

图 2.10 新建hex文件

在弹出的对话框中,设置Number of words为4096,Word size为8,然后点击OK,即可创建一个新的hex文件,如图 2.11所示:

图 2.11 设置hex文件大小

接着点击【File>>Save As…】将文件存储为” mcu_test.hex”。 如图 2.12所示:

图 2.12 保存hex文件

(2) 生成ROM模块

(1) 从【Tools>>MegaWizard Plug-In Manager…】打开如图 2.13 所示添加兆功能模块向导。选择【Create a new custom megafunction variation】新建一个新的兆功能模块。然后点击进入向导 page2。

图 2.13 添加兆功能模块向导对话框

(2) 在 page2,在搜索框中输入“rom”,选择搜索结果中的ROM:1-PORT,然后指定生成这个ROM 的器件系列(默认已经是Cyclone IV E),硬件描述语言(VHDL)和输出文件存放路径及名字(mc8051_rom),如图2.14所示。

图 2.14 page2创建ROM IP核

(3) 在 page3 上,设置 ROM 的信息:数据宽度 8bits,数据个数 4069。其余默认就行了。如图 2.15 所示。

图 2.15 page3 设置存储器大小

(4) 在 page4 上,取消 ROM 的输出寄存器,时钟使能信号及异步清零信号不用选,如图2.16所示

图 2.16 page4 取消输出寄存器

(5) 如图 2.17 所示在 page5 上指定 ROM 的初始化数据文件(也即单片机程序的机器码.hex 文件)。初始化数据文件可以是.mif 或.Hex 文件。对于 ROM 模块,是一定要指定初始化数据的,要不然向导就不能完成。这里我们选择之前创建的那个空白hex文件mcu_test.hex 文件(这里我们是先先随便找了个.hex 文件填进去,到后面再更换成我们所要的测试文件)。

然后我们勾选“Allow In-System Memory Content Editor to capture and update content independently of the system clock”,这样,当我们更改了我们的软件代码并生成了新的Hex文件时,就可以直接使用In-System Memory Content Editor工具来在线将新的hex文件下载到ROM中,从而避开在工程中重新替换hex文件并编译工程的工作。

图 2.17 page5 指定ROM的初始化hex文件

(6) 在 page6 上,不需要进行任何更改

(7) 在page7上,选择需要生成的文件,这里我们勾选上mc8051_rom_inst.vhd。然后点“finish”即可生成 ROM 宏单元了。其中 mc8051_rom.vhd 为生成的VHDL 源文件。如图 2.18 所示

图 2.18 page7 指定需要生成的文件

(2) 生成RAM模块

MC8051 中 RAM 模块包括内部 RAM 和扩展 RAM,其生成方法和 ROM 的生成方法差不多。这里只简单的说一下参数设置,详细的步骤可参考 ROM 模块的生成这一部分的内容。

(1) 内部 RAM 的参数设置 在如图 2.14 所示的对话框中输入ram,在搜索结果中选择 RAM:1-PORT 模块,并将其命名为 mc8051_ram;设置数据宽度为 8bits,数据个数为 128;取消 RAM 的数据输出寄存器,同时选中时钟使能信号端,如图 2.19所示;勾选上生成mc8051_ram_inst.vhd文件,其它的选项默认不变。

图 2.19 page7 RAM设置

(2) 扩展 RAM 的参数设置 在如图 2.14 所示的对话框中输入ram,在搜索结果中选择 RAM:1-PORT 模块,并将其命名为 mc8051_ramx;设置数据宽度为 8bits,数据个数为 2048;取消 RAM 的数据输出寄存器;不需要选中时钟使能信号端,如图 2.20所示;勾选上生成mc8051_ramx_inst.vhd文件,其它的选项默认不变。

图 2.20 page7 RAM设置

至此我们已经完成了 mc8051 中 ROM、RAM 模块的生成。下面将介绍如何对 mc8051

core 进行封装,也可以说是对 mc8051 core 进行打包,方便于以后的设计调用。

2.2 MC8051 core 的组装

到现在为止,MC8051核RTL级实现的所有模块都已经具备了,接下来就使用将这些模块组装到一起,得到一个含完整mc8051核的Quartus· II工程,在新建工程之前我们还要对一些 mc8051 core 的源文件进行更新修改,使之符合我们的设计。

2.2.1 更新 mc8051 core 的顶层源文件

由于默认提供的源码中的顶层设计文件中的存储模块(ROM、RAM)是仿真时使用的, 现在要进行硬件测试,所以必须改成我们实际用到的 ROM、RAM 模块(也就是前一节我们生成的 ROM、RAM 模块)。

(1) 首先在工程目录下新建一个 mc8051core 的文件夹,将 mc8051 core 的源代码文件(位于:\mc8051_Source\VHDL 目录)拷贝到 mc8051core 文件夹。

(2) 打开 mc8051_Source\VHDL 目录下的 mc8051_p.vhd 文件,将原文件中 ROM、RAM 模块调用的代码(如程序清单 2.1 所示)全部替换为符合本设计的程序代码(如程序清单 2.2 所示)。

程序清单 2.1 mc8051_p.vhd 文件代修改代码

  --------------------------------------------------------------------
-- START: Component declarations for simulation models
--------------------------------------------------------------------
component mc8051_ram
port (
clk : in std_logic;
reset : in std_logic;
ram_data_i : in std_logic_vector( downto );
ram_data_o : out std_logic_vector( downto );
ram_adr_i : in std_logic_vector( downto );
ram_wr_i : in std_logic;
ram_en_i : in std_logic);
end component; component mc8051_ramx
port (
clk : in std_logic;
reset : in std_logic;
ram_data_i : in std_logic_vector( downto );
ram_data_o : out std_logic_vector( downto );
ram_adr_i : in std_logic_vector( downto );
ram_wr_i : in std_logic);
end component; component mc8051_rom
port (
clk : in std_logic;
reset : in std_logic;
rom_data_o : out std_logic_vector( downto );
rom_adr_i : in std_logic_vector( downto ));
end component;
--------------------------------------------------------------------
-- END: Component declarations for simulation models
--------------------------------------------------------------------

程序清单 2.2 mc8051_p.vhd 文件更新的源代码

  --------------------------------------------------------------------
-- START: Component declarations for simulation models
--------------------------------------------------------------------
component mc8051_ram
port (
clock : in std_logic;
data : in std_logic_vector( downto );
q : out std_logic_vector( downto );
address : in std_logic_vector( downto );
wren : in std_logic;
clken : in std_logic);
end component; component mc8051_ramx
port (
clock : in std_logic;
data : in std_logic_vector( downto );
q : out std_logic_vector( downto );
address : in std_logic_vector( downto );
wren : in std_logic);
end component; component mc8051_rom
port (
clock : in std_logic;
q : out std_logic_vector( downto );
address : in std_logic_vector( downto ));
end component; --------------------------------------------------------------------
-- END: Component declarations for simulation models
--------------------------------------------------------------------

(3) 打开 mc8051core目录下的 mc8051_top_struc.vhd 文件,首先做如程序清单 2.3 所示修改,其中行末标注“--new”的行为新增加的内容。然后将原文件中 ROM、RAM 模块调用部分的代码修改成如程序清单 2.4 所示的代码。这样就完成了源文件更新修改。

程序清单 2.3 mc8051_top_struc.vhd 文件新增的代码

architecture struc of mc8051_top is

  signal s_rom_adr_sml:   std_logic_vector( downto );  -- new
signal s_ramx_adr_sml: std_logic_vector( downto ); -- new signal s_rom_adr: std_logic_vector( downto ); -- Programmcounter =
-- ROM-adress
signal s_rom_data: std_logic_vector( downto ); -- data input from ROM
signal s_ram_data_out: std_logic_vector( downto ); -- data output to
-- internal RAM
signal s_ram_data_in: std_logic_vector( downto ); -- data input from
-- internal RAM
signal s_ram_adr: std_logic_vector( downto ); -- internal RAM-adress
signal s_ram_wr: std_logic; -- read ()/write ()
-- internal RAM
signal s_ram_en: std_logic; -- RAM-block enable
signal s_ramx_data_out: std_logic_vector( downto ); -- data output to
-- ext. RAM
signal s_ramx_data_in: std_logic_vector( downto ); -- data input from
-- ext. RAM
signal s_ramx_adr: std_logic_vector( downto ); -- ext. RAM-adress
signal s_ramx_wr: std_logic; -- read ()/write ()
-- ext. RAM begin -- architecture structural
s_rom_adr_sml <= std_logic_vector(s_rom_adr( downto )); -- *** new
s_ramx_adr_sml <= std_logic_vector(s_ramx_adr( downto )); -- *** new i_mc8051_core : mc8051_core
port map(clk => clk,
reset => reset,
rom_data_i => s_rom_data,

其中,

就是新增加的内容

程序清单 2.4 mc8051_top_struc.vhd 文件中更新的源代码

  --------------------------------------------------------------------
-- Hook up the general purpose 128x8 synchronous on-chip RAM.
i_mc8051_ram : mc8051_ram
port map (
clock => clk,
data => s_ram_data_in,
q => s_ram_data_out,
address => s_ram_adr,
wren => s_ram_wr,
clken => s_ram_en); -- THIS RAM IS A MUST HAVE!!
-------------------------------------------------------------------- --------------------------------------------------------------------
-- Hook up the (up to) 64kx8 synchronous on-chip ROM.
i_mc8051_rom : mc8051_rom
port map (
clock => clk,
q => s_rom_data,
address => s_rom_adr_sml);
-- THE ROM OF COURSE IS A MUST HAVE, ALTHOUGH THE SIZE CAN BE SMALLER!!
-------------------------------------------------------------------- --------------------------------------------------------------------
-- Hook up the (up to) 64kx8 synchronous RAM.
i_mc8051_ramx : mc8051_ramx
port map (
clock => clk,
data => s_ramx_data_out,
q => s_ramx_data_in,
address => s_ramx_adr_sml,
wren => s_ramx_wr);
-- THIS RAM (IF USED) CAN BE ON OR OFF CHIP, THE SIZE IS ARBITRARY.
--------------------------------------------------------------------

2.2.2 添加mc8051 Core相关文件到Quartus II工程中

在将mc8051的源码添加到Quartus II工程前,我们需要首先对部分文件的文件名进行更改。原版的VHDL源码,部分文件的文件名末尾加了有“_”,而实际源码中的模块名没有加“_”,因此,如果将这些文件直接添加到Quartus II工程中,编译就会报错,提示找不到模块。

因此我们首先将源码文件以“_”结尾的文件名中的“_”全部去掉,例如,将“addsub_core_.vhd”更改为“addsub_core.vhd”。当所有的文件名更改完成之后,方可添加这些文件到工程中。

在Quartus II软件中,点击【Project】>>Add/Remove Files in Project】,在弹出的对话框中,点击浏览文件符号,如图 2.21 所示:

图 2.21 添加文件按钮

选择mc8051core文件夹下的所有非配置文件(即以cfg结尾的文件不用选中),然后点击打开按钮,即可将文件添加到工程中来。如图 2.22 所示:

图 2.22 选择需要添加的文件

点“OK”完成文件的添加。

2.2.3设置工程顶层文件

在Files栏中,选中mc8051_top.vhd文件,点击右键,选择“Set as Top-Level Entity”,即可将mc8051_top.vhd设置为工程的顶层文件,(这里设置为顶层主要是为了封装IP核方便,临时性的,并不是最终作为工程顶层)。如图 2.23 所示:

图 2.23 选择需要添加的文件

2.2.4 综合工程文件

(1) 综合工程

在 Quartus II 软件的主界面,点击分析和综合按钮(或者直接按键盘组合键ctrl+k),即可开始对工程进行分析和综合。这个过程大概需要几分钟到十几分钟,视软件版本和电脑配置,耗费时间有差异。

(2) 查看RTL图

综合编译后我们需要检查顶层设计是否正确,这时可以通过 RTL 图来检查,双击RTL Viewer,如图2.24 所示

图 2.24 点击打开RTL Viewer

按钮可以打开 RTL 图,我们可以很清晰的看到 8051 core 的顶层结构图,如图 2.25所示。如果没问题我们就可以进行下一步的设计了。

图 2.25 mc8051 core RTL 图

2.3 MC8051 core 在 Quartus II 中的应用

在看这节内容之前建议大家先看一下 2.4 节,了解一下单片机的应用测试程序及测试流

程,因为这两部分内容是同时进行,密切关联。

在这一节我们将对 2.1 节建立的 Quartus 工程做进一步的设计,并将 mc8051 core 应用

于设计中。同时对 Quartus 的简单应用做进一步的学习。具体包括以下内容:

1. 建立 PLL 数字锁相环模块;

2. mc8051 core 在 Quartus II 中的应用设计;

3. FPGA 参数设置;

4. 下载硬件设计到目标 FPGA。

2.3.1 建立 PLL 数字锁相环模块

众所周知,单片机需要时钟信号才能运行,那怎样才能得到一个稳定而可靠的时钟源呢?我们的实验板上有一个 50MHz 的有源晶振,但对于 mc8051core 来说,频率比较高,需要分频,这时可以用 FPGA 自带的 PLL 调整时钟频率,PLL 输出的时钟频率、相位都可调而且精度很高,下面我们将介绍如何在 Quartus II 中调用 PLL 模块。

(1) 打开我们在 2.1 节建立的 QuartusII 工程,从【Tool】>>【MegaWizard Plug-In Manager…】打开如图 2.13 所示的添加宏单元的向导。

(2) 在图 2.13 中按进入向导第 2 页,按图 2.26 所示输入“pll”选择 ALTPLL,并选择器件类型及存放路径,注意标记部分。

图 2.26 MegeWizard Plug-In Manager page2

(3) 在图 2.26 中按进入向导第 3 页,按图 2.27 所示选择和设置,注意标记部分。由于电路板上的有源晶振频率为 50MHz,所以输入频率设为 50MHz。

图 2.27 page3 设置输入时钟频率

(4) 在图 2.27 中按进入向导第 4 页,在图 2.28 所示的窗口选择 PLL 的控制信号,如 PLL 使能控制“pllena”;异步复位“areset”;锁相输出“locked”等。这里我们不选任何控制信号。

图 2.28 page4 设置控制信号

(5) 在图 2.28中按连续按下直到进入向导第8页,按图2.30所示选择c0输出频率为18MHz,时钟相移和占空比不改变。

图 2.29 page8 设置时钟输出频率

(6) 在图 2.29 中按进入向导第 9 页 c1 的设置界面,由于c1以及后续其他输出都不再使用,因此,这里可以直接跳过其他所有输出的配置,直到最后按完成 PLL 兆功能模块的定制。

在完成定制 PLL 后,在 Quartus II工程文件夹中将产生 pll.bsf文件和 pll.v 的Verilog HDL源文件。

2.3.2 建立MC8051应用工程,

这一小节将讲述如何使用以上移植的mc8051的核建立一个实际的Quartus II 工程并能够在芯航线FPGA学习套件的主板上运行。 具体步骤如下:

(1) 在工程顶层中例化mc8051核

(2) 在工程顶层中例化pll

(3) 对工程进行分析和综合

(4) 分配引脚

(5) 编译并生成FPGA配置文件

(6) 使用USB Blaster配置FPGA

打开之前建立的Quartus II工程,打开mc8051_test.v文件,首先编写模块的端口,这个模块的端口也是工程最终的对外引脚,这里直接设置模块端口为mc8051的IO。 如程序清单2.5的第1行至第23行所示。

接着在工程中例化mc8051核,这里就是例化mc8051_top。Quartus II中,可以直接在Verilog文件中例化使用VHDL编写的模块,因此这里直接按照Verilog的格式例化mc8051_top即可,如程序清单2.5的第33行至第56行所示。注意,mc8051核的复位端口是高电平复位,而我们开发板上是将复位信号接到了轻触按键上,轻触按键在没有被按下时,输出的是高电平,因此该信号不能直接接到mc8051的复位输入端,需要先将其取反,因此直接在例化时将Rst_n取反后连接到mc8051的reset端即可(第36行)。

然后在工程中例化pll核,例化pll的代码如程序清单2.5的第27行至第31行所示,pll的时钟输入端连接到芯片的时钟输入信号Clk50M上,c0输出为18M,连接到mc8051的时钟输入端口clk上。

程序清单 2.5 mc8051_test.v 文件的源代码

  module mc8051_test(
input Clk50M,//板级时钟源,50M
input Rst_n, //复位端口
input int0_i, //mc8051外部中断0输入
input int1_i, //mc8051外部中断1输入
input all_t0_i, //mc8051计数器0输入
input all_t1_i, //mc8051计数器1输入 input [:]p0_i, //mc8051端口0输入
input [:]p1_i, //mc8051端口1输入
input [:]p2_i, //mc8051端口2输入
input [:]p3_i, //mc8051端口3输入 output [:]p0_o, //mc8051端口0输出
output [:]p1_o, //mc8051端口1输出
output [:]p2_o, //mc8051端口2输出
output [:]p3_o, //mc8051端口3输出 input all_rxd_i, //mc8051串口接收端口
output all_rxd_o, //mc8051串口方式0时输出端口
output all_txd_o, //mc8051串口发送端口
output all_rxdwr_o //rxd 输入/输出方向控制信号(高电平输出)
); wire Clk18M; //例化PLL模块
pll pll(
.inclk0(Clk50M),
.c0(Clk18M)
); //例化mc8051核
mc8051_top mc8051_top_inst(
.clk(Clk18M),
.reset(~Rst_n), //mc8051为高电平复位,因此将复位按键状态取反接到reset上
.int0_i(int0_i),
.int1_i(int1_i),
.all_t0_i(all_t0_i),
.all_t1_i(all_t1_i), .p0_i(p0_i),
.p1_i(p1_i),
.p2_i(p2_i),
.p3_i(p3_i), .p0_o(p0_o),
.p1_o(p1_o),
.p2_o(p2_o),
.p3_o(p3_o), .all_rxd_i(all_rxd_i),
.all_rxd_o(all_rxd_o),
.all_txd_o(all_txd_o),
.all_rxdwr_o(all_rxdwr_o)
); endmodule

接着我们将mc8051_test.v文件设置为工程顶层,然后点击分析和综合按钮(或者按下键盘组合键ctrl+k)来对工程进行分析和综合。

分析和综合完成后,我们打开Pin planner,进行引脚的锁定。依次点击【Assignments】>>【Pin Planner】,如图 2.30所示:

图 2.30 打开引脚分配卡

这里,我们只需要分配我们使用到的部分外设,没有使用到的暂不做引脚分配。本例中,我们将在Keil中编写软件代码测试mc8051的定时器、串口和P1口。我们使用开发板上板载的4个led灯进行测试P1口P1_o[0:3]的测试。因此我们需要分配引脚的端口有P1_o[0:3],all_rxd_i,all_txd_o,Clk50M以及Rst_n。其他没有使用的端口暂不分配引脚。引脚分配表如下所示:

将以上引脚对应分配给相应的信号即可。分配结果如图 2.31所示:

图 2.31 引脚分配结果

引脚分配完毕后,关闭Pin Planner,点击Start Compilation(或者键盘组合键ctrl+L)·来对工程进行全编译并生成FPGA配置文件(.sof)。

编译完毕后,使用USB Mini线连接芯航线FPGA开发板,连接上USB Blaster,然后打开Programmer,在Hardware Setup中选择USB Blaster。添加mc8051_test.sof文件,然后点击start即可将生成的配置文件下载到FPGA芯片中。如图 2.32所示:

图 2.32 引脚分配结果

2.4 测试 MC8051 的 I/O、UART 和定时器功能

在这一节中我们将通过一个简单的流水灯、UART 程序验证我们的 mc8051 core。

2.4.1 Keil C 测试程序

我们的 mc8051 core 已经建立起来了,现在需要一个程序进行硬件测试,这里的程序

是指普通的 51 程序,可以用 Keil C 或其它工具来编译我们写的测试程序,并生成.HEX 文件具体的操作过程就不用做介绍了。

如程序清单 2.6 所示是一个简单的测试程序,用于测试 I/O、定时器和 UART。定时器 0 用来做流水灯控制,从 P1 口输出;串口波特率(9600b/s)由定时器 1 决定 。

程序清单 2.6 mc8051 IP核测试程序

/*************************************************
* mc8051 IP核I/O、Timer、UART 测试程序
* 时钟频率:18MHz
* 文件名:main.c
*************************************************/
#include<reg51.h>
#include<stdio.h>
#define uchar unsigned char
#define uint unsigned int
char xdata Xcount _at_ 0x500; //定义外部 RAM 变量
uchar led=0xff; //LED 初化值
uchar counter; //500ms 计数器
//*************************** 延时程序
void delay(uint n)
{
uint k;
while(n--);
{
for (k=;k<;k++)
{;}
}
}
//*************************** 定时器中断 0 程序
void timer0(void) interrupt
{
ET0=; //关定时器 0 中断
TR0=; //不允许定时器 0 计数
TH0=0x8a; //重装定时初值(18MHz)
TL0=0xd0;
TR0=; //允许时器 0 计数
if(++counter==) //500ms 计数
{
counter=;
if(led==0xf0)
led=0xff;
else
led<<=; //左移 1 位
}
P1=led; //输出到 P0 口
ET0=;
}
//*************************** UART 程序
char putchar(char c)
{
SBUF = c;
if (c == '\n') SBUF = 0x0D;
while (!TI);
TI = ;
return (c);
}
//*************************** 主程序
main()
{
SCON = 0x50; //选择模式 1, 8 位数据格式,使能 UART
PCON |= 0x80; //波特率加倍
TMOD = 0x21; //定时器 0:模式 1;定时器 1:模式 2
TH0=0x8a; //20ms 定时初值(18MHz)
TL0=0xd0;
TH1 = 0xF6; //定时器 1 自动装载初值, 时钟频率 18MHz, 0xF6(9600bps)
TL1 = 0xF6;
TR0=; //允许定时器 0 计数
TR1 = ; //定时器 1 计数使能
ET0=; //允许定时器 0 中断
EA=; //开总中断
Xcount=;
while()
{
printf("Xiao MeiGe 8051 System On FPGA\n");
printf("Xin Hangxian Starter Board\n");
printf("http://xiaomeige.taobao.com/\n");
printf("This is the UART and led experiment\n");
printf("Xcount = %02bX\n",Xcount++);
printf("20160101\n");
printf("\n\n\n\n");
printf("hello world\n");
delay();
delay();
delay();
delay();
delay();
delay();
}
}

2.4.2 测试步骤

将程序清单 2.6 的程序进行编译并生成.hex 文件,为了方便大家测试,我们提供了一个创建好的Keil工程,在“mc8051_test\Cproject\uart_led”目录下,使用Keil C51 v4打开。

在Quartus II软件中,依次选择【Tools】>>【In-System Memory Content Editor】,打开In-System Memory Content Editor工具,右侧选择Hardware为USB-Blaster [USB-0],如图 2.33所示:

图 2.33 选择下载器

然后工具会自动搜索到器件和器件中存在的支持该工具的节点,搜索完成后整个工具界面如图 2.34所示:

图 2.34 In-System Memory Content Editor界面

鼠标选中ROM0(这里是我在配置ROM核的时候修改的索引名,如果你在配置的时候忘了修改索引名,则这里默认显示的名字应该是NONE),点击右键,选择Import Data From File。定位到C工程目录下,我这里为:E:\CoreCourse_fpga\mc8051_test\Cproject\uart_led,选择uart_led_test.hex文件并打开。这时候我们可以看到,工具下方已经有数据了,我们点击下传按钮以将数据传输进FPGA中的ROM中。如图 2.35所示:

图 2.35 下载程序到mc8051的ROM中

然后,我们打开电脑上的串口调试工具(任意一个你熟悉的就行),我这里使用友善串口调试助手,选择板子端口对应串口,设置波特率为9600,数据位为8位,无校验位,1位停止位,接收格式为ASCII。然后点击打开串口,则可以看到串口接收窗口中接收到了开发板传输过来的数据。同时板子开发板上的4个LED灯循环依次点亮。如图 2.36所示:

图 2.36 串口接收的数据

当我们的程序调试无误后需要固定到芯片中永久使用时,就将编译好的hex文件名称修改为mcu_test.hex,替换工程目录下原有的mcu_test.hex文件,然后重新编译文件,然后配置FPGA即可。

小梅哥

2016年2月26日星期五

芯航线电子工作室

小梅哥店铺链接:https://xiaomeige.taobao.com/

关于学习资料,小梅哥系列所有能够开放的资料和更新(包括视频教程,程序代码,教程文档,工具软件,开发板资料)都会发布在我的云分享。(记得订阅)链接:http://yun.baidu.com/share/home?uk=402885837&view=share#category/type=0

赠送芯航线AC6102型开发板配套资料预览版下载链接:链接:http://pan.baidu.com/s/1slW2Ojj 密码:9fn3

赠送SOPC公开课链接和FPGA进阶视频教程。链接:http://pan.baidu.com/s/1bEzaFW 密码:rsyh

附录 A MC8051 指令表

附表 1 MC8051 指令表

【小梅哥FPGA进阶教程】MC8051软核在FPGA上的使用的更多相关文章

  1. 【小梅哥FPGA进阶教程】第十四章 TFT屏显示图片

    十四.TFT屏显示图片 本文由杭电网友曾凯峰贡献,特此感谢 学习了小梅哥的TFT显示屏驱动设计后,想着在此基础上通过TFT屏显示一张图片,有了这个想法就开始动工了.首先想到是利用FPGA内部ROM存储 ...

  2. 【小梅哥FPGA进阶教程】第九章 基于串口猎人软件的串口示波器

    九.基于串口猎人软件的串口示波器 1.实验介绍 本实验,为芯航线开发板的综合实验,该实验利用芯航线开发板上的ADC.独立按键.UART等外设,搭建了一个具备丰富功能的数据采集卡,芯航线开发板负责进行数 ...

  3. 【小梅哥FPGA进阶教程】串口发送图片数据到SRAM在TFT屏上显示

    十五.串口发送图片数据到SRAM在TFT屏上显示 之前分享过rom存储图片数据在TFT屏上显示,该方法只能显示小点的图片,如果想显示TFT屏幕大小的图片上述方法rom内存大小不够.小梅哥给了个方案,利 ...

  4. 【小梅哥FPGA进阶教程】第十三章 四通道数字电压表

    十三.四通道数字电压表 本文由山东大学研友袁卓贡献,特此感谢 实验目的 设计一个四通道的数字电压表 实验平台 芯航线FPGA核心板.AD/DA模块 实验现象 实现一个四通道的数字电压表,其中可以用按键 ...

  5. 【小梅哥FPGA进阶教程】第十二章 数字密码锁设计

    十二.数字密码锁设计 本文由山东大学研友袁卓贡献,特此感谢 实验目的 实现数字密码锁设计,要求矩阵按键输出且数码管显示输入密码,密码输入正确与否均会有相应标志信号产生. 实验平台 芯航线FPGA核心板 ...

  6. 【小梅哥FPGA进阶教程】第十一章 四通道幅频相可调DDS信号发生器

    十一.四通道幅频相可调DDS信号发生器 本文由山东大学研友袁卓贡献,特此感谢 实验目标 实现多通道可调信号发生器 实验平台 芯航线FPGA核心板.ADDA模块 实验现象 实现基于FPGA的多通道可调信 ...

  7. FPGA的软核与硬核

    硬核 zynq和pynq系列的fpga都是双ARM/Cortex-A9构成,这里的ARM处理器为硬核,Cortex-A9部分为FPGA部分.即整体分为两部分:PS/PL.PS部分为A9处理器部分,PL ...

  8. ISE创建Microblaze软核(三)

    第七步 进入SDK开发环境 编译完成后弹出如下对话框,选择SDK的工作目录.在MicroblazeTutor中创建一个Workspace文件夹,并选择该文件夹为SDK的工作目录. 进入SDK主界面. ...

  9. 每天进步一点点------创建Microblaze软核(三)

    第七步 进入SDK开发环境编译完成后弹出如下对话框,选择SDK的工作目录.在MicroblazeTutor中创建一个Workspace文件夹,并选择该文件夹为SDK的工作目录.进入SDK主界面.第八步 ...

随机推荐

  1. java后台面试题整理

    java基础 Arrays.sort实现原理和Collection实现原理foreach和while的区别(编译之后)线程池的种类,区别和使用场景分析线程池的实现原理和线程的调度过程线程池如何调优线程 ...

  2. [Z]QPS、PV和需要部署机器数量计算公式

    QPS = req/sec = 请求数/秒 [QPS计算PV和机器的方式] QPS统计方式 [一般使用 http_load 进行统计]QPS = 总请求数 / ( 进程总数 *   请求时间 )QPS ...

  3. SharePreferences基本用法

    Android提供的轻量级数据储存方法,一般存少量数据,比如配置什么的.方式是通过键值对存取,比较方便. 下面通过一个 记住密码 的简单例子来说明 public class MainActivity ...

  4. 一个简单的环境光shader

    关于shader的一个简短的历史 在DirectX8之前,GPU有一个固定的方法去变换顶点和像素,称为“固定管线”.这使得在将它们传递给GPU后,开发者不可能操作顶点和像素的变换. DirectX8介 ...

  5. C++ Assert()函数

    assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义: #include <assert.h> void assert( i ...

  6. Android开发实战之简单音乐播放器

    最近开始学习音频相关.所以,很想自己做一个音乐播放器,于是,花了一天学习,将播放器的基本功能实现了出来.我觉得学习知识点还是蛮多的,所以写篇博客总结一下关于一个音乐播放器实现的逻辑.希望这篇博文对你的 ...

  7. 创建数据库sql语句

    create database JXGL; go create table S( sno char(10)primary key not null, sname nvarchar(10) not nu ...

  8. UIImage分类,设置边框

    #import "UIImage+image.h" @implementation UIImage (image) + (UIImage *)imageWithBorder:(CG ...

  9. Opencv Convex Hull (凸包)

    #include <iostream>#include <opencv2/opencv.hpp> using namespace std;using namespace cv; ...

  10. Linux安装设置VNC远程桌面

    1,先检查一下服务器是否已经安装了VNC服务,没有安装,检查服务器的是否安装VNC的命令如下[root@linuxidc rpms]# ps -eaf|grep vncroot      1789  ...