最近打算参加一个CPU设计竞赛,遂开始从头开始看一本叫做《自己动手写CPU》的书,因为年头比较古老了,其中的干货还很有价值,但是涉及诸如仿真、Mips环境搭建等事宜,再以书中内容做参考就不太适宜了。

书中给出的Mips编译器还是2013年的呢,这篇文章我将记述如何一边google一边寻找最新版的编译器来完成同样的事情。

当然了,不使用最新版的同样也可以完成,而且直接按书上来的就是了,但是我总是喜欢用最新版的软件,所以这就是这篇文章的目的:如何使用最新版的工具链来编译MIPS32程序。

背景

关于实现这个事情,我最早想到的是直接去WSL里面安装MIPS的交叉编译链就是了。我的WSL使用的是OpenSUSE,我在yast里面直接搜索mips,然后安装带有cross字样的那个包,就是GCC交叉编译MIPS的包。后来又仔细研究了一下,发现交叉编译有两种不同的工具链。一种是在yast里安装的这种,我总结出它的特征就是在编译完的产物中你用readelf -h去看编译产物,你会发现它的Flags里面多一个o32或者其他什么东西,而另一种工具链编译完你去看就只有mips32一个Flag。由于书上的目标是直接在Verilog写的CPU中运行程序,换句话说编译产物是直接作为二进制读入CPU,然后被执行的,这中间没有操作系统来做一些脏活累活,因此这就要求你要是用Bare Metal版本的工具链,也就是后一者编译出来Flags只有一个mips32的那个。虽然就后面那个演示程序来说二者编译结果都一样,但是在编译C语言或C++的时候,前者可能会直接调用一些一来操作系统的功能,而后者则不会,这样能够有效避免很多问题(它没有操作系统,而你用了依赖操作系统的指令,我觉得十有八九肯定会出毛病)。

MIPS交叉编译GNU工具链

一开始在谷歌上搜索,我找到这么一个网页,也是MIPS官方网站:「ELF (Bare Metal)」,可是问题是我怎么也下不来页面上的文件,总是跟我说服务器500错误。我一想这事情必然有蹊跷,遂在官网上搜索。一开始搜索Bare Metal,毕竟我要下载这个版本的工具链。结果没搜到什么有用的东西,又尝试搜索ToolChain,工具链嘛,总该有相关的了吧。找到了「Linux Toolchain」,结果上面的文件一点开就会主页了。这时候我觉得可能MIPS官方在演我,我不甘心。

最终我在主页顶端导航栏的Develop选项卡下面的Developer Tools里看到了端倪:Developer Tools,在这个页面的Compilers一节,内附一个链接,打开之后跳到标题为「MIPS Compilers」,这回终于是对了。开门见山,直接给出了Codespace上用于GNU编译器的MIPS工具。最终的下载下来Windows64位版本的Bare Metal工具链。

放在一个固定的文件夹里面,然后在WSL里面配置PATH环境变量。因为我这边用的是OpenSUSE,它不自动继承Windows系统的环境变量,因此需要单独设置,如果是Debian或其他发行版本,我记得他会自动继承Windows的Path设置。export PATH="/mnt/c/mips-mti-elf/2019.09-02/bin:$PATH"

重新进入后键入mips然后按TAB,如果能自动补全就说明成功了。不过这里不好的一点就在于每一个命令之后你需要追加.exe,但好处是可以在PowerShell中运行。如果追求与Linux完全兼容的话,可以考虑下载Linux版本的,然后直接放在WSL里面。我这边为了方便在PowerShell中调用,就暂时忍了那个.exe的小尾巴了。

测试编译链

源程序

文件名inst_rom.S.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

程序很简单,就是四个使用不同寄存器的逻辑与运算。最终这段程序应当转化为一个只包含这四条指令的二进制文件,然后再通过其他工具转换成Verilog内置函数$readmemh可以直接读入的文件。

编译

编译需要使用mips-mti-elf-as.exe:mips-mti-elf-as.exe -mips32 inst_rom.S -o inst_rom.o

这里inst_rom.S是上面的源文件,inst_rom.o是编译产物。

连接

连接需要使用mips-mti-elf-ld.exe及ram.ld文件。后者是描述编译产物的各个块是如何安排的(我也没学过编译原理,大概就是这个意思),内容如下:/* default.ld. Default linker script for Or1ksim test programs

Copyright (C) 1999-2006 OpenCores

Copyright (C) 2010 Embecosm Limited

Contributors various OpenCores participants

Contributor Jeremy Bennett

This file is part of OpenRISC 1000 Architectural Simulator.

This program is free software; you can redistribute it and/or modify it

under the terms of the GNU General Public License as published by the Free

Software Foundation; either version 3 of the License, or (at your option)

any later version.

This program is distributed in the hope that it will be useful, but WITHOUT

ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for

more details.

You should have received a copy of the GNU General Public License along

with this program. If not, see . */

