Presentation is loading. Please wait.

Presentation is loading. Please wait.

Modular Refinement - 2 Arvind

Similar presentations


Presentation on theme: "Modular Refinement - 2 Arvind"— Presentation transcript:

1 Modular Refinement - 2 Arvind
Computer Science & Artificial Intelligence Lab Massachusetts Institute of Technology February 25, 2009

2 Successive refinement & Modular Structure
fetch execute iMem rf CPU decode memory pc write- back dMem fetch & decode execute pc rf CPU bu Can we derive the 5-stage pipeline by successive refinement of a 2-stage pipeline? February 25, 2009

3 A Modular organization
CPU iMem RFile rf FIFO bu dMem modules call each other (recursive) execute WB fetch & decode setPc pc stall enqIt Suppose we include rf and pc in Fetch and bu in Execute Fetch delivers decoded instructions to Execute and needs to consult Execute for the stall condition Execute writes back data in rf and supplies the pc value in case of a branch misprediction February 25, 2009

4 Recursive modular organization
module mkCPU2#(Mem iMem, Mem dMem)(); Execute execute <- mkExecute(dMem, fetch); Fetch fetch <- mkFetch(iMem, execute); endmodule interface Fetch; method Action setPC (Iaddress cpc); method Action writeback (RName dst, Value v); endinterface interface Execute; method Action enqIt(InstTemplate it); method Bool stall(Instr instr) recursive calls This first method describe what happens in the fetch of this pipeline. This methods says that given any processor term, we can always rewrite it to a new term wehre, and we enqueue the current instuction into bf. And at the same time the pc field is incremende by one It may look like this method can fire forever, but because bf is bounded, when a method enqueue into bf, there is an implied predicate that say bf must not be full. Unfortunately, recursive module syntax is not as simple February 25, 2009 8 8 6 8

5 Fetch Module module mkFetch#(IMem iMem, Execute execute) (Fetch);
Instr instr = iMem.read(pc); Iaddress predIa = pc + 1; Reg#(Iaddress) pc <- mkReg(0); RegFile#(RName, Bit#(32)) rf <- mkBypassRegFile(); rule fetch_and_decode (!execute.stall(instr)); execute.enqIt(newIt(instr,rf)); pc <= predIa; endrule method Action writeback(RName rd, Value v); rf.upd(rd,v); endmethod method Action setPC(Iaddress newPC); pc <= newPC; endmodule February 25, 2009

6 Execute Module module mkExecute#(DMem dMem, Fetch fetch) (Execute);
SFIFO#(InstTemplate) bu <- mkSLoopyFifo(findf); InstTemplate it = bu.first; rule execute … method Action enqIt(InstTemplate it); bu.enq(it); endmethod method Bool stall(Instr instr); return (stallFunc(instr, bu)); endmodule February 25, 2009

7 Execute Module Rule rule execute (True); case (it) matches tagged EAdd{dst:.rd,src1:.va,src2:.vb}: begin fetch.writeback(rd, va+vb); bu.deq(); end tagged EBz {cond:.cv,addr:.av}: if (cv == 0) then begin fetch.setPC(av); bu.clear(); end else bu.deq(); tagged ELoad{dst:.rd,addr:.av}: begin fetch.writeback(rd, dMem.read(av)); bu.deq(); end tagged EStore{value:.vv,addr:.av}: begin dMem.write(av, vv); bu.deq(); endcase endrule February 25, 2009

8 Fetch Module Refinement Separating Fetch and Decode
module mkFetch#(IMem iMem, Execute execute) (Fetch); FIFO#(Instr) buD <- mkLoopyFIFO(); Instr instr = iMem.read(pc); Iaddress predIa = pc + 1; rule fetch(True); pc <= predIa; buD.enq(instr); endrule rule decode(!execute.stall(buD.first())); execute.enqIt(newIt(buD.first(),rf)); buD.deq(); method Action writeback(RName rd, Value v); rf.upd(rd,v); endmethod method Action setPC(Iaddress newPC); pc <= newPC; buD.clear(); endmodule February 25, 2009

