A RISC Processor實驗
這是一個精簡指令集 (Reduced Instruction Set Computer) 的微處理器, 並利用FPGA內的RAM作為微處理器的程式記憶體; 程式 (機械碼) 則寫在Prog1.v
本實驗包含HDL : riscpu.v和memory file : Prog1.v
Source
|
Verilog : riscpu.v |
|
module riscpu ( mclk,nrst, iopa,iopb,iopc,iopd );
input mclk,nrst; inout[7:0] iopa,iopb,iopc,iopd;
reg[15:0] pdx,pdy; reg[11:0] pc,pcx,stk0,stk1,stk2,stk3,stko; reg[8:0] alo; reg[7:0] rgg0,rgg1,rgg2,rgg3,rgg4,rgg5,rgg6,rgg7, rgg8,rgg9,rgga,rggb,rggc,rggd,rgge,rggf, rqab,rqbb,rdi; reg[3:0] ws; reg[1:0] sp; reg wen,wenx,weny, pcmx,pcmxx, pcadmx,pcadmxx, pushst,pushstx, aldb,tcnd;
wire[15:0] pd; wire rzr;
///// program ROM prom prom(.addr(pc[7:0]),.dq(pd));
///// Instruction pipeline always @(posedge mclk or negedge nrst) begin if(~nrst) begin pdx<=0; pdy<=0; end else begin pdx<=pd; pdy<=pdx; end end
///// register file with 2_read/1write ports always @(posedge mclk) begin case(pdx[11:8]) 4'b0000 : rqab<=rgg0; 4'b0001 : rqab<=rgg1; 4'b0010 : rqab<=rgg2; 4'b0011 : rqab<=rgg3; 4'b0100 : rqab<=rgg4; 4'b0101 : rqab<=rgg5; 4'b0110 : rqab<=rgg6; 4'b0111 : rqab<=rgg7; 4'b1000 : rqab<=rgg8; 4'b1001 : rqab<=rgg9; 4'b1010 : rqab<=rgga; 4'b1011 : rqab<=rggb; 4'b1100 : rqab<=iopa; 4'b1101 : rqab<=iopb; 4'b1110 : rqab<=iopc; 4'b1111 : rqab<=iopd; endcase end
always @(posedge mclk) begin if(aldb) rqbb<=pdx[7:0]; else begin case(pdx[7:4]) 4'b0000 : rqbb<=rgg0; 4'b0001 : rqbb<=rgg1; 4'b0010 : rqbb<=rgg2; 4'b0011 : rqbb<=rgg3; 4'b0100 : rqbb<=rgg4; 4'b0101 : rqbb<=rgg5; 4'b0110 : rqbb<=rgg6; 4'b0111 : rqbb<=rgg7; 4'b1000 : rqbb<=rgg8; 4'b1001 : rqbb<=rgg9; 4'b1010 : rqbb<=rgga; 4'b1011 : rqbb<=rggb; 4'b1100 : rqbb<=iopa; 4'b1101 : rqbb<=iopb; 4'b1110 : rqbb<=iopc; 4'b1111 : rqbb<=iopd; endcase end end
always @(posedge mclk) begin if(weny) begin if(ws==4'b0000) rgg0<=rdi; if(ws==4'b0001) rgg1<=rdi; if(ws==4'b0010) rgg2<=rdi; if(ws==4'b0011) rgg3<=rdi; if(ws==4'b0100) rgg4<=rdi; if(ws==4'b0101) rgg5<=rdi; if(ws==4'b0110) rgg6<=rdi; if(ws==4'b0111) rgg7<=rdi; if(ws==4'b1000) rgg8<=rdi; if(ws==4'b1001) rgg9<=rdi; if(ws==4'b1010) rgga<=rdi; if(ws==4'b1011) rggb<=rdi; if(ws==4'b1100) rggc<=rdi; if(ws==4'b1101) rggd<=rdi; if(ws==4'b1110) rgge<=rdi; if(ws==4'b1111) rggf<=rdi; end end
///// alu
always @(pdy or rqab or rqbb) begin case(pdy[13:12]) 2'b00 : alo<={1'b0,rqab}+{1'b0,rqbb}; 2'b01 : alo<={1'b0,rqab}-{1'b0,rqbb}; 2'b10 : alo<={1'b0,rqab&rqbb}; 2'b11 : alo<={1'b0,rqab|rqbb}; endcase end
always @(posedge mclk) rdi<=alo[7:0];
///// flags : carry/borrow in alo[8], zero in rzr
assign rzr=(alo[7:0]==8'h00);
///// programe counter
always @(posedge mclk or negedge nrst) begin if(~nrst) pc<=0; else if(pcmxx) pc<=stko; else pc<=pc+(pcadmxx?pdy[11:0]:12'h001); end
always @(posedge mclk) pcx<=pc;
///// pc stack
always @(posedge mclk) begin if(pushstx) begin if(sp==0) stk0<=pcx; if(sp==1) stk1<=pcx; if(sp==2) stk2<=pcx; if(sp==3) stk3<=pcx; end end
always @(sp or stk0 or stk1 or stk2 or stk3) begin case(sp) 0 : stko=stk0; 1 : stko=stk1; 2 : stko=stk2; 3 : stko=stk3; endcase end
///// stack pointer
always @(posedge mclk or negedge nrst) begin if(~nrst) sp<=0; else if(pcmx&~pcadmxx) // Pop stack. pcmx asserts : PC is loaded from the stack, ie. RET sp<=sp+1; else if(pushstx) // Push stack when CALL. Push & Pop never occur simultaniously. sp<=sp-1; end
///// controll logics ///// branch condition always @(pdx or rzr or alo) begin casex(pdx[14:12]) 3'b0xx : tcnd=1'b1; // unconditional branch 3'b100 : tcnd=rzr; // jz 3'b101 : tcnd=~rzr; // jnz 3'b110 : tcnd=alo[8]; // jc 3'b111 : tcnd=~alo[8]; // jnc endcase end
// write_back/branch/push_pop controls // if branch has occurred(pcadmxx==1), all control signals are disabled(flushed) // wen=1 if branch has occurred(pcadmxx==1) // always @(posedge mclk or negedge nrst) begin if(~nrst) begin wen<=1'b0; pcmx<=1'b0; pcadmx<=1'b0; pushst<=1'b0; aldb<=1'b0; end else casex(pd[15:12]) // NOP : all controls into the pipes are null. 4'b0000 : begin wen<=1'b0; pcmx<=1'b0; pcadmx<=1'b0; pushst<=1'b0; aldb<=1'b0; end // RET : PC will be loaded with stack contents(pcmx=1 -> pcmxx=1) // pcadmx also asserts indicating branch has occurred : pcadmxx=1 -> previous instruction is a taken branch // Assign pcmx=~pcadmxx instead of pcmx=1 to exclude the condition that previous instruction is a taken branch // ,so that this next instruction shold be annulled(flushed). The other control signals use this same mechanism. 4'b0001 : begin wen<=1'b0; pcmx<=~pcadmxx; pcadmx<=~pcadmxx; pushst<=1'b0; aldb<=1'b0; end // JMP : PC will be loaded with PC+offset(pdy[11:0])(pcadmxx=1) 4'b0010 : begin wen<=1'b0; pcmx<=1'b0; pcadmx<=~pcadmxx; pushst<=1'b0; aldb<=1'b0; end // CALL : PC will be loaded with PC+offset(pdy[11:0](pcadmxx=1), and next address will be pushed into stack 4'b0011 : begin wen<=1'b0; pcmx<=1'b0; pcadmx<=~pcadmxx; pushst<=~pcadmxx; aldb<=1'b0; end // JZ,JNZ,JC,JNC : PC will be loaded with PC+offset(pdy[11:0](pcadmxx=1) 4'b01xx : begin wen<=1'b0; pcmx<=1'b0; pcadmx<=~pcadmxx; pushst<=1'b0; aldb<=1'b0; end // ADD,SUB,AND,OR RRR : Register write enable wen=1, both the input (rqab,rqbb) of the ALU are from rigster 4'b10xx : begin wen<=~pcadmxx; pcmx<=1'b0; pcadmx<=1'b0; pushst<=1'b0; aldb<=1'b0; end // ADD,SUB,AND,OR RI : Register write enable wen=1, one of the input of the ALU is from op (rqbb=pdx[7:0], // when aldb=1) 4'b11xx : begin wen<=~pcadmxx; pcmx<=1'b0; pcadmx<=1'b0; pushst<=1'b0; aldb<=1'b1; end endcase end
// Second stage pipe controls always @(posedge mclk or negedge nrst) begin if(~nrst) begin pcadmxx<=0; pcmxx<=0; pushstx<=0; wenx<=0; weny<=0; end else begin pcadmxx<=pcadmx&tcnd&~pcadmxx; pcmxx<=pcmx&~pcadmxx; pushstx<=pushst&~pcadmxx; wenx<=wen&~pcadmxx; weny<=wenx; end end
always @(posedge mclk) begin if(pdy[14]) ws<=pdy[11:8]; else ws<=pdy[3:0]; end
///// bidirectional io ports. Directions controlled by rggb
assign iopa[7:4]=rggb[0]?rggc[7:4]:4'bzzzz; assign iopa[3:0]=rggb[1]?rggc[3:0]:4'bzzzz; assign iopb[7:4]=rggb[2]?rggd[7:4]:4'bzzzz; assign iopb[3:0]=rggb[3]?rggd[3:0]:4'bzzzz; assign iopc[7:4]=rggb[4]?rgge[7:4]:4'bzzzz; assign iopc[3:0]=rggb[5]?rgge[3:0]:4'bzzzz; assign iopd[7:4]=rggb[6]?rggf[7:4]:4'bzzzz; assign iopd[3:0]=rggb[7]?rggf[3:0]:4'bzzzz;
endmodule
|
|
prom.v |
|
module prom ( addr, dq );
input[7:0] addr; output[15:0] dq;
reg[15:0] dq;
always @(addr) begin case(addr)
'h00 : dq='hFBF0; // OR B,#F0 'h01 : dq='hF201; // OR 2,#01 'h02 : dq='hEE00; // AND E,#00 'h03 : dq='hEF00; // AND F,#00 'h04 : dq='h3003; // CALL 0009 'h05 : dq='h8EDE; // ADD E,D,E 'h06 : dq='h7FFC; // JNC 4 'h07 : dq='hCF01; // ADD F,#01 'h08 : dq='h2FFA; // JMP 4 'h09 : dq='hBDD4; // OR D,D,4 'h0A : dq='hBCC5; // OR C,C,5 'h0B : dq='hC600; // AND 6,#00 'h0C : dq='h0000; // NOP 'h0D : dq='h0000; // NOP 'h0E : dq='hD601; // SUB 6,#01 'h0F : dq='h5FFD; // JNZ E 'h10 : dq='hD501; // SUB 5,#01 'h11 : dq='h5FFB; // JNZ E 'h12 : dq='hD401; // SUB 4,#01 'h13 : dq='h5FF5; // JNZ A 'h14 : dq='h1000; // RET default : dq='h0000; // NOP endcase end
endmodule
// jump/branch displacement = target_addr-(pc+2)
|
|
|
opcode |
inst |
remark |
flag |
|||
|
0 |
0000 |
0000 |
0000 |
0000 |
NOP |
No operation |
|
|
1 |
0001 |
---- |
---- |
---- |
RET |
Return from the subroutine |
|
|
2 |
0010 |
aaaa |
aaaa |
aaaa |
JMP aaa |
Jump to the address aaa |
|
|
3 |
0011 |
aaaa |
aaaa |
aaaa |
CALL aaa |
Call the address aaa |
|
|
4 |
0100 |
dddd |
dddd |
dddd |
JZ ddd |
Branch to pc+2+ddd when zf=1 |
|
|
5 |
0101 |
dddd |
dddd |
dddd |
JNZ ddd |
Branch to pc+2+ddd when zf=0 |
|
|
6 |
0110 |
dddd |
dddd |
dddd |
JC ddd |
Branch to pc+2+ddd when cf=1 |
|
|
7 |
0111 |
dddd |
dddd |
dddd |
JNC ddd |
Branch to pc+2+ddd when cf=0 |
|
|
8 |
1000 |
xxxx |
yyyy |
zzzz |
ADD X, Y, Z |
Rz=Rx+Ry |
zf, cf |
|
9 |
1001 |
xxxx |
yyyy |
zzzz |
SUB X, Y, Z |
Rz=Rx-Ry |
zf, cf |
|
A |
1010 |
xxxx |
yyyy |
zzzz |
AND X, Y, Z |
Rz=Rx&Ry |
zf |
|
B |
1011 |
xxxx |
yyyy |
zzzz |
OR X, Y, Z |
Rz=Rx|Ry |
zf |
|
C |
1100 |
xxxx |
dddd |
dddd |
ADD X, #DD |
Rx=Rx+dd |
zf, cf |
|
D |
1101 |
xxxx |
dddd |
dddd |
SUB X, #DD |
Rx=Rx-dd |
zf, cf |
|
E |
1110 |
xxxx |
dddd |
dddd |
AND X, #DD |
Rx=Rx&dd |
zf |
|
F |
1111 |
xxxx |
dddd |
dddd |
OR X, #DD |
Rx=Rx|dd |
zf |