/* ----------------------------------------------------------------------------

This code is commented throughout for use with Doxygen.

--------------------------------------------------------------------------*/

MEMORY

{

ram : 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)

保存后进行连接:mips-mti-elf-ld.exe -T ram.ld inst_rom.o -o inst_rom.om

这时候inst_rom.om就是最终的ELF文件了。这里不详细说明什么是ELF了,总是他是一个面向操作系统的可执行文件,如果使用readelf去看的话,你可以发现一些数据和书上列出来的有些差距。

首先是Start of section headers,我这边的值比书上列的大了200,而后面Number of section headers和Section header string table index分别比书上的多了2和4。我觉得相同的文件怎么编译也应该差不出这么多。但是我也没在意(因为确实是不懂),后来导出的时候发现四条指令竟然导出了10条指令的量,前四个是正常的指令,后面六个对照MIPS32的指令表,怎么看怎么不像正常的指令。

经过搜索om文件和导出的数据,配合readelf -S查看块的数据,发现编译产物中多了一个.MIPS.abiflags的块,需要在导出时排除掉。

复制出指令部分

这部分使用mips-mti-elf-objcopy.exe,需要排除上面说的那个不相关的块:mips-mti-elf-objcopy.exe -R .MIPS.abiflags -O binary inst

_rom.om inst_rom.bin

其中-R就是排除块,最终产物inst_rom.bin是二进制形式,可以使用hexdump查看其内容,与书上得到的结果一样。

转换为$readmemh可读格式

随书资料中附带了一个转换的工具,只可惜我这边提示此应用无法在你的电脑上运行,所以这里只好自己写一个了。本来想用Java的,但是考虑到要在Make里面调用,还是C++相对好点,代码如下:#include

#include

#include

using namespace std;

std::ifstream fin;

std::ofstream fout;

string source_file_name;

string target_file_name;

int main(int argc, char * argv[])

{

if(argc != 3){

cout << "Usage: bin2mem raw target" << endl;

return 0;

}

source_file_name = argv[1];

target_file_name = argv[2];

fin.open(source_file_name);

if(!fin)

{

cout << "failed to open source file " << source_file_name << endl;;

exit(-1);

}

fout.open(target_file_name);

if(!fout)

{

cout << "failed to create target file " << source_file_name << endl;

exit(-1);

}

fout << hex; // 十六进制形式输出

char ch;

int count = 0;

while(fin.get(ch))

{

count ++;

int value = static_cast(ch);

// cout << value << endl;

if(value < 0x10)

fout << '0';

fout << value;

if(count % 4 == 0) // 4个字节,32位,一条指令

fout << '\n';

}

fin.close();

fout.close();

return 0;

}

有一说一我的C++确实是不咋地,就这点东西连查带调试,其中有些还是复制粘贴来的代码,就整了半个多小时。之前用Java测试的时候5分钟就写完了。

使用g++编译成可执行文件:g++ -o bin2mem ./bin2mem.cpp

使用:./bin2mem inst_rom.bin inst_rom.data

最终输出的inst_rom.data就是$readmemh可以直接读取的格式了。这里针对的是MIPS32,如果是64位字长的话,需要按照实际指令的长度调整上面44行的数。

自动化

每次都来一套这些命令确实不太行,因此这里使用Makefile借助工具Make来做自动化编译。ifndef CROSS_COMPILE

CROSS_COMPILE = mips-mti-elf-

endif

CC = $(CROSS_COMPILE)as.exe

LD = $(CROSS_COMPILE)ld.exe

OBJCOPY = $(CROSS_COMPILE)objcopy.exe

OBJDUMP = $(CROSS_COMPILE)objdump.exe

OBJECTS = inst_rom.o

export CROSS_COMPILE

# ********************

# Rules of Compilation

# ********************

all: inst_rom.om inst_rom.bin inst_rom.asm inst_rom.data

%.o: %.S

$(CC) -mips32 $< -o $@

inst_rom.om: ram.ld $(OBJECTS)

$(LD) -T ram.ld $(OBJECTS) -o $@

inst_rom.bin: inst_rom.om

$(OBJCOPY) -R .MIPS.abiflags -O binary $< $@

inst_rom.asm: inst_rom.om

$(OBJDUMP) -D $< > $@

inst_rom.data: inst_rom.bin

./bin2mem $< $@

clean:

rm -f *.o *.om *.bin *.data *.mif *.asm

没啥好说的,根据书上代码修改的。关键就是告诉make要用到的工具都在哪里,怎么调用。

-全文完-

生活不易,一点广告

天空 Blond 采用 知识共享 署名 - 非商业性使用 - 相同方式共享 4.0 国际 许可协议进行许可。

本许可协议授权之外的使用权限可以从 https://www.skyblond.info/about.html 处获得。