9 Execute Module Refinement
module mkExecute#(DMem dMem, Fetch fetch) (Execute); SFIFO#(InstTemplate) bu <- mkSLoopyFifo(findf); InstTemplate it = bu.first; rule execute … method Action enqIt(InstTemplate it); bu.enq(it); endmethod method Bool stall(Instr instr); return (stallFunc(instr, bu)); endmodule Introduce two more queues and break this rule into execute, memory operation and commit rules February 25, 2009

10 Execute Module Refinement
module mkExecute#(DMem dMem, Fetch fetch) (Execute); SFIFO#(InstTemplate) buE <- mkSLoopyFifo(findfE); SFIFO#(InstTemplateM) buM <- mkSLoopyFIFO(findfM); SFIFO#(InstTemplateC) buC <- mkSLoopyFIFO(findfC); rule execute … rule memory … rule commit … method Action enqIt(InstTemplate it); buE.enq(it); endmethod method Bool stall(Instr instr); return(stallFuncE(instr, buE) && stallFuncM(instr, buM) && stallFuncC(instr, buC)); endmodule February 25, 2009

11 New Types for Instruction Templates
typedef union tagged { struct {RName dst; Value val;} MWB; void MNop; struct {RName dst; IAddress addr;} MLoad; struct {IAddress addr; Value val} MStore; } InstTemplateM deriving(Bits, Eq); struct {RName dst; Value val;} CWB; void CNop; InstTemplateC deriving(Bits, Eq); February 25, 2009

12 The New Execute Rule Does not do mem-ops and writebacks
rule execute(True); case (buE.first()) matches tagged EAdd{dst:.rd,src1:.va,src2:.vb}: begin buM.enq(tagged MWB{dst:rd, val:va+vb}); buE.deq();end tagged EBz {cond:0,addr:.av}: begin fetch.setPC(av); buE.clear(); buM.enq(tagged MNop{});end tagged EBz {cond:.cv,addr:.av}: begin buM.enq(tagged MNop{}); buE.deq(); end tagged ELoad{dst:.rd,addr:.av}: begin buM.enq(tagged MLoad{dst:rd,addr:av}); tagged EStore{value:.vv,addr:.av}: begin buM.enq(tagged MStore{addr:av,val:vv}); endcase endrule February 25, 2009

13 The Memory Rule rule memory(True); case (buM.first()) matches
tagged MWB{dst:.rd,val:.v}: begin buC.enq(tagged CWB{dst:rd, val:v}); buM.deq(); end tagged MNop {}: begin buC.enq(tagged CNop); tagged MLoad{dst:.rd,addr:.av}: begin buC.enq(tagged CWB{dst:rd, val:dMem.read(av)}); buM.deq();end tagged MStore{addr:.av, val:vv}}: begin buC.enq(tagged CNop{}); dMem.write(av,vv); buM.deq();end endcase endrule February 25, 2009

14 The Commit Rule rule commit(True); case (buC.first()) matches
tagged CWB{dst:.rd,val:.v}: fetch.writeback(rd,v); tagged CNop {}: noAction; endcase buC.deq(); endrule February 25, 2009

15 Stall Functions Same as before, save variation in types in Queue.
February 25, 2009

16 Synchronous Refinements
pc rf fetch decode execute memory write- back iMem dMem CPU Realistic processor Pipelines often have synchronous pieces connected asynchronously, i.e., using FIFOs February 25, 2009

17 Sync. Execute Module module mkExecute#(DMem dMem, Fetch fetch) (Execute); SFIFO#(InstTemplate) buE <- mkSLoopyFifo(findf); Reg#(Maybe#(InstTemplateM) buRegM <- mkReg(Invalid); Reg#(Maybe#(InstTemplateC) buRegC <- mkReg(Invalid); rule executePipe … method Action enqIt(InstTemplate it); buE.enq(it); endmethod method Bool stall(Instr instr); return(stallFuncE(instr, buE) && stallFuncM(instr, buRegM) && stallFuncC(instr, buRegC)); endmodule February 25, 2009

