将陆续上传本人写的新书《自己动手写CPU》(尚未出版),今天是第14篇,我尽量每周四篇
4.4.6 编写Makefile文件
为了得到指令存储器初始化文件,我们需要输入4条命令,有点麻烦,最好只输入一条命令就可以了,这需要使用到Makefile文件。在汇编程序inst_rom.S所在目录下新建一个Document,文件名为Makefile,内容如下。
ifndef CROSS_COMPILE CROSS_COMPILE = mips-sde-elf- endif CC = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump OBJECTS = inst_rom.o export CROSS_COMPILE # ******************** # Rules of Compilation # ******************** all: inst_rom.data %.o: %.S $(CC) -mips32 $< -o [email protected] inst_rom.om: ram.ld $(OBJECTS) $(LD) -T ram.ld $(OBJECTS) -o [email protected] inst_rom.bin: inst_rom.om $(OBJCOPY) -O binary $< [email protected] inst_rom.data: inst_rom.bin ./Bin2Mem.exe -f $< -o [email protected] clean: rm -f *.o *.om *.bin *.data
这是一个很简单的Makefile,借助于它介绍Makefile的组成。Makefile的前半部分是一些变量的定义,比如:定义CC为mips-sde-elf-as,定义LD为mips-sde-elf-ld,其中引用了预定义的变量CROSS_COMPILE。Makefile的后半部分定义了多个目标,有all、clean等,采用的语法如下:
目标:依赖文件 命令
上述形式表示的意思是:(1)要想得到“目标”,那么需要执行“命令”;(2)“目标”依赖于“依赖文件”,当“依赖文件”中至少一个文件比“目标”文件新时,“命令”才被执行。在上面Makefile的“命令”中使用了Makefile一些预定义的变量,含义如下:
$< 表示第一个依赖文件的名称 [email protected] 表示目标的完整名称
所以上述Makefile可以解读如下:
(1)用户输入make all,要求得到目标all,目标all的依赖文件是inst_rom.data,要先得到inst_rom.data
(2)要得到inst_rom.data,需要依赖文件inst_rom.bin。
(3)要得到inst_rom.bin,需要依赖文件inst_rom.om。
(4)要得到inst_rom.om,需要依赖文件$(OBJECTS),其中OBJECTS是预定义变量,其值为inst_rom.o,所以此处就是需要依赖文件inst_rom.o。
(5)要得到inst_rom.o,需要依赖文件inst_rom.S,该文件已经提供,满足依赖条件,所以会执行命令$(CC) –mips $< -o [email protected],实际就是如下命令,执行后得到inst_rom.o。
mips-sde-elf-as –mips inst_rom.S –o inst_rom.o
(6)得到inst_rom.o后,满足了目标inst_rom.om的依赖条件,所以可以进一步得到inst_rom.om,通过执行命令$(LD) -T ram.ld $(OBJECTS)-o [email protected],实际就是通过如下命令得到inst_rom.om。
mip-sde-elf-ld -T ram.ld inst_rom.o –o inst_rom.om
(7)得到inst_rom.om后,满足了目标inst_rom.bin的依赖条件,所以可以进一步得到inst_rom.bin,通过执行命令$(OBJCOPY) -O binary$< [email protected],实际就是通过如下命令得到inst_rom.bin。
mip-sde-elf-objcopy -O binary inst_rom.om inst_rom.bin
(8)得到inst_rom.bin后,满足了目标inst_rom.data的依赖条件,所以可以进一步得到inst_rom.data,通过执行命令./Bin2Mem.exe -f $< -o [email protected],实际就是通过如下命令得到inst_rom.data。
./Bin2Mem.exe -f inst_rom.bin –o inst_rom.data
(9)得到inst_rom.data,满足了目标all的依赖条件,从而实现目标all。
有了Makefile文件,我们在终端中输入“make all”就可以完成所有的过程了。简单总结一下从测试程序得到指令存储器ROM初始化文件的步骤。
(1)编写源代码,当然是汇编代码,文件名为inst_rom.S。
(2)复制本节编写的Makefile、Bin2Mem.exe、ram.ld到源代码所在目录。
(3)打开终端,路径调整到源代码所在目录,输入“make all”。
经过上述步骤,即可得到能够在ModelSim仿真中使用的指令存储器ROM初始化文件inst_rom.data。
最后,我们可以增加一步,使用工具mips-sde-elf-objdump对inst_rom.om进行反汇编,从而得到指令与其二进制字的对应。如下。
mips-sde-elf-objdump -D inst_rom.om > inst_rom.asm
得到inst_rom.asm文件,使用记事本打开该文件,内容如图4-31所示。重点是图中使用黑框包围的部分,其对应的就是测试程序的4条指令。每一行分为三列:左边一列是指令地址,中间一列是指令对应的二进制字,右边是汇编指令。注意:这里的指令进行了变化,虽然测试程序都是ori指令,但是这里都改为了li指令,li是汇编指令,ori是机器指令,两者是相等的。
li rt, immediate => ori rt,$0,immediate
另外,此处的寄存器没有使用$1、$2、$3、$4这种方式,而是使用了约定命名。MIPS32中通用寄存器的约定命名可以参考第1章的表1-1。有了inst_rom.asm文件,在进行仿真波形分析的时候,有助于将仿真波形中的32bit二进制指令字与汇编程序中的指令对应,便于分析。
可以修改Makefile文件,使得在编译得到inst_rom.data的同时得到反汇编文件inst_rom.asm,具体修改方法不再详述,读者可以参考本书附带光盘的Code\Chapter4\TestAsm目录下的Makefile文件。
4.5 第一条指令实现小结
本章是很重要的一章,而且内容相对比较杂,在此做一小结,主要做了四项工作。
(1)本章通过实现指令ori,搭建了一个原始的五级流水线结构,这也是OpenMIPS的核心,当然,目前OpenMIPS还只能执行ori指令,后续会逐步丰富。
(2)实现了一个用于测试的最小SOPC,仅仅包括处理器OpenMIPS、指令存储器ROM,并编写了Test Bench测试文件。
(3)在ModelSim中通过仿真验证了ori指令实现的正确性,也验证了OpenMIPS五级流水线实现的正确性。
(4)详细介绍了从汇编代码编写的测试程序得到仿真中使用的指令存储器初始化文件的过程,同时,利用Makefile简化了这个过程。
第一条指令ori实现代码的下载地址:
http://download.csdn.net/detail/leishangwen/7686717
自己动手写CPU之第四阶段(4)——Makefile文件建立