引言

之前我们写过OR的裸机程序,写过基于OR的linux设备驱动程序,也反汇编过OR的机器码。

本小节,我们将通过一个简单的实验,对OR的汇编(指令集)做一个简单的梳理和測试。

1,基本思想

要想了解OR的指令集,事实上仅仅要查查OpenRISC architecture manual就能够了,可是不是最好的熟悉方式,也没有必要将其全部指令集记下来。我觉得,通过一个实际的project或者样例,从中了解OR的指令集是比較好的一种方式。

那么,通过什么样例呢?

一般RISC的指令集包含,运算指令,分支指令,和訪存指令,三类。所以我们这个实验最好能用到这三类指令,碰巧,我近期在測试DDR控制器,所以我们以下将通过一个读写内存的样例来熟悉OR的指令集。

2,实验步骤

2.1实验准备

在開始编码之前,我们首先须要考虑例如以下几个问题:

a,怎样对汇编源程序(.S文件)进行编译,生成机器码。

b,怎样载入机器码使OR的指令总线能读到。

c,怎样查看机器码的执行过程和结果。

依据前面,我们积累下来的经验,可知,利用bootrom进行RTL仿真,能够非常好的解决上面三个问题。而且都是自己主动化的。

2.2 实验步骤

在了解并攻克了上面几个问题之后,剩下的就是详细的操作了。

a,改动soc-design/orpsocv2/sw/bootrom文件夹下的board.h

#ifndef _BOARD_H_
#define _BOARD_H_ //#define IN_CLK 50000000 // Hz
#define IN_CLK 66666667 // Hz
#define PRELOAD_RAM
#define BOOTROM_MEM_TEST
//
// ROM bootloader
//
// Uncomment the appropriate bootloader define. This will effect the bootrom.S
// file, which is compiled and converted into Verilog for inclusion at
// synthesis time. See bootloader/bootloader.S for details on each option.
#ifndef PRELOAD_RAM
#define BOOTROM_SPI_FLASH
//#define BOOTROM_GOTO_RESET
//#define BOOTROM_LOOP_AT_ZERO
//#define BOOTROM_LOOP_IN_ROM
#else
#ifdef BOOTROM_MEM_TEST
#define BOOTROM_MEM_TEST1
#else
#define BOOTROM_GOTO_RESET
#endif
#endif // Address bootloader should start from in FLASH
// Last 256KB of 2MB flash - offset 0x1c0000 (2MB-256KB)
#define BOOTROM_ADDR_BYTE2 0x1c
#define BOOTROM_ADDR_BYTE1 0x00
#define BOOTROM_ADDR_BYTE0 0x00
// Causes SPI bootloader to loop if SPI didn't give correct size of image
#define SPI_RETRY_IF_INSANE_SIZEWORD //
// Defines for each core (memory map base, OR1200 interrupt line number, etc.)
//
#define SDRAM_BASE 0x0 #define GPIO_0_BASE 0x91000000 #define UART0_BASE 0x90000000
#define UART0_IRQ 2
#define UART0_BAUD_RATE 115200 #define SPI0_BASE 0xb0000000
#define SPI0_IRQ 6 #define I2C_0_BASE 0xa0000000
#define I2C_0_IRQ 10 #define I2C_1_BASE 0xa1000000
#define I2C_1_IRQ 11 #define ETH0_BASE 0x92000000
#define ETH0_IRQ 4 #define ETH_MACADDR0 0x00
#define ETH_MACADDR1 0x12
#define ETH_MACADDR2 0x34
#define ETH_MACADDR3 0x56
#define ETH_MACADDR4 0x78
#define ETH_MACADDR5 0x9a //
// OR1200 tick timer period define
//
#define TICKS_PER_SEC 100 //
// CFI flash controller base
//
#define CFI_CTRL_BASE 0xf0000000 //
// UART driver configuration
//
#define UART_NUM_CORES 1
#define UART_BASE_ADDRESSES_CSV UART0_BASE
#define UART_BAUD_RATES_CSV UART0_BAUD_RATE //
// i2c_master_slave core driver configuration
// #define I2C_MASTER_SLAVE_NUM_CORES 2 #define I2C_MASTER_SLAVE_BASE_ADDRESSES_CSV \
I2C_0_BASE, I2C_1_BASE #endif

b,改动soc-design/orpsocv2/sw/bootrom文件夹下的bootrom.S

这个文件,是须要我们自己手动编写OR的汇编了。

须要注意的有几点。

首先,怎样让仿真自己主动退出:使用“l.nop 1”这条指令,详细原因可參考or1200_monitor.v文件里的相关内容。

其次,怎样推断读写内存的成功与失败,分别使用“l.nop 4”和“l.nop 3”。

最后,这些汇编,都非常easy理解,唯一须要注意的是OR支持延迟槽。

