从零开始设计RISC - CPU——002

记录剩下的7个模块,其中最后一个控制器没写完放到明天

2.指令寄存器

这里的指令寄存器设计的还是比较好理解的,从端口上来说可以有

输入:CLK、8位的DATA 、LOAD_IR、RESET

输出:16位opc_iraddrs

基本原理:在取指令LOAD_IR为高电位,CLK时钟上升沿来临时,将一条16位的指令拆分为高8位与低8位,分两次CLK上升沿拆递给8位的DATA。这里声明了一个中间变量state用于判断是高8位的指令还是低8位的指令。当中间变量state为0,进行取高8位;当中间变量state为1,进行取高低位。还需注意的是指令是存在内部的opc_iraddrs中,这里是16位的。而高3位为操作码,低13位为地址,经计算2的13次方为8192,因此寻址空间为8K字节。

有一点不是很明白:8K的指令是按照顺序存入吗?到底如何存?

Verilog代码

‘timescle 1ns/1ns
module register(opc_iraddr,clk,ena,rst,data);
input clk,rst,ena;
input [7:0] data;
output [15:0] opc_iraddr;
reg [15:0] opc_iraddr;
reg state;
always @(posedge clk)
 begin
  if(rst)
begin
  opc_iraddr<=16’b0000_0000_0000_0000;
  state<=1’b0;
end
  else 
begin
  if(ena)
    begin
      casex(state)
        1’b0:
          begin
               opc_iraddr[15:8]<=data;
               state<=1’b1;
          end
1’b1:
          begin
               opc_iraddr[7:0]<=data;
               state<=1’b0;
          end
default:
          begin
               opc_iraddr[15:0]<=16’bxxxx_xxxx_xxxx_xxxx;
               state<=1’bx;
          end
      endcase
    end
  else
    state<=1’b0;
 end
end
endmodule

3.累加器

用于存放当前的结果,它也是双目计算中的一个来源。复位后,累加器的值为0。当累加器ena端口收到CPU状态控制器发出的load_acc信号时,在一个时钟上升沿到来时,累加器便会收到来自数据总线的数据。

Verilog代码

‘timescle 1ns/1ns
module accum(accum,data,ena,clk,rst);
input [7:0]data;
input clk,ena,rst;
output [7:0]accum;
reg [7:0]accum;
always @(posedge clk)
  begin
if(rst)
accum<=8’b0000_0000;
else
if(ena)
accum<=data;
  end
endmodule

4.算术运算器

根据输入的操作码,实现对应加、与、异或、跳转、写入、读出、暂停等

Verilog代码

‘timescle 1ns/1ns
module alu(alu_out,zero,data,accum,alu_ena,opcode,alu_clk);
input [7:0] data,accum;
input [2:0] opcode;
input alu_clk;
output zero;
output [7:0]alu_out;
parameter HLT  = 3’b000;
           SKZ = 3’b001;
           ADD = 3’b010;
           AND = 3’b011;
           XOR = 3’b100;
           LDA  = 3’b101;
           STO = 3’b110;
           JMP = 3’b111;
assgin zero =! accum;
always @(posedge alu_clk)
  begin
   casex(opcode)  //来自指令寄存器的输出opc_irddr[15:0]的低三位。
      HLT:alu_out<=accum;
      SKZ: alu_out<=accum;
      ADD: alu_out<=data + accum;
      AND: alu_out<= data&accum;
      XOR: alu_out<= data^accum;
      LDA:alu_out<= data;
      STO: alu_out<=accum;
      JMP: alu_out<=accum;
      default: alu_out<=8’bxxxx_xxxx;
   endcase
  end
endmodule

5.数据控制器

控制数据data何时输出到总线上,供其他模块使用

Verilog代码

‘timescle 1ns/1ns
module datactl(data, in,data_ena);
input [7:0]in;
input data_ena;
output [7:0] data;
assign data=(data_ena)?in:8’bzzzz_zzzz;//数据不使用时,置位高阻态。
endmoudle

6.地址多路选择器

用于选择输出的地址是PC(程序计数器)地址还是数据/端口地址。每个指令周期的前4个时钟周期用于从ROM中读取指令,输出的应是PC地址;后四个时钟周期用于对RAM或端口的读写,该地址由指令给出。地址的选择输出信号由8分频信号fetch提供。

Verilog代码

‘timescle 1ns/1ns
module adr(addr,fetch,ir_addr,pc_addr);
input fetch;
input [12:0]ir_addr,pc_addr;
output [12:0]addr;
assign addr = fetch?pc_addr:ir_addr;
endmodule

7.程序计数器

用于提供指令地址

Verilog代码

‘timescle 1ns/1ns
module counter(pc_addr,ir_addr,load,rst,clock);
input [12:0]ir_addr;
input load,clock,rst;
output [12:0]pc_addr;
reg [12:0]pc_addr;
always @(posedge clock or posedge rst)
  begin
if(rst)
 pc_addr<=13’b0_0000_0000_0000;//复位后pc_addr从0出发
else
 if(load)//这个应该是JMP指令出发的
  pc_addr<=ir_addr;
 else
  pc_addr<=pc_addr+1;
  end
endmoulde

8.状态控制器

此部分由两部分组成,状态机和状态控制器。状态机是CPU最为核心的地方

状态控制器用于控制状态机是否工作。

状态控制器Verilog代码

‘timescle 1ns/1ns
module machinectl(ena,fetch,rst,clk);
input fetch,rst,clk;
output ena;
reg ena;
reg state;
  always @(posedge clk);
begin
 if(rst)
  begin
   ena<=0
  end
 else
  if(fetch)
   begin
    ena<=1;
   end
end
endmodule
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值