jjzjj

32位MIPS单周期CPU设计

adriaW 2023-10-11 原文

参考实验书目:《数字设计和计算机体系结构》机械工业出版社,7章

实验平台:vivado

语言:system verilog

一、实验信息

     略...咱的专业课实验报告

二、实验内容

(一)设计原理及实验方案

总体设计思路:

将微体系结构分为两个部分:数据路径和控制。数据路径对数据字进行操作。控制单元从数据路径接收当前指令,并控制数据路径如何执行指令。前者包含存储器,寄存器,ALU和复用器等结构,本次实验设计32位的处理器,因此应采用32位数据路径。后者根据指令需求产生各种使能信号来控制寄存器写,存储器写,复用器数据选择等功能。

设计+实验流程:

1.基础部分(只涉及到教材所提及的指令)

  • 确定MIPS处理器的状态元件,再基于当前状态在状态元件之间增加组合逻辑计算新的状态。在本次实验中,共涉及到4个状态元件:                                                                                 
  • 1)程序计数器:输入计算的新的PC,输出为当前PC,每个PC指向对应的指令。           
  • 2)寄存器文件:以instr的rs,rt字段(如果有的话)为地址,读数据;写入数据。               
  • 3)指令存储器:输入PC取指令instr。                                                                                 
  • 4)数据存储器:以ALU的计算结果为地值取数据或者存数据,lw或者sw,取数据会加载到寄存器,存数据时数据来源于rt字段从寄存器中读取的数据。
  • 处理器的动作取决于取出的具体指令。
  • 从具体指令出发,构造数据路径连接,逐步引入电路元件,当遇到需要共用数据通路时(如寄存器写入时数据来源,ALU计算时的srcB来源等),增加复用器和选择信号。
  • 完成一条指令的数据通路后,逐步泛化,在已完成的数据通路上增加连接,引入复用器和其他元件,完成其他指令的数据路径扩展,当lw,sw,R类型,beq,addi,j指令的数据通路都完成后,所有数据路径板块设计完毕。
  • 接着整理电路中引入的使能信号(包括寄存器文件,数据存储器的写信号,各个复用器的选择信号,ALU模块执行运算的选择信号),开始完善控制板块。
  • 因为指令的不同导致处理器的动作不同,故指令为控制单元的输入信号。本实验中指令的高6位Opcode以及低6位Funct决定指令的功能类型,因此决定各信号的值。在控制单元的设计中,将其分为主译码器和ALU译码器,Opcode作为主译码器的输入信号,计算大部分控制信号,如memtoreg, memwrite, branch, alusrc, regdst, regwrite, jump等,同时产生一个信号aluop(位数取决于指令数,在基础部分时该信号为2位,扩展andi,ori,bne指令后,该信号扩展成3位),该信号与Funct信号一起输入ALU译码器,决定alucontrol的值,控制alu模块的运算类型。
  • 根据以上分析做出主译码器和ALU译码器的真值表。

主译码器真值表:

ALU译码器真值表:

  • 结合上述流程中做出的最终原理图和完成的两个译码器的真值表,编写system verilog代码,并加入仿真测试文件testbench.sv以及指令文件memfile.txt做仿真测试,观察仿真结果。

基础部分处理器原理图:

2.扩展部分(增加andi,ori,bne指令)

  • 在基础部分设计的的CPU基础上,从指令出发,根据增加的指令,扩展数据通路,增加需要的元件和信号。
  • 扩展指令功能分析:bne: 条件跳转指令,与beq跳转条件相反,若指令instr的rs字段在寄存器中读取的数据和rt字段读取的数据不相等(Zero为两信号是否相等的标志,zero==1表示读取数据相等,0表示不等),则PC’=(PC)+4+(4*符号扩展后的立即数(即偏移量)。andi:将rs字段对应数据与经过零扩展的立即数做逻辑与运算,得到的值储存到rt指向的寄存器里。ori(或运算),xori(异或运算)的功能类似。
  • 扩展指令的具体实现:
    1. bne部分,考虑增加一个复用器,复用器选择信号zeroselect,当zeroselect值为1时选择输入zero,表示prcsrc=branch&zero,进行beq条件判断;当zeroselect值为0时,选择输入(~zero),表示prcsrc=branch&~zero,进行bne条件判断。zero值为1表示指令取出的两个数据值相等,zero值为0则表示不相等。
    2. andi部分,需要增加一个复用器,复用器选择信号immselect来选择signimm或者zeroimm,值为1表示选择符号扩展立即数进入接下来alusrc的选择,值为0表示选择零扩展立即数进入接下来alusrc的选择。考虑到此复用器关系到进入ALU运算的srcB的来源(rt字段取数or符号扩展立即数or零扩展立即数),所以alusrc==1(选择立即数作为srcb)的指令,需要明确给出immselect的值,如lw,sw,addi等,immselect=1;而andi,ori指令对应的immselect==0。
    3. ori部分,因为已经在扩展andi指令时完成了数据路径的扩展,所以只需在addi的基础上,将对应真值表中aluop定为100,使srca和srcb在ALU模块里的运算变成按位或。
  • 整理新增控制信号,扩展主译码器和ALU译码器真值表。因为扩展指令后需要的aluop数超过4(加,减,与,或,R类),所以aluop变量更改为三位向量。扩展后的两真值表如下图所示。

主译码器真值表:

指令

opcode

regwrite

regdst

alusrc

branch

memwrite

memtoreg

aluop

jump

zeroselect

immselect

R类型

000000

1

1

0

0

0

0

010

0

x

x

lw

100011

1

0

1

0

0

1

000

0

x

1

sw

101011

0

x

1

0

1

x

000

0

x

1

beq

00100

0

x

0

1

0

x

001

0

1

x

addi

001000

1

0

1

0

0

0

000

0

x

1

j

000010

0

x

x

x

0

x

xxx

1

x

x

bne

000101

0

x

0

1

0

x

001

0

0

X

andi

001100

1

0

1

0

0

0

011

0

x

0

ori

001101

1

0

1

0

0

0

100

0

x

0

 

ALU译码器真值表:

aluop

funct

alucontrol

000

X

010(加)

001

X

110(减)

010

100000

010(加)

010

100010

110(减)

010

100100

000(与)

010

100101

001(或)

010

101010

111(小于置位)

011

x

000(与)

100

x

001(或)

  • 根据扩展后的原理图和真值表,修改system Verilog代码,指令文件等,重新进行仿真测试,观察仿真结果。

        扩展指令后的原理图:

     3.增加I/O接口准备上板部分

         将dmem扩展成DataMemoryDecoder,该模块包括数据存储器(dmem)、I/O接口,7段数码管三个子模块,其原理图如下。

    • 从主译码器中output出的Write值与数据地址的第八位共同决定目前的writedata写入数据存储器还是I/O接口部分,当Write值为1时,若addr[7]==1,则pWrite=1;若addr[7]==0,则WE=1,可以将writedata存入数据存储器。因为七段数码管需要显示十六进制数,每组数码管的显示值由四位二进制数决定,实验开发板上开关为16位,决定输入的两个两位十六进制数,另外增加一个12位的变量led,决定加法运算得出的结果——一个三位十六进制,数码管上等号的实现不需要动态变化,直接在代码中为数码管赋相应值即可。因为要将开关输入的两个十六进制数相加并且输出结果到七段数码管的操作,所以增加将mips处理后output的writedata写入I/O接口的路径。当pWrite==1时,若addr[3:2]为01,则将经过alu加法计算得到的writedata值写入I/O中的led变量,根据led的真值(三组0/1串)给对应的数码管赋值。
    • 数据地址的第八位addr[7]映射到I/O接口的pRead端口,表示当addr[7]==1时,如下图所示,根据具体内存位置00,10,11,来决定pReadData的内容是状态端口(Switchcheck和ledcheck,是否准备好输入数据和输出数据)或者Switch端口低位值或者Switch端口高位值,数据读入到pReadData后,经addr[7]作为使能信号的复用器传输到mips处理器的readdata处,然后进行lw操作存值到寄存器,进行条件判断或者加法运算。
    • 此外,I/O接口部分有从top文件映射过来的Switch,ButtonL(决定status[0]的值,led输出是否已准备就绪),ButtonR(决定status[1]的值,switch值读入是否已准备就绪),reset(ButtonC,清零信号)。
    • I/O接口部分的led端口值为用拼接符赋值的32位变量,从高位到低位每四位一组,决定一组数码管的显示值。该端口映射到7段数码管的digit端口。
    • 7段数码管的分时显示:用时钟分频得到的三位向量和case语句选择0~7编号的各个数码管和该数码管显示的十六进制数,因为遍历8个数码管的周期很小,所以在人眼看来是同时显示了各个数码管的值,即显示出两个两位十六进制数相加得到一个三位十六进制数的结果的等式
    • 更改top文件端口和调用模块(将对dmem 的调用改为对DatamemoryDecoder的调 用),  加入引脚约束文件,将指令文件加入design source和simulation source,前者用于生成bitstream文件上板验证,后者用于vivado内的仿真。
    • 对于仿真文件,首先logic定义top文件中的端口值,然后实例化top文件,然后对top文件中input端口对应的变量做初始化(initial)。时钟设置为100MHZ。做清零操作并输出:ButtonC先设置为1,一段时间后设置为0,ButtonL设置为1一段时间后又设置为0。输入Switch的值4’h1234。将输入输出状态调整为准备就绪:ButtonL和ButtonR的值赋为1。仿真文件写好后,进行仿真操作,调整并观察波形,查看AN,和A2G的值是否与预期相符合。
    • 上板验证时,将生成的bit文件下载到实验开发板上,按顺序进行清零,输入数据,读入数据,输出数据操作。更改输入的数据多次验证,可得到不同的2位十六进制数相加的等式和正确结果。

(二)实验结果及分析

  1. 关键代码分析

(1)在基础verilog代码上根据需要扩展代码而发生改动的局部代码。

1)maindec

