差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
自己设计一款cpu [2018/09/18 16:19]
group003 [CPU的行为描述]
自己设计一款cpu [2018/09/19 16:18] (当前版本)
group003 [让CPU运行软件程序]
行 2: 行 2:
 我们以姜咏江老师的书《自己设计制作CPU与单片机》中一个简单CPU为例子,说明CPU的工作原理和设计过程。 \\ 我们以姜咏江老师的书《自己设计制作CPU与单片机》中一个简单CPU为例子,说明CPU的工作原理和设计过程。 \\
 该CPU的程序在设计之初是固定的,并没有设计外部程序输入接口,所以这是一个专用CPU。\\ 该CPU的程序在设计之初是固定的,并没有设计外部程序输入接口,所以这是一个专用CPU。\\
 +{{::​jdcpu.docx|jdcpu完整代码}}
 ====CPU的端口描述==== ====CPU的端口描述====
 <code verilog> <code verilog>
行 179: 行 180:
 ===指令执行周期的描述=== ===指令执行周期的描述===
 指令执行周期的详细描述实际上是CPU设计最核心的部分。\\ 指令执行周期的详细描述实际上是CPU设计最核心的部分。\\
-<​code ​veilog>+<​code ​verilog>
 2:  begin                               //​CPU进入jp=2的状态 ​       ​ 2:  begin                               //​CPU进入jp=2的状态 ​       ​
                 case (q_w[15:​11]) ​              //​用指令编码确定指令                 case (q_w[15:​11]) ​              //​用指令编码确定指令
行 257: 行 258:
                 endcase                 endcase
             end              end 
- 
 </​code>​ </​code>​
 jp=2状态结束后,sdal、sdah、jmp、jz、jn等指令就已经执行完成了,这说明这几条指令的指令周期只有3个时钟节拍。指令执行完成后,指令标识和节拍变量切记归零,若不是转移指令,还要讲程序计数器pc加1,以便CPU去取下一条指令;如果没有执行完成,那么将节拍状态改为下一个。\\ jp=2状态结束后,sdal、sdah、jmp、jz、jn等指令就已经执行完成了,这说明这几条指令的指令周期只有3个时钟节拍。指令执行完成后,指令标识和节拍变量切记归零,若不是转移指令,还要讲程序计数器pc加1,以便CPU去取下一条指令;如果没有执行完成,那么将节拍状态改为下一个。\\
行 406: 行 406:
         end         end
 </​code>​ </​code>​
- +====让CPU运行软件程序==== 
 +如何验证我们设计的CPU是成功的呢?\\ 
 +办法只有用CPU指令系统编写程序,运行在这个CPU上面,如果结果是正确的,那说明我们的设计是成功的。\\ 
 +这个CPU支持的指令有 
 +<code verilog>​ 
 +//指令: 
 +     ​lda, ​   //​取数:​从数据单元取数到da 
 +     ​add, ​   //​加:​da与数据单元相加,结果放入da 
 +     ​out, ​   //​输出:​将数据单元内容输出到输出寄存器 
 +     ​sdal, ​  //​低8位立即数:​将8位立即数扩充为16位送da 
 +     ​sdah, ​  //​高8位立即数:​将8位立即数作为高8位,与原da低8位连接成16位放在da中 
 +     ​str, ​   //​da送数据存储单元:​ 
 +     ​sub, ​   //​减:​da与数据单元相减,结果放入da 
 +     ​jmp, ​   //跳转 
 +     ​jz, ​    //​da为0跳转 
 +     ​jn, ​    //​da为负跳转 
 +     ​call, ​  //​调用子程序 
 +     ​ret, ​   //返回 
 +     ​mult, ​  //​乘:​da与数据单元相乘,结果放入da 
 +     ​divi, ​  //​除:​da除以数据单元,结果放入da 
 +     ​stp; ​   //停止 
 +</​code>​ 
 +===设计用于检验的汇编程序=== 
 +我们用该CPU的指令系统编写一个能够求出8!(8的阶乘)的汇编程序 
 +<code c> 
 +start: sdal 1   ;​将1送到累加器da的低8位 
 + str one  ​ ;​累加器内容送到数据存储器的one单元 
 + str result  ​ ;​将1送到数据存储器的result单元 
 + sdal 8   ;​将8送到累加器da的低8位 
 + str x  ​ ;​将累加器内容送数据存储器x单元 
 +loop:​ lda x  ​ ;​将x单元的数据送到累加器da 
 + jz exit  ​ ;​如果da=0则跳转到exit地址取指令执行 
 + mult    result ​   ;​da的值乘以result的值,结果送到da 
 + str result  ​ ;​将da的值回送到result 
 + lda x  ​ ;​将x单元的值送到da 
 + sub one  ​ ;​da-1送到da 
 + str x  ​ ;​再将da值送回x 
 + jmp loop  ​ ;​转到loop地址取指令执行 
 +exit:​ out result  ​ ;​输出最终结果 
 + stp  ​ ;​停止CPU运行  
 +</​code>​ 
 +===用表来编译汇编程序=== 
 +现在程序的编译一般都有专门的汇编器,这里我们以人工绘表的方式来编译,这种程序编译表格是最基本的编译工具。\\ 
 +{{::​自己设计cpu_编译表.png|}}\\ 
 +左边“地址”一栏是程序存储器或数据存储器的地址编号,“标号”和“汇编程序”两栏是汇编程序,“二进制编码”一栏是二进制数的机器指令,“编译”一栏是十六进制的机器指令,“数据”一栏是数据变量的位置分配。最后两栏是该设计中的CPU指令和编码。\\ 
 +这个汇编程序使用了3个16位的数据变量 one、result、x。它们在存储器中的位置被安排在1,2,3号存储单元。\\ 
 +程序计数器pc的初始值是0,我们将标号start定位0号存储单元,依次往下排可以得到loop标注5号存储单元,exit是13号存储单元。\\ 
 +二进制编译一栏是对指令操作码和操作数的译码。左面5位是对应指令的编码,如sdal 编码是00100,右面的11位数是对应操作数的编码,其编码依据指令格式来确定。如果操作数是变量型操作数即one,result,x,则对应变量的存储单元地址1,2,3。如果操作数是立即数,则直接使用立即数本身。\\ 
 +====仿真检验CPU设计====