300 likes | 424 Views
EHRs : Designing modules with concurrent methods Arvind Computer Science & Artificial Intelligence Lab. Massachusetts Institute of Technology. f1. f2. f3. Elastic pipeline. x. inQ. fifo1. fifo2. outQ.
E N D
EHRs: Designing modules with concurrent methods Arvind Computer Science & Artificial Intelligence Lab. Massachusetts Institute of Technology http://csg.csail.mit.edu/6.375
f1 f2 f3 Elastic pipeline x inQ fifo1 fifo2 outQ Whether these rules can fire concurrently depends crucially on the properties of fifo methods rule stage1 if (True); fifo1.enq(f1(inQ.first()); inQ.deq(); endrule rule stage2 if (True); fifo2.enq(f2(fifo1.first()); fifo1.deq(); endrule rule stage3 if (True); outQ.enq(f3(fifo2.first()); fifo2.deq(); endrule http://csg.csail.mit.edu/6.375
Designing FIFOs http://csg.csail.mit.edu/6.375
n enab enq rdy not full enab Fifo module rdy deq not empty One-Element FIFO modulemkCFFifo(Fifo#(1, t)); Reg#(t) data <- mkRegU; Reg#(Bool) full <- mkReg(False); method Action enq(t x) if (!full); full <= True; data <= x; endmethod method Action deqif (full); full <= False; endmethod method t first if (full); return (data); endmethod endmodule Can enq and deqexecute concurrently enq and deq cannot even be enabled together much less fire concurrently! http://csg.csail.mit.edu/6.375
Two-Element FIFO modulemkCFFifo(Fifo#(2, t)); Reg#(t) da <- mkRegU(); Reg#(Bool) va<- mkReg(False); Reg#(t) db<- mkRegU(); Reg#(Bool) vb<- mkReg(False); method Action enq(t x) if (!vb); ifvathen begin db<= x; vb<= True; end else begin da <= x; va<= True; end endmethod method Action deqif (va); ifvbthen begin da <= db; vb<= False; end else begin va<= False; end endmethod method t first if (va); returnda; endmethod endmodule db da Assume, if there is only one element in the FIFO it resides in da Canenqand deqbe ready concurrently? yes Do enq and deq conflict? yes, both read/write the same elements http://csg.csail.mit.edu/6.375
BSV model needs to be extended to express Fifos with concurrent methods EHR: Ephemeral History Registers http://csg.csail.mit.edu/6.375
w[0].data w[0].en 0 1 EHR: Register with a bypass Interface r[0] < w[0] w[0] < r[1] D Q normal r[0] r[1] bypass r[1] – if write is not enabled itreturns the current state and if write is enabled it returns the value being written http://csg.csail.mit.edu/6.375
w[1].data w[0].data w[1].en w[0].en 0 0 D Q 1 1 Ephemeral History Register (EHR) Dan Rosenband [MEMOCODE’04] r[0] < w[0] r[1] < w[1] w[0] < w[1] < …. r[0] r[1] w[i+1] takes precedence over w[i] http://csg.csail.mit.edu/6.375
Designing FIFOs using EHRs http://csg.csail.mit.edu/6.375
One-Element Pipelined FIFO modulemkPipelineFifo(Fifo#(1, t)) provisos(Bits#(t, tSz)); Reg#(t) data <- mkRegU; Ehr#(2, Bool) full <- mkEhr(False); methodActionenq(t x) if(!full[1]); data <= x; full[1] <= True; endmethod methodActiondeqif(full[0]); full[0] <= False; endmethod method t first if(full[0]); return data; endmethod endmodule One can enq into a full Fifo provided someone is trying to deqfrom it simultaneously. first < enq deq < enq first < deq enq and deq calls can be from the same rule or different rules. http://csg.csail.mit.edu/6.375
One-Element Bypass FIFOusing EHRs modulemkBypassFifo(Fifo#(1, t)) provisos(Bits#(t, tSz)); Ehr#(2, t) data <- mkEhr(?); Ehr#(2, Bool) full <- mkEhr(False); methodAction enq(t x) if(!full[0]); data[0] <= x; full[0] <= True; endmethod methodActiondeqif(full[1]); full[1] <= False; endmethod method t first if(full[1]); returndata[1]; endmethod endmodule One can deq from an empty Fifo provided someone is trying to enq into it simultaneously. enq < first enq < deq first < deq enq and deq calls can be from the same rule or different rules http://csg.csail.mit.edu/6.375
Two-Element Conflict-free FIFO modulemkCFFifo(Fifo#(2, t)) provisos(Bits#(t, tSz)); Ehr#(2, t) da <- mkEhr(?); Ehr#(2, Bool) va <- mkEhr(False); Ehr#(2, t) db <- mkEhr(?); Ehr#(2, Bool) vb <- mkEhr(False); rulecanonicalizeif(vb[1] && !va[1]); da[1] <= db[1]; va[1] <= True; vb[1] <= False; endrule methodActionenq(t x) if(!vb[0]); db[0] <= x; vb[0] <= True; endmethod methodActiondeqif (va[0]); va[0] <= False; endmethod method t first if(va[0]); returnda[0]; endmethod endmodule db da Assume, if there is only one element in the FIFO it resides in da first CF enq deq CF enq first < deq enq and deq, even if performed simultaneously, can’t see each other’s effects until the next cycle http://csg.csail.mit.edu/6.375
Scheduling constraints due to multiple modules bToa Can ra and rb be scheduled concurrently? rb ra y x aTob rule ra; aTob.enq(fa(x)); if (bToa.nonEmpty) begin x <= ga(bToa.first); bToa.deq; end endrule rule rb; y <= gb(aTob.first); aTob.deq; bToa.enq(fb(y)); endrule fifos are initially empty aTobbToa Concurrent fifofifo scheduling? CF CF CF pipeline CF bypass pipeline CF pipeline pipeline pipeline bypass bypass CF bypass pipeline bypass bypass x x http://csg.csail.mit.edu/6.375
N-element Conflict-free FIFO temp storage to hold values until canonicalization locks for preventing accesses until canonicalization • an enq updates enqP and puts the old value of enqP and enq data into oldEnqP and newData, respectively. It also sets enqEn to false to prevent further enqueues • a deq updates deqPand sets deqEnto false to prevent further dequeues • Canonicalize rule calculates the new count and puts the new data into the array and sets the enqEn and deqEn bits appropriately oldEnqP enqEn deqEn enqP deqP newData http://csg.csail.mit.edu/6.375
Pointer comparison • enqP and deqP can contain indices for upto twice the size of the FIFO, to distinguish between full and empty conditions • Full: enqP == deqP + FIFO_size • Empty: enqP == deqP http://csg.csail.mit.edu/6.375
N-element Conflict-free FIFO modulemkCFFifo(Fifo#(n, t)) provisos(Bits#(t, tSz), Add#(n, 1, n1), Log#(n1, sz), Add#(sz, 1, sz1)); Integer ni = valueOf(n); Bit#(sz1) nb = fromInteger(ni); Bit#(sz1) n2 = 2*nb; Vector#(n, Reg#(t)) data <- replicateM(mkRegU); Ehr#(2, Bit#(sz1)) enqP <- mkEhr(0); Ehr#(2, Bit#(sz1)) deqP <- mkEhr(0); Ehr#(2, Bool) enqEn <- mkEhr(True); Ehr#(2, Bool) deqEn <- mkEhr(False); Ehr#(2, t) newData <- mkEhr(?); Ehr#(2, Maybe#(Bit#(sz1))) oldEnqP<- mkEhr(Invalid); http://csg.csail.mit.edu/6.375
N-element Conflict-free FIFO continued-1 rulecanonicalize; Bit#(sz1) cnt = enqP[1] >= deqP[1]? enqP[1] - deqP[1]: (enqP[1]%nb + nb) - deqP[1]%nb; if(!enqEn[1] && cnt != nb) enqEn[1] <= True; if(!deqEn[1] && cnt != 0) deqEn[1] <= True; if(isValid(oldEnqP[1])) begin data[validValue(oldEnqP[1])] <= newData[1]; oldEnqP[1] <= Invalid; end endrule http://csg.csail.mit.edu/6.375
N-element Conflict-free FIFO continued-2 methodActionenq(t x) if(enqEn[0]); newData[0] <= x; oldEnqP[0] <= Valid (enqP[0]%nb); enqP[0] <= (enqP[0] + 1)%n2; enqEn[0] <= False; endmethod method Actiondeqif(deqEn[0]); deqP[0] <= (deqP[0] + 1)%n2; deqEn[0] <= False; endmethod method t first if(deqEn[0]); return data[deqP[0]%nb]; endmethod endmodule http://csg.csail.mit.edu/6.375
Register File:normal and bypass • Normal rf: {rd1, rd2} < wr; the effect of a register update can only be seen a cycle later, consequently, reads and writes are conflict-free • Bypass rf: wr < {rd1, rd2}; in case of concurrent reads and write, check if rd1==wr or rd2==wr then pass the new value as the result and update the register file, otherwise the old value in the rf is read http://csg.csail.mit.edu/6.375
Normal Register File modulemkRFile(RFile); Vector#(32,Reg#(Data)) rfile <- replicateM(mkReg(0)); method Action wr(Rindxrindx, Data data); if(rindx!=0) rfile[rindx] <= data; endmethod method Data rd1(Rindxrindx) = rfile[rindx]; method Data rd2(Rindxrindx) = rfile[rindx]; endmodule {rd1, rd2} < wr http://csg.csail.mit.edu/6.375
Bypass Register File using EHR modulemkBypassRFile(RFile); Vector#(32,EHR#(2, Data)) rfile <- replicateM(mkEHR(0)); method Action wr(Rindxrindx, Data data); if(rindex!==0) rfile[rindex][0] <= data; endmethod method Data rd1(Rindxrindx) = rfile[rindx][1]; method Data rd2(Rindxrindx) = rfile[rindx][1]; endmodule wr < {rd1, rd2} http://csg.csail.mit.edu/6.375
Bypass Register Filewith external bypassing modulemkBypassRFile(BypassRFile); RFilerf <- mkRFile; Fifo#(1, Tuple2#(RIndx, Data)) bypass <- mkBypassSFifo; rule move; beginrf.wr(bypass.first); bypass.deqend; endrule method Action wr(RIndxrindx, Data data); if(rindex!==0) bypass.enq(tuple2(rindx, data)); endmethod method Data rd1(RIndxrindx) = return (!bypass.search1(rindx)) ? rf.rd1(rindx) : bypass.read1(rindx); methodData rd2(RIndxrindx) = return (!bypass.search2(rindx)) ? rf.rd2(rindx) : bypass.read2(rindx); endmodule {rf.rd1, rf.rd2} < rf.wr wr < {rd1, rd2} http://csg.csail.mit.edu/6.375
Extras may be good for a lab exercise http://csg.csail.mit.edu/6.375
N-element searchable FIFO search CF {deq, enq} Need a oldDeqP also to avoid scheduling constraints between deq and Search modulemkCFSFifo#(function BoolisFound(t v, st k))(SFifo#(n, t, st)) provisos(Bits#(t, tSz), Add#(n, 1, n1), Log#(n1, sz), Add#(sz, 1, sz1)); Integer ni = valueOf(n); Bit#(sz1) nb = fromInteger(ni); Bit#(sz1) n2 = 2*nb; Vector#(n, Reg#(t)) data <- replicateM(mkRegU); Ehr#(2, Bit#(sz1)) enqP <- mkEhr(0); Ehr#(2, Bit#(sz1)) deqP <- mkEhr(0); Ehr#(2, Bool) enqEn <- mkEhr(True); Ehr#(2, Bool) deqEn <- mkEhr(False); Ehr#(2, t) newData <- mkEhr(?); Ehr#(2, Maybe#(Bit#(sz1))) oldEnqP<- mkEhr(Invalid); Ehr#(2, Maybe#(Bit#(sz1))) oldDeqP<- mkEhr(Invalid); http://csg.csail.mit.edu/6.375
N-element searchable FIFO search CF {deq, enq} continued-1 Bit#(sz1) cnt0 = enqP[0] >= deqP[0]? enqP[0] - deqP[0]: (enqP[0]%nb + nb) - deqP[0]%nb; Bit#(sz1) cnt1 = enqP[1] >= deqP[1]? enqP[1] - deqP[1]: (enqP[1]%nb + nb) - deqP[1]%nb; rulecanonicalize; if(!enqEn[1] && cnt2 != nb) enqEn[1] <= True; if(!deqEn[1] && cnt2 != 0) deqEn[1] <= True; if(isValid(oldEnqP[1])) begin data[validValue(oldEnqP[1])] <= newData[1]; oldEnqP[1] <= Invalid; end if(isValid(oldDeqP[1])) begin deqP[0] <= validValue(oldDeqP[1]); oldDeqP[1]<=Invalid; end endrule http://csg.csail.mit.edu/6.375
N-element searchable FIFO search CF {deq, enq} continued-2 methodActionenq(t x) if(enqEn[0]); newData[0] <= x; oldEnqP[0] <= Valid (enqP[0]%nb); enqP[0] <= (enqP[0] + 1)%n2; enqEn[0] <= False; endmethod method Action deqif(deqEn[0]); oldDeqP[0] <= Valid ((deqP[0] + 1)%n2); deqEn[0] <= False; endmethod methodt first if(deqEn[0]); return data[deqP[0]%nb]; endmethod http://csg.csail.mit.edu/6.375
N-element searchable FIFO search CF {deq, enq} continued-3 methodBool search(st s); Bool ret = False; for(Bit#(sz1) i = 0; i < nb; i = i + 1) begin letptr = (deqP[0] + i)%nb; if(isFound(data[ptr], s) && i < cnt0) ret = True; end return ret; endmethod endmodule http://csg.csail.mit.edu/6.375
N-element searchable FIFO deq < search, deq < enq This will make a good lab assignment modulemkPipelineSFifo#(function BoolisFound(t v, st k))(SFifo#(n, t, st)) provisos(Bits#(t, tSz), Add#(n, 1, n1), Log#(n1, sz), Add#(sz, 1, sz1), Bits#(st, stz)); Integer ni = valueOf(n); Bit#(sz1) nb = fromInteger(ni); Bit#(sz1) n2 = 2*nb; Vector#(n, Reg#(t)) data <- replicateM(mkRegU); Ehr#(2, Bit#(sz1)) enqP <- mkEhr(0); Ehr#(2, Bit#(sz1)) deqP <- mkEhr(0); http://csg.csail.mit.edu/6.375
N-element searchable FIFO deq < search, deq < enq Bit#(sz1) cnt0 = enqP[0] >= deqP[0]? enqP[0] - deqP[0]: (enqP[0]%nb + nb) - deqP[0]%nb; Bit#(sz1) cnt1 = enqP[0] >= deqP[1]? enqP[0] - deqP[1]: (enqP[0]%nb + nb) - deqP[1]%nb; method Actionenq(t x) if(cnt1 < nb); enqP[0] <= (enqP[0] + 1)%n2; data[enqP[0]%nb] <= x; endmethod method Actiondeqif(cnt0 != 0); deqP[0] <= (deqP[0] + 1)%n2; endmethod method t first if(cnt0 != 0); return data[deqP[0]%nb]; endmethod http://csg.csail.mit.edu/6.375
N-element searchable FIFO deq < search, deq < enq methodBool search(st s); Bool ret = False; for(Bit#(sz1) i = 0; i < nb; i = i + 1) begin letptr = (deqP[1] + i)%nb; if(isFound(data[ptr], s) && i < cnt1) ret = True; end return ret; endmethod endmodule http://csg.csail.mit.edu/6.375