[读书日志]8051软核处理器设计实战(基于FPGA)第七篇:8051软核处理器的测试(verilog+C)

news2025/1/15 7:55:26

6. 8051软核处理器的验证和使用

为了充分测试8051的性能,我们需要测试每一条指令。在HELLO文件夹中存放了整个测试的C语言工程文件。主函数存放在指令被分为五大类,和上面一样。

在这里插入图片描述

在这里插入图片描述

打开后是这样的文件结构。HELLO.c是主文件,这是里面的代码:

/*------------------------------------------------------------------------------
HELLO.C

Copyright 1995-2005 Keil Software, Inc.
------------------------------------------------------------------------------*/

#include <REG52.H>                /* special function register declarations   */
                                  /* for the intended 8051 derivative         */

#include <stdio.h>                /* prototype declarations for I/O functions */

#include "instruction.h"


/*------------------------------------------------
The main C function.  Program execution starts
here after stack initialization.
------------------------------------------------*/
void main (void) {
  test_status = 1;
	
	instruction_test_all();
	
	
	if (test_status) {
		printf("Test success!\n");
	}else{
		printf("Test failed!\n");
	}
  printf("Test finished!\n");
	kill_self = 1;
  while (1);
}

这里引用了头文件instruction.h,它的实现在Instruction文件夹中,先看一下instruction.c的内容:

#include <REG52.H>
#include <stdio.h> 
#include "instruction.h"

void error(void){
	if (test_status==0) {
    printf("ERROR HERE...\n");
		while(1);
	}
}	

void instruction_test_all(void){
#ifdef ARITHMETIC
  arithmetic();  
#endif
#ifdef LOGICAL
	logical();
#endif
#ifdef TRANSFER
	transfer();
#endif
#ifdef BOOLEAN
	boolean();
#endif
#ifdef PROGRAM
	program();
#endif
}

void arithmetic(void){
#ifdef ADD_A_RN
    add_a_rn();
#endif
#ifdef ADD_A_DI
    add_a_di();
#endif	
#ifdef ADD_A_RI
    add_a_ri();
#endif		
#ifdef ADD_A_DA
    add_a_da();
#endif
#ifdef ADDC_A_RN
    addc_a_rn();
#endif	
#ifdef ADDC_A_DI
    addc_a_di();
#endif		
#ifdef ADDC_A_RI
    addc_a_ri();
#endif
#ifdef ADDC_A_DA
    addc_a_da();
#endif
#ifdef SUBB_A_RN
    subb_a_rn();
#endif
#ifdef SUBB_A_DI
    subb_a_di();
#endif
#ifdef SUBB_A_RI
    subb_a_ri();
#endif
#ifdef SUBB_A_DA
    subb_a_da();
#endif
#ifdef INC_A
    inc_a();
#endif
#ifdef INC_RN
    inc_rn();
#endif
#ifdef INC_DI
    inc_di();
#endif
#ifdef INC_RI
    inc_ri();
#endif
#ifdef INC_DP
    inc_dp();
#endif
#ifdef DEC_A
    dec_a();
#endif
#ifdef DEC_RN
    dec_rn();
#endif
#ifdef DEC_DI
    dec_di();
#endif
#ifdef DEC_RI
    dec_ri();
#endif
#ifdef MULT
    mult();
#endif
#ifdef DIVIDE
    divide();
#endif
#ifdef DA_A
    da_a();
#endif
}

这里只列出了一部分。可以看出通过预编译指令定义了五类指令及每一类的指令。而每一类中具体的指令通过汇编语言使用预编译指令进行编译。它们分布在剩余的几个c文件中。比如算术运算指令如下:

#include <REG52.H>
#include <stdio.h> 
#include "instruction.h"

void add_a_rn(void) {
	printf("ADD_A_RN\n");
	#pragma ASM  
	push psw
	push acc
  mov  psw,#0H	
  setb rs0     
	setb rs1	
  #pragma ENDASM 
	
	#pragma ASM
	mov acc,#01H
	mov R0,#0fH
	add A,R0
  #pragma ENDASM	
	if (ACC!=0x10) test_status = 0;
	if (AC!=1) test_status = 0;
	if (OV!=0) test_status = 0;
	if (CY!=0) test_status = 0;
	AC = 0;
		
	#pragma ASM
	mov acc,#40H
	mov R1,#40H
	add A,R1
	#pragma ENDASM
	if (ACC!=0x80) test_status = 0;
	if (AC!=0) test_status = 0;
	if (OV!=1) test_status = 0;
	if (CY!=0) test_status = 0;
	OV = 0;

	
	#pragma ASM
  mov acc,#80H
	mov R2,#81H
	add A,R2
  #pragma ENDASM
	if (ACC!=0x01) test_status = 0;
	if (AC!=0) test_status = 0;
	if (OV!=1) test_status = 0;
	if (CY!=1) test_status = 0;
	OV = 0;
	CY = 0;
	
	#pragma ASM
  mov acc,#0C0H
	mov R3,#0C2H
	add A,R3
  #pragma ENDASM
	if (ACC!=0x82) test_status = 0;
	if (AC!=0) test_status = 0;
	if (OV!=0) test_status = 0;
	if (CY!=1) test_status = 0;
	CY = 0;	
	
	#pragma ASM 
	pop acc
  pop psw	
  #pragma ENDASM 	
	error();
}

