自制cpu

本人是一位初中生,闲暇时写了一篇关于自制cpu的小论文,不喜勿喷,版权所有,复制需经作者(本人)同意关于自制cpu的小论文,图片未传,正稿请联系作者
一、制作原因
众所周知,中央处理器也即cpu是这个信息时代的中心,我想通过制作一个小型的cpu经行对其的探究
二、原理解析
Cpu分为单指令周期cpu和多指令周期cpu两种,而多指令周期的cpu多用流水线pipeline这一模式,单指令周期多用总线沟通各个构件,但相对而言单周期的cpu原理更为简单,更容易贯彻冯诺依曼结构的核心所以我决定制作单指令周期的cpu。单指令周期的概念就是在cpu中非并行指令,一个指令占用一个甚至多个时钟周期。
单指令周期与多指令周期对比
单指令周期 多指令周期
优点 由于总线的存在,单指令周期的cpu拓展性和兼容性更强 由于流水线pipeline的工作模式,多指令周期的 cpu效率更高
结构简单 可以制成结构更为复杂,集成性更高的cpu
缺点 效率相对略低(可以用更高的主频来弥补 扩展性差
对比来看,单指令周期cpu在这个模实验中更具有优势。
在cpu数据中,最重要的是数据的进制,数字电路中,0/1一个bool就是1位数据,
4位数据组成半字,8位组成字,即byte
接下来是对cpu的组成分析

  1. 时钟
    顾名思义,时钟是cpu中控制时间的构件。时钟是cpu内部的一个重要组成部分,时钟频率决定了cpu的主频。时钟的主要作用是产生方正波,其他部件会在电波上升沿进行操作。
    时钟的本质是一个输出方正波的震荡(脉冲)电路
    2.总线
    总线是cpu内部数据流通的重要媒介载体,它链接了各个部件,由总线控制器进行控制端到端的一对一通信。而总线的位数同时影响了cpu的单次通信效率。市面上多采用8位总线。
    3.寄存器
    寄存器是数据存储容器,是由D双稳态多谐振荡器D flip-flop构成,每个D双稳态多谐振荡器可存储一位的数据,而D双稳态多谐振荡器是在D锁存器D latch基础上多了两个与门和一个时钟信号。寄存器的读写速度特别快。
    4.Ram随机存储内存
    Ram分为两种,SRam和DRam,SRam是由逻辑电路构成,即两个反向非门。SRam则是由电容构成,所以在读取后要重新写入数据。
    Ram对比
    SRam DRam
    优点 速度快
    容量大
    不用重复写入 价格低廉,结构简单
    缺点 无 每次读取后需重新写入
    显然,近乎没有缺点的SRam更胜一筹,对于我们这样的小规模cpuDRam不太合适

5.Rom只读存储内存
Rom只读存储内存分为四类Rom、PRom、EPRom、EEPRom.
四种Rom
英文简写 Rom PRom EPRom EEPRom
中文名称 只读存储器 可擦只读存储器 电可擦只读存储器 电可擦可写只读存储器
由生产时注入数据,不可改写 可由特定频率紫外线擦 可由电擦除数据 可由电擦、写
对于我们的cpu来说,EEPERom无疑是最好的
6.计数器
计数器是程序运行时对时钟信号计数来确定当前所运行的指令的地址,同时冗余的计数器也可以进行时间记录
7.加法器
ALU是加法运算单元,由若干全加器组成,全加器又由两个半加器组成,而减法是由减数的补码即减数的反码加1加上被减数。
8.外部io
外部io是通过1/0进行对外并行或串行数据输出。常见的并行有LED数字灯管、LCD显示屏,串行有UART协议、VGA等.信息论的核心精神中在一个封闭的信息闭环是无意义的,只有对外有所输出才会产生信息熵.所以外部io是必不可少的
三、Cpu设计
1.时钟
时钟有两种设计,分别为电容-电阻脉冲电路结合ne555时基电路与晶振。经过实验,得出以下表格
Ne555 晶振
优点 速度可调节,通过对电阻-电容时钟电路经行频率调节 频率高
缺点 输出clk波形在高频情况下容易失真 频率不可调
在本次设计中,采用了ne555时基电路,在这个研究性cpu中不需要过高的时钟频率,且晶振产生的高频时钟信号容易使电路出现不可测问题
2.总线bus
总线是cpu内部数据流通的重要媒介载体,它链接了各个部件,由总线控制器进行控制端到端的一对一通信。而总线的位数同时影响了cpu的单次通信效率。
总线位数对比
4位 8位 16位
优点 内容简单 单次传输数据满足大部分构建输入输出位数 单次传输的数据多
缺点 效率低下、数据传输量小 对宽位数指令支持度不高 有大量的数据位冗余
综合表格与实际得出,8位的总线更为合适,而
且市面上的cpu多用8位线为与总线交互,模块均由74ls245总线三态门接入总线
3.ALU设计
运算单元由74ls283两个4位全加器和74ls283和两个74ls86或非门组成,两个或非门的B全部与低位的全加器进位引脚相接,以做加减法控制,当此线接通高电平时做减法操作,反之做加法操作。ALU的输出是由74ls245三态总线收发器进行向总线输出数据。74ls245是一个常用的8位总线通信芯片(右侧为电路)
在对ALU进行数据输入时,由于总线的特殊性,所以在一个时钟周期内不可能同时传输一个以上的数据,所以我们需要两个8位寄存器来进行数据的零时存储。寄存器我们分别用一个74ls245进行与总线通讯,和两个74ls173 4位寄存器。
4.寄存器集群
对于cpu中较多的临时数据存储,需要一个寄存器集群,将8组8位寄存器组合,每组寄存器使用两个74ls173来进行存储,并在读写操作时使用3-8译码器来经行控制。
5.cache
运行中的程序将存在cache中,由于cache与内存在本cpu上使用的是相同的芯片即74ls189同为SRam所以可以将一些底层逻辑程序放在cache中。Cache的位数大小是受
6.程序寄存器
为了更方便地解析当前所正在执行的机器码语句,所以程序寄存器起到一个隔离和缓冲的作用,同时程序寄存器的位数大小是受运行的指令架构所影响的
7.Ram数据存储器
在这个Cpu中含盖了Ram,这样才能正常运行cpu。为了更大的储存容量,在cpu中我制作了两个data-ram,每个使用两个74ls189 ram芯片和74ls04反相器以及一个74ls245总线三态门。因为74ls ram芯片的输出是反相的,所以才需要74ls04反相器将输出转换为原输入。
当然,对于data-ram,一个地址寄存器也是必不可少的,因为addr与ram的读写数据不能同时传输,所以使用一个74ls 4位寄存器芯片来零时存储地址。
8.外部io
在这个cpu中,外部io所使用的接口有两种:并行的图像io和UART串口io。图像使用4位数字七段共阴数码管、LED点整屏,UART串行则使用4个74hc 4位移位寄存器进行读取,由程序控制输出
9.计数器
Cpu采用4组计数器,每组由1个74ls161 4位计数器芯片和
74ls245 8位总线收发器构成,其中一个为主计数器,是受cpu主频时钟控制的,共有jump,clr,count三根控制线来进行控制
10.Rom
在cpu中共加入两组rom只读存储器,每组使用一个28C16 EEProm进行存储和一个74ls245 8位总线收发器与总线通讯。28C16 EERom容量为16k*8,共128kb,可以做cpu
的长期存储。
四、部件制作
1.时钟 2.ALU 3.寄存器组 4.Data-Ram

5.cache 6.计数器组

五、材料清单
电容 0.01uF 74LS138 3-8译码器
电容 0.1uF 74LS139 2-4译码器
电容 1u 74LS157 四个双端多路器
555定时器 直插NE555P 74LS161 二进制计数器
74LS00 与非门 74LS173 三态D触发器
74LS02 或非门 74LS189 64位RAM
74LS04 反相器 74LS245 三态收发器
74LS08 与门 74LS273 8路D触发器
74LS32 二输入或门 74LS283 4位加法器
74LS76 J-K触发器 EEPROM 28C16
74LS86 二输入异或门 74LS138 3-8译码器
74LS139 2-4译码器

六、指令集编写
指令集的种类很多,如x86、risc-V、amd等等。指令集分为复杂指令集和精简指令集两种,如x86指令架构是复杂指令集,risc-V是精简指令集。我在Mul指令集的基础上开发出了一套临时指令集:multp,意味:‘多路传输’
16位指令集multp
add Rs(3) Rt(3) Rs(3) None(3) 00000
addi Rs(3) Rt(3) Im(4) None(2) 00001
sub Rs(3) Rt(3) Rs(3) None(3) 00010
subi Rs(3) Rt(3) Im(4) None(2) 00011
mul Rs(3) Rt(3) Rs(3) None(3) 00100
muli Rs(3) Rt(3) Im(4) None(2) 00101
and Rs(3) Rt(3) Rs(3) 00110
not Rs(3) Rt(3) 00111
or Rs(3) Rt(3) Rs(3) 01000
xor Rs(3) Rt(3) Rs(3) 01001
div Rs(3) Rs(3) Rs(3) None(3) 01010
divi Rs(3) Rs(3) Im(4) None(2) 01011
sll Rs(3) Rt(3) None(3) None(3) 01100
srl Rs(3) Rt(3) None(3) None(3) 01101
out Ort(3) Rs(3) None(3) 01110
outi Ort(3) Im(4) None(3) 01111
jump Rs(3) None(3) 10000
jumpi Im(4) None(3) 10001
if Rs(3) Rt(3) Im(2) Addr(4) 10010
ifi Rs(3) Im(4) Im(2) Addr(4) 10011
in Ors(3) Rt(3) None(10) 10100
Ramin Addr(4) Addr(2) Rs(3) 10101
Ramini Addr(4) Addr(2) Im(8) 10110
Ramout Addr(4) Addr(2) Rs(3) 10111
Romin Addr(10) Addr(2) 11000
Romini Addr(10) Addr(2) 11001
Romout Addr(10) Addr(2) 11010
Countset Addr(2) Rs(3) 11011
Countseti Addr(2) Rs(3) 11100
Countclr Addr(2) 11101
jc 11110
None 11111
这款指令集逻辑简单,内容直接,但有很多缺陷,如指令与数据易混且不易编译等特点。
所以又进行了升级。Cpu指令架构的位宽会直接影响硬件,所以又对指令集的位宽进行了分析。经过实验,得出以下表格
Cpu指令集位宽分析
16位 32位
优点 存储、传输所要求的硬件少 内容可更丰富,兼容性、扩展性强
缺点 内容容易冲突 传输更加麻烦,存储更占空间
根据分析,32位的指令架构更加合适于这个cpu
于是我开发了multp32位复杂指令集:
multp 32位复杂指令架构
数据位 结束位 31 27 23 19 15 11 7 3
起始位 28 24 20 16 12 8 4 0
基础运算 add 0000 0000 Rs Rt Rs
addi 0000 0001 Rs Rt Im
sub 0000 0010 Rs Rt Rs
subi 0000 0011 Rs Rt Im
复杂运算 mul 0000 0100 Rs Rt Rs
muli 0000 0101 Rs Rt Im
div 0000 0110 Rs Rt Rs
divi 0000 0111 Rs Rt Im
字节运算 not 0000 1000 Rs Rt
and 0000 1001 Rs Rt Rs
or 0000 1010 Rs Rt Rs
xor 0000 1011 Rs Rt Rs
sll 0000 1100 Rs Rt
srl 0000 1101 Rs Rt
寄存器操作 regin 0000 1110 Rs Rs2
reginadi 0000 1111 Rs Im
regini 0001 0000 Im Rs2
reginisdi 0001 0001 Im Im
regout 0001 0010 Rt Rs2
regoutadi 0001 0011 Rt Im
Ram操作 ramin 0001 0100 Rs Rs2
raminadi 0001 0101 Rs Im
ramini 0001 0110 Im Rs2
raminiadi 0001 0111 Im Im
ramout 0001 1000 Rt Rs2
ramoutadi 0001 1001 Rt Im
Ram操作 romin 0001 1010 Rs Rs2
rominadi 0001 1011 Rs Im
romini 0001 1100 Im Rs2
rominiadi 0001 1101 Im Im
romout 0001 1110 Rt Rs2
romoutadi 0001 1111 Rt Im
计数器 Countset 0002 0000 Rs Rs2
Countsetadi 0002 0001 Rs Im
Countseti 0002 0010 Im Rs2
Countsetiadi 0002 0011 Im Im
Countclr 0002 0100 Rs2
Countclradi 0002 0101 Im
Countout 0002 0110 Rt Rs2
Countoutadi 0002 0111 Rt Im
外部io ioin 0002 1000 Rt Rs2
ioinadi 0002 1001 Rt Im
oiout 0002 1010 Rs Rs2
oioutadii 0002 1011 Rs Im
ioouti 0002 1100 Im Rs2
iooutiadi 0002 1101 Im Im
地址跳转 jump 0002 1110 Rs
jumpi 0002 1111 Im
if 0003 0000 Rs Im Rs2
ifi 0003 0001 Rs Im Im
jc 0003 0010 Im
以及risc-Z 32位精简指令集:
risc-Z 32位精简指令架构
数据位 结束位 31 27 23 19 15 11 7 3
起始位 28 24 20 16 12 8 4 0
基础运算 add 0000 0000 Rs Rt Rs
sub 0000 0001 Rs Rt Rs
字节运算 not 0000 0100 Rs Rt
and 0000 0101 Rs Rt Rs
or 0000 0110 Rs Rt Rs
寄存器操作 regin 0000 1010 Rs Rs2
regout 0000 1011 Rt Rs2
Ram操作 ramin 0000 1100 Rs Rs2
ramout 0000 1101 Rt Rs2
Ram操作 romin 0000 1110 Rs Rs2
romout 0000 1111 Rt Rs2
计数器 Countset 0001 0000 Rs Rs2
Countclr 0001 0001 Rs2
Countout 0001 0010 Rt Rs2
外部io ioin 0001 0011 Rt Rs2
ioout 0001 0100 Rs Rs2
地址跳转 jump 0001 0101 Rs
if 0001 0110 Rs Im Rs2
jc 0001 0111 Im

指令架构分析
精简指令集risc-z 复杂指令集multp
优点 内容不重复,占用空间小 指令更细致,利于开发者理解和编写,避免重复造轮子
缺点 编码时略有反复性编码 指令集内容有小部分重复,同时占用存储空间
对比来看,精简指令集risc-z更加适合这个小规模,低存储的cpu,但是在实际指令集写入中与cpu无影响,因为指令集背后的微指令实际都是这个cpu上的各个控制引脚

3.微指令设计
每个指令中都由若干给微指令构成
Cpu控制引脚
ALU Comp
ALUin0 ALUin1 ALUfunct ALUout Compin0
Comp ByteALU
Compin1 Compfunct Compout0 Compout1 ByteALUin0
ByteALU Reg
ByteALUin1 ByteALUfunct0 ByteALUfunct1 ByteALUout RegAdin
Reg Ram
Regin Regout RamAdin0 Ramin Ramout
Rom Count
Romadin0 Romout Countadin Jump Countstop
io RAM Rom
ioadin ioread Ioput Ramadin1 Romadin1

五、软件开发
为了使用指令集进行开发,还需要配套的翻译程序,来进行将开发者所编写的汇编指令转换为机器码即0/1来写入cpu的ram存储器。
以下程序为python代码
1.Xl2set.py可以将excel文件转换为编译器所使用的set文件,这样可以简化开发流程,只需要对excel进行操作就可以完成指令集的开发,大大缩短了开发周期同时降低了开发难度,利于编译器的生态
Xl2set.py

import openpyxl,csv

print('source file name为空时使用系统默认指令集')
source=input('source file name')
Target=input('Target instruction set name')
if source=='':
    source='~risc-Z.xlsx'

data=[]

wb = openpyxl.load_workbook(source)
sheet = wb.worksheets[0]
for row in sheet.iter_rows():
    row_data=[]
    for cell in row:
        print(cell.coordinate, cell.value)
        row_data.append(str(cell.value))
    row_data[1]=row_data[1]+row_data[2]
    del row_data[2]
    data.append(row_data)
print(data)

filename = 'set^risc-Z.set'

csvFile = open(filename,'w',newline='\n')

writer = csv.writer(csvFile)

for row in data:
      print(row)
      writer.writerow(row)
csvFile.close()

2.compile.py编译库文件
我自行写了一个简单的库,封装了compile函数,对汇编经行编译。同时这个库支持导入其他自行开发的指令集,可以做到做大的兼容性和可扩展性。
compile.py

def compile(data,set):
    set_dict=[]
    set_table={}
    for row in set:
        row_set={}
        row_set['name']=row[0]
        row_set['byte'] = row[1]
        set_table[row_set['name']]=row_set['byte']
        row_set['data']=[]
        count=0
        for i in row:
            if count>1:
                row_set['data'].append(i)
            count+=1
        set_dict.append(row_set)
    command=[]
    for row in data:
        command.append(row.split())
    res=[]
    for i in range(0,len(command)):
        #try:
        row=set_table[command[i][0]]
        for item in set_dict:

            if item['name']==command[i][0]:
                count=1
                print(command)
                for it in item['data']:
                    if it == 'None':
                        row+='0000'
                    else:
                        print(it)
                        zero={1:'000',2:'00',3:'0',4:''}
                        row+=zero[len(command[i][count])]
                        row+=command[i][count]
                        count+=1
        res.append(row)
        #except:
        #    print('error')
        #若想关闭报错内容,请解开注释
    return res

3.Main.py核心程序
运行即可进行对输入文件的编译
main.py


from compile import *
import csv

set_list=[]
code_list=[]
if __name__=='__main__':
    print('set name为空时使用系统默认指令集')
    set=input('set name')
project=input('project name')
code=input(‘code type’)
    project='pro.test'
	if code==’’:
		code=’GBK’
    if set == '':
        set = 'set^risc-Z.set'
    set_file = open(set, mode='r', encoding =code)
    reader = csv.reader(set_file)
    for item in reader:
        set_list.append(item)
    set_file.close()
    project_file = open(project, "r")
    for line in project_file:
        code_list.append(line)
    project_file.close()
print(compile(code_list,set_list))

4.指令集文件
set^risc-Z.set,risc-Z处理后的set文件,code type为utf-8


add,00000000,Rs,Rt,Rs,None,None,None
sub,00000001,Rs,Rt,Rs,None,None,None
mul,00000010,Rs,Rt,Rs,None,None,None
div,00000011,Rs,Rt,Rs,None,None,None
not,00000100,Rs,Rt,None,None,None,None
and,00000101,Rs,Rt,Rs,None,None,None
or,00000110,Rs,Rt,Rs,None,None,None
xor,00000111,Rs,Rt,Rs,None,None,None
sll,00001000,Rs,Rt,None,None,None,None
srl,00001001,Rs,Rt,None,None,None,None
regin,00001010,Rs,None,None,Rs2,None,None
regout,00001011,None,Rt,None,Rs2,None,None
ramin,00001100,Rs,None,None,Rs2,None,None
ramout,00001101,None,Rt,None,Rs2,None,None
romin,00001110,Rs,None,None,Rs2,None,None
romout,00001111,None,Rt,None,Rs2,None,None
Countset,00010000,Rs,None,None,Rs2,None,None
Countclr,00010001,None,None,None,Rs2,None,None
Countout,00010010,None,Rt,None,Rs2,None,None
ioin,00010011,None,Rt,None,Rs2,None,None
oiout,00010100,Rs,None,None,Rs2,None,None
jump,00010101,Rs,None,None,None,None,None
if,00010110,Rs,None,Im,Rs2,None,None
jc,00010111,None,None,Im,None,None,None

set^multp.setmultp编译后的set文件,code type为utf-8

add,00000000,Rs,Rt,Rs,None,None,None
addi,00000001,Rs,Rt,Im,None,None,None
sub,00000010,Rs,Rt,Rs,None,None,None
subi,00000011,Rs,Rt,Im,None,None,None
mul,00000100,Rs,Rt,Rs,None,None,None
muli,00000101,Rs,Rt,Im,None,None,None
div,00000110,Rs,Rt,Rs,None,None,None
divi,00000111,Rs,Rt,Im,None,None,None
not,00001000,Rs,Rt,None,None,None,None
and,00001001,Rs,Rt,Rs,None,None,None
or,00001010,Rs,Rt,Rs,None,None,None
xor,00001011,Rs,Rt,Rs,None,None,None
sll,00001100,Rs,Rt,None,None,None,None
srl,00001101,Rs,Rt,None,None,None,None
regin,00001110,Rs,None,None,Rs2,None,None
reginadi,00001111,Rs,None,None,Im,None,None
regini,00010000,None,None,Im,Rs2,None,None
reginisdi,00010001,None,None,Im,Im,None,None
regout,00010010,None,Rt,None,Rs2,None,None
regoutadi,00010011,None,Rt,None,Im,None,None
ramin,00010100,Rs,None,None,Rs2,None,None
raminadi,00010101,Rs,None,None,Im,None,None
ramini,00010110,None,None,Im,Rs2,None,None
raminiadi,00010111,None,None,Im,Im,None,None
ramout,00011000,None,Rt,None,Rs2,None,None
ramoutadi,00011001,None,Rt,None,Im,None,None
romin,00011010,Rs,None,None,Rs2,None,None
rominadi,00011011,Rs,None,None,Im,None,None
romini,00011100,None,None,Im,Rs2,None,None
rominiadi,00011101,None,None,Im,Im,None,None
romout,00011110,None,Rt,None,Rs2,None,None
romoutadi,00011111,None,Rt,None,Im,None,None
Countset,00020000,Rs,None,None,Rs2,None,None
Countsetadi,00020001,Rs,None,None,Im,None,None
Countseti,00020010,None,None,Im,Rs2,None,None
Countsetiadi,00020011,None,None,Im,Im,None,None
Countclr,00020100,None,None,None,Rs2,None,None
Countclradi,00020101,None,None,None,Im,None,None
Countout,00020110,None,Rt,None,Rs2,None,None
Countoutadi,00020111,None,Rt,None,Im,None,None
ioin,00021000,None,Rt,None,Rs2,None,None
ioinadi,00021001,None,Rt,None,Im,None,None
oiout,00021010,Rs,None,None,Rs2,None,None
oioutadii,00021011,Rs,None,None,Im,None,None
ioouti,00021100,None,None,Im,Rs2,None,None
iooutiadi,00021101,None,None,Im,Im,None,None
jump,00021110,Rs,None,None,None,None,None
jumpi,00021111,None,None,Im,None,None,None
if,00030000,Rs,None,Im,Rs2,None,None
ifi,00030001,Rs,None,Im,Im,None,None
jc,00030010,None,None,Im,None,None,None
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值