因为增加了zeroselect,immselect以及aluop从2位扩展成3位,controls更改位12位向量。根据真值表在case语句中,增加了bne,andi,ori对应的controls值,同时对其他指令的controls值做了修改。

2)aludec

因为aluop的变为3位,所以aludec的case语句中各条件值也做了变化,新增011和100令alucontrol赋值为与运算、或运算的信号值。

3)增加零扩展模块

令扩展时,高位直接补零,将16位立即数扩展称32位,用于andi和ori运算。

4)datapath中增加选择扩展后进入alu运算的立即数类型的复用器。

immselect选择immsrc,immsrc参与srcb的选择。

5)controller中增加选择beq或者bne的zerosrc的语句。

在controller中选择条件跳转的信号来源zerosrc,zero表示beq条件;opzero=~zero,表示bne条件。

(2)最终代码整体分析

1)top.sv

增加了IO设备后的top文件端口发生了变化,输入和输出与实验开发板的开关,按钮,7段数码管联系起来。

增加DataMemoryDecoder模块,该模块包含数据存储器,I/O接口,7段数码管3个子模块。

2)mips

包含controller和datapath模块,controller模块包含主译码器,alu译码器模块,datapath包含原理图中的各个功能模块,controller中的译码器代码因为真值表的变化而产生一些变化,aluop变成3位向量,以及增加immselect信号,从controller输出,输入datapath,datapath中增加了零扩展模块和立即数选择模块。

3)imem

指令存储器,根据pc读取memfile.dat中的指令,因为指令文件添加到了项目中,所以读取时采用相对路径。

4)DataMemoryDecoder

包含dmem,IO,mux7seg模块。

dmem模块根据we和rd信号进行存数、取数操作。

IO模块,switchl用于接收从switch端口输入的信号,并在pRead==1时,内存地址正确时将开关输入的数据经过pReadData进入mips处理器;ledl用于在pWrite==1时,内存地址正确时,接收开关输入数据经mips处理的结果writedata。并且在ButtonL==1时,即输出就绪时,将ledl中暂存的结果输出到led端口,output到DataMemoryDecoder,与switch一起组成32位digit输入到7段数码管模块;status用于储存目前状态,当按下ButtonR时status[1]=1,表示准备读入开关数据,当按下ButtonL时status[0]=1,表示准备输出运算结果。

 