18 Sync. Execute Pipeline From Lecture 5
rule sync-pipeline (True); if (inQ.notEmpty()) begin sReg1 <= Valid f1(inQ.first()); inQ.deq(); end else sReg1 <= Invalid; case (sReg1) matches tagged Valid .sx1: sReg2 <= Valid f2(sx1); tagged Invalid: sReg2 <= Invalid; endcase case (sReg2) matches tagged Valid .sx2: outQ.enq(f3(sx2)); endcase endrule Use the following Mapping: inQ -> buE sReg1 -> buRegM sReg2 -> buRegC outQ.enq -> fetch.writeback February 25, 2009

19 Sync. Execute Pipeline rule executePipe (True); if (buE.notEmpty()) begin buRegM <= Valid f1(buE.first()); buE.deq(); end else buRegM <= Invalid; case (buRegM) matches tagged Valid .sx1: buRegC <= Valid f2(sx1); tagged Invalid: buRegC <= Invalid; endcase case (buRegC) matches tagged Valid .sx2: fetch.writeback(f3(sx2)); endcase endrule Exec Action Mem Action Commit Action In Processor pipelines, the stage functions require additional side effects (actions) e.g. setPC/dMem.write/etc. For clarity, we will show these actions one by one February 25, 2009

20 Execute Action “Extra effects” if (buE.notEmpty())
begin buRegM <= Valid f1(buE.first()); buE.deq(); end else buRegM <= Invalid; case (buE.first()) matches tagged EAdd{dst:.rd,src1:.va,src2:.vb}: begin buRegM <= Valid MWB{dst:rd, val:va+vb}; buE.deq();end tagged EBz {cond:0,addr:.av}: begin fetch.setPC(av); buE.clear(); buRegM <= Valid MNop{};end tagged EBz {cond:.cv,addr:.av}: begin buRegM <= Valid MNop{}; buE.deq(); end tagged ELoad{dst:.rd,addr:.av}: begin buRegM <= Valid MLoad{dst:rd,addr:av}; buE.deq();end tagged EStore{value:.vv,addr:.av}: begin buRegM <= Valid MStore{addr:av,val:vv}; buE.deq();end endcase “Extra effects” February 25, 2009

21 Memory Action case (itM) matches tagged MWB{dst:.rd,val:.v}:
case (buRegM) matches tagged Valid .itM: buRegC <= Valid f2(itM); tagged Invalid: buRegC <= Invalid; case (itM) matches tagged MWB{dst:.rd,val:.v}: buRegC <= tagged CWB{dst:rd, val:v}; tagged MNop {}: buRegC <= tagged CNop {}; tagged MLoad{dst:.rd,addr:.av}: buRegC <= tagged CWB{dst:rd, val:dMem.read(av)}; tagged MStore{addr:.av, val:vv}}: begin buRegC <= tagged CNop{}; dMem.write(av,vv);end endcase “Extra effects” February 25, 2009

22 Commit Action case (itC) matches tagged CWB{dst:.rd,val:.v}:
case (buRegC) matches tagged Valid .itC: fetch.writeback(f3(itC)); endcase case (itC) matches tagged CWB{dst:.rd,val:.v}: fetch.writeback(rd,v); tagged CNop {}: noAction; endcase February 25, 2009

23 Sync. Execute Pipeline Execute Action; Memory Action; Commit Action;
rule executePipe (True); if (buE.notEmpty()) begin buRegM <= Valid f1(buE.first()); buE.deq(); end else buRegM <= Invalid; case (buRegM) matches tagged Valid .sx1: buRegC <= Valid f2(sx1); tagged Invalid: buRegC <= Invalid; endcase case (buRegC) matches tagged Valid .sx2: fetch.writeback(f3(sx2)); endcase endrule Execute Action; Memory Action; Commit Action; yes February 25, 2009

24 Refining the Memory Subsystem
Non-combinational memory reads February 25, 2009

25 Realistic memory systems
No combinational reads: The request to read the memory is a different event from the event when the response comes back The response to the request should be treated as an asynchronous event because its time can vary (cache misses) Request and response events or actions have to be dealt in different rules iMem.read(pc) or dMem.read(addr) are no longer read methods – rules using them have to be split up February 25, 2009

