c++编写简易mips编译器

原创 2016年05月30日 22:23:18

由于在写计组实验时,需要首先将mips语句转换为二进制机器码,在没有编译器的辅助之下,只能一句一句对着码表,手动编译二进制机器码。一个不小心就会出错,出错了还很难找出错误的地方,有时还需要重新编译一遍。

因此,决定用c++实现一个简易的mips编译器,能编译基本的需要的mips语句为32位字长的二进制机器码。


首先,我们需要将mips指令编写在文本文件txt里面,如下图,采用的是我的另一篇博客(多周期cpu设计与实现)里的mips指令。


之后我们要将mips指令读入到c++文件中,并进行字符串的解析,从而进行译码。

int main() {
	int binary[32][32];
	ifstream fin;
	fin.open("mips.txt", ios_base::in);
	if(!fin) {
		cerr << "Open Error!" << endl;
		exit(1);
	}
	int i, j;
	char buffer[256];
	char* q = NULL;
	char* op;
	string oop;
	for(i = 0;i < 32;i++) {
		for(j = 0; j < 32; j++) {
			binary[i][j] = 0;
		}
	}
	j = 0;
	while(!fin.eof()) {
		fin.getline(buffer, 100);
		if(buffer[0] != 0) {
			q = NULL;
			op = strtok(buffer, ",$(),() ");
			oop = op;
		    int* newline = fromooptobinary(oop);
		    for(i = 0; i < 32; i++) {
		    	binary[j][i] = newline[i];
			}
		}
		j++;
	}
	int count = j;

在这里运用的是getline的方法将一行的mips指令以字符串的形式读入到buffer中。
接着利用strtok方法解析字符串,这里所运用的strtok方法安全性不高,网上资料建议是使用strtok_r,区别不大,读者可以搜索一下两个函数的具体用法。
利用strtok得到的应该是mips指令的第一个值,那么它应该是一个指令名称,例如“add”,“sub”, “jal”等等。
在这里我自定义一个函数int*  fromooptobinary(string oop),它能根据不同的指令名称做相应的译码,返回值是一个整形数组,利用二维整形数组binary保存译码的结果也就是机器码。
这里的译码全部参考我的另一个博客(多周期cpu设计与实现):http://blog.csdn.net/zhongzi_l/article/details/51485113

int*   fromooptobinary(string  oop)的实现如下图:


由于oop指令名称有可能存在大小写混合的情况,因此使用string  tolower(string oop)的自定义方法将大写字母转为小写字母
在这里网上资料推荐是使用stl的方法transition函数来转换大小写,但我感觉那个也挺麻烦的,而且只是将大写转为小写也挺容易实现:

string tolower(string s) {
	int len = s.size();
    for (int i=0; i<len; i++) {
        if ( s[i] >= 'A' && s[i] <= 'Z' ) {
            s[i] += ('a' - 'A' ) ;
        }
    }
    return s;
}

接下来,由于有的指令例如“j  0x00000010”跳转指令,对于后面00000010十六进制地址需要转换为32位长度的二进制机器码,由此自定义了函数:

int* chartobinary(char *p) {
	int i = 0;
	int j = -1;
	int k = 0;
	int *q = new int[32];
	for (i = 3; i < 10; i++) {
		int a = p[i] - '0';
		j += 4;
		for(k = 0; k < 4; k++) {
			q[j] = a%2;
			a = a/2;
			j--;
		}
		j += 4;
	}
	return q;
}

用到这个函数的地方在int*   fromooptobinary(string  oop)函数中:

if(oop == "j" || oop == "jal") {
		binary[0] = binary[1] = binary[2] = 1;
		if(oop == "jal") binary[4] = 1;
		p = strtok(NULL, ",$(),() ");
		int *k = chartobinary(p);
		for(i = 6; i < 32; i++) {
			binary[i] = k[i-6];
		}
	}


接下来还有一个译码需要将寄存器号转换为五位的二进制机器码,或者也有的是十六位的二进制机器码,自定义函数:

int* inttobinary(int t, bool choose) {
	int i = 0;
	if(choose) {
		int* q = new int[5];
		for(i = 4; i >= 0; i--) {
			q[i] = t%2;
			t=t/2;
		}
		return q;
	} else {
		bool check = false;
		if(t<0) {
			check = true;
			t = -t;
		}
		int* p = new int[16];
		for(i = 15; i >= 0; i--) {
			p[i] = t%2;
			t=t/2;
		}
		if(check) {
			for(i = 15; i >= 0; i--) {
				if(p[i] == 0) p[i] = 1;
				else p[i] = 0;
			}
			int j = 15;
			while(p[j] != 0) {
				p[j] = 0;
				j--;
			}
			if(j>=0&&p[j]==0) {
				p[j] = 1;
			}
		}
		return p;
	}
}


用到这个函数的地方同样在int*   fromooptobinary(string  oop)函数中,例如:

else if(oop == "move") {
		binary[0] = 1;
		p = strtok(NULL, ",$(),() ");
		int k = atoi(p);
		int* newline = inttobinary(k, true);
		p = strtok(NULL, ",$(),() ");
		k = atoi(p);
		int* newline2 = inttobinary(k, true);
		for(i = 6; i < 11; i++) {
			binary[i] = newline2[i-6];
			binary[i+10] = newline[i-6];
		}
	}


到这里译码基本完成,接下来只需要将binary数组写到另外一个文本文件中即可:

/*write to txt*/
	ofstream out;
	out.open("data.txt", ios::out|ios::trunc);
	if(out.is_open()) {
		for(i = 0; i < count; i++) {
			for(j = 0; j < 32; j++) {
				out << binary[i][j];
				if((j+1)%8 == 0 && j!=31) {
					out << " ";
				}
			}
			if(i != count - 1) {
				out << "\n";
			}
		}
		cout << "compile success!" <<endl;
		out.close();
	}


其中ios::trunc意思是打开文件时首先将文件内容清空。

具体的c++文件读写可以参考http://blog.csdn.net/zhongzi_l/article/details/51541351


那么简易的mips编译器就这么愉快的完成了,当然其中也有很多不完善的地方,比如如果输入不是按照基本的输入格式,那么译码可能会出现不可预知的错误。

下面来看一下编译的结果:


结果与多周期cpu设计与实现中的值是一致的。编译成功。

接下来,我也利用这个自制简易mips编译器编译了一下我另外一个博客(单周期cpu设计和实现)里的mips指令,当然也做了一点修改,结果也是正确的。


本次做简易的mips编译器,过程中遇到不少的困难,但总体来说比较令我满意,之后希望能做更厉害的编译器。





【Linux】Linux下搭建MIPS交叉编译环境

Ubuntu下搭建MIPS交叉编译环境 费了九牛二虎之力,终于把MIPS交叉编译环境搭建好了。接下来跟大家分享一下这篇文章,里面的方法是我亲自试过的,绝对好用。谢谢写这篇文章的博主。 ...
  • xiaoguaihai
  • xiaoguaihai
  • 2013年04月07日 10:23
  • 10565

自己动手写CPU之第四阶段(3)——MIPS编译环境的建立

OpenMIPS处理器在设计的时候就计划与MIPS32指令集架构兼容,所以可以使用MIPS32架构下已有的GNU开发工具链。本节将说明如何安装使用GNU开发工具链以及如何制作Makefile文件,从而...
  • leishangwen
  • leishangwen
  • 2014年07月28日 13:32
  • 5354

MIPS编译器

  • 2014年06月21日 23:58
  • 46.59MB
  • 下载

ubuntu14.04系统下mips交叉编译环境搭建

1.安装必要软件 2.下载解压buildroot 3.配置编译 4.设置环境变量 1.安装必要软件    sudo apt-get install build-essential b...
  • u012746763
  • u012746763
  • 2016年07月26日 09:12
  • 3233

MIPS在X86上的模拟器--Spim编译器

最近一年都在学习研究MIPS架构的东西,现在也在做Cavium的案子,所以把一些MIPS相关的东西整理一下。 在学习MIPS架构的时候,肯定要涉及到相关的指令集,在x86上BIOS都需要熟练掌握汇编...
  • pankul
  • pankul
  • 2013年03月15日 13:50
  • 4441

mips-4.3-81-mips-sde-elf-i686-pc-linux-gnu MIPS交叉编译工具

  • 2012年01月15日 19:38
  • 46.59MB
  • 下载

Ubuntu下安装MIPS交叉编译器 mips-linux-gcc

1.添加源 以root权限添加下面两行内容到 /etc/apt/sources.list 文件deb http://ftp.de.debian.org/debian squeeze main d...
  • xingjiarong
  • xingjiarong
  • 2015年11月16日 10:14
  • 8057

一步一步搭建mips-linux-gcc-4.4.0交叉编译工具

http://blog.sina.com.cn/circlewood2010 一步一步搭建mips-linux-gcc-4.4.0交叉编译工具   一、准备工作:  工作环境:宿主机:ub...
  • leolinux
  • leolinux
  • 2011年10月03日 15:29
  • 9071

android support c++11

http://www.drdobbs.com/cpp/accessing-c11-features-of-the-android-nd/240168385 Accessing C...
  • faral
  • faral
  • 2015年07月15日 16:54
  • 1160

c++编写简易mips编译器

由于在写计组实验时,需要首先将mips语句转换为二进制机器码,在没有编译器的辅助之下,只能一句一句对着码表,手动编译二进制机器码。一个不小心就会出错,出错了还很难找出错误的地方,有时还需要重新编译一遍...
  • Zhongzi_L
  • Zhongzi_L
  • 2016年05月30日 22:23
  • 1786
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:c++编写简易mips编译器
举报原因:
原因补充:

(最多只允许输入30个字)