A RISC Processor實驗

 

 

這是一個精簡指令集 (Reduced Instruction Set Computer) 的微處理器, 並利用FPGA內的RAM作為微處理器的程式記憶體; 程式 (機械碼) 則寫在Prog1.v

 

本實驗包含HDL : riscpu.v和memory file : Prog1.v

 

Source

 

1. 建立FPGA的Project : riscpu.

 

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)

 

 

 

 

 

 

1. The simple RISC processor consititues of three parts: I.Decoder and Control Pipleline II.ALU Main Data Path III. Program Control Unit shown in the above figures.

 

2. The instruction set is as follows:

 

 

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

 

3. Only the instructions with OP=8~F will write the ALU results back to the register file. Instructions with OP=8~B(pdy[14]=0) write to Rz(pdy[3:0]); instructions with OP=C~F(pdy[14]=1) write to Rx(pdy[11:8]). The mux of the write address ws[3:0] controls this selection.

 

4. OP=1~7 are branch instructions. OP=1 is the RET instruction with PC loaded from the stack content. Unconductional branch instructions (OP=2~3) add the PC value with the signed offset of ddd in the opcode. Condictional branch instructions (OP=4~7) will add the PC value with the signed offset of ddd when conduction is true, and, like all the other non-branch instructions, will advance the PC=PC+1 when condiction is false.

 

5. Because of the pipeline nature of the processor, when branch is taken, the branch instruction is in its third stage, and the PC value has already advanced for two cycles, the correct target address of the branch instruction is PC=PC+2+ddd.

 

6. When branch is taken, the pcadmx is always asserted. That is, when the pcadmx is true, or its pipeline signal pcadmxx is true, a branch has occurred. And the following instructions should be annulled ( flushed ).

 

 

 

 

文章標籤
全站熱搜
創作者介紹
創作者 zeppe 的頭像
zeppe

ZEPPE

zeppe 發表在 痞客邦 留言(0) 人氣(302)