zoukankan      html  css  js  c++  java
  • OpenRisc-67-OR的汇编

    引言

    之前我们写过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的指令集。



  • 相关阅读:
    前端生成pdf文件之pdfmake.js
    vim 安装
    linux基础学习
    python 编码处理
    Ubuntu 下配置 SSH服务全过程及问题解决
    yum 安装
    Ubuntu安装MySQL
    Linux各发行版本及其软件包管理方法
    轻松学习LINUX系列教程推出
    常用命令
  • 原文地址:https://www.cnblogs.com/blfshiye/p/3789436.html
Copyright © 2011-2022 走看看