mips-mti-gnu-linux,【歪门邪道】利用WSL搭建MIPS32构建环境相关推荐

  1. Linux上利用nginx搭建一个简单的rtmp视频流服务器(不涉及直播)

    文章目录 Linux上利用nginx搭建一个简单的rtmp视频流服务器(不涉及直播) 一.基础环境搭建 二.构建Nginx 下载nginx-rtmp-module 安装Nginx 编译nginx,代理 ...

  2. Linux mono环境,linux+mono+xsp+apache搭建asp.net环境

    linux+mono+xsp+apache搭建asp.net环境 发布时间:2020-10-09 18:20:35 来源:51CTO 阅读:3101 作者:huilinux 环境: 系统:centos ...

  3. Linux服务器利用Nginx搭建网站

    需要注意的事情: 已经申请了云服务器 已经注册域名,做了域名解析,本文的域名为 www.kdog.top 在本文中出现的域名均可替换为自己的域名 利用Nginx搭建网站(Ubuntu 20.04 LT ...

  4. 利用gulp搭建less编译环境

    什么是less? 一种 动态 样式 语言. LESS 将 CSS 赋予了动态语言的特性,如 变量, 继承, 运算, 函数. LESS 既可以在 客户端 上运行 (支持IE 6+, Webkit, Fi ...

  5. 利用Maven搭建Spring开发环境 【转】

    2019独角兽企业重金招聘Python工程师标准>>> 一.   概要说明 最近几天在测试Spring3.0的AOP功能,在测试功能之前,首先是要搭建出Spring3.0的开发功能. ...

  6. c++获取当前目录_如何在 Linux 下利用 Vim 搭建 C/C++ 开发环境?

    2020年了,不要再看网上那些老旧的文章还在教你使用手工生成 tags 的,请使用自动代码索引生成工具,比如 vim-gutentags,现在网上好像就没有一篇能正确讨论 Vim C/C++ 环境搭建 ...

  7. 苹果手机ios搭建服务器linux,iOS 利用CocoaHttpServer搭建手机本地服务器

    1.首先导入第三方 目录结构 屏幕快照 2017-07-25 下午1.39.53.png 然后导入你需要加载的html资源 17656F3B-8000-42A3-BA37-182924DAA1CF.p ...

  8. linux eclipse stm32,在ubuntu下利用eclipse搭建stm32开发环境和st-link调试

    一.下载eclipse: 我们选择的工具为Eclipse IDE for C/C++ Developers,官网下载地址在 https://www.eclipse.org/downloads/pack ...

  9. linux搭建rtmp服务器搭建,linux下利用Nginx搭建RTMP服务器

    RTMP 实时消息传递协议(RTMP)由Macromedia开发,作为为其Flash技术传输数据,音频和视频的方法.Macromedia随后被Adobe收购,因为该规范已部分发布,使第三方能够在Ado ...

最新文章

  1. easymailobjects php,用easymailobject组件处理exchange邮件源代码(6)_asp实例
  2. mysql本地可以访问 网络不能访问
  3. 全卷积神经网路【U-net项目实战】肺结节分割案例分析:DSB3Tutorial
  4. 使用KubeKey安装K8S集群
  5. jsp解决mysql乱码_解决mysql+jsp出现乱码的问题
  6. MySQL工作笔记-使用rand生成随机数及用随机数填充记录
  7. @echo off是什么意思_高街、BF、FOG、OS风。。。都是些什么鬼?
  8. Web之路笔记之三 - 使用Floating实现双栏样式
  9. redis基础_NOSQL介绍
  10. 二元函数求导公式_基本函数求导公式
  11. 计算机蓝屏代码0xc0000020,电脑运行程序时出现“损坏的映像错误0xc0000020”提示怎么办?...
  12. 制造业生产过程中多源异构数据处理方法综述
  13. C++ Const 初步总结(《C++程序设计语言》读后感)
  14. 关于 kubernetes网络(CNI规范)中Calico,NetworkPolicy(网络策略)方面的一些笔记
  15. CTF——MISC习题讲解(GKCTF 2021系列)
  16. 提炼函数(Extract Method)
  17. 12位符号数转归一化float的实现
  18. 以可信度加权的方式做决定
  19. 普通大学生自学 JAVA 怎样才能进BAT大厂?
  20. 安装 Motorola ADB Interface 驱动失败的解决办法

热门文章

  1. Maven Docker几个插件打包+推送到镜像仓库或者私服(Harbor)的方法
  2. APPLE G5 机箱改造“黑苹果”全攻略
  3. 解除百度网盘下载限速
  4. java版,实现人民币的大小写转换
  5. “2018 Unreal Open Day 虚幻引擎技术开放日”活动开启预售
  6. 自己撸一个Wordcount
  7. 从红海里面寻找蓝海,看一个人的思维模式
  8. 随笔 | 写作的意义
  9. perl代码实现DNA翻译蛋白序列
  10. 几个cad二次开发的网站