以下是详细代码清单:

//////////////////////////////////////////////////////////////////////
/// ////
/// bootrom Rill 2014-04-28 ////
/// ////
/// Assembly programs to be embedded inside system to aid boot ////
/// ////
/// ////
////////////////////////////////////////////////////////////////////// // Defines for which bootrom app to use are in board.h - TODO: use the
// processed orspoc-defines.v file for this define. It makes more sense
// as this software ends up as gates. #include "board.h" #ifdef BOOTROM_MEM_TEST1 #define RAM_LOAD_BASE 0x100000
#define RESET_ADDR 0x100
#define RAM_LOAD_VALUE 0x5555
#define RAM_LOAD_SIZE 0xc boot_init:
l.movhi r0, 0 /*0*/
l.movhi r1, RAM_LOAD_BASE /*1*/ mem_write:
l.movhi r6, 0 /*2*/ /* counter*/
l.ori r7, r0, RAM_LOAD_SIZE /*3*/
//l.movhi r7, RAM_LOAD_SIZE
l.movhi r8, 0 /*4*/ /* load addr index*/
write:
l.ori r3,r0, RAM_LOAD_VALUE /*5*/ /* Read a byte into r3 */
l.add r8, r1, r6 /*6*/ /* Calculate store address */
l.sw 0(r8), r3 /*7*/ /* Write byte to memory */
l.addi r6, r6, 4 /*8*/ /* Increment counter */
l.sfeq r6, r7 /*9*/ /* Check if we've finished loading the words */
l.bnf write /*10*/ /* Continue copying if not last word */
l.nop /*11*/ mem_read:
l.movhi r6, 0
l.ori r7, r0, RAM_LOAD_SIZE
l.movhi r8, 0
read:
l.add r8, r1, r6
l.lwz r3, 0(r8)
l.j check
l.nop
read2:
l.addi r6, r6, 4
l.sfeq r6, r7
l.bnf read
l.nop
l.j success
l.nop check:
l.ori r5,r0, RAM_LOAD_VALUE
l.sfeq r3, r5
l.bnf error
l.nop
l.j read2
l.nop error:
l.nop 3
l.j error
l.nop 1 success:
l.nop 4
l.j success
l.nop 1 #endif

c,创建C语言裸机測试文件夹和程序

因为我们想利用ORPSoC现成的測试环境,所以我们还须要编写一个假的,仅仅是为了满足原有的測试环境的文件夹和文件。

在soc-design/orpsocv2/board/xilinx/ml501/sw/tests文件夹下创建文件夹和文件:

mkdir mem
cd mem
touch mem.c
cp ../../Makefile .

编辑mem.c:

/*
* Rill
* april/28/2014
*/ int main()
{
while(1);//we run instructions in bootrom ONLY.
return 0;
}

因为我们仅仅执行bootrom.S中的指令,所以mem.c里面写什么语句不重要。

d,測试与验证

完毕编码之后,我们就能够执行我们刚才写的汇编程序了,方法我们之前已经介绍过多次了,这里反复例如以下:

在 soc-design/orpsocv2/board/xilinx/ml501/sim/run文件夹下执行例如以下:

make rtl-test TEST=mem VCD=1

非常快,我们就能够仿真结束,然后,我们就能够查看仿真日志文件和仿真波形。

从中能够看出,对内存的读写都是正确的。

or1200_monitor输出的日志文件:mem-general.log

58598000.0 ps: l.nop 4 putc (U)
58718000.0 ps: l.nop exit (00005555)

vcd波形文件:

3,小结

对于cpu来说,对全部外设(uart,i2c,vga......)的控制都能够通过load/store来完毕,和读写内存的实质是全然同样的,所以,通过上面的汇编,我们仅仅要改变一下读写地址改动成相应外设的地址,我们就能够实现对该设备的控制了。

当然,编写出优秀的汇编程序也不是一件太easy的事情,这就须要详细阅读OR的架构手冊,掌握GPR和SPR的用法。甚至,我们还要查看or32-elf-asm来了解更准确的OR的指令集。

