基于PGL122G FPGA 设计32位CPU,提供的灵活性允许根据需要开启或禁止处理器、IP内核以及软件平台的高级功能,并且可以对许多独立参数进行精细调整,直到在软件一级满足应用的要求。此外,利用建模工具可以识别任何性能关键的软件功能并将其分流至适当的硬件加速器或协处理器来完成。基于 FPGA 的五级流水线 CPU 的总体结构模型,实现了取指IF、指令译码ID、指令执行EXE、存储MEM,取指周期设计了PC寄存器和指令存储器,实现了取指令功能;译码周期设计了控制器CU、寄存器堆等部件,完成了20条指令的译码功能;指令执行周期主要对运算器ALU的设计,实现了对数据的运算操作;存储周期完成了数据存储器的设计,用于存储周期的读写操作;结果写回周期,通过设计多路器,实现将正确的结果写回到目的寄存器中。
32位CPU内核结构:寄存器组(①)、NVIC(②)、中断和异常(③)、储存器映射(④)、总线接口(⑤)、调试支持(⑥)、指令集。
可配置处理系统的配置(或定制)的层面包括:
处理器配置:
•乘法器、除法器、浮点单元以及其它。
•指令或数据缓冲配置。
•协处理器或硬件加速器。
系统配置
•I/O外设选择、定制、DMA选择。
•存储器外设选择、定制。
应用配置
•RTOS选择、定制。
•应用库/中间件定制
控制器设计
module CtrlUnit(
input [31:0] instr,
input [31:0] rdata1, rdata2,
input [31:0] pc,ram_data,hi,lo,alu_r,cop_data,mul_out,
input [31:0] exc_addr,
input clk,
output mtc0,eret,teq_exc,
output reg [2:0] mdu,
output reg reg_wena,
output ram_wena,
output reg [3:0] cause,
output [4:0] rs,rt,rd,waddr,
output reg [31:0] wdata,reg_data,
output [31:0] ram_addr,
output reg [31:0] pc_in,
output reg [31:0] alu_a,alu_b,
output reg [3:0] alu_op
);
//******MIPS-55*********//
parameter //SPECIAL OP LIST 5-0
ADDU = 6'b100001,
SUBU = 6'b100011,
ADD = 6'b100000,
SUB = 6'b100010,
AND = 6'b100100,
OR = 6'b100101,
XOR = 6'b100110,
NOR = 6'b100111,
SLT = 6'b101010,
SLTU = 6'b101011,
SRL = 6'b000010,
SRA = 6'b000011,
SLL = 6'b000000,
SLLV = 6'b000100,
SRLV = 6'b000110,
SRAV = 6'b000111,
JR = 6'b001000,
JALR = 6'b001001,
MULT = 6'b011000,
MULTU = 6'b011001,
DIV = 6'b011010,
DIVU = 6'b011011,
MFHI = 6'b010000,
MFLO = 6'b010010,
MTHI = 6'b010001,
MTLO = 6'b010011,
BREAK = 6'b001101,
SYSCALL = 6'b001100,
TEQ = 6'b110100,
//SPECIAL 2 func
CLZ = 6'b100000,
MUL = 6'b000010,
//REGIMM OP LIST 20-16
BLTZ = 5'b00000,
BGEZ = 5'b00001,
//COP0 OP LIST
ERET = 6'b011000, //5-0&&25TH=1
MFC0 = 5'b00000, //20-16
MTC0 = 5'b00100,
//OPCODE FIELD 31-26
ADDI = 6'b001000,
ADDIU = 6'b001001,
ANDI = 6'b001100,
ORI = 6'b001101,
XORI = 6'b001110,
LW = 6'b100011,
SW = 6'b101011,
BEQ = 6'b000100,
BNE = 6'b000101,
BLEZ = 6'b000110,
BGTZ = 6'b000111,
SLTI = 6'b001010,
SLTIU = 6'b001011,
LUI = 6'b001111,
J = 6'b000010,
JAL = 6'b000011,
LB = 6'b100000,// Load Byte Function=6'h24
LBU = 6'b100100,// 1Load Byte Unsigned
LH = 6'b100001,// Load high
LHU = 6'b100101,// Load High Unsigned
SB = 6'b101000,// Send Byte
SH = 6'b101001,// Send High
SPECIAL = 6'b000000,
SPECIAL2= 6'b011100,
REGIMM = 6'b000001,
COP0 = 6'b010000;
//ALU OPCODE
parameter _ADDU = 4'b0000; //r=a+b unsigned
parameter _ADD = 4'b0010; //r=a+b signed
parameter _SUBU = 4'b0001; //r=a-b unsigned
parameter _SUB = 4'b0011; //r=a-b signed
parameter _AND = 4'b0100; //r=a&b
parameter _OR = 4'b0101; //r=a|b
parameter _XOR = 4'b0110; //r=a^b
parameter _NOR = 4'b0111; //r=~(a|b)
parameter _LUI = 4'b1000; //r={b[15:0],16'b0}
parameter _SLT = 4'b1011; //r=(a-b<0)?1:0 signed
parameter _SLTU = 4'b1010; //r=(a-b<0)?1:0 unsigned
parameter _SRA = 4'b1100; //r=b>>>a
parameter _SLL = 4'b1110; //r=b<<a
parameter _SRL = 4'b1101; //r=b>>a
parameter _SYSCALL= 4'b1000,
_BREAK = 4'b1001,
_TEQ = 4'b1101;
wire [5:0] op = instr[31:26];
assign rs = instr[25:21];
assign rt = instr[20:16];
assign rd = instr[15:11];
wire [5:0] func = instr[5:0];
wire [4:0] shamt = instr[10:6];
wire [15:0] imm = instr[15:0];
wire [25:0] addr = instr[25:0];
parameter SIGN = 1'b1;
parameter UNSIGN = 1'b0;
wire imm_sign = (op==ANDI||op==ORI||op==XORI)?UNSIGN:SIGN;
wire [31:0] shamt_ext = {27'b0,shamt};
wire [31:0] imm_ext = imm_sign?{{(16){imm[15]}},imm}:{16'b0,imm};
reg [31:0] load_data,clz_data;
assign waddr = (op==SPECIAL||op==SPECIAL2)? rd: (op==JAL) ?5'b11111:rt;
always@(*)begin
case(op)
SB: reg_data = {24'b0,rdata2[7:0]};
SH: reg_data = {16'b0,rdata2[15:0]};
SW: reg_data = rdata2;
default:reg_data = rdata2;
endcase
case(op)
LB: load_data = {{24{ram_data[7]}},ram_data[7:0]};
LBU: load_data = {24'b0,ram_data[7:0]};
LH: load_data = {{16{ram_data[15]}},ram_data[15:0]};
LHU: load_data = {16'b0,ram_data[15:0]};
LW: load_data = ram_data;
default:load_data = ram_data;
endcase
if(op==SPECIAL)
case(func)
SYSCALL:cause = _SYSCALL;
BREAK: cause = _BREAK;
TEQ: cause = _TEQ;
default:cause = 5'b0;
endcase
else cause = 5'b0;
/*
1 mult
2 multu
3 div
4 divu
5 mthi
6 mtlo
7 mul
*/
if(op==SPECIAL)
case(func)
MULT: mdu = 3'h1;
MULTU: mdu = 3'h2;
DIV: mdu = 3'h3;
DIVU: mdu = 3'h4;
MTHI: mdu = 3'h5;
MTLO: mdu = 3'h6;
default:mdu = 3'h0;
endcase
else mdu = 3'h0;
end
wire [31:0] npc = pc+4;
wire [31:0] pc_branch = npc + {{(14){imm[15]}},imm,2'b00};
wire [31:0] pc_jmp = {npc[31:28],addr,2'b00};
assign ram_addr = rdata1 + imm_ext;
assign eret = op==COP0 && func==ERET;
wire mfc0 = op==COP0 && rs==MFC0;
assign mtc0 = op==COP0 && rs==MTC0;
assign teq_exc = rdata1==rdata2;
parameter ENA = 1'b1;
parameter DIS = 1'b0;
wire mem_load = op==LB || op==LH || op==LBU || op==LHU || op==LW;
assign ram_wena = op==SW || op==SH || op==SB;
integer i;
always@(*)begin
case(op)
SPECIAL: case(func)
MULTU,
DIV,
DIVU,
JR,
MTHI,
MTLO,
BREAK,
SYSCALL:reg_wena = DIS;
default:reg_wena = ENA;
endcase
COP0: reg_wena = rs==MFC0?ENA:DIS;
SPECIAL2,
LB,
LBU,
LH,
LHU,
ADDI,
ADDIU,
ANDI,
ORI,
XORI,
LW,
SLTI,
SLTIU,
LUI,
JAL: reg_wena = ENA;
default: reg_wena = DIS;
endcase
case(op)
SPECIAL:case(func)
JALR: wdata = npc;
MFHI: wdata = hi;
MFLO: wdata = lo;
default:wdata = alu_r;
endcase
SPECIAL2:begin
if(func==CLZ) casez(rdata1)
32'b1???????????????????????????????: wdata = 32'h0;
32'b01??????????????????????????????: wdata = 32'h1;
32'b001?????????????????????????????: wdata = 32'h2;
32'b0001????????????????????????????: wdata = 32'h3;
32'b00001???????????????????????????: wdata = 32'h4;
32'b000001??????????????????????????: wdata = 32'h5;
32'b0000001?????????????????????????: wdata = 32'h6;
32'b00000001????????????????????????: wdata = 32'h7;
32'b000000001???????????????????????: wdata = 32'h8;
32'b0000000001??????????????????????: wdata = 32'h9;
32'b00000000001?????????????????????: wdata = 32'ha;
32'b000000000001????????????????????: wdata = 32'hb;
32'b0000000000001???????????????????: wdata = 32'hc;
32'b00000000000001??????????????????: wdata = 32'hd;
32'b000000000000001?????????????????: wdata = 32'he;
32'b0000000000000001????????????????: wdata = 32'hf;
32'b00000000000000001???????????????: wdata = 32'h10;
32'b000000000000000001??????????????: wdata = 32'h11;
32'b0000000000000000001?????????????: wdata = 32'h12;
32'b00000000000000000001????????????: wdata = 32'h13;
32'b000000000000000000001???????????: wdata = 32'h14;
32'b0000000000000000000001??????????: wdata = 32'h15;
32'b00000000000000000000001?????????: wdata = 32'h16;
32'b000000000000000000000001????????: wdata = 32'h17;
32'b0000000000000000000000001???????: wdata = 32'h18;
32'b00000000000000000000000001??????: wdata = 32'h19;
32'b000000000000000000000000001?????: wdata = 32'h1a;
32'b0000000000000000000000000001????: wdata = 32'h1b;
32'b00000000000000000000000000001???: wdata = 32'h1c;
32'b000000000000000000000000000001??: wdata = 32'h1d;
32'b0000000000000000000000000000001?: wdata = 32'h1e;
32'b00000000000000000000000000000001: wdata = 32'h1f;
32'b00000000000000000000000000000000: wdata = 32'h20;
endcase
else if(func==MUL) wdata = mul_out;
else wdata = alu_r;
end
JAL: wdata = npc;
LW,LB,LH,LBU,LHU: wdata = load_data;
COP0: if(rs==MFC0) wdata = cop_data;
else wdata = alu_r;
default: wdata = alu_r;
endcase
//Below is OK
case(op)
SPECIAL: case(func)
SLL,
SRL,
SRA:begin
alu_a = shamt_ext;
alu_b = rdata2;
end
default:begin
alu_a = rdata1;
alu_b = rdata2;
end
endcase
ADDI,
ADDIU,
ANDI,
ORI,
XORI,
SLTI,
SLTIU,
LUI:begin
alu_a = rdata1;
alu_b = imm_ext;
end
default:begin
alu_a = rdata1;
alu_b = rdata2;
end
endcase
//PC Source
case(op)
SPECIAL: case(func)
SYSCALL,
TEQ,
BREAK: pc_in = exc_addr;
JALR,
JR: pc_in = rdata1;
default:pc_in = npc;
endcase
COP0: case(func)
ERET: pc_in = exc_addr;
default:pc_in = npc;
endcase
REGIMM: case(rt)
BLTZ:if(rdata1[31])
pc_in = pc_branch;
else
pc_in = npc;
BGEZ:if(!rdata1[31])
pc_in = pc_branch;
else
pc_in = npc;
default:pc_in = npc;
endcase
J,
JAL: pc_in = pc_jmp;
BEQ:if(rdata1==rdata2)
pc_in = pc_branch;
else pc_in = npc;
BNE:if(rdata1!=rdata2)
pc_in = pc_branch;
else pc_in = npc;
BLEZ:if(rdata1[31] || rdata1==32'b0)
pc_in = pc_branch;
else pc_in = npc;
BGTZ:if(!rdata1[31] && rdata1!=32'b0)
pc_in = pc_branch;
else pc_in = npc;
default: pc_in = npc;
endcase
case(op)
SPECIAL:case(func)
ADDU: alu_op = _ADDU;
SUBU: alu_op = _SUBU;
ADD: alu_op = _ADD;
SUB: alu_op = _SUB;
AND: alu_op = _AND;
OR: alu_op = _OR;
XOR: alu_op = _XOR;
NOR: alu_op = _NOR;
SLT: alu_op = _SLT;
SRL: alu_op = _SRL;
SLL: alu_op = _SLL;
SRA: alu_op = _SRA;
SLTU: alu_op = _SLTU;
SRLV: alu_op = _SRL;
SLLV: alu_op = _SLL;
SRAV: alu_op = _SRA;
default: alu_op = _ADDU;
endcase
ORI: alu_op = _OR;
XORI: alu_op = _XOR;
BEQ: alu_op = _SUBU;
BNE: alu_op = _SUBU;
ANDI: alu_op = _AND;
ADDIU: alu_op = _ADDU;
ADDI: alu_op = _ADD;
SLTI: alu_op = _SLT;
SLTIU: alu_op = _SLTU;
LUI: alu_op = _LUI;
default: alu_op = _ADDU;
endcase
end
endmodule
PC寄存器设计
input clk,
input rst,
input ena,
input [31:0] data_in,
output [31:0] data_out
);
reg [31:0] data=32'b0;
always @(posedge clk or posedge rst) begin
if(rst) data<=32'h00400000; //reset key
else begin
if(ena) data<=data_in; //enable ,input
end
end
assign data_out = data;
Endmodule
Regfiles设计
module RegFiles(
input clk,
input rst,
input we,
input [4:0] raddr1,
input [4:0] raddr2,
input [4:0] waddr,
input [31:0] wdata,
output [31:0] rdata1,
output [31:0] rdata2
);
reg [31:0] data [0:31];
always@(posedge clk or posedge rst) begin
if(rst) for(i=0;i<32;i=i+1) begin
data[i]<=32'b0;
end
else begin
if(we&&waddr!=5'b0) data[waddr]<=wdata;
end
end
Endmodule
ALU设计
module alu(
input [31:0] a, //OP1
input [31:0] b, //OP2
input [3:0] aluc, //controller
output [31:0] r, //result
output zero,
output carry,
output negative,
output overflow);
parameter Addu = 4'b0000; //r=a+b unsigned
parameter Add = 4'b0010; //r=a+b signed
parameter Subu = 4'b0001; //r=a-b unsigned
parameter Sub = 4'b0011; //r=a-b signed
parameter And = 4'b0100; //r=a&b
parameter Or = 4'b0101; //r=a|b
parameter Xor = 4'b0110; //r=a^b
parameter Nor = 4'b0111; //r=~(a|b)
parameter Lui1 = 4'b1000; //r={b[15:0],16'b0}
parameter Lui2 = 4'b1001; //r={b[15:0],16'b0}
parameter Slt = 4'b1011; //r=(a-b<0)?1:0 signed
parameter Sltu = 4'b1010; //r=(a-b<0)?1:0 unsigned
parameter Sra = 4'b1100; //r=b>>>a
parameter Sll = 4'b1110; //r=b<<a
parameter Srl = 4'b1101; //r=b>>a
parameter bits=31;
parameter ENABLE=1,DISABLE=0;
reg [32:0] result;
wire signed [31:0] sa=a,sb=b;
always@(*)begin
case(aluc)
Addu: begin
result=a+b;
end
Subu: begin
result=a-b;
end
Add: begin
result=sa+sb;
end
Sub: begin
result=sa-sb;
end
Sra: begin
if(a==0) {result[31:0],result[32]}={b,1'b0};
else {result[31:0],result[32]}=sb>>>(a-1);
end
Srl: begin
if(a==0) {result[31:0],result[32]}={b,1'b0};
else {result[31:0],result[32]}=b>>(a-1);
end
Sll: begin
result=b<<a;
end
And: begin
result=a&b;
end
Or: begin
result=a|b;
end
Xor: begin
result=a^b;
end
Nor: begin
result=~(a|b);
end
Sltu: begin
result=a<b?1:0;
end
Slt: begin
result=sa<sb?1:0;
end
Lui1,Lui2: result = {b[15:0], 16'b0};
default:
result=a+b;
endcase
end
assign r=result[31:0];
assign carry = result[32];
assign zero=(r==32'b0)?1:0;
assign negative=result[31];
assign overflow=result[32];
Endmodule
RAM设计
module ram(
input clk,
input wena,
input [8:0] addr,
input [31:0] data_in,
output [31:0] data_out
);
reg [31:0] state [0:512];
always@(posedge clk) begin
if(wena) begin
if(addr!=0) state[addr]<=data_in;
end
end
assign data_out=state[addr];endmodule
Pango Design Suite 仿真
扫码免费申请试用
紫光同创PGL22G开发平台试用连载(3)——驱动OV5640 摄像头实现sobel算子边缘检测算法
紫光同创PGL22G开发平台试用连载(2)——基于SD卡的音频MP3播放器
紫光同创PGL22G开发平台试用连载(1)——开发板硬件软件初步评估篇
紫光同创PGL22G开发平台试用连载-(4)以太网测试工程三
紫光同创PGL22G开发平台试用连载(3)---以太网测试工程二
紫光同创PGL22G开发平台试用连载-(2)以太网测试工程一
紫光同创PGL22G开发平台试用连载-(1)软硬件初步体验
紫光同创PGL22G开发平台试用连载(8)---程序密码之程序篇
紫光同创PGL22G开发平台试用连载(7)---程序密码之理论篇
紫光同创PGL22G开发平台试用连载(6)---边缘检测之综合篇
紫光同创PGL22G开发平台试用连载(5)---边缘检测之算法篇
紫光同创PGL22G开发平台试用连载(4)---边缘检测之串口通信篇
紫光同创PGL22G开发平台试用连载(3)---重点功能初探
紫光同创PGL22G开发平台试用连载(2)---基本流程dome
紫光同创PGL22G开发平台试用连载(1)---软件和器件
紫光同创PGL22G开发平台试用连载(1)-FPGA参数分析和对比
紫光同创PGL22G开发平台试用连载(2)---PDS软件试用
紫光同创PGL22G开发平台试用连载(3)---在FPGA上实现DW8051 MCU