26 Request-Response Interface for Synchronous Memory
Data Ack Ready req deq peek Addr Ready ctr (ctr > 0) ctr++ ctr-- deq Enable enq Synch Mem Latency N interface Mem#(type addrT, type dataT); method Action req(addrT x); method Action deq(); method dataT peek(); endinterface Making a synchronous component latency- insensitive February 25, 2009

27 Request-Response Memory Interface
interface Mem#(type addrT, type dataT); method Action req(MemReq#(addrT,dataT) x); method Action deq(); method dataT peek(); endinterface typedef union tagged { struct {addrT addr; dataT val;} Write; struct {addrT addr;} Read; } MemReq#(type addrT, type dataT) deriving(Bits, Eq); We will assume that the memory processes read and write requests in the order received February 25, 2009

28 Non-combinational reads
dMem.read(a) execute write-back dMem execute dMem.req(a) dMem.peek/deq write-back dMem execute dMem.req(a) write-back dMem.peek/deq dMem February 25, 2009

29 The Modified Execute Rule
rule execute(True); case (buE.first()) matches tagged EAdd{dst:.rd,src1:.va,src2:.vb}: begin buC.enq(tagged CWB{dst:rd, val:va+vb}); buE.deq();end tagged EBz {cond:0,addr:.av}: begin fetch.setPC(av); buE.clear(); buC.enq(tagged CNop{});end tagged EBz {cond:.cv,addr:.av}: begin buC.enq(tagged CNop{}); buE.deq(); end tagged ELoad{dst:.rd,addr:.av}: begin buC.enq(tagged CLoad{dst:rd}); dMem.req(Read{addr:av}); tagged EStore{value:.vv,addr:.av}: dMem.req(Write{addr:av, val:vv}); endcase endrule February 25, 2009

30 The modified Commit Rule
rule commit(True); case (buC.first()) matches tagged CWB{dst:.rd,val:.v}: fetch.writeback(rd,v); tagged CNop {}: noAction; tagged CLoad{dst:.rd}: begin fetch.writeback(rd,dMem.peek()); dMem.deq(); end endcase buC.deq(); endrule February 25, 2009

31 Fetch Module Are any changes needed in the methods?
module mkFetch#(IMem iMem, Execute execute) (Fetch); FIFO#(void) buD <- mkLoopyFIFO(); Instr instr = iMem.peek(); Iaddress predIa = pc + 1; rule fetch(True); pc <= predIa; iMem.req(Read{addr:pc}); buD.enq(void); endrule rule decode (!execute.stall(instr)); execute.enqIt(newIt(instr,rf)); iMem.deq(); buD.deq(); method Action setPC … method Action writeback … endmodule Are any changes needed in the methods? February 25, 2009

32 Fetch Module Refinement
module mkFetch#(IMem iMem, Execute execute) (Fetch); FIFO#(void) buD <- mkFIFO(); Iaddress predIa = pc + 1; method Action writeback(RName rd, Value v); rf.upd(rd,v); endmethod method Action setPC(Iaddress newPC); pc <= newPC; buD.clear(); endmodule Does this work? Must kill or drain the instruction fetches already in progress February 25, 2009

33 Fetch Module module mkFetch#(IMem iMem, Execute execute) (Fetch)
Reg#(Bool) drainingIMem <- mkReg(False); … rule fetch(!drainingIMem); pc <= predIa; iMem.req(Read{addr:pc}); buD.enq(void); endrule rule decode(!drainingIMem && !execute.stall(instr)); iMem.deq(); buD.deq(); execute.enqIt(newIt(instr,rf)); rule drain(drainingIMem); if(buD.notEmpty)begin iMem.deq(); buD.deq(); end else drainingIMem <= False; method Action setPC(Iaddress newPC); pc <= newPC; drainingIMem <= buD.notEmpty(); endmethod method Action writeback … endmodule February 25, 2009

34 Power of Modular Refinement
Any Fetch-Decode module refinements we’ve shown, will work with each of the Execute module refinements we’ve shown Some refinements require interface changes (e.g. magic memory vs. realistic memory) The Correctness of refinements often depends on extra-linguistic properties (architectural reasoning) It should be easy to add caches to new memory abstraction February 25, 2009


Download ppt "Modular Refinement - 2 Arvind"

Similar presentations


Ads by Google