虚拟机: VMware 17 pro
环境:Ubuntu 22.04.1
不多说现在开始:
编译环境搭建好的结果就是,在一个inst_rom.S文件中写好MIPS32的汇编代码,经过编译环境,最终得到一个inst_rom.data,结束编译。inst_rom.data可以在verilog语言中,通过系统函数$readmemh导入rom中,提供给MIPS32指令集的CPU执行。
1、在Ubuntu的一个文件夹,以计算机/opt文件夹为例,点击其他位置-双击打开“计算机”-双击打开“opt”文件夹-鼠标右击-在终端打开(作为新手,opt文件夹里面应该是空的):
2、新建 inst_rom.S文件
在终端输入:
su
(输入一个命令后按一下enter,接下来每条命令都enter)
然后输入Ubuntu密码(密码不会显示,输入完后enter),这个是获取root权限的过程,没有获取权限,做不了很多事。
在终端中输入
touch inst_rom.S
3、写 touch inst_rom.S 文件
在终端中,点击最小化
此时,./opt 文件夹下应该有一个 inst_rom.S,但这个时候你直接双击进去发现可能是只读,这个时候有两个办法,一个是在终端输入
sudo nautilus
,可能会要求输入密码,然后进入拥有root权限的文件夹,这个时候再修改inst_rom.S就没问题了。另一个方法是 在终端输入
sudo chmod 777 inst_rom.S
,通过修改inst_rom.S文件的读写权限, 这个时候就可以修改 inst_rom.S了。
再inst_rom.S文件写入《自己动手写CPU》中的代码例子:
.org 0x0
.global _start
.set noat
_start:
ori $1, $0, 0x1100 # $1 = $0 | 0x1100 = 0x1100
ori $2, $0, 0x0020 # $2 = $0 | 0x0020 = 0x0020
ori $3, $0, 0xff00 # $3 = $0 | 0xff00 = 0xff00
ori $4, $0, 0xffff # $4 = $0 | 0xffff = 0xffff
保存退出。
4、安装GNU工具链
在终端输入
mips-linux-gnu-gcc -v
根据提示安装工具链 ,各式如下,XXX填入提示的工具包
sudo apt-get install XXX
5、调用包进行编译
根据inst_rom.S 得到 inst_rom.o
mips-linux-gnu-as -mips32 inst_rom.S -o inst_rom.o
在opt文件夹中发现多了一个inst_rom.o文件。
6、调用包进行链接
在此之前,先建立一个ram.ld 文件
touch ram.ld
在ram.ld写入,该代码来自《自己动手写CPU》,如果文件只读,参见第3步的两种方法。
MEMORY
{
ram(RW) : ORIGIN = 0x00000000, LENGTH = 0x00001000
}
SECTIONS
{
/*
For some reason the linker script can't see the _reset_vector symbol
(even if we declare it global), so we explicitly set it. */
.text :
{
*(.text)
} > ram
.data :
{
*(.data)
} > ram
.bss :
{
*(.bss)
} > ram
.stack ALIGN(0x10) (NOLOAD):
{
*(.stack)
_ram_end = .;
} > ram
}
ENTRY (_start)
,保存ram.ld,然后在终端执行下列代码,对inst_rom.o文件进行链接:
mips-linux-gnu-ld -T ram.ld inst_rom.o -o inst_rom.om
7、格式文件转换
在终端输入
mips-linux-gnu-objcopy -O binary inst_rom.om inst_rom.bin
,得到inst_rom.bin文件,此时里面的就是机器码的二进制形式,为了得到rom初始化文件.data,再进行最后一步转换。
8、bin转换成data
在终端输入下列代码,建立一个perl文件
touch Bin2Mem.pl
在Bin2Mem.pl里面输入下列代码,然后保存,文件只读详见第3步。 代码改写自gcvideo/bin2mem.pl at main · ikorb/gcvideo · GitHub
#!/usr/bin/env perl
use warnings;
use strict;
use feature ':5.10';
if (scalar(@ARGV) != 2) {
say "Usage: $0 in.bin out.data\n";
exit 1;
}
open IN,"<",$ARGV[0] or die "Can't open $ARGV[0]: $!";
open OUT,">",$ARGV[1] or die "Can't open $ARGV[1]: $!";
binmode IN;
binmode OUT;
my $buffer;
read(IN,$buffer,(-s $ARGV[0])) or die "Can't read from input: $!";
# pad to word size
while ((length($buffer) % 4) != 0) {
$buffer .= chr(0);
}
# swap endianness of words
#$buffer = pack("N*", unpack("V*", $buffer));
# swap nibbles
#$buffer = pack("H*", unpack("h*", $buffer));
my $address = 0;
while (length($buffer) > 0) {
#printf OUT "@%08X", $address;
my $str = substr($buffer, 0, 4 );
for (my $i=0; $i<length($str); $i++) {
printf OUT "%02X", ord(substr($str, $i, 1));
}
print OUT "\n";
$buffer = substr($buffer, length($str));
#$address += 16;
}
close IN;
close OUT;
然后输入下列代码,进行格式转换,
./Bin2Mem.pl inst_rom.bin inst_rom.data
如果提示bash Bin2Mem.pl :权限不够,就在终端输入下列指令,没有就略过这一步:
chmod a+x ./Bin2Mem.pl
结果得到最后的inst_rom.data文件,此文件可以初始化rom。下图是结果inst_rom.data
这一个流程就完成任务了,之后修改inst_rom.S文件,再依次执行一下四条代码,inst_rom.data就是相应的目标文件了。
mips-linux-gnu-as -mips32 -EB inst_rom.S -o inst_rom.o
mips-linux-gnu-ld -T ram.ld inst_rom.o -o inst_rom.om
mips-linux-gnu-objcopy -O binary inst_rom.om inst_rom.bin
./Bin2Mem.pl inst_rom.bin inst_rom.data
,但是笔者嫌麻烦,根据《自己动手写CPU》,这里提供的代码,修改自书本提供的Makefile文件。
9、建立Makefile文件
终端输入
touch Makefile
建立Makefile文件,在里面写入,,,根据《自己动手写CPU》,这里提供的代码,修改自书本提供的Makefile文件。
ifndef CROSS_COMPILE
CROSS_COMPILE = mips-linux-gnu-
endif
CC = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
OBJECTS = inst_rom.o
export CROSS_COMPILE
all:inst_rom.data inst_rom.om inst_rom.o inst_rom.bin inst_rom.asm
%.o:%.S
$(CC) -mips32 -EB $< -o $@
inst_rom.om:ram.ld $(OBJECTS)
$(LD) -T ram.ld $(OBJECTS) -o $@
inst_rom.bin:inst_rom.om
$(OBJCOPY) -O binary $< $@
inst_rom.asm:inst_rom.om
$(OBJDUMP) -D $< >$@
inst_rom.data:inst_rom.bin
./Bin2Mem.pl $< $@
clean:
rm -f *.o *.om *.bin *.data
,保存,然后在终端输入
sudo apt install make
,就完成了,以后再修改inst_rom.S文件,只需在终端输入
make all
一次完成四条指令,得到修改后的inst_rom.data,如果没有修改,会提示 all 没有事情可做。
除此之外,Makefile中还添加了一部分代码,可以根据inst_rom.om文件反汇编产生相对于的汇编文件 inst_rom.asm。
10、写在最后
a,在操作的过程中,可能会面临权限不够的困境,则在执行该条代码之前执行 su ,然后输入密码获取root权限,或者是在执行代码的前插入 sudo ,比如 sudo make all
b,有时候会出现找不到文件,无法打开之类的问题,那就对相应的文件,执行
chmod 777 XXX
,XXX 改成相应的文件名及后缀,修改相应文件的权限,尤其是Bin2Mem.pl,ram.lm,Makefile ,inst_rom.S这些文件。
c,笔者本身是根据《自己动手写CPU》的书籍内容照葫芦画瓢来的,
下载了虚拟机VMware 17 Pro
安装 Ubuntu 22.04.1
等了老半天才完成注册账号,然后苦于安装vmware tools ,各种查找CSDN回答,各种参考,多次安装,才实现了共享文件夹,其中的困难重重,如果有缘我会更新我踩过的这些坑。
实现共享文件夹了之后,好不容易可以正式开始了,导入了《自己动手写CPU》提供的工具链文件后,照样子安装之后,发现工具包无法使用,仔细一查,有博主说工具包根据32位运行,但是我的电脑是64位,ubuntu也是,心态崩了,然后才从一篇知乎上找到另有其他gnu工具包(,知乎源回答Ubuntu中搭建MIPS编译环境 - 知乎 (zhihu.com)。)
照着来,发现到Bin2Mem.exe的时候又是出了问题,于是爬到网上,根据
risc-v MCU 的研究 - eddsos的日志 - EETOP 创芯网论坛 (原名:电子顶级开发网) -
的答主的说法,我找到了github(gcvideo/bin2mem.pl at main · ikorb/gcvideo · GitHub)的一段类似地perl代码,进行修改得到Bin2Mem.pl,使用方法有小小的改动。
然后再最后的整合,我又对《自己动手写CPU》提供的Makefile文件做出一些小改动,终于完成任务。
d,说说感受,本身答主没有接触过虚拟机,没有接触过linux,更没有了解linux的操作,各种东西都是一步步摸着石头过河完成的,不会perl、Makefile,对对着看修改参数,不懂linux操作,就网上搜着教程自己感悟,也是如此,我提供的思路和代码,或许在众多大佬面前是如此的幼稚,但是还请原谅,毕竟这修改自某个小白之手。
e,因为我写这篇文章,默认的读者是有阅读过《自己动手写CPU》的,所以很多步骤究竟是为什么我就不详细说明了,而且很多CSDN文章也有相似的内容。