OpenRisc-67-OR的汇编的更多相关文章

  1. 3.2 GUN as汇编(本文内容大部分引用原文,非原创)

    as86汇编仅仅用于编译内核中的boot/bootsect.s引导扇区程序和实模式下的设置程序boot/setup.s.内核中其余所有汇编语言程序(包括C语言产生的汇编程序)均使用gas来编译,并与C ...

  2. 从汇编看c++成员函数指针(三)

    前面的从汇编看c++中成员函数指针(一)和从汇编看c++成员函数指针(二)讨论的要么是单一类,要么是普通的多重继承,没有讨论虚拟继承,下面就来看一看,当引入虚拟继承之后,成员函数指针会有什么变化. 下 ...

  3. 从汇编看c++成员函数指针(二)

    下面先看一段c++源码: #include <cstdio> using namespace std; class X { public: virtual int get1() { ; } ...

  4. 从汇编看c++中的虚拟继承及内存布局(二)

    下面是c++源码: class Top {//虚基类 public: int i; Top(int ii) { i = ii; } virtual int getTop() { cout <&l ...

  5. C语言的本质(29)——C语言与汇编之寄存器和寻址方式

    x86的通用寄存器有eax.ebx.ecx.edx.edi.esi.这些寄存器在大多数指令中是可以任意选用的,比如movl指令可以把一个立即数传送到eax中,也可传送到ebx中.但也有一些指令规定只能 ...

  6. PC逆向之代码还原技术,第六讲汇编中除法代码还原以及原理第二讲,被除数是正数 除数非2的幂

    目录 一丶简介 二丶代码还原讲解 1.被除数无符号 除数非2的幂 2.被除数无符号 除数为特例7 三丶代码还原总结 一丶简介 上一篇博客说的除2的幂. 如果被除数是有符号的,那么会进行调整,并使用位操 ...

  7. C51汇编典型代码&一些org-mode技巧

    C51汇编典型代码&一些org-mode技巧 文档存放 具体内容可见存放的数据. 下面主要介绍关键代码. ASM 部分 1;; LCD数据发送========================= ...

  8. 基于汇编的 C/C++ 协程 - 切换上下文

    在前一篇文章<基于汇编的 C/C++ 协程 - 背景知识>中提到一个用于 C/C++ 的协程所需要实现的两大功能: 协程调度 上下文切换 其中调度,其实在技术实现上与其他的线程.进程调度没 ...

  9. 汇编看C函数调用

    http://blog.csdn.net/wishfly/article/details/5022008   简单的函数调用,通过简单的函数调用反汇编可以清楚了解如下 1.栈到底是什么,如何操纵栈的? ...

随机推荐

  1. java中子类与基类变量间的赋值

    Java中子类与基类变量间的赋值 子类对象可以直接赋给基类变量. 基类对象要赋给子类对象变量,必须执行类型转换, 其语法是: 子类对象变量=(子类名)基类对象名; 也不能乱转换.如果类型转换失败Jav ...

  2. SpringMVC + Spring + MyBatis 学习笔记:提交数据遭遇基础类型和日期类型报400错误解决方法

    系统:WIN8.1 数据库:Oracle 11GR2 开发工具:MyEclipse 8.6 框架:Spring3.2.9.SpringMVC3.2.9.MyBatis3.2.8 使用SpringMVC ...

  3. C/C++——C++变量的作用域与生命周期,C语言中变量的作用域和生命周期

    全局变量 作用域:全局作用域(全局变量只需在一个源文件中定义,就可以作用于所有的源文件.) 生命周期:程序运行期一直存在 引用方法:其他文件中要使用必须用extern 关键字声明要引用的全局变量. 内 ...

  4. arm tiny6410双网卡桥接问题

    这几天做实验,想用arm tiny6410板子做个mesh网络节点.该板子本身自带一个lan网卡,我自己配了一个tp-link的usb无线网卡.其中wlan网卡工作在adhoc模式下,作为mesh骨干 ...

  5. 第三百五十八天 how can I 坚持

    万事要有度,不要话唠,也不能不说,把握好分寸,今天貌似又说多了. 加了天班,理了个发,还有老爸明天来北京. 还有同学聚会没去,还有金龙让去吃鱼,没去. 还有.小米视频通话还行,能远程控制桌面, 还有, ...

  6. ms-class的进化

    ms-class是avalon用得最多的几个绑定之一,也正因为如此其功能一直在扩充中.根据时期的不同,分为旧风格与新风格两种. 旧风格是指正在ms-class后面跟着类外,然后在绑定值中添加表达式,即 ...

  7. G450 Ubuntu14 无线网卡解决

    安装了Ubuntu14,与win7共存. grub界面启动. G450的本子,安装完之后发现无线网卡不能被驱动,但能被之别到,因此激活一次broadcom sta wireless driver 命令 ...

  8. WEB数据挖掘(十六)——Aperture数据抽取(9):数据源

    One of the central concepts of Aperture is the notion of a DataSource. A DataSource contains all inf ...

  9. 编译安装-Percona 5.6

    CentOS 6.4编译安装Percona 5.6.16 Percona 下载地址:http://www.percona.com 一.卸载原有MySQL检查是否安装有MySQL Server: rpm ...

  10. 100个直接可以拿来用的JavaScript实用功能代码片段(转载)

    把平时网站上常用的一些实用功能代码片段通通收集起来,方面网友们学习使用,利用好的话可以加快网友们的开发速度,提高工作效率. 目录如下: 1.原生JavaScript实现字符串长度截取2.原生JavaS ...