7段数码管模块

利用时钟产生一个3位向量s用于选择数码管。

选择亮起的数码管后,同时用s选择对应该数码管应该显示的值digit2

根据digit2的值选择数码管的A2G值,注意到当digit2值为0000时使用if else语句做出判断,这是因为digit输入mux7seg时,应该显示等号的数码管对应的digit值为0000,所以对digit2=0000时应该显示“0”或者“=”做出了判断。

 

仿真testbench

2. 仿真结果         

   1)基础部分

根据教材给出的测试文件和指令集,对具有R类型、lw,sw、beq、addi、j指令的单周期CPU代码进行测试,得到仿真结果如下,说明该CPU各项功能正常。

 2)扩展指令后

扩展andi,ori,bne指令后,进行仿真验证3个指令的功能,由仿真结果可知,三个指令的功能正常。

3)增加IO设计后

仿真时钟自定为100MHZ,每隔约1.3ms选择数码管的信号count一次。仿真开始时,设置了10ns的清零操作和输出操作此后输入信号与输出信号一直保持为1,switch信号设置为4’h1234,可通过AN和A2G信号的仿真波形看出,各个数码管依次显示1234=046。仿真成功。

3.实验开发板

  1. 上板清零     

 

      2.实现12+34=046

  1. 其他十六进制数相加的验证

  • 实验中的问题分析总结
  1. 添加memfile.dat时的问题

在仿真和最后实验上板的时候都出现了无法读入指令的情况,经过探索与实践,得到的解决办法是在design source和simulation source中都添加memfile.dat文件,前者用于生成.bit文件,后者用于vivado内的仿真。且用于生成bit文件的指令文件需要为.dat格式而非.txt格式。

     2.调试代码

根据仿真结果判断仿真是否正确时,可以加入内部变量的波形,如pc,instr等,根据pc地址和指令逐步分析,查漏补缺。

另外判断其他部分代码是否正确可以通过vivado中的open elaborated design查看电路图,比对设计时理想的电路图排除错误。

有关32位MIPS单周期CPU设计的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  4. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  5. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  6. ruby-on-rails - 设计注册确认 - 2

    我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:

  7. ruby-on-rails - 设计通过 reset_password_token 获取用户 - 2

    我正在尝试创建密码规则来设计可恢复的密码更改。我通过passwords_controller.rb做了一个父类(superclass),但我需要在应用规则之前检查用户角色,但我所拥有的只是reset_password_token。 最佳答案 假设您的模型是用户:User.with_reset_password_token(your_token_here)Source 关于ruby-on-rails-设计通过reset_password_token获取用户,我们在StackOverflow

  8. ruby-on-rails - Rails 5,公寓和设计 : sign in with subdomains are not working - 2

    我已经使用Apartment设置了一个Rails5应用程序(1.2.0)和Devise(4.2.0)。由于某些DDNS问题,应用只能在app.myapp.com下访问(请注意子域app)。myapp.com重定向到app.myapp.com。我的用例是每个注册该应用的用户(租户)都应该通过他们的子域(例如tenant.myapp.com)访问他们的特定数据。用户不应限定在其子域内。基本上应该可以从任何子域登录。重定向到租户的正确子域由ApplicationController处理。根据Devise标准,登录页面位于app.myapp.com/users/sign_in。这就是问题开始的

  9. ruby-on-rails - 设计中的 ArgumentError::RegistrationsController#new 错误的参数数量(2 代表 0..1) - 2

    我在关注RyanbatesRailsCast的devise和omniauth(第235集-devise-and-omniauth-revised)。当我尝试使用Twitter登录时,标题中不断出现错误。defself.new_with_session(params,session)ifsession["devise.user_attributes"]new(session["devise.user_attributes"],without_protection:true)do|user|user.attributes=paramsuser.valid?end完整跟踪:C:/Ruby20

  10. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

随机推荐