如果每一条指令都通过,最后会打印测试成功字样,如果有任何一条指令执行有误则会导致抛出错误和暂停测试。

将HELLO工程编译后生成了HELLO.bin,这就是我们最后需要使用的文件,将其留存。之后编写一个tb文件,用于对接接口和设置存储空间:

`timescale 1 ns/1 ps
`define PERIOD 10
`define HALF_PERIOD (`PERIOD/2)
//`define TYPE8052
`define CODE_FILE "C:/Users/15661/Desktop/R8051_test/HELLO/HELLO.bin"
module tb;

reg     clk = 1'b0;
always #`HALF_PERIOD clk = ~clk;

reg     rst = 1'b1;
initial #`PERIOD rst = 1'b0;

wire            rom_en;
wire [15:0]     rom_addr;
reg  [7:0]      rom_byte;
reg             rom_vld;

wire            ram_rd_en_data;
wire            ram_rd_en_sfr;
wire            ram_rd_en_xdata;
wire [15:0]     ram_rd_addr;

reg  [7:0]      ram_rd_byte;

wire            ram_wr_en_data;
wire            ram_wr_en_sfr;
wire            ram_wr_en_xdata;
wire [15:0]     ram_wr_addr;
wire [7:0]      ram_wr_byte;


r8051 u_cpu (
    .clk                  (    clk              ),
	.rst                  (    rst              ),
	.cpu_en               (    1'b1             ),
	.cpu_restart          (    1'b0             ),
	
	.rom_en               (    rom_en           ),
	.rom_addr             (    rom_addr         ),
	.rom_byte             (    rom_byte         ),
	.rom_vld              (    rom_vld          ),
	
	.ram_rd_en_data       (    ram_rd_en_data   ),
	.ram_rd_en_sfr        (    ram_rd_en_sfr    ),
	.ram_rd_en_xdata      (    ram_rd_en_xdata  ),
	.ram_rd_addr          (    ram_rd_addr      ),
	.ram_rd_byte          (    ram_rd_byte      ),
	.ram_rd_vld           (    1'b1             ),
	
	.ram_wr_en_data       (    ram_wr_en_data   ),
	.ram_wr_en_sfr        (    ram_wr_en_sfr    ),
	.ram_wr_en_xdata      (    ram_wr_en_xdata  ),
	.ram_wr_addr          (    ram_wr_addr      ),
	.ram_wr_byte          (    ram_wr_byte      )

);

reg [7:0] rom[(1'b1<<16)-1:0];

integer fd,fx;
initial begin
  fd = $fopen(`CODE_FILE,"rb");
  fx = $fread(rom,fd);
  $fclose(fd);
end
	
always @ ( posedge clk )
if ( rom_en )
    rom_byte <=  rom[rom_addr];
else;

always @ ( posedge clk )
rom_vld <=  rom_en;


reg [7:0] data [127:0];
reg [7:0] data_rd_byte;
always @ ( posedge clk )
if ( ram_rd_en_data )
    data_rd_byte <=  data[ram_rd_addr[6:0]];
else;

always @ ( posedge clk )
if ( ram_wr_en_data )
    data[ram_wr_addr[6:0]] <=  ram_wr_byte;
else;

reg [7:0] xdata [127:0];
reg [7:0] xdata_rd_byte;
always @ ( posedge clk )
if ( ram_rd_en_xdata )
    xdata_rd_byte <=  xdata[ram_rd_addr[6:0]];
else;

always @ ( posedge clk )
if ( ram_wr_en_xdata )
    if (( ram_wr_addr[6:0]==8'h7f ) & ram_wr_byte[0] ) begin
	    repeat(1000) @ (posedge clk);
		$display("Test over, simulation is OK!");
		$stop(1);
		end
	else
        xdata[ram_wr_addr[6:0]] <=  ram_wr_byte;
else;

reg [7:0] sfr_rd_byte;

always @ ( posedge clk )
if ( ram_wr_en_sfr & ( ram_wr_addr[7:0]==8'h99 ) )
    $write("%s",ram_wr_byte);
else;


always @ ( posedge clk )
if ( ram_rd_en_sfr ) 
    if ( ram_rd_addr[7:0]==8'h98 )
	    sfr_rd_byte <=  8'h3;
	else if ( ram_rd_addr[7:0]==8'h99 )
	    sfr_rd_byte <=  0;
	else
    begin
        $display($time," ns : --- SFR READ: %2h---",ram_rd_addr[7:0]);
        //$stop;
    end
else;	

always @ ( posedge clk )
if ( ram_wr_en_sfr )
    if(( ram_wr_addr[7:0]==8'h98 )|( ram_wr_addr[7:0]==8'h99 ))
	    #0;
    else	
    begin
    $display($time," ns : --- SFR WRITE: %2h -> %2h---",ram_wr_addr[7:0],ram_wr_byte);
    //$stop;
    end
else;	

reg [1:0] read_flag;
always @ ( posedge clk )
if ( ram_rd_en_sfr )
    read_flag <= 2'b10;
else if ( ram_rd_en_xdata )
    read_flag <= 2'b01;	
else if ( ram_rd_en_data )
    read_flag <= 2'b0;
else;

always @*
if ( read_flag[1] )
    ram_rd_byte = sfr_rd_byte;
else if ( read_flag[0] )
    ram_rd_byte = xdata_rd_byte;
else
    ram_rd_byte = data_rd_byte;

endmodule

将tb.v和R8051.v一起加入Modelsim工程(注意不要导入instruction.v,否则会报错,需要更改的有两处路径,分别是tb中引用HELLO.bin的路径,和R8051.v中对instruction.v引用的路径,更改后即可复现代码。)之后进行仿真,结果正确。

在这里插入图片描述

在这里插入图片描述

至此,我们的8051软核处理器开发基本完毕。之后可以自行修改一些功能,使用这套测试框架进行测试。现在这个软核处理器中没有添加中断,在书中并没有提供添加中断的说明。后续如果有机会将继续更新添加中断的内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2276893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vue实战】Vuex 和 Axios 拦截器设置全局 Loading

目录 1. 效果图 2. 思路分析 2.1 实现思路 2.2 可能存在的问题 2.2.1 并发请求管理 2.2.2 请求快速响应和缓存带来的问题 3. 代码实现 4. 总结 1. 效果图 如下图所示&#xff0c;当路由变化或发起请求时&#xff0c;出现 Loading 等待效果&#xff0c;此时页面不可见。…

一文读懂yolo11模型训练

一文读懂yolo11模型训练 一、环境准备 Anaconda安装 简介 Anaconda 是一个流行的开源 Python 发行版&#xff0c;专注于数据科学、机器学习、科学计算和分析等领域。它提供了一个强大的包管理器和环境管理器&#xff0c;名为 Conda&#xff0c;以及一个预装了大量科学计算和…

Apache PAIMON 学习

参考&#xff1a;Apache PAIMON&#xff1a;实时数据湖技术框架及其实践 数据湖不仅仅是一个存储不同类数据的技术手段&#xff0c;更是提高数据分析效率、支持数据驱动决策、加速AI发展的基础设施。 新一代实时数据湖技术&#xff0c;Apache PAIMON兼容Apache Flink、Spark等…

音视频入门基础:RTP专题(1)——RTP官方文档下载

一、引言 实时传输协议&#xff08;Real-time Transport Protocol&#xff0c;简写RTP&#xff09;是一个网络传输协议&#xff0c;由IETF的多媒体传输工作小组1996年在《RFC 1889》中公布的。 RTP作为因特网标准在《RFC 3550》有详细说明。而《RFC 3551》详细描述了使用最小…

【Vim Masterclass 笔记13】第 7 章:Vim 核心操作之——文本对象与宏操作 + S07L28:Vim 文本对象

文章目录 Section 7&#xff1a;Text Objects and MacrosS07L28 Text Objects1 文本对象的含义2 操作文本对象的基本语法3 操作光标所在的整个单词4 删除光标所在的整个句子5 操作光标所在的整个段落6 删除光标所在的中括号内的文本7 删除光标所在的小括号内的文本8 操作尖括号…

LiveGBS流媒体平台GB/T28181常见问题-没有收到视频流播放时候提示none rtp data receive未收到摄像头推流如何处理?

LiveGBS没有收到视频流播放时候提示none rtp data receive未收到摄像头推流如何处理&#xff1f; 1、none rtp data receive2、搭建GB28181视频直播平台 1、none rtp data receive LiveSMS 收不到下级推流 首先需要排查服务器端 UDP & TCP 30000-30249 端口是否开放其次排…

使用Docker模拟PX4固件的无人机用于辅助地面站开发

前言 最近在制作鸿蒙无人机地面站&#xff0c;模仿的是QGroundControl&#xff0c;协议使用mavlink&#xff0c;记录一下本地模拟mavlink协议通过tcp/udp发送 废话不多说直接上命令 1.启动docker的桌面端 启动之后才能使用docker命令来创建容器 docker run --rm -it jonas…

【Docker】保姆级 docker 容器部署 MySQL 及 Navicat 远程连接

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. docker 容器部署 MySQL1.1 拉取mysql镜像1.2 启动容器1.3 进入容器1.4 使用 root 用户登录 2. Navicat 连…

【大数据】机器学习-----线性模型

一、线性模型基本形式 线性模型旨在通过线性组合输入特征来预测输出。其一般形式为&#xff1a; 其中&#xff1a; x ( x 1 , x 2 , ⋯ , x d ) \mathbf{x}(x_1,x_2,\cdots,x_d) x(x1​,x2​,⋯,xd​) 是输入特征向量&#xff0c;包含 d d d 个特征。 w ( w 1 , w 2 , ⋯ ,…

装备制造行业(复杂机械制造)数字化顶层规划 - 汇报会

行业业务特点&#xff1a; 尊敬的各位管理层&#xff1a; 大家好&#xff01;今天我将向大家汇报装备制造企业数字化战略的顶层规划设计。在当今数字化浪潮下&#xff0c;装备制造企业面临着转型升级的迫切需求&#xff0c;数字化战略的制定与实施对于提升企业竞争力、实现可持…

深度探索C++20协程机制

#include <iostream> #include <coroutine>class CoroTaskSub { public://编译器在处理协程函数时是通过其返回类型【即协程接口类型】&#xff0c;确定协程的承诺类型和协程句柄类型struct promise_type;using CoroHdl std::coroutine_handle<promise_type>…

linux手动安装mysql5.7

一、下载mysql5.7 1、可以去官方网站下载mysql-5.7.24-linux-glibc2.12-x86_64.tar压缩包&#xff1a; https://downloads.mysql.com/archives/community/ 2、在线下载&#xff0c;使用wget命令&#xff0c;直接从官网下载到linux服务器上 wget https://downloads.mysql.co…

Java Stream实现【Int / Long / Double / Bigdecimal】累计求和

文章目录 背景实现方案案例素材Int类型求和Long 类型求和Double 类型求和BigDecimal 类型求和 背景 在项目开发中经常会使用到数据统计&#xff0c;Java中有求和的方法&#xff0c;可使用Java的Stream工作流实现&#xff0c;记录下来&#xff0c;方便备查。 实现方案 可使用…

OFD文件纯前端查看解决方案

文章目录 ofd.js原有bug修复1、ofd格式文档打开报错2、签章信息不显示 效果展示源码下载 使用前请查看免责声明 ofd.js原有bug修复 1、ofd格式文档打开报错 原因分析&#xff1a; 文档打开时会解析所用到的字体信息&#xff0c;如果字体不在ofd.js预设字体时&#xff0c;会触…

使用 Docker 部署 Java 项目(通俗易懂)

目录 1、下载与配置 Docker 1.1 docker下载&#xff08;这里使用的是Ubuntu&#xff0c;Centos命令可能有不同&#xff09; 1.2 配置 Docker 代理对象 2、打包当前 Java 项目 3、进行编写 DockerFile&#xff0c;并将对应文件传输到 Linux 中 3.1 编写 dockerfile 文件 …

二手车交易系统的设计与实现(代码+数据库+LW)

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统二手车交易信息管理难度大&#xff0c;容错率低&#xf…

抖音ip属地没有手机卡会显示吗

在数字时代&#xff0c;社交媒体平台如抖音已成为人们日常生活的重要组成部分。随着抖音等应用对用户体验和隐私保护的不断优化&#xff0c;IP属地显示功能逐渐走进大众视野。这一功能旨在提高网络环境的透明度&#xff0c;打击虚假信息和恶意行为。然而&#xff0c;对于没有手…

springMVC---resultful风格

目录 一、创建项目 pom.xml 二、配置文件 1.web.xml 2.spring-mvc.xml 三、图解 四、controller 一、创建项目 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi…

[Git] 深入理解 Git 的客户端与服务器角色

Git 的一个核心设计理念是 分布式&#xff0c;每个 Git 仓库都可以既是 客户端&#xff0c;也可以是 服务器。为了更好地理解这一特性&#xff0c;我们通过一个实际的 GitHub 远程仓库和本地仓库的场景来详细说明 Git 如何在客户端和服务器之间协作&#xff0c;如何独立地进行版…

网络安全-RSA非对称加密算法、数字签名

数字签名非常普遍&#xff1a; 了解数字签名前先了解一下SHA-1摘要&#xff0c;RSA非对称加密算法。然后再了解数字签名。 SHA-1 SHA-1&#xff08;secure hash Algorithm &#xff09;是一种 数据加密算法。该算法的思想是接收一段明文&#xff0c;然后以一种不可逆的方式将…