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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

occ的开发框架

occ的开发框架 1.Introduction This manual explains how to use the Open CASCADE Application Framework (OCAF). It provides basic documentation on using OCAF. 2.Purpose of OCAF OCAF (the Open CASCADE Application Framework) is an easy-to-use platform for ra…

python识别图片中指定颜色的图案并保存为图片

示例代码&#xff1a; def chuli(color):import cv2import numpy as np# 定义颜色名称到HSV阈值范围的映射color_thresholds {red: ([0, 100, 100], [10, 255, 255], [160, 100, 100], [180, 255, 255]),yellow: ([20, 100, 100], [30, 255, 255]),blue: ([90, 100, 100], [1…

《利用深度神经网络在广角小口径望远镜中实现天文目标的检测与分类》论文精读

摘要 大口径小口径望远镜被广泛应用于光学瞬态观测&#xff0c;对观测图像中的天文目标进行检测和分类是最重要也是最基础的步骤。本文提出了一种基于深度神经网络的天文目标检测与分类框架。该框架采用了Faster R-CNN的概念&#xff0c;以改进的Resnet-50为主干网络&#xff…

Redis数据结构服务器

Redis数据结构服务器 什么是Redis数据结构服务器 的概念和特点 是一个开源&#xff08;BSD许可&#xff09;&#xff0c;内存中的数据结构存储服务器&#xff0c;可用作数据库、缓存和消息中间件。它支持多种类型的数据结构&#xff0c;如字符串&#xff08;strings&#xff09…

逻辑测试题

https://blog.csdn.net/qq_39081315/article/details/121393597 先生成一个点&#xff0c;每生成一个点判断距离&#xff0c;角度&#xff0c;满足加入存点的容器&#xff0c;直到容器大小为4。 随机生成点&#xff1a; 分区域&#xff1a;最大距离20&#xff0c;以20为正方形…

【UE5 C++课程系列笔记】27——多线程基础——ControlFlow插件的基本使用

目录 步骤 一、搭建基本同步框架 二、添加委托 三、添加蓝图互动框架 四、修改为异步框架 完整代码 通过一个游戏初始化流程的示例来介绍“ControlFlows”的基本使用。 步骤 一、搭建基本同步框架 1. 勾选“ControlFlows”插件 2. 新建一个空白C类&#xff0c;这里…

前端性能优化方面

页面加载过程 网页资源的加载通常需要以下基本步骤&#xff1a; 地址栏输入网页服务器地址 浏览器获取网页html文件 解析html文件中存在的js、css、图片等资源&#xff0c;通过网络线程加载 在特定时机执行js代码&#xff0c;可以在js中动态加载需要的静态资源 执行js里存在的f…

解锁“搭子小程序”开发新机遇,助力企业数字化转型

搭子作为一种新型的社交方式&#xff0c;逐渐进入到了年轻人的生活中&#xff0c;在日常旅游、学习、逛街等&#xff0c;年轻人都可以找到志同道合的“搭子”&#xff0c;提高生活的幸福指数。 随着搭子市场的发展&#xff0c;通过互联网寻找搭子已经成为了年轻人的必备方式。…

Open FPV VTX开源之ardupilot配置

Open FPV VTX开源之ardupilot配置 1. 源由2. 配置3. 总结4. 参考资料5. 补充5.1 飞控固件版本5.2 配置Ardupilot的BF OSD5.3 OSD偏左问题 1. 源由 飞控嵌入式OSD - ardupilot配置使用ardupliot配套OSD图片。 Choose correct font depending on Flight Controller SW. ──>…

Harmony NEXT开发ArkUI框架速成二基础语法

程序员Feri一名12年的程序员,做过开发带过团队创过业,擅长Java、嵌入式、鸿蒙、人工智能等,专注于程序员成长那点儿事,希望在成长的路上有你相伴&#xff01;君志所向,一往无前&#xff01; 1.ArkUI基础语法 1.1 ArkTS页面组成 在创建的时候&#xff0c;可以创建Page也可以直…

【树莓派3B】香瓜树莓派3B之语音识别机器人

本文最后修改时间&#xff1a;2018年04月03日 11:27 一、本节简介 本节用树莓派3代B型开发板做一个语音识别机器人&#xff0c;实现基础的语音对话功能。 注&#xff1a;转载原文路径 https://github.com/WhisperHear/Voice_Recognition_Control_Robot#userconsent# 上文个…

雷达流量监测系统:精准监控水流,确保水资源安全

水是生命之源&#xff0c;水资源的有效管理和保护直接关系到人类的生存与发展。随着全球气候变化和人口增加&#xff0c;水资源的短缺问题日益严重&#xff0c;如何高效监控和管理水资源&#xff0c;成为了水利、环保、农业等多个领域亟待解决的重要问题。而在这一过程中&#…

战场物联网:通信挑战与最新解决方案综述

论文标题 The Internet of Battle Things: A Survey on Communication Challenges and Recent Solutions 作者信息 Rachel Kufakunesu, Herman Myburgh, Allan De Freitas 论文出处 Discover Internet of Things (2025) 5:3 | The internet of battle things: a survey on…

GitLab 国际站中国大陆等地区停服,如何将数据快速迁移到云效

代码托管平台 GitLab 国际站&#xff08;GitLab.com&#xff09;近日发布公告&#xff0c;官宣即将停止对中国大陆、香港、澳门地区的用户账号提供服务&#xff0c;并提供 60 天过渡期自行迁移账户数据&#xff0c;超期未迁移的账号可能会被 GitLab 清除。这一重要决策引起了全…

React方向:react中5种Dom的操作方式

1、通过原生JS获取Dom去操作 通过document.querySelector(#title)原生js的方式去拿到dom节点&#xff0c;然后去进行操作。 import {Component} from "react";class App extends Component {//定义获取Dom的函数handleGetDom(){let title document.querySelector(#t…

更灵活的对象之间的联动 - 观察者模式(Observer Pattern)

观察者模式&#xff08;Observer Pattern&#xff09; 观察者模式&#xff08;Observer Pattern&#xff09;观察者模式&#xff08;Observer Pattern&#xff09;概述观察者模式&#xff08;Observer Pattern&#xff09; 结构图观察者模式&#xff08;Observer Pattern&#…

Webpack 5 混淆插件terser-webpack-plugin生命周期作用时机和使用注意事项

参考案例代码 海南酷森科技有限公司/webpack-simple-demo Terser&#xff08;简要的/简短的&#xff09; 混淆依据 混淆是发生在代码已经 bundle 之后的事情 变量或者函数在被引用或赋值时才能被混淆 孤立的函数或者变量可能会被移除&#xff0c;但不会被混淆&#xff0c;要…

‌OCP英文全称是什么

在数据库领域&#xff0c;OCP全称为Oracle Certified Professional&#xff0c;是Oracle公司提供的Oracle数据库中级认证&#xff0c;专门针对数据库管理员(Database Administrator&#xff0c;简称DBA)和数据库开发人员。以下是关于OCP认证的详细介绍&#xff1a; 认证领域与…

MyBatis实现数据库的CRUD

本文主要讲解使用MyBatis框架快速实现数据库中最常用的操作——CRUD。本文讲解的SQL语句都是MyBatis基于注解的方式定义的&#xff0c;相对简单。 Mybatis中#占位符和$拼接符的区别 “#”占位符 在使用MyBatis操作数据库的时候&#xff0c;可以直接使用如下SQL语句删除一条数…

微调神经机器翻译模型全流程

MBART: Multilingual Denoising Pre-training for Neural Machine Translation 模型下载 mBART 是一个基于序列到序列的去噪自编码器&#xff0c;使用 BART 目标在多种语言的大规模单语语料库上进行预训练。mBART 是首批通过去噪完整文本在多种语言上预训练序列到序列模型的方…