From c31c456f939434cfc9ede70b34d148f6a4153e7e Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Sun, 13 Mar 2022 19:38:54 -0400 Subject: [PATCH 01/38] basics --- bscRuntime/memories/Locks.bsv | 96 +++--- bscRuntime/memories/Memories.bsv | 318 +++++++++--------- except-new.pdl | 47 +++ except.pdl | 45 +++ insns.hex | 4 + src/main/scala/pipedsl/Main.scala | 5 +- src/main/scala/pipedsl/Parser.scala | 23 +- .../scala/pipedsl/common/PrettyPrinter.scala | 19 ++ src/main/scala/pipedsl/common/Syntax.scala | 30 +- .../pipedsl/passes/ExceptingToNormal.scala | 18 + src/test/tests/histogram/histogram_nested.sim | 0 11 files changed, 398 insertions(+), 207 deletions(-) create mode 100644 except-new.pdl create mode 100644 except.pdl create mode 100644 insns.hex create mode 100644 src/main/scala/pipedsl/passes/ExceptingToNormal.scala delete mode 100644 src/test/tests/histogram/histogram_nested.sim diff --git a/bscRuntime/memories/Locks.bsv b/bscRuntime/memories/Locks.bsv index 2832991b..41d8f6e8 100644 --- a/bscRuntime/memories/Locks.bsv +++ b/bscRuntime/memories/Locks.bsv @@ -21,6 +21,7 @@ interface QueueLock#(type id); method ActionValue#(id) res1(); method Bool owns1(id i); method Action rel1(id i); + method Action abort1(id i); method Bool isEmpty(); method Bool canRes1(); endinterface @@ -47,25 +48,25 @@ module mkQueueLock(QueueLock#(LockId#(d))); Reg#(LockId#(d)) nextId <- mkReg(0); FIFOF#(LockId#(d)) held <- mkSizedFIFOF(valueOf(d)); - + Reg#(LockId#(d)) cnt <- mkReg(0); - + Bool lockFree = !held.notEmpty; LockId#(d) owner = held.first; method Bool isEmpty(); return lockFree; endmethod - + method Bool canRes1(); return held.notFull; endmethod - + //Returns True if thread `tid` already owns the lock method Bool owns1(LockId#(d) tid); return owner == tid; endmethod - + //Releases the lock iff thread `tid` owns it already method Action rel1(LockId#(d) tid); if (owner == tid) @@ -73,7 +74,15 @@ module mkQueueLock(QueueLock#(LockId#(d))); held.deq(); end endmethod - + + //Clears everything after `tid` when `tid` comes to the head + method Action abort1(LockId#(d) tid); + if (owner == tid) + begin + held.clear(); + end + endmethod + //Reserves the lock and returns the associated id method ActionValue#(LockId#(d)) res1(); held.enq(nextId); @@ -81,12 +90,12 @@ module mkQueueLock(QueueLock#(LockId#(d))); cnt <= cnt + 1; return nextId; endmethod - + endmodule module mkCountingLock(QueueLock#(LockId#(d))); - Ehr#(2, LockId#(d)) nextId <- mkEhr(0); + Ehr#(2, LockId#(d)) nextId <- mkEhr(0); Reg#(LockId#(d)) owner <- mkReg(0); Reg#(Bool) empty <- mkReg(True); @@ -94,7 +103,8 @@ module mkCountingLock(QueueLock#(LockId#(d))); RWire#(Bool) doRes <- mkRWire(); RWire#(LockId#(d)) doRel <- mkRWire(); - + //i think i need to add a doAbrt wire here + (*fire_when_enabled*) rule updateEmpty; let res = fromMaybe(False, doRes.wget()); @@ -108,29 +118,35 @@ module mkCountingLock(QueueLock#(LockId#(d))); method Bool isEmpty(); return empty; endmethod - + method Bool canRes1(); return !full; endmethod - + //Returns True if thread `tid` already owns the lock method Bool owns1(LockId#(d) tid); return owner == tid; endmethod - + //Releases the lock method Action rel1(LockId#(d) tid); owner <= owner + 1; doRel.wset(owner + 1); endmethod - + + method Action abort1(LockId#(d) tid); + nextId[0] <= 0; + owner <= 0; + empty <= True; + endmethod + //Reserves the lock and returns the associated id method ActionValue#(LockId#(d)) res1(); nextId[0] <= nextId[0] + 1; doRes.wset(True); return nextId[0]; endmethod - + endmodule module mkCheckpointQueueLock(CheckpointQueueLock#(LockId#(d), LockId#(d))); @@ -138,10 +154,10 @@ module mkCheckpointQueueLock(CheckpointQueueLock#(LockId#(d), LockId#(d))); Ehr#(2, LockId#(d)) nextId <- mkEhr(0); Reg#(LockId#(d)) owner <- mkReg(0); Reg#(Bool) empty <- mkReg(True); - + RWire#(Bool) doRes <- mkRWire(); RWire#(LockId#(d)) doRel <- mkRWire(); - + //for when you're doing not rollback (*fire_when_enabled*) rule updateEmpty; @@ -149,38 +165,38 @@ module mkCheckpointQueueLock(CheckpointQueueLock#(LockId#(d), LockId#(d))); if (res &&& doRel.wget() matches tagged Invalid) empty <= False; if (!res &&& doRel.wget() matches tagged Valid.nextOwner) empty <= nextOwner == nextId[1]; endrule - + method Bool isEmpty(); return empty; endmethod - + method Bool canRes1(); return empty || nextId[0] != owner; endmethod - + //Returns True if thread `tid` already owns the lock method Bool owns1(LockId#(d) tid); return owner == tid; endmethod - + //Releases the lock, assume `tid` owns it method Action rel1(LockId#(d) tid); owner <= owner + 1; //assign next owner doRel.wset(owner + 1); endmethod - + //Reserves the lock and returns the associated id method ActionValue#(LockId#(d)) res1(); nextId[0] <= nextId[0] + 1; doRes.wset(True); return nextId[0]; endmethod - + method ActionValue#(LockId#(d)) checkpoint(); //return point after this cycle's reservations return nextId[1]; endmethod - + method Action rollback(LockId#(d) i, Bool doRoll, Bool doRollRel); //rollback release is noop //conflicts with other update rules - cannot res/rel and rollback @@ -189,15 +205,15 @@ module mkCheckpointQueueLock(CheckpointQueueLock#(LockId#(d), LockId#(d))); nextId[0] <= i; empty <= i == owner; //if i is Owner, then this is actually empty after rollback end - endmethod - + endmethod + endmodule typedef UInt#(TLog#(n)) LockIdx#(numeric type n); module mkFAAddrLock(AddrLock#(LockId#(d), addr, numlocks)) provisos(Bits#(addr, szAddr), Eq#(addr)); - + Vector#(numlocks, QueueLock#(LockId#(d))) lockVec <- replicateM( mkCountingLock() ); Vector#(numlocks, Reg#(Maybe#(addr))) entryVec <- replicateM( mkConfigReg(tagged Invalid) ); //Signal that a reservation used an already-allocated lock this cycle @@ -206,18 +222,18 @@ module mkFAAddrLock(AddrLock#(LockId#(d), addr, numlocks)) provisos(Bits#(addr, //Allow each lock entry to be freed once it's no longer used, //but tagged as valid, *AND* was there isn't a reservation this cycle to it. - for (Integer i = 0; i < valueOf(numlocks); i = i + 1) begin + for (Integer i = 0; i < valueOf(numlocks); i = i + 1) begin rule freelock(lockVec[i].isEmpty && isValid(entryVec[i]) && !isValid(resVec[i].wget())); entryVec[i] <= tagged Invalid; endrule end - + //returns the index of the lock associated with loc //returns invalid if no lock is associated with loc function Maybe#(LockIdx#(numlocks)) getLockIndex(addr loc); Maybe#(LockIdx#(numlocks)) result = tagged Invalid; for (Integer idx = 0; idx < valueOf(numlocks); idx = idx + 1) - if (result matches tagged Invalid &&& + if (result matches tagged Invalid &&& entryVec[idx] matches tagged Valid.t &&& t == loc) result = tagged Valid fromInteger(idx); return result; @@ -229,7 +245,7 @@ module mkFAAddrLock(AddrLock#(LockId#(d), addr, numlocks)) provisos(Bits#(addr, else return tagged Invalid; endfunction - + //gets the first index where an address is not assigned to the lock OR the lock is empty //returns invalid if all locks are in use function Maybe#(LockIdx#(numlocks)) getFreeLock(); @@ -237,14 +253,14 @@ module mkFAAddrLock(AddrLock#(LockId#(d), addr, numlocks)) provisos(Bits#(addr, for (Integer idx = 0; idx < valueOf(numlocks); idx = idx + 1) if (result matches tagged Invalid &&& entryVec[idx] matches tagged Invalid) - result = tagged Valid fromInteger(idx); + result = tagged Valid fromInteger(idx); return result; endfunction //returns true iff there is a lock location free function Bool isFreeLock(); return isValid(getFreeLock()); - endfunction + endfunction //true if lock is associated w/ addr or there is a location free method Bool canRes1(addr loc); @@ -252,7 +268,7 @@ module mkFAAddrLock(AddrLock#(LockId#(d), addr, numlocks)) provisos(Bits#(addr, if (lockAddr matches tagged Valid.l) return True; else return isFreeLock(); endmethod - + //true if lock associated w/ address is empty or there is a lock lockation free method Bool isEmpty(addr loc); Maybe#(QueueLock#(LockId#(d))) addrLock = getLock(loc); @@ -275,7 +291,7 @@ module mkFAAddrLock(AddrLock#(LockId#(d), addr, numlocks)) provisos(Bits#(addr, //free then this location is acquirable return hasFree; endmethod - + method Action rel1(LockId#(d) tid, addr loc); Maybe#(LockIdx#(numlocks)) lockIdx = getLockIndex(loc); if (lockIdx matches tagged Valid.idx) @@ -286,7 +302,7 @@ module mkFAAddrLock(AddrLock#(LockId#(d), addr, numlocks)) provisos(Bits#(addr, end //else no lock is associated with loc, do nothing endmethod - + method ActionValue#(LockId#(d)) res1(addr loc); Maybe#(LockIdx#(numlocks)) lockIdx = getLockIndex(loc); if (lockIdx matches tagged Valid.idx) @@ -312,7 +328,7 @@ module mkFAAddrLock(AddrLock#(LockId#(d), addr, numlocks)) provisos(Bits#(addr, endmodule: mkFAAddrLock module mkDMAddrLock(AddrLock#(LockId#(d), addr, unused)) provisos(PrimIndex#(addr, szAddr)); - + Vector#(TExp#(szAddr), QueueLock#(LockId#(d))) lockVec <- replicateM( mkCountingLock() ); method Bool isEmpty(addr loc); @@ -322,20 +338,20 @@ module mkDMAddrLock(AddrLock#(LockId#(d), addr, unused)) provisos(PrimIndex#(add method Bool owns1(LockId#(d) tid, addr loc); return lockVec[loc].owns1(tid); endmethod - + method Bool canRes1(addr loc); return True; endmethod - + method Action rel1(LockId#(d) tid, addr loc); lockVec[loc].rel1(tid); endmethod - + method ActionValue#(LockId#(d)) res1(addr loc); let id <- lockVec[loc].res1(); return id; endmethod - + endmodule: mkDMAddrLock endpackage diff --git a/bscRuntime/memories/Memories.bsv b/bscRuntime/memories/Memories.bsv index 2586f886..7f537da7 100644 --- a/bscRuntime/memories/Memories.bsv +++ b/bscRuntime/memories/Memories.bsv @@ -87,7 +87,7 @@ interface AsyncMem2#(type addr, type elem, type mid, numeric type nsz); method Bool checkRespId1(mid a); method Action resp1(mid a); interface Client#(Tuple3#(Bit#(nsz), addr, elem), elem) bram_client1; - + method ActionValue#(mid) req2(addr a, elem b, Bit#(nsz) wmask); method elem peekResp2(mid a); method Bool checkRespId2(mid a); @@ -102,7 +102,7 @@ interface QueueLockCombMem#(type addr, type elem, type id); method Action write(addr a, elem b); interface QueueLock#(id) lock; method Bool canAtom_r1(addr a); - method Bool canAtom_r2(addr a); + method Bool canAtom_r2(addr a); method elem atom_r(addr a); method Bool canAtom_w1(addr a); method Action atom_w(addr a, elem b); @@ -113,7 +113,7 @@ interface CheckpointQueueLockCombMem#(type addr, type elem, type id, type cid); method Action write(addr a, elem b); interface CheckpointQueueLock#(id, cid) lock; method Bool canAtom_r1(addr a); - method Bool canAtom_r2(addr a); + method Bool canAtom_r2(addr a); method elem atom_r(addr a); method Bool canAtom_w1(addr a); method Action atom_w(addr a, elem b); @@ -123,7 +123,7 @@ interface QueueLockAsyncMem#(type addr, type elem, type rid, numeric type nsz, t interface AsyncMem#(addr, elem, rid, nsz) mem; interface QueueLock#(lid) lock; method Bool canAtom1(addr a); - method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); + method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); endinterface interface QueueLockAsyncMem2#(type addr, type elem, type rid, numeric type nsz, type lid); @@ -132,23 +132,23 @@ interface QueueLockAsyncMem2#(type addr, type elem, type rid, numeric type nsz, method Bool canAtom1(addr a); method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); method Bool canAtom2(addr a); - method ActionValue#(rid) atom_req2(addr a, elem b, Bit#(nsz) wmask); + method ActionValue#(rid) atom_req2(addr a, elem b, Bit#(nsz) wmask); endinterface interface AddrLockCombMem#(type addr, type elem, type id, numeric type size); method elem read (addr a); method Action write(addr a, elem b); method Bool canAtom_r1(addr a); - method Bool canAtom_r2(addr a); + method Bool canAtom_r2(addr a); method elem atom_r(addr a); method Bool canAtom_w1(addr a); - method Action atom_w(addr a, elem b); + method Action atom_w(addr a, elem b); interface AddrLock#(id, addr, size) lock; endinterface -interface BypassLockCombMem#(type addr, type elem, type id, numeric type size); +interface BypassLockCombMem#(type addr, type elem, type id, numeric type size); method Bool canAtom_r1(addr a); - method Bool canAtom_r2(addr a); + method Bool canAtom_r2(addr a); method Bool canRes_w1(addr a); method ActionValue#(id) res_w1(addr a); method Bool owns_w1(id i); @@ -161,7 +161,7 @@ interface AddrLockAsyncMem#(type addr, type elem, type rid, numeric type nsz, ty interface AsyncMem#(addr, elem, rid, nsz) mem; interface AddrLock#(lid, addr, size) lock; method Bool canAtom1(addr a); - method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); + method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); endinterface interface AddrLockAsyncMem2#(type addr, type elem, type rid, numeric type nsz, type lid, numeric type size); @@ -170,7 +170,7 @@ interface AddrLockAsyncMem2#(type addr, type elem, type rid, numeric type nsz, t method Bool canAtom1(addr a); method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); method Bool canAtom2(addr a); - method ActionValue#(rid) atom_req2(addr a, elem b, Bit#(nsz) wmask); + method ActionValue#(rid) atom_req2(addr a, elem b, Bit#(nsz) wmask); endinterface //TODO fix this "mem" interface part since they client type doesn't quite match up. @@ -187,16 +187,16 @@ endinterface module mkRegister#(elem init)(RegFile#(addr, elem)) provisos (Bits#(addr, szAddr), Bits#(elem, szElem)); - Reg#(elem) data <- mkReg(init); + Reg#(elem) data <- mkReg(init); method Action upd(addr a, elem d); data <= d; endmethod - + method elem sub(addr a); return data; endmethod - + endmodule module mkRegFile#(parameter Bool init, parameter String initFile)(RegFile#(addr, elem)) @@ -219,7 +219,7 @@ module mkBramPort#(parameter Bool init, parameter String file)(BramPort#(addr, e p <- mkBRAMCore1BELoad(memSize, hasOutputReg, file, False); else p <- mkBRAMCore1BE(memSize, hasOutputReg); - + Reg#(Bool) doRead <- mkDReg(False); Wire#(elem) nextData <- mkWire(); @@ -227,7 +227,7 @@ module mkBramPort#(parameter Bool init, parameter String file)(BramPort#(addr, e rule moveToOutFifo (doRead); nextData <= p.read; endrule - + interface Server bram_server; interface Put request; method Action put (Tuple3#(Bit#(nsz), addr, elem) req); @@ -243,37 +243,37 @@ module mkBramPort#(parameter Bool init, parameter String file)(BramPort#(addr, e endmethod endinterface endinterface - - + + endmodule - + module mkBramPort2#(parameter Bool init, parameter String file) (BramPort2#(addr, elem, MemId#(inflight), nsz)) provisos (Bits#(addr,szAddr), Bits#(elem,szElem), Mul#(TDiv#(szElem, nsz), nsz, szElem)); BRAM_DUAL_PORT_BE#(addr, elem, nsz) dp; Integer maxMemSize = 2 ** 20; //1M mem words, or 4 MB for int32; - let memSize = min(maxMemSize, 2 ** valueOf(szAddr)); + let memSize = min(maxMemSize, 2 ** valueOf(szAddr)); let hasOutputReg = False; if (init) dp <- mkBRAMCore2BELoad(memSize, hasOutputReg, file, False); else dp <- mkBRAMCore2BE(memSize, hasOutputReg); - + Reg#(Bool) doRead1 <- mkDReg(False); Reg#(Bool) doRead2 <- mkDReg(False); Wire#(elem) nextData1 <- mkWire(); Wire#(elem) nextData2 <- mkWire(); - + (* fire_when_enabled *) rule moveToOutFifo1 (doRead1); nextData1 <= dp.a.read; endrule - + (* fire_when_enabled *) rule moveToOutFifo2 (doRead2); nextData2 <= dp.b.read; endrule - + interface Server bram_server1; interface Put request; method Action put (Tuple3#(Bit#(nsz), addr, elem) req); @@ -306,85 +306,85 @@ module mkBramPort2#(parameter Bool init, parameter String file) endinterface endinterface - - + + endmodule //data read from memory made available IMMEDIATELY //rep & resp can go in any order module mkAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) _unused_) provisos(Bits#(addr, szAddr), Bits#(elem, szElem)); - + let outDepth = valueOf(inflight); - + Wire#(Tuple3#(Bit#(n), addr, elem)) toMem <- mkWire(); Wire#(elem) fromMem <- mkWire(); - + //this must be at least size 2 to work correctly (safe bet) Vector#(inflight, Ehr#(2, elem)) outData <- replicateM( mkEhr(unpack(0)) ); Vector#(inflight, Ehr#(2, Bool)) valid <- replicateM( mkEhr(False) ); - + Reg#(MemId#(inflight)) head <- mkReg(0); Wire#(MemId#(inflight)) freeEntry <- mkWire(); - + Bool okToRequest = valid[head][1] == False; - + Reg#(Maybe#(MemId#(inflight))) nextData <- mkDReg(tagged Invalid); - + (* fire_when_enabled *) rule moveToOutFifo (nextData matches tagged Valid.idx); outData[idx][0] <= fromMem; valid[idx][0] <= True; endrule - + (*fire_when_enabled*) rule freeResp; valid[freeEntry][1] <= False; endrule - + method ActionValue#(MemId#(inflight)) req1(addr a, elem b, Bit#(n) wmask) if (okToRequest); toMem <= tuple3(wmask, a, b); head <= head + 1; nextData <= tagged Valid head; return head; endmethod - + method elem peekResp1(MemId#(inflight) a); return outData[a][1]; endmethod - + method Bool checkRespId1(MemId#(inflight) a); return valid[a][1] == True; endmethod - + //Make this invisible to other ops this cycle but happen at any time method Action resp1(MemId#(inflight) a); freeEntry <= a; endmethod - + interface Client bram_client; interface Get request; method ActionValue#(Tuple3#(Bit#(n), addr, elem)) get(); return toMem; endmethod endinterface - + interface Put response; method Action put(elem); fromMem <= elem; endmethod endinterface - + endinterface - + endmodule module mkAsyncMem2(AsyncMem2#(addr, elem, MemId#(inflight), n) _unused_) provisos(Bits#(addr, szAddr), Bits#(elem, szElem)); - + let outDepth = valueOf(inflight); - + Wire#(Tuple3#(Bit#(n), addr, elem)) toMem1 <- mkWire(); Wire#(Tuple3#(Bit#(n), addr, elem)) toMem2 <- mkWire(); Wire#(elem) fromMem1 <- mkWire(); @@ -394,123 +394,123 @@ module mkAsyncMem2(AsyncMem2#(addr, elem, MemId#(inflight), n) _unused_) Vector#(inflight, Ehr#(2, Bool)) valid1 <- replicateM( mkEhr(False) ); Vector#(inflight, Ehr#(2, elem)) outData2 <- replicateM( mkEhr(unpack(0)) ); Vector#(inflight, Ehr#(2, Bool)) valid2 <- replicateM( mkEhr(False) ); - + Reg#(MemId#(inflight)) head1 <- mkReg(0); - Wire#(MemId#(inflight)) freeEntry1 <- mkWire(); + Wire#(MemId#(inflight)) freeEntry1 <- mkWire(); Bool okToRequest1 = valid1[head1][1] == False; - + Reg#(MemId#(inflight)) head2 <- mkReg(0); - Wire#(MemId#(inflight)) freeEntry2 <- mkWire(); + Wire#(MemId#(inflight)) freeEntry2 <- mkWire(); Bool okToRequest2 = valid2[head2][1] == False; - + Reg#(Maybe#(MemId#(inflight))) nextData1 <- mkDReg(tagged Invalid); Reg#(Maybe#(MemId#(inflight))) nextData2 <- mkDReg(tagged Invalid); - + (* fire_when_enabled *) rule moveToOutFifo1 (nextData1 matches tagged Valid.idx); outData1[idx][0] <= fromMem1; valid1[idx][0] <= True; endrule - + (* fire_when_enabled *) rule moveToOutFifo2 (nextData2 matches tagged Valid.idx); outData2[idx][0] <= fromMem2; valid2[idx][0] <= True; endrule - (* fire_when_enabled *) + (* fire_when_enabled *) rule freeResp1; valid1[freeEntry1][1] <= False; endrule - (* fire_when_enabled *) + (* fire_when_enabled *) rule freeResp2; valid2[freeEntry2][1] <= False; endrule - + method ActionValue#(MemId#(inflight)) req1(addr a, elem b, Bit#(n) wmask) if (okToRequest1); toMem1 <= tuple3(wmask, a, b); head1 <= head1 + 1; nextData1 <= tagged Valid head1; return head1; endmethod - + method elem peekResp1(MemId#(inflight) a); return outData1[a][1]; endmethod - + method Bool checkRespId1(MemId#(inflight) a); return valid1[a][1] == True; endmethod - + method Action resp1(MemId#(inflight) a); freeEntry1 <= a; endmethod - + method ActionValue#(MemId#(inflight)) req2(addr a, elem b, Bit#(n) wmask) if (okToRequest2); toMem2 <= tuple3(wmask, a, b); head2 <= head2 + 1; nextData2 <= tagged Valid head2; return head2; endmethod - + method elem peekResp2(MemId#(inflight) a); return outData2[a][1]; endmethod - + method Bool checkRespId2(MemId#(inflight) a); return valid2[a][1] == True; endmethod - + method Action resp2(MemId#(inflight) a); freeEntry2 <= a; endmethod - + interface Client bram_client1; interface Get request; method ActionValue#(Tuple3#(Bit#(n), addr, elem)) get(); return toMem1; endmethod endinterface - + interface Put response; method Action put(elem); fromMem1 <= elem; endmethod endinterface endinterface - + interface Client bram_client2; interface Get request; method ActionValue#(Tuple3#(Bit#(n), addr, elem)) get(); return toMem2; endmethod endinterface - + interface Put response; method Action put(elem); fromMem2 <= elem; endmethod endinterface endinterface - + endmodule module mkQueueLockCombMem(RegFile#(addr, elem) rf, QueueLockCombMem#(addr, elem, LockId#(d)) _unused_); QueueLock#(LockId#(d)) l <- mkQueueLock(); - + interface lock = l; - + method elem read(addr a); return rf.sub(a); endmethod - + method Action write(addr a, elem b); rf.upd(a, b); endmethod - + method Bool canAtom_r1(addr a); return l.isEmpty; endmethod @@ -518,35 +518,35 @@ module mkQueueLockCombMem(RegFile#(addr, elem) rf, QueueLockCombMem#(addr, elem, method Bool canAtom_r2(addr a); return l.isEmpty; endmethod - + method elem atom_r(addr a); return rf.sub(a); endmethod - + method Bool canAtom_w1(addr a); return l.isEmpty; endmethod - + method Action atom_w(addr a, elem b); rf.upd(a, b); endmethod - + endmodule module mkCheckpointQueueLockCombMem(RegFile#(addr, elem) rf, CheckpointQueueLockCombMem#(addr, elem, LockId#(d), LockId#(d)) _unused_); CheckpointQueueLock#(LockId#(d), LockId#(d)) l <- mkCheckpointQueueLock(); - + interface lock = l; - + method elem read(addr a); return rf.sub(a); endmethod - + method Action write(addr a, elem b); rf.upd(a, b); endmethod - + method Bool canAtom_r1(addr a); return l.isEmpty; endmethod @@ -554,19 +554,19 @@ module mkCheckpointQueueLockCombMem(RegFile#(addr, elem) rf, CheckpointQueueLock method Bool canAtom_r2(addr a); return l.isEmpty; endmethod - + method elem atom_r(addr a); return rf.sub(a); endmethod - + method Bool canAtom_w1(addr a); return l.isEmpty; endmethod - + method Action atom_w(addr a, elem b); rf.upd(a, b); endmethod - + endmodule module mkFAAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, LockId#(d), numlocks) _unused_) @@ -576,7 +576,7 @@ module mkFAAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, method elem read(addr a); return rf.sub(a); endmethod - + method Bool canAtom_r1(addr a); return l.isEmpty(a); endmethod @@ -584,7 +584,7 @@ module mkFAAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, method Bool canAtom_r2(addr a); return l.isEmpty(a); endmethod - + method elem atom_r(addr a); return rf.sub(a); endmethod @@ -592,7 +592,7 @@ module mkFAAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, method Bool canAtom_w1(addr a); return l.isEmpty(a); endmethod - + method Action atom_w(addr a, elem b); rf.upd(a, b); endmethod @@ -600,7 +600,7 @@ module mkFAAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, method Action write(addr a, elem b); rf.upd(a, b); endmethod - + interface lock = l; endmodule @@ -611,7 +611,7 @@ module mkDMAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, method elem read(addr a); return rf.sub(a); endmethod - + method Bool canAtom_r1(addr a); return l.isEmpty(a); endmethod @@ -619,7 +619,7 @@ module mkDMAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, method Bool canAtom_r2(addr a); return l.isEmpty(a); endmethod - + method elem atom_r(addr a); return rf.sub(a); endmethod @@ -627,7 +627,7 @@ module mkDMAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, method Bool canAtom_w1(addr a); return l.isEmpty(a); endmethod - + method Action atom_w(addr a, elem b); rf.upd(a, b); endmethod @@ -635,80 +635,80 @@ module mkDMAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, method Action write(addr a, elem b); rf.upd(a, b); endmethod - + interface lock = l; endmodule - + module mkQueueLockAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) amem, QueueLockAsyncMem#(addr, elem, MemId#(inflight), n, LockId#(d)) _unused_) provisos(Bits#(addr, szAddr), Bits#(elem, szElem)); - + QueueLock#(LockId#(d)) l <- mkQueueLock(); - + interface lock = l; interface mem = amem; - + method Bool canAtom1(addr a); return l.isEmpty; endmethod - + method ActionValue#(MemId#(inflight)) atom_req1(addr a, elem b, Bit#(n) wmask); let r <- amem.req1(a, b, wmask); return r; endmethod - + endmodule module mkFAAddrLockAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) amem, AddrLockAsyncMem#(addr, elem, MemId#(inflight), n, LockId#(d), numlocks) _unused_) provisos(Bits#(addr, szAddr), Bits#(elem, szElem), Eq#(addr)); - + AddrLock#(LockId#(d), addr, numlocks) l <- mkFAAddrLock(); - + interface mem = amem; interface lock = l; method Bool canAtom1(addr a); return l.isEmpty(a); endmethod - + method ActionValue#(MemId#(inflight)) atom_req1(addr a, elem b, Bit#(n) wmask); let r <- amem.req1(a, b, wmask); return r; - endmethod - + endmethod + endmodule module mkDMAddrLockAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) amem, AddrLockAsyncMem#(addr, elem, MemId#(inflight), n, LockId#(d), numlocks) _unused_) provisos(PrimIndex#(addr, szAddr), Bits#(addr, szAddr), Bits#(elem, szElem)); - + AddrLock#(LockId#(d), addr, numlocks) l <- mkDMAddrLock(); - + interface mem = amem; interface lock = l; method Bool canAtom1(addr a); return l.isEmpty(a); endmethod - + method ActionValue#(MemId#(inflight)) atom_req1(addr a, elem b, Bit#(n) wmask); let r <- amem.req1(a, b, wmask); return r; endmethod - + endmodule module mkQueueLockAsyncMem2(AsyncMem2#(addr, elem, MemId#(inflight), n) amem, QueueLockAsyncMem2#(addr, elem, MemId#(inflight), n, LockId#(d)) _unused_) provisos(Bits#(addr, szAddr), Bits#(elem, szElem)); - + QueueLock#(LockId#(d)) l <- mkQueueLock(); - + interface lock = l; interface mem = amem; - + method Bool canAtom1(addr a); return l.isEmpty; endmethod - + method ActionValue#(MemId#(inflight)) atom_req1(addr a, elem b, Bit#(n) wmask); let r <- amem.req1(a, b, wmask); return r; @@ -717,27 +717,27 @@ module mkQueueLockAsyncMem2(AsyncMem2#(addr, elem, MemId#(inflight), n) amem, Qu method Bool canAtom2(addr a); return l.isEmpty; endmethod - + method ActionValue#(MemId#(inflight)) atom_req2(addr a, elem b, Bit#(n) wmask); let r <- amem.req2(a, b, wmask); return r; endmethod - - + + endmodule module mkFAAddrLockAsyncMem2(AsyncMem2#(addr, elem, MemId#(inflight), n) amem, AddrLockAsyncMem2#(addr, elem, MemId#(inflight), n, LockId#(d), numlocks) _unused_) provisos(Bits#(addr, szAddr), Bits#(elem, szElem), Eq#(addr)); - + AddrLock#(LockId#(d), addr, numlocks) l <- mkFAAddrLock(); - + interface mem = amem; interface lock = l; method Bool canAtom1(addr a); return l.isEmpty(a); endmethod - + method ActionValue#(MemId#(inflight)) atom_req1(addr a, elem b, Bit#(n) wmask); let r <- amem.req1(a, b, wmask); return r; @@ -746,38 +746,38 @@ module mkFAAddrLockAsyncMem2(AsyncMem2#(addr, elem, MemId#(inflight), n) amem, A method Bool canAtom2(addr a); return l.isEmpty(a); endmethod - + method ActionValue#(MemId#(inflight)) atom_req2(addr a, elem b, Bit#(n) wmask); let r <- amem.req2(a, b, wmask); return r; - endmethod + endmethod endmodule module mkDMAddrLockAsyncMem2(AsyncMem2#(addr, elem, MemId#(inflight), n) amem, AddrLockAsyncMem2#(addr, elem, MemId#(inflight), n, LockId#(d), numlocks) _unused_) provisos(PrimIndex#(addr, szAddr), Bits#(addr, szAddr), Bits#(elem, szElem)); - + AddrLock#(LockId#(d), addr, numlocks) l <- mkDMAddrLock(); - + interface mem = amem; interface lock = l; method Bool canAtom1(addr a); return l.isEmpty(a); endmethod - + method ActionValue#(MemId#(inflight)) atom_req1(addr a, elem b, Bit#(n) wmask); let r <- amem.req1(a, b, wmask); return r; - endmethod - + endmethod + method Bool canAtom2(addr a); return l.isEmpty(a); endmethod - + method ActionValue#(MemId#(inflight)) atom_req2(addr a, elem b, Bit#(n) wmask); let r <- amem.req1(a, b, wmask); return r; - endmethod + endmethod endmodule @@ -822,7 +822,7 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos Wire#(Tuple3#(Bit#(n), addr, elem)) toMem <- mkWire(); Wire#(elem) fromMem <- mkWire(); - + ///Store Stuff Reg#(MemId#(inflight)) stHead <- mkReg(unpack(0)); Vector#(inflight, Ehr#(2, Bool)) stQValid <- replicateM(mkEhr(False)); @@ -843,15 +843,15 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos function Bool isNewerStore(MemId#(inflight) a, MemId#(inflight) b); return isNewer(a, b, stHead); endfunction - + function Bool isOlderLoad(MemId#(inflight) a, MemId#(inflight) b); return isOlder(a, b, ldHead); endfunction - + //search starting at the _newest_ store //newest store is at head - 1 (and go backwards) function Maybe#(MemId#(inflight)) getMatchingStore(addr a); - + Maybe#(MemId#(inflight)) result = tagged Invalid; for (Integer i = 0; i < valueOf(inflight); i = i + 1) begin if (stQValid[i][0] && stQAddr[i] == a) @@ -865,7 +865,7 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos end return result; endfunction - + //search starting at the _oldest_ load //always read start of cycle values ([0] from Ehrs) -> loads will issue (no earlier than) //the first cycle that they can issue @@ -884,7 +884,7 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos end return result; endfunction - + //ldQStr[i][1] -> read & write _after_ reserves (write to [0]) //ldQData[i][1] -> write _after_ reserve function Action write(MemId#(inflight) n, elem b, Bit#(n) wmask); @@ -894,7 +894,7 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos for (Integer i = 0; i < valueOf(inflight); i = i + 1) begin if (ldQStr[i][1] matches tagged Valid.s &&& s == n) begin - ldQStr[i][1] <= tagged Invalid; + ldQStr[i][1] <= tagged Invalid; //order this after reserve (so reserve addr ;write addr forwards data appropriately) if (wmask == '1) ldQData[i][1] <= tagged Valid b; else ldQData[i][1] <= tagged Invalid; @@ -917,16 +917,16 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos //TODO avoid starvation between issueSt and issueLd (currently one always has precedence over the other) //this shouldn't cause liveness issues in real designs but we would need to deal w/ this - //when considering other memory models + //when considering other memory models rule issueSt; let st = stIssueQ.first(); toMem <= tuple3(st.m, st.a, st.d); stIssueQ.deq(); // $display("Issuing Memory Store for addr %d, data %d, %t", st.a, st.d, $time()); endrule - + Reg#(Maybe#(MemId#(inflight))) nextData <- mkDReg(tagged Invalid); - + //run this _after_ commits so that we don't issue a load that's getting freed this cycle rule issueLd (getIssuingLoad matches tagged Valid.idx); // $display("Issuing Memory Load for tag %d, addr %d, %t", idx, ldQAddr[idx], $time()); @@ -934,12 +934,12 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos nextData <= tagged Valid idx; ldQIssued[idx][1] <= True; endrule - + rule moveLdData (nextData matches tagged Valid.idx); //schedule this last for simplicity (can change later) ldQData[idx][2] <= tagged Valid fromMem; endrule - + method ActionValue#(MemId#(inflight)) res_r1(addr a) if (okToLd); Maybe#(MemId#(inflight)) matchStr = getMatchingStore(a); Maybe#(StReq#(elem, Bit#(n))) rreq = tagged Invalid; @@ -955,16 +955,16 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos matchStr = tagged Invalid; data = tagged Valid r.d; end - + ldQValid[ldHead][0] <= True; ldQAddr[ldHead] <= a; ldQData[ldHead][0] <= data; ldQStr[ldHead][0] <= matchStr; - + ldHead <= ldHead + 1; return ldHead; endmethod - + method ActionValue#(MemId#(inflight)) res_w1(addr a) if (okToSt); //Using index [0] means these are the first writes -- [1] reads can combinationally observe these writes stQValid[stHead][0] <= True; @@ -973,7 +973,7 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos stHead <= stHead + 1; return stHead; endmethod - + //checks if it's safe to read data associated w/ ldq entry @@ -991,7 +991,7 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos ldQStr[n][2] <= tagged Invalid; ldQIssued[n][0] <= False; endmethod - + //Only Issue stores after committing method Action rel_w1(MemId#(inflight) n); stQValid[n][1] <= False; @@ -1024,7 +1024,7 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos endmethod endinterface - + interface Client bram_client; interface Get request; method ActionValue#(Tuple3#(Bit#(n), addr, elem)) get(); @@ -1048,14 +1048,14 @@ module mkBypassLockCombMem(RegFile#(addr, elem) rf, BypassLockCombMem#(addr, ele provisos (Bits#(addr, szAddr), Bits#(elem, szElem), Eq#(addr)); Vector#(n, Reg#(Maybe#(addr))) resVec <- replicateM(mkConfigReg(tagged Invalid)); - Vector#(n, Reg#(Maybe#(elem))) dataVec <- replicateM(mkConfigReg(tagged Invalid)); + Vector#(n, Reg#(Maybe#(elem))) dataVec <- replicateM(mkConfigReg(tagged Invalid)); Vector#(n, RWire#(elem)) bypassWire <- replicateM(mkRWireSBR()); Reg#(LockId#(n)) head <- mkReg(0); Reg#(LockId#(n)) owner <- mkConfigReg(0); Wire#(LockId#(n)) toCommit <- mkWire(); - + function Maybe#(LockId#(n)) getMatchingEntry(addr a); Maybe#(LockId#(n)) result = tagged Invalid; for (Integer i = 0; i < valueOf(n); i = i + 1) begin @@ -1070,17 +1070,17 @@ module mkBypassLockCombMem(RegFile#(addr, elem) rf, BypassLockCombMem#(addr, ele end return result; endfunction - - + + Bool headFree = !isValid(resVec[head]); Bool unowned = !isValid(resVec[owner]); - + function Maybe#(elem) readBypassData(LockId#(n) ent); let vecData = dataVec[ent]; let wData = bypassWire[ent]; Maybe#(elem) result = tagged Invalid; - if (wData.wget matches tagged Valid.bdata) result = tagged Valid bdata; - else if (vecData matches tagged Valid.vdata) result = tagged Valid vdata; + if (wData.wget matches tagged Valid.bdata) result = tagged Valid bdata; + else if (vecData matches tagged Valid.vdata) result = tagged Valid vdata; return result; endfunction @@ -1093,14 +1093,14 @@ module mkBypassLockCombMem(RegFile#(addr, elem) rf, BypassLockCombMem#(addr, ele fromMaybe(?, readBypassData(fromInteger(j))), $time()); end endrule **/ - + (*fire_when_enabled*) rule doCommit; let rfdata = fromMaybe(?, readBypassData(toCommit)); let rfaddr = fromMaybe(?, resVec[toCommit]); rf.upd(rfaddr, rfdata); endrule - + //can read THIS Cycle method Bool canAtom_r1(addr a); Bool canGo = False; @@ -1123,39 +1123,39 @@ module mkBypassLockCombMem(RegFile#(addr, elem) rf, BypassLockCombMem#(addr, ele else canGo = True; return canGo; endmethod - + method Bool canRes_w1(addr a); return headFree; endmethod - + method ActionValue#(LockId#(n)) res_w1(addr a) if (headFree); head <= head + 1; resVec[head] <= tagged Valid a; dataVec[head] <= tagged Invalid; return head; - endmethod - + endmethod + method Bool owns_w1(LockId#(n) id); return True; endmethod - + method Action rel_w1(LockId#(n) id); resVec[id] <= tagged Invalid; owner <= owner + 1; toCommit <= id; endmethod - + method elem atom_r(addr a); elem outdata = rf.sub(a); let wdataEnt = getMatchingEntry(a); if (wdataEnt matches tagged Valid.id) outdata = fromMaybe(?, readBypassData(id)); return outdata; endmethod - + method Action write(LockId#(n) id, elem b); dataVec[id] <= tagged Valid b; bypassWire[id].wset(b); endmethod - + endmodule endpackage diff --git a/except-new.pdl b/except-new.pdl new file mode 100644 index 00000000..ffe00f9f --- /dev/null +++ b/except-new.pdl @@ -0,0 +1,47 @@ +exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0]] :uint<4> { + start(imem); + uint<8> insn <- imem[pc]; + end(imem); + --- + print("PC: %h", pc); + print("INSN: %h", insn); + opcode = insn{7:4}; + imm = insn{3:0}; + done = opcode == 0; + add = opcode == 1; + sub = opcode == 2; + ex = !(done || add || sub); + start(acc); + acc_val = acc[]; + split + { + case: (add) + { + acc[] <- acc_val + imm; + } + case: (sub) + { + acc[] <- acc_val - imm; + } + } + if (done) + { + output acc_val; + } else + { + call cpu(pc + 1); + } + end(acc); +} +commit: + {} +except: + {} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 1); + c = new cpu[ti, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/except.pdl b/except.pdl new file mode 100644 index 00000000..21667f6e --- /dev/null +++ b/except.pdl @@ -0,0 +1,45 @@ + + +pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0]] :uint<4> { + start(imem); + uint<8> insn <- imem[pc]; + end(imem); + --- + print("PC: %h", pc); + print("INSN: %h", insn); + opcode = insn{7:4}; + imm = insn{3:0}; + done = opcode == 0; + add = opcode == 1; + sub = opcode == 2; + ex = !(done || add || sub); + start(acc); + acc_val = acc[]; + split + { + case: (add) + { + acc[] <- acc_val + imm; + } + case: (sub) + { + acc[] <- acc_val - imm; + } + } + if (done) + { + output acc_val; + } else + { + call cpu(pc + 1); + } + end(acc); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 1); + c = new cpu[ti, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/insns.hex b/insns.hex new file mode 100644 index 00000000..f0e2be3e --- /dev/null +++ b/insns.hex @@ -0,0 +1,4 @@ +13 +16 +22 +00 \ No newline at end of file diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index b8b94862..6b4d9ca3 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -3,12 +3,11 @@ package pipedsl import java.io.{File, PrintWriter} import java.nio.file.{Files, Paths, StandardCopyOption} import com.typesafe.scalalogging.Logger - import org.apache.commons.io.FilenameUtils import pipedsl.codegen.bsv.{BSVPrettyPrinter, BluespecInterfaces} import pipedsl.codegen.bsv.BluespecGeneration.BluespecProgramGenerator import pipedsl.common.DAGSyntax.PStage -import pipedsl.common.Syntax.{Id, Prog} +import pipedsl.common.Syntax.{ExceptableProg, Id, Prog} import pipedsl.common.{CommandLineParser, MemoryInputParser, PrettyPrinter, ProgInfo} import pipedsl.passes._ import pipedsl.typechecker.TypeInferenceWrapper.TypeInference @@ -42,7 +41,7 @@ object Main { } def parse(debug: Boolean, printOutput: Boolean, inputFile: File, outDir: File, - rfLockImpl: Option[String] = None): Prog = { + rfLockImpl: Option[String] = None): ExceptableProg = { if (!Files.exists(inputFile.toPath)) { throw new RuntimeException(s"File $inputFile does not exist") } diff --git a/src/main/scala/pipedsl/Parser.scala b/src/main/scala/pipedsl/Parser.scala index 7862312c..483095af 100644 --- a/src/main/scala/pipedsl/Parser.scala +++ b/src/main/scala/pipedsl/Parser.scala @@ -368,6 +368,17 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { cmd <~ "---" ^^ {c => CTBar(c, CEmpty())} | seqCmd } ))("cmd") + lazy val commital: P[Command] = positioned { + "commit:" ~> cmd ^^ (i => i) + } + + lazy val except: P[Command] = positioned { + "except:" ~> cmd ^^ (i => i) + } + + lazy val exn_body: P[(Command, Command, Command)] = + cmd ~ commital ~ except ^^ {case bod ~ com ~ ex => (bod, com, ex)} + lazy val bitWidthAtom :P[TBitWidth] = iden ^^ {id => TBitWidthVar(Id(generic_type_prefix + id.v))} | posint ^^ {i => TBitWidthLen(i)} @@ -486,10 +497,14 @@ lazy val genericName :P[Id] = iden ^^ {i => Id(generic_type_prefix + i.v)} } } - lazy val moddef: P[ModuleDef] = dlog(positioned { + lazy val moddef: P[ModuleTrait] = dlog(positioned { "pipe" ~> iden ~ parens(repsep(param, ",")) ~ brackets(repsep(param, ",")) ~ (":" ~> typ).? ~ braces(cmd) ^^ { case i ~ ps ~ mods ~ rt ~ c => ModuleDef(i, ps, mods, rt, c) } + } | positioned { + "exn-pipe" ~> iden ~ parens(repsep(param, ",")) ~ brackets(repsep(param, ",")) ~ (":" ~> typ).? ~ braces(exn_body) ^^ { + case i ~ ps ~ mods ~ rt ~ c => ExceptingModule(i, ps, mods, rt, c._1, c._2, c._3) + } })("module") lazy val ccall: P[CirCall] = positioned { @@ -576,14 +591,14 @@ lazy val genericName :P[Id] = iden ^^ {i => Id(generic_type_prefix + i.v)} case i ~ t ~ f => ExternDef(i, t.getOrElse(List()).map(x => TNamedType(x)), f) } } - lazy val prog: P[Prog] = positioned { + lazy val prog: P[ExceptableProg] = positioned { extern.* ~ fdef.* ~ moddef.* ~ circuit ^^ { - case e ~ f ~ p ~ c => Prog(e, f, p, c) + case e ~ f ~ p ~ c => ExceptableProg(e, f, p, c) } } - def parseCode(code :String) :Prog = { + def parseCode(code :String) :ExceptableProg = { val r = parseAll(prog, code) r match { case Success(program, _) => program diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index 0fd50fdc..d25f2f65 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -30,6 +30,11 @@ class PrettyPrinter(output: Option[File]) { p.moddefs.foreach(m => printModule(m)) printCircuit(p.circ) } + def printProgram(p :ExceptableProg) :Unit = { + p.fdefs.foreach(printFunction) + p.moddefs.foreach(printExModule) + printCircuit(p.circ) + } def printFunction(f: FuncDef): Unit = { pline("def " + f.name.v + "(" + @@ -38,12 +43,26 @@ class PrettyPrinter(output: Option[File]) { printCmdToString(f.body, 2) + "\n}") } + def printExModule(m :ModuleTrait) : Unit = m match + { + case m:ModuleDef => printModule(m) + case m:ExceptingModule => printExceptingModule(m) + } + def printModule(m: ModuleDef): Unit = { pline("pipe " + m.name.v + "(" + m.inputs.map(printParamToString).mkString(",") + ")[" + m.modules.map(printParamToString).mkString(",") + "] {\n" + printCmdToString(m.body, 2) + "\n}") } + def printExceptingModule(m :ExceptingModule) :Unit = { + pline("exn-pipe " + m.name.v + "(" + m.inputs.map(printParamToString).mkString(",") + + ")[" + m.modules.map(printParamToString).mkString(",") + "] {\n" + + printCmdToString(m.body, 2) + "\n}\ncommit:\n" + + printCmdToString(m.commit_block, 2) + "\n}\nexcept:\n" + + printCmdToString(m.exn_block, 2) + "\n}") + } + def printCircuit(c: Circuit): Unit = pline("circuit {\n" + printCircuitToString(c, 2) + "\n}") def printCircuitToString(c: Circuit, indent: Int = 0): String = { diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 2cf88a95..2a105d85 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -688,12 +688,14 @@ object Syntax { lat :Latency ) extends Definition + sealed trait ModuleTrait extends Definition + case class ModuleDef( name: Id, inputs: List[Param], modules: List[Param], ret: Option[Type], - body: Command) extends Definition with RecursiveAnnotation with SpeculativeAnnotation with HasCopyMeta + body: Command) extends ModuleTrait with RecursiveAnnotation with SpeculativeAnnotation with HasCopyMeta { override val copyMeta: HasCopyMeta => ModuleDef = { @@ -706,10 +708,36 @@ object Syntax { } } + case class ExceptingModule + ( + name: Id, + inputs: List[Param], + modules: List[Param], + ret: Option[Type], + body: Command, + commit_block :Command, + exn_block :Command, + ) extends ModuleTrait with RecursiveAnnotation with SpeculativeAnnotation with HasCopyMeta + { + override val copyMeta: HasCopyMeta => ExceptingModule = + { + case from :ModuleDef => + maybeSpec = from.maybeSpec + isRecursive = from.isRecursive + pos = from.pos + this + case _ => this + } + } + case class Param(name: Id, typ: Type) extends Positional case class ExternDef(name: Id, typParams: List[Type], methods: List[MethodDef]) extends Definition with TypeAnnotation + + case class ExceptableProg(exts: List[ExternDef], + fdefs: List[FuncDef], moddefs: List[ModuleTrait], circ: Circuit) extends Positional + case class Prog(exts: List[ExternDef], fdefs: List[FuncDef], moddefs: List[ModuleDef], circ: Circuit) extends Positional diff --git a/src/main/scala/pipedsl/passes/ExceptingToNormal.scala b/src/main/scala/pipedsl/passes/ExceptingToNormal.scala new file mode 100644 index 00000000..659a39ea --- /dev/null +++ b/src/main/scala/pipedsl/passes/ExceptingToNormal.scala @@ -0,0 +1,18 @@ +package pipedsl.passes + +import pipedsl.common.Syntax._ + +object ExceptingToNormal + { + def run(p :ExceptableProg) :Prog = + { + Prog(p.exts, p.fdefs, p.moddefs.map(translateModule), p.circ) + } + private def translateModule(m :ModuleTrait) :ModuleDef = m match + { + case m:ModuleDef => m + case ExceptingModule(name, inputs, modules, ret, body, commit_block, exn_block) => ??? + } + + + } diff --git a/src/test/tests/histogram/histogram_nested.sim b/src/test/tests/histogram/histogram_nested.sim deleted file mode 100644 index e69de29b..00000000 From 263fed8eabccce5c92d807d4287959a16bce939b Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Sun, 13 Mar 2022 22:43:47 -0400 Subject: [PATCH 02/38] commit --- except-new.pdl | 11 ++++-- src/main/scala/pipedsl/Main.scala | 10 ++++-- src/main/scala/pipedsl/Parser.scala | 5 +-- src/main/scala/pipedsl/common/Errors.scala | 8 +++++ .../scala/pipedsl/common/PrettyPrinter.scala | 6 ++-- src/main/scala/pipedsl/common/Syntax.scala | 4 ++- src/main/scala/pipedsl/common/Utilities.scala | 1 + .../pipedsl/passes/CanonicalizePass.scala | 1 + .../pipedsl/passes/ExceptingToNormal.scala | 36 ++++++++++++++++++- .../pipedsl/typechecker/BaseTypeChecker.scala | 1 + .../typechecker/TimingTypeChecker.scala | 3 +- .../typechecker/TypeInferenceWrapper.scala | 5 +-- 12 files changed, 76 insertions(+), 15 deletions(-) diff --git a/except-new.pdl b/except-new.pdl index ffe00f9f..f80bcbf3 100644 --- a/except-new.pdl +++ b/except-new.pdl @@ -23,6 +23,10 @@ exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0]] :uint<4 { acc[] <- acc_val - imm; } + case: (ex) + { + except(); + } } if (done) { @@ -32,11 +36,12 @@ exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0]] :uint<4 call cpu(pc + 1); } end(acc); -} commit: - {} + print("no exn here!"); except: - {} + --- + print("exception!"); +} circuit { diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index 6b4d9ca3..49081285 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -57,7 +57,8 @@ object Main { rfLockImpl: Option[String] = None): Unit = { val outputName = FilenameUtils.getBaseName(inputFile.getName) + ".interpret" val outputFile = new File(Paths.get(outDir.getPath, outputName).toString) - val prog = parse(debug = false, printOutput = false, inputFile, outDir) + val ex_prog = parse(debug = false, printOutput = false, inputFile, outDir) + val prog = ExceptingToNormal.run(ex_prog) val i: Interpreter = new Interpreter(maxIterations) i.interp_prog(RemoveTimingPass.run(prog), MemoryInputParser.parse(memoryInputs), outputFile) } @@ -70,9 +71,12 @@ object Main { val outputName = FilenameUtils.getBaseName(inputFile.getName) + ".typecheck" val outputFile = new File(Paths.get(outDir.getPath, outputName).toString) - val prog = parse(debug = false, printOutput = false, inputFile, outDir, rfLockImpl = rfLockImpl) - val pinfo = new ProgInfo(prog) + val ex_prog = parse(debug = false, printOutput = false, inputFile, outDir, rfLockImpl = rfLockImpl) + try { + val prog = ExceptingToNormal.run(ex_prog) + new PrettyPrinter(None).printProgram(prog) + val pinfo = new ProgInfo(prog) MarkNonRecursiveModulePass.run(prog) //First: add lock regions + checkpoints, then do other things val inferredProg = new LockRegionInferencePass().run(prog) diff --git a/src/main/scala/pipedsl/Parser.scala b/src/main/scala/pipedsl/Parser.scala index 483095af..22850c30 100644 --- a/src/main/scala/pipedsl/Parser.scala +++ b/src/main/scala/pipedsl/Parser.scala @@ -262,6 +262,7 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { typ.? ~ lhs ~ "<-" ~ expr ^^ { case t ~ l ~ _ ~ r => l.typ = t; CRecv(l, r) } | check | resolveSpec | + "except()" ^^ {_ => CExcept()} | "start" ~> parens(iden) ^^ { i => CLockStart(i) } | "end" ~> parens(iden) ^^ { i => CLockEnd(i) } | "acquire" ~> parens(lockArg ~ ("," ~> lockType).?) ^^ { case i ~ t => CSeq(CLockOp(i, Reserved, t, List(), None), CLockOp(i, Acquired, t, List(), None)) } | @@ -376,8 +377,8 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { "except:" ~> cmd ^^ (i => i) } - lazy val exn_body: P[(Command, Command, Command)] = - cmd ~ commital ~ except ^^ {case bod ~ com ~ ex => (bod, com, ex)} + lazy val exn_body: P[(Command, Command, Command)] = dlog( + cmd ~ commital ~ except ^^ {case bod ~ com ~ ex => (bod, com, ex)})("Exception body") lazy val bitWidthAtom :P[TBitWidth] = iden ^^ {id => TBitWidthVar(Id(generic_type_prefix + id.v))} | posint ^^ {i => TBitWidthLen(i)} diff --git a/src/main/scala/pipedsl/common/Errors.scala b/src/main/scala/pipedsl/common/Errors.scala index 16a049ec..8bd69c1c 100644 --- a/src/main/scala/pipedsl/common/Errors.scala +++ b/src/main/scala/pipedsl/common/Errors.scala @@ -213,4 +213,12 @@ object Errors { case class BadConstraintsAtCall(app :EApp) extends RuntimeException( withPos(s"Constraints for $app not satisfied", app.pos) ) + + case class ReleaseInExnBlock(p :Position) extends RuntimeException( + withPos(s"You may not release locks in the except block!", p) + ) + + case class ReleaseWhenMaybeExcepting(p :Position) extends RuntimeException( + withPos(s"No no no! No releasing when you might be excepting!!", p) + ) } diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index d25f2f65..25090ab3 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -58,8 +58,8 @@ class PrettyPrinter(output: Option[File]) { def printExceptingModule(m :ExceptingModule) :Unit = { pline("exn-pipe " + m.name.v + "(" + m.inputs.map(printParamToString).mkString(",") + ")[" + m.modules.map(printParamToString).mkString(",") + "] {\n" + - printCmdToString(m.body, 2) + "\n}\ncommit:\n" + - printCmdToString(m.commit_block, 2) + "\n}\nexcept:\n" + + printCmdToString(m.body, 2) + "\ncommit:\n" + + printCmdToString(m.commit_block, 2) + "\nexcept:\n" + printCmdToString(m.exn_block, 2) + "\n}") } @@ -127,6 +127,7 @@ class PrettyPrinter(output: Option[File]) { printExprToString(originalSpec) + " = update(" + specId + ", " + printExprToString(value) + ");" case Syntax.ICheck(specId, value) => ins + "check(" + specId + ", " + printExprToString(value) + ");" case Syntax.CCheckpoint(h, m) => ins + printExprToString(h) + " <- checkpoint(" + m.v + ");" + case Syntax.CExcept() => ins + "except()" case _ => "TODO PRINTING COMMAND" } } @@ -153,6 +154,7 @@ class PrettyPrinter(output: Option[File]) { case Syntax.EApp(func, args) => func.v + "(" + args.map(a => printExprToString(a)).mkString(",") + ")" case Syntax.ECall(id, name, args, isAtomic) => "call" + (if(isAtomic) " " else " ") + id + "(" + args.map(a => printExprToString(a)).mkString(",") + ")" case Syntax.EVar(id) => id.v + case Syntax.EString(v) => s""""${v}"""" case Syntax.ECast(ctyp, exp) => "cast(" + printExprToString(exp) + "," + printTypeToString(ctyp) + ")" case expr: Syntax.CirExpr => expr match { case CirMem(elemTyp, addrSize, numPorts) => "memory(" + printTypeToString(elemTyp) + "," + addrSize.toString + "," + numPorts.toString + ")" diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 2a105d85..1bc2d707 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -643,7 +643,7 @@ object Syntax { } case class CSplit(cases: List[CaseObj], default: Command) extends Command case class CEmpty() extends Command - + case class CExcept() extends Command sealed trait InternalCommand extends Command @@ -734,6 +734,8 @@ object Syntax { case class ExternDef(name: Id, typParams: List[Type], methods: List[MethodDef]) extends Definition with TypeAnnotation + val is_excepting_var: Id = + Id("__excepting").setType(TBool()) case class ExceptableProg(exts: List[ExternDef], fdefs: List[FuncDef], moddefs: List[ModuleTrait], circ: Circuit) extends Positional diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index 73d072ad..81ab58b9 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -83,6 +83,7 @@ object Utilities { case ICondCommand(cond, cs) => getUsedVars(cond) ++ cs.foldLeft(Set[Id]())((s, c) => getAllVarNames(c) ++ s) case IUpdate(specId, value, originalSpec) => getUsedVars(value) ++ getUsedVars(originalSpec) + specId case Syntax.CEmpty() => Set() + case CExcept() => Set() case _ => throw UnexpectedCommand(c) } diff --git a/src/main/scala/pipedsl/passes/CanonicalizePass.scala b/src/main/scala/pipedsl/passes/CanonicalizePass.scala index 911134f4..f4460dc3 100644 --- a/src/main/scala/pipedsl/passes/CanonicalizePass.scala +++ b/src/main/scala/pipedsl/passes/CanonicalizePass.scala @@ -112,6 +112,7 @@ class CanonicalizePass() extends CommandPass[Command] with ModulePass[ModuleDef] case CLockEnd(_) => c case CLockOp(_, _, _, _, _) => c case CEmpty() => c + case CExcept() => c case _: InternalCommand => c } diff --git a/src/main/scala/pipedsl/passes/ExceptingToNormal.scala b/src/main/scala/pipedsl/passes/ExceptingToNormal.scala index 659a39ea..74095930 100644 --- a/src/main/scala/pipedsl/passes/ExceptingToNormal.scala +++ b/src/main/scala/pipedsl/passes/ExceptingToNormal.scala @@ -1,5 +1,7 @@ package pipedsl.passes +import pipedsl.common.Errors.{ReleaseInExnBlock, ReleaseWhenMaybeExcepting} +import pipedsl.common.Locks.Released import pipedsl.common.Syntax._ object ExceptingToNormal @@ -11,7 +13,39 @@ object ExceptingToNormal private def translateModule(m :ModuleTrait) :ModuleDef = m match { case m:ModuleDef => m - case ExceptingModule(name, inputs, modules, ret, body, commit_block, exn_block) => ??? + case m@ExceptingModule(name, inputs, modules, ret, body, commit_block, exn_block) => + check_exn_block(exn_block) + check_body(body) + ModuleDef( + name, inputs, modules, ret, + ast_append(body, CIf(EVar(is_excepting_var), exn_block, commit_block))).copyMeta(m) + } + + private def ast_append(original :Command, tail :Command) :Command = original match + { + case CTBar(c1, c2) => CTBar(c1, ast_append(c2, tail)).copyMeta(original) + case CEmpty() => tail + case _ => CSeq(original, tail) + } + + private def check_body(c :Command) :Unit = c match + { + case CSeq(c1, c2) => check_body(c1); check_body(c2); + case CTBar(c1, c2) => check_body(c1); check_body(c2); + case CIf(_, cons, alt) => check_body(cons); check_body(alt) + case CSplit(cases, default) => cases.foreach(c => check_body(c.body)) + case CLockOp(_, Released, _, _, _) => throw ReleaseWhenMaybeExcepting(c.pos) + case _ => () + } + + private def check_exn_block(c :Command): Unit = c match + { + case CSeq(c1, c2) => check_exn_block(c1); check_exn_block(c2) + case CTBar(c1, c2) => check_exn_block(c1); check_exn_block(c2); + case CIf(_, cons, alt) => check_exn_block(cons); check_exn_block(alt) + case CSplit(cases, default) => cases.foreach(c => check_exn_block(c.body)); check_exn_block(default) + case CLockOp(_, Released, _, _, _) => throw ReleaseInExnBlock(c.pos) + case _ => () } diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index 4e29c450..37fa4a73 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -460,6 +460,7 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { }) tenv case CEmpty() => tenv + case CExcept() => tenv case _ => throw UnexpectedCommand(c) } diff --git a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala index 7847e507..02a71849 100644 --- a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala @@ -230,6 +230,7 @@ object TimingTypeChecker extends TypeChecks[Id, Type] { checkExpr(exp, vars) (vars, nextVars) case Syntax.CEmpty() => (vars, nextVars) + case CExcept() => (vars, nextVars) case CPrint(args) => args.foreach(a => { checkExpr(a, vars) @@ -328,7 +329,7 @@ object TimingTypeChecker extends TypeChecks[Id, Type] { //calling another pipe case None => Asynchronous } - case EVar(id) => if(!vars(id) && isRhs) { + case EVar(id) => if(!vars(id) && isRhs && !(id == is_excepting_var)) { throw UnavailableArgUse(e.pos, id.toString) } //TODO make this error message more clear about what's wrong when these are lock handle vars else { Combinational } diff --git a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala index 88d56d5d..66b45346 100644 --- a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala +++ b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala @@ -187,7 +187,6 @@ object TypeInferenceWrapper } - def checkProgram(p: Prog): Prog = { val extEnv = p.exts.foldLeft[Environment[Id, Type]](TypeEnv())((env, ext) => { @@ -208,7 +207,8 @@ object TypeInferenceWrapper val (nenv, nfunc) = checkFunc(f, env.asInstanceOf[TypeEnv]) (nenv, lst.prepended(nfunc)) }) - val (modEnvs, newMods) = p.moddefs.foldLeft[(Environment[Id, Type], List[ModuleDef])]((funcEnvs, List.empty[ModuleDef]))((envNlst, m) => + val (modEnvs, newMods) = p.moddefs.foldLeft[(Environment[Id, Type], + List[ModuleDef])]((funcEnvs.add(is_excepting_var, TBool()), List.empty[ModuleDef]))((envNlst, m) => { val env = envNlst._1 val lst = envNlst._2 @@ -345,6 +345,7 @@ object TypeInferenceWrapper case b => throw UnexpectedType(mem.id.pos, c.toString, "Memory or Module Type", b) } case CEmpty() => (c, env, sub) + case CExcept() => (c, env, sub) case cr@CReturn(exp) => val (s, t, e, fixed) = infer(env, exp) val tempSub = compose_subst(sub, s) From c11d649c460c2fb742e536b78c75764b1e1bab5c Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Thu, 17 Mar 2022 01:40:01 -0400 Subject: [PATCH 03/38] tmp --- except-new.pdl | 3 ++- insns.hex | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/except-new.pdl b/except-new.pdl index f80bcbf3..c6e12959 100644 --- a/except-new.pdl +++ b/except-new.pdl @@ -25,6 +25,7 @@ exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0]] :uint<4 } case: (ex) { + cause = 4; except(); } } @@ -36,10 +37,10 @@ exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0]] :uint<4 call cpu(pc + 1); } end(acc); + --- commit: print("no exn here!"); except: - --- print("exception!"); } diff --git a/insns.hex b/insns.hex index f0e2be3e..f7c4dba1 100644 --- a/insns.hex +++ b/insns.hex @@ -1,4 +1,4 @@ -13 -16 -22 -00 \ No newline at end of file +13 //add 3 +16 //add 6 +22 //sub 2 +00 //terminate \ No newline at end of file From 5269a3ebcd6a69bc9f7f4b9b587f173a7081f9c9 Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Thu, 17 Mar 2022 01:52:16 -0400 Subject: [PATCH 04/38] add exceptions task description --- docs/exceptions.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/exceptions.md diff --git a/docs/exceptions.md b/docs/exceptions.md new file mode 100644 index 00000000..5ff07781 --- /dev/null +++ b/docs/exceptions.md @@ -0,0 +1,40 @@ +# Exceptions +## how they work + - introduce `except(args)` command that causes a thread to be marked as + excepting, and provides `args` in a pipeline register for future stages + - create two end "possibilities", marked with `commit:` and `except:`, where + you have to be in a commit block to release locks. Except blocks have more + complex rules: + + things that are "in scope": `args` and anything from before the earliest + point an exception can be thrown. + + all held locks are implicitly aborted on entry + + you may acquire new locks in the usual way, but (for now) may not throw + exceptions. + + all "future" threads have their locks aborted + - when a thread is marked as excepting, it still has to step through the commit + block so that previous threads have time to finish releasing their locks + - As soon as an excepting thread gets to the commit block, it tags a register + so that future threads will not be allowed to enter (or abort their locks + immediately) + +## What needs to happen: + 1. modify typechecking for excepting pipelines to enforce the above rules. + 2. emit code for excepting pipelines. This will involve translating a lot of the + implicit stuff about them into explicit things, like the calls to abort, and + a couple of registers that are used, such as the `args`. + 3. update lock implementations to support an `abort` operation. + 4. write a risc-v processor that implements exceptions + +## Partial order on tasks: +``` +1 < 2 < 4 +3 < 4 +``` +we could get started on an excepting processor early, but testing seems +important. + +## Sequential semantics +the `except(args)` command acts like a jump to the except block, which is +otherwise ignored. This means the except block needs to necessarily contain one +recursive call xor output, which makes sense. + From 28f0c60a3b019a9191f687df8ebbca83f08d273e Mon Sep 17 00:00:00 2001 From: Drew Zagieboylo Date: Thu, 17 Mar 2022 14:20:14 -0400 Subject: [PATCH 05/38] Update exceptions.md --- docs/exceptions.md | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/docs/exceptions.md b/docs/exceptions.md index 5ff07781..4e221901 100644 --- a/docs/exceptions.md +++ b/docs/exceptions.md @@ -1,40 +1,45 @@ # Exceptions ## how they work - - introduce `except(args)` command that causes a thread to be marked as + - Introduce `except(args)` command that causes a thread to be marked as excepting, and provides `args` in a pipeline register for future stages - - create two end "possibilities", marked with `commit:` and `except:`, where + - Create two end "possibilities", marked with `commit:` and `except:`, where you have to be in a commit block to release locks. Except blocks have more complex rules: - + things that are "in scope": `args` and anything from before the earliest + + Things that are "in scope": `args` and anything from before the earliest point an exception can be thrown. - + all held locks are implicitly aborted on entry - + you may acquire new locks in the usual way, but (for now) may not throw + -- can always start with _just `args`_ being in scope for simplicity. + + All held locks are implicitly aborted on entry. + + You may acquire new locks in the usual way, but (for now) may not throw exceptions. - + all "future" threads have their locks aborted - - when a thread is marked as excepting, it still has to step through the commit + + All "future" threads have their locks aborted. + -- The "abort" method of a lock should essentially throw out _all_ non-committed updates / locks. + - When a thread is marked as excepting, it still has to step through the commit block so that previous threads have time to finish releasing their locks - As soon as an excepting thread gets to the commit block, it tags a register - so that future threads will not be allowed to enter (or abort their locks - immediately) + so that future threads will not be allowed to enter (essentially, we need to ensure that + _every_ stage in the early part of the pipeline is killed and doesn't enter the "excepting" or "committing" + parts of the pipeline --- the actual mechanism to do that is up for debate). ## What needs to happen: - 1. modify typechecking for excepting pipelines to enforce the above rules. - 2. emit code for excepting pipelines. This will involve translating a lot of the + 1. Modify typechecking for excepting pipelines to enforce the above rules. + 2. Emit code for excepting pipelines. This will involve translating a lot of the implicit stuff about them into explicit things, like the calls to abort, and a couple of registers that are used, such as the `args`. - 3. update lock implementations to support an `abort` operation. - 4. write a risc-v processor that implements exceptions + It also involves the tricky bits of making sure early stages are killed when an exception is handled. + 3. Update lock implementations to support an `abort` operation. This operation should throw + out all pending updates (reads and writes) -- some lock implementations may need to + be modified to delay writes until "release" is called to support this. + 4. Implement a risc-v processor that uses exceptions. ## Partial order on tasks: ``` 1 < 2 < 4 3 < 4 ``` -we could get started on an excepting processor early, but testing seems -important. +we could get started on an excepting processor early, but testing seems important. ## Sequential semantics -the `except(args)` command acts like a jump to the except block, which is +The `except(args)` command acts like a jump to the except block, which is otherwise ignored. This means the except block needs to necessarily contain one recursive call xor output, which makes sense. From 30953efc52856a690ceee1e274aaf1e38d43967f Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Mon, 28 Mar 2022 16:55:12 -0400 Subject: [PATCH 06/38] start exn typechecking. currently working on typeinference --- except-new-other.pdl | 54 +++++++++++++++ except-new.pdl | 1 - src/main/scala/pipedsl/Main.scala | 17 +++-- src/main/scala/pipedsl/Parser.scala | 24 ++++--- .../scala/pipedsl/common/PrettyPrinter.scala | 36 +++++----- src/main/scala/pipedsl/common/Syntax.scala | 65 ++++++++++--------- src/main/scala/pipedsl/common/Utilities.scala | 9 ++- .../passes/AddCheckpointHandlesPass.scala | 9 ++- .../pipedsl/passes/AddVerifyValuesPass.scala | 8 ++- .../pipedsl/passes/BindModuleTypes.scala | 2 +- .../pipedsl/passes/CanonicalizePass.scala | 10 ++- .../scala/pipedsl/passes/CheckExcepting.scala | 42 ++++++++++++ .../pipedsl/passes/ExceptingToNormal.scala | 52 --------------- .../passes/LockOpTranslationPass.scala | 2 +- .../passes/LockRegionInferencePass.scala | 13 +++- .../passes/MarkNonRecursiveModulePass.scala | 4 +- .../pipedsl/passes/RemoveTimingPass.scala | 2 +- .../pipedsl/passes/SimplifyRecvPass.scala | 2 +- .../pipedsl/typechecker/BaseTypeChecker.scala | 2 +- .../typechecker/TimingTypeChecker.scala | 4 +- .../typechecker/TypeInferenceWrapper.scala | 25 +++++-- 21 files changed, 239 insertions(+), 144 deletions(-) create mode 100644 except-new-other.pdl create mode 100644 src/main/scala/pipedsl/passes/CheckExcepting.scala delete mode 100644 src/main/scala/pipedsl/passes/ExceptingToNormal.scala diff --git a/except-new-other.pdl b/except-new-other.pdl new file mode 100644 index 00000000..297cd5bc --- /dev/null +++ b/except-new-other.pdl @@ -0,0 +1,54 @@ +exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0], oth :uint<4>[0]] :uint<4> { + start(imem); + uint<8> insn <- imem[pc]; + end(imem); + --- + print("PC: %h", pc); + print("INSN: %h", insn); + opcode = insn{7:4}; + imm = insn{3:0}; + done = opcode == 0; + add = opcode == 1; + sub = opcode == 2; + ex = !(done || add || sub); + start(acc); + acc_val = acc[]; + split + { + case: (add) + { + acc[] <- acc_val + imm; + } + case: (sub) + { + acc[] <- acc_val - imm; + } + case: (ex) + { + except(4); + } + } + if (done) + { + output acc_val; + } else + { + call cpu(pc + 1); + } + end(acc); + --- +commit: + print("no exn here!"); +except(arg :uint<4>): + oth[] <- arg; + --- + call cpu(0); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 1); + c = new cpu[ti, acc, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/except-new.pdl b/except-new.pdl index c6e12959..30f62064 100644 --- a/except-new.pdl +++ b/except-new.pdl @@ -25,7 +25,6 @@ exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0]] :uint<4 } case: (ex) { - cause = 4; except(); } } diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index 49081285..7343a820 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -7,7 +7,7 @@ import org.apache.commons.io.FilenameUtils import pipedsl.codegen.bsv.{BSVPrettyPrinter, BluespecInterfaces} import pipedsl.codegen.bsv.BluespecGeneration.BluespecProgramGenerator import pipedsl.common.DAGSyntax.PStage -import pipedsl.common.Syntax.{ExceptableProg, Id, Prog} +import pipedsl.common.Syntax.{Id, Prog} import pipedsl.common.{CommandLineParser, MemoryInputParser, PrettyPrinter, ProgInfo} import pipedsl.passes._ import pipedsl.typechecker.TypeInferenceWrapper.TypeInference @@ -41,7 +41,7 @@ object Main { } def parse(debug: Boolean, printOutput: Boolean, inputFile: File, outDir: File, - rfLockImpl: Option[String] = None): ExceptableProg = { + rfLockImpl: Option[String] = None): Prog = { if (!Files.exists(inputFile.toPath)) { throw new RuntimeException(s"File $inputFile does not exist") } @@ -57,8 +57,7 @@ object Main { rfLockImpl: Option[String] = None): Unit = { val outputName = FilenameUtils.getBaseName(inputFile.getName) + ".interpret" val outputFile = new File(Paths.get(outDir.getPath, outputName).toString) - val ex_prog = parse(debug = false, printOutput = false, inputFile, outDir) - val prog = ExceptingToNormal.run(ex_prog) + val prog = parse(debug = false, printOutput = false, inputFile, outDir) val i: Interpreter = new Interpreter(maxIterations) i.interp_prog(RemoveTimingPass.run(prog), MemoryInputParser.parse(memoryInputs), outputFile) } @@ -71,11 +70,11 @@ object Main { val outputName = FilenameUtils.getBaseName(inputFile.getName) + ".typecheck" val outputFile = new File(Paths.get(outDir.getPath, outputName).toString) - val ex_prog = parse(debug = false, printOutput = false, inputFile, outDir, rfLockImpl = rfLockImpl) + val prog = parse(debug = false, printOutput = false, inputFile, outDir, rfLockImpl = rfLockImpl) try { - val prog = ExceptingToNormal.run(ex_prog) - new PrettyPrinter(None).printProgram(prog) + //val prog = ExceptingToNormal.run(ex_prog) + // new PrettyPrinter(None).printProgram(prog) val pinfo = new ProgInfo(prog) MarkNonRecursiveModulePass.run(prog) //First: add lock regions + checkpoints, then do other things @@ -83,6 +82,8 @@ object Main { val verifProg = AddCheckpointHandlesPass.run(AddVerifyValuesPass.run(inferredProg)) val canonProg2 = new CanonicalizePass().run(verifProg) val canonProg = new TypeInference(autocast).checkProgram(canonProg2) + new PrettyPrinter(None).printProgram(canonProg) + val basetypes = BaseTypeChecker.check(canonProg, None) FunctionConstraintChecker.check(canonProg) val nprog = new BindModuleTypes(basetypes).run(canonProg) @@ -93,10 +94,8 @@ object Main { pinfo.addLockInfo(lockWellformedChecker.getModLockGranularityMap) val lockOperationTypeChecker = new LockOperationTypeChecker(lockWellformedChecker.getModLockGranularityMap) lockOperationTypeChecker.check(recvProg) - val portChecker = new PortChecker(port_warn) portChecker.check(recvProg, None) - val predicateGenerator = new PredicateGenerator() val ctx = predicateGenerator.run(recvProg) val lockChecker = new LockConstraintChecker(locks, lockWellformedChecker.getModLockGranularityMap, ctx) diff --git a/src/main/scala/pipedsl/Parser.scala b/src/main/scala/pipedsl/Parser.scala index 22850c30..7502730b 100644 --- a/src/main/scala/pipedsl/Parser.scala +++ b/src/main/scala/pipedsl/Parser.scala @@ -262,7 +262,7 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { typ.? ~ lhs ~ "<-" ~ expr ^^ { case t ~ l ~ _ ~ r => l.typ = t; CRecv(l, r) } | check | resolveSpec | - "except()" ^^ {_ => CExcept()} | + "except" ~> parens(expr.?) ^^ {arg => CExcept(arg)} | "start" ~> parens(iden) ^^ { i => CLockStart(i) } | "end" ~> parens(iden) ^^ { i => CLockEnd(i) } | "acquire" ~> parens(lockArg ~ ("," ~> lockType).?) ^^ { case i ~ t => CSeq(CLockOp(i, Reserved, t, List(), None), CLockOp(i, Acquired, t, List(), None)) } | @@ -373,11 +373,15 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { "commit:" ~> cmd ^^ (i => i) } - lazy val except: P[Command] = positioned { - "except:" ~> cmd ^^ (i => i) + lazy val except: P[ExceptBlock] = positioned { + "except" ~> parens(iden ~ ":" ~ typ).? ~ (":" ~> cmd) ^^ {case id ~ cmd => id match + { + case Some(arg) => ExceptFull(arg._1._1.setType(arg._2), cmd) + case None => ExceptNoArgs(cmd) + }} } - lazy val exn_body: P[(Command, Command, Command)] = dlog( + lazy val exn_body: P[(Command, Command, ExceptBlock)] = dlog( cmd ~ commital ~ except ^^ {case bod ~ com ~ ex => (bod, com, ex)})("Exception body") lazy val bitWidthAtom :P[TBitWidth] = iden ^^ {id => TBitWidthVar(Id(generic_type_prefix + id.v))} | @@ -498,13 +502,13 @@ lazy val genericName :P[Id] = iden ^^ {i => Id(generic_type_prefix + i.v)} } } - lazy val moddef: P[ModuleTrait] = dlog(positioned { + lazy val moddef: P[ModuleDef] = dlog(positioned { "pipe" ~> iden ~ parens(repsep(param, ",")) ~ brackets(repsep(param, ",")) ~ (":" ~> typ).? ~ braces(cmd) ^^ { - case i ~ ps ~ mods ~ rt ~ c => ModuleDef(i, ps, mods, rt, c) + case i ~ ps ~ mods ~ rt ~ c => ModuleDef(i, ps, mods, rt, c, None, ExceptEmpty()) } } | positioned { "exn-pipe" ~> iden ~ parens(repsep(param, ",")) ~ brackets(repsep(param, ",")) ~ (":" ~> typ).? ~ braces(exn_body) ^^ { - case i ~ ps ~ mods ~ rt ~ c => ExceptingModule(i, ps, mods, rt, c._1, c._2, c._3) + case i ~ ps ~ mods ~ rt ~ c => ModuleDef(i, ps, mods, rt, c._1, Some(c._2), c._3) } })("module") @@ -592,14 +596,14 @@ lazy val genericName :P[Id] = iden ^^ {i => Id(generic_type_prefix + i.v)} case i ~ t ~ f => ExternDef(i, t.getOrElse(List()).map(x => TNamedType(x)), f) } } - lazy val prog: P[ExceptableProg] = positioned { + lazy val prog: P[Prog] = positioned { extern.* ~ fdef.* ~ moddef.* ~ circuit ^^ { - case e ~ f ~ p ~ c => ExceptableProg(e, f, p, c) + case e ~ f ~ p ~ c => Prog(e, f, p, c) } } - def parseCode(code :String) :ExceptableProg = { + def parseCode(code :String) :Prog = { val r = parseAll(prog, code) r match { case Success(program, _) => program diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index 25090ab3..83a15e05 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -30,11 +30,6 @@ class PrettyPrinter(output: Option[File]) { p.moddefs.foreach(m => printModule(m)) printCircuit(p.circ) } - def printProgram(p :ExceptableProg) :Unit = { - p.fdefs.foreach(printFunction) - p.moddefs.foreach(printExModule) - printCircuit(p.circ) - } def printFunction(f: FuncDef): Unit = { pline("def " + f.name.v + "(" + @@ -43,24 +38,31 @@ class PrettyPrinter(output: Option[File]) { printCmdToString(f.body, 2) + "\n}") } - def printExModule(m :ModuleTrait) : Unit = m match - { - case m:ModuleDef => printModule(m) - case m:ExceptingModule => printExceptingModule(m) - } + def printModule(m :ModuleDef) : Unit = + if (is_excepting(m)) printExceptingModule(m) + else _printModule(m) + - def printModule(m: ModuleDef): Unit = { + def _printModule(m: ModuleDef): Unit = { pline("pipe " + m.name.v + "(" + m.inputs.map(printParamToString).mkString(",") + ")[" + m.modules.map(printParamToString).mkString(",") + "] {\n" + printCmdToString(m.body, 2) + "\n}") } - def printExceptingModule(m :ExceptingModule) :Unit = { + def printExceptingModule(m :ModuleDef) :Unit = { pline("exn-pipe " + m.name.v + "(" + m.inputs.map(printParamToString).mkString(",") + - ")[" + m.modules.map(printParamToString).mkString(",") + "] {\n" + - printCmdToString(m.body, 2) + "\ncommit:\n" + - printCmdToString(m.commit_block, 2) + "\nexcept:\n" + - printCmdToString(m.exn_block, 2) + "\n}") + ")[" + m.modules.map(printParamToString).mkString(",") + "] {\n" + + printCmdToString(m.body, 2) + "\ncommit:\n" + + printCmdToString(m.commit_blk.get, 2) + "\n" + + printExnBlock(m.except_blk, 2) + "\n}" + ) + } + + def printExnBlock(block: Syntax.ExceptBlock, ident: Int): String = block match + { + case ExceptEmpty() => "" + case ExceptFull(arg, c) => "except(" + arg.v + "):\n" + printCmdToString(c, ident) + case ExceptNoArgs(c) => "except:\n" + printCmdToString(c, ident) } def printCircuit(c: Circuit): Unit = pline("circuit {\n" + printCircuitToString(c, 2) + "\n}") @@ -127,7 +129,7 @@ class PrettyPrinter(output: Option[File]) { printExprToString(originalSpec) + " = update(" + specId + ", " + printExprToString(value) + ");" case Syntax.ICheck(specId, value) => ins + "check(" + specId + ", " + printExprToString(value) + ");" case Syntax.CCheckpoint(h, m) => ins + printExprToString(h) + " <- checkpoint(" + m.v + ");" - case Syntax.CExcept() => ins + "except()" + case Syntax.CExcept(arg) => ins + "except(" + arg.fold("")(printExprToString) + ");" case _ => "TODO PRINTING COMMAND" } } diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 1bc2d707..4382a2b1 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -643,7 +643,7 @@ object Syntax { } case class CSplit(cases: List[CaseObj], default: Command) extends Command case class CEmpty() extends Command - case class CExcept() extends Command + case class CExcept(arg: Option[Expr]) extends Command sealed trait InternalCommand extends Command @@ -688,14 +688,38 @@ object Syntax { lat :Latency ) extends Definition - sealed trait ModuleTrait extends Definition + sealed trait ExceptBlock extends Positional with HasCopyMeta + { + def map(f : Command => Command) : ExceptBlock + def get :Command + def copyMeta(other :ExceptBlock) = this.setPos(other.pos) + } - case class ModuleDef( - name: Id, - inputs: List[Param], - modules: List[Param], - ret: Option[Type], - body: Command) extends ModuleTrait with RecursiveAnnotation with SpeculativeAnnotation with HasCopyMeta + + case class ExceptEmpty() extends ExceptBlock + { + override def map(f: Command => Command): ExceptBlock = this + override def get :Command = throw new NoSuchElementException("EmptyExcept") + } + case class ExceptNoArgs(c :Command) extends ExceptBlock + { + override def map(f: Command => Command): ExceptBlock = ExceptNoArgs(f(c)).copyMeta(this) + override def get :Command = c + } + case class ExceptFull(arg :Id, c :Command) extends ExceptBlock + { + override def map(f: Command => Command): ExceptBlock = ExceptFull(arg, f(c)).copyMeta(this) + override def get :Command = c + } + + + case class ModuleDef(name: Id, inputs: List[Param], + modules: List[Param], + ret: Option[Type], + body: Command, + commit_blk: Option[Command], + except_blk: ExceptBlock) + extends Definition with RecursiveAnnotation with SpeculativeAnnotation with HasCopyMeta { override val copyMeta: HasCopyMeta => ModuleDef = { @@ -708,27 +732,7 @@ object Syntax { } } - case class ExceptingModule - ( - name: Id, - inputs: List[Param], - modules: List[Param], - ret: Option[Type], - body: Command, - commit_block :Command, - exn_block :Command, - ) extends ModuleTrait with RecursiveAnnotation with SpeculativeAnnotation with HasCopyMeta - { - override val copyMeta: HasCopyMeta => ExceptingModule = - { - case from :ModuleDef => - maybeSpec = from.maybeSpec - isRecursive = from.isRecursive - pos = from.pos - this - case _ => this - } - } + def is_excepting(m :ModuleDef) :Boolean = m.commit_blk.nonEmpty case class Param(name: Id, typ: Type) extends Positional @@ -737,9 +741,6 @@ object Syntax { val is_excepting_var: Id = Id("__excepting").setType(TBool()) - case class ExceptableProg(exts: List[ExternDef], - fdefs: List[FuncDef], moddefs: List[ModuleTrait], circ: Circuit) extends Positional - case class Prog(exts: List[ExternDef], fdefs: List[FuncDef], moddefs: List[ModuleDef], circ: Circuit) extends Positional diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index 81ab58b9..97af8d36 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -83,7 +83,7 @@ object Utilities { case ICondCommand(cond, cs) => getUsedVars(cond) ++ cs.foldLeft(Set[Id]())((s, c) => getAllVarNames(c) ++ s) case IUpdate(specId, value, originalSpec) => getUsedVars(value) ++ getUsedVars(originalSpec) + specId case Syntax.CEmpty() => Set() - case CExcept() => Set() + case CExcept(arg) => arg.fold(Set[Id]())(getUsedVars) case _ => throw UnexpectedCommand(c) } @@ -681,10 +681,9 @@ object Utilities { def typeMapFunc(fun :FuncDef, f_opt :Option[Type] => FOption[Type]) :FuncDef = fun.copy(body = typeMapCmd(fun.body, f_opt)) def typeMapModule(mod :ModuleDef, f_opt :Option[Type] => FOption[Type]) :ModuleDef = - mod.copy(body = typeMapCmd(mod.body, f_opt), - modules = mod.modules.map(p => - p.copy(typ = f_opt(Some(p.typ)).getOrElse(p.typ)) - )).copyMeta(mod) + mod.copy(modules = mod.modules.map(p => + p.copy(typ = f_opt(Some(p.typ)).getOrElse(p.typ)) + ), body = typeMapCmd(mod.body, f_opt), commit_blk = None, except_blk = ExceptEmpty()).copyMeta(mod) def typeMap(p: Prog, f: Type => Option[Type]) :Unit= { diff --git a/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala b/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala index 419c4186..a5b4cf81 100644 --- a/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala +++ b/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala @@ -26,7 +26,14 @@ object AddCheckpointHandlesPass extends CommandPass[Command] with ModulePass[Mod nc } - override def run(m: ModuleDef): ModuleDef = m.copy(body = run(m.body)).copyMeta(m) + override def run(m: ModuleDef): ModuleDef = + { + val (fixed_body, main_handles) = addCheckpointHandles(m.body, (Set(), Set())) + val fixed_commit = m.commit_blk.map(addCheckpointHandles(_, main_handles)._1) + val fixed_except = m.except_blk.map(addCheckpointHandles(_, main_handles)._1) + println(m.except_blk) + m.copy(body = fixed_body, commit_blk = fixed_commit, except_blk = fixed_except).copyMeta(m) + } override def run(p: Prog): Prog = p.copy(exts = p.exts, fdefs = p.fdefs, moddefs = p.moddefs.map(m => run(m))).setPos(p.pos) diff --git a/src/main/scala/pipedsl/passes/AddVerifyValuesPass.scala b/src/main/scala/pipedsl/passes/AddVerifyValuesPass.scala index 85bc641a..cc484ed2 100644 --- a/src/main/scala/pipedsl/passes/AddVerifyValuesPass.scala +++ b/src/main/scala/pipedsl/passes/AddVerifyValuesPass.scala @@ -22,7 +22,13 @@ object AddVerifyValuesPass extends CommandPass[Command] with ModulePass[ModuleDe nc } - override def run(m: ModuleDef): ModuleDef = m.copy(body = run(m.body)).copyMeta(m) + override def run(m: ModuleDef): ModuleDef = + { + val (fixed_body, main_handles) = addVerifyValues(m.body, Map()) + val fixed_commit = m.commit_blk.map(addVerifyValues(_, main_handles)._1) + val fixed_except = m.except_blk.map(addVerifyValues(_, main_handles)._1) + m.copy(body = fixed_body, commit_blk = fixed_commit, except_blk = fixed_except).copyMeta(m) + } override def run(p: Prog): Prog = p.copy(exts = p.exts, fdefs = p.fdefs, moddefs = p.moddefs.map(m => run(m))).setPos(p.pos) diff --git a/src/main/scala/pipedsl/passes/BindModuleTypes.scala b/src/main/scala/pipedsl/passes/BindModuleTypes.scala index 7aae8ed0..65385626 100644 --- a/src/main/scala/pipedsl/passes/BindModuleTypes.scala +++ b/src/main/scala/pipedsl/passes/BindModuleTypes.scala @@ -15,7 +15,7 @@ class BindModuleTypes(val tenv: Environment[Id, Type]) extends ProgPass[Prog] { } def run(m: ModuleDef): ModuleDef = { - m.copy(modules = m.modules.map(p => Param(p.name, replaceNamedType(p.typ)))).copyMeta(m) + m.copy(modules = m.modules.map(p => Param(p.name, replaceNamedType(p.typ))), commit_blk = None, except_blk = ExceptEmpty()).copyMeta(m) } private def replaceNamedType(t: Type): Type = t match { diff --git a/src/main/scala/pipedsl/passes/CanonicalizePass.scala b/src/main/scala/pipedsl/passes/CanonicalizePass.scala index f4460dc3..ba23a158 100644 --- a/src/main/scala/pipedsl/passes/CanonicalizePass.scala +++ b/src/main/scala/pipedsl/passes/CanonicalizePass.scala @@ -41,7 +41,9 @@ class CanonicalizePass() extends CommandPass[Command] with ModulePass[ModuleDef] removeCEmpty(nc) } - override def run(m: ModuleDef): ModuleDef = m.copy(body = run(m.body)).copyMeta(m) + override def run(m: ModuleDef): ModuleDef = m.copy(body = run(m.body), + commit_blk = m.commit_blk.map(run), + except_blk = m.except_blk.map(run)).copyMeta(m) override def run(f: FuncDef): FuncDef = f.copy(body = run(f.body)).setPos(f.pos) @@ -112,7 +114,11 @@ class CanonicalizePass() extends CommandPass[Command] with ModulePass[ModuleDef] case CLockEnd(_) => c case CLockOp(_, _, _, _, _) => c case CEmpty() => c - case CExcept() => c + case CExcept(arg) => if (arg.isDefined) + { + val (nexp, nasgn) = extractCastVars(arg.get) + CSeq(nasgn, CExcept(Some(nexp)).setPos(c.pos)).setPos(c.pos) + } else c case _: InternalCommand => c } diff --git a/src/main/scala/pipedsl/passes/CheckExcepting.scala b/src/main/scala/pipedsl/passes/CheckExcepting.scala new file mode 100644 index 00000000..8da0283a --- /dev/null +++ b/src/main/scala/pipedsl/passes/CheckExcepting.scala @@ -0,0 +1,42 @@ +//package pipedsl.passes +// +//import pipedsl.common.Errors.{ReleaseInExnBlock, ReleaseWhenMaybeExcepting} +//import pipedsl.common.Locks.Released +//import pipedsl.common.Syntax._ +// +//object CheckExcepting +// { +// def run(p :Prog) :Unit = +// { +// p.moddefs.foreach(checkModule) +// } +// private def checkModule(m :ModuleDef) :Unit = +// if (is_excepting(m)) +// { +// check_exn_block(m.except_blk.get) +// check_body(m.body) +// } +// +// private def check_body(c :Command) :Unit = c match +// { +// case CSeq(c1, c2) => check_body(c1); check_body(c2); +// case CTBar(c1, c2) => check_body(c1); check_body(c2); +// case CIf(_, cons, alt) => check_body(cons); check_body(alt) +// case CSplit(cases, default) => cases.foreach(c => check_body(c.body)) +// case CLockOp(_, Released, lt, _, _) if !lt.contains(LockRead) => +// throw ReleaseWhenMaybeExcepting(c.pos) +// case _ => () +// } +// +// private def check_exn_block(c :Command): Unit = c match +// { +// case CSeq(c1, c2) => check_exn_block(c1); check_exn_block(c2) +// case CTBar(c1, c2) => check_exn_block(c1); check_exn_block(c2); +// case CIf(_, cons, alt) => check_exn_block(cons); check_exn_block(alt) +// case CSplit(cases, default) => cases.foreach(c => check_exn_block(c.body)); check_exn_block(default) +// case CLockOp(_, Released, _, _, _) => throw ReleaseInExnBlock(c.pos) +// case _ => () +// } +// +// +// } diff --git a/src/main/scala/pipedsl/passes/ExceptingToNormal.scala b/src/main/scala/pipedsl/passes/ExceptingToNormal.scala deleted file mode 100644 index 74095930..00000000 --- a/src/main/scala/pipedsl/passes/ExceptingToNormal.scala +++ /dev/null @@ -1,52 +0,0 @@ -package pipedsl.passes - -import pipedsl.common.Errors.{ReleaseInExnBlock, ReleaseWhenMaybeExcepting} -import pipedsl.common.Locks.Released -import pipedsl.common.Syntax._ - -object ExceptingToNormal - { - def run(p :ExceptableProg) :Prog = - { - Prog(p.exts, p.fdefs, p.moddefs.map(translateModule), p.circ) - } - private def translateModule(m :ModuleTrait) :ModuleDef = m match - { - case m:ModuleDef => m - case m@ExceptingModule(name, inputs, modules, ret, body, commit_block, exn_block) => - check_exn_block(exn_block) - check_body(body) - ModuleDef( - name, inputs, modules, ret, - ast_append(body, CIf(EVar(is_excepting_var), exn_block, commit_block))).copyMeta(m) - } - - private def ast_append(original :Command, tail :Command) :Command = original match - { - case CTBar(c1, c2) => CTBar(c1, ast_append(c2, tail)).copyMeta(original) - case CEmpty() => tail - case _ => CSeq(original, tail) - } - - private def check_body(c :Command) :Unit = c match - { - case CSeq(c1, c2) => check_body(c1); check_body(c2); - case CTBar(c1, c2) => check_body(c1); check_body(c2); - case CIf(_, cons, alt) => check_body(cons); check_body(alt) - case CSplit(cases, default) => cases.foreach(c => check_body(c.body)) - case CLockOp(_, Released, _, _, _) => throw ReleaseWhenMaybeExcepting(c.pos) - case _ => () - } - - private def check_exn_block(c :Command): Unit = c match - { - case CSeq(c1, c2) => check_exn_block(c1); check_exn_block(c2) - case CTBar(c1, c2) => check_exn_block(c1); check_exn_block(c2); - case CIf(_, cons, alt) => check_exn_block(cons); check_exn_block(alt) - case CSplit(cases, default) => cases.foreach(c => check_exn_block(c.body)); check_exn_block(default) - case CLockOp(_, Released, _, _, _) => throw ReleaseInExnBlock(c.pos) - case _ => () - } - - - } diff --git a/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala b/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala index ebd4331a..ff5afb36 100644 --- a/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala @@ -64,7 +64,7 @@ object LockOpTranslationPass extends ProgPass[Prog] with CommandPass[Command] wi override def run(m: ModuleDef): ModuleDef = { - val nm = m.copy(body = run(m.body)) + val nm = m.copy(body = run(m.body), commit_blk = None, except_blk = ExceptEmpty()) nm.isRecursive = m.isRecursive nm.maybeSpec = m.maybeSpec nm diff --git a/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala b/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala index b80be63e..c19d57ab 100644 --- a/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala +++ b/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala @@ -38,7 +38,7 @@ class LockRegionInferencePass() extends ModulePass[ModuleDef] with ProgPass[Prog checkpointConds = Map() m.modules.foreach(p => { p.typ match { - case TMemType(_, _, _, _, _, _) => + case _ :TMemType => unlockedMems = unlockedMems + p.name case _ => () } @@ -51,7 +51,16 @@ class LockRegionInferencePass() extends ModulePass[ModuleDef] with ProgPass[Prog checkpointConds = checkpointConds.removedAll(haveCheckpoint(m.body)) val (memsThatNeedChks, _) = needsCheckpoint(m.body, m.maybeSpec) val checks = insertChecks(ends, modIds.intersect(checkpointConds.keySet).intersect(memsThatNeedChks)) - m.copy(body = checks._1).copyMeta(m) + val new_exn = if(is_excepting(m)) + { + val started_exn = m.except_blk.map(insertStarts(_, modIds, Set())._1) + val ended_exn = started_exn.map(insertEnds(_, modIds, Set())._1) + findInvalidateConds(ended_exn.get, None, (Set(), Set())) + checkpointConds = checkpointConds.removedAll(haveCheckpoint(m.except_blk.get)) + val (exn_needs_checked, _) = needsCheckpoint(m.except_blk.get, m.maybeSpec) + ended_exn.map(insertChecks(_, modIds.intersect(checkpointConds.keySet).intersect(exn_needs_checked))._1) + } else ExceptEmpty() + m.copy(body = checks._1, except_blk = new_exn).copyMeta(m) } /** diff --git a/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala b/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala index c2301254..09c3d245 100644 --- a/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala +++ b/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala @@ -25,7 +25,9 @@ object MarkNonRecursiveModulePass extends ModulePass[ModuleDef] with ProgPass[Pr override def run(m: ModuleDef): ModuleDef = { val (isRec, isSpec) = hasRecursiveCall(m.body, m.name) - m.isRecursive = isRec + m.isRecursive = isRec || (if(is_excepting(m)) + hasRecursiveCall(m.commit_blk.get, m.name)._1 || hasRecursiveCall(m.except_blk.get, m.name)._1 + else false) m.maybeSpec = isSpec m } diff --git a/src/main/scala/pipedsl/passes/RemoveTimingPass.scala b/src/main/scala/pipedsl/passes/RemoveTimingPass.scala index e5bdec63..5f013838 100644 --- a/src/main/scala/pipedsl/passes/RemoveTimingPass.scala +++ b/src/main/scala/pipedsl/passes/RemoveTimingPass.scala @@ -13,7 +13,7 @@ object RemoveTimingPass extends CommandPass[Command] with ModulePass[ModuleDef] } override def run(m: ModuleDef): ModuleDef = { - m.copy(body = run(m.body)).setPos(m.pos) + m.copy(body = run(m.body), commit_blk = None, except_blk = ExceptEmpty()).setPos(m.pos) } override def run(c: Command): Command = { diff --git a/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala b/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala index 44f285bb..7be5a4af 100644 --- a/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala +++ b/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala @@ -24,7 +24,7 @@ object SimplifyRecvPass extends CommandPass[Command] with ModulePass[ModuleDef] override def run(m: ModuleDef): ModuleDef = { usedVars = m.modules.foldLeft[Set[Id]](usedVars)((s,p) => s + p.name) - m.copy(body = run(m.body)).setPos(m.pos).copyMeta(m) + m.copy(body = run(m.body), commit_blk = None, except_blk = ExceptEmpty()).setPos(m.pos).copyMeta(m) } override def run(c: Command): Command = { diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index 37fa4a73..93b4d506 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -460,7 +460,7 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { }) tenv case CEmpty() => tenv - case CExcept() => tenv + case CExcept(arg) => arg.foreach(checkExpression(_, tenv, None)); tenv case _ => throw UnexpectedCommand(c) } diff --git a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala index 02a71849..a7747578 100644 --- a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala @@ -230,7 +230,9 @@ object TimingTypeChecker extends TypeChecks[Id, Type] { checkExpr(exp, vars) (vars, nextVars) case Syntax.CEmpty() => (vars, nextVars) - case CExcept() => (vars, nextVars) + case CExcept(arg) => + arg.foreach(checkExpr(_, vars)) + (vars, nextVars) case CPrint(args) => args.foreach(a => { checkExpr(a, vars) diff --git a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala index 66b45346..2058a69a 100644 --- a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala +++ b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala @@ -7,7 +7,7 @@ import pipedsl.common.Syntax._ import pipedsl.common.Constraints._ import pipedsl.common.Constraints.ImplicitConstraints._ import pipedsl.common.Utilities.{defaultReadPorts, defaultWritePorts, degenerify, fopt_func, is_generic, is_my_generic, specialize, typeMap, typeMapFunc, typeMapModule, without_prefix} -import pipedsl.typechecker.Environments.{EmptyTypeEnv, Environment, TypeEnv} +import pipedsl.typechecker.Environments.{EmptyIntEnv, EmptyTypeEnv, Environment, TypeEnv} import pipedsl.typechecker.Subtypes.{canCast, isSubtype} import com.microsoft.z3.{Status, AST => Z3AST, ArithExpr => Z3ArithExpr, BoolExpr => Z3BoolExpr, Context => Z3Context, IntExpr => Z3IntExpr, Solver => Z3Solver} import TBitWidthImplicits._ @@ -240,9 +240,24 @@ object TypeInferenceWrapper val modEnv = env.add(m.name, TModType(inputTypes, modTypes, m.ret, Some(m.name))) val inEnv = m.inputs.foldLeft[Environment[Id, Type]](modEnv)((env, p) => env.add(p.name, p.typ)) val pipeEnv = m.modules.zip(modTypes).foldLeft[Environment[Id, Type]](inEnv)((env, m) => env.add(m._1.name, m._2)) - val (fixed_cmd, _, subst) = checkCommand(m.body, pipeEnv.asInstanceOf[TypeEnv], mod_subs) - val hash = mutable.HashMap.from(subst) - val newMod = typeMapModule(m.copy(body = fixed_cmd).copyMeta(m), fopt_func(type_subst_map_fopt(_, hash))) + val (fixed_cmd, out_env, subst) = checkCommand(m.body, pipeEnv.asInstanceOf[TypeEnv], mod_subs) + val (fixed_commit, _, subst1) = m.commit_blk match + { + case None => (None, out_env, subst) + case Some(c) => checkCommand(c, out_env, subst) |> {case (x, y, z) => (Some(x), y, z)} + } + val (fixed_except, final_subst) = m.except_blk match + { + case ExceptEmpty() => (ExceptEmpty(), subst1) + case ExceptNoArgs(c) => checkCommand(c, out_env, subst) |> {case (x, _, z) => (ExceptNoArgs(x), z)} //TODO IMPROVE PRECISION OF OUT_ENV, SUBST + case ExceptFull(arg, c) => checkCommand(c, out_env.add(arg, arg.typ.get).asInstanceOf[TypeEnv], subst) |> {case (cmd, _, s) => (ExceptFull(arg, cmd), s)} + } + val hash = mutable.HashMap.from(final_subst) + val newMod = typeMapModule(m.copy(body = fixed_cmd, commit_blk = fixed_commit, except_blk = fixed_except).copyMeta(m), fopt_func(type_subst_map_fopt(_, hash))) + + println(fixed_commit) + println(fixed_except) + val new_input = newMod.inputs.map(p => p.typ) val new_mod_tps = newMod.modules.map(m => replaceNamedType(m.typ, env)) @@ -345,7 +360,7 @@ object TypeInferenceWrapper case b => throw UnexpectedType(mem.id.pos, c.toString, "Memory or Module Type", b) } case CEmpty() => (c, env, sub) - case CExcept() => (c, env, sub) + case CExcept(args) => (c, env, sub) //TODO IMPLEMENT case cr@CReturn(exp) => val (s, t, e, fixed) = infer(env, exp) val tempSub = compose_subst(sub, s) From 86409a84808adcef27a5bc169fe8fca9dc794d67 Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Mon, 4 Apr 2022 18:28:01 -0400 Subject: [PATCH 07/38] type inference --- src/main/scala/pipedsl/Parser.scala | 7 +++---- .../scala/pipedsl/common/PrettyPrinter.scala | 6 ++---- src/main/scala/pipedsl/common/Syntax.scala | 17 ++++++++--------- src/main/scala/pipedsl/common/Utilities.scala | 4 ++-- .../passes/AddCheckpointHandlesPass.scala | 1 - .../scala/pipedsl/passes/CanonicalizePass.scala | 7 ++----- .../typechecker/TypeInferenceWrapper.scala | 13 +++++-------- 7 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/main/scala/pipedsl/Parser.scala b/src/main/scala/pipedsl/Parser.scala index 7502730b..0ba7061c 100644 --- a/src/main/scala/pipedsl/Parser.scala +++ b/src/main/scala/pipedsl/Parser.scala @@ -262,7 +262,7 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { typ.? ~ lhs ~ "<-" ~ expr ^^ { case t ~ l ~ _ ~ r => l.typ = t; CRecv(l, r) } | check | resolveSpec | - "except" ~> parens(expr.?) ^^ {arg => CExcept(arg)} | + "except" ~> parens(repsep(expr, ",")) ^^ {args => CExcept(args)} | "start" ~> parens(iden) ^^ { i => CLockStart(i) } | "end" ~> parens(iden) ^^ { i => CLockEnd(i) } | "acquire" ~> parens(lockArg ~ ("," ~> lockType).?) ^^ { case i ~ t => CSeq(CLockOp(i, Reserved, t, List(), None), CLockOp(i, Acquired, t, List(), None)) } | @@ -374,10 +374,9 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { } lazy val except: P[ExceptBlock] = positioned { - "except" ~> parens(iden ~ ":" ~ typ).? ~ (":" ~> cmd) ^^ {case id ~ cmd => id match + "except" ~> parens(repsep(iden ~ ":" ~ typ, ",")) ~ (":" ~> cmd) ^^ {case id ~ cmd => id match { - case Some(arg) => ExceptFull(arg._1._1.setType(arg._2), cmd) - case None => ExceptNoArgs(cmd) + case args => ExceptFull(args.map({ case id ~ _ ~ tp => id.setType(tp)}), cmd) }} } diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index 83a15e05..ea4c52a9 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -42,7 +42,6 @@ class PrettyPrinter(output: Option[File]) { if (is_excepting(m)) printExceptingModule(m) else _printModule(m) - def _printModule(m: ModuleDef): Unit = { pline("pipe " + m.name.v + "(" + m.inputs.map(printParamToString).mkString(",") + ")[" + m.modules.map(printParamToString).mkString(",") + "] {\n" + @@ -61,8 +60,7 @@ class PrettyPrinter(output: Option[File]) { def printExnBlock(block: Syntax.ExceptBlock, ident: Int): String = block match { case ExceptEmpty() => "" - case ExceptFull(arg, c) => "except(" + arg.v + "):\n" + printCmdToString(c, ident) - case ExceptNoArgs(c) => "except:\n" + printCmdToString(c, ident) + case ExceptFull(args, c) => "except(" + args.map((id) => id.v).reduce((acc, elem) => acc + "," + elem) + "):\n" + printCmdToString(c, ident) } def printCircuit(c: Circuit): Unit = pline("circuit {\n" + printCircuitToString(c, 2) + "\n}") @@ -129,7 +127,7 @@ class PrettyPrinter(output: Option[File]) { printExprToString(originalSpec) + " = update(" + specId + ", " + printExprToString(value) + ");" case Syntax.ICheck(specId, value) => ins + "check(" + specId + ", " + printExprToString(value) + ");" case Syntax.CCheckpoint(h, m) => ins + printExprToString(h) + " <- checkpoint(" + m.v + ");" - case Syntax.CExcept(arg) => ins + "except(" + arg.fold("")(printExprToString) + ");" + case Syntax.CExcept(args) => ins + "except(" + args.map(printExprToString).reduce((acc, elem) => acc + ", " + elem) + ");" case _ => "TODO PRINTING COMMAND" } } diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 4382a2b1..4861430c 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -643,7 +643,7 @@ object Syntax { } case class CSplit(cases: List[CaseObj], default: Command) extends Command case class CEmpty() extends Command - case class CExcept(arg: Option[Expr]) extends Command + case class CExcept(args: List[Expr]) extends Command sealed trait InternalCommand extends Command @@ -701,14 +701,9 @@ object Syntax { override def map(f: Command => Command): ExceptBlock = this override def get :Command = throw new NoSuchElementException("EmptyExcept") } - case class ExceptNoArgs(c :Command) extends ExceptBlock - { - override def map(f: Command => Command): ExceptBlock = ExceptNoArgs(f(c)).copyMeta(this) - override def get :Command = c - } - case class ExceptFull(arg :Id, c :Command) extends ExceptBlock + case class ExceptFull(args: List[Id], c: Command) extends ExceptBlock { - override def map(f: Command => Command): ExceptBlock = ExceptFull(arg, f(c)).copyMeta(this) + override def map(f: Command => Command): ExceptBlock = ExceptFull(args, f(c)).copyMeta(this) override def get :Command = c } @@ -732,7 +727,11 @@ object Syntax { } } - def is_excepting(m :ModuleDef) :Boolean = m.commit_blk.nonEmpty + def is_excepting(m :ModuleDef) :Boolean = m.except_blk match + { + case ExceptEmpty() => false + case _ :ExceptFull => true + } case class Param(name: Id, typ: Type) extends Positional diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index 97af8d36..ff54d7e5 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -83,7 +83,7 @@ object Utilities { case ICondCommand(cond, cs) => getUsedVars(cond) ++ cs.foldLeft(Set[Id]())((s, c) => getAllVarNames(c) ++ s) case IUpdate(specId, value, originalSpec) => getUsedVars(value) ++ getUsedVars(originalSpec) + specId case Syntax.CEmpty() => Set() - case CExcept(arg) => arg.fold(Set[Id]())(getUsedVars) + case CExcept(args) => args.foldLeft(Set[Id]())((set, arg) => set.union(getUsedVars(arg))) case _ => throw UnexpectedCommand(c) } @@ -683,7 +683,7 @@ object Utilities { def typeMapModule(mod :ModuleDef, f_opt :Option[Type] => FOption[Type]) :ModuleDef = mod.copy(modules = mod.modules.map(p => p.copy(typ = f_opt(Some(p.typ)).getOrElse(p.typ)) - ), body = typeMapCmd(mod.body, f_opt), commit_blk = None, except_blk = ExceptEmpty()).copyMeta(mod) + ), body = typeMapCmd(mod.body, f_opt)).copyMeta(mod) def typeMap(p: Prog, f: Type => Option[Type]) :Unit= { diff --git a/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala b/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala index a5b4cf81..2bbb252b 100644 --- a/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala +++ b/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala @@ -31,7 +31,6 @@ object AddCheckpointHandlesPass extends CommandPass[Command] with ModulePass[Mod val (fixed_body, main_handles) = addCheckpointHandles(m.body, (Set(), Set())) val fixed_commit = m.commit_blk.map(addCheckpointHandles(_, main_handles)._1) val fixed_except = m.except_blk.map(addCheckpointHandles(_, main_handles)._1) - println(m.except_blk) m.copy(body = fixed_body, commit_blk = fixed_commit, except_blk = fixed_except).copyMeta(m) } diff --git a/src/main/scala/pipedsl/passes/CanonicalizePass.scala b/src/main/scala/pipedsl/passes/CanonicalizePass.scala index ba23a158..a62938b5 100644 --- a/src/main/scala/pipedsl/passes/CanonicalizePass.scala +++ b/src/main/scala/pipedsl/passes/CanonicalizePass.scala @@ -114,11 +114,8 @@ class CanonicalizePass() extends CommandPass[Command] with ModulePass[ModuleDef] case CLockEnd(_) => c case CLockOp(_, _, _, _, _) => c case CEmpty() => c - case CExcept(arg) => if (arg.isDefined) - { - val (nexp, nasgn) = extractCastVars(arg.get) - CSeq(nasgn, CExcept(Some(nexp)).setPos(c.pos)).setPos(c.pos) - } else c + case CExcept(args) => val (nargs, nc) = extractCastVars(args) + CSeq(nc, CExcept(nargs).setPos(c.pos)) case _: InternalCommand => c } diff --git a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala index 2058a69a..673c0148 100644 --- a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala +++ b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala @@ -239,8 +239,8 @@ object TypeInferenceWrapper compose_subst(subst, unify(types._1.typ, types._2)._1)) val modEnv = env.add(m.name, TModType(inputTypes, modTypes, m.ret, Some(m.name))) val inEnv = m.inputs.foldLeft[Environment[Id, Type]](modEnv)((env, p) => env.add(p.name, p.typ)) - val pipeEnv = m.modules.zip(modTypes).foldLeft[Environment[Id, Type]](inEnv)((env, m) => env.add(m._1.name, m._2)) - val (fixed_cmd, out_env, subst) = checkCommand(m.body, pipeEnv.asInstanceOf[TypeEnv], mod_subs) + val pipeEnv = m.modules.zip(modTypes).foldLeft[Environment[Id, Type]](inEnv)((env, m) => env.add(m._1.name, m._2)).asInstanceOf[TypeEnv] + val (fixed_cmd, out_env, subst) = checkCommand(m.body, pipeEnv, mod_subs) val (fixed_commit, _, subst1) = m.commit_blk match { case None => (None, out_env, subst) @@ -249,16 +249,13 @@ object TypeInferenceWrapper val (fixed_except, final_subst) = m.except_blk match { case ExceptEmpty() => (ExceptEmpty(), subst1) - case ExceptNoArgs(c) => checkCommand(c, out_env, subst) |> {case (x, _, z) => (ExceptNoArgs(x), z)} //TODO IMPROVE PRECISION OF OUT_ENV, SUBST - case ExceptFull(arg, c) => checkCommand(c, out_env.add(arg, arg.typ.get).asInstanceOf[TypeEnv], subst) |> {case (cmd, _, s) => (ExceptFull(arg, cmd), s)} + //TODO IMPROVE PRECISION OF OUT_ENV, SUBST + case ExceptFull(args, c) => checkCommand(c, args.foldLeft(pipeEnv)((env, id) => env.add(id, id.typ.get).asInstanceOf[TypeEnv]), subst) |> + {case (cmd, _, s) => (ExceptFull(args, cmd), s)} } val hash = mutable.HashMap.from(final_subst) val newMod = typeMapModule(m.copy(body = fixed_cmd, commit_blk = fixed_commit, except_blk = fixed_except).copyMeta(m), fopt_func(type_subst_map_fopt(_, hash))) - println(fixed_commit) - println(fixed_except) - - val new_input = newMod.inputs.map(p => p.typ) val new_mod_tps = newMod.modules.map(m => replaceNamedType(m.typ, env)) From b0ca5cd4bb9b94850a2ee6e9d003e38cbfb6da9e Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Mon, 4 Apr 2022 18:31:46 -0400 Subject: [PATCH 08/38] type inference --- src/main/scala/pipedsl/common/Utilities.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index ff54d7e5..7e4759bb 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -683,7 +683,9 @@ object Utilities { def typeMapModule(mod :ModuleDef, f_opt :Option[Type] => FOption[Type]) :ModuleDef = mod.copy(modules = mod.modules.map(p => p.copy(typ = f_opt(Some(p.typ)).getOrElse(p.typ)) - ), body = typeMapCmd(mod.body, f_opt)).copyMeta(mod) + ), body = typeMapCmd(mod.body, f_opt), + commit_blk = mod.commit_blk.map(typeMapCmd(_, f_opt)), + except_blk = mod.except_blk.map(typeMapCmd(_, f_opt))).copyMeta(mod) def typeMap(p: Prog, f: Type => Option[Type]) :Unit= { From d3d7bfc37914c9224f97a6db47057171c5acf010 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Tue, 19 Apr 2022 06:49:12 -0400 Subject: [PATCH 09/38] add typechecking based on the rules we discussed --- .../pipedsl/passes/ConvertExnModulePass.scala | 5 ++ .../FinalblocksConstraintChecker.scala | 62 +++++++++++++++++++ .../typechecker/LockRegionChecker.scala | 40 +++++++++--- 3 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 src/main/scala/pipedsl/passes/ConvertExnModulePass.scala create mode 100644 src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala diff --git a/src/main/scala/pipedsl/passes/ConvertExnModulePass.scala b/src/main/scala/pipedsl/passes/ConvertExnModulePass.scala new file mode 100644 index 00000000..18bd631f --- /dev/null +++ b/src/main/scala/pipedsl/passes/ConvertExnModulePass.scala @@ -0,0 +1,5 @@ +package pipedsl.passes + +object ConvertExnModulePass { + +} diff --git a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala new file mode 100644 index 00000000..f5a32a78 --- /dev/null +++ b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala @@ -0,0 +1,62 @@ +package pipedsl.typechecker + +import org.apache.commons.io.filefilter.FalseFileFilter +import pipedsl.common.Syntax._ +import pipedsl.typechecker.Environments._ +import pipedsl.common.Errors._ + +class FinalblocksConstraintChecker { + private var currentMod: Id = Id("-invalid-") + private var ifPostCall: Boolean = false + private var hasCommitBlk: Boolean = false + + def check(p:Prog) : Unit = { + val Prog(_, _, moddefs, _) = p + moddefs.foreach(m => checkModule(m)) + } + + private def checkModule(moduleDef: ModuleDef): Unit = { + currentMod = moduleDef.name + ifPostCall = false + hasCommitBlk = false + + moduleDef.commit_blk match { + case Some(c) => + hasCommitBlk = true + checkCommand(c) + case _ => () + } + + moduleDef.except_blk match { + case ExceptEmpty() => () + case ExceptFull(args, c) if (hasCommitBlk == true) => checkCommand(c) + case ExceptFull(args, c) if (hasCommitBlk == false) => + throw MalformedExceptBlock(c.pos) + } + } + + private def checkCommand(command: Command): Unit = command match { + case CSeq(c1, c2) => val s1 = checkCommand(c1); checkCommand(c2) + case CTBar(c1, c2) => val s1 = checkCommand(c1); checkCommand(c2) + case CIf(_, cons, alt) => val s1 = checkCommand(cons); checkCommand(alt) + case CSplit(cases, default) => + checkCommand(default) + case CLockOp(mem, _, _, _, _) => + if (ifPostCall == true) throw MalformedLockTypes("Cannot Reserve any locks after a call") + case CAssign(lhs, rhs) => checkExpr(lhs); checkExpr(rhs) + case CRecv(lhs, rhs) => checkExpr(lhs); checkExpr(rhs) + case CExcept(args) => throw IllegalThrowPlacement(command.pos) + case _ => () + } + + private def checkExpr(e: Expr): Unit = e match { + case EIsValid(ex) => checkExpr(ex) + case EFromMaybe(ex) => checkExpr(ex) + case EToMaybe(ex) => checkExpr(ex) + case EUop(_, ex) => checkExpr(ex) + case EBinop(_, e1, e2) => checkExpr(e1); checkExpr(e2) + case ETernary(cond, tval, fval) => checkExpr(cond); checkExpr(tval); checkExpr(fval) + case EApp(_, args) => ifPostCall = true + case ECall(_, _, _, _) => ifPostCall = true + } +} diff --git a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala index d82b90f4..4b8a303b 100644 --- a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala @@ -33,11 +33,37 @@ object LockRegionChecker extends TypeChecks[Id, LockState] { case _ => throw UnexpectedCase(m.pos) }) - val finalStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) - finalStates.getMappedKeys().foreach(m => finalStates(m) match { - case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, finalStates(m), Locks.Released) - case _ => () - }) + // let read lock release + m.commit_blk match { + case Some(commit_blk) => + val postBodyStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) + postBodyStates.getMappedKeys().foreach(m => postBodyStates(m) match { + case Locks.Released => throw InvalidLockState(m.pos, m.v, postBodyStates(m), Locks.Released) + case _ => () + }) + val postCommitStates: Environment[Id, LockState] = checkLockRegions(commit_blk, nenv) + postCommitStates.getMappedKeys().foreach(m => postCommitStates(m) match { + case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postCommitStates(m), Locks.Released) + case _ => () + }) + case _ => + val postBodyStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) + postBodyStates.getMappedKeys().foreach(m => postBodyStates(m) match { + case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postBodyStates(m), Locks.Released) + case _ => () + }) + } + + m.except_blk match { + case ExceptEmpty() => () + case ExceptFull(args, c) => + nenv.getMappedKeys().foreach(m => nenv.add(m, Free)) + val postExceptStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) + postExceptStates.getMappedKeys().foreach(m => postExceptStates(m) match { + case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postExceptStates(m), Locks.Released) + case _ => () + }) + } env //no change to lock map after checking module } @@ -91,7 +117,7 @@ object LockRegionChecker extends TypeChecks[Id, LockState] { throw InvalidLockState(c.pos, lock.v, env(lock), Acquired) } env - //can only reserve locks insisde of the relevant lock region + //can only reserve locks inside of the relevant lock region //other lock ops can be outside of this pass case CLockOp(mem, op, _, _, _) if op == Reserved => if (env(mem.id) != Acquired) { @@ -101,6 +127,7 @@ object LockRegionChecker extends TypeChecks[Id, LockState] { case CAssign(lhs, rhs) => checkMemAccess(lhs, env); checkMemAccess(rhs, env); env case CRecv(lhs, rhs) => checkMemAccess(lhs, env); checkMemAccess(rhs, env); env case Syntax.CEmpty() => env + case CExcept(args) => args.foreach(a => checkMemAccess(a, env)); env case _ => env } @@ -138,6 +165,5 @@ object LockRegionChecker extends TypeChecks[Id, LockState] { case _ => () } - override def checkCircuit(c: Circuit, env: Environment[Id, LockState]): Environment[Id, LockState] = env } From 7840a73513d4c4a56f9e1b0add3ab46f59a7d4bf Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Tue, 19 Apr 2022 06:50:26 -0400 Subject: [PATCH 10/38] fix some ast --- src/main/scala/pipedsl/passes/ConvertExnModulePass.scala | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 src/main/scala/pipedsl/passes/ConvertExnModulePass.scala diff --git a/src/main/scala/pipedsl/passes/ConvertExnModulePass.scala b/src/main/scala/pipedsl/passes/ConvertExnModulePass.scala deleted file mode 100644 index 18bd631f..00000000 --- a/src/main/scala/pipedsl/passes/ConvertExnModulePass.scala +++ /dev/null @@ -1,5 +0,0 @@ -package pipedsl.passes - -object ConvertExnModulePass { - -} From 4f5a9a5543ddb6dc67de8e00b102bdaf1793fbd9 Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Mon, 2 May 2022 04:24:11 -0400 Subject: [PATCH 11/38] type checking working for exceptions? only positively --- src/main/scala/pipedsl/common/Errors.scala | 8 ++ src/main/scala/pipedsl/common/Syntax.scala | 11 +++ .../pipedsl/passes/BindModuleTypes.scala | 2 +- .../passes/LockOpTranslationPass.scala | 8 +- .../pipedsl/passes/PredicateGenerator.scala | 3 +- .../pipedsl/passes/SimplifyRecvPass.scala | 2 +- .../pipedsl/typechecker/BaseTypeChecker.scala | 3 +- .../typechecker/LinearExecutionChecker.scala | 48 ++++++++++-- .../typechecker/LockConstraintChecker.scala | 59 +++++++------- .../typechecker/LockRegionChecker.scala | 78 ++++++++++++------- .../typechecker/LockWellformedChecker.scala | 6 +- .../typechecker/TimingTypeChecker.scala | 16 ++-- 12 files changed, 159 insertions(+), 85 deletions(-) diff --git a/src/main/scala/pipedsl/common/Errors.scala b/src/main/scala/pipedsl/common/Errors.scala index 8bd69c1c..a4d3ee07 100644 --- a/src/main/scala/pipedsl/common/Errors.scala +++ b/src/main/scala/pipedsl/common/Errors.scala @@ -221,4 +221,12 @@ object Errors { case class ReleaseWhenMaybeExcepting(p :Position) extends RuntimeException( withPos(s"No no no! No releasing when you might be excepting!!", p) ) + + case class MalformedExceptBlock(p :Position) extends RuntimeException( + withPos("Mistake in except block.", p) + ) + + case class IllegalThrowPlacement(p :Position) extends RuntimeException( + withPos("Throw not allowed here.", p) + ) } diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 4861430c..1d3b1416 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -691,6 +691,7 @@ object Syntax { sealed trait ExceptBlock extends Positional with HasCopyMeta { def map(f : Command => Command) : ExceptBlock + def foreach(f : Command => Unit) :Unit def get :Command def copyMeta(other :ExceptBlock) = this.setPos(other.pos) } @@ -699,11 +700,13 @@ object Syntax { case class ExceptEmpty() extends ExceptBlock { override def map(f: Command => Command): ExceptBlock = this + override def foreach(f: Command => Unit): Unit = () override def get :Command = throw new NoSuchElementException("EmptyExcept") } case class ExceptFull(args: List[Id], c: Command) extends ExceptBlock { override def map(f: Command => Command): ExceptBlock = ExceptFull(args, f(c)).copyMeta(this) + override def foreach(f: Command => Unit): Unit = f(c) override def get :Command = c } @@ -725,6 +728,14 @@ object Syntax { this case _ => this } + + def command_map(f : Command => Command) :ModuleDef = copy(body = f(body), + commit_blk = commit_blk.map(f), except_blk = except_blk.map(f)) + + def extendedBody(): Command = commit_blk match { + case None => body + case Some(c) => CSeq(body, c) + } } def is_excepting(m :ModuleDef) :Boolean = m.except_blk match diff --git a/src/main/scala/pipedsl/passes/BindModuleTypes.scala b/src/main/scala/pipedsl/passes/BindModuleTypes.scala index 65385626..7aae8ed0 100644 --- a/src/main/scala/pipedsl/passes/BindModuleTypes.scala +++ b/src/main/scala/pipedsl/passes/BindModuleTypes.scala @@ -15,7 +15,7 @@ class BindModuleTypes(val tenv: Environment[Id, Type]) extends ProgPass[Prog] { } def run(m: ModuleDef): ModuleDef = { - m.copy(modules = m.modules.map(p => Param(p.name, replaceNamedType(p.typ))), commit_blk = None, except_blk = ExceptEmpty()).copyMeta(m) + m.copy(modules = m.modules.map(p => Param(p.name, replaceNamedType(p.typ)))).copyMeta(m) } private def replaceNamedType(t: Type): Type = t match { diff --git a/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala b/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala index ff5afb36..0cabb517 100644 --- a/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala @@ -62,13 +62,7 @@ object LockOpTranslationPass extends ProgPass[Prog] with CommandPass[Command] wi p.copy(moddefs = p.moddefs.map(run)) } - override def run(m: ModuleDef): ModuleDef = - { - val nm = m.copy(body = run(m.body), commit_blk = None, except_blk = ExceptEmpty()) - nm.isRecursive = m.isRecursive - nm.maybeSpec = m.maybeSpec - nm - } + override def run(m: ModuleDef): ModuleDef = m.command_map(run).copyMeta(m) override def run(c: Command): Command = c match { diff --git a/src/main/scala/pipedsl/passes/PredicateGenerator.scala b/src/main/scala/pipedsl/passes/PredicateGenerator.scala index 9e52c8bb..fe898bb9 100644 --- a/src/main/scala/pipedsl/passes/PredicateGenerator.scala +++ b/src/main/scala/pipedsl/passes/PredicateGenerator.scala @@ -22,7 +22,8 @@ class PredicateGenerator extends ProgPass[Z3Context] { private def run(m: ModuleDef): Unit = { //no need to reset any state here, at the end of a module predicates will be just true - annotateCommand(m.body) + annotateCommand(m.extendedBody()) + m.except_blk.foreach(annotateCommand) } private def annotateCommand(c: Command): Unit = { diff --git a/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala b/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala index 7be5a4af..cbf97313 100644 --- a/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala +++ b/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala @@ -24,7 +24,7 @@ object SimplifyRecvPass extends CommandPass[Command] with ModulePass[ModuleDef] override def run(m: ModuleDef): ModuleDef = { usedVars = m.modules.foldLeft[Set[Id]](usedVars)((s,p) => s + p.name) - m.copy(body = run(m.body), commit_blk = None, except_blk = ExceptEmpty()).setPos(m.pos).copyMeta(m) + m.copy(body = run(m.body), commit_blk = m.commit_blk.map(run), except_blk = m.except_blk.map(run)).setPos(m.pos).copyMeta(m) } override def run(c: Command): Command = { diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index 93b4d506..8f39a792 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -95,7 +95,8 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { val bodyEnv = pipeEnv.add(m.name, modTyp) val outEnv = tenv.add(m.name, modTyp) checkModuleBodyWellFormed(m.body, Set()) - checkCommand(m.name, m.body, bodyEnv) + checkCommand(m.name, m.extendedBody(), bodyEnv) + m.except_blk.foreach(checkCommand(m.name, _, bodyEnv)) outEnv } diff --git a/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala b/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala index 3eadefa4..79a4e93b 100644 --- a/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala @@ -22,6 +22,7 @@ class LinearExecutionChecker(val ctx: Z3Context) extends TypeChecks[Id, Z3AST] private val solver: Z3Solver = ctx.mkSolver() private val predicates: mutable.Stack[Z3AST] = mutable.Stack(ctx.mkFalse()) + private val except_pred :mutable.Stack[Z3AST] = mutable.Stack(ctx.mkFalse()) private var currentPipe: Id = null override def emptyEnv(): Environments.Environment[Id, Z3AST] = null @@ -40,20 +41,49 @@ class LinearExecutionChecker(val ctx: Z3Context) extends TypeChecks[Id, Z3AST] { predicates.clear() predicates.push(ctx.mkFalse()) + except_pred.clear() + except_pred.push(ctx.mkFalse()) currentPipe = m.name - checkCommand(m.body) - checkAllRecurse() match - { - case Z3Status.SATISFIABLE | Z3Status.UNKNOWN => - throw LonelyPaths(m.name) - case _ => + m.except_blk match { + case ExceptEmpty() => + checkCommand(m.body) + checkAllRecurse() match + { + case Z3Status.SATISFIABLE | Z3Status.UNKNOWN => + throw LonelyPaths(m.name) + case _ => + } + env + case ExceptFull(args, c) => + checkCommand(c) + checkAllRecurse() match { + case Z3Status.SATISFIABLE | Z3Status.UNKNOWN => + throw LonelyPaths(m.name) + case _ => () + } + predicates.clear() + predicates.push(ctx.mkFalse()) + checkCommand(m.extendedBody()) + checkAllRecurse() match { + case Z3Status.SATISFIABLE | Z3Status.UNKNOWN => + throw LonelyPaths(m.name) + case _ => () + env + } + } - env + } override def checkCircuit(c: Circuit, env: Environments.Environment[Id, Z3AST]): Environments.Environment[Id, Z3AST] = env + + /* + Output xor call. + + + */ def checkCommand(c: Command): Unit = { c match @@ -65,6 +95,7 @@ class LinearExecutionChecker(val ctx: Z3Context) extends TypeChecks[Id, Z3AST] for (caseObj <- cases) checkCommand(caseObj.body) checkCommand(default) case COutput(_) => verifyRecursive(c.predicateCtx.get, c.pos) + case CExcept(_) => except_pred.push(c.predicateCtx.get) case CVerify(_, args, _, _, _) => val pred = c.predicateCtx.get args.foreach(a => checkExpr(a, pred)) @@ -124,7 +155,8 @@ class LinearExecutionChecker(val ctx: Z3Context) extends TypeChecks[Id, Z3AST] * Checks to see if all the predicates together form a tautology */ def checkAllRecurse(): Z3Status = { - solver.add(ctx.mkNot(mkOr(ctx, predicates.toSeq: _*))) + val all_conds :Seq[Z3AST] = predicates.toSeq.appendedAll(except_pred) + solver.add(ctx.mkNot(mkOr(ctx, all_conds :_*))) val check = solver.check() solver.reset() check diff --git a/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala index d588f7c3..62cc0862 100644 --- a/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala @@ -62,32 +62,39 @@ class LockConstraintChecker(lockMap: Map[Id, Set[LockArg]], lockGranularityMap: override def checkFunc(f: FuncDef, env: Environment[LockArg, Z3AST]): Environment[LockArg, Z3AST] = env override def checkModule(m: ModuleDef, env: Environment[LockArg, Z3AST]): Environment[LockArg, Z3AST] = { - //Reads must go before writes, so the modes are initialized to read - lockGranularityMap(m.name) - .filter(l => l._2 == Specific) - .keys - .foreach(l => { - topLevelReserveModeMap += (l -> mkImplies(ctx, ctx.mkTrue(), ctx.mkEq(lockReserveMode, ctx.mkInt(READ)))) - topLevelReleaseModeMap += (l -> mkImplies(ctx, ctx.mkTrue(), ctx.mkEq(lockReleaseMode, ctx.mkInt(READ)))) - SMTReserveModeListMap += (l -> Set()) - SMTReleaseModeListMap += (l -> Set()) + checkChunk(m.name, m.extendedBody(), env) + m.except_blk.foreach(checkChunk(m.name, _, env)) + env + } + + def checkChunk(name :Id, c :Command, env :Environment[LockArg, Z3AST]) :Environment[LockArg, Z3AST] = + { + //Reads must go before writes, so the modes are initialized to read + lockGranularityMap(name) + .filter(l => l._2 == Specific) + .keys + .foreach(l => { + topLevelReserveModeMap += (l -> mkImplies(ctx, ctx.mkTrue(), ctx.mkEq(lockReserveMode, ctx.mkInt(READ)))) + topLevelReleaseModeMap += (l -> mkImplies(ctx, ctx.mkTrue(), ctx.mkEq(lockReleaseMode, ctx.mkInt(READ)))) + SMTReserveModeListMap += (l -> Set()) + SMTReleaseModeListMap += (l -> Set()) + }) + currentMod = name + writeDoMap.clear(); writeReserveMap.clear() + val nenv = lockMap(name).foldLeft[Environment[LockArg, Z3AST]](emptyEnv())((e, mem) => e.add(mem, makeEquals(mem, Free))) + val finalenv = checkCommand(c, nenv) + //At end of execution all locks must be free or released + finalenv.getMappedKeys().foreach(id => { + checkState(id, finalenv, ctx.mkTrue(), Released.order, Free.order) match { + case Z3Status.SATISFIABLE => + throw new RuntimeException("We want everything at end to be free or released") + case _ => + } }) - currentMod = m.name - writeDoMap.clear(); writeReserveMap.clear() - val nenv = lockMap(m.name).foldLeft[Environment[LockArg, Z3AST]](emptyEnv())((e, mem) => e.add(mem, makeEquals(mem, Free))) - val finalenv = checkCommand(m.body, nenv) - //At end of execution all locks must be free or released - finalenv.getMappedKeys().foreach(id => { - checkState(id, finalenv, ctx.mkTrue(), Released.order, Free.order) match { - case Z3Status.SATISFIABLE => - throw new RuntimeException("We want everything at end to be free or released") - case _ => - } - }) - writeReserveMap.foreachEntry((mem, when_reserved) => + writeReserveMap.foreachEntry((mem, when_reserved) => { solver.add(ctx.mkXor(when_reserved, writeDoMap.getOrElse(mem, - throw new RuntimeException("Some write locks are reserved without being used")))) + throw new RuntimeException("Some write locks are reserved without being used")))) solver.check() match { case Z3Status.UNSATISFIABLE => @@ -96,9 +103,8 @@ class LockConstraintChecker(lockMap: Map[Id, Set[LockArg]], lockGranularityMap: case Z3Status.SATISFIABLE => throw new RuntimeException("Some write locks are reserved without being used") }}) - - env //no change to lock map after checking module - } + env //no change to lock map after checking module + } def checkCommand(c: Command, env: Environment[LockArg, Z3AST]): Environment[LockArg, Z3AST] = { c match { @@ -284,7 +290,6 @@ class LockConstraintChecker(lockMap: Map[Id, Set[LockArg]], lockGranularityMap: } private def checkState(mem: LockArg, env: Environment[LockArg, Z3AST], predicates: Z3BoolExpr, lockStateOrders: Int*): Z3Status = { - // Makes an OR of all given lock states val stateAST = lockStateOrders.foldLeft(ctx.mkFalse())((ast, order) => ctx.mkOr(ast, ctx.mkEq(ctx.mkIntConst(constructVarName(mem)), ctx.mkInt(order)))) diff --git a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala index 4b8a303b..5208c66a 100644 --- a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala @@ -14,6 +14,7 @@ import pipedsl.typechecker.TypeChecker.TypeChecks * - Checks: That all lock "reserve" statements occur inside the appropriate lock region. * - Checks: That all lock regions are well formed according to the above. */ + object LockRegionChecker extends TypeChecks[Id, LockState] { override def emptyEnv(): Environment[Id, LockState] = Environments.EmptyLockEnv @@ -33,37 +34,54 @@ object LockRegionChecker extends TypeChecks[Id, LockState] { case _ => throw UnexpectedCase(m.pos) }) - // let read lock release - m.commit_blk match { - case Some(commit_blk) => - val postBodyStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) - postBodyStates.getMappedKeys().foreach(m => postBodyStates(m) match { - case Locks.Released => throw InvalidLockState(m.pos, m.v, postBodyStates(m), Locks.Released) - case _ => () - }) - val postCommitStates: Environment[Id, LockState] = checkLockRegions(commit_blk, nenv) - postCommitStates.getMappedKeys().foreach(m => postCommitStates(m) match { - case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postCommitStates(m), Locks.Released) - case _ => () - }) - case _ => - val postBodyStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) - postBodyStates.getMappedKeys().foreach(m => postBodyStates(m) match { - case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postBodyStates(m), Locks.Released) - case _ => () - }) - } + val finalStates: Environment[Id, LockState] = checkLockRegions(m.extendedBody(), nenv) + finalStates.getMappedKeys().foreach(m => finalStates(m) match { + case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, finalStates(m), Locks.Released) + case _ => () + }) - m.except_blk match { - case ExceptEmpty() => () - case ExceptFull(args, c) => - nenv.getMappedKeys().foreach(m => nenv.add(m, Free)) - val postExceptStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) - postExceptStates.getMappedKeys().foreach(m => postExceptStates(m) match { - case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postExceptStates(m), Locks.Released) - case _ => () - }) - } + m.except_blk.foreach(checkLockRegions(_, nenv).getMappedKeys().foreach(m => finalStates(m) match { + case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, finalStates(m), Locks.Released) + case _ => () + })) + +// +// // let read lock release +// m.commit_blk match { +// case Some(commit_blk) => +// val postBodyStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) +// postBodyStates.getMappedKeys().foreach(m => { +// println(m.typ); +// postBodyStates(m) match { +// case Locks.Released => () +// case _ => +// throw InvalidLockState(m.pos, m.v, postBodyStates(m), Locks.Released) +// } +// } +// ) +// val postCommitStates: Environment[Id, LockState] = checkLockRegions(commit_blk, nenv) +// postCommitStates.getMappedKeys().foreach(m => postCommitStates(m) match { +// case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postCommitStates(m), Locks.Released) +// case _ => () +// }) +// case _ => +// val postBodyStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) +// postBodyStates.getMappedKeys().foreach(m => postBodyStates(m) match { +// case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postBodyStates(m), Locks.Released) +// case _ => () +// }) +// } +// +// m.except_blk match { +// case ExceptEmpty() => () +// case ExceptFull(args, c) => +// nenv.getMappedKeys().foreach(m => nenv.add(m, Free)) +// val postExceptStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) +// postExceptStates.getMappedKeys().foreach(m => postExceptStates(m) match { +// case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postExceptStates(m), Locks.Released) +// case _ => () +// }) +// } env //no change to lock map after checking module } diff --git a/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala b/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala index 240ac510..831f560e 100644 --- a/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala @@ -2,6 +2,7 @@ package pipedsl.typechecker import pipedsl.common.Errors.MalformedLockTypes import pipedsl.common.Locks.{General, LockGranularity, Specific} +import pipedsl.common.Syntax import pipedsl.common.Syntax.{CIf, CLockOp, CSeq, CSplit, CTBar, Command, Id, LockArg, ModuleDef, Prog} /** @@ -40,7 +41,10 @@ class LockWellformedChecker() { private def checkModule(moduleDef: ModuleDef, set: Set[LockArg]): Set[LockArg] = { currentMod = moduleDef.name - checkCommand(moduleDef.body, set) + checkCommand(moduleDef.extendedBody(), set).union(moduleDef.except_blk match { + case Syntax.ExceptEmpty() => Set() + case Syntax.ExceptFull(_, c) => checkCommand(c, set) + }) } private def checkCommand(command: Command, lockArgs: Set[LockArg]): Set[LockArg] = command match { diff --git a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala index a7747578..00055f30 100644 --- a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala @@ -35,18 +35,18 @@ object TimingTypeChecker extends TypeChecks[Id, Type] { val allAvailable = m.modules.foldLeft[Available](inputs)((av, m) => { av + m.name }) - checkCommand(m.body, allAvailable, NoneAvailable) + checkCommand(m.extendedBody(), allAvailable, NoneAvailable) + m.except_blk match { + case ExceptEmpty() => () + case ExceptFull(args, c) => val inputs = args.foldLeft[Available](NoneAvailable)((av, p) => av + p) + val allAvailable = m.modules.foldLeft(inputs)((av, m) => av + m.name) + checkCommand(c, allAvailable, NoneAvailable) + } env } /** - * TODO comment - * @param lhs - * @param rhs - * @param isRecv - * @param vars - * @param nextVars - * @return + * checks a receive or assign command. */ private def check_recv_or_asn(lhs :Expr, rhs :Expr, isRecv :Boolean, vars: Available, nextVars: Available): (Available, Available) = From 8c8f56b711aeb59ff38241efe4c0192588d51eaa Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Wed, 4 May 2022 23:43:32 -0400 Subject: [PATCH 12/38] untested, but done? --- src/main/scala/pipedsl/Main.scala | 3 +- src/main/scala/pipedsl/common/Errors.scala | 12 ++ .../FinalblocksConstraintChecker.scala | 186 ++++++++++++++---- .../LockOperationTypeChecker.scala | 3 +- .../typechecker/LockRegionChecker.scala | 37 ---- 5 files changed, 159 insertions(+), 82 deletions(-) diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index 7343a820..edd1b89c 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -82,7 +82,7 @@ object Main { val verifProg = AddCheckpointHandlesPass.run(AddVerifyValuesPass.run(inferredProg)) val canonProg2 = new CanonicalizePass().run(verifProg) val canonProg = new TypeInference(autocast).checkProgram(canonProg2) - new PrettyPrinter(None).printProgram(canonProg) + // new PrettyPrinter(None).printProgram(canonProg) val basetypes = BaseTypeChecker.check(canonProg, None) FunctionConstraintChecker.check(canonProg) @@ -101,6 +101,7 @@ object Main { val lockChecker = new LockConstraintChecker(locks, lockWellformedChecker.getModLockGranularityMap, ctx) lockChecker.check(recvProg, None) LockReleaseChecker.check(recvProg) + FinalblocksConstraintChecker.check(recvProg) val linChecker = new LinearExecutionChecker(ctx) linChecker.check(recvProg, None) val specChecker = new SpeculationChecker(ctx) diff --git a/src/main/scala/pipedsl/common/Errors.scala b/src/main/scala/pipedsl/common/Errors.scala index a4d3ee07..e6d13bce 100644 --- a/src/main/scala/pipedsl/common/Errors.scala +++ b/src/main/scala/pipedsl/common/Errors.scala @@ -229,4 +229,16 @@ object Errors { case class IllegalThrowPlacement(p :Position) extends RuntimeException( withPos("Throw not allowed here.", p) ) + + case class MustEndBeforeCall(p :Position) extends RuntimeException( + withPos("Must not have any open lock regions when calling from except block", p) + ) + + case class NoCommittingWriteInBody(p :Position) extends RuntimeException( + withPos("No committing writes in the main body!", p) + ) + + case class NoWriteReleaseInBody(p :Position) extends RuntimeException( + withPos("No release writes in the main body!", p) + ) } diff --git a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala index f5a32a78..c0d884d4 100644 --- a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala +++ b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala @@ -1,62 +1,162 @@ package pipedsl.typechecker import org.apache.commons.io.filefilter.FalseFileFilter +import org.graalvm.compiler.nodes.virtual.LockState import pipedsl.common.Syntax._ import pipedsl.typechecker.Environments._ import pipedsl.common.Errors._ +import pipedsl.common.Locks.{General, Released} +import pipedsl.common.Syntax +import pipedsl.typechecker.TypeChecker.TypeChecks -class FinalblocksConstraintChecker { - private var currentMod: Id = Id("-invalid-") - private var ifPostCall: Boolean = false - private var hasCommitBlk: Boolean = false +object FinalblocksConstraintChecker { - def check(p:Prog) : Unit = { - val Prog(_, _, moddefs, _) = p - moddefs.foreach(m => checkModule(m)) + def check(p :Prog) :Unit = + { + p.moddefs.foreach(checkModule) + } + + private def checkModule(m :ModuleDef) :Unit = + { + m.except_blk match { + case ExceptEmpty() => checkNormBody(m.body) + case ExceptFull(args, c) => + checkExBody(m.body) + checkExceptingBlock(c) + } } - private def checkModule(moduleDef: ModuleDef): Unit = { - currentMod = moduleDef.name - ifPostCall = false - hasCommitBlk = false + private sealed trait ExnStatus + private case object NonExn extends ExnStatus + private case object PreCall extends ExnStatus + private case object PostCall extends ExnStatus - moduleDef.commit_blk match { - case Some(c) => - hasCommitBlk = true - checkCommand(c) - case _ => () - } - moduleDef.except_blk match { - case ExceptEmpty() => () - case ExceptFull(args, c) if (hasCommitBlk == true) => checkCommand(c) - case ExceptFull(args, c) if (hasCommitBlk == false) => - throw MalformedExceptBlock(c.pos) - } + private def lub(e1 :ExnStatus, e2 :ExnStatus) :ExnStatus = (e1, e2) match { + case (PreCall, PostCall) | (PostCall, PreCall) => PostCall + case (x, y) if x == y => x + case _ => throw new RuntimeException("Bad lub of exnstati") } - private def checkCommand(command: Command): Unit = command match { - case CSeq(c1, c2) => val s1 = checkCommand(c1); checkCommand(c2) - case CTBar(c1, c2) => val s1 = checkCommand(c1); checkCommand(c2) - case CIf(_, cons, alt) => val s1 = checkCommand(cons); checkCommand(alt) - case CSplit(cases, default) => - checkCommand(default) - case CLockOp(mem, _, _, _, _) => - if (ifPostCall == true) throw MalformedLockTypes("Cannot Reserve any locks after a call") - case CAssign(lhs, rhs) => checkExpr(lhs); checkExpr(rhs) - case CRecv(lhs, rhs) => checkExpr(lhs); checkExpr(rhs) - case CExcept(args) => throw IllegalThrowPlacement(command.pos) + private def after_call(e :ExnStatus) = e match { + case NonExn => NonExn + case _ => PostCall + } + + + private def checkExBody(c :Command) :Unit = c match { + case CSeq(c1, c2) => checkExBody(c1); checkExBody(c2) + case CTBar(c1, c2) => checkExBody(c1); checkExBody(c2) + case CIf(_, cons, alt) => checkExBody(cons); checkExBody(alt) + case CRecv(EMemAccess(mem, _, _, _, _, isAtomic), _) if isAtomic || !isLockedMemory(mem)=> throw NoCommittingWriteInBody(c.pos) + case c@CLockOp(mem, Released, _, _, _) if c.memOpType.contains(LockWrite) || c.granularity == General => throw NoWriteReleaseInBody(c.pos) + case CSplit(cases, default) => checkExBody(default); cases.foreach(co => checkExBody(co.body)) case _ => () } - private def checkExpr(e: Expr): Unit = e match { - case EIsValid(ex) => checkExpr(ex) - case EFromMaybe(ex) => checkExpr(ex) - case EToMaybe(ex) => checkExpr(ex) - case EUop(_, ex) => checkExpr(ex) - case EBinop(_, e1, e2) => checkExpr(e1); checkExpr(e2) - case ETernary(cond, tval, fval) => checkExpr(cond); checkExpr(tval); checkExpr(fval) - case EApp(_, args) => ifPostCall = true - case ECall(_, _, _, _) => ifPostCall = true + private def checkExceptingBlock(c :Command) :Unit = checkNoThrow(c, PreCall) + + private def checkNormBody(c: Command) :Unit = checkNoThrow(c, NonExn) + + + private def checkNoThrow(c :Command, estat :ExnStatus) :ExnStatus = c match { + case CSeq(c1, c2) => checkNoThrow(c2, checkNoThrow(c1, estat)) + case CTBar(c1, c2) => checkNoThrow(c2, checkNoThrow(c1, estat)) + case CIf(cond, cons, alt) => lub(checkNoThrow(cons, estat), checkNoThrow(alt, estat)) + case CAssign(lhs, rhs) => checkNoThrowExpr(rhs, estat) + case CRecv(lhs, rhs) => checkNoThrowExpr(rhs, estat) + case CSpecCall(handle, pipe, args) => after_call(estat) + case CUpdate(newHandle, handle, args, preds, checkHandles) => args.foldLeft(estat)((es, ex) => lub(es, checkNoThrowExpr(ex, estat))) + case CPrint(args) => args.foldLeft(estat)((es, ex) => lub(estat, checkNoThrowExpr(ex, estat))) + case COutput(exp) => checkNoThrowExpr(exp, estat) + case CReturn(exp) => checkNoThrowExpr(exp, estat) + case CExpr(exp) => checkNoThrowExpr(exp, estat) + case CLockEnd(mod) if estat == PostCall => throw MustEndBeforeCall(c.pos) + case CLockOp(mem, op, lockType, args, ret) => args.foldLeft(estat)((es, ex) => lub(es, checkNoThrowExpr(ex, estat))) + case CSplit(cases, default) => cases.foldLeft(checkNoThrow(default, estat))((es, co) => lub(checkNoThrow(co.body, estat), es)) + case CExcept(_) => throw IllegalThrowPlacement(c.pos) + case _ => estat } + + private def checkNoThrowExpr(e :Expr, estat :ExnStatus) :ExnStatus = + { + def reccall(e :Expr) :ExnStatus = checkNoThrowExpr(e, estat) + e match { + case EIsValid(ex) => reccall(ex) + case EFromMaybe(ex) => reccall(ex) + case EToMaybe(ex) => reccall(ex) + case EUop(_, ex) => reccall(ex) + case EBinop(_, e1, e2) => lub(reccall(e1), reccall(e2)) + case ERecAccess(rec, _) => reccall(rec) + case ERecLiteral(fields) => fields.foldLeft(estat)((es, idex) => lub(reccall(idex._2), es)) + case EMemAccess(_, index, _, _, _, _) => reccall(index) + case EBitExtract(num, _, _) => reccall(num) + case ETernary(_, tval, fval) => lub(reccall(tval), reccall(fval)) + case EApp(_, args) => args.foldLeft(estat)((es, ex) => lub(reccall(ex), es)) + case _ :ECall => estat match { + case NonExn => NonExn + case _ => PostCall + } + case ECast(_, exp) => reccall(exp) + case _ => estat + } + } + + + + +// private var currentMod: Id = Id("-invalid-") +// private var ifPostCall: Boolean = false +// private var hasCommitBlk: Boolean = false +// +// def check(p:Prog) : Unit = { +// val Prog(_, _, moddefs, _) = p +// moddefs.foreach(m => checkModule(m)) +// } +// +// private def checkModule(moduleDef: ModuleDef): Unit = { +// currentMod = moduleDef.name +// ifPostCall = false +// hasCommitBlk = false +// +// moduleDef.commit_blk match { +// case Some(c) => +// hasCommitBlk = true +// checkCommand(c) +// case _ => () +// } +// +// moduleDef.except_blk match { +// case ExceptEmpty() => () +// case ExceptFull(args, c) if (hasCommitBlk == true) => checkCommand(c) +// case ExceptFull(args, c) if (hasCommitBlk == false) => +// throw MalformedExceptBlock(c.pos) +// } +// } +// +// private def checkCommand(command: Command): Unit = command match { +// case CSeq(c1, c2) => val s1 = checkCommand(c1); checkCommand(c2) +// case CTBar(c1, c2) => val s1 = checkCommand(c1); checkCommand(c2) +// case CIf(_, cons, alt) => val s1 = checkCommand(cons); checkCommand(alt) +// case CSplit(cases, default) => +// checkCommand(default) +// case CLockOp(mem, _, _, _, _) => +// if (ifPostCall == true) throw MalformedLockTypes("Cannot Reserve any locks after a call") +// case CAssign(lhs, rhs) => checkExpr(lhs); checkExpr(rhs) +// case CRecv(lhs, rhs) => checkExpr(lhs); checkExpr(rhs) +// case CExcept(args) => throw IllegalThrowPlacement(command.pos) +// case _ => () +// } +// +// private def checkExpr(e: Expr): Unit = e match { +// case EIsValid(ex) => checkExpr(ex) +// case EFromMaybe(ex) => checkExpr(ex) +// case EToMaybe(ex) => checkExpr(ex) +// case EUop(_, ex) => checkExpr(ex) +// case EBinop(_, e1, e2) => checkExpr(e1); checkExpr(e2) +// case ETernary(cond, tval, fval) => checkExpr(cond); checkExpr(tval); checkExpr(fval) +// case EApp(_, args) => ifPostCall = true +// case ECall(_, _, _, _) => ifPostCall = true +// } + } diff --git a/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala b/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala index 541dac5b..3cb4f551 100644 --- a/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala @@ -44,7 +44,8 @@ class LockOperationTypeChecker(val memGranularityMap:Map[Id, Map[Id, LockGranula private def checkModule(moduleDef: ModuleDef): Unit = { currentMod = moduleDef.name - checkCommand(moduleDef.body) + checkCommand(moduleDef.extendedBody()) + moduleDef.except_blk.foreach(checkCommand) } private def checkCommand(command: Command): Unit = command match { diff --git a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala index 5208c66a..a47079a5 100644 --- a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala @@ -45,43 +45,6 @@ object LockRegionChecker extends TypeChecks[Id, LockState] { case _ => () })) -// -// // let read lock release -// m.commit_blk match { -// case Some(commit_blk) => -// val postBodyStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) -// postBodyStates.getMappedKeys().foreach(m => { -// println(m.typ); -// postBodyStates(m) match { -// case Locks.Released => () -// case _ => -// throw InvalidLockState(m.pos, m.v, postBodyStates(m), Locks.Released) -// } -// } -// ) -// val postCommitStates: Environment[Id, LockState] = checkLockRegions(commit_blk, nenv) -// postCommitStates.getMappedKeys().foreach(m => postCommitStates(m) match { -// case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postCommitStates(m), Locks.Released) -// case _ => () -// }) -// case _ => -// val postBodyStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) -// postBodyStates.getMappedKeys().foreach(m => postBodyStates(m) match { -// case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postBodyStates(m), Locks.Released) -// case _ => () -// }) -// } -// -// m.except_blk match { -// case ExceptEmpty() => () -// case ExceptFull(args, c) => -// nenv.getMappedKeys().foreach(m => nenv.add(m, Free)) -// val postExceptStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) -// postExceptStates.getMappedKeys().foreach(m => postExceptStates(m) match { -// case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, postExceptStates(m), Locks.Released) -// case _ => () -// }) -// } env //no change to lock map after checking module } From c60610ec58cd29dc5fb9a51e12b7c0f135bf6f12 Mon Sep 17 00:00:00 2001 From: dz333 Date: Thu, 5 May 2022 11:00:24 -0400 Subject: [PATCH 13/38] added useful code for generating abort calls --- .../scala/pipedsl/common/LockImplementation.scala | 15 +++++++++++++++ .../FinalblocksConstraintChecker.scala | 2 -- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/scala/pipedsl/common/LockImplementation.scala b/src/main/scala/pipedsl/common/LockImplementation.scala index 3d452493..e500760e 100644 --- a/src/main/scala/pipedsl/common/LockImplementation.scala +++ b/src/main/scala/pipedsl/common/LockImplementation.scala @@ -61,6 +61,7 @@ object LockImplementation { private val checkpointName = "checkpoint" private val rollbackName = "rollback" + private val abortName = "abort" private def toPortString(port: Option[Int]): String = port match { case Some(value) => value.toString @@ -147,6 +148,10 @@ object LockImplementation { l.getType.methods.get(Id(rollbackName)) } + def getAbort(l: LockInterface): Option[(TFun, Latency)] = { + l.getType.methods.get(Id(abortName)) + } + //-------Methods for translation info--------------------------\\ private val lockIntStr = "lock." def getCanReserveInfo(l: IReserveLock): Option[MethodInfo] = { @@ -279,6 +284,16 @@ object LockImplementation { } } + def getAbortInfo(mem: Id): Option[MethodInfo] = { + val interface = getLockImplFromMemTyp(mem) + getAbort(interface) match { + case Some(_) => + val methodName = (if(interface.hasLockSubInterface) lockIntStr else "") + abortName + Some(MethodInfo(methodName, doesModify = true, List())) + case None => None + } + } + private def extractHandle(h: Expr): Expr = { val e = EFromMaybe(h).setPos(h.pos) e.typ = h.typ.get.matchOrError(h.pos, "Lock Handle", "Maybe type") { diff --git a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala index c0d884d4..a08ad17f 100644 --- a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala +++ b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala @@ -1,7 +1,5 @@ package pipedsl.typechecker -import org.apache.commons.io.filefilter.FalseFileFilter -import org.graalvm.compiler.nodes.virtual.LockState import pipedsl.common.Syntax._ import pipedsl.typechecker.Environments._ import pipedsl.common.Errors._ From 2431f4d23f32f1dfcbb8f23d431a769ceeb99f93 Mon Sep 17 00:00:00 2001 From: dz333 Date: Thu, 5 May 2022 13:26:10 -0400 Subject: [PATCH 14/38] added a simple abort-able lock --- bscRuntime/memories/Locks.bsv | 40 +++++++++++-------- bscRuntime/memories/Memories.bsv | 24 ++++++++--- .../pipedsl/common/LockImplementation.scala | 3 +- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/bscRuntime/memories/Locks.bsv b/bscRuntime/memories/Locks.bsv index 41d8f6e8..b54b018a 100644 --- a/bscRuntime/memories/Locks.bsv +++ b/bscRuntime/memories/Locks.bsv @@ -4,6 +4,7 @@ import FIFOF :: *; import Ehr :: *; import Vector :: *; import ConfigReg :: *; +import GetPut :: *; export LockId(..); export QueueLock(..); export CheckpointQueueLock(..); @@ -21,19 +22,20 @@ interface QueueLock#(type id); method ActionValue#(id) res1(); method Bool owns1(id i); method Action rel1(id i); - method Action abort1(id i); method Bool isEmpty(); method Bool canRes1(); endinterface -interface CheckpointQueueLock#(type id, type cid); +interface CheckpointQueueLock#(type id, type cid, type winfo); method ActionValue#(id) res1(); method Bool owns1(id i); method Action rel1(id i); method Bool isEmpty(); method Bool canRes1(); + method Action write(winfo wd); method ActionValue#(cid) checkpoint(); method Action rollback(cid id, Bool doRoll, Bool doRel); + method Action abort(); endinterface interface AddrLock#(type id, type addr, numeric type size); @@ -75,14 +77,6 @@ module mkQueueLock(QueueLock#(LockId#(d))); end endmethod - //Clears everything after `tid` when `tid` comes to the head - method Action abort1(LockId#(d) tid); - if (owner == tid) - begin - held.clear(); - end - endmethod - //Reserves the lock and returns the associated id method ActionValue#(LockId#(d)) res1(); held.enq(nextId); @@ -134,12 +128,6 @@ module mkCountingLock(QueueLock#(LockId#(d))); doRel.wset(owner + 1); endmethod - method Action abort1(LockId#(d) tid); - nextId[0] <= 0; - owner <= 0; - empty <= True; - endmethod - //Reserves the lock and returns the associated id method ActionValue#(LockId#(d)) res1(); nextId[0] <= nextId[0] + 1; @@ -149,12 +137,14 @@ module mkCountingLock(QueueLock#(LockId#(d))); endmodule -module mkCheckpointQueueLock(CheckpointQueueLock#(LockId#(d), LockId#(d))); +module mkCheckpointQueueLock(Put#(winfo) mem, CheckpointQueueLock#(LockId#(d), LockId#(d), winfo) _unused_) + provisos(Bits#(winfo,wsz)); Ehr#(2, LockId#(d)) nextId <- mkEhr(0); Reg#(LockId#(d)) owner <- mkReg(0); Reg#(Bool) empty <- mkReg(True); + Reg#(Maybe#(winfo)) wdata <- mkReg(tagged Invalid); RWire#(Bool) doRes <- mkRWire(); RWire#(LockId#(d)) doRel <- mkRWire(); @@ -166,6 +156,13 @@ module mkCheckpointQueueLock(CheckpointQueueLock#(LockId#(d), LockId#(d))); if (!res &&& doRel.wget() matches tagged Valid.nextOwner) empty <= nextOwner == nextId[1]; endrule + method Action abort(); + nextId[0] <= 0; + owner <= 0; + empty <= True; + wdata <= tagged Invalid; + endmethod + method Bool isEmpty(); return empty; endmethod @@ -179,10 +176,19 @@ module mkCheckpointQueueLock(CheckpointQueueLock#(LockId#(d), LockId#(d))); return owner == tid; endmethod + //store the write data + method Action write(winfo wd); + wdata <= tagged Valid wd; + endmethod + //Releases the lock, assume `tid` owns it method Action rel1(LockId#(d) tid); owner <= owner + 1; //assign next owner doRel.wset(owner + 1); + if (wdata matches tagged Valid.wd) begin + mem.put(wd); + wdata <= tagged Invalid; + end endmethod //Reserves the lock and returns the associated id diff --git a/bscRuntime/memories/Memories.bsv b/bscRuntime/memories/Memories.bsv index 7f537da7..ce2115ff 100644 --- a/bscRuntime/memories/Memories.bsv +++ b/bscRuntime/memories/Memories.bsv @@ -61,6 +61,14 @@ function Bool isNewer(UInt#(sz) a, UInt#(sz) b, UInt#(sz) h); return !isOlder(a, b, h); endfunction +function Put#(Tuple2#(addr, elem)) rfToPut (RegFile#(addr, elem) rf); + return (interface Put; + method Action put(Tuple2#(addr, elem) x); + rf.upd(tpl_1(x), tpl_2(x)); + endmethod + endinterface); +endfunction + //Types of memories X Locks: //For the built-in types of locks & mems: @@ -111,7 +119,7 @@ endinterface interface CheckpointQueueLockCombMem#(type addr, type elem, type id, type cid); method elem read(addr a); method Action write(addr a, elem b); - interface CheckpointQueueLock#(id, cid) lock; + interface CheckpointQueueLock#(id, cid, Tuple2#(addr, elem)) lock; method Bool canAtom_r1(addr a); method Bool canAtom_r2(addr a); method elem atom_r(addr a); @@ -121,7 +129,7 @@ endinterface interface QueueLockAsyncMem#(type addr, type elem, type rid, numeric type nsz, type lid); interface AsyncMem#(addr, elem, rid, nsz) mem; - interface QueueLock#(lid) lock; + interface QueueLock#(lid) lock; method Bool canAtom1(addr a); method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); endinterface @@ -209,6 +217,7 @@ module mkRegFile#(parameter Bool init, parameter String initFile)(RegFile#(addr, return rf; endmodule + module mkBramPort#(parameter Bool init, parameter String file)(BramPort#(addr, elem, MemId#(inflight), nsz)) provisos (Bits#(addr,szAddr), Bits#(elem,szElem), Mul#(TDiv#(szElem, nsz), nsz, szElem)); BRAM_PORT_BE#(addr, elem, nsz) p; @@ -533,10 +542,13 @@ module mkQueueLockCombMem(RegFile#(addr, elem) rf, QueueLockCombMem#(addr, elem, endmodule -module mkCheckpointQueueLockCombMem(RegFile#(addr, elem) rf, CheckpointQueueLockCombMem#(addr, elem, LockId#(d), LockId#(d)) _unused_); - - CheckpointQueueLock#(LockId#(d), LockId#(d)) l <- mkCheckpointQueueLock(); +module mkCheckpointQueueLockCombMem(RegFile#(addr, elem) rf, CheckpointQueueLockCombMem#(addr, elem, LockId#(d), LockId#(d)) _unused_) +provisos(Bits#(Tuple2#(addr, elem), tuplsz)); + + Put#(Tuple2#(addr, elem)) doWrite = rfToPut(rf); + CheckpointQueueLock#(LockId#(d), LockId#(d), Tuple2#(addr, elem)) l <- mkCheckpointQueueLock(doWrite); + interface lock = l; method elem read(addr a); @@ -544,7 +556,7 @@ module mkCheckpointQueueLockCombMem(RegFile#(addr, elem) rf, CheckpointQueueLock endmethod method Action write(addr a, elem b); - rf.upd(a, b); + l.write(tuple2(a, b)); endmethod method Bool canAtom_r1(addr a); diff --git a/src/main/scala/pipedsl/common/LockImplementation.scala b/src/main/scala/pipedsl/common/LockImplementation.scala index e500760e..9465c713 100644 --- a/src/main/scala/pipedsl/common/LockImplementation.scala +++ b/src/main/scala/pipedsl/common/LockImplementation.scala @@ -491,7 +491,8 @@ object LockImplementation { TObject(queueLockName, List(), parent.methods ++ Map( Id(checkpointName) -> (TFun(List(), checkType), Sequential), - Id(rollbackName) -> (TFun(List(checkType), TVoid()), Sequential) + Id(rollbackName) -> (TFun(List(checkType), TVoid()), Sequential), + Id(abortName) -> (TFun(List(), TVoid()), Sequential) ) ) } From 64a4d865aebc88197e98fd5d9d95381b132ae2ca Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Mon, 9 May 2022 06:11:56 -0400 Subject: [PATCH 15/38] testing for exceptions --- .../FinalblocksConstraintChecker.scala | 4 ++- src/test/tests/typecheckTests/.#exn-pass.pdl | 1 + src/test/tests/typecheckTests/exn-basic.pdl | 28 +++++++++++++++ .../typecheckTests/exn-no-end-after-call.pdl | 35 +++++++++++++++++++ .../typecheckTests/exn-no-release-main.pdl | 28 +++++++++++++++ .../typecheckTests/exn-no-throw-commit.pdl | 29 +++++++++++++++ .../typecheckTests/exn-no-throw-except.pdl | 29 +++++++++++++++ .../typecheckTests/exn-no-throw-normal.pdl | 23 ++++++++++++ .../exn-no-unlocked-write-main.pdl | 32 +++++++++++++++++ .../solutions/exn-basic.typechecksol | 1 + .../exn-no-end-after-call.typechecksol | 1 + .../exn-no-release-main.typechecksol | 1 + .../exn-no-throw-commit.typechecksol | 1 + .../exn-no-throw-except.typechecksol | 1 + .../exn-no-throw-normal.typechecksol | 1 + .../exn-no-unlocked-write-main.typechecksol | 1 + .../solutions/exn-pass.typechecksol | 1 + 17 files changed, 216 insertions(+), 1 deletion(-) create mode 120000 src/test/tests/typecheckTests/.#exn-pass.pdl create mode 100644 src/test/tests/typecheckTests/exn-basic.pdl create mode 100644 src/test/tests/typecheckTests/exn-no-end-after-call.pdl create mode 100644 src/test/tests/typecheckTests/exn-no-release-main.pdl create mode 100644 src/test/tests/typecheckTests/exn-no-throw-commit.pdl create mode 100644 src/test/tests/typecheckTests/exn-no-throw-except.pdl create mode 100644 src/test/tests/typecheckTests/exn-no-throw-normal.pdl create mode 100644 src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl create mode 100644 src/test/tests/typecheckTests/solutions/exn-basic.typechecksol create mode 100644 src/test/tests/typecheckTests/solutions/exn-no-end-after-call.typechecksol create mode 100644 src/test/tests/typecheckTests/solutions/exn-no-release-main.typechecksol create mode 100644 src/test/tests/typecheckTests/solutions/exn-no-throw-commit.typechecksol create mode 100644 src/test/tests/typecheckTests/solutions/exn-no-throw-except.typechecksol create mode 100644 src/test/tests/typecheckTests/solutions/exn-no-throw-normal.typechecksol create mode 100644 src/test/tests/typecheckTests/solutions/exn-no-unlocked-write-main.typechecksol create mode 100644 src/test/tests/typecheckTests/solutions/exn-pass.typechecksol diff --git a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala index c0d884d4..93e4bf74 100644 --- a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala +++ b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala @@ -20,8 +20,9 @@ object FinalblocksConstraintChecker { { m.except_blk match { case ExceptEmpty() => checkNormBody(m.body) - case ExceptFull(args, c) => + case ExceptFull(_, c) => checkExBody(m.body) + checkCommit(m.commit_blk.get) checkExceptingBlock(c) } } @@ -58,6 +59,7 @@ object FinalblocksConstraintChecker { private def checkNormBody(c: Command) :Unit = checkNoThrow(c, NonExn) + private def checkCommit(c :Command) :Unit = checkNoThrow(c, NonExn) private def checkNoThrow(c :Command, estat :ExnStatus) :ExnStatus = c match { case CSeq(c1, c2) => checkNoThrow(c2, checkNoThrow(c1, estat)) diff --git a/src/test/tests/typecheckTests/.#exn-pass.pdl b/src/test/tests/typecheckTests/.#exn-pass.pdl new file mode 120000 index 00000000..223dfbc1 --- /dev/null +++ b/src/test/tests/typecheckTests/.#exn-pass.pdl @@ -0,0 +1 @@ +charles@SHREK-2.135513:1652021910 \ No newline at end of file diff --git a/src/test/tests/typecheckTests/exn-basic.pdl b/src/test/tests/typecheckTests/exn-basic.pdl new file mode 100644 index 00000000..f6bd5b0f --- /dev/null +++ b/src/test/tests/typecheckTests/exn-basic.pdl @@ -0,0 +1,28 @@ +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { + reserve(acc); + --- + block(acc); + acc_val = acc[]; + acc[] <- acc_val + 1; + if(acc_val + 1 == 13) + { + except(0); + } else + { + call cpu(pc + 1); + } +commit: + release(acc); + print("no exn here!"); +except(arg :uint<4>): + print("exception..."); + output(1); +} + + +circuit { + accr = register(uint<4>); + acc = Queue(accr); + c = new cpu[acc, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/src/test/tests/typecheckTests/exn-no-end-after-call.pdl b/src/test/tests/typecheckTests/exn-no-end-after-call.pdl new file mode 100644 index 00000000..6d8243d0 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-end-after-call.pdl @@ -0,0 +1,35 @@ +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { + reserve(acc); + --- + block(acc); + acc_val = acc[]; + acc[] <- acc_val + 1; + if(acc_val + 1 == 13) + { + except(0); + } else + { + call cpu(pc + 1); + } +commit: + release(acc); + print("no exn here!"); +except(arg :uint<4>): + print("exception..."); + start(oth); + call cpu(0); + reserve(oth); + end(oth); + --- + block(oth); + oth[] <- 0; + release(oth); +} + + +circuit { + accr = register(uint<4>); + acc = Queue(accr); + c = new cpu[acc, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/src/test/tests/typecheckTests/exn-no-release-main.pdl b/src/test/tests/typecheckTests/exn-no-release-main.pdl new file mode 100644 index 00000000..dd63bb80 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-release-main.pdl @@ -0,0 +1,28 @@ +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { + reserve(acc); + --- + block(acc); + acc_val = acc[]; + acc[] <- acc_val + 1; + if(acc_val + 1 == 13) + { + except(0); + } else + { + call cpu(pc + 1); + } + release(acc); +commit: + print("no exn here!"); +except(arg :uint<4>): + print("exception..."); + output(1); +} + + +circuit { + accr = register(uint<4>); + acc = Queue(accr); + c = new cpu[acc, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/src/test/tests/typecheckTests/exn-no-throw-commit.pdl b/src/test/tests/typecheckTests/exn-no-throw-commit.pdl new file mode 100644 index 00000000..e7aa08d6 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-throw-commit.pdl @@ -0,0 +1,29 @@ +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { + reserve(acc); + --- + block(acc); + acc_val = acc[]; + acc[] <- acc_val + 1; + if(acc_val + 1 == 13) + { + except(0); + } else + { + call cpu(pc + 1); + } +commit: + release(acc); + except(0); + print("no exn here!"); +except(arg :uint<4>): + print("exception..."); + output(1); +} + + +circuit { + accr = register(uint<4>); + acc = Queue(accr); + c = new cpu[acc, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/src/test/tests/typecheckTests/exn-no-throw-except.pdl b/src/test/tests/typecheckTests/exn-no-throw-except.pdl new file mode 100644 index 00000000..f4115bb4 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-throw-except.pdl @@ -0,0 +1,29 @@ +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { + reserve(acc); + --- + block(acc); + acc_val = acc[]; + acc[] <- acc_val + 1; + if(acc_val + 1 == 13) + { + except(0); + } else + { + call cpu(pc + 1); + } +commit: + release(acc); + print("no exn here!"); +except(arg :uint<4>): + print("exception..."); + except(1); + output(1); +} + + +circuit { + accr = register(uint<4>); + acc = Queue(accr); + c = new cpu[acc, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/src/test/tests/typecheckTests/exn-no-throw-normal.pdl b/src/test/tests/typecheckTests/exn-no-throw-normal.pdl new file mode 100644 index 00000000..161111a1 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-throw-normal.pdl @@ -0,0 +1,23 @@ +pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { + reserve(acc); + --- + block(acc); + acc_val = acc[]; + acc[] <- acc_val + 1; + if(acc_val + 1 == 13) + { + except(0); + output(1); + } else + { + call cpu(pc + 1); + } +} + + +circuit { + accr = register(uint<4>); + acc = Queue(accr); + c = new cpu[acc, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl b/src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl new file mode 100644 index 00000000..5d660687 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl @@ -0,0 +1,32 @@ +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue), abc :uint<8>[16] ] :uint<4> { + start(abc); + abc[pc] <- 4; + end(abc); + + reserve(acc); + --- + block(acc); + acc_val = acc[]; + acc[] <- acc_val + 1; + if(acc_val + 1 == 13) + { + except(0); + } else + { + call cpu(pc + 1); + } +commit: + release(acc); + print("no exn here!"); +except(arg :uint<4>): + print("exception..."); + output(1); +} + + +circuit { + accr = register(uint<4>); + acc = Queue(accr); + c = new cpu[acc, acc]; + call c(u0<16>); +} \ No newline at end of file diff --git a/src/test/tests/typecheckTests/solutions/exn-basic.typechecksol b/src/test/tests/typecheckTests/solutions/exn-basic.typechecksol new file mode 100644 index 00000000..9fb4ec93 --- /dev/null +++ b/src/test/tests/typecheckTests/solutions/exn-basic.typechecksol @@ -0,0 +1 @@ +Passed \ No newline at end of file diff --git a/src/test/tests/typecheckTests/solutions/exn-no-end-after-call.typechecksol b/src/test/tests/typecheckTests/solutions/exn-no-end-after-call.typechecksol new file mode 100644 index 00000000..7eb5d231 --- /dev/null +++ b/src/test/tests/typecheckTests/solutions/exn-no-end-after-call.typechecksol @@ -0,0 +1 @@ +Failed diff --git a/src/test/tests/typecheckTests/solutions/exn-no-release-main.typechecksol b/src/test/tests/typecheckTests/solutions/exn-no-release-main.typechecksol new file mode 100644 index 00000000..7eb5d231 --- /dev/null +++ b/src/test/tests/typecheckTests/solutions/exn-no-release-main.typechecksol @@ -0,0 +1 @@ +Failed diff --git a/src/test/tests/typecheckTests/solutions/exn-no-throw-commit.typechecksol b/src/test/tests/typecheckTests/solutions/exn-no-throw-commit.typechecksol new file mode 100644 index 00000000..7eb5d231 --- /dev/null +++ b/src/test/tests/typecheckTests/solutions/exn-no-throw-commit.typechecksol @@ -0,0 +1 @@ +Failed diff --git a/src/test/tests/typecheckTests/solutions/exn-no-throw-except.typechecksol b/src/test/tests/typecheckTests/solutions/exn-no-throw-except.typechecksol new file mode 100644 index 00000000..7eb5d231 --- /dev/null +++ b/src/test/tests/typecheckTests/solutions/exn-no-throw-except.typechecksol @@ -0,0 +1 @@ +Failed diff --git a/src/test/tests/typecheckTests/solutions/exn-no-throw-normal.typechecksol b/src/test/tests/typecheckTests/solutions/exn-no-throw-normal.typechecksol new file mode 100644 index 00000000..7eb5d231 --- /dev/null +++ b/src/test/tests/typecheckTests/solutions/exn-no-throw-normal.typechecksol @@ -0,0 +1 @@ +Failed diff --git a/src/test/tests/typecheckTests/solutions/exn-no-unlocked-write-main.typechecksol b/src/test/tests/typecheckTests/solutions/exn-no-unlocked-write-main.typechecksol new file mode 100644 index 00000000..7eb5d231 --- /dev/null +++ b/src/test/tests/typecheckTests/solutions/exn-no-unlocked-write-main.typechecksol @@ -0,0 +1 @@ +Failed diff --git a/src/test/tests/typecheckTests/solutions/exn-pass.typechecksol b/src/test/tests/typecheckTests/solutions/exn-pass.typechecksol new file mode 100644 index 00000000..9fb4ec93 --- /dev/null +++ b/src/test/tests/typecheckTests/solutions/exn-pass.typechecksol @@ -0,0 +1 @@ +Passed \ No newline at end of file From f13e86a421eaa985e52025d3bde8bafcad640d9d Mon Sep 17 00:00:00 2001 From: Charles Sherk Date: Mon, 9 May 2022 06:13:45 -0400 Subject: [PATCH 16/38] yeet old code --- .../FinalblocksConstraintChecker.scala | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala index c99eafbf..d4bf2b52 100644 --- a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala +++ b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala @@ -101,62 +101,4 @@ object FinalblocksConstraintChecker { case _ => estat } } - - - - -// private var currentMod: Id = Id("-invalid-") -// private var ifPostCall: Boolean = false -// private var hasCommitBlk: Boolean = false -// -// def check(p:Prog) : Unit = { -// val Prog(_, _, moddefs, _) = p -// moddefs.foreach(m => checkModule(m)) -// } -// -// private def checkModule(moduleDef: ModuleDef): Unit = { -// currentMod = moduleDef.name -// ifPostCall = false -// hasCommitBlk = false -// -// moduleDef.commit_blk match { -// case Some(c) => -// hasCommitBlk = true -// checkCommand(c) -// case _ => () -// } -// -// moduleDef.except_blk match { -// case ExceptEmpty() => () -// case ExceptFull(args, c) if (hasCommitBlk == true) => checkCommand(c) -// case ExceptFull(args, c) if (hasCommitBlk == false) => -// throw MalformedExceptBlock(c.pos) -// } -// } -// -// private def checkCommand(command: Command): Unit = command match { -// case CSeq(c1, c2) => val s1 = checkCommand(c1); checkCommand(c2) -// case CTBar(c1, c2) => val s1 = checkCommand(c1); checkCommand(c2) -// case CIf(_, cons, alt) => val s1 = checkCommand(cons); checkCommand(alt) -// case CSplit(cases, default) => -// checkCommand(default) -// case CLockOp(mem, _, _, _, _) => -// if (ifPostCall == true) throw MalformedLockTypes("Cannot Reserve any locks after a call") -// case CAssign(lhs, rhs) => checkExpr(lhs); checkExpr(rhs) -// case CRecv(lhs, rhs) => checkExpr(lhs); checkExpr(rhs) -// case CExcept(args) => throw IllegalThrowPlacement(command.pos) -// case _ => () -// } -// -// private def checkExpr(e: Expr): Unit = e match { -// case EIsValid(ex) => checkExpr(ex) -// case EFromMaybe(ex) => checkExpr(ex) -// case EToMaybe(ex) => checkExpr(ex) -// case EUop(_, ex) => checkExpr(ex) -// case EBinop(_, e1, e2) => checkExpr(e1); checkExpr(e2) -// case ETernary(cond, tval, fval) => checkExpr(cond); checkExpr(tval); checkExpr(fval) -// case EApp(_, args) => ifPostCall = true -// case ECall(_, _, _, _) => ifPostCall = true -// } - } From 1a1f94ca7d3a22a61cd6bc4984d4ff3e69b3a285 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 22 Jun 2022 10:52:34 -0400 Subject: [PATCH 17/38] exn_translation --- src/main/scala/pipedsl/Main.scala | 5 +- .../codegen/bsv/BluespecGeneration.scala | 25 +++- src/main/scala/pipedsl/common/Syntax.scala | 2 + src/main/scala/pipedsl/common/Utilities.scala | 2 + .../pipedsl/passes/ExnTranslationPass.scala | 131 ++++++++++++++++++ .../pipedsl/typechecker/BaseTypeChecker.scala | 4 + 6 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 src/main/scala/pipedsl/passes/ExnTranslationPass.scala diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index edd1b89c..24bc9307 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -13,7 +13,6 @@ import pipedsl.passes._ import pipedsl.typechecker.TypeInferenceWrapper.TypeInference import pipedsl.typechecker._ - object Main { val logger: Logger = Logger("main") @@ -108,13 +107,15 @@ object Main { specChecker.check(recvProg, None) val lock_prog = LockOpTranslationPass.run(recvProg) TimingTypeChecker.check(lock_prog, Some(basetypes)) + val exnprog = ExnTranslationPass.run(lock_prog) + new PrettyPrinter(None).printProgram(exnprog) if (printOutput) { val writer = new PrintWriter(outputFile) writer.write("Passed") writer.close() } ctx.close() - (lock_prog, pinfo) + (exnprog, pinfo) } catch { case t: Throwable => { //If fails, print the error to the file diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index af445856..cb97fc62 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -1,6 +1,6 @@ package pipedsl.codegen.bsv -import BSVSyntax._ +import BSVSyntax.{BBOp, _} import pipedsl.common.DAGSyntax.{PStage, PipelineEdge} import pipedsl.common.Errors.{UnexpectedCommand, UnexpectedExpr} import pipedsl.common.LockImplementation.{LockInterface, MethodInfo} @@ -397,7 +397,8 @@ object BluespecGeneration { private val threadIdVar = BVar(threadIdName, getThreadIdType) private val outputData = BVar("data", translator.toType(mod.ret.getOrElse(TVoid()))) private val outputQueue = BVar("outputQueue", bsInts.getOutputQType(threadIdVar.typ, outputData.typ)) - + //Registers for exceptions + private val globalExnFlag = BVar("globalExnFlag", bsInts.getRegType(BBool)) //Data types for passing between stages private val edgeStructInfo = getEdgeStructInfo(otherStages, addTId = true, addSpecId = mod.maybeSpec) //First stage should have exactly one input edge by definition @@ -431,7 +432,7 @@ object BluespecGeneration { vars + (m.name -> nvar) case _ => vars } - }) + }) + (mod.name -> BVar("_lock_" + mod.name, translator.getLockedModType(LockImplementation.getModLockImpl))) private val lockRegions: LockInfo = mod.modules.foldLeft[LockInfo](Map())((locks, m) => { locks + (m.name -> BVar(genLockRegionName(m.name), @@ -631,6 +632,9 @@ object BluespecGeneration { BUOp("!", BFromMaybe(BBoolLit(true), bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder)))) //also need these in case we're waiting on responses we need to dequeue + case IStageClear() => + l :+ globalExnFlag + case ICondCommand(cond, cs) => val condconds = getKillConds(cs) if (condconds.nonEmpty) { @@ -917,12 +921,17 @@ object BluespecGeneration { val outputInst = BModInst(outputQueue, bsInts.getOutputQ(BZero)) val threadInst = BModInst(BVar(threadIdName, bsInts.getRegType(getThreadIdType)), bsInts.getReg(BZero)) + + //Instantiate Exception Register + val globalExnInst = BModInst(globalExnFlag, bsInts.getReg(BBoolLit(false))) + //Instantiate the speculation table if the module is speculative val specInst = if (mod.maybeSpec) BModInst(specTable, bsInts.getSpecTable) else BEmpty var stmts: List[BStatement] = startFifo +: (edgeFifos.values.toList ++ memRegions.values.toList ++ modLockInsts) if (mod.isRecursive) stmts = stmts :+ busyInst if (mod.maybeSpec) stmts = stmts :+ specInst + stmts = stmts :+ globalExnInst stmts = (stmts :+ outputInst :+ threadInst) ++ stgStmts //expose a start method as part of the top level interface var methods = List[BMethodDef]() @@ -1257,9 +1266,18 @@ object BluespecGeneration { } else { None } + case IAbort(mem) => + val abortInfo = LockImplementation.getAbortInfo(mem) + if (abortInfo.isDefined && abortInfo.get.doesModify) { + val abortMethod = translateMethod(getLockName(mem), abortInfo.get) + Some(BExprStmt(abortMethod)) + } else { + None + } case IAssignLock(handle, src, _) => Some( BAssign(translator.toVar(handle), translator.toExpr(src)) ) + case cl@IReleaseLock(mem, _) => val methodInfo = LockImplementation.getReleaseInfo(cl) if (methodInfo.isDefined && methodInfo.get.doesModify) { @@ -1357,6 +1375,7 @@ object BluespecGeneration { case CAssign(_, _) => None case CExpr(_) => None case CEmpty() => None + case _: IStageClear => None case _: InternalCommand => throw UnexpectedCommand(cmd) case CRecv(_, _) => throw UnexpectedCommand(cmd) case CSeq(_, _) => throw UnexpectedCommand(cmd) diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 1d3b1416..5af97c32 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -647,6 +647,8 @@ object Syntax { sealed trait InternalCommand extends Command + case class IAbort(mem: Id) extends InternalCommand + case class IStageClear() extends InternalCommand case class ICondCommand(cond: Expr, cs: List[Command]) extends InternalCommand case class IUpdate(specId: Id, value: EVar, originalSpec: EVar) extends InternalCommand case class ICheck(specId: Id, value: EVar) extends InternalCommand diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index 7e4759bb..f8ebcf9b 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -197,6 +197,8 @@ object Utilities { case None => Set() }) case ILockNoOp(_) => Set() + case IStageClear() => Set() + case IAbort(_) => Set() case CLockStart(_) => Set() case CLockEnd(_) => Set() case CSpecCall(handle, _, args) => args.foldLeft(Set(handle.id))((s, a) => s ++ getUsedVars(a)) diff --git a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala new file mode 100644 index 00000000..ff6d5852 --- /dev/null +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -0,0 +1,131 @@ +package pipedsl.passes + +import pipedsl.common.Syntax._ +import pipedsl.passes.Passes.{ModulePass, ProgPass} +import pipedsl.typechecker.BaseTypeChecker.replaceNamedType + +object ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ + private var exnArgMap = Map[Id, Id]() + + override def run(m: ModuleDef): ModuleDef = + { + val fixed_commit = m.commit_blk match { + case Some(c) => c + case _ => CEmpty() + } + + val fixed_except = m.except_blk match { + case ExceptFull(_, c) => c + case ExceptEmpty() => CEmpty() + } + + val new_m = addExnVars(m) + new_m.name.typ = m.name.typ + print(new_m.body) + val modified_exnblk = m.except_blk.map(convertExnArgsId) + createNewStg(new_m.copy(body = new_m.body, commit_blk = new_m.commit_blk, except_blk = modified_exnblk)) + } + + override def run(p: Prog): Prog = p.copy(moddefs = p.moddefs.map(m => run(m))) + + def addExnVars(m: ModuleDef): ModuleDef = + { + val fixed_except = m.except_blk match { + case ExceptFull(args, c) => + var arg_count = 0 + args.foreach(arg => { + exnArgMap = exnArgMap + (arg -> Id("_exnArg_"+arg_count.toString())) + arg_count += 1 + }) + case ExceptEmpty() => CEmpty() + } + + val newAssignments = exnArgMap.foldLeft(CSeq(CEmpty(), CEmpty()))((c, id_mapping) => { + val (lhs, rhs) = id_mapping + val setCurrArg = CAssign(EVar(lhs), EBool(false)) + CSeq(c, setCurrArg) + }) + m.copy(body = CSeq(IStageClear(), convertPrimitives(m.body)), commit_blk = m.commit_blk, except_blk = m.except_blk) + } + + def convertPrimitives(c: Command): Command = { + c match { + case CSeq(c1, c2) => CSeq(convertPrimitives(c1), convertPrimitives(c2)).copyMeta(c) + case CIf(cond, cons, alt) => CIf(cond, convertPrimitives(cons), convertPrimitives(alt)).copyMeta(c) + case CTBar(c1, c2) => CTBar(convertPrimitives(c1), CSeq(IStageClear(), convertPrimitives(c2))).copyMeta(c) + case CSplit(cases, default) => + val newCases = List[CaseObj]() + val newDefault = convertPrimitives(default) + for (index <- cases.indices) { + val newBody = convertPrimitives(cases(index).body) + newCases :+ cases(index).copy(body = newBody) + } + CSplit(newCases, newDefault) + case CExcept(args) => + val localflag = EVar(Id("_localExnFlag")) + localflag.typ = Some(TBool()) + localflag.id.typ = localflag.typ + + val setLocalErrFlag = CAssign(localflag, EBool(true)).copyMeta(c) + var arg_count = 0 + val setArgs: Command = args.foldLeft[Command](CSeq(setLocalErrFlag, CEmpty()))((c, arg) => { + val setCurrArg = CAssign(EVar(Id("_exnArg_"+arg_count.toString())), arg).copyMeta(c) + arg_count += 1 + CSeq(c, setCurrArg).copyMeta(c) + }) + setArgs + case _ => c + } + } + + def convertExnArgsId(c: Command): Command = { + c match { + case CSeq(c1, c2) => CSeq(convertExnArgsId(c1), convertExnArgsId(c2)) + case CIf(cond, cons, alt) => CIf(cond, convertExnArgsId(cons), convertExnArgsId(alt)) + case CTBar(c1, c2) => CSeq(convertExnArgsId(c1), convertExnArgsId(c2)); + case CSplit(cases, default) => + val newCases = List[CaseObj]() + val newDefault = convertExnArgsId(default) + for (index <- cases.indices) { + val newBody = convertExnArgsId(cases(index).body) + newCases :+ cases(index).copy(body = newBody) + } + CSplit(newCases, newDefault) + case CAssign(v, exp) => + val newv = EVar(exnArgMap.getOrElse(v.id, v.id)).setPos(v.pos) + CAssign(newv, exp) + case CPrint(args) => + val newArgs = args.foldLeft(List[Expr]())((l, arg) => { + arg match { + case EVar(id) => l :+ EVar(exnArgMap.getOrElse(id, id)).setPos(arg.pos) + case _ => l + } + }) + CPrint(newArgs) + case _ => c + } + } + + def createNewStg(m: ModuleDef): ModuleDef = { + val commit_stmts = m.commit_blk match { + case Some(c) => c + case _ => CEmpty() + } + val except_stmts = m.except_blk match { + case ExceptFull(_, c) => +// m.modules.filter() + CSeq(IAbort(m.name), c) + case ExceptEmpty() => CEmpty() + } + val localflag = EVar(Id("_localExnFlag")) + localflag.typ = Some(TBool()) + localflag.id.typ = localflag.typ + val checkLocalFlag = CIf(localflag, commit_stmts, except_stmts) + val newBody = CTBar(m.body, checkLocalFlag) + + val inputTyps = m.inputs.foldLeft[List[Type]](List())((l, p) => { l :+ p.typ }) + //TODO require memory or module types + m.name.typ = Some(TModType(inputTyps, List[Type](), m.ret, Some(m.name))) + m.copy(body = newBody, commit_blk = None, except_blk = ExceptEmpty()) + } +} diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index 8f39a792..c14f766a 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -96,6 +96,10 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { val outEnv = tenv.add(m.name, modTyp) checkModuleBodyWellFormed(m.body, Set()) checkCommand(m.name, m.extendedBody(), bodyEnv) +// m.except_blk match { +// +// } +// env.add() m.except_blk.foreach(checkCommand(m.name, _, bodyEnv)) outEnv } From 9fcf97817029b47c658aca7d93fc6cb97df0f8cc Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 22 Jun 2022 11:39:21 -0400 Subject: [PATCH 18/38] add testcase --- examples/exn.pdl | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 examples/exn.pdl diff --git a/examples/exn.pdl b/examples/exn.pdl new file mode 100644 index 00000000..8c6f4867 --- /dev/null +++ b/examples/exn.pdl @@ -0,0 +1,46 @@ +exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0], oth :uint<4>[0]] :uint<4> { + start(imem); + uint<8> insn <- imem[pc]; + end(imem); + --- + //DECODE + print("PC: %h", pc); + print("INSN: %h", insn); + opcode = insn{7:4}; + imm = insn{3:0}; + done = opcode == 0; + mult = opcode == 1; + div = opcode == 2; + acc_val = acc[]; + --- + if(div){ + if(imm == 0){ + uint<4> err_code = 1; + except(); + } + } + --- + if (done) + { + output acc_val; + } else + { + call cpu(pc + 1); + } + end(acc); + --- +commit: + print("commit"); +except(): + print("exn"); + --- + call cpu(0); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 1); + c = new cpu[ti, acc, acc]; + call c(u0<16>); +} \ No newline at end of file From bd4d8868425b13c6169296af7adcf4667f6cf28e Mon Sep 17 00:00:00 2001 From: dz333 Date: Wed, 22 Jun 2022 12:49:54 -0400 Subject: [PATCH 19/38] updated this example to reflect a bug - BaseTypeChecker should check that every memory used in an excepting pipeline is Locked (this can be weakened to: any memory which is _written_ to, or has reservations made in the main body of the pipeline must be locked) --- examples/exn.pdl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/exn.pdl b/examples/exn.pdl index 8c6f4867..01e85775 100644 --- a/examples/exn.pdl +++ b/examples/exn.pdl @@ -11,7 +11,10 @@ exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0], oth :ui done = opcode == 0; mult = opcode == 1; div = opcode == 2; + start(acc); acc_val = acc[]; + reserve(acc); + end(acc); --- if(div){ if(imm == 0){ @@ -27,7 +30,6 @@ exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0], oth :ui { call cpu(pc + 1); } - end(acc); --- commit: print("commit"); From 16c8893d59fcc634c9d9391e5d5e9a49129238f3 Mon Sep 17 00:00:00 2001 From: dz333 Date: Wed, 22 Jun 2022 12:53:48 -0400 Subject: [PATCH 20/38] updated example to do a write --- examples/exn.pdl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/exn.pdl b/examples/exn.pdl index 01e85775..4e478779 100644 --- a/examples/exn.pdl +++ b/examples/exn.pdl @@ -30,9 +30,12 @@ exn-pipe cpu(pc :uint<16>)[imem :uint<8>[16], acc :uint<4>[0], oth :ui { call cpu(pc + 1); } + block(acc); + acc = acc_val + opcode; //this should do a real thing --- commit: print("commit"); + release(acc); except(): print("exn"); --- From 6f1b359b76534956158e9183e7254ae1a8201ed1 Mon Sep 17 00:00:00 2001 From: dz333 Date: Thu, 23 Jun 2022 12:10:15 -0400 Subject: [PATCH 21/38] fixed some bugs in pretty printer, and made port checker pass run on commit and exception blocks --- src/main/scala/pipedsl/Main.scala | 6 +----- src/main/scala/pipedsl/common/PrettyPrinter.scala | 4 ++-- src/main/scala/pipedsl/passes/ExnTranslationPass.scala | 1 - src/main/scala/pipedsl/typechecker/PortChecker.scala | 4 +++- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index 24bc9307..f566a83f 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -72,7 +72,6 @@ object Main { val prog = parse(debug = false, printOutput = false, inputFile, outDir, rfLockImpl = rfLockImpl) try { - //val prog = ExceptingToNormal.run(ex_prog) // new PrettyPrinter(None).printProgram(prog) val pinfo = new ProgInfo(prog) MarkNonRecursiveModulePass.run(prog) @@ -81,8 +80,6 @@ object Main { val verifProg = AddCheckpointHandlesPass.run(AddVerifyValuesPass.run(inferredProg)) val canonProg2 = new CanonicalizePass().run(verifProg) val canonProg = new TypeInference(autocast).checkProgram(canonProg2) - // new PrettyPrinter(None).printProgram(canonProg) - val basetypes = BaseTypeChecker.check(canonProg, None) FunctionConstraintChecker.check(canonProg) val nprog = new BindModuleTypes(basetypes).run(canonProg) @@ -106,9 +103,8 @@ object Main { val specChecker = new SpeculationChecker(ctx) specChecker.check(recvProg, None) val lock_prog = LockOpTranslationPass.run(recvProg) - TimingTypeChecker.check(lock_prog, Some(basetypes)) + TimingTypeChecker.check(lock_prog, Some(basetypes)) val exnprog = ExnTranslationPass.run(lock_prog) - new PrettyPrinter(None).printProgram(exnprog) if (printOutput) { val writer = new PrintWriter(outputFile) writer.write("Passed") diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index ea4c52a9..b3bf7b3f 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -60,7 +60,7 @@ class PrettyPrinter(output: Option[File]) { def printExnBlock(block: Syntax.ExceptBlock, ident: Int): String = block match { case ExceptEmpty() => "" - case ExceptFull(args, c) => "except(" + args.map((id) => id.v).reduce((acc, elem) => acc + "," + elem) + "):\n" + printCmdToString(c, ident) + case ExceptFull(args, c) => "except(" + args.map((id) => id.v).foldLeft("")((acc, elem) => acc + "," + elem) + "):\n" + printCmdToString(c, ident) } def printCircuit(c: Circuit): Unit = pline("circuit {\n" + printCircuitToString(c, 2) + "\n}") @@ -127,7 +127,7 @@ class PrettyPrinter(output: Option[File]) { printExprToString(originalSpec) + " = update(" + specId + ", " + printExprToString(value) + ");" case Syntax.ICheck(specId, value) => ins + "check(" + specId + ", " + printExprToString(value) + ");" case Syntax.CCheckpoint(h, m) => ins + printExprToString(h) + " <- checkpoint(" + m.v + ");" - case Syntax.CExcept(args) => ins + "except(" + args.map(printExprToString).reduce((acc, elem) => acc + ", " + elem) + ");" + case Syntax.CExcept(args) => ins + "except(" + args.map(printExprToString).foldLeft("")((acc, elem) => acc + ", " + elem) + ");" case _ => "TODO PRINTING COMMAND" } } diff --git a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala index ff6d5852..952b9035 100644 --- a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -21,7 +21,6 @@ object ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ val new_m = addExnVars(m) new_m.name.typ = m.name.typ - print(new_m.body) val modified_exnblk = m.except_blk.map(convertExnArgsId) createNewStg(new_m.copy(body = new_m.body, commit_blk = new_m.commit_blk, except_blk = modified_exnblk)) } diff --git a/src/main/scala/pipedsl/typechecker/PortChecker.scala b/src/main/scala/pipedsl/typechecker/PortChecker.scala index 1de95609..2aea4b62 100644 --- a/src/main/scala/pipedsl/typechecker/PortChecker.scala +++ b/src/main/scala/pipedsl/typechecker/PortChecker.scala @@ -62,7 +62,9 @@ class PortChecker(port_warn :Boolean) extends TypeChecks[Id, (Int, Int)] case _ : TModType => modLims.addOne((mod.name, (1, 1))) case _ => }) - val port_map = checkPipe(m.body, emptyEnv()) + val port_tmp = checkPipe(m.body, emptyEnv()) + val port_com = if (m.commit_blk.isDefined) { checkPipe(m.commit_blk.get, port_tmp) } else port_tmp; + val port_map = checkPipe(m.except_blk.get, port_com); if(port_warn) port_map.getMappedKeys().foreach(mem => { From f465d0d818ad66c93241cf64eb1fbd8476ebfbc9 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Thu, 7 Jul 2022 08:04:52 -0400 Subject: [PATCH 22/38] partially resolved comments, enables exn_args and kill_rules --- examples/exn_output.pdl | 0 src/main/scala/pipedsl/Main.scala | 6 +- .../codegen/bsv/BSVPrettyPrinter.scala | 13 +- .../scala/pipedsl/codegen/bsv/BSVSyntax.scala | 4 +- .../codegen/bsv/BluespecGeneration.scala | 180 +++++++++--------- .../codegen/bsv/BluespecInterfaces.scala | 10 +- src/main/scala/pipedsl/common/Syntax.scala | 12 +- src/main/scala/pipedsl/common/Utilities.scala | 1 + .../pipedsl/passes/ExnTranslationPass.scala | 103 +++++----- .../pipedsl/typechecker/BaseTypeChecker.scala | 10 +- 10 files changed, 185 insertions(+), 154 deletions(-) create mode 100644 examples/exn_output.pdl diff --git a/examples/exn_output.pdl b/examples/exn_output.pdl new file mode 100644 index 00000000..e69de29b diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index f566a83f..42d1e38f 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -103,8 +103,10 @@ object Main { val specChecker = new SpeculationChecker(ctx) specChecker.check(recvProg, None) val lock_prog = LockOpTranslationPass.run(recvProg) - TimingTypeChecker.check(lock_prog, Some(basetypes)) - val exnprog = ExnTranslationPass.run(lock_prog) + TimingTypeChecker.check(lock_prog, Some(basetypes)) + val exnTranslationPass = new ExnTranslationPass() + val exnprog = exnTranslationPass.run(lock_prog) + new PrettyPrinter(None).printProgram(exnprog) if (printOutput) { val writer = new PrintWriter(outputFile) writer.write("Passed") diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala index 4a690b80..e8b771f0 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala @@ -110,8 +110,9 @@ object BSVPrettyPrinter { case BTruncate(e) => mkExprString("truncate(", toBSVExprStr(e), ")") case BStructAccess(rec, field) => toBSVExprStr(rec) + "." + toBSVExprStr(field) case BVar(name, _) => name - case BBOp(op, lhs, rhs, isInfix) if isInfix => mkExprString("(", toBSVExprStr(lhs), op, toBSVExprStr(rhs), ")") - case BBOp(op, lhs, rhs, isInfix) if !isInfix => mkExprString( op + "(", toBSVExprStr(lhs), ",", toBSVExprStr(rhs), ")") + case BBOp(op, lhs, rhs, isInfix, omitBrackets) if isInfix && !omitBrackets => mkExprString("(", toBSVExprStr(lhs), op, toBSVExprStr(rhs), ")") + case BBOp(op, lhs, rhs, isInfix, omitBrackets) if isInfix && omitBrackets => mkExprString(toBSVExprStr(lhs), op, toBSVExprStr(rhs)) + case BBOp(op, lhs, rhs, isInfix, _) if !isInfix => mkExprString( op + "(", toBSVExprStr(lhs), ",", toBSVExprStr(rhs), ")") case BUOp(op, expr) => mkExprString("(", op, toBSVExprStr(expr), ")") //TODO incorporate bit types into the typesystem properly //and then remove the custom pack/unpack operations @@ -238,10 +239,10 @@ object BSVPrettyPrinter { } def printBSVRule(rule: BRuleDef): Unit = { - val condString = if (rule.conds.nonEmpty) { - "(" + rule.conds.map(c => toBSVExprStr(c)).mkString(" && ") + ")" - } else { - "" + val condString = rule.conds match { + case BDontCare => "" + case _ => toBSVExprStr(rule.conds) + } w.write(mkStatementString("rule", rule.name, condString)) incIndent() diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index 59b58573..b33a472f 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -452,7 +452,7 @@ object BSVSyntax { case class BStructLit(typ: BStruct, fields: Map[BVar, BExpr]) extends BExpr case class BStructAccess(rec: BExpr, field: BExpr) extends BExpr case class BVar(name: String, typ: BSVType) extends BExpr - case class BBOp(op: String, lhs: BExpr, rhs: BExpr, isInfix: Boolean = true) extends BExpr + case class BBOp(op: String, lhs: BExpr, rhs: BExpr, isInfix: Boolean = true, omitBrackets: Boolean = false) extends BExpr case class BUOp(op: String, expr: BExpr) extends BExpr case class BBitExtract(expr: BExpr, start: BIndex, end: BIndex) extends BExpr case class BConcat(first: BExpr, rest: List[BExpr]) extends BExpr @@ -502,7 +502,7 @@ object BSVSyntax { case class BStructDef(typ: BStruct, derives: List[String]) - case class BRuleDef(name: String, conds: List[BExpr], body: List[BStatement]) + case class BRuleDef(name: String, conds: BExpr, body: List[BStatement]) case class BMethodSig(name: String, typ: MethodType, params: List[BVar]) diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index cb97fc62..8efbaf01 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -1,6 +1,6 @@ package pipedsl.codegen.bsv -import BSVSyntax.{BBOp, _} +import BSVSyntax.{BBOp, BEmpty, _} import pipedsl.common.DAGSyntax.{PStage, PipelineEdge} import pipedsl.common.Errors.{UnexpectedCommand, UnexpectedExpr} import pipedsl.common.LockImplementation.{LockInterface, MethodInfo} @@ -398,7 +398,7 @@ object BluespecGeneration { private val outputData = BVar("data", translator.toType(mod.ret.getOrElse(TVoid()))) private val outputQueue = BVar("outputQueue", bsInts.getOutputQType(threadIdVar.typ, outputData.typ)) //Registers for exceptions - private val globalExnFlag = BVar("globalExnFlag", bsInts.getRegType(BBool)) + private val globalExnFlag = BVar("_globalExnFlag", bsInts.getRegType(BBool)) //Data types for passing between stages private val edgeStructInfo = getEdgeStructInfo(otherStages, addTId = true, addSpecId = mod.maybeSpec) //First stage should have exactly one input edge by definition @@ -432,7 +432,7 @@ object BluespecGeneration { vars + (m.name -> nvar) case _ => vars } - }) + (mod.name -> BVar("_lock_" + mod.name, translator.getLockedModType(LockImplementation.getModLockImpl))) + }) private val lockRegions: LockInfo = mod.modules.foldLeft[LockInfo](Map())((locks, m) => { locks + (m.name -> BVar(genLockRegionName(m.name), @@ -550,6 +550,19 @@ object BluespecGeneration { } private var stgSpecOrder: Int = 0 + + private def getMergedCond(lhs: BExpr, rhs: BExpr): BExpr = { + if (lhs == BDontCare && rhs == BDontCare){ + BDontCare + } else if (lhs == BDontCare){ + rhs + } else if (rhs == BDontCare){ + lhs + } else { + BBOp("&&", lhs, rhs, isInfix = true, omitBrackets = true) + } + } + /** * Given a pipeline stage and the necessary edge info, * generate a BSV module definition. @@ -570,7 +583,7 @@ object BluespecGeneration { val execRule = getStageRule(stg) //Add a stage kill rule if it needs one val killRule = getStageKillRule(stg) - val rules = if (mod.maybeSpec && killRule.isDefined) List(execRule, killRule.get) else List(execRule) + val rules = if ((mod.maybeSpec && killRule.isDefined) || (is_excepting(mod) && killRule.isDefined)) List(execRule, killRule.get) else List(execRule) stgSpecOrder = 0 translator.setVariablePrefix("") (sBody, rules) @@ -595,7 +608,7 @@ object BluespecGeneration { BDisplay(Some(mod.name.v + ":Thread %d:Executing Stage " + stg.name + " %t"), List(translator.toBSVVar(threadIdVar), BTime)) } else BEmpty - BRuleDef( genParamName(stg) + "_execute", blockingConds ++ recvConds, + BRuleDef( genParamName(stg) + "_execute", getMergedCond(blockingConds, recvConds), writeCmdDecls ++ writeCmdStmts ++ queueStmts :+ debugStmt) } @@ -608,46 +621,40 @@ object BluespecGeneration { */ private def getStageKillRule(stg: PStage): Option[BRuleDef] = { val killConds = getKillConds(stg.getCmds) - if (killConds.isEmpty) { - None - } else { - val recvConds = getRecvConds(stg.getCmds) - val debugStmt = if (debug) { - BDisplay(Some(mod.name.v + ":SpecId %d: Killing Stage " + stg.name + "%t"), - List(getSpecIdVal, BTime)) - } else { BEmpty } - val deqStmts = getEdgeQueueStmts(stg, stg.inEdges) ++ getRecvCmds(stg.getCmds) - val freeStmt = BExprStmt(bsInts.getSpecFree(specTable, getSpecIdVal)) - Some(BRuleDef( genParamName(stg) + "_kill", killConds ++ recvConds, deqStmts :+ freeStmt :+ debugStmt)) - } + val recvConds = getRecvConds(stg.getCmds) + val debugStmt = if (debug) { + BDisplay(Some(mod.name.v + ":SpecId %d: Killing Stage " + stg.name + "%t"), + List(getSpecIdVal, BTime)) + } else { BEmpty } + val deqStmts = getEdgeQueueStmts(stg, stg.inEdges) ++ getRecvCmds(stg.getCmds) + val freeStmt = BExprStmt(bsInts.getSpecFree(specTable, getSpecIdVal)) + Some(BRuleDef( genParamName(stg) + "_kill", getMergedCond(killConds, recvConds), deqStmts :+ freeStmt :+ debugStmt)) } - private def getKillConds(cmds: Iterable[Command]): List[BExpr] = { - cmds.foldLeft(List[BExpr]())((l, c) => c match { - //check definitely misspeculated - // isValid(spec) && !fromMaybe(True, check(spec)) + private def getKillConds(cmds: Iterable[Command]): BExpr = { + var resultingConds: BExpr = BDontCare + var readGlobalExnFlag: Boolean = false + cmds.foreach(c => c match { case CCheckSpec(_) => - l :+ BBOp("&&", BIsValid(translator.toBSVVar(specIdVar)), + resultingConds = getMergedCond(resultingConds, BBOp("&&", BIsValid(translator.toBSVVar(specIdVar)), //order is LATE if stage has no update BUOp("!", BFromMaybe(BBoolLit(true), - bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder)))) + bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder))))) //also need these in case we're waiting on responses we need to dequeue case IStageClear() => - l :+ globalExnFlag - + readGlobalExnFlag = true case ICondCommand(cond, cs) => - val condconds = getKillConds(cs) - if (condconds.nonEmpty) { - val nestedConds = condconds.tail.foldLeft(condconds.head)((exp, n) => { - BBOp("&&", exp, n) - }) - val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) - l :+ newCond - } else { - l - } - case _ => l + val nestedConds = getKillConds(cs) + val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) + resultingConds = getMergedCond(resultingConds, newCond) + case _ => BDontCare }) + + if(readGlobalExnFlag){ + resultingConds = BBOp("||", globalExnFlag, resultingConds) + } + + resultingConds } private def translateMethod(mod: BVar, mi: MethodInfo): BMethodInvoke = { @@ -670,115 +677,107 @@ object BluespecGeneration { * @param cmds The list of commands to translate * @return The list of translated blocking commands */ - private def getBlockingConds(cmds: Iterable[Command]): List[BExpr] = { - cmds.foldLeft(List[BExpr]())((l, c) => c match { + private def getBlockingConds(cmds: Iterable[Command]): BExpr = { + var resultingConds: BExpr = BDontCare + cmds.foreach(c => c match { case CLockStart(mod) => - l :+ bsInts.getCheckStart(lockRegions(mod)) + resultingConds = getMergedCond(resultingConds, bsInts.getCheckStart(lockRegions(mod))) case cl@IReserveLock(_, mem) => val methodInfo = LockImplementation.getCanReserveInfo(cl) if (methodInfo.isDefined) { - l :+ translateMethod(modParams(mem.id), methodInfo.get) + resultingConds = getMergedCond(resultingConds, translateMethod(modParams(mem.id), methodInfo.get)) } else { - l + resultingConds } case cl@ICheckLockOwned(mem, _, _) => val methodInfo = LockImplementation.getBlockInfo(cl) if (methodInfo.isDefined) { - l :+ translateMethod(getLockName(mem.id), methodInfo.get) + resultingConds = getMergedCond(resultingConds, translateMethod(getLockName(mem.id), methodInfo.get)) } else { - l + resultingConds } case im@IMemWrite(mem, addr, data, _, _, isAtomic) if isAtomic => val methodInfo = LockImplementation.getCanAtomicWrite(mem, addr, data, im.portNum) if (methodInfo.isDefined) { - l :+ translateMethod(getLockName(mem), methodInfo.get) + resultingConds = getMergedCond(resultingConds, translateMethod(getLockName(mem), methodInfo.get)) } else { - l + resultingConds } case im@IMemSend(_, _, mem, data, addr, _, _, isAtomic) if isAtomic => val methodInfo = LockImplementation.getCanAtomicAccess(mem, addr, data, im.portNum) if (methodInfo.isDefined) { - l :+ translateMethod(getLockName(mem), methodInfo.get) + resultingConds = getMergedCond(resultingConds, translateMethod(getLockName(mem), methodInfo.get)) } else { - l + resultingConds } //these are just to find EMemAccesses that are also atomic - case CAssign(_, rhs) => l ++ getBlockConds(rhs) - case CRecv(_, rhs) => l ++ getBlockConds(rhs) - case COutput(_) => l :+ bsInts.getOutCanWrite(outputQueue, translator.toBSVVar(threadIdVar)) + case CAssign(_, rhs) => resultingConds = getMergedCond(resultingConds, getBlockConds(rhs)) + case CRecv(_, rhs) => resultingConds = getMergedCond(resultingConds, getBlockConds(rhs)) + case COutput(_) => resultingConds = getMergedCond(resultingConds, bsInts.getOutCanWrite(outputQueue, translator.toBSVVar(threadIdVar))) //Execute ONLY if check(specid) == Valid(True) && isValid(specid) // fromMaybe(False, check(specId)) <=> check(specid) == Valid(True) - case CCheckSpec(isBlocking) if isBlocking => l ++ List( + case CCheckSpec(isBlocking) if isBlocking => resultingConds = getMergedCond(resultingConds, BBOp("||", BUOp("!", BIsValid(translator.toBSVVar(specIdVar))), BFromMaybe(BBoolLit(false), bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder)) ) ) //Execute if check(specid) != Valid(False) //fromMaybe(True, check(specId)) <=> check(specid) == (Valid(True) || Invalid) - case CCheckSpec(isBlocking) if !isBlocking => l ++ List( + case CCheckSpec(isBlocking) if !isBlocking => resultingConds = getMergedCond(resultingConds, BBOp("||", BUOp("!", BIsValid(translator.toBSVVar(specIdVar))), //order is LATE if stage has no update BFromMaybe(BBoolLit(true), bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder)) ) ) case ICondCommand(cond, cs) => - val condconds = getBlockingConds(cs) - if (condconds.nonEmpty) { - val nestedConds = condconds.tail.foldLeft(condconds.head)((exp, n) => { - BBOp("&&", exp, n) - }) - val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) - l :+ newCond - } else { - l - } - case _ => l + val nestedConds = getMergedCond(getBlockingConds(cs), BDontCare) + val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) + resultingConds = getMergedCond(resultingConds, newCond) + case _ => resultingConds }) + resultingConds } //only necessary to find atomic Reads and get their blocking conds - private def getBlockConds(e: Expr): List[BExpr] = e match { + private def getBlockConds(e: Expr): BExpr = e match { case EIsValid(ex) => getBlockConds(ex) case EFromMaybe(ex) => getBlockConds(ex) case EToMaybe(ex) => getBlockConds(ex) case EUop(_, ex) => getBlockConds(ex) - case EBinop(_, e1, e2) => getBlockConds(e1) ++ getBlockConds(e2) + case EBinop(_, e1, e2) => getMergedCond(getBlockConds(e1), getBlockConds(e2)) case em@EMemAccess(mem, index, _, _, _, isAtomic) if isAtomic => val methodInfo = LockImplementation.getCanAtomicRead(mem, index, em.portNum) if (methodInfo.isDefined) { - List(translateMethod(getLockName(mem), methodInfo.get)) - } else List() + translateMethod(getLockName(mem), methodInfo.get) + } else BDontCare case EBitExtract(num, _, _) => getBlockConds(num) //can't appear in cond of ternary - case ETernary(_, tval, fval) => getBlockConds(tval) ++ getBlockConds(fval) - case EApp(_, args) => args.foldLeft(List[BExpr]())((l, a) => { - l ++ getBlockConds(a) - }) - case ECall(_, _, args, isAtomic) => args.foldLeft(List[BExpr]())((l, a) => { - l ++ getBlockConds(a) - }) + case ETernary(_, tval, fval) => getMergedCond(getBlockConds(tval), getBlockConds(fval)) + case EApp(_, args) => + var resultingConds: BExpr = BDontCare + args.foreach(a => getMergedCond(resultingConds, getBlockConds(a))) + resultingConds + case ECall(_, _, args, isAtomic) => + var resultingConds: BExpr = BDontCare + args.foreach(a => getMergedCond(resultingConds, getBlockConds(a))) + resultingConds case ECast(_, exp) => getBlockConds(exp) - case _ => List() + case _ => BDontCare } - private def getRecvConds(cmds: Iterable[Command]): List[BExpr] = { - cmds.foldLeft(List[BExpr]())((l, c) => c match { + private def getRecvConds(cmds: Iterable[Command]): BExpr = { + var resultingConds: BExpr = BDontCare + cmds.foreach(c => c match { case IMemRecv(mem: Id, handle: EVar, _: Option[EVar]) => - l :+ bsInts.getCheckMemResp(modParams(mem), translator.toVar(handle), c.portNum, isLockedMemory(mem)) + resultingConds = getMergedCond(resultingConds, bsInts.getCheckMemResp(modParams(mem), translator.toVar(handle), c.portNum, isLockedMemory(mem))) case IRecv(handle, sender, _) => - l :+ bsInts.getModCheckHandle(modParams(sender), translator.toExpr(handle)) + resultingConds = getMergedCond(resultingConds, bsInts.getModCheckHandle(modParams(sender), translator.toExpr(handle))) case ICondCommand(cond, cs) => - val condconds = getRecvConds(cs) - if (condconds.nonEmpty) { - val nestedConds = condconds.tail.foldLeft(condconds.head)((exp, n) => { - BBOp("&&", exp, n) - }) - val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) - l :+ newCond - } else { - l - } - case _ => l + val nestedConds = getMergedCond(getRecvConds(cs), BDontCare) + val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) + resultingConds = getMergedCond(resultingConds, newCond) + case _ => resultingConds }) + resultingConds } /** @@ -1375,6 +1374,7 @@ object BluespecGeneration { case CAssign(_, _) => None case CExpr(_) => None case CEmpty() => None + case ISetGlobalExnFlag(state) => Some(BModAssign(globalExnFlag, BBoolLit(state))) case _: IStageClear => None case _: InternalCommand => throw UnexpectedCommand(cmd) case CRecv(_, _) => throw UnexpectedCommand(cmd) diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala index b0f62ff7..69894fcb 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala @@ -39,21 +39,21 @@ class BluespecInterfaces() { val debugStart = if (debug) { BDisplay(Some("Starting Pipeline %t"), List(BTime)) } else BEmpty val initRule = BRuleDef( name = "initTB", - conds = List(initCond), + conds = initCond, body = initStmts :+ setStartReg :+ debugStart ) val timerRule = BRuleDef( name = "timerCount", - conds = List(), + conds = BDontCare, body = List(BModAssign(timerReg, BBOp("+", timerReg, BOne))) ) val timerDone = BBOp(">=", timerReg, BIntLit(1000000,10,32)) val doneConds = if (modDone.isEmpty) { - List(timerDone) + timerDone } else { - List(BBOp("||", timerDone, modDone.reduce((l, r) => { + BBOp("||", timerDone, modDone.reduce((l, r) => { BBOp("&&", l, r)} - ))) + )) } val doneRule = BRuleDef( name = "stopTB", diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 5af97c32..1efc1849 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -39,6 +39,9 @@ object Syntax { sealed trait SpeculativeAnnotation { var maybeSpec: Boolean = false } + sealed trait ExceptionAnnotation { + var isExcepting: Boolean = false + } sealed trait LockInfoAnnotation { var memOpType: Option[LockType] = None var granularity: LockGranularity = General @@ -649,6 +652,7 @@ object Syntax { case class IAbort(mem: Id) extends InternalCommand case class IStageClear() extends InternalCommand + case class ISetGlobalExnFlag(state: Boolean) extends InternalCommand case class ICondCommand(cond: Expr, cs: List[Command]) extends InternalCommand case class IUpdate(specId: Id, value: EVar, originalSpec: EVar) extends InternalCommand case class ICheck(specId: Id, value: EVar) extends InternalCommand @@ -695,6 +699,7 @@ object Syntax { def map(f : Command => Command) : ExceptBlock def foreach(f : Command => Unit) :Unit def get :Command + def args : List[Id] def copyMeta(other :ExceptBlock) = this.setPos(other.pos) } @@ -703,12 +708,14 @@ object Syntax { { override def map(f: Command => Command): ExceptBlock = this override def foreach(f: Command => Unit): Unit = () + override def args : List[Id] = throw new NoSuchElementException("EmptyExcept") override def get :Command = throw new NoSuchElementException("EmptyExcept") } - case class ExceptFull(args: List[Id], c: Command) extends ExceptBlock + case class ExceptFull(exn_args: List[Id], c: Command) extends ExceptBlock { override def map(f: Command => Command): ExceptBlock = ExceptFull(args, f(c)).copyMeta(this) override def foreach(f: Command => Unit): Unit = f(c) + override def args : List[Id] = exn_args override def get :Command = c } @@ -719,12 +726,13 @@ object Syntax { body: Command, commit_blk: Option[Command], except_blk: ExceptBlock) - extends Definition with RecursiveAnnotation with SpeculativeAnnotation with HasCopyMeta + extends Definition with RecursiveAnnotation with SpeculativeAnnotation with ExceptionAnnotation with HasCopyMeta { override val copyMeta: HasCopyMeta => ModuleDef = { case from :ModuleDef => maybeSpec = from.maybeSpec + isExcepting = from.isExcepting isRecursive = from.isRecursive pos = from.pos this diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index f8ebcf9b..a48096b0 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -198,6 +198,7 @@ object Utilities { }) case ILockNoOp(_) => Set() case IStageClear() => Set() + case ISetGlobalExnFlag(_) => Set() case IAbort(_) => Set() case CLockStart(_) => Set() case CLockEnd(_) => Set() diff --git a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala index 952b9035..c269229b 100644 --- a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -4,8 +4,11 @@ import pipedsl.common.Syntax._ import pipedsl.passes.Passes.{ModulePass, ProgPass} import pipedsl.typechecker.BaseTypeChecker.replaceNamedType -object ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ - private var exnArgMap = Map[Id, Id]() +class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ + private var exnArgIdMap = Map[Id, Id]() + private var exnArgTypeMap = Map[Id, Type]() + + private val localExnFlag = EVar(Id("_localExnFlag")) override def run(m: ModuleDef): ModuleDef = { @@ -22,29 +25,38 @@ object ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ val new_m = addExnVars(m) new_m.name.typ = m.name.typ val modified_exnblk = m.except_blk.map(convertExnArgsId) - createNewStg(new_m.copy(body = new_m.body, commit_blk = new_m.commit_blk, except_blk = modified_exnblk)) + createNewStg(new_m.copy(body = new_m.body, commit_blk = new_m.commit_blk, except_blk = modified_exnblk).copyMeta(m)) } override def run(p: Prog): Prog = p.copy(moddefs = p.moddefs.map(m => run(m))) def addExnVars(m: ModuleDef): ModuleDef = { + localExnFlag.typ = Some(TBool()) + localExnFlag.id.typ = localExnFlag.typ val fixed_except = m.except_blk match { case ExceptFull(args, c) => var arg_count = 0 args.foreach(arg => { - exnArgMap = exnArgMap + (arg -> Id("_exnArg_"+arg_count.toString())) - arg_count += 1 + arg.typ match { + case Some(t: Type) => + val newExnArgId = Id("_exnArg_"+arg_count.toString()) + arg_count += 1 + exnArgIdMap = exnArgIdMap + (arg -> newExnArgId) + exnArgTypeMap = exnArgTypeMap + (newExnArgId -> t) + case _ => + arg_count += 1 + } }) case ExceptEmpty() => CEmpty() } - val newAssignments = exnArgMap.foldLeft(CSeq(CEmpty(), CEmpty()))((c, id_mapping) => { + val newAssignments = exnArgIdMap.foldLeft(CSeq(CEmpty(), CEmpty()))((c, id_mapping) => { val (lhs, rhs) = id_mapping val setCurrArg = CAssign(EVar(lhs), EBool(false)) CSeq(c, setCurrArg) }) - m.copy(body = CSeq(IStageClear(), convertPrimitives(m.body)), commit_blk = m.commit_blk, except_blk = m.except_blk) + m.copy(body = CSeq(IStageClear(), convertPrimitives(m.body)), commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) } def convertPrimitives(c: Command): Command = { @@ -53,24 +65,23 @@ object ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case CIf(cond, cons, alt) => CIf(cond, convertPrimitives(cons), convertPrimitives(alt)).copyMeta(c) case CTBar(c1, c2) => CTBar(convertPrimitives(c1), CSeq(IStageClear(), convertPrimitives(c2))).copyMeta(c) case CSplit(cases, default) => - val newCases = List[CaseObj]() - val newDefault = convertPrimitives(default) - for (index <- cases.indices) { - val newBody = convertPrimitives(cases(index).body) - newCases :+ cases(index).copy(body = newBody) - } - CSplit(newCases, newDefault) + val newCases = cases.map(c => CaseObj(c.cond, convertPrimitives(c.body))) + CSplit(newCases, convertPrimitives(default)).copyMeta(c) case CExcept(args) => - val localflag = EVar(Id("_localExnFlag")) - localflag.typ = Some(TBool()) - localflag.id.typ = localflag.typ - - val setLocalErrFlag = CAssign(localflag, EBool(true)).copyMeta(c) + val setLocalErrFlag = CAssign(localExnFlag, EBool(true)).copyMeta(c) var arg_count = 0 val setArgs: Command = args.foldLeft[Command](CSeq(setLocalErrFlag, CEmpty()))((c, arg) => { - val setCurrArg = CAssign(EVar(Id("_exnArg_"+arg_count.toString())), arg).copyMeta(c) - arg_count += 1 - CSeq(c, setCurrArg).copyMeta(c) + arg.typ match { + case Some(t: Type) => + val translatedVarId = Id("_exnArg_"+arg_count.toString()) + translatedVarId.setType(exnArgTypeMap.getOrElse(translatedVarId, TVoid())) + val translatedVar = EVar(translatedVarId) + translatedVar.typ = translatedVarId.typ + val setCurrArg = CAssign(translatedVar, arg).copyMeta(c) + arg_count += 1 + CSeq(c, setCurrArg).copyMeta(c) + case _ => c + } }) setArgs case _ => c @@ -79,28 +90,27 @@ object ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ def convertExnArgsId(c: Command): Command = { c match { - case CSeq(c1, c2) => CSeq(convertExnArgsId(c1), convertExnArgsId(c2)) - case CIf(cond, cons, alt) => CIf(cond, convertExnArgsId(cons), convertExnArgsId(alt)) - case CTBar(c1, c2) => CSeq(convertExnArgsId(c1), convertExnArgsId(c2)); + case CSeq(c1, c2) => CSeq(convertExnArgsId(c1), convertExnArgsId(c2)).copyMeta(c) + case CIf(cond, cons, alt) => CIf(cond, convertExnArgsId(cons), convertExnArgsId(alt)).copyMeta(c) + case CTBar(c1, c2) => CSeq(convertExnArgsId(c1), convertExnArgsId(c2)).copyMeta(c); case CSplit(cases, default) => - val newCases = List[CaseObj]() - val newDefault = convertExnArgsId(default) - for (index <- cases.indices) { - val newBody = convertExnArgsId(cases(index).body) - newCases :+ cases(index).copy(body = newBody) - } - CSplit(newCases, newDefault) + val newCases = cases.map(c => CaseObj(c.cond, convertExnArgsId(c.body))) + CSplit(newCases, convertExnArgsId(default)).copyMeta(c) case CAssign(v, exp) => - val newv = EVar(exnArgMap.getOrElse(v.id, v.id)).setPos(v.pos) - CAssign(newv, exp) + val newv = EVar(exnArgIdMap.getOrElse(v.id, v.id)).setPos(v.pos) + newv.typ = Some(exnArgTypeMap.getOrElse(v.id, TVoid())) + CAssign(newv, exp).copyMeta(c) case CPrint(args) => val newArgs = args.foldLeft(List[Expr]())((l, arg) => { arg match { - case EVar(id) => l :+ EVar(exnArgMap.getOrElse(id, id)).setPos(arg.pos) + case EVar(id) => + val newv = EVar(exnArgIdMap.getOrElse(id, id)).setPos(c.pos) + newv.typ = Some(exnArgTypeMap.getOrElse(id, TVoid())) + l :+ newv case _ => l } }) - CPrint(newArgs) + CPrint(newArgs).copyMeta(c) case _ => c } } @@ -112,19 +122,20 @@ object ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ } val except_stmts = m.except_blk match { case ExceptFull(_, c) => -// m.modules.filter() - CSeq(IAbort(m.name), c) + val setGlobalExnFlag = ISetGlobalExnFlag(true) + val unsetGlobalExnFlag = ISetGlobalExnFlag(false) + val abortStmts = m.modules.foldLeft(CSeq(CEmpty(), CEmpty()))((c, mod) => + mod.typ match { + case TLockedMemType(mem, _, _) => CSeq(c, IAbort(mod.name)) + case _ => c + }) + CSeq(setGlobalExnFlag, CSeq(abortStmts, CTBar(c, unsetGlobalExnFlag))) case ExceptEmpty() => CEmpty() } - val localflag = EVar(Id("_localExnFlag")) - localflag.typ = Some(TBool()) - localflag.id.typ = localflag.typ - val checkLocalFlag = CIf(localflag, commit_stmts, except_stmts) - val newBody = CTBar(m.body, checkLocalFlag) + val checkLocalFlag = CIf(localExnFlag, commit_stmts, except_stmts) + val newBody = CSeq(m.body, checkLocalFlag) - val inputTyps = m.inputs.foldLeft[List[Type]](List())((l, p) => { l :+ p.typ }) //TODO require memory or module types - m.name.typ = Some(TModType(inputTyps, List[Type](), m.ret, Some(m.name))) - m.copy(body = newBody, commit_blk = None, except_blk = ExceptEmpty()) + m.copy(body = newBody, commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) } } diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index c14f766a..a2715165 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -100,7 +100,15 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { // // } // env.add() - m.except_blk.foreach(checkCommand(m.name, _, bodyEnv)) + if(m.except_blk.isInstanceOf[ExceptFull]){ + val exnenv = m.except_blk.args.foldLeft[Environment[Id, Type]](bodyEnv)((env, arg) => { + arg.typ match { + case Some(t: Type) => env.add(arg, t) + case None => env.add(arg, TVoid()) + } + }) + m.except_blk.foreach(checkCommand(m.name, _, exnenv)) + } outEnv } From 730997ed4700daffba4f027f205ca4ee7985139b Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Tue, 12 Jul 2022 06:45:56 -0400 Subject: [PATCH 23/38] debugs and change kill rule impl --- src/main/scala/pipedsl/Main.scala | 2 +- .../codegen/bsv/BSVPrettyPrinter.scala | 10 +- .../scala/pipedsl/codegen/bsv/BSVSyntax.scala | 2 +- .../codegen/bsv/BluespecGeneration.scala | 188 ++++++++++-------- .../codegen/bsv/BluespecInterfaces.scala | 10 +- .../pipedsl/passes/ExnTranslationPass.scala | 20 +- .../pipedsl/typechecker/PortChecker.scala | 2 +- 7 files changed, 122 insertions(+), 112 deletions(-) diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index 42d1e38f..73884a07 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -106,7 +106,7 @@ object Main { TimingTypeChecker.check(lock_prog, Some(basetypes)) val exnTranslationPass = new ExnTranslationPass() val exnprog = exnTranslationPass.run(lock_prog) - new PrettyPrinter(None).printProgram(exnprog) +// new PrettyPrinter(None).printProgram(exnprog) if (printOutput) { val writer = new PrintWriter(outputFile) writer.write("Passed") diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala index e8b771f0..122df451 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala @@ -239,10 +239,10 @@ object BSVPrettyPrinter { } def printBSVRule(rule: BRuleDef): Unit = { - val condString = rule.conds match { - case BDontCare => "" - case _ => toBSVExprStr(rule.conds) - + val condString = if (rule.conds.nonEmpty) { + "(" + rule.conds.map(c => toBSVExprStr(c)).mkString(" && ") + ")" + } else { + "" } w.write(mkStatementString("rule", rule.name, condString)) incIndent() @@ -250,7 +250,7 @@ object BSVPrettyPrinter { decIndent() w.write(mkIndentedExpr("endrule\n")) } - + def printBSVMethodSig(sig: BMethodSig, cond: Option[BExpr]): Unit = { val mtypstr = sig.typ match { case Action => "Action" diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index b33a472f..a5957e39 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -502,7 +502,7 @@ object BSVSyntax { case class BStructDef(typ: BStruct, derives: List[String]) - case class BRuleDef(name: String, conds: BExpr, body: List[BStatement]) + case class BRuleDef(name: String, conds: List[BExpr], body: List[BStatement]) case class BMethodSig(name: String, typ: MethodType, params: List[BVar]) diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index 8efbaf01..e86f421d 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -551,18 +551,6 @@ object BluespecGeneration { private var stgSpecOrder: Int = 0 - private def getMergedCond(lhs: BExpr, rhs: BExpr): BExpr = { - if (lhs == BDontCare && rhs == BDontCare){ - BDontCare - } else if (lhs == BDontCare){ - rhs - } else if (rhs == BDontCare){ - lhs - } else { - BBOp("&&", lhs, rhs, isInfix = true, omitBrackets = true) - } - } - /** * Given a pipeline stage and the necessary edge info, * generate a BSV module definition. @@ -582,8 +570,8 @@ object BluespecGeneration { //Generate the set of execution rules for reading args and writing outputs val execRule = getStageRule(stg) //Add a stage kill rule if it needs one - val killRule = getStageKillRule(stg) - val rules = if ((mod.maybeSpec && killRule.isDefined) || (is_excepting(mod) && killRule.isDefined)) List(execRule, killRule.get) else List(execRule) + val killRule = getStageKillRule(stg, mod.maybeSpec, is_excepting(mod)) + val rules = if (killRule.isEmpty) List(execRule) else List(execRule) ++ killRule stgSpecOrder = 0 translator.setVariablePrefix("") (sBody, rules) @@ -608,7 +596,7 @@ object BluespecGeneration { BDisplay(Some(mod.name.v + ":Thread %d:Executing Stage " + stg.name + " %t"), List(translator.toBSVVar(threadIdVar), BTime)) } else BEmpty - BRuleDef( genParamName(stg) + "_execute", getMergedCond(blockingConds, recvConds), + BRuleDef( genParamName(stg) + "_execute", blockingConds ++ recvConds, writeCmdDecls ++ writeCmdStmts ++ queueStmts :+ debugStmt) } @@ -619,42 +607,62 @@ object BluespecGeneration { * @param stg - The stage to process * @return Some(BSV) rule if the stage can be killed, else None */ - private def getStageKillRule(stg: PStage): Option[BRuleDef] = { - val killConds = getKillConds(stg.getCmds) + private def getStageKillRule(stg: PStage, is_spec: Boolean, is_excepting: Boolean): List[BRuleDef] = { + val misspecKillConds = getMisspecKillConds(stg.getCmds) + val exnKillConds = getExnKillConds(stg.getCmds) val recvConds = getRecvConds(stg.getCmds) - val debugStmt = if (debug) { - BDisplay(Some(mod.name.v + ":SpecId %d: Killing Stage " + stg.name + "%t"), + val misspecDebugStmt = if (debug) { + BDisplay(Some(mod.name.v + ":SpecId %d: Killing Stage (on Misspec)" + stg.name + "%t"), List(getSpecIdVal, BTime)) } else { BEmpty } + val exnDebugStmt = if (debug) { + BDisplay(Some(mod.name.v + "Killing Stage (on Exception)" + stg.name), + List()) + } else { BEmpty } val deqStmts = getEdgeQueueStmts(stg, stg.inEdges) ++ getRecvCmds(stg.getCmds) val freeStmt = BExprStmt(bsInts.getSpecFree(specTable, getSpecIdVal)) - Some(BRuleDef( genParamName(stg) + "_kill", getMergedCond(killConds, recvConds), deqStmts :+ freeStmt :+ debugStmt)) + val misspecKillRule = Some(BRuleDef( genParamName(stg) + "_kill_on_misspec", misspecKillConds ++ recvConds, deqStmts :+ freeStmt :+ misspecDebugStmt)) + val exnKillRule = Some(BRuleDef(genParamName(stg) + "_kill_on_exn", exnKillConds, deqStmts :+ freeStmt :+ exnDebugStmt)) + + var resultingKillRules = List[BRuleDef]() + if (misspecKillRule.isDefined && is_spec) resultingKillRules = resultingKillRules :+ misspecKillRule.get + if (exnKillRule.isDefined && is_excepting) resultingKillRules = resultingKillRules :+ exnKillRule.get + resultingKillRules + } + + private def getExnKillConds(cmds: Iterable[Command]): List[BExpr] = { + cmds.foldLeft(List[BExpr]())((l, c) => c match { + case IStageClear() => l :+ globalExnFlag + case _ => l + }) } - private def getKillConds(cmds: Iterable[Command]): BExpr = { - var resultingConds: BExpr = BDontCare - var readGlobalExnFlag: Boolean = false - cmds.foreach(c => c match { + private def getMisspecKillConds(cmds: Iterable[Command]): List[BExpr] = { + cmds.foldLeft(List[BExpr]())((l, c) => c match { + //check definitely misspeculated + // isValid(spec) && !fromMaybe(True, check(spec)) case CCheckSpec(_) => - resultingConds = getMergedCond(resultingConds, BBOp("&&", BIsValid(translator.toBSVVar(specIdVar)), + l :+ BBOp("&&", BIsValid(translator.toBSVVar(specIdVar)), //order is LATE if stage has no update BUOp("!", BFromMaybe(BBoolLit(true), - bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder))))) + bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder)))) //also need these in case we're waiting on responses we need to dequeue - case IStageClear() => - readGlobalExnFlag = true case ICondCommand(cond, cs) => - val nestedConds = getKillConds(cs) - val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) - resultingConds = getMergedCond(resultingConds, newCond) - case _ => BDontCare + val condconds = getMisspecKillConds(cs) + if (condconds.nonEmpty) { + val nestedConds = condconds.tail.foldLeft(condconds.head)((exp, n) => { + BBOp("&&", exp, n) + }) + val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) + l :+ newCond + } else { + l + } + case IStageClear() => + val disjointCond = BUOp("!", globalExnFlag) + l :+ disjointCond + case _ => l }) - - if(readGlobalExnFlag){ - resultingConds = BBOp("||", globalExnFlag, resultingConds) - } - - resultingConds } private def translateMethod(mod: BVar, mi: MethodInfo): BMethodInvoke = { @@ -677,107 +685,115 @@ object BluespecGeneration { * @param cmds The list of commands to translate * @return The list of translated blocking commands */ - private def getBlockingConds(cmds: Iterable[Command]): BExpr = { - var resultingConds: BExpr = BDontCare - cmds.foreach(c => c match { + private def getBlockingConds(cmds: Iterable[Command]): List[BExpr] = { + cmds.foldLeft(List[BExpr]())((l, c) => c match { case CLockStart(mod) => - resultingConds = getMergedCond(resultingConds, bsInts.getCheckStart(lockRegions(mod))) + l :+ bsInts.getCheckStart(lockRegions(mod)) case cl@IReserveLock(_, mem) => val methodInfo = LockImplementation.getCanReserveInfo(cl) if (methodInfo.isDefined) { - resultingConds = getMergedCond(resultingConds, translateMethod(modParams(mem.id), methodInfo.get)) + l :+ translateMethod(modParams(mem.id), methodInfo.get) } else { - resultingConds + l } case cl@ICheckLockOwned(mem, _, _) => val methodInfo = LockImplementation.getBlockInfo(cl) if (methodInfo.isDefined) { - resultingConds = getMergedCond(resultingConds, translateMethod(getLockName(mem.id), methodInfo.get)) + l :+ translateMethod(getLockName(mem.id), methodInfo.get) } else { - resultingConds + l } case im@IMemWrite(mem, addr, data, _, _, isAtomic) if isAtomic => val methodInfo = LockImplementation.getCanAtomicWrite(mem, addr, data, im.portNum) if (methodInfo.isDefined) { - resultingConds = getMergedCond(resultingConds, translateMethod(getLockName(mem), methodInfo.get)) + l :+ translateMethod(getLockName(mem), methodInfo.get) } else { - resultingConds + l } case im@IMemSend(_, _, mem, data, addr, _, _, isAtomic) if isAtomic => val methodInfo = LockImplementation.getCanAtomicAccess(mem, addr, data, im.portNum) if (methodInfo.isDefined) { - resultingConds = getMergedCond(resultingConds, translateMethod(getLockName(mem), methodInfo.get)) + l :+ translateMethod(getLockName(mem), methodInfo.get) } else { - resultingConds + l } //these are just to find EMemAccesses that are also atomic - case CAssign(_, rhs) => resultingConds = getMergedCond(resultingConds, getBlockConds(rhs)) - case CRecv(_, rhs) => resultingConds = getMergedCond(resultingConds, getBlockConds(rhs)) - case COutput(_) => resultingConds = getMergedCond(resultingConds, bsInts.getOutCanWrite(outputQueue, translator.toBSVVar(threadIdVar))) - //Execute ONLY if check(specid) == Valid(True) && isValid(specid) - // fromMaybe(False, check(specId)) <=> check(specid) == Valid(True) - case CCheckSpec(isBlocking) if isBlocking => resultingConds = getMergedCond(resultingConds, + case CAssign(_, rhs) => l ++ getBlockConds(rhs) + case CRecv(_, rhs) => l ++ getBlockConds(rhs) + case COutput(_) => l :+ bsInts.getOutCanWrite(outputQueue, translator.toBSVVar(threadIdVar)) + //Execute ONLY if check(specid) == Valid(True) && isValid(specid) + // fromMaybe(False, check(specId)) <=> check(specid) == Valid(True) + case CCheckSpec(isBlocking) if isBlocking => l ++ List( BBOp("||", BUOp("!", BIsValid(translator.toBSVVar(specIdVar))), BFromMaybe(BBoolLit(false), bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder)) ) ) //Execute if check(specid) != Valid(False) //fromMaybe(True, check(specId)) <=> check(specid) == (Valid(True) || Invalid) - case CCheckSpec(isBlocking) if !isBlocking => resultingConds = getMergedCond(resultingConds, + case CCheckSpec(isBlocking) if !isBlocking => l ++ List( BBOp("||", BUOp("!", BIsValid(translator.toBSVVar(specIdVar))), //order is LATE if stage has no update BFromMaybe(BBoolLit(true), bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder)) ) ) case ICondCommand(cond, cs) => - val nestedConds = getMergedCond(getBlockingConds(cs), BDontCare) - val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) - resultingConds = getMergedCond(resultingConds, newCond) - case _ => resultingConds + val condconds = getBlockingConds(cs) + if (condconds.nonEmpty) { + val nestedConds = condconds.tail.foldLeft(condconds.head)((exp, n) => { + BBOp("&&", exp, n) + }) + val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) + l :+ newCond + } else { + l + } + case _ => l }) - resultingConds } //only necessary to find atomic Reads and get their blocking conds - private def getBlockConds(e: Expr): BExpr = e match { + private def getBlockConds(e: Expr): List[BExpr] = e match { case EIsValid(ex) => getBlockConds(ex) case EFromMaybe(ex) => getBlockConds(ex) case EToMaybe(ex) => getBlockConds(ex) case EUop(_, ex) => getBlockConds(ex) - case EBinop(_, e1, e2) => getMergedCond(getBlockConds(e1), getBlockConds(e2)) + case EBinop(_, e1, e2) => getBlockConds(e1) ++ getBlockConds(e2) case em@EMemAccess(mem, index, _, _, _, isAtomic) if isAtomic => val methodInfo = LockImplementation.getCanAtomicRead(mem, index, em.portNum) if (methodInfo.isDefined) { - translateMethod(getLockName(mem), methodInfo.get) - } else BDontCare + List(translateMethod(getLockName(mem), methodInfo.get)) + } else List() case EBitExtract(num, _, _) => getBlockConds(num) //can't appear in cond of ternary - case ETernary(_, tval, fval) => getMergedCond(getBlockConds(tval), getBlockConds(fval)) - case EApp(_, args) => - var resultingConds: BExpr = BDontCare - args.foreach(a => getMergedCond(resultingConds, getBlockConds(a))) - resultingConds - case ECall(_, _, args, isAtomic) => - var resultingConds: BExpr = BDontCare - args.foreach(a => getMergedCond(resultingConds, getBlockConds(a))) - resultingConds + case ETernary(_, tval, fval) => getBlockConds(tval) ++ getBlockConds(fval) + case EApp(_, args) => args.foldLeft(List[BExpr]())((l, a) => { + l ++ getBlockConds(a) + }) + case ECall(_, _, args, isAtomic) => args.foldLeft(List[BExpr]())((l, a) => { + l ++ getBlockConds(a) + }) case ECast(_, exp) => getBlockConds(exp) - case _ => BDontCare + case _ => List() } - private def getRecvConds(cmds: Iterable[Command]): BExpr = { - var resultingConds: BExpr = BDontCare - cmds.foreach(c => c match { + private def getRecvConds(cmds: Iterable[Command]): List[BExpr] = { + cmds.foldLeft(List[BExpr]())((l, c) => c match { case IMemRecv(mem: Id, handle: EVar, _: Option[EVar]) => - resultingConds = getMergedCond(resultingConds, bsInts.getCheckMemResp(modParams(mem), translator.toVar(handle), c.portNum, isLockedMemory(mem))) + l :+ bsInts.getCheckMemResp(modParams(mem), translator.toVar(handle), c.portNum, isLockedMemory(mem)) case IRecv(handle, sender, _) => - resultingConds = getMergedCond(resultingConds, bsInts.getModCheckHandle(modParams(sender), translator.toExpr(handle))) + l :+ bsInts.getModCheckHandle(modParams(sender), translator.toExpr(handle)) case ICondCommand(cond, cs) => - val nestedConds = getMergedCond(getRecvConds(cs), BDontCare) - val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) - resultingConds = getMergedCond(resultingConds, newCond) - case _ => resultingConds + val condconds = getRecvConds(cs) + if (condconds.nonEmpty) { + val nestedConds = condconds.tail.foldLeft(condconds.head)((exp, n) => { + BBOp("&&", exp, n) + }) + val newCond = BBOp("||", BUOp("!", translator.toExpr(cond)), nestedConds) + l :+ newCond + } else { + l + } + case _ => l }) - resultingConds } /** diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala index 69894fcb..b0f62ff7 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala @@ -39,21 +39,21 @@ class BluespecInterfaces() { val debugStart = if (debug) { BDisplay(Some("Starting Pipeline %t"), List(BTime)) } else BEmpty val initRule = BRuleDef( name = "initTB", - conds = initCond, + conds = List(initCond), body = initStmts :+ setStartReg :+ debugStart ) val timerRule = BRuleDef( name = "timerCount", - conds = BDontCare, + conds = List(), body = List(BModAssign(timerReg, BBOp("+", timerReg, BOne))) ) val timerDone = BBOp(">=", timerReg, BIntLit(1000000,10,32)) val doneConds = if (modDone.isEmpty) { - timerDone + List(timerDone) } else { - BBOp("||", timerDone, modDone.reduce((l, r) => { + List(BBOp("||", timerDone, modDone.reduce((l, r) => { BBOp("&&", l, r)} - )) + ))) } val doneRule = BRuleDef( name = "stopTB", diff --git a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala index c269229b..5b76953f 100644 --- a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -12,20 +12,14 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ override def run(m: ModuleDef): ModuleDef = { - val fixed_commit = m.commit_blk match { - case Some(c) => c - case _ => CEmpty() + if(is_excepting(m)){ + val new_m = addExnVars(m) + new_m.name.typ = m.name.typ + val modified_exnblk = m.except_blk.map(convertExnArgsId) + createNewStg(new_m.copy(body = new_m.body, commit_blk = new_m.commit_blk, except_blk = modified_exnblk).copyMeta(m)) + } else { + m } - - val fixed_except = m.except_blk match { - case ExceptFull(_, c) => c - case ExceptEmpty() => CEmpty() - } - - val new_m = addExnVars(m) - new_m.name.typ = m.name.typ - val modified_exnblk = m.except_blk.map(convertExnArgsId) - createNewStg(new_m.copy(body = new_m.body, commit_blk = new_m.commit_blk, except_blk = modified_exnblk).copyMeta(m)) } override def run(p: Prog): Prog = p.copy(moddefs = p.moddefs.map(m => run(m))) diff --git a/src/main/scala/pipedsl/typechecker/PortChecker.scala b/src/main/scala/pipedsl/typechecker/PortChecker.scala index 2aea4b62..1133730f 100644 --- a/src/main/scala/pipedsl/typechecker/PortChecker.scala +++ b/src/main/scala/pipedsl/typechecker/PortChecker.scala @@ -64,7 +64,7 @@ class PortChecker(port_warn :Boolean) extends TypeChecks[Id, (Int, Int)] }) val port_tmp = checkPipe(m.body, emptyEnv()) val port_com = if (m.commit_blk.isDefined) { checkPipe(m.commit_blk.get, port_tmp) } else port_tmp; - val port_map = checkPipe(m.except_blk.get, port_com); + val port_map = if (is_excepting(m)) { checkPipe(m.except_blk.get, port_com) } else port_com; if(port_warn) port_map.getMappedKeys().foreach(mem => { From 96a465b3f60440918db35064d9b22603c2a47e80 Mon Sep 17 00:00:00 2001 From: dz333 Date: Tue, 12 Jul 2022 09:11:02 -0400 Subject: [PATCH 24/38] added a spectable.clear() function that resets it to initial state --- bscRuntime/memories/Speculation.bsv | 12 ++++++++++++ .../pipedsl/codegen/bsv/BluespecInterfaces.scala | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/bscRuntime/memories/Speculation.bsv b/bscRuntime/memories/Speculation.bsv index faaa1822..e2e019ab 100644 --- a/bscRuntime/memories/Speculation.bsv +++ b/bscRuntime/memories/Speculation.bsv @@ -12,6 +12,7 @@ interface SpecTable#(type sid, numeric type bypcnt); method Action free(sid s); method Action validate(sid s, Integer i); method Action invalidate(sid s, Integer i); + method Action clear(); endinterface module mkSpecTable(SpecTable#(SpecId#(entries), bypassCnt)); @@ -53,6 +54,17 @@ module mkSpecTable(SpecTable#(SpecId#(entries), bypassCnt)); inUse[head] <= True; specStatus[head][valueOf(bypassCnt)-1] <= tagged Invalid; endrule + + //reset to the initial state + method Action clear(); + head <= 0; + for (Integer i = 0; i < valueOf(entries); i = i + 1) begin + SpecId#(entries) lv = fromInteger(i); + specStatus[lv][0] <= tagged Invalid; + inUse[lv] <= False; + end + endmethod + //allocate a new entry in the table to track speculation. do this in a nonblocking way //and just assume that only 1 client calls per cycle method ActionValue#(SpecId#(entries)) alloc() if (!full); diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala index b0f62ff7..cc4d3b31 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala @@ -314,6 +314,7 @@ class BluespecInterfaces() { private val specModuleType = "SpecTable" private val specAllocName = "alloc" private val specFreeName = "free" + private val specClearName = "clear" private val specCheckName = "check" private val specValidateName = "validate" private val specInvalidateName = "invalidate" @@ -337,6 +338,10 @@ class BluespecInterfaces() { BMethodInvoke(st, specFreeName, List(h)) } + def getSpecClear(st: BVar): BExpr = { + BMethodInvoke(st, specClearName); + } + def getSpecCheck(st: BVar, h: BExpr, order: Int): BExpr = { BMethodInvoke(st, specCheckName, List(h, BUnsizedInt(order))) } From dc848436130f2531575174590cee029dc09b7ba6 Mon Sep 17 00:00:00 2001 From: dz333 Date: Tue, 12 Jul 2022 10:38:02 -0400 Subject: [PATCH 25/38] added a clear method for our async mems that clears their request queues --- bscRuntime/memories/Memories.bsv | 24 +++++++++++++++++++ .../codegen/bsv/BluespecInterfaces.scala | 11 ++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/bscRuntime/memories/Memories.bsv b/bscRuntime/memories/Memories.bsv index ce2115ff..a49719d4 100644 --- a/bscRuntime/memories/Memories.bsv +++ b/bscRuntime/memories/Memories.bsv @@ -86,6 +86,7 @@ interface AsyncMem#(type addr, type elem, type mid, numeric type nsz); method elem peekResp1(mid a); method Bool checkRespId1(mid a); method Action resp1(mid a); + method Action clear(); interface Client#(Tuple3#(Bit#(nsz), addr, elem), elem) bram_client; endinterface @@ -94,6 +95,7 @@ interface AsyncMem2#(type addr, type elem, type mid, numeric type nsz); method elem peekResp1(mid a); method Bool checkRespId1(mid a); method Action resp1(mid a); + method Action clear(); interface Client#(Tuple3#(Bit#(nsz), addr, elem), elem) bram_client1; method ActionValue#(mid) req2(addr a, elem b, Bit#(nsz) wmask); @@ -351,6 +353,14 @@ module mkAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) _unused_) valid[freeEntry][1] <= False; endrule + method Action clear(); + head <= 0; + for (Integer i = 0; i < valueOf(inflight); i = i + 1) begin + MemId#(inflight) ent = fromInteger(i); + valid[ent][1] <= False; + end + endmethod + method ActionValue#(MemId#(inflight)) req1(addr a, elem b, Bit#(n) wmask) if (okToRequest); toMem <= tuple3(wmask, a, b); head <= head + 1; @@ -437,6 +447,16 @@ module mkAsyncMem2(AsyncMem2#(addr, elem, MemId#(inflight), n) _unused_) valid2[freeEntry2][1] <= False; endrule + method Action clear(); + head1 <= 0; + head2 <= 0; + for (Integer i = 0; i < valueOf(inflight); i = i + 1) begin + MemId#(inflight) ent = fromInteger(i); + valid1[ent][1] <= False; + valid2[ent][1] <= False; + end + endmethod + method ActionValue#(MemId#(inflight)) req1(addr a, elem b, Bit#(n) wmask) if (okToRequest1); toMem1 <= tuple3(wmask, a, b); head1 <= head1 + 1; @@ -1035,6 +1055,10 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos method Action resp1(MemId#(inflight) i); endmethod + method Action clear(); + //TODO determine if there's really something to do here - I don't think so + endmethod + endinterface interface Client bram_client; diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala index cc4d3b31..dc9abc56 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala @@ -224,6 +224,7 @@ class BluespecInterfaces() { private val memAsyncReqName = "req" private val memAsyncRespName = "resp" private val memAsyncCheckName = "checkRespId" + private val memAsyncClearName = "clear" //TODO refactor to reuse code better def toMask(isWrite: Boolean, m: Option[BExpr]): BExpr = { @@ -275,6 +276,14 @@ class BluespecInterfaces() { BMethodInvoke(mem, (if (isLocked) memAsync else "") + memAsyncRespName + portString, List(handle)) } + def getMemClear(mem: BVar, isAsync: Boolean, isLocked: Boolean): Option[BMethodInvoke] = { + if (isAsync) { + Some(BMethodInvoke(mem, (if (isLocked) memAsync else "") + memAsyncClearName, List())) + } else { + None + } + } + /** * Uses the configured fifo interface type and the provided * BSV type to make a paramterized fifo type. @@ -339,7 +348,7 @@ class BluespecInterfaces() { } def getSpecClear(st: BVar): BExpr = { - BMethodInvoke(st, specClearName); + BMethodInvoke(st, specClearName, List()); } def getSpecCheck(st: BVar, h: BExpr, order: Int): BExpr = { From 68245bf9e3f3d939a2303b35e4e0709a2b41525f Mon Sep 17 00:00:00 2001 From: dz333 Date: Tue, 12 Jul 2022 15:22:45 -0400 Subject: [PATCH 26/38] finish problem with old ModLock instantiations --- .../scala/pipedsl/codegen/bsv/BSVSyntax.scala | 17 +++++++++++------ .../pipedsl/common/LockImplementation.scala | 15 +++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index a5957e39..feed2787 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -62,8 +62,8 @@ object BSVSyntax { case TLockedMemType(mem, idsz, limpl) => val lidtyp = if (idsz.isDefined) BSizedInt(unsigned = true, idsz.get) else modmap(n) val cidtyp = if (LockImplementation.supportsCheckpoint(limpl)) { - Some(if (idsz.isDefined) { - BSizedInt(unsigned = true, limpl.getChkIdSize(idsz.get)) + Some(if (idsz.isDefined && limpl.getChkIdSize(idsz.get).isDefined) { + BSizedInt(unsigned = true, limpl.getChkIdSize(idsz.get).get) } else { lockIdToCheckId(modmap(n)) }) @@ -108,8 +108,8 @@ object BSVSyntax { mtyp.tparams.find(bv => bv.name == bsints.reqIdName).get.typ } val cidtyp = if (LockImplementation.supportsCheckpoint(limpl)) { - Some(if (idsz.isDefined) { - bsints.getChkHandleType(limpl.getChkIdSize(idsz.get)) + Some(if (idsz.isDefined && limpl.getChkIdSize(idsz.get).isDefined) { + bsints.getChkHandleType(limpl.getChkIdSize(idsz.get).get) } else bsints.getDefaultChkHandleType) } else { None } //TODO pass checkpoint ID @@ -311,8 +311,13 @@ object BSVSyntax { //TODO make these parameters passable and no just linked to the static lockimpl definition def getLockedModType(limpl: LockInterface): BInterface = { val lid = BVar("lidtyp", bsints.getLockHandleType(limpl.getLockIdSize)) - val chkid = BVar("chkidtyp", bsints.getChkHandleType(limpl.getChkIdSize(limpl.getLockIdSize))) - BInterface(limpl.getModuleName(None), List(lid, chkid)) + val chkid = limpl.getChkIdSize(limpl.getLockIdSize) + if (chkid.isDefined) { + val chktyp = BVar("chkidtyp", bsints.getChkHandleType(chkid.get)) + BInterface(limpl.getModuleName(None), List(lid, chktyp)) + } else { + BInterface(limpl.getModuleName(None), List(lid)) + } } diff --git a/src/main/scala/pipedsl/common/LockImplementation.scala b/src/main/scala/pipedsl/common/LockImplementation.scala index 9465c713..4c189301 100644 --- a/src/main/scala/pipedsl/common/LockImplementation.scala +++ b/src/main/scala/pipedsl/common/LockImplementation.scala @@ -429,7 +429,7 @@ object LockImplementation { def useUniqueLockId(): Boolean = true def getLockIdSize: Int = defaultLockHandleSize - def getChkIdSize(lidSize: Int): Int = defaultChkHandleSize + def getChkIdSize(lidSize: Int): Option[Int] = None def getTypeArgs(szParams: List[Int]): List[Int] = List() @@ -458,7 +458,7 @@ object LockImplementation { */ private class LockQueue extends LockInterface { - private val queueLockName = Id("QueueLock") + protected val queueLockName = Id("QueueLock") override def getType: TObject = TObject(queueLockName, List(), Map( Id(resName) -> (TFun(List(), handleType), Sequential), @@ -484,7 +484,7 @@ object LockImplementation { private class CheckpointLockQueue extends LockQueue { - protected val queueLockName = Id("CheckpointQueueLock") + override protected val queueLockName = Id("CheckpointQueueLock") override def getType: TObject = { val parent = super.getType @@ -506,11 +506,11 @@ object LockImplementation { override def getModInstArgs(m: TMemType, szParams: List[Int]): List[Int] = List() //Checkpoint id must equal the lock id size - override def getChkIdSize(lidSize: Int): Int = lidSize + override def getChkIdSize(lidSize: Int): Option[Int] = Some(lidSize) } //This class should only be used to mediate calls to PDL pipelines - private class ModLock extends CheckpointLockQueue { + private class ModLock extends LockQueue { override def getModuleName(m: Option[TMemType]): String = queueLockName.v override def getModuleName(m: TMemType): String = queueLockName.v @@ -578,6 +578,7 @@ object LockImplementation { override def shortName: String = "BypassQueue" override def getModuleName(m: TMemType): String = "BypassLockCombMem" + } /** @@ -625,7 +626,7 @@ object LockImplementation { override def getModuleName(m: TMemType): String = "CheckpointBypassRF" //Checkpoint id must equal the lock id size - override def getChkIdSize(lidSize: Int): Int = lidSize + override def getChkIdSize(lidSize: Int): Option[Int] = Some(lidSize) } /** @@ -678,6 +679,8 @@ object LockImplementation { override def shortName: String = "CheckpointRF" override def getModuleName(m: TMemType): String = "CheckpointRF" + + override def getChkIdSize(lidSize: Int): Option[Int] = Some(defaultChkHandleSize) } private class ForwardingRegfile extends RenameRegfile { From 7626eebb7799b0a0f9626249c5e3ced366de7b99 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Sat, 30 Jul 2022 17:20:08 -0400 Subject: [PATCH 27/38] tests passed --- .../scala/pipedsl/codegen/bsv/BluespecGeneration.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index e86f421d..929ac8b3 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -570,7 +570,7 @@ object BluespecGeneration { //Generate the set of execution rules for reading args and writing outputs val execRule = getStageRule(stg) //Add a stage kill rule if it needs one - val killRule = getStageKillRule(stg, mod.maybeSpec, is_excepting(mod)) + val killRule = getStageKillRules(stg, mod.maybeSpec, is_excepting(mod)) val rules = if (killRule.isEmpty) List(execRule) else List(execRule) ++ killRule stgSpecOrder = 0 translator.setVariablePrefix("") @@ -607,7 +607,7 @@ object BluespecGeneration { * @param stg - The stage to process * @return Some(BSV) rule if the stage can be killed, else None */ - private def getStageKillRule(stg: PStage, is_spec: Boolean, is_excepting: Boolean): List[BRuleDef] = { + private def getStageKillRules(stg: PStage, is_spec: Boolean, is_excepting: Boolean): List[BRuleDef] = { val misspecKillConds = getMisspecKillConds(stg.getCmds) val exnKillConds = getExnKillConds(stg.getCmds) val recvConds = getRecvConds(stg.getCmds) @@ -625,8 +625,8 @@ object BluespecGeneration { val exnKillRule = Some(BRuleDef(genParamName(stg) + "_kill_on_exn", exnKillConds, deqStmts :+ freeStmt :+ exnDebugStmt)) var resultingKillRules = List[BRuleDef]() - if (misspecKillRule.isDefined && is_spec) resultingKillRules = resultingKillRules :+ misspecKillRule.get - if (exnKillRule.isDefined && is_excepting) resultingKillRules = resultingKillRules :+ exnKillRule.get + if (misspecKillRule.isDefined && is_spec && !misspecKillConds.isEmpty) resultingKillRules = resultingKillRules :+ misspecKillRule.get + if (exnKillRule.isDefined && is_excepting && !exnKillConds.isEmpty) resultingKillRules = resultingKillRules :+ exnKillRule.get resultingKillRules } From 60c58bbf1df3ea5b498ba9d3b199fdcae7249298 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Tue, 29 Nov 2022 08:34:37 -0500 Subject: [PATCH 28/38] tests and fixes --- src/main/scala/pipedsl/Main.scala | 3 +- .../codegen/bsv/BluespecGeneration.scala | 2 +- .../scala/pipedsl/common/PrettyPrinter.scala | 6 + .../pipedsl/passes/ExnTranslationPass.scala | 81 +++-- .../pipedsl/typechecker/BaseTypeChecker.scala | 1 + .../typechecker/TimingTypeChecker.scala | 6 +- src/test/scala/pipedsl/ExceptionSuite.scala | 30 ++ src/test/scala/pipedsl/package.scala | 1 + .../scala/pipedsl/project/build.properties | 1 + .../tests/exception/exn-recovery-spec.pdl | 62 ++++ src/test/tests/exception/exn-recovery.pdl | 48 +++ .../tests/exception/exn-risc-pipe-basic.pdl | 337 ++++++++++++++++++ src/test/tests/exception/exn-simple-spec.pdl | 53 +++ src/test/tests/exception/exn-simple.pdl | 35 ++ src/test/tests/exception/memInputs/rename | 32 ++ src/test/tests/exception/memInputs/ti | 14 + .../solutions/exn-simple-1.typechecksol | 1 + 17 files changed, 679 insertions(+), 34 deletions(-) create mode 100644 src/test/scala/pipedsl/ExceptionSuite.scala create mode 100644 src/test/scala/pipedsl/project/build.properties create mode 100644 src/test/tests/exception/exn-recovery-spec.pdl create mode 100644 src/test/tests/exception/exn-recovery.pdl create mode 100644 src/test/tests/exception/exn-risc-pipe-basic.pdl create mode 100644 src/test/tests/exception/exn-simple-spec.pdl create mode 100644 src/test/tests/exception/exn-simple.pdl create mode 100644 src/test/tests/exception/memInputs/rename create mode 100644 src/test/tests/exception/memInputs/ti create mode 100644 src/test/tests/exception/solutions/exn-simple-1.typechecksol diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index 73884a07..43942661 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -72,7 +72,6 @@ object Main { val prog = parse(debug = false, printOutput = false, inputFile, outDir, rfLockImpl = rfLockImpl) try { - // new PrettyPrinter(None).printProgram(prog) val pinfo = new ProgInfo(prog) MarkNonRecursiveModulePass.run(prog) //First: add lock regions + checkpoints, then do other things @@ -106,7 +105,7 @@ object Main { TimingTypeChecker.check(lock_prog, Some(basetypes)) val exnTranslationPass = new ExnTranslationPass() val exnprog = exnTranslationPass.run(lock_prog) -// new PrettyPrinter(None).printProgram(exnprog) + new PrettyPrinter(None).printProgram(exnprog) if (printOutput) { val writer = new PrintWriter(outputFile) writer.write("Passed") diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index 929ac8b3..584bd365 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -622,7 +622,7 @@ object BluespecGeneration { val deqStmts = getEdgeQueueStmts(stg, stg.inEdges) ++ getRecvCmds(stg.getCmds) val freeStmt = BExprStmt(bsInts.getSpecFree(specTable, getSpecIdVal)) val misspecKillRule = Some(BRuleDef( genParamName(stg) + "_kill_on_misspec", misspecKillConds ++ recvConds, deqStmts :+ freeStmt :+ misspecDebugStmt)) - val exnKillRule = Some(BRuleDef(genParamName(stg) + "_kill_on_exn", exnKillConds, deqStmts :+ freeStmt :+ exnDebugStmt)) + val exnKillRule = Some(BRuleDef(genParamName(stg) + "_kill_on_exn", exnKillConds, deqStmts :+ exnDebugStmt)) var resultingKillRules = List[BRuleDef]() if (misspecKillRule.isDefined && is_spec && !misspecKillConds.isEmpty) resultingKillRules = resultingKillRules :+ misspecKillRule.get diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index b3bf7b3f..f53c4504 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -128,6 +128,12 @@ class PrettyPrinter(output: Option[File]) { case Syntax.ICheck(specId, value) => ins + "check(" + specId + ", " + printExprToString(value) + ");" case Syntax.CCheckpoint(h, m) => ins + printExprToString(h) + " <- checkpoint(" + m.v + ");" case Syntax.CExcept(args) => ins + "except(" + args.map(printExprToString).foldLeft("")((acc, elem) => acc + ", " + elem) + ");" + case Syntax.CCheckSpec(isBlk) => ins + (if (isBlk) "spec_barrier();" else "spec_check();") + case Syntax.IAbort(mem) => ins + "abort(" + mem +");" + case Syntax.IStageClear() => ins + "clearOnExn();" + case Syntax.ISetGlobalExnFlag(state) => ins + "setGlobalExnFlag(" + state +");" + case Syntax.IReleaseLock(mem, inHandle) => ins + "release(" + mem + ");" + case Syntax.IReserveLock(mem, inHandle) => ins + "reserve(" + mem + ");" case _ => "TODO PRINTING COMMAND" } } diff --git a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala index 5b76953f..a5039a64 100644 --- a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -5,8 +5,8 @@ import pipedsl.passes.Passes.{ModulePass, ProgPass} import pipedsl.typechecker.BaseTypeChecker.replaceNamedType class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ - private var exnArgIdMap = Map[Id, Id]() - private var exnArgTypeMap = Map[Id, Type]() + private var exnArgCallMap = Map[Int, EVar]() + private var exnArgApplyMap = Map[Id, EVar]() private val localExnFlag = EVar(Id("_localExnFlag")) @@ -32,12 +32,16 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case ExceptFull(args, c) => var arg_count = 0 args.foreach(arg => { + arg.typ match { case Some(t: Type) => val newExnArgId = Id("_exnArg_"+arg_count.toString()) + newExnArgId.typ = Some(t) + val newExnArgVar = EVar(newExnArgId) + newExnArgVar.typ = Some(t) + exnArgCallMap = exnArgCallMap + (arg_count -> newExnArgVar) + exnArgApplyMap = exnArgApplyMap + (arg -> newExnArgVar) arg_count += 1 - exnArgIdMap = exnArgIdMap + (arg -> newExnArgId) - exnArgTypeMap = exnArgTypeMap + (newExnArgId -> t) case _ => arg_count += 1 } @@ -45,11 +49,6 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case ExceptEmpty() => CEmpty() } - val newAssignments = exnArgIdMap.foldLeft(CSeq(CEmpty(), CEmpty()))((c, id_mapping) => { - val (lhs, rhs) = id_mapping - val setCurrArg = CAssign(EVar(lhs), EBool(false)) - CSeq(c, setCurrArg) - }) m.copy(body = CSeq(IStageClear(), convertPrimitives(m.body)), commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) } @@ -67,10 +66,7 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ val setArgs: Command = args.foldLeft[Command](CSeq(setLocalErrFlag, CEmpty()))((c, arg) => { arg.typ match { case Some(t: Type) => - val translatedVarId = Id("_exnArg_"+arg_count.toString()) - translatedVarId.setType(exnArgTypeMap.getOrElse(translatedVarId, TVoid())) - val translatedVar = EVar(translatedVarId) - translatedVar.typ = translatedVarId.typ + val translatedVar = exnArgCallMap.getOrElse(arg_count, EVar(Id("_Undefined_"))) val setCurrArg = CAssign(translatedVar, arg).copyMeta(c) arg_count += 1 CSeq(c, setCurrArg).copyMeta(c) @@ -85,27 +81,55 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ def convertExnArgsId(c: Command): Command = { c match { case CSeq(c1, c2) => CSeq(convertExnArgsId(c1), convertExnArgsId(c2)).copyMeta(c) - case CIf(cond, cons, alt) => CIf(cond, convertExnArgsId(cons), convertExnArgsId(alt)).copyMeta(c) - case CTBar(c1, c2) => CSeq(convertExnArgsId(c1), convertExnArgsId(c2)).copyMeta(c); + case CIf(cond, cons, alt) => CIf(convertExnArgsId(cond), convertExnArgsId(cons), convertExnArgsId(alt)).copyMeta(c) + case CTBar(c1, c2) => CTBar(convertExnArgsId(c1), convertExnArgsId(c2)).copyMeta(c); case CSplit(cases, default) => val newCases = cases.map(c => CaseObj(c.cond, convertExnArgsId(c.body))) CSplit(newCases, convertExnArgsId(default)).copyMeta(c) case CAssign(v, exp) => - val newv = EVar(exnArgIdMap.getOrElse(v.id, v.id)).setPos(v.pos) - newv.typ = Some(exnArgTypeMap.getOrElse(v.id, TVoid())) - CAssign(newv, exp).copyMeta(c) + val newv = exnArgApplyMap.getOrElse(v.id, EVar(v.id)).setPos(c.pos) + CAssign(newv, convertExnArgsId(exp)).copyMeta(c) + case CExpr(exp) => + CExpr(convertExnArgsId(exp)).copyMeta(c) case CPrint(args) => + val newArgs = args.map(convertExnArgsId) + CPrint(newArgs).copyMeta(c) + case _ => c + } + } + + def convertExnArgsId(e: Expr): Expr = { + e match { + case EIsValid(ex) => EIsValid(convertExnArgsId(ex)) + case EFromMaybe(ex) => EFromMaybe(convertExnArgsId(ex)) + case EToMaybe(ex) => EToMaybe(convertExnArgsId(ex)) + case EUop(op, ex) => EUop(op, convertExnArgsId(ex)) + case EBinop(op, e1, e2) => EBinop(op, convertExnArgsId(e1), convertExnArgsId(e2)) + case EApp(func, args) => { val newArgs = args.foldLeft(List[Expr]())((l, arg) => { arg match { case EVar(id) => - val newv = EVar(exnArgIdMap.getOrElse(id, id)).setPos(c.pos) - newv.typ = Some(exnArgTypeMap.getOrElse(id, TVoid())) + val newv = exnArgApplyMap.getOrElse(id, EVar(id)).setPos(e.pos) l :+ newv - case _ => l + case _ => l :+ arg } }) - CPrint(newArgs).copyMeta(c) - case _ => c + EApp(func, newArgs) + } + case ECall(mod, name, args, isAtomic) => { + val newArgs = args.foldLeft(List[Expr]())((l, arg) => { + arg match { + case EVar(id) => + val newv = exnArgApplyMap.getOrElse(id, EVar(id)).setPos(e.pos) + l :+ newv + case _ => l :+ arg + } + }) + ECall(mod, name, newArgs, isAtomic) + } + case ECast(ctyp, e) => ECast(ctyp, convertExnArgsId(e)) + case EVar(id) => exnArgApplyMap.getOrElse(id, EVar(id)).setPos(e.pos) + case _ => e } } @@ -120,14 +144,15 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ val unsetGlobalExnFlag = ISetGlobalExnFlag(false) val abortStmts = m.modules.foldLeft(CSeq(CEmpty(), CEmpty()))((c, mod) => mod.typ match { - case TLockedMemType(mem, _, _) => CSeq(c, IAbort(mod.name)) - case _ => c + case TLockedMemType(mem, _, _) => CSeq(IAbort(mod.name), setGlobalExnFlag) + case _ => CSeq(CEmpty(), setGlobalExnFlag) }) - CSeq(setGlobalExnFlag, CSeq(abortStmts, CTBar(c, unsetGlobalExnFlag))) + CTBar(abortStmts, CSeq(c, unsetGlobalExnFlag)) case ExceptEmpty() => CEmpty() } - val checkLocalFlag = CIf(localExnFlag, commit_stmts, except_stmts) - val newBody = CSeq(m.body, checkLocalFlag) + val initLocalErrFlag = CAssign(localExnFlag, EBool(false)).copyMeta(m.body) + val finalBlocks = CIf(localExnFlag, CTBar(CEmpty(),except_stmts), commit_stmts) + val newBody = CSeq(initLocalErrFlag, CSeq(m.body,finalBlocks)) //TODO require memory or module types m.copy(body = newBody, commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index a2715165..2c456ef1 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -681,6 +681,7 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { id.typ = Some(t) (t, tenv) } else { + println(id) throw UnexpectedType(id.pos, "variable", s"variable type set to new conflicting type : ${tenv(id)}", t) } case None if (tenv.get(id).isDefined || defaultType.isEmpty) => id.typ = Some(tenv(id)); (tenv(id), tenv) diff --git a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala index 00055f30..546bc29a 100644 --- a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala @@ -35,11 +35,11 @@ object TimingTypeChecker extends TypeChecks[Id, Type] { val allAvailable = m.modules.foldLeft[Available](inputs)((av, m) => { av + m.name }) - checkCommand(m.extendedBody(), allAvailable, NoneAvailable) + checkCommand(m.extendedBody(), allAvailable, NoneAvailable) m.except_blk match { case ExceptEmpty() => () - case ExceptFull(args, c) => val inputs = args.foldLeft[Available](NoneAvailable)((av, p) => av + p) - val allAvailable = m.modules.foldLeft(inputs)((av, m) => av + m.name) + case ExceptFull(args, c) => val exceptInputs = args.foldLeft[Available](inputs)((av, p) => av + p) + val allAvailable = m.modules.foldLeft(exceptInputs)((av, m) => av + m.name) checkCommand(c, allAvailable, NoneAvailable) } env diff --git a/src/test/scala/pipedsl/ExceptionSuite.scala b/src/test/scala/pipedsl/ExceptionSuite.scala new file mode 100644 index 00000000..80ece317 --- /dev/null +++ b/src/test/scala/pipedsl/ExceptionSuite.scala @@ -0,0 +1,30 @@ +package pipedsl + +import org.scalatest.funsuite.AnyFunSuite + +import java.io.File + +class ExceptionSuite extends AnyFunSuite{ + private val folder = "src/test/tests/exception" + private val testFiles = getListOfTests(folder) + private val testFolder = new File(folder) + + private val inputFolder = folder + "/memInputs" + private val inputRF = inputFolder + "/rename" + private val inputIMEM = inputFolder + "/ti" + private val inputMap = Map("rename" -> inputRF, "ti" -> inputIMEM) + + testFiles.foreach(t => { + val testBaseName = getTestName(t) +// val simFile = getSimFile(testFolder, testBaseName) +// test(testBaseName + " Typecheck; Compile; Simulate") { +// val doesTypecheck = testTypecheck(testFolder, t) +// if (doesTypecheck) { +// testBlueSpecCompile(testFolder, t, None, inputMap) +// if (simFile.exists) { +// testBlueSpecSim(testFolder, t, None, inputMap) +// } +// } +// } + }) +} diff --git a/src/test/scala/pipedsl/package.scala b/src/test/scala/pipedsl/package.scala index a9f43b30..c3760912 100644 --- a/src/test/scala/pipedsl/package.scala +++ b/src/test/scala/pipedsl/package.scala @@ -69,6 +69,7 @@ package object pipedsl { def testBlueSpecSim(testDir: File, inputFile: File, addrLockMod: Option[String] = None, memInit: Map[String, String], simFile: Option[String] = None): Unit = { val _ = (pathToBluespecScript + " c " + testDir.getAbsolutePath).!! Main.gen(testDir, inputFile, printStgInfo = false, debug = false, memInit, portWarn = false, autocast = false, addrLockMod) + Console.err.println((pathToBluespecScript + " s " + testDir.getAbsolutePath + " " + FilenameUtils.getBaseName(inputFile.getName) + ".sim")) val exit = (pathToBluespecScript + " s " + testDir.getAbsolutePath + " " + FilenameUtils.getBaseName(inputFile.getName) + ".sim").! val success = exit == 0 && compareFiles(testDir, inputFile, "sim", simFile) deleteGeneratedFiles(testDir) diff --git a/src/test/scala/pipedsl/project/build.properties b/src/test/scala/pipedsl/project/build.properties new file mode 100644 index 00000000..c8fcab54 --- /dev/null +++ b/src/test/scala/pipedsl/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.6.2 diff --git a/src/test/tests/exception/exn-recovery-spec.pdl b/src/test/tests/exception/exn-recovery-spec.pdl new file mode 100644 index 00000000..017c76aa --- /dev/null +++ b/src/test/tests/exception/exn-recovery-spec.pdl @@ -0,0 +1,62 @@ +//Expect 5 Success, 1 Exception, 1 Success post recovery +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { +spec_check(); + start(acc); + reserve(acc); + checkpoint(acc); + end(acc); + print("PC: %d", pc); + --- + spec_check(); + s <- speccall cpu(pc + 1); + --- + spec_barrier(); + block(acc); + acc_val = acc[0]; + acc[0] <- acc_val + 1; + print(acc_val); + if(acc_val == 7) + { + invalidate(s); + except(u0<4>); + } else { + if(acc_val == 2) + { + invalidate(s); + print("3 Should not present!"); + call cpu(pc + 3); + } else { + if(acc_val == 9){ + print("recovered from exception"); + invalidate(s); + output(0); + } else { + verify(s, pc + 1); + } + } + } + --- +commit: + release(acc); + print("no exn here!"); +except(arg: uint<4>): + print("exception... with arg: %d", arg); + start(acc); + reserve(acc); + end(acc); + --- + block(acc); + acc[0] <- 9; + --- + release(acc); + call cpu(pc + 1); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 0); + locked = CheckpointQueue(acc); + c = new cpu[locked]; + call c(u1<16>); +} diff --git a/src/test/tests/exception/exn-recovery.pdl b/src/test/tests/exception/exn-recovery.pdl new file mode 100644 index 00000000..9fe18b9b --- /dev/null +++ b/src/test/tests/exception/exn-recovery.pdl @@ -0,0 +1,48 @@ +//Expect 5 Success, 1 Exception, 1 Success post recovery +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { + start(acc); + reserve(acc); + end(acc); + print("PC: %d", pc); + --- + block(acc); + acc_val = acc[0]; + acc[0] <- acc_val + 1; + print(acc_val); + if(acc_val == 5) + { + except(u0<4>); + } else + { + if(acc_val == 7){ + print("recovered from exception"); + output(0); + } else { + call cpu(pc + 1); + } + } + --- +commit: + release(acc); + print("no exn here!"); +except(arg: uint<4>): + print("exception... with arg: %d", arg); + start(acc); + reserve(acc); + end(acc); + --- + block(acc); + acc[0] <- 7; + --- + release(acc); + call cpu(pc + 1); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 0); + locked = CheckpointQueue(acc); + c = new cpu[locked]; + call c(u1<16>); +} diff --git a/src/test/tests/exception/exn-risc-pipe-basic.pdl b/src/test/tests/exception/exn-risc-pipe-basic.pdl new file mode 100644 index 00000000..5ca3ffe7 --- /dev/null +++ b/src/test/tests/exception/exn-risc-pipe-basic.pdl @@ -0,0 +1,337 @@ +def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { + uint<32> mag1 = cast(mag(arg1), uint<32>); + uint<32> mag2 = cast(mag(arg2), uint<32>); + //MULHU => positive sign always + int<32> s1 = (op == 3) ? 1 : sign(arg1); + //MULHU/MULHSU => positive sign always + int<32> s2 = (op >= 2) ? 1 : sign(arg2); + int<64> magRes = cast((mag1 * mag2), int<64>); + int<64> m = (s1 == s2) ? (magRes) : -(magRes); + if (op == 0) { //MUL + return m{31:0}; + } else { + return m{63:32}; + } +} + +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + shamt = cast(arg2{4:0}, uint<5>); + if (op == 0) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2) { //010 == SLT + return (arg1 < arg2) ? 1 : 0; + } else { + if (op == u3) { //011 == SLTU + un1 = cast(arg1, uint<32>); + un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1 : 0; + } else { + if (op == u4) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +def br(pc: int<16>, off:int<16>, op:uint<3>, arg1:int<32>, arg2:int<32>): int<16> { + //divide by 4 b/c we count instructions not bytes + offpc = pc + (off >> 2); + npc = pc + 1<16>; + if (op == u0<3>) { //BEQ + if (arg1 == arg2) { return offpc; } else { return npc; } + } else { + if (op == u1<3>) { //BNE + if (arg1 != arg2) { return offpc; } else { return npc; } + } else { + if (op == u4<3>) { //BLT + if (arg1 < arg2) { return offpc; } else { return npc; } + } else { + if (op == u5<3>) { //BGE + if (arg1 >= arg2) { return offpc; } else { return npc; } + } else { + if (op == u6<3>) { //BLTU + un1 = cast(arg1, uint<32>); + un2 = cast(arg2, uint<32>); + if (un1 < un2) { return offpc; } else { return npc; } + } else { + if (op == u7<3>) { //BGEU + un1 = cast(arg1, uint<32>); + un2 = cast(arg2, uint<32>); + if (un1 >= un2) { return offpc; } else { return npc; } + } else { + return npc; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return ((1) << (off)); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + boff = start ++ u0<3>; + tmp = data >> boff; + bdata = cast(tmp, uint<8>); + hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0; + }}}}} +} + +pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32>, cnt: uint<5>, retQuot: bool)[]: uint<32> { + tmp = acc{30:0} ++ num{31:31}; + na = (tmp >= denom) ? (tmp - denom) : (tmp); + nq = (tmp >= denom) ? ((quot << 1){31:1} ++ 1) : (quot << 1); + nnum = num << 1; + if (cnt == 31) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + 1, retQuot); + } +} + + +exn-pipe cpu(pc: int<16>)[rf: int<32>[5](FAQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div]: bool { + spec_check(); + start(imem); + pcaddr = cast(pc, uint<16>); + insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + spec_barrier(); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if ((!done) && notBranch) { + verify(s, pc + 1<16>); + } else { + invalidate(s); + } + start(rf); + if (needrs1) { + int<32> rf1 = rf[rs1]; + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + int<32> rf2 = rf[rs2]; + } else { + int<32> rf2 = 0<32>; + } + if (writerd) { + reserve(rf[rd]); + } + end(rf); + --- + if (isBranch) { + int<16> npc = br(pc, immB, funct3, rf1, rf2); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + if ((!done) && (!notBranch)) { call cpu(npc); } + + int<32> alu_arg2 = (isOpImm) ? immI : rf2; + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + bool invertRes = isSignedDiv && (sdividend != sdivisor); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + if(divisor == u0<32>){ + uint<32> udivout <- u0<32>; + except(u1<4>); + } else { + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } + } else { + uint<32> udivout <- u0<32>; + bool invertRes = false; + } + --- + split { + case: (isLui) { + int<32> alu_res = immU; + } + case: (isAui) { + //all pc computation needs to be multiplied by 4 + int<32> pc32 = (0<16> ++ pc) << 2; + int<32> alu_res = pc32 + immU; + } + case: (isDiv) { + int<32> alu_res = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + } + case: (isMDiv) { + int<32> alu_res = mul(rf1, rf2, funct3); + } + default: { + int<32> alu_res = alu(rf1, alu_arg2, funct3, flip); + } + } + split { + case: (isStore) { + //addresses also are word-sized + int<32> tmp = immS + rf1; + uint<32> ctmp = cast(tmp, uint<32>); + uint<16> memaddr = (ctmp >> 2){15:0}; + uint<2> boff = ctmp{1:0}; + } + case: (isLoad) { + //addresses also are word-sized + int<32> tmp = immI + rf1; + uint<32> ctmp = cast(tmp, uint<32>); + uint<16> memaddr = (ctmp >> 2){15:0}; + uint<2> boff = ctmp{1:0}; + } + default: { + uint<16> memaddr = u0<16>; + uint<2> boff = u0<2>; + } + } + --- +commit: + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + block(rf[rd]); + if (isLoad) { + int<32> insnout = maskLoad(wdata, funct3, boff); + } else { + if (isJal || isJalr) { + //need to multiply by 4 b/c it is arch visible. + int<16> nextpc = pc + 1<16>; + int<32> insnout = 0<16> ++ (nextpc << 2); //todo make pc 32 bits + } else { + int<32> insnout = alu_res; + }} + print("Writing %d to r%d", insnout, rd); + rf[rd] <- insnout; + release(rf[rd]); + } + if (done) { output(true); } +except(errcode: uint<4>): + if(errcode == u1<4>){ + print("Div by zero"); + } + --- + output(false); +} + +circuit { + ti = memory(int<32>, 16); + i = Queue(ti); + td = memory(int<32>, 16); + rf = regfile(int<32>, 5); + r = FAQueue(rf); + div = new multi_stg_div[]; + c = new cpu[r, i, td, div]; + call c(0<16>); +} diff --git a/src/test/tests/exception/exn-simple-spec.pdl b/src/test/tests/exception/exn-simple-spec.pdl new file mode 100644 index 00000000..9298a155 --- /dev/null +++ b/src/test/tests/exception/exn-simple-spec.pdl @@ -0,0 +1,53 @@ +//Expected Success +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { + spec_check(); + start(acc); + reserve(acc); + checkpoint(acc); + end(acc); + print("PC: %d", pc); + --- + spec_check(); + s <- speccall cpu(pc + 1); + --- + spec_barrier(); + block(acc); + acc_val = acc[0]; + acc[0] <- acc_val + 1; + print(acc_val); + if(acc_val == 7) + { + invalidate(s); + except(u0<4>); + } else { + if(acc_val == 2) + { + invalidate(s); + print("3 Should not present!"); + call cpu(pc + 3); + } else { + if(acc_val == 8){ + invalidate(s); + output(0); + } else { + verify(s, pc + 1); + } + } + } + --- +commit: + release(acc); + print("no exn here!"); +except(arg :uint<4>): + print("exception... with arg: %d", arg); + output(1); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 0); + locked = CheckpointQueue(acc); + c = new cpu[locked]; + call c(u1<16>); +} diff --git a/src/test/tests/exception/exn-simple.pdl b/src/test/tests/exception/exn-simple.pdl new file mode 100644 index 00000000..3c70b92e --- /dev/null +++ b/src/test/tests/exception/exn-simple.pdl @@ -0,0 +1,35 @@ +//Expect 5 Success, 1 Exception +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { + start(acc); + reserve(acc); + end(acc); + print("PC: %d", pc); + --- + block(acc); + acc_val = acc[0]; + acc[0] <- acc_val + 1; + print(acc_val); + if(acc_val == 6) + { + except(u0<4>); + } else + { + call cpu(pc + 1); + } + --- +commit: + release(acc); + print("no exn here!"); +except(arg :uint<4>): + print("exception... with arg: %d", arg); + output(1); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 0); + locked = CheckpointQueue(acc); + c = new cpu[locked]; + call c(u1<16>); +} diff --git a/src/test/tests/exception/memInputs/rename b/src/test/tests/exception/memInputs/rename new file mode 100644 index 00000000..5c240de2 --- /dev/null +++ b/src/test/tests/exception/memInputs/rename @@ -0,0 +1,32 @@ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +1a +1b +1c +1d +1e +1f \ No newline at end of file diff --git a/src/test/tests/exception/memInputs/ti b/src/test/tests/exception/memInputs/ti new file mode 100644 index 00000000..5f5c8d62 --- /dev/null +++ b/src/test/tests/exception/memInputs/ti @@ -0,0 +1,14 @@ +// 1111 1111 1111 11111 11111 11111 1111 1 +// rd rs2 rs1 brImm op +00000000 // rf[0] <= rf[0] + rf[0] ; pc + 1 PRED CORRECT (print 0) +00000000 // rf[0] <= rf[0] + rf[0] ; pc + 1 PRED CORRECT (print 0) +00000005 // beq rf[0], rf[0], pc + 2 ; pc + 2 PRED WRONG +00000005 // beq rf[0], rf[0], pc + 2 ; SKIPPED +00008420 // rf[1] <= rf[1] + rf[1] ; pc + 1 PRED CORRECT (print 2) +00000025 // beq rf[0], rf[1], pc + 2 ; pc + 1 PRED CORRECT +00000425 // beq rf[1], rf[1], pc + 2 ; pc + 2 PRED WRONG +00000420 // rf[0] <= rf[1] + rf[1] ; pc + 1 SKIPPED +00000845 // beq rf[2], rf[2], pc + 2 ; pc + 2 PRED WRONG +00000000 // w/e SKIPPED +00000420 // rf[0] <= rf[1] + rf[1] ; pc + 1 PRED CORRECT (print 4) +ffffffff // END \ No newline at end of file diff --git a/src/test/tests/exception/solutions/exn-simple-1.typechecksol b/src/test/tests/exception/solutions/exn-simple-1.typechecksol new file mode 100644 index 00000000..9fb4ec93 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-simple-1.typechecksol @@ -0,0 +1 @@ +Passed \ No newline at end of file From 7fdfe43a1c6611191f9ddb18a31ddcaf5df94e0e Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 1 Mar 2023 00:08:23 -0500 Subject: [PATCH 29/38] resolve all comments and fix bugs, add ehr --- src/main/scala/pipedsl/Main.scala | 1 - .../codegen/bsv/BSVPrettyPrinter.scala | 3 ++ .../scala/pipedsl/codegen/bsv/BSVSyntax.scala | 3 ++ .../codegen/bsv/BluespecGeneration.scala | 18 ++++++----- .../codegen/bsv/BluespecInterfaces.scala | 10 ++++++ .../scala/pipedsl/common/PrettyPrinter.scala | 5 +++ src/main/scala/pipedsl/common/Syntax.scala | 1 + src/main/scala/pipedsl/common/Utilities.scala | 1 + .../pipedsl/passes/ExnTranslationPass.scala | 19 +++++++----- .../pipedsl/typechecker/BaseTypeChecker.scala | 7 +---- src/test/scala/pipedsl/package.scala | 1 - .../tests/exception/exn-recovery-spec.pdl | 6 +--- src/test/tests/exception/exn-recovery.pdl | 11 +++---- src/test/tests/exception/exn-simple-spec.pdl | 31 +++++++++---------- 14 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index 43942661..95657717 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -105,7 +105,6 @@ object Main { TimingTypeChecker.check(lock_prog, Some(basetypes)) val exnTranslationPass = new ExnTranslationPass() val exnprog = exnTranslationPass.run(lock_prog) - new PrettyPrinter(None).printProgram(exnprog) if (printOutput) { val writer = new PrintWriter(outputFile) writer.write("Passed") diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala index 122df451..efc0e1e7 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala @@ -140,6 +140,7 @@ object BSVPrettyPrinter { case BAllOnes => "'1" case BTime => "$time()" case BValueOf(s) => s"valueOf($s)" + case BVectorAccess(name, index) => toBSVExprStr(name) + "[" + toBSVIndString(index) + "]" } def getFilePrinter(name: File): BSVPretyPrinterImpl = { @@ -207,6 +208,8 @@ object BSVPrettyPrinter { w.write(mkStatementString(getLetString(stmt) + toBSVExprStr(lhs), "<-", toBSVExprStr(rhs))) case BModAssign(lhs, rhs) => w.write(mkStatementString(toBSVExprStr(lhs), "<=", toBSVExprStr(rhs))) + case BVectorAssign(lhs, rhs) => + w.write(mkStatementString(toBSVExprStr(lhs), "<=", toBSVExprStr(rhs))) case BAssign(lhs, rhs) => w.write(mkStatementString(getLetString(stmt) + toBSVExprStr(lhs), "=", toBSVExprStr(rhs))) case BIntAssign(lhs, rhs) => diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index feed2787..01067bea 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -465,6 +465,7 @@ object BSVSyntax { case class BMethodInvoke(mod: BExpr, method: String, args: List[BExpr]) extends BExpr case class BFuncCall(func: String, args: List[BExpr]) extends BExpr case class BValueOf(s :String) extends BExpr + case class BVectorAccess(name: BVar, index: BIndex) extends BExpr sealed trait BIndex case class BIndConst(n :Int) extends BIndex @@ -487,6 +488,8 @@ object BSVSyntax { case class BModAssign(lhs: BVar, rhs: BExpr) extends BStatement + case class BVectorAssign(lhs: BVectorAccess, rhs: BExpr) extends BStatement + case class BAssign(lhs: BVar, rhs: BExpr) extends BStatement case class BInvokeAssign(lhs: BVar, rhs: BExpr) extends BStatement diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index 584bd365..54c0dcfd 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -24,9 +24,10 @@ object BluespecGeneration { private val combLib = "RegFile" private val asyncLib = "BRAMCore" private val verilogLib = "VerilogLibs" + private val ehrLib = "Ehr" private def getRequiredTopLibs: List[BImport] = List(clientLib, connLib, lockLib, memLib, verilogLib, combLib, asyncLib).map(l => BImport(l)) - private def getRequiredModLibs: List[BImport] = List(fifoLib, specFifoLib, queueLib, lockLib, memLib, verilogLib, specLib, combLib).map(l => BImport(l)) + private def getRequiredModLibs: List[BImport] = List(fifoLib, specFifoLib, queueLib, lockLib, memLib, verilogLib, specLib, combLib, ehrLib).map(l => BImport(l)) class BluespecProgramGenerator(prog: Prog, stageInfo: Map[Id, List[PStage]], pinfo: ProgInfo, debug: Boolean = false, bsInts: BluespecInterfaces, funcmodname: String = "Functions", @@ -398,7 +399,7 @@ object BluespecGeneration { private val outputData = BVar("data", translator.toType(mod.ret.getOrElse(TVoid()))) private val outputQueue = BVar("outputQueue", bsInts.getOutputQType(threadIdVar.typ, outputData.typ)) //Registers for exceptions - private val globalExnFlag = BVar("_globalExnFlag", bsInts.getRegType(BBool)) + private val globalExnFlag = BVar("_globalExnFlag", bsInts.getEhrType(2, BBool)) //Data types for passing between stages private val edgeStructInfo = getEdgeStructInfo(otherStages, addTId = true, addSpecId = mod.maybeSpec) //First stage should have exactly one input edge by definition @@ -632,7 +633,7 @@ object BluespecGeneration { private def getExnKillConds(cmds: Iterable[Command]): List[BExpr] = { cmds.foldLeft(List[BExpr]())((l, c) => c match { - case IStageClear() => l :+ globalExnFlag + case IStageClear() => l :+ BVectorAccess(globalExnFlag, BIndConst(1)) case _ => l }) } @@ -659,7 +660,7 @@ object BluespecGeneration { l } case IStageClear() => - val disjointCond = BUOp("!", globalExnFlag) + val disjointCond = BUOp("!", BVectorAccess(globalExnFlag, BIndConst(1))) l :+ disjointCond case _ => l }) @@ -938,7 +939,7 @@ object BluespecGeneration { bsInts.getReg(BZero)) //Instantiate Exception Register - val globalExnInst = BModInst(globalExnFlag, bsInts.getReg(BBoolLit(false))) + val globalExnInst = BModInst(globalExnFlag, bsInts.getEhr(BBoolLit(false))) //Instantiate the speculation table if the module is speculative val specInst = if (mod.maybeSpec) BModInst(specTable, bsInts.getSpecTable) else BEmpty @@ -1289,6 +1290,9 @@ object BluespecGeneration { } else { None } + case ISpecClear() => + val clearStmt = BExprStmt(bsInts.getSpecClear(specTable)) + Some(clearStmt) case IAssignLock(handle, src, _) => Some( BAssign(translator.toVar(handle), translator.toExpr(src)) ) @@ -1390,8 +1394,8 @@ object BluespecGeneration { case CAssign(_, _) => None case CExpr(_) => None case CEmpty() => None - case ISetGlobalExnFlag(state) => Some(BModAssign(globalExnFlag, BBoolLit(state))) - case _: IStageClear => None + case IStageClear() => None + case ISetGlobalExnFlag(state) => Some(BVectorAssign(BVectorAccess(globalExnFlag, BIndConst(0)), BBoolLit(state))) case _: InternalCommand => throw UnexpectedCommand(cmd) case CRecv(_, _) => throw UnexpectedCommand(cmd) case CSeq(_, _) => throw UnexpectedCommand(cmd) diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala index dc9abc56..d15f9e22 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala @@ -91,6 +91,9 @@ class BluespecInterfaces() { private val regModuleName = "mkReg" private val regType = "Reg" + private val ehrType = "Ehr" + private val ehrModuleName = "mkEhr" + private val fifoModuleName = "mkFIFOF" private val fifoNBModuleName = "mkNBFIFOF" private val fifoType = "FIFOF" @@ -377,6 +380,13 @@ class BluespecInterfaces() { BModule(regModuleName, List(initVal)) } + def getEhrType(port_num: Int, typ: BSVType): BInterface = { + BInterface(ehrType, List(BVar("_unused_", BNumericType(port_num)), BVar("elemtyp", typ))) + } + + def getEhr(initVal: BExpr): BModule = { + BModule(ehrModuleName, List(initVal)) + } def defineInterface(intName: String, inputs: List[BVar], handleTyp: BSVType, retTyp: Option[BSVType]): BInterfaceDef = { diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index f53c4504..b50c9913 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -131,9 +131,14 @@ class PrettyPrinter(output: Option[File]) { case Syntax.CCheckSpec(isBlk) => ins + (if (isBlk) "spec_barrier();" else "spec_check();") case Syntax.IAbort(mem) => ins + "abort(" + mem +");" case Syntax.IStageClear() => ins + "clearOnExn();" + case Syntax.ISpecClear() => ins + "spectable.clear();" case Syntax.ISetGlobalExnFlag(state) => ins + "setGlobalExnFlag(" + state +");" case Syntax.IReleaseLock(mem, inHandle) => ins + "release(" + mem + ");" case Syntax.IReserveLock(mem, inHandle) => ins + "reserve(" + mem + ");" + case Syntax.ICheckLockOwned(mem, inHandle, outHandle) => ins + "block(" + mem + ");" + case Syntax.CInvalidate(handle, checkHandles) => ins + "invalidate(" + handle.id + ");" + case Syntax.CSpecCall(handle, pipe, args) => handle.id + " <- speccall " + pipe + "(" + args.map(a => printExprToString(a)).mkString(",") + ")" + case Syntax.CVerify(handle, args, preds, update, checkHandles) => "verify(" + handle.id + ");" //TODO: print out more info case _ => "TODO PRINTING COMMAND" } } diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 1efc1849..c56a548b 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -652,6 +652,7 @@ object Syntax { case class IAbort(mem: Id) extends InternalCommand case class IStageClear() extends InternalCommand + case class ISpecClear() extends InternalCommand case class ISetGlobalExnFlag(state: Boolean) extends InternalCommand case class ICondCommand(cond: Expr, cs: List[Command]) extends InternalCommand case class IUpdate(specId: Id, value: EVar, originalSpec: EVar) extends InternalCommand diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index a48096b0..5e2376fc 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -198,6 +198,7 @@ object Utilities { }) case ILockNoOp(_) => Set() case IStageClear() => Set() + case ISpecClear() => Set() case ISetGlobalExnFlag(_) => Set() case IAbort(_) => Set() case CLockStart(_) => Set() diff --git a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala index a5039a64..f1800cec 100644 --- a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -109,7 +109,7 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ val newArgs = args.foldLeft(List[Expr]())((l, arg) => { arg match { case EVar(id) => - val newv = exnArgApplyMap.getOrElse(id, EVar(id)).setPos(e.pos) + val newv = exnArgApplyMap.getOrElse(id, arg).setPos(e.pos) l :+ newv case _ => l :+ arg } @@ -120,7 +120,7 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ val newArgs = args.foldLeft(List[Expr]())((l, arg) => { arg match { case EVar(id) => - val newv = exnArgApplyMap.getOrElse(id, EVar(id)).setPos(e.pos) + val newv = exnArgApplyMap.getOrElse(id, arg).setPos(e.pos) l :+ newv case _ => l :+ arg } @@ -128,7 +128,7 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ ECall(mod, name, newArgs, isAtomic) } case ECast(ctyp, e) => ECast(ctyp, convertExnArgsId(e)) - case EVar(id) => exnArgApplyMap.getOrElse(id, EVar(id)).setPos(e.pos) + case EVar(id) => exnArgApplyMap.getOrElse(id, e).setPos(e.pos) case _ => e } } @@ -140,18 +140,23 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ } val except_stmts = m.except_blk match { case ExceptFull(_, c) => - val setGlobalExnFlag = ISetGlobalExnFlag(true) val unsetGlobalExnFlag = ISetGlobalExnFlag(false) val abortStmts = m.modules.foldLeft(CSeq(CEmpty(), CEmpty()))((c, mod) => mod.typ match { - case TLockedMemType(mem, _, _) => CSeq(IAbort(mod.name), setGlobalExnFlag) - case _ => CSeq(CEmpty(), setGlobalExnFlag) + case TLockedMemType(mem, _, _) => CSeq(c, IAbort(mod.name)) + case _ => CSeq(c, CEmpty()) }) CTBar(abortStmts, CSeq(c, unsetGlobalExnFlag)) case ExceptEmpty() => CEmpty() } + val setGlobalExnFlag = ISetGlobalExnFlag(true) val initLocalErrFlag = CAssign(localExnFlag, EBool(false)).copyMeta(m.body) - val finalBlocks = CIf(localExnFlag, CTBar(CEmpty(),except_stmts), commit_stmts) + val clearSpecTable = if (m.maybeSpec) { + ISpecClear() + } else { + CEmpty() + } + val finalBlocks = CIf(localExnFlag, CTBar(CSeq(setGlobalExnFlag, clearSpecTable), except_stmts), commit_stmts) val newBody = CSeq(initLocalErrFlag, CSeq(m.body,finalBlocks)) //TODO require memory or module types diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index 2c456ef1..0b10dc07 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -96,15 +96,11 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { val outEnv = tenv.add(m.name, modTyp) checkModuleBodyWellFormed(m.body, Set()) checkCommand(m.name, m.extendedBody(), bodyEnv) -// m.except_blk match { -// -// } -// env.add() if(m.except_blk.isInstanceOf[ExceptFull]){ val exnenv = m.except_blk.args.foldLeft[Environment[Id, Type]](bodyEnv)((env, arg) => { arg.typ match { case Some(t: Type) => env.add(arg, t) - case None => env.add(arg, TVoid()) + case None => env } }) m.except_blk.foreach(checkCommand(m.name, _, exnenv)) @@ -681,7 +677,6 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { id.typ = Some(t) (t, tenv) } else { - println(id) throw UnexpectedType(id.pos, "variable", s"variable type set to new conflicting type : ${tenv(id)}", t) } case None if (tenv.get(id).isDefined || defaultType.isEmpty) => id.typ = Some(tenv(id)); (tenv(id), tenv) diff --git a/src/test/scala/pipedsl/package.scala b/src/test/scala/pipedsl/package.scala index c3760912..a9f43b30 100644 --- a/src/test/scala/pipedsl/package.scala +++ b/src/test/scala/pipedsl/package.scala @@ -69,7 +69,6 @@ package object pipedsl { def testBlueSpecSim(testDir: File, inputFile: File, addrLockMod: Option[String] = None, memInit: Map[String, String], simFile: Option[String] = None): Unit = { val _ = (pathToBluespecScript + " c " + testDir.getAbsolutePath).!! Main.gen(testDir, inputFile, printStgInfo = false, debug = false, memInit, portWarn = false, autocast = false, addrLockMod) - Console.err.println((pathToBluespecScript + " s " + testDir.getAbsolutePath + " " + FilenameUtils.getBaseName(inputFile.getName) + ".sim")) val exit = (pathToBluespecScript + " s " + testDir.getAbsolutePath + " " + FilenameUtils.getBaseName(inputFile.getName) + ".sim").! val success = exit == 0 && compareFiles(testDir, inputFile, "sim", simFile) deleteGeneratedFiles(testDir) diff --git a/src/test/tests/exception/exn-recovery-spec.pdl b/src/test/tests/exception/exn-recovery-spec.pdl index 017c76aa..04d51a9c 100644 --- a/src/test/tests/exception/exn-recovery-spec.pdl +++ b/src/test/tests/exception/exn-recovery-spec.pdl @@ -5,7 +5,6 @@ spec_check(); reserve(acc); checkpoint(acc); end(acc); - print("PC: %d", pc); --- spec_check(); s <- speccall cpu(pc + 1); @@ -14,7 +13,6 @@ spec_check(); block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; - print(acc_val); if(acc_val == 7) { invalidate(s); @@ -23,11 +21,9 @@ spec_check(); if(acc_val == 2) { invalidate(s); - print("3 Should not present!"); call cpu(pc + 3); } else { if(acc_val == 9){ - print("recovered from exception"); invalidate(s); output(0); } else { @@ -38,7 +34,7 @@ spec_check(); --- commit: release(acc); - print("no exn here!"); + print("no exn here! with acc_val of %d", acc_val); except(arg: uint<4>): print("exception... with arg: %d", arg); start(acc); diff --git a/src/test/tests/exception/exn-recovery.pdl b/src/test/tests/exception/exn-recovery.pdl index 9fe18b9b..27432994 100644 --- a/src/test/tests/exception/exn-recovery.pdl +++ b/src/test/tests/exception/exn-recovery.pdl @@ -3,19 +3,16 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { start(acc); reserve(acc); end(acc); - print("PC: %d", pc); --- block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; - print(acc_val); - if(acc_val == 5) + if(acc_val == 6) { except(u0<4>); } else { - if(acc_val == 7){ - print("recovered from exception"); + if(acc_val == 9){ output(0); } else { call cpu(pc + 1); @@ -24,7 +21,7 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { --- commit: release(acc); - print("no exn here!"); + print("no exn here! with acc_val of %d", acc_val); except(arg: uint<4>): print("exception... with arg: %d", arg); start(acc); @@ -32,7 +29,7 @@ except(arg: uint<4>): end(acc); --- block(acc); - acc[0] <- 7; + acc[0] <- 9; --- release(acc); call cpu(pc + 1); diff --git a/src/test/tests/exception/exn-simple-spec.pdl b/src/test/tests/exception/exn-simple-spec.pdl index 9298a155..1ec704b4 100644 --- a/src/test/tests/exception/exn-simple-spec.pdl +++ b/src/test/tests/exception/exn-simple-spec.pdl @@ -5,39 +5,36 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { reserve(acc); checkpoint(acc); end(acc); - print("PC: %d", pc); --- spec_check(); s <- speccall cpu(pc + 1); --- - spec_barrier(); + spec_check(); block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; - print(acc_val); if(acc_val == 7) { - invalidate(s); - except(u0<4>); + except(u0<4>); + } + --- + spec_barrier(); + if(acc_val == 2) + { + invalidate(s); + call cpu(pc + 3); } else { - if(acc_val == 2) - { - invalidate(s); - print("3 Should not present!"); - call cpu(pc + 3); + if(acc_val == 8){ + invalidate(s); + output(0); } else { - if(acc_val == 8){ - invalidate(s); - output(0); - } else { - verify(s, pc + 1); - } + verify(s, pc + 1); } } --- commit: release(acc); - print("no exn here!"); + print("no exn here! with acc_val of %d", acc_val); except(arg :uint<4>): print("exception... with arg: %d", arg); output(1); From d9e204ceaf99f47c761eb658171c2f1a5de4b186 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 1 Mar 2023 12:47:23 -0500 Subject: [PATCH 30/38] fix tests --- src/test/scala/pipedsl/ExceptionSuite.scala | 20 +++++++++---------- .../tests/exception/exn-recovery-spec.pdl | 10 +++++----- src/test/tests/exception/exn-recovery.pdl | 17 ++++++++-------- ...basic.pdl => exn-risc-pipe-basic.pdl.temp} | 0 src/test/tests/exception/exn-simple-spec.pdl | 8 ++++---- src/test/tests/exception/exn-simple.pdl | 11 ++++------ .../solutions/exn-recovery-spec.simsol | 8 ++++++++ ...hecksol => exn-recovery-spec.typechecksol} | 0 .../exception/solutions/exn-recovery.simsol | 8 ++++++++ .../solutions/exn-recovery.typechecksol | 1 + .../solutions/exn-simple-spec.simsol | 7 +++++++ .../solutions/exn-simple-spec.typechecksol | 1 + .../exception/solutions/exn-simple.simsol | 7 +++++++ .../solutions/exn-simple.typechecksol | 1 + 14 files changed, 64 insertions(+), 35 deletions(-) rename src/test/tests/exception/{exn-risc-pipe-basic.pdl => exn-risc-pipe-basic.pdl.temp} (100%) create mode 100644 src/test/tests/exception/solutions/exn-recovery-spec.simsol rename src/test/tests/exception/solutions/{exn-simple-1.typechecksol => exn-recovery-spec.typechecksol} (100%) create mode 100644 src/test/tests/exception/solutions/exn-recovery.simsol create mode 100644 src/test/tests/exception/solutions/exn-recovery.typechecksol create mode 100644 src/test/tests/exception/solutions/exn-simple-spec.simsol create mode 100644 src/test/tests/exception/solutions/exn-simple-spec.typechecksol create mode 100644 src/test/tests/exception/solutions/exn-simple.simsol create mode 100644 src/test/tests/exception/solutions/exn-simple.typechecksol diff --git a/src/test/scala/pipedsl/ExceptionSuite.scala b/src/test/scala/pipedsl/ExceptionSuite.scala index 80ece317..d74efe2b 100644 --- a/src/test/scala/pipedsl/ExceptionSuite.scala +++ b/src/test/scala/pipedsl/ExceptionSuite.scala @@ -16,15 +16,15 @@ class ExceptionSuite extends AnyFunSuite{ testFiles.foreach(t => { val testBaseName = getTestName(t) -// val simFile = getSimFile(testFolder, testBaseName) -// test(testBaseName + " Typecheck; Compile; Simulate") { -// val doesTypecheck = testTypecheck(testFolder, t) -// if (doesTypecheck) { -// testBlueSpecCompile(testFolder, t, None, inputMap) -// if (simFile.exists) { -// testBlueSpecSim(testFolder, t, None, inputMap) -// } -// } -// } + val simFile = getSimFile(testFolder, testBaseName) + test(testBaseName + " Typecheck; Compile; Simulate") { + val doesTypecheck = testTypecheck(testFolder, t) + if (doesTypecheck) { + testBlueSpecCompile(testFolder, t, None, inputMap) + if (simFile.exists) { + testBlueSpecSim(testFolder, t, None, inputMap) + } + } + } }) } diff --git a/src/test/tests/exception/exn-recovery-spec.pdl b/src/test/tests/exception/exn-recovery-spec.pdl index 04d51a9c..52160cce 100644 --- a/src/test/tests/exception/exn-recovery-spec.pdl +++ b/src/test/tests/exception/exn-recovery-spec.pdl @@ -1,6 +1,6 @@ //Expect 5 Success, 1 Exception, 1 Success post recovery exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { -spec_check(); + spec_check(); start(acc); reserve(acc); checkpoint(acc); @@ -13,12 +13,12 @@ spec_check(); block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; - if(acc_val == 7) + if(acc_val == 6) { invalidate(s); except(u0<4>); } else { - if(acc_val == 2) + if(acc_val == 3) { invalidate(s); call cpu(pc + 3); @@ -34,9 +34,9 @@ spec_check(); --- commit: release(acc); - print("no exn here! with acc_val of %d", acc_val); + print("no exn at PC == %d! with acc_val of %d", pc, acc_val); except(arg: uint<4>): - print("exception... with arg: %d", arg); + print("exception at PC == %d! with arg: %d", pc, arg); start(acc); reserve(acc); end(acc); diff --git a/src/test/tests/exception/exn-recovery.pdl b/src/test/tests/exception/exn-recovery.pdl index 27432994..b7c78526 100644 --- a/src/test/tests/exception/exn-recovery.pdl +++ b/src/test/tests/exception/exn-recovery.pdl @@ -7,23 +7,22 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; + if(acc_val == 10){ + output(0); + } else { + call cpu(pc + 1); + } + --- if(acc_val == 6) { except(u0<4>); - } else - { - if(acc_val == 9){ - output(0); - } else { - call cpu(pc + 1); - } } --- commit: release(acc); - print("no exn here! with acc_val of %d", acc_val); + print("no exn at PC == %d! with acc_val of %d", pc, acc_val); except(arg: uint<4>): - print("exception... with arg: %d", arg); + print("exception at PC == %d! with arg: %d", pc, arg); start(acc); reserve(acc); end(acc); diff --git a/src/test/tests/exception/exn-risc-pipe-basic.pdl b/src/test/tests/exception/exn-risc-pipe-basic.pdl.temp similarity index 100% rename from src/test/tests/exception/exn-risc-pipe-basic.pdl rename to src/test/tests/exception/exn-risc-pipe-basic.pdl.temp diff --git a/src/test/tests/exception/exn-simple-spec.pdl b/src/test/tests/exception/exn-simple-spec.pdl index 1ec704b4..94b6a09b 100644 --- a/src/test/tests/exception/exn-simple-spec.pdl +++ b/src/test/tests/exception/exn-simple-spec.pdl @@ -13,7 +13,7 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; - if(acc_val == 7) + if(acc_val == 6) { except(u0<4>); } @@ -34,9 +34,9 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { --- commit: release(acc); - print("no exn here! with acc_val of %d", acc_val); -except(arg :uint<4>): - print("exception... with arg: %d", arg); + print("no exn at PC == %d! with acc_val of %d", pc, acc_val); +except(arg: uint<4>): + print("exception at PC == %d! with arg: %d", pc, arg); output(1); } diff --git a/src/test/tests/exception/exn-simple.pdl b/src/test/tests/exception/exn-simple.pdl index 3c70b92e..426bc48b 100644 --- a/src/test/tests/exception/exn-simple.pdl +++ b/src/test/tests/exception/exn-simple.pdl @@ -3,25 +3,22 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { start(acc); reserve(acc); end(acc); - print("PC: %d", pc); --- block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; - print(acc_val); + call cpu(pc + 1); + --- if(acc_val == 6) { except(u0<4>); - } else - { - call cpu(pc + 1); } --- commit: release(acc); - print("no exn here!"); + print("no exn at PC == %d! with acc_val of %d", pc, acc_val); except(arg :uint<4>): - print("exception... with arg: %d", arg); + print("exception at PC == %d! with arg: %d", pc, arg); output(1); } diff --git a/src/test/tests/exception/solutions/exn-recovery-spec.simsol b/src/test/tests/exception/solutions/exn-recovery-spec.simsol new file mode 100644 index 00000000..ad3b2eb1 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-recovery-spec.simsol @@ -0,0 +1,8 @@ +no exn at PC == 1! with acc_val of 0 +no exn at PC == 2! with acc_val of 1 +no exn at PC == 3! with acc_val of 2 +no exn at PC == 4! with acc_val of 3 +no exn at PC == 7! with acc_val of 4 +no exn at PC == 8! with acc_val of 5 +exception at PC == 9! with arg: 0 +no exn at PC == 10! with acc_val of 9 diff --git a/src/test/tests/exception/solutions/exn-simple-1.typechecksol b/src/test/tests/exception/solutions/exn-recovery-spec.typechecksol similarity index 100% rename from src/test/tests/exception/solutions/exn-simple-1.typechecksol rename to src/test/tests/exception/solutions/exn-recovery-spec.typechecksol diff --git a/src/test/tests/exception/solutions/exn-recovery.simsol b/src/test/tests/exception/solutions/exn-recovery.simsol new file mode 100644 index 00000000..1afe3744 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-recovery.simsol @@ -0,0 +1,8 @@ +no exn at PC == 1! with acc_val of 0 +no exn at PC == 2! with acc_val of 1 +no exn at PC == 3! with acc_val of 2 +no exn at PC == 4! with acc_val of 3 +no exn at PC == 5! with acc_val of 4 +no exn at PC == 6! with acc_val of 5 +exception at PC == 7! with arg: 0 +no exn at PC == 8! with acc_val of 9 diff --git a/src/test/tests/exception/solutions/exn-recovery.typechecksol b/src/test/tests/exception/solutions/exn-recovery.typechecksol new file mode 100644 index 00000000..9fb4ec93 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-recovery.typechecksol @@ -0,0 +1 @@ +Passed \ No newline at end of file diff --git a/src/test/tests/exception/solutions/exn-simple-spec.simsol b/src/test/tests/exception/solutions/exn-simple-spec.simsol new file mode 100644 index 00000000..45396004 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-simple-spec.simsol @@ -0,0 +1,7 @@ +no exn at PC == 1! with acc_val of 0 +no exn at PC == 2! with acc_val of 1 +no exn at PC == 3! with acc_val of 2 +no exn at PC == 6! with acc_val of 3 +no exn at PC == 7! with acc_val of 4 +no exn at PC == 8! with acc_val of 5 +exception at PC == 9! with arg: 0 diff --git a/src/test/tests/exception/solutions/exn-simple-spec.typechecksol b/src/test/tests/exception/solutions/exn-simple-spec.typechecksol new file mode 100644 index 00000000..9fb4ec93 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-simple-spec.typechecksol @@ -0,0 +1 @@ +Passed \ No newline at end of file diff --git a/src/test/tests/exception/solutions/exn-simple.simsol b/src/test/tests/exception/solutions/exn-simple.simsol new file mode 100644 index 00000000..be256e55 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-simple.simsol @@ -0,0 +1,7 @@ +no exn at PC == 1! with acc_val of 0 +no exn at PC == 2! with acc_val of 1 +no exn at PC == 3! with acc_val of 2 +no exn at PC == 4! with acc_val of 3 +no exn at PC == 5! with acc_val of 4 +no exn at PC == 6! with acc_val of 5 +exception at PC == 7! with arg: 0 diff --git a/src/test/tests/exception/solutions/exn-simple.typechecksol b/src/test/tests/exception/solutions/exn-simple.typechecksol new file mode 100644 index 00000000..9fb4ec93 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-simple.typechecksol @@ -0,0 +1 @@ +Passed \ No newline at end of file From b386fb4d14894ecd6de57f626dc97055d84a710b Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Thu, 6 Apr 2023 17:36:35 -0400 Subject: [PATCH 31/38] rewrite impl with stgclear --- bscRuntime/libs/PdlFifo.bsv | 0 .../codegen/bsv/BluespecGeneration.scala | 50 +++++++++++++++++-- .../codegen/bsv/BluespecInterfaces.scala | 3 ++ src/main/scala/pipedsl/common/DAGSyntax.scala | 2 +- .../pipedsl/passes/ExnTranslationPass.scala | 8 +-- 5 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 bscRuntime/libs/PdlFifo.bsv diff --git a/bscRuntime/libs/PdlFifo.bsv b/bscRuntime/libs/PdlFifo.bsv new file mode 100644 index 00000000..e69de29b diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index 54c0dcfd..92df2f91 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -6,7 +6,7 @@ import pipedsl.common.Errors.{UnexpectedCommand, UnexpectedExpr} import pipedsl.common.LockImplementation.{LockInterface, MethodInfo} import pipedsl.common.{LockImplementation, ProgInfo} import pipedsl.common.Syntax._ -import pipedsl.common.Utilities.{annotateSpecTimings, flattenStageList, log2} +import pipedsl.common.Utilities.{annotateSpecTimings, flattenStageList, log2, visit} import scala.collection.immutable.ListMap @@ -1394,7 +1394,7 @@ object BluespecGeneration { case CAssign(_, _) => None case CExpr(_) => None case CEmpty() => None - case IStageClear() => None + case IStageClear() => Some(BStmtSeq(getFIFOClears().map(mi => BExprStmt(mi)))) case ISetGlobalExnFlag(state) => Some(BVectorAssign(BVectorAccess(globalExnFlag, BIndConst(0)), BBoolLit(state))) case _: InternalCommand => throw UnexpectedCommand(cmd) case CRecv(_, _) => throw UnexpectedCommand(cmd) @@ -1440,6 +1440,50 @@ object BluespecGeneration { } getEdgeQueueStmts(firstStage.inEdges.head.from, firstStage.inEdges, Some(argmap)) } - } + private def findFirstExceptStg(): Option[PStage] = { + otherStages.foldLeft(None: Option[PStage])((result, st) => { + var stgIsFound = st.getCmds.foldLeft(false)((found, c) => { + c match { + case IStageClear() => true + case _ => found + } + }) + if (stgIsFound) { + Some(st) + } else { + result + } + }) + } + + private def getFIFOClears(): List[BMethodInvoke] = { + findFirstExceptStg() match { + case Some(st) => { + var resultList = List[BMethodInvoke]() + var unvisited = st.preds + var visited = Set[PStage]() + var currVisit = st + while(unvisited.nonEmpty){ + currVisit = unvisited.head + visited += currVisit + currVisit.outEdges.foreach(e => { + if(e.to != st) { + resultList = resultList.appended(bsInts.getFifoClear(edgeParams(e))) + } + }) + currVisit.preds.foreach(pred => { + if(!visited.contains(pred)){ + unvisited += pred + } + }) + unvisited -= currVisit + } + resultList + } + case None => List[BMethodInvoke]() + } + } + + } } diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala index d15f9e22..3f0f3e3a 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala @@ -319,6 +319,9 @@ class BluespecInterfaces() { def getOutCanRead(q: BVar, tag: BExpr): BMethodInvoke = { BMethodInvoke(q, "canRead", List(tag)); } + def getFifoClear(f: BVar) : BMethodInvoke = { + BMethodInvoke(f, "clear", List()) + } private val specHandleName = "SpecId" private val defaultSpecHandleSize = 4 diff --git a/src/main/scala/pipedsl/common/DAGSyntax.scala b/src/main/scala/pipedsl/common/DAGSyntax.scala index 36d0efea..d24c2532 100644 --- a/src/main/scala/pipedsl/common/DAGSyntax.scala +++ b/src/main/scala/pipedsl/common/DAGSyntax.scala @@ -28,7 +28,7 @@ object DAGSyntax { * stages via edgges that are realized as Registers or FIFOs. * @param n The identifier for this stage; these should be unique. */ - class PStage(n:Id) extends Process(n) { + class PStage(n:Id, tag:String = "") extends Process(n) { //Any outgoing communication edge, including normal pipeline flow, calls and communication with memories private var edges: Set[PipelineEdge] = Set() diff --git a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala index f1800cec..3336f493 100644 --- a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -49,14 +49,14 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case ExceptEmpty() => CEmpty() } - m.copy(body = CSeq(IStageClear(), convertPrimitives(m.body)), commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) + m.copy(body = convertPrimitives(m.body), commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) } def convertPrimitives(c: Command): Command = { c match { case CSeq(c1, c2) => CSeq(convertPrimitives(c1), convertPrimitives(c2)).copyMeta(c) case CIf(cond, cons, alt) => CIf(cond, convertPrimitives(cons), convertPrimitives(alt)).copyMeta(c) - case CTBar(c1, c2) => CTBar(convertPrimitives(c1), CSeq(IStageClear(), convertPrimitives(c2))).copyMeta(c) + case CTBar(c1, c2) => CTBar(convertPrimitives(c1), convertPrimitives(c2)).copyMeta(c) case CSplit(cases, default) => val newCases = cases.map(c => CaseObj(c.cond, convertPrimitives(c.body))) CSplit(newCases, convertPrimitives(default)).copyMeta(c) @@ -141,7 +141,7 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ val except_stmts = m.except_blk match { case ExceptFull(_, c) => val unsetGlobalExnFlag = ISetGlobalExnFlag(false) - val abortStmts = m.modules.foldLeft(CSeq(CEmpty(), CEmpty()))((c, mod) => + val abortStmts = m.modules.foldLeft(CSeq(IStageClear(), CEmpty()))((c, mod) => mod.typ match { case TLockedMemType(mem, _, _) => CSeq(c, IAbort(mod.name)) case _ => CSeq(c, CEmpty()) @@ -152,7 +152,7 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ val setGlobalExnFlag = ISetGlobalExnFlag(true) val initLocalErrFlag = CAssign(localExnFlag, EBool(false)).copyMeta(m.body) val clearSpecTable = if (m.maybeSpec) { - ISpecClear() + ISpecClear() } else { CEmpty() } From 635d92d527823e2f28f24cf40e12f335a503a1f5 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Thu, 6 Apr 2023 17:56:18 -0400 Subject: [PATCH 32/38] fix sq --- bscRuntime/memories/SpecialQueues.bsv | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/bscRuntime/memories/SpecialQueues.bsv b/bscRuntime/memories/SpecialQueues.bsv index ccb66dd5..b526a2f7 100644 --- a/bscRuntime/memories/SpecialQueues.bsv +++ b/bscRuntime/memories/SpecialQueues.bsv @@ -51,23 +51,32 @@ module mkOutputFIFOF(ttyp initT, OutputQ#(ttyp, dtyp) res) provisos endmodule +// Change to a CReg, two element Queue for per cycle. module mkNBFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); FIFOF#(dtyp) f <- mkFIFOF(); //allow multiple writes in the same cycle RWire#(dtyp) enq_data <- mkRWireSBR(); - + + //Make sure no enq could happen during clear (takes 2 cycles) + Reg#(Bool) clearCalled <- mkReg(False); + + rule doClear(clearCalled); + f.clear(); + clearCalled <= False; + endrule + (*fire_when_enabled*) rule doEnq (enq_data.wget() matches tagged Valid.d); f.enq(d); endrule //only allow the LAST enq each cycle to work, drop the others - method Action enq(dtyp a) if (f.notFull()); + method Action enq(dtyp a) if (f.notFull() && !clearCalled); enq_data.wset(a); endmethod - method Action deq(); + method Action deq() if (!clearCalled); f.deq(); endmethod @@ -82,11 +91,11 @@ module mkNBFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); method Bool notEmpty(); return f.notEmpty(); endmethod - + method Action clear(); - f.clear(); + clearCalled <= True; endmethod - + endmodule From 24e6edd8c8d5f46907de1802d64994719c3065b3 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Thu, 6 Apr 2023 17:58:03 -0400 Subject: [PATCH 33/38] fix --- bscRuntime/libs/PrioFifo.bsv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bscRuntime/libs/PrioFifo.bsv b/bscRuntime/libs/PrioFifo.bsv index e1f39878..bd609eec 100644 --- a/bscRuntime/libs/PrioFifo.bsv +++ b/bscRuntime/libs/PrioFifo.bsv @@ -11,7 +11,7 @@ module mkNBFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); FIFOF#(dtyp) f <- mkFIFOF(); //allow multiple writes in the same cycle RWire#(dtyp) enq_data <- mkRWireSBR(); - + (*fire_when_enabled*) rule doEnq (enq_data.wget() matches tagged Valid.d); f.enq(d); @@ -36,7 +36,7 @@ module mkNBFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); method Bool notEmpty(); return f.notEmpty(); endmethod - + method Action clear(); f.clear(); endmethod From 793506407370c4fd472f4698de1bb1d3d9185ac4 Mon Sep 17 00:00:00 2001 From: Drew Zagieboylo Date: Fri, 7 Apr 2023 15:01:11 -0400 Subject: [PATCH 34/38] Update scala.yml move to ubuntu 22 --- .github/workflows/scala.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 0510363f..06d72d34 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -9,7 +9,7 @@ on: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 steps: - name: Set up JDK 1.8 @@ -37,9 +37,9 @@ jobs: - name: Install BSV id: install-bsv run: | - wget https://github.com/B-Lang-org/bsc/releases/download/2021.07/bsc-2021.07-ubuntu-18.04.tar.gz - tar -xvf bsc-2021.07-ubuntu-18.04.tar.gz - mv bsc-2021.07-ubuntu-18.04 bsc + wget https://github.com/B-Lang-org/bsc/releases/download/2023.01/bsc-2023.01-ubuntu-22.04.tar.gz + tar -xvf bsc-2023.01-ubuntu-22.04.tar.gz + mv bsc-2023.01-ubuntu-22.04 bsc - name: Build Libs env: BLUESPECDIR: ${{github.workspace}}/bsc From 737bc6de394159dc4e15635d860eccd3388307c2 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Tue, 8 Aug 2023 10:38:35 -0400 Subject: [PATCH 35/38] further exn change --- bscRuntime/libs/BypassRF.v | 1 + bscRuntime/libs/Ehr.bsv | 1 + bscRuntime/libs/Memories.bsv | 1 + bscRuntime/libs/Named.bsv | 1 + bscRuntime/libs/NamedEhr.bsv | 1 + bscRuntime/libs/PdlFifo.bsv | 0 bscRuntime/libs/PrioFifo.bsv | 1 + bscRuntime/libs/Speculation.bsv | 1 + bscRuntime/libs/nametb.bsv | 1 + bscRuntime/libs/project/build.properties | 1 + bscRuntime/libs/tb.bsv | 1 + bscRuntime/memories/Ehr.bsv | 1 + bscRuntime/memories/Interrupt.bsv | 35 ++ bscRuntime/memories/Locks.bsv | 1 + bscRuntime/memories/Makefile | 2 +- bscRuntime/memories/Memories.bsv | 16 +- bscRuntime/memories/SpecialQueues.bsv | 25 +- bscRuntime/memories/Speculation.bsv | 44 +- bscRuntime/memories/StgFIFOs.bsv | 58 +++ bscRuntime/memories/tb.bsv | 1 + bscRuntime/verilog/BHT.v | 1 + bscRuntime/verilog/BypassRF.v | 1 + bscRuntime/verilog/CheckpointBypassRF.v | 1 + bscRuntime/verilog/CheckpointRenameRF.v | 56 +- bscRuntime/verilog/ForwardRenameRF.v | 1 + bscRuntime/verilog/RenameRF.v | 1 + bscRuntime/verilog/VerilogLibs.bsv | 14 +- bscRuntime/verilog/tb.bsv | 1 + src/main/scala/pipedsl/Interpreter.scala | 1 + src/main/scala/pipedsl/Main.scala | 2 + src/main/scala/pipedsl/Parser.scala | 12 +- .../scala/pipedsl/codegen/Translations.scala | 1 + .../codegen/bsv/BSVPrettyPrinter.scala | 1 + .../scala/pipedsl/codegen/bsv/BSVSyntax.scala | 1 + .../codegen/bsv/BluespecGeneration.scala | 100 ++-- .../codegen/bsv/BluespecInterfaces.scala | 7 + .../codegen/bsv/ConstraintsToBluespec.scala | 1 + .../pipedsl/common/CommandLineParser.scala | 1 + .../scala/pipedsl/common/Constraints.scala | 1 + src/main/scala/pipedsl/common/DAGSyntax.scala | 1 + src/main/scala/pipedsl/common/Dataflow.scala | 1 + src/main/scala/pipedsl/common/Errors.scala | 5 + .../pipedsl/common/LockImplementation.scala | 5 +- src/main/scala/pipedsl/common/Locks.scala | 1 + .../pipedsl/common/MemoryInputParser.scala | 1 + .../scala/pipedsl/common/PrettyPrinter.scala | 3 +- src/main/scala/pipedsl/common/ProgInfo.scala | 1 + src/main/scala/pipedsl/common/Security.scala | 1 + src/main/scala/pipedsl/common/Syntax.scala | 5 +- src/main/scala/pipedsl/common/Utilities.scala | 6 +- .../passes/AddCheckpointHandlesPass.scala | 1 + .../pipedsl/passes/AddEdgeValuePass.scala | 1 + .../pipedsl/passes/AddVerifyValuesPass.scala | 1 + .../pipedsl/passes/BindModuleTypes.scala | 1 + .../pipedsl/passes/CanonicalizePass.scala | 2 + .../scala/pipedsl/passes/CheckExcepting.scala | 1 + .../pipedsl/passes/CollapseStagesPass.scala | 1 + .../pipedsl/passes/ConvertAsyncPass.scala | 1 + .../pipedsl/passes/ExnTranslationPass.scala | 72 +-- .../pipedsl/passes/ExpandCatchPass.scala | 35 ++ .../pipedsl/passes/LockEliminationPass.scala | 1 + .../passes/LockOpTranslationPass.scala | 1 + .../passes/LockRegionInferencePass.scala | 1 + .../passes/MarkNonRecursiveModulePass.scala | 1 + src/main/scala/pipedsl/passes/Passes.scala | 1 + .../pipedsl/passes/PredicateGenerator.scala | 1 + .../pipedsl/passes/RemoveReentrantPass.scala | 1 + .../pipedsl/passes/RemoveTimingPass.scala | 1 + .../pipedsl/passes/SimplifyRecvPass.scala | 1 + .../pipedsl/passes/SplitStagesPass.scala | 1 + .../typechecker/AnalysisProvider.scala | 1 + .../pipedsl/typechecker/BaseTypeChecker.scala | 2 + .../typechecker/CheckpointChecker.scala | 1 + .../pipedsl/typechecker/Environments.scala | 4 +- .../FinalblocksConstraintChecker.scala | 19 +- .../FunctionConstraintChecker.scala | 1 + .../pipedsl/typechecker/LatencyChecker.scala | 1 + .../typechecker/LinearExecutionChecker.scala | 1 + .../typechecker/LockConstraintChecker.scala | 4 +- .../LockOperationTypeChecker.scala | 1 + .../typechecker/LockRegionChecker.scala | 1 + .../typechecker/LockReleaseChecker.scala | 1 + .../typechecker/LockWellformedChecker.scala | 1 + .../pipedsl/typechecker/PortChecker.scala | 1 + .../typechecker/SpeculationChecker.scala | 8 +- .../scala/pipedsl/typechecker/Subtypes.scala | 1 + .../typechecker/TimingTypeChecker.scala | 5 +- .../pipedsl/typechecker/TypeChecker.scala | 1 + .../typechecker/TypeInferenceWrapper.scala | 7 +- src/test/scala/pipedsl/CSplitSuite.scala | 1 + src/test/scala/pipedsl/ExceptionSuite.scala | 1 + src/test/scala/pipedsl/LockMergeSuite.scala | 1 + .../scala/pipedsl/LockTypecheckSuite.scala | 1 + src/test/scala/pipedsl/MainSuite.scala | 1 + .../scala/pipedsl/MiscSimulationSuite.scala | 1 + .../scala/pipedsl/RegisterRenamingSuite.scala | 1 + src/test/scala/pipedsl/RiscSuite.scala | 28 +- src/test/scala/pipedsl/SpeculationSuite.scala | 1 + .../scala/pipedsl/TypeAutoCastSuite.scala | 1 + src/test/scala/pipedsl/package.scala | 1 + .../autocastTests/autocast-basic-pass.pdl | 1 + .../tests/autocastTests/risc-pipe-spec.pdl | 1 + .../type-inference-basic-pass.pdl | 1 + .../type-inference-bit-width-tests.pdl | 1 + .../type-inference-fail-base-type.pdl | 1 + ...e-fail-bit-too-small-memAccessToosmall.pdl | 1 + ...ype-inference-fail-bit-too-small-minus.pdl | 1 + ...type-inference-fail-bit-too-small-mult.pdl | 1 + ...type-inference-fail-bit-too-small-plus.pdl | 1 + .../type-inference-fail-boolBinOp.pdl | 1 + .../type-inference-fail-call-args.pdl | 1 + .../type-inference-fail-call.pdl | 1 + .../type-inference-fail-eqBinOp.pdl | 1 + .../type-inference-fail-func-app-arg.pdl | 1 + .../type-inference-fail-funcApp.pdl | 1 + .../type-inference-fail-numBinOp.pdl | 1 + .../type-inference-fail-ternary.pdl | 1 + src/test/tests/branchesCheck/branch-1.pdl | 1 + src/test/tests/branchesCheck/branch-2.pdl | 1 + src/test/tests/branchesCheck/branch-3.pdl | 1 + src/test/tests/branchesCheck/nested-1.pdl | 1 + src/test/tests/branchesCheck/nested-2.pdl | 1 + .../tests/branchesCheck/nested-branches-1.pdl | 1 + src/test/tests/branchesCheck/split-1.pdl | 1 + src/test/tests/branchesCheck/split-2.pdl | 1 + src/test/tests/branchesCheck/split-3.pdl | 1 + src/test/tests/branchesCheck/split-4.pdl | 1 + .../tests/exception/exn-recovery-spec.pdl | 8 +- src/test/tests/exception/exn-recovery.pdl | 25 +- src/test/tests/exception/exn-simple-spec.pdl | 4 +- src/test/tests/exception/exn-simple.pdl | 4 +- .../exception/solutions/exn-recovery.simsol | 6 +- src/test/tests/histogram/histogram.pdl | 1 + src/test/tests/histogram/histogram_bram.pdl | 1 + src/test/tests/histogram/histogram_bram2.pdl | 1 + src/test/tests/histogram/histogram_nested.pdl | 1 + src/test/tests/histogram/histogram_short.pdl | 1 + src/test/tests/lockTests/lock-infer-1.pdl | 1 + src/test/tests/lockTests/lock-infer-2.pdl | 1 + src/test/tests/lockTests/lock-infer-3.pdl | 1 + src/test/tests/lockTests/lock-infer-4.pdl | 1 + src/test/tests/lockTests/lock-merge-1.pdl | 1 + src/test/tests/lockTests/lock-merge-2.pdl | 1 + src/test/tests/lockTests/lock-merge-3.pdl | 1 + src/test/tests/lockTests/lock-merge-4.pdl | 1 + src/test/tests/matpow/matpow.pdl | 1 + src/test/tests/matpow/matpow_alt.pdl | 1 + src/test/tests/matpow/matpow_bram.pdl | 1 + src/test/tests/multiExec/multiexec.pdl | 1 + src/test/tests/multiExec/multiexec_alt.pdl | 1 + src/test/tests/multiExec/multiexec_split.pdl | 1 + .../tests/registerRenamingTests/3-stg-lsq.pdl | 1 + .../registerRenamingTests/3-stg-pipe.pdl | 1 + .../lock-wrong-type-nested-fail.pdl | 1 + .../lock-wrong-type-read-write-fail.pdl | 1 + .../lock-wrong-type-write-read-fail.pdl | 1 + .../registerRenamingTests/validLockTypes.pdl | 1 + src/test/tests/risc-pipe/risc-pipe-3stg.pdl | 1 + src/test/tests/risc-pipe/risc-pipe-cache.pdl | 1 + .../risc-pipe/risc-pipe-spec-bypass-bht.pdl | 1 + .../tests/risc-pipe/risc-pipe-spec-exn.pdl | 488 ++++++++++++++++++ .../risc-pipe/risc-pipe-spec-rename-bht.pdl | 1 + .../risc-pipe-spec-rename-ooo-infer.pdl | 1 + .../risc-pipe/risc-pipe-spec-rename-ooo.pdl | 1 + .../risc-pipe/risc-pipe-spec-write-2.pdl | 1 + .../risc-pipe/risc-pipe-spec-write-infer.pdl | 1 + .../tests/risc-pipe/risc-pipe-spec-write.pdl | 1 + src/test/tests/risc-pipe/risc-pipe-spec.pdl | 7 +- src/test/tests/risc-pipe/risc-pipe.pdl | 1 + .../solutions/risc-pipe-spec-exn.typechecksol | 1 + src/test/tests/simtests/unlocked-reg.pdl | 1 + .../tests/speculation/3-stg-pipe-spec-2.pdl | 1 + .../tests/speculation/3-stg-pipe-spec-3.pdl | 1 + .../tests/speculation/3-stg-pipe-spec.pdl | 1 + src/test/tests/speculation/3-stg-pipe.pdl | 1 + src/test/tests/speculation/bad-spec-1.pdl | 1 + src/test/tests/speculation/bad-spec-2.pdl | 1 + src/test/tests/speculation/bad-spec-3.pdl | 1 + src/test/tests/speculation/bad-spec-4.pdl | 1 + src/test/tests/speculation/bad-spec-5.pdl | 1 + src/test/tests/speculation/spec-write-2.pdl | 1 + .../tests/speculation/spec-write-fail.pdl | 1 + .../tests/speculation/spec-write-fail2.pdl | 1 + .../tests/speculation/spec-write-fail3.pdl | 1 + .../tests/speculation/spec-write-infer.pdl | 1 + src/test/tests/speculation/spec-write.pdl | 1 + .../speculation/unnecessary-checkpoint.pdl | 1 + .../typecheckTests/acquire-in-expr-fail.pdl | 1 + .../tests/typecheckTests/acquire-in-expr.pdl | 1 + .../tests/typecheckTests/boolean-mishap.pdl | 1 + .../tests/typecheckTests/double-call-fail.pdl | 1 + .../typecheckTests/double-call-guarded.pdl | 1 + src/test/tests/typecheckTests/exn-basic.pdl | 1 + .../typecheckTests/exn-no-end-after-call.pdl | 1 + .../typecheckTests/exn-no-release-main.pdl | 1 + .../typecheckTests/exn-no-throw-commit.pdl | 1 + .../typecheckTests/exn-no-throw-except.pdl | 1 + .../typecheckTests/exn-no-throw-normal.pdl | 1 + .../exn-no-unlocked-write-main.pdl | 1 + .../typecheckTests/extern-synch-fail.pdl | 1 + src/test/tests/typecheckTests/extern_pass.pdl | 1 + .../tests/typecheckTests/generic-bht-fail.pdl | 1 + src/test/tests/typecheckTests/generic-bht.pdl | 1 + .../tests/typecheckTests/generic_adder.pdl | 1 + .../typecheckTests/generic_adder_unsigned.pdl | 1 + .../typecheckTests/generic_func_fail.pdl | 1 + .../typecheckTests/generic_funcs_pass.pdl | 1 + .../typecheckTests/generic_funcs_passz3.pdl | 1 + .../typecheckTests/generic_unify_fail.pdl | 1 + .../tests/typecheckTests/input-smt-fail.pdl | 1 + .../lock-acquire-in-split-case.pdl | 1 + .../lock-fail-acquire-before-access.pdl | 1 + .../lock-fail-branch-acquire.pdl | 1 + .../lock-fail-branch-release.pdl | 1 + .../typecheckTests/lock-fail-double-write.pdl | 1 + .../lock-fail-no-acquire-before-release.pdl | 1 + .../lock-fail-no-acquire-in-split-case.pdl | 1 + .../lock-fail-no-default-acquire-split.pdl | 1 + .../lock-fail-read-after-writes-branch.pdl | 1 + .../lock-fail-read-after-writes-release.pdl | 1 + .../lock-fail-reads-after-writes.pdl | 1 + .../lock-fail-reserve-without-write.pdl | 1 + .../typecheckTests/lock-fail-top-branch.pdl | 1 + .../lock-fail-wrong-branch-acquire.pdl | 1 + ...ock-release-OOO-different-address-fail.pdl | 1 + .../typecheckTests/lock-release-OOO-fail.pdl | 1 + .../lock-release-OOO-nested-branches-fail.pdl | 1 + .../lock-release-OOO-nested-if-fail.pdl | 1 + .../lock-release-OOO-split-fail.pdl | 1 + .../lock-success-read-write-order.pdl | 1 + .../typecheckTests/lock-tests-general.pdl | 1 + .../typecheckTests/lock-tests-specific.pdl | 1 + .../lock-wellformedness-fail.pdl | 1 + .../tests/typecheckTests/missing-one-fail.pdl | 1 + .../typecheckTests/more_generic_tests.pdl | 1 + .../tests/typecheckTests/nested_generic.pdl | 1 + .../tests/typecheckTests/pipe-lock-fail1.pdl | 1 + .../tests/typecheckTests/pipe-lock-fail2.pdl | 1 + src/test/tests/typecheckTests/pipe-lock.pdl | 1 + .../typecheckTests/quad-call-disjoint.pdl | 1 + .../typecheckTests/risc-pipe-spec-generic.pdl | 1 + src/test/tests/typecheckTests/signedInts.pdl | 1 + .../tests/typecheckTests/superscalar-fail.pdl | 1 + .../type-inference-basic-pass.pdl | 1 + .../type-inference-bit-width-tests.pdl | 1 + .../type-inference-fail-base-type.pdl | 1 + ...e-fail-bit-too-small-memAccessToosmall.pdl | 1 + ...ype-inference-fail-bit-too-small-minus.pdl | 1 + ...type-inference-fail-bit-too-small-mult.pdl | 1 + ...type-inference-fail-bit-too-small-plus.pdl | 1 + .../type-inference-fail-boolBinOp.pdl | 1 + .../type-inference-fail-call-args.pdl | 1 + .../type-inference-fail-call.pdl | 1 + .../type-inference-fail-eqBinOp.pdl | 1 + .../type-inference-fail-func-app-arg.pdl | 1 + .../type-inference-fail-funcApp.pdl | 1 + .../type-inference-fail-numBinOp.pdl | 1 + .../type-inference-fail-ternary.pdl | 1 + .../tests/typecheckTests/unlocked-mem-1.pdl | 1 + .../typecheckTests/unlocked-mem-fail-1.pdl | 1 + .../typecheckTests/unlocked-mem-fail.pdl | 1 + .../tests/typecheckTests/unlocked-mem.pdl | 1 + .../tests/typecheckTests/unlocked-reg.pdl | 1 + 263 files changed, 1172 insertions(+), 178 deletions(-) delete mode 100644 bscRuntime/libs/PdlFifo.bsv create mode 100644 bscRuntime/libs/project/build.properties create mode 100644 bscRuntime/memories/Interrupt.bsv create mode 100644 bscRuntime/memories/StgFIFOs.bsv create mode 100644 src/main/scala/pipedsl/passes/ExpandCatchPass.scala create mode 100644 src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl create mode 100644 src/test/tests/risc-pipe/solutions/risc-pipe-spec-exn.typechecksol diff --git a/bscRuntime/libs/BypassRF.v b/bscRuntime/libs/BypassRF.v index 5e4b4168..288eaa25 100644 --- a/bscRuntime/libs/BypassRF.v +++ b/bscRuntime/libs/BypassRF.v @@ -1,3 +1,4 @@ +// BypassRF.v `ifdef BSV_ASSIGNMENT_DELAY `else `define BSV_ASSIGNMENT_DELAY diff --git a/bscRuntime/libs/Ehr.bsv b/bscRuntime/libs/Ehr.bsv index 98048693..e85b6252 100644 --- a/bscRuntime/libs/Ehr.bsv +++ b/bscRuntime/libs/Ehr.bsv @@ -1,3 +1,4 @@ +// Ehr.bsv // Copyright (c) 2017 Massachusetts Institute of Technology // diff --git a/bscRuntime/libs/Memories.bsv b/bscRuntime/libs/Memories.bsv index d72fbb91..3a28f88f 100644 --- a/bscRuntime/libs/Memories.bsv +++ b/bscRuntime/libs/Memories.bsv @@ -1,3 +1,4 @@ +// Memories.bsv package Memories; import GetPut :: *; diff --git a/bscRuntime/libs/Named.bsv b/bscRuntime/libs/Named.bsv index 3c390739..a3b32418 100644 --- a/bscRuntime/libs/Named.bsv +++ b/bscRuntime/libs/Named.bsv @@ -1,3 +1,4 @@ +// Named.bsv package Named; import Memories :: *; diff --git a/bscRuntime/libs/NamedEhr.bsv b/bscRuntime/libs/NamedEhr.bsv index 70732d70..f8ed3b04 100644 --- a/bscRuntime/libs/NamedEhr.bsv +++ b/bscRuntime/libs/NamedEhr.bsv @@ -1,3 +1,4 @@ +// NamedEhr.bsv package Named; import RegFile :: *; diff --git a/bscRuntime/libs/PdlFifo.bsv b/bscRuntime/libs/PdlFifo.bsv deleted file mode 100644 index e69de29b..00000000 diff --git a/bscRuntime/libs/PrioFifo.bsv b/bscRuntime/libs/PrioFifo.bsv index bd609eec..61341409 100644 --- a/bscRuntime/libs/PrioFifo.bsv +++ b/bscRuntime/libs/PrioFifo.bsv @@ -1,3 +1,4 @@ +// PrioFifo.bsv package PrioFifo; import FIFOF :: *; diff --git a/bscRuntime/libs/Speculation.bsv b/bscRuntime/libs/Speculation.bsv index 4397bd53..da90ce7b 100644 --- a/bscRuntime/libs/Speculation.bsv +++ b/bscRuntime/libs/Speculation.bsv @@ -1,3 +1,4 @@ +// Speculation.bsv package Speculation; import Vector :: *; diff --git a/bscRuntime/libs/nametb.bsv b/bscRuntime/libs/nametb.bsv index 7d74a0d9..ea43bdb0 100644 --- a/bscRuntime/libs/nametb.bsv +++ b/bscRuntime/libs/nametb.bsv @@ -1,3 +1,4 @@ +// nametb.bsv import Named::*; import FIFO::*; diff --git a/bscRuntime/libs/project/build.properties b/bscRuntime/libs/project/build.properties new file mode 100644 index 00000000..c8fcab54 --- /dev/null +++ b/bscRuntime/libs/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.6.2 diff --git a/bscRuntime/libs/tb.bsv b/bscRuntime/libs/tb.bsv index c4ce500b..7e2f1727 100644 --- a/bscRuntime/libs/tb.bsv +++ b/bscRuntime/libs/tb.bsv @@ -1,3 +1,4 @@ +// tb.bsv import Memories :: *; import Connectable :: *; diff --git a/bscRuntime/memories/Ehr.bsv b/bscRuntime/memories/Ehr.bsv index 98048693..e85b6252 100644 --- a/bscRuntime/memories/Ehr.bsv +++ b/bscRuntime/memories/Ehr.bsv @@ -1,3 +1,4 @@ +// Ehr.bsv // Copyright (c) 2017 Massachusetts Institute of Technology // diff --git a/bscRuntime/memories/Interrupt.bsv b/bscRuntime/memories/Interrupt.bsv new file mode 100644 index 00000000..b47c39ee --- /dev/null +++ b/bscRuntime/memories/Interrupt.bsv @@ -0,0 +1,35 @@ +package Interrupt; + +import FIFOF :: *; +import Ehr :: *; + +interface TimingInterruptController#(numeric type addr); + method ActionValue#(Bool) req(Int#(addr) a); + method Action ack(Int#(addr) a); +endinterface + +module mkTimingInterruptController(TimingInterruptController#(addr) _unused_); + + Reg#(Bool) status <- mkReg(False); + Reg#(UInt#(10)) timer <- mkReg(0); + Wire#(Int#(addr)) getAck <- mkWire(); + + // rule to update timer and set status to True every 1000 cycle + rule updateTimer; + timer <= timer + 1; + if (timer == 999) begin + timer <= 0; + status <= True; + end + endrule + + method ActionValue#(Bool) req(Int#(addr) p); + return status; + endmethod + + method Action ack(Int#(addr) a); + status <= False; + endmethod +endmodule + +endpackage \ No newline at end of file diff --git a/bscRuntime/memories/Locks.bsv b/bscRuntime/memories/Locks.bsv index b54b018a..4c9af97c 100644 --- a/bscRuntime/memories/Locks.bsv +++ b/bscRuntime/memories/Locks.bsv @@ -1,3 +1,4 @@ +// Locks.bsv package Locks; import FIFOF :: *; diff --git a/bscRuntime/memories/Makefile b/bscRuntime/memories/Makefile index 8f592c0c..7b7c84dc 100644 --- a/bscRuntime/memories/Makefile +++ b/bscRuntime/memories/Makefile @@ -1,5 +1,5 @@ BSC=bsc -no-show-timestamps -no-show-version --aggressive-conditions -TOBUILD=Ehr.bo Locks.bo Memories.bo Speculation.bo SpecialQueues.bo +TOBUILD=Ehr.bo Locks.bo Memories.bo Speculation.bo SpecialQueues.bo Interrupt.bo ## Default simulator is iverilog VSIM = -vsim iverilog diff --git a/bscRuntime/memories/Memories.bsv b/bscRuntime/memories/Memories.bsv index a49719d4..28188d94 100644 --- a/bscRuntime/memories/Memories.bsv +++ b/bscRuntime/memories/Memories.bsv @@ -1,3 +1,4 @@ +// Memories.bsv package Memories; import GetPut :: *; @@ -331,6 +332,8 @@ module mkAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) _unused_) Wire#(Tuple3#(Bit#(n), addr, elem)) toMem <- mkWire(); Wire#(elem) fromMem <- mkWire(); + RWire#(Bool) doClear <- mkRWireSBR(); + //this must be at least size 2 to work correctly (safe bet) Vector#(inflight, Ehr#(2, elem)) outData <- replicateM( mkEhr(unpack(0)) ); Vector#(inflight, Ehr#(2, Bool)) valid <- replicateM( mkEhr(False) ); @@ -348,17 +351,24 @@ module mkAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) _unused_) valid[idx][0] <= True; endrule + (*conflict_free = "freeResp, doClearRule"*) (*fire_when_enabled*) rule freeResp; valid[freeEntry][1] <= False; endrule - method Action clear(); + (*no_implicit_conditions*) + rule doClearRule (doClear.wget() matches tagged Valid.d); + //$display("Memory Cleared"); head <= 0; for (Integer i = 0; i < valueOf(inflight); i = i + 1) begin - MemId#(inflight) ent = fromInteger(i); - valid[ent][1] <= False; + MemId#(inflight) ent = fromInteger(i); + valid[ent][1] <= False; end + endrule + + method Action clear(); + doClear.wset(True); endmethod method ActionValue#(MemId#(inflight)) req1(addr a, elem b, Bit#(n) wmask) if (okToRequest); diff --git a/bscRuntime/memories/SpecialQueues.bsv b/bscRuntime/memories/SpecialQueues.bsv index b526a2f7..f7aa3214 100644 --- a/bscRuntime/memories/SpecialQueues.bsv +++ b/bscRuntime/memories/SpecialQueues.bsv @@ -1,3 +1,4 @@ +// SpecialQueues.bsv package SpecialQueues; import Ehr :: *; @@ -57,26 +58,26 @@ module mkNBFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); FIFOF#(dtyp) f <- mkFIFOF(); //allow multiple writes in the same cycle RWire#(dtyp) enq_data <- mkRWireSBR(); + RWire#(Bool) doClear <- mkRWireSBR(); - //Make sure no enq could happen during clear (takes 2 cycles) - Reg#(Bool) clearCalled <- mkReg(False); - - rule doClear(clearCalled); - f.clear(); - clearCalled <= False; - endrule - + (*conflict_free = "doEnqRule, doClearRule"*) (*fire_when_enabled*) - rule doEnq (enq_data.wget() matches tagged Valid.d); + rule doEnqRule (enq_data.wget() matches tagged Valid.d); f.enq(d); endrule + //reset to the initial state + (*no_implicit_conditions*) + rule doClearRule (doClear.wget() matches tagged Valid.d); + f.clear(); + endrule + //only allow the LAST enq each cycle to work, drop the others - method Action enq(dtyp a) if (f.notFull() && !clearCalled); + method Action enq(dtyp a) if (f.notFull()); enq_data.wset(a); endmethod - method Action deq() if (!clearCalled); + method Action deq(); f.deq(); endmethod @@ -93,7 +94,7 @@ module mkNBFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); endmethod method Action clear(); - clearCalled <= True; + doClear.wset(True); endmethod endmodule diff --git a/bscRuntime/memories/Speculation.bsv b/bscRuntime/memories/Speculation.bsv index e2e019ab..3702903d 100644 --- a/bscRuntime/memories/Speculation.bsv +++ b/bscRuntime/memories/Speculation.bsv @@ -1,3 +1,4 @@ +// Speculation.bsv package Speculation; import Vector :: *; @@ -41,30 +42,43 @@ module mkSpecTable(SpecTable#(SpecId#(entries), bypassCnt)); $display("Head: %d", head); for (Integer i = 0; i < valueOf(entries); i = i + 1) begin - $display("Idx %d, InUse: %b", i, inUse[fromInteger(i)]); - $display("Idx %d, Status: %b", i, specStatus[fromInteger(i)]); + $display("Idx %d, InUse: %b", i, inUse[fromInteger(i)]); + $display("Idx %d, Status: %b", i, specStatus[fromInteger(i)][0]); end endrule - */ - + */ + //Make sure no enq could happen during clear (takes 2 cycles) + RWire#(Bool) doAlloc <- mkRWireSBR(); + RWire#(Bool) doClear <- mkRWireSBR(); + + /* + Reg#(Bool) enabled <- mkReg(True); + */ + (*conflict_free = "doAllocRule, doClearRule"*) (*fire_when_enabled*) rule doAllocRule (doAlloc.wget() matches tagged Valid.d); - head <= head + 1; - inUse[head] <= True; - specStatus[head][valueOf(bypassCnt)-1] <= tagged Invalid; + head <= head + 1; + inUse[head] <= True; + specStatus[head][valueOf(bypassCnt)-1] <= tagged Invalid; endrule - + //reset to the initial state + (*no_implicit_conditions*) + rule doClearRule (doClear.wget() matches tagged Valid.d); + //$display("SpecTable Cleared"); + head <= 0; + for (Integer i = 0; i < valueOf(entries); i = i + 1) begin + SpecId#(entries) lv = fromInteger(i); + specStatus[lv][0] <= tagged Invalid; + inUse[lv] <= False; + end + endrule + method Action clear(); - head <= 0; - for (Integer i = 0; i < valueOf(entries); i = i + 1) begin - SpecId#(entries) lv = fromInteger(i); - specStatus[lv][0] <= tagged Invalid; - inUse[lv] <= False; - end + doClear.wset(True); endmethod - + //allocate a new entry in the table to track speculation. do this in a nonblocking way //and just assume that only 1 client calls per cycle method ActionValue#(SpecId#(entries)) alloc() if (!full); diff --git a/bscRuntime/memories/StgFIFOs.bsv b/bscRuntime/memories/StgFIFOs.bsv new file mode 100644 index 00000000..2e757a1b --- /dev/null +++ b/bscRuntime/memories/StgFIFOs.bsv @@ -0,0 +1,58 @@ +// StgFIFOs.bsv +package StgFIFOs; + +import Ehr :: *; +import ConfigReg :: *; +import FIFOF :: *; + +export mkStgFIFOF; + +// Change to a CReg, two element Queue for per cycle. +module mkStgFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); + + FIFOF#(dtyp) f <- mkFIFOF(); + //allow multiple writes in the same cycle + RWire#(dtyp) enq_data <- mkRWireSBR(); + RWire#(Bool) doClear <- mkRWireSBR(); + + //Make sure no enq could happen during clear (takes 2 cycles) + + (*conflict_free = "doEnqRule, doFIFOClearRule"*) + (*fire_when_enabled, no_implicit_conditions*) + rule doEnqRule (enq_data.wget() matches tagged Valid.d); + f.enq(d); + endrule + + (*fire_when_enabled, no_implicit_conditions*) + rule doFIFOClearRule (doClear.wget() matches tagged Valid.d); + f.clear(); + endrule + + //only allow the LAST enq each cycle to work, drop the others + method Action enq(dtyp a) if (f.notFull()); + enq_data.wset(a); + endmethod + + method Action deq(); + f.deq(); + endmethod + + method dtyp first(); + return f.first(); + endmethod + + method Bool notFull(); + return f.notFull(); + endmethod + + method Bool notEmpty(); + return f.notEmpty(); + endmethod + + method Action clear(); + doClear.wset(True); + endmethod + +endmodule + +endpackage diff --git a/bscRuntime/memories/tb.bsv b/bscRuntime/memories/tb.bsv index 53d0a29a..68a0c2ca 100644 --- a/bscRuntime/memories/tb.bsv +++ b/bscRuntime/memories/tb.bsv @@ -1,3 +1,4 @@ +// tb.bsv import Locks :: *; import Memories::*; import FIFO::*; diff --git a/bscRuntime/verilog/BHT.v b/bscRuntime/verilog/BHT.v index 4f9d4aa0..97f6537f 100644 --- a/bscRuntime/verilog/BHT.v +++ b/bscRuntime/verilog/BHT.v @@ -1,3 +1,4 @@ +// BHT.v `ifdef BSV_ASSIGNMENT_DELAY `else `define BSV_ASSIGNMENT_DELAY diff --git a/bscRuntime/verilog/BypassRF.v b/bscRuntime/verilog/BypassRF.v index 209c9205..f3920c9f 100644 --- a/bscRuntime/verilog/BypassRF.v +++ b/bscRuntime/verilog/BypassRF.v @@ -1,3 +1,4 @@ +// BypassRF.v `ifdef BSV_ASSIGNMENT_DELAY `else `define BSV_ASSIGNMENT_DELAY diff --git a/bscRuntime/verilog/CheckpointBypassRF.v b/bscRuntime/verilog/CheckpointBypassRF.v index c1268d71..f042a687 100644 --- a/bscRuntime/verilog/CheckpointBypassRF.v +++ b/bscRuntime/verilog/CheckpointBypassRF.v @@ -1,3 +1,4 @@ +// CheckpointBypassRF.v `ifdef BSV_ASSIGNMENT_DELAY `else `define BSV_ASSIGNMENT_DELAY diff --git a/bscRuntime/verilog/CheckpointRenameRF.v b/bscRuntime/verilog/CheckpointRenameRF.v index 149c0816..134e874c 100644 --- a/bscRuntime/verilog/CheckpointRenameRF.v +++ b/bscRuntime/verilog/CheckpointRenameRF.v @@ -1,3 +1,4 @@ +// CheckpointRenameRF.v `ifdef BSV_ASSIGNMENT_DELAY `else `define BSV_ASSIGNMENT_DELAY @@ -21,6 +22,7 @@ module CheckpointRenameRF(CLK, VALID_NAME_2, VALID_OUT_2, //check valid data 2 NAME_F, FE, //free name CHK_OUT, CHK_E, CHK_READY, //checkpoint req + ABORT, //abort req ROLLBK_IN, DO_ROLL, DO_REL, ROLLBK_E //rollback req ); @@ -83,7 +85,9 @@ module CheckpointRenameRF(CLK, //rollback input [replica_width - 1 : 0] ROLLBK_IN; input ROLLBK_E, DO_ROLL, DO_REL; - + + //abort + input ABORT; parameter copy_width = name_width * (hi_arch-lo_arch+1); //arch reg file (name file) @@ -155,24 +159,31 @@ module CheckpointRenameRF(CLK, always@(*) begin - if (ROLLBK_E) - begin - case ({DO_REL, DO_ROLL}) - 2'b00 : nextFreeReplicas = freeReplicas; - 2'b01 : nextFreeReplicas = ~(1 << ROLLBK_IN); // free everything but ROLLBK_IN - 2'b10 : nextFreeReplicas = freeReplicas | (1 << ROLLBK_IN); //only free ROLLBK_IN - 2'b11 : nextFreeReplicas = ~0; // free everything - endcase // case ({DO_REL, DO_ROLL}) - end - else - begin - nextFreeReplicas = freeReplicas; - end // else: !if(ROLLBK_E) + if (ABORT) + begin + nextFreeReplicas = ~0; + end // if abort + else + begin + if (ROLLBK_E) + begin + case ({DO_REL, DO_ROLL}) + 2'b00 : nextFreeReplicas = freeReplicas; + 2'b01 : nextFreeReplicas = ~(1 << ROLLBK_IN); // free everything but ROLLBK_IN + 2'b10 : nextFreeReplicas = freeReplicas | (1 << ROLLBK_IN); //only free ROLLBK_IN + 2'b11 : nextFreeReplicas = ~0; // free everything + endcase // case ({DO_REL, DO_ROLL}) + end + else + begin + nextFreeReplicas = freeReplicas; + end // else: !if(ROLLBK_E) + end // if not abort if (CHK_E & nextReplicaValid) - begin - nextFreeReplicas[nextReplica] = 0; - end - end // always@ begin + begin + nextFreeReplicas[nextReplica] = 0; + end + end // always@ begin assign CHK_READY = nextReplicaValid; assign CHK_OUT = nextReplica; @@ -265,6 +276,14 @@ module CheckpointRenameRF(CLK, end else begin + if (ABORT) + begin + names <= `BSV_ASSIGNMENT_DELAY name_copies[0] | name_copies[1]; + free <= `BSV_ASSIGNMENT_DELAY free_copies[0] | free_copies[1] | (FE << oldName) | free; + freeReplicas <= `BSV_ASSIGNMENT_DELAY nextFreeReplicas; + end // if(abort) + else + begin //ROLLBK_E & DO_ROLL => !CHK_E & !ALLOC_E if (ROLLBK_E | (CHK_E & nextReplicaValid)) begin @@ -302,6 +321,7 @@ module CheckpointRenameRF(CLK, begin free[oldName] <= `BSV_ASSIGNMENT_DELAY 1; end + end // else: !if(ABORT) end // else: !if(RST) end // always@ (posedge CLK) diff --git a/bscRuntime/verilog/ForwardRenameRF.v b/bscRuntime/verilog/ForwardRenameRF.v index be253aa4..8f8f6a1c 100644 --- a/bscRuntime/verilog/ForwardRenameRF.v +++ b/bscRuntime/verilog/ForwardRenameRF.v @@ -1,3 +1,4 @@ +// ForwardRenameRF.v `ifdef BSV_ASSIGNMENT_DELAY `else `define BSV_ASSIGNMENT_DELAY diff --git a/bscRuntime/verilog/RenameRF.v b/bscRuntime/verilog/RenameRF.v index 3a255523..0c821f6f 100644 --- a/bscRuntime/verilog/RenameRF.v +++ b/bscRuntime/verilog/RenameRF.v @@ -1,3 +1,4 @@ +// RenameRF.v `ifdef BSV_ASSIGNMENT_DELAY `else `define BSV_ASSIGNMENT_DELAY diff --git a/bscRuntime/verilog/VerilogLibs.bsv b/bscRuntime/verilog/VerilogLibs.bsv index cdcb1df8..fe49cd11 100644 --- a/bscRuntime/verilog/VerilogLibs.bsv +++ b/bscRuntime/verilog/VerilogLibs.bsv @@ -1,3 +1,4 @@ +// VerilogLibs.bsv package VerilogLibs; import RegFile :: *; @@ -39,6 +40,7 @@ interface CheckpointRF#(type addr, type elem, type name, type cid); method Action write(name a, elem b); //write data given allocated name method ActionValue#(cid) checkpoint(); method Action rollback(cid c, Bool doRoll, Bool doRel); + method Action abort(); //abort endinterface interface BypassRF#(type addr, type elem, type id); @@ -136,7 +138,7 @@ import "BVI" ForwardRenameRF = method D_OUT read[2] (NAME); method NAME_OUT res_w1(ADDR_IN) enable(ALLOC_E) ready(ALLOC_READY); method rel_w1(NAME_F) enable(FE); - method write[2] (NAME_IN, D_IN) enable(WE); + method write[2] (NAME_IN, D_IN) enable(WE); schedule (res_r1,res_r2) CF (res_r1,res_r2); schedule (res_r1,res_r2) CF (owns_r1, owns_r2, read, res_w1, write, rel_w1); @@ -183,11 +185,14 @@ import "BVI" CheckpointRenameRF = method CHK_OUT checkpoint() enable(CHK_E) ready(CHK_READY); method rollback (ROLLBK_IN, DO_ROLL, DO_REL) enable(ROLLBK_E); - + + method abort() enable(ABORT); + schedule (checkpoint) C (checkpoint); schedule (rollback) C (rollback); + schedule (abort) C (abort); schedule (checkpoint) CF (rollback); - schedule (checkpoint, rollback) CF (res_r1, res_r2, owns_r1, owns_r2, read, write, rel_w1); + schedule (checkpoint, rollback) CF (res_r1, res_r2, owns_r1, owns_r2, read, write, rel_w1); schedule (res_r1, res_r2) CF (res_r1, res_r2); schedule (res_r1, res_r2) CF (owns_r1, owns_r2, read, res_w1, write, rel_w1); schedule (owns_r1, owns_r2) CF (owns_r1, owns_r2); @@ -198,7 +203,8 @@ import "BVI" CheckpointRenameRF = schedule (res_w1) CF (write, rel_w1, checkpoint, rollback); schedule (write) CF (write, rel_w1); schedule (rel_w1) C (rel_w1); - + schedule (abort) CF (checkpoint, rollback, res_r1, res_r2, res_w1, owns_r1, owns_r2, read, write, rel_w1); + endmodule diff --git a/bscRuntime/verilog/tb.bsv b/bscRuntime/verilog/tb.bsv index a6e9b836..3d2c92c0 100644 --- a/bscRuntime/verilog/tb.bsv +++ b/bscRuntime/verilog/tb.bsv @@ -1,3 +1,4 @@ +// tb.bsv import VerilogLibs::*; import FIFO::*; import RegFile :: *; diff --git a/src/main/scala/pipedsl/Interpreter.scala b/src/main/scala/pipedsl/Interpreter.scala index 01a1936d..3439b50f 100644 --- a/src/main/scala/pipedsl/Interpreter.scala +++ b/src/main/scala/pipedsl/Interpreter.scala @@ -1,3 +1,4 @@ +/* Interpreter.scala */ package pipedsl import java.io.{File, PrintWriter} diff --git a/src/main/scala/pipedsl/Main.scala b/src/main/scala/pipedsl/Main.scala index 95657717..f9b4a011 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -1,3 +1,4 @@ +/* Main.scala */ package pipedsl import java.io.{File, PrintWriter} @@ -73,6 +74,7 @@ object Main { try { val pinfo = new ProgInfo(prog) + MarkNonRecursiveModulePass.run(prog) //First: add lock regions + checkpoints, then do other things val inferredProg = new LockRegionInferencePass().run(prog) diff --git a/src/main/scala/pipedsl/Parser.scala b/src/main/scala/pipedsl/Parser.scala index 0ba7061c..83d7e849 100644 --- a/src/main/scala/pipedsl/Parser.scala +++ b/src/main/scala/pipedsl/Parser.scala @@ -1,3 +1,4 @@ +/* Parser.scala */ package pipedsl import scala.util.parsing.combinator._ import common.Syntax._ @@ -262,7 +263,7 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { typ.? ~ lhs ~ "<-" ~ expr ^^ { case t ~ l ~ _ ~ r => l.typ = t; CRecv(l, r) } | check | resolveSpec | - "except" ~> parens(repsep(expr, ",")) ^^ {args => CExcept(args)} | + catchInterrupt | throwExn | "start" ~> parens(iden) ^^ { i => CLockStart(i) } | "end" ~> parens(iden) ^^ { i => CLockEnd(i) } | "acquire" ~> parens(lockArg ~ ("," ~> lockType).?) ^^ { case i ~ t => CSeq(CLockOp(i, Reserved, t, List(), None), CLockOp(i, Acquired, t, List(), None)) } | @@ -318,12 +319,21 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers { case ni ~ _ ~ _ ~ (oi ~ _ ~ e) => CUpdate(EVar(ni), oi, e, List(), List()) } } + lazy val throwExn: P[Command] = positioned { + "throw" ~> parens(repsep(expr, ",")) ^^ {args => CExcept(args)} + } + lazy val resolveSpec: P[Command] = positioned { "verify" ~> parens(variable ~ "," ~ repsep(expr,",")) ~ braces(methodCall).? ^^ { case i ~ _ ~ e ~ u => CVerify(i, e, List(), u, List()) } | "invalidate" ~> parens(variable) ^^ (i => CInvalidate(i, List())) } + lazy val catchInterrupt: P[Command] = positioned { + "catch" ~> parens(iden) ~ braces(throwExn).? ^^ { + case i ~ u => CCatch(i, u.get)} + } + lazy val casestmt: P[CaseObj] = positioned { "case:" ~> expr ~ block ^^ { case e ~ b => CaseObj(e, b) } } diff --git a/src/main/scala/pipedsl/codegen/Translations.scala b/src/main/scala/pipedsl/codegen/Translations.scala index b4df86b5..4ddfe12e 100644 --- a/src/main/scala/pipedsl/codegen/Translations.scala +++ b/src/main/scala/pipedsl/codegen/Translations.scala @@ -1,3 +1,4 @@ +/* Translations.scala */ package pipedsl.codegen import pipedsl.common.Syntax._ diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala index efc0e1e7..c1274a1a 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala @@ -1,3 +1,4 @@ +/* BSVPrettyPrinter.scala */ package pipedsl.codegen.bsv import java.io.{File, FileOutputStream, OutputStreamWriter, Writer} diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index 01067bea..89c9c0c4 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -1,3 +1,4 @@ +/* BSVSyntax.scala */ package pipedsl.codegen.bsv import pipedsl.codegen.Translations.Translator diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index 92df2f91..1f4cd9da 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -1,3 +1,4 @@ +/* BluespecGeneration.scala */ package pipedsl.codegen.bsv import BSVSyntax.{BBOp, BEmpty, _} @@ -20,6 +21,7 @@ object BluespecGeneration { private val specLib = "Speculation" private val fifoLib = "FIFOF" private val specFifoLib = "SpecialFIFOs" + private val stgFifoLib = "StgFIFOs" private val queueLib = "SpecialQueues" private val combLib = "RegFile" private val asyncLib = "BRAMCore" @@ -27,7 +29,7 @@ object BluespecGeneration { private val ehrLib = "Ehr" private def getRequiredTopLibs: List[BImport] = List(clientLib, connLib, lockLib, memLib, verilogLib, combLib, asyncLib).map(l => BImport(l)) - private def getRequiredModLibs: List[BImport] = List(fifoLib, specFifoLib, queueLib, lockLib, memLib, verilogLib, specLib, combLib, ehrLib).map(l => BImport(l)) + private def getRequiredModLibs: List[BImport] = List(fifoLib, stgFifoLib, specFifoLib, queueLib, lockLib, memLib, verilogLib, specLib, combLib, ehrLib).map(l => BImport(l)) class BluespecProgramGenerator(prog: Prog, stageInfo: Map[Id, List[PStage]], pinfo: ProgInfo, debug: Boolean = false, bsInts: BluespecInterfaces, funcmodname: String = "Functions", @@ -399,7 +401,7 @@ object BluespecGeneration { private val outputData = BVar("data", translator.toType(mod.ret.getOrElse(TVoid()))) private val outputQueue = BVar("outputQueue", bsInts.getOutputQType(threadIdVar.typ, outputData.typ)) //Registers for exceptions - private val globalExnFlag = BVar("_globalExnFlag", bsInts.getEhrType(2, BBool)) + private val globalExnFlag = BVar("_globalExnFlag", bsInts.getRegType(BBool)) //Data types for passing between stages private val edgeStructInfo = getEdgeStructInfo(otherStages, addTId = true, addSpecId = mod.maybeSpec) //First stage should have exactly one input edge by definition @@ -416,7 +418,7 @@ object BluespecGeneration { es ++ s.inEdges ++ s.outEdges }) val edgeParams: EdgeInfo = allEdges.foldLeft(Map[PipelineEdge, BVar]())((m, e) => { - m + (e -> BVar(genParamName(e), bsInts.getFifoType(edgeMap(e)))) + m + (e -> BVar(genParamName(e), bsInts.getStgFifoType(edgeMap(e)))) }) //Generate map from existing module parameter names to BSV variables private val modParams: ModInfo = mod.modules.foldLeft[ModInfo](ListMap())((vars, m) => { @@ -593,11 +595,17 @@ object BluespecGeneration { val queueStmts = getEdgeQueueStmts(stg, stg.allEdges) val blockingConds = getBlockingConds(stg.getCmds) val recvConds = getRecvConds(stg.getCmds) + val exnDisjointConds = getExnKillConds(stg.getCmds, true) + val exnConds = if (exnDisjointConds.isEmpty) { + List[BExpr](globalExnFlag) + } else { + exnDisjointConds + } val debugStmt = if (debug) { BDisplay(Some(mod.name.v + ":Thread %d:Executing Stage " + stg.name + " %t"), List(translator.toBSVVar(threadIdVar), BTime)) } else BEmpty - BRuleDef( genParamName(stg) + "_execute", blockingConds ++ recvConds, + BRuleDef( genParamName(stg) + "_execute", (if(is_excepting(mod)) exnConds else List[BExpr]()) ++ blockingConds ++ recvConds, writeCmdDecls ++ writeCmdStmts ++ queueStmts :+ debugStmt) } @@ -610,30 +618,38 @@ object BluespecGeneration { */ private def getStageKillRules(stg: PStage, is_spec: Boolean, is_excepting: Boolean): List[BRuleDef] = { val misspecKillConds = getMisspecKillConds(stg.getCmds) - val exnKillConds = getExnKillConds(stg.getCmds) + val exnKillConds = getExnKillConds(stg.getCmds, false) + val exnDisjointConds = getExnKillConds(stg.getCmds, true) val recvConds = getRecvConds(stg.getCmds) val misspecDebugStmt = if (debug) { BDisplay(Some(mod.name.v + ":SpecId %d: Killing Stage (on Misspec)" + stg.name + "%t"), List(getSpecIdVal, BTime)) } else { BEmpty } val exnDebugStmt = if (debug) { - BDisplay(Some(mod.name.v + "Killing Stage (on Exception)" + stg.name), - List()) + BDisplay(Some(mod.name.v + " Killing Stage (on Exception)" + "%t"), + List(BTime)) } else { BEmpty } val deqStmts = getEdgeQueueStmts(stg, stg.inEdges) ++ getRecvCmds(stg.getCmds) - val freeStmt = BExprStmt(bsInts.getSpecFree(specTable, getSpecIdVal)) - val misspecKillRule = Some(BRuleDef( genParamName(stg) + "_kill_on_misspec", misspecKillConds ++ recvConds, deqStmts :+ freeStmt :+ misspecDebugStmt)) - val exnKillRule = Some(BRuleDef(genParamName(stg) + "_kill_on_exn", exnKillConds, deqStmts :+ exnDebugStmt)) - + val freeStmt = if (!misspecKillConds.isEmpty) { + BExprStmt(bsInts.getSpecFree(specTable, getSpecIdVal)) + } else { BEmpty } + val misspecKillRule = Some(BRuleDef(genParamName(stg) + "_kill_on_misspec", exnDisjointConds ++ misspecKillConds ++ recvConds, deqStmts :+ freeStmt :+ misspecDebugStmt)) + val exnKillRule = Some(BRuleDef(genParamName(stg) + "_kill_on_exn", exnKillConds, deqStmts :+ freeStmt :+ exnDebugStmt)) var resultingKillRules = List[BRuleDef]() if (misspecKillRule.isDefined && is_spec && !misspecKillConds.isEmpty) resultingKillRules = resultingKillRules :+ misspecKillRule.get - if (exnKillRule.isDefined && is_excepting && !exnKillConds.isEmpty) resultingKillRules = resultingKillRules :+ exnKillRule.get + // if (exnKillRule.isDefined && is_excepting && !exnKillConds.isEmpty) resultingKillRules = resultingKillRules :+ exnKillRule.get resultingKillRules } - private def getExnKillConds(cmds: Iterable[Command]): List[BExpr] = { + private def getExnKillConds(cmds: Iterable[Command], disjoint_cond: Boolean): List[BExpr] = { cmds.foldLeft(List[BExpr]())((l, c) => c match { - case IStageClear() => l :+ BVectorAccess(globalExnFlag, BIndConst(1)) + case ICheckExn() => { + if (disjoint_cond) { + l :+ BUOp("!", globalExnFlag) + } else { + l :+ globalExnFlag + } + } case _ => l }) } @@ -659,9 +675,6 @@ object BluespecGeneration { } else { l } - case IStageClear() => - val disjointCond = BUOp("!", BVectorAccess(globalExnFlag, BIndConst(1))) - l :+ disjointCond case _ => l }) } @@ -834,6 +847,16 @@ object BluespecGeneration { }) } + private def getInEdgeClearStmts(s: PStage, es: Iterable[PipelineEdge], + args: Option[Iterable[BExpr]] = None): List[BStatement] = { + es.foldLeft(List[BStatement]())((l, e) => { + if (e.to == s) { + val stmt = BExprStmt(bsInts.getFifoClear(edgeParams(e))) + l :+ stmt + } else { l } + }) + } + /** * * @param stg The stage to compile @@ -906,7 +929,7 @@ object BluespecGeneration { if (mod.isRecursive) { bsInts.getNBFifo } else { bsInts.getBypassFifo }) val edgeFifos = allEdges.foldLeft(Map[PipelineEdge, BModInst]())((m, e) => { if (e != startEdge) { - m + (e -> BModInst(edgeParams(e), bsInts.getFifo)) + m + (e -> BModInst(edgeParams(e), bsInts.getStgFifo)) } else { m } @@ -939,8 +962,7 @@ object BluespecGeneration { bsInts.getReg(BZero)) //Instantiate Exception Register - val globalExnInst = BModInst(globalExnFlag, bsInts.getEhr(BBoolLit(false))) - + val globalExnInst = BModInst(globalExnFlag, bsInts.getReg(BBoolLit(false))) //Instantiate the speculation table if the module is speculative val specInst = if (mod.maybeSpec) BModInst(specTable, bsInts.getSpecTable) else BEmpty var stmts: List[BStatement] = startFifo +: @@ -1282,21 +1304,25 @@ object BluespecGeneration { } else { None } - case IAbort(mem) => - val abortInfo = LockImplementation.getAbortInfo(mem) - if (abortInfo.isDefined && abortInfo.get.doesModify) { - val abortMethod = translateMethod(getLockName(mem), abortInfo.get) - Some(BExprStmt(abortMethod)) - } else { - None - } + case IAbort(mem) => mem.typ.get match { + case TMemType(_, _, Latency.Asynchronous, writeLatency, readPorts, writePorts) => Some(BExprStmt( + bsInts.getMemClear(modParams(mem), true, isLockedMemory(mem)).get)) + case TMemType(_, _, _ , writeLatency, readPorts, writePorts) => None + case _ => + val abortInfo = LockImplementation.getAbortInfo(mem) + if (abortInfo.isDefined && abortInfo.get.doesModify) { + val abortMethod = translateMethod(getLockName(mem), abortInfo.get) + Some(BExprStmt(abortMethod)) + } else { + None + } + } case ISpecClear() => val clearStmt = BExprStmt(bsInts.getSpecClear(specTable)) Some(clearStmt) case IAssignLock(handle, src, _) => Some( BAssign(translator.toVar(handle), translator.toExpr(src)) ) - case cl@IReleaseLock(mem, _) => val methodInfo = LockImplementation.getReleaseInfo(cl) if (methodInfo.isDefined && methodInfo.get.doesModify) { @@ -1394,8 +1420,9 @@ object BluespecGeneration { case CAssign(_, _) => None case CExpr(_) => None case CEmpty() => None - case IStageClear() => Some(BStmtSeq(getFIFOClears().map(mi => BExprStmt(mi)))) - case ISetGlobalExnFlag(state) => Some(BVectorAssign(BVectorAccess(globalExnFlag, BIndConst(0)), BBoolLit(state))) + case ICheckExn() => None + case IFifoClear() => Some(BStmtSeq(getFIFOClears().map(mi => BExprStmt(mi)))) + case ISetGlobalExnFlag(state) => Some(BModAssign(globalExnFlag, BBoolLit(state))) case _: InternalCommand => throw UnexpectedCommand(cmd) case CRecv(_, _) => throw UnexpectedCommand(cmd) case CSeq(_, _) => throw UnexpectedCommand(cmd) @@ -1445,7 +1472,8 @@ object BluespecGeneration { otherStages.foldLeft(None: Option[PStage])((result, st) => { var stgIsFound = st.getCmds.foldLeft(false)((found, c) => { c match { - case IStageClear() => true + case ICondCommand(_, cs) => found || cs.contains(ICheckExn()) + case ICheckExn() => true case _ => found } }) @@ -1461,16 +1489,14 @@ object BluespecGeneration { findFirstExceptStg() match { case Some(st) => { var resultList = List[BMethodInvoke]() - var unvisited = st.preds + var unvisited = Set[PStage](st) var visited = Set[PStage]() var currVisit = st while(unvisited.nonEmpty){ currVisit = unvisited.head visited += currVisit - currVisit.outEdges.foreach(e => { - if(e.to != st) { - resultList = resultList.appended(bsInts.getFifoClear(edgeParams(e))) - } + currVisit.inEdges.foreach(e => { + resultList = resultList.appended(bsInts.getFifoClear(edgeParams(e))) }) currVisit.preds.foreach(pred => { if(!visited.contains(pred)){ diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala index 3f0f3e3a..0bfb35e4 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecInterfaces.scala @@ -1,3 +1,4 @@ +/* BluespecInterfaces.scala */ package pipedsl.codegen.bsv import BSVSyntax._ @@ -101,6 +102,8 @@ class BluespecInterfaces() { private val fifoEnqueueMethodName = "enq" private val fifoFirstMethodName = "first" + private val fifoStgModuleName = "mkFIFOF" + private val lockHandleName = "LockId" private val chkpointHandleName = "LockId" @@ -297,11 +300,15 @@ class BluespecInterfaces() { def getFifoType(typ: BSVType): BInterface = { BInterface(fifoType, List(BVar("elemtyp", typ))) } + def getStgFifoType(typ: BSVType): BInterface = { + BInterface(fifoType, List(BVar("elemtyp", typ))) + } def getOutputQType(ttyp: BSVType, dtyp: BSVType): BInterface = { BInterface("OutputQ", List(BVar("tagtyp", ttyp), BVar("datatyp", dtyp))); } def getFifo: BModule = BModule(fifoModuleName, List()) def getNBFifo: BModule = BModule(fifoNBModuleName, List()) + def getStgFifo: BModule = BModule(fifoStgModuleName, List()) def getBypassFifo: BModule = BModule("mkBypassFIFOF", List()) def getOutputQ(init: BExpr): BModule = BModule("mkOutputFIFOF", List(init)) def getFifoDeq(f: BVar): BMethodInvoke = { diff --git a/src/main/scala/pipedsl/codegen/bsv/ConstraintsToBluespec.scala b/src/main/scala/pipedsl/codegen/bsv/ConstraintsToBluespec.scala index e208d5b3..93e7dade 100644 --- a/src/main/scala/pipedsl/codegen/bsv/ConstraintsToBluespec.scala +++ b/src/main/scala/pipedsl/codegen/bsv/ConstraintsToBluespec.scala @@ -1,3 +1,4 @@ +/* ConstraintsToBluespec.scala */ package pipedsl.codegen.bsv import pipedsl.common.Constraints._ diff --git a/src/main/scala/pipedsl/common/CommandLineParser.scala b/src/main/scala/pipedsl/common/CommandLineParser.scala index ca65ba50..448d64b6 100644 --- a/src/main/scala/pipedsl/common/CommandLineParser.scala +++ b/src/main/scala/pipedsl/common/CommandLineParser.scala @@ -1,3 +1,4 @@ +/* CommandLineParser.scala */ package pipedsl.common import java.io.File diff --git a/src/main/scala/pipedsl/common/Constraints.scala b/src/main/scala/pipedsl/common/Constraints.scala index 12bf8bbc..bdd72cce 100644 --- a/src/main/scala/pipedsl/common/Constraints.scala +++ b/src/main/scala/pipedsl/common/Constraints.scala @@ -1,3 +1,4 @@ +/* Constraints.scala */ package pipedsl.common import pipedsl.common.Syntax.{EIndAdd, EIndConst, EIndSub, EIndex, Id, TBitWidth, TNamedType} diff --git a/src/main/scala/pipedsl/common/DAGSyntax.scala b/src/main/scala/pipedsl/common/DAGSyntax.scala index d24c2532..828b7f80 100644 --- a/src/main/scala/pipedsl/common/DAGSyntax.scala +++ b/src/main/scala/pipedsl/common/DAGSyntax.scala @@ -1,3 +1,4 @@ +/* DAGSyntax.scala */ package pipedsl.common import pipedsl.common.Errors.UnexpectedCommand diff --git a/src/main/scala/pipedsl/common/Dataflow.scala b/src/main/scala/pipedsl/common/Dataflow.scala index 80122cb2..fa66c849 100644 --- a/src/main/scala/pipedsl/common/Dataflow.scala +++ b/src/main/scala/pipedsl/common/Dataflow.scala @@ -1,3 +1,4 @@ +/* Dataflow.scala */ package pipedsl.common import DAGSyntax._ diff --git a/src/main/scala/pipedsl/common/Errors.scala b/src/main/scala/pipedsl/common/Errors.scala index e6d13bce..f16fb1e5 100644 --- a/src/main/scala/pipedsl/common/Errors.scala +++ b/src/main/scala/pipedsl/common/Errors.scala @@ -1,3 +1,4 @@ +/* Errors.scala */ package pipedsl.common import scala.util.parsing.input.{NoPosition, Position, Positional} @@ -241,4 +242,8 @@ object Errors { case class NoWriteReleaseInBody(p :Position) extends RuntimeException( withPos("No release writes in the main body!", p) ) + + case class MustThrowWithExnPipe(p :Position) extends RuntimeException( + withPos("Must have at least one throw for a module with defined exception handler", p) + ) } diff --git a/src/main/scala/pipedsl/common/LockImplementation.scala b/src/main/scala/pipedsl/common/LockImplementation.scala index 4c189301..e7782ab9 100644 --- a/src/main/scala/pipedsl/common/LockImplementation.scala +++ b/src/main/scala/pipedsl/common/LockImplementation.scala @@ -1,3 +1,4 @@ +/* LockImplementation.scala */ package pipedsl.common import pipedsl.common.Errors.{MissingType, UnexpectedLockImpl} @@ -286,6 +287,7 @@ object LockImplementation { def getAbortInfo(mem: Id): Option[MethodInfo] = { val interface = getLockImplFromMemTyp(mem) + println(interface) getAbort(interface) match { case Some(_) => val methodName = (if(interface.hasLockSubInterface) lockIntStr else "") + abortName @@ -668,7 +670,8 @@ object LockImplementation { val parent = super.getType TObject(Id("CheckpointRF"), List(), parent.methods ++ Map( Id(checkpointName) -> (TFun(List(), checkType), Sequential), - Id(rollbackName) -> (TFun(List(checkType), TVoid()), Sequential) + Id(rollbackName) -> (TFun(List(checkType), TVoid()), Sequential), + Id(abortName) -> (TFun(List(), TVoid()), Sequential) )) } //TODO make more parameterizable diff --git a/src/main/scala/pipedsl/common/Locks.scala b/src/main/scala/pipedsl/common/Locks.scala index 145c0008..ed34eb9f 100644 --- a/src/main/scala/pipedsl/common/Locks.scala +++ b/src/main/scala/pipedsl/common/Locks.scala @@ -1,3 +1,4 @@ +/* Locks.scala */ package pipedsl.common import pipedsl.common.DAGSyntax.PStage diff --git a/src/main/scala/pipedsl/common/MemoryInputParser.scala b/src/main/scala/pipedsl/common/MemoryInputParser.scala index 971043b8..edc0b439 100644 --- a/src/main/scala/pipedsl/common/MemoryInputParser.scala +++ b/src/main/scala/pipedsl/common/MemoryInputParser.scala @@ -1,3 +1,4 @@ +/* MemoryInputParser.scala */ package pipedsl.common import scala.collection.immutable diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index b50c9913..26098c9e 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -1,3 +1,4 @@ +/* PrettyPrinter.scala */ package pipedsl.common import java.io.{File, FileOutputStream, OutputStreamWriter} @@ -130,7 +131,7 @@ class PrettyPrinter(output: Option[File]) { case Syntax.CExcept(args) => ins + "except(" + args.map(printExprToString).foldLeft("")((acc, elem) => acc + ", " + elem) + ");" case Syntax.CCheckSpec(isBlk) => ins + (if (isBlk) "spec_barrier();" else "spec_check();") case Syntax.IAbort(mem) => ins + "abort(" + mem +");" - case Syntax.IStageClear() => ins + "clearOnExn();" + case Syntax.ICheckExn() => ins + "clearStgOnExn();" case Syntax.ISpecClear() => ins + "spectable.clear();" case Syntax.ISetGlobalExnFlag(state) => ins + "setGlobalExnFlag(" + state +");" case Syntax.IReleaseLock(mem, inHandle) => ins + "release(" + mem + ");" diff --git a/src/main/scala/pipedsl/common/ProgInfo.scala b/src/main/scala/pipedsl/common/ProgInfo.scala index 8aab1f3f..5be416de 100644 --- a/src/main/scala/pipedsl/common/ProgInfo.scala +++ b/src/main/scala/pipedsl/common/ProgInfo.scala @@ -1,3 +1,4 @@ +/* ProgInfo.scala */ package pipedsl.common import pipedsl.common.Locks.LockGranularity diff --git a/src/main/scala/pipedsl/common/Security.scala b/src/main/scala/pipedsl/common/Security.scala index 58cc95d1..93b24a45 100644 --- a/src/main/scala/pipedsl/common/Security.scala +++ b/src/main/scala/pipedsl/common/Security.scala @@ -1,3 +1,4 @@ +/* Security.scala */ package pipedsl.common import scala.util.parsing.input.Positional diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index c56a548b..7e2d26ec 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -1,3 +1,4 @@ +/* Syntax.scala */ package pipedsl.common import scala.util.parsing.input.{Position, Positional} import Errors._ @@ -647,11 +648,13 @@ object Syntax { case class CSplit(cases: List[CaseObj], default: Command) extends Command case class CEmpty() extends Command case class CExcept(args: List[Expr]) extends Command + case class CCatch(mod: Id, onCatch: Command) extends Command sealed trait InternalCommand extends Command case class IAbort(mem: Id) extends InternalCommand - case class IStageClear() extends InternalCommand + case class IFifoClear() extends InternalCommand + case class ICheckExn() extends InternalCommand case class ISpecClear() extends InternalCommand case class ISetGlobalExnFlag(state: Boolean) extends InternalCommand case class ICondCommand(cond: Expr, cs: List[Command]) extends InternalCommand diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index 5e2376fc..970f9a07 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -1,3 +1,4 @@ +/* Utilities.scala */ package pipedsl.common import com.microsoft.z3.{AST => Z3AST, BoolExpr => Z3BoolExpr, Context => Z3Context} @@ -84,6 +85,7 @@ object Utilities { case IUpdate(specId, value, originalSpec) => getUsedVars(value) ++ getUsedVars(originalSpec) + specId case Syntax.CEmpty() => Set() case CExcept(args) => args.foldLeft(Set[Id]())((set, arg) => set.union(getUsedVars(arg))) + case CCatch(m, c) => Set() case _ => throw UnexpectedCommand(c) } @@ -197,10 +199,11 @@ object Utilities { case None => Set() }) case ILockNoOp(_) => Set() - case IStageClear() => Set() + case ICheckExn() => Set() case ISpecClear() => Set() case ISetGlobalExnFlag(_) => Set() case IAbort(_) => Set() + case IFifoClear() => Set() case CLockStart(_) => Set() case CLockEnd(_) => Set() case CSpecCall(handle, _, args) => args.foldLeft(Set(handle.id))((s, a) => s ++ getUsedVars(a)) @@ -214,6 +217,7 @@ object Utilities { case CInvalidate(handle, cHandles) => Set(handle.id) ++ cHandles.map(v => v.id) case CCheckSpec(_) => Set() case CEmpty() => Set() + case CCatch(m, c) => Set() } /** diff --git a/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala b/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala index 2bbb252b..f7cabd8f 100644 --- a/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala +++ b/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala @@ -1,3 +1,4 @@ +/* AddCheckpointHandlesPass.scala */ package pipedsl.passes import pipedsl.common.Syntax._ diff --git a/src/main/scala/pipedsl/passes/AddEdgeValuePass.scala b/src/main/scala/pipedsl/passes/AddEdgeValuePass.scala index cb8a4f25..36c2b5ad 100644 --- a/src/main/scala/pipedsl/passes/AddEdgeValuePass.scala +++ b/src/main/scala/pipedsl/passes/AddEdgeValuePass.scala @@ -1,3 +1,4 @@ +/* AddEdgeValuePass.scala */ package pipedsl.passes import pipedsl.common.Dataflow._ diff --git a/src/main/scala/pipedsl/passes/AddVerifyValuesPass.scala b/src/main/scala/pipedsl/passes/AddVerifyValuesPass.scala index cc484ed2..7678ddbd 100644 --- a/src/main/scala/pipedsl/passes/AddVerifyValuesPass.scala +++ b/src/main/scala/pipedsl/passes/AddVerifyValuesPass.scala @@ -1,3 +1,4 @@ +/* AddVerifyValuesPass.scala */ package pipedsl.passes import pipedsl.common.Errors.MissingPredictionValues diff --git a/src/main/scala/pipedsl/passes/BindModuleTypes.scala b/src/main/scala/pipedsl/passes/BindModuleTypes.scala index 7aae8ed0..bead1b32 100644 --- a/src/main/scala/pipedsl/passes/BindModuleTypes.scala +++ b/src/main/scala/pipedsl/passes/BindModuleTypes.scala @@ -1,3 +1,4 @@ +/* BindModuleTypes.scala */ package pipedsl.passes import pipedsl.common.Syntax._ diff --git a/src/main/scala/pipedsl/passes/CanonicalizePass.scala b/src/main/scala/pipedsl/passes/CanonicalizePass.scala index a62938b5..3f72939f 100644 --- a/src/main/scala/pipedsl/passes/CanonicalizePass.scala +++ b/src/main/scala/pipedsl/passes/CanonicalizePass.scala @@ -1,3 +1,4 @@ +/* CanonicalizePass.scala */ package pipedsl.passes import pipedsl.common.Syntax._ @@ -116,6 +117,7 @@ class CanonicalizePass() extends CommandPass[Command] with ModulePass[ModuleDef] case CEmpty() => c case CExcept(args) => val (nargs, nc) = extractCastVars(args) CSeq(nc, CExcept(nargs).setPos(c.pos)) + case CCatch(m, oc) => c case _: InternalCommand => c } diff --git a/src/main/scala/pipedsl/passes/CheckExcepting.scala b/src/main/scala/pipedsl/passes/CheckExcepting.scala index 8da0283a..950c8790 100644 --- a/src/main/scala/pipedsl/passes/CheckExcepting.scala +++ b/src/main/scala/pipedsl/passes/CheckExcepting.scala @@ -1,3 +1,4 @@ +/* CheckExcepting.scala */ //package pipedsl.passes // //import pipedsl.common.Errors.{ReleaseInExnBlock, ReleaseWhenMaybeExcepting} diff --git a/src/main/scala/pipedsl/passes/CollapseStagesPass.scala b/src/main/scala/pipedsl/passes/CollapseStagesPass.scala index c50a1769..4fe7e284 100644 --- a/src/main/scala/pipedsl/passes/CollapseStagesPass.scala +++ b/src/main/scala/pipedsl/passes/CollapseStagesPass.scala @@ -1,3 +1,4 @@ +/* CollapseStagesPass.scala */ package pipedsl.passes import pipedsl.common.DAGSyntax._ diff --git a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala index 6a420874..720cf2cd 100644 --- a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala +++ b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala @@ -1,3 +1,4 @@ +/* ConvertAsyncPass.scala */ package pipedsl.passes import pipedsl.common.Syntax._ diff --git a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala index 3336f493..45271459 100644 --- a/src/main/scala/pipedsl/passes/ExnTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -1,3 +1,4 @@ +/* ExnTranslationPass.scala */ package pipedsl.passes import pipedsl.common.Syntax._ @@ -22,7 +23,7 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ } } - override def run(p: Prog): Prog = p.copy(moddefs = p.moddefs.map(m => run(m))) + override def run(p: Prog): Prog = p.copy(moddefs = p.moddefs.map(m => run(m).copyMeta(m))) def addExnVars(m: ModuleDef): ModuleDef = { @@ -32,7 +33,6 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case ExceptFull(args, c) => var arg_count = 0 args.foreach(arg => { - arg.typ match { case Some(t: Type) => val newExnArgId = Id("_exnArg_"+arg_count.toString()) @@ -49,17 +49,17 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case ExceptEmpty() => CEmpty() } - m.copy(body = convertPrimitives(m.body), commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) + m.copy(body = CSeq(ICheckExn(), convertBody(m.body)), commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) } - def convertPrimitives(c: Command): Command = { + def convertBody(c: Command): Command = { c match { - case CSeq(c1, c2) => CSeq(convertPrimitives(c1), convertPrimitives(c2)).copyMeta(c) - case CIf(cond, cons, alt) => CIf(cond, convertPrimitives(cons), convertPrimitives(alt)).copyMeta(c) - case CTBar(c1, c2) => CTBar(convertPrimitives(c1), convertPrimitives(c2)).copyMeta(c) + case CSeq(c1, c2) => CSeq(convertBody(c1), convertBody(c2)).copyMeta(c) + case CIf(cond, cons, alt) => CIf(cond, convertBody(cons), convertBody(alt)).copyMeta(c) + case CTBar(c1, c2) => CTBar(convertBody(c1), CSeq(ICheckExn(), convertBody(c2))).copyMeta(c) case CSplit(cases, default) => - val newCases = cases.map(c => CaseObj(c.cond, convertPrimitives(c.body))) - CSplit(newCases, convertPrimitives(default)).copyMeta(c) + val newCases = cases.map(c => CaseObj(c.cond, convertBody(c.body))) + CSplit(newCases, convertBody(default)).copyMeta(c) case CExcept(args) => val setLocalErrFlag = CAssign(localExnFlag, EBool(true)).copyMeta(c) var arg_count = 0 @@ -100,11 +100,11 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ def convertExnArgsId(e: Expr): Expr = { e match { - case EIsValid(ex) => EIsValid(convertExnArgsId(ex)) - case EFromMaybe(ex) => EFromMaybe(convertExnArgsId(ex)) - case EToMaybe(ex) => EToMaybe(convertExnArgsId(ex)) - case EUop(op, ex) => EUop(op, convertExnArgsId(ex)) - case EBinop(op, e1, e2) => EBinop(op, convertExnArgsId(e1), convertExnArgsId(e2)) + case EIsValid(ex) => EIsValid(convertExnArgsId(ex)).setPos(e.pos) + case EFromMaybe(ex) => EFromMaybe(convertExnArgsId(ex)).setPos(e.pos) + case EToMaybe(ex) => EToMaybe(convertExnArgsId(ex)).setPos(e.pos) + case EUop(op, ex) => EUop(op, convertExnArgsId(ex)).setPos(e.pos) + case EBinop(op, e1, e2) => EBinop(op, convertExnArgsId(e1), convertExnArgsId(e2)).setPos(e.pos) case EApp(func, args) => { val newArgs = args.foldLeft(List[Expr]())((l, arg) => { arg match { @@ -114,7 +114,7 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case _ => l :+ arg } }) - EApp(func, newArgs) + EApp(func, newArgs).setPos(e.pos) } case ECall(mod, name, args, isAtomic) => { val newArgs = args.foldLeft(List[Expr]())((l, arg) => { @@ -125,9 +125,9 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case _ => l :+ arg } }) - ECall(mod, name, newArgs, isAtomic) + ECall(mod, name, newArgs, isAtomic).setPos(e.pos) } - case ECast(ctyp, e) => ECast(ctyp, convertExnArgsId(e)) + case ECast(ctyp, e) => ECast(ctyp, convertExnArgsId(e)).setPos(e.pos) case EVar(id) => exnArgApplyMap.getOrElse(id, e).setPos(e.pos) case _ => e } @@ -139,27 +139,31 @@ class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ case _ => CEmpty() } val except_stmts = m.except_blk match { - case ExceptFull(_, c) => - val unsetGlobalExnFlag = ISetGlobalExnFlag(false) - val abortStmts = m.modules.foldLeft(CSeq(IStageClear(), CEmpty()))((c, mod) => - mod.typ match { - case TLockedMemType(mem, _, _) => CSeq(c, IAbort(mod.name)) - case _ => CSeq(c, CEmpty()) - }) - CTBar(abortStmts, CSeq(c, unsetGlobalExnFlag)) + case ExceptFull(_, c) => c case ExceptEmpty() => CEmpty() } - val setGlobalExnFlag = ISetGlobalExnFlag(true) + + val abortStmts = m.modules.foldLeft(CSeq(CEmpty(), CEmpty()))((c, mod) => + mod.typ match { + case TLockedMemType(mem, _, _) => CSeq(c, IAbort(mod.name)) + case TMemType(_, _, _, _, _, _) => CSeq(c, IAbort(mod.name)) + case _ => CSeq(c, CEmpty()) + }) + + println(abortStmts) val initLocalErrFlag = CAssign(localExnFlag, EBool(false)).copyMeta(m.body) - val clearSpecTable = if (m.maybeSpec) { - ISpecClear() - } else { - CEmpty() - } - val finalBlocks = CIf(localExnFlag, CTBar(CSeq(setGlobalExnFlag, clearSpecTable), except_stmts), commit_stmts) - val newBody = CSeq(initLocalErrFlag, CSeq(m.body,finalBlocks)) + val setGlobalExnFlag = ISetGlobalExnFlag(true) + val unsetGlobalExnFlag = ISetGlobalExnFlag(false) + + val clearSpecTable = if (m.maybeSpec) ISpecClear() else CEmpty() + val clearFifos = IFifoClear() + + val exnRollbackStmts = CTBar(setGlobalExnFlag, CSeq(CSeq(abortStmts, clearSpecTable), clearFifos)) + val translatedExnBlock = CTBar(exnRollbackStmts, CSeq(except_stmts, unsetGlobalExnFlag)) + val finalBlocks = CIf(localExnFlag, translatedExnBlock, commit_stmts) + val newBody = CSeq(initLocalErrFlag, CSeq(m.body, finalBlocks)) //TODO require memory or module types - m.copy(body = newBody, commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) + m.copy(body = newBody, commit_blk = None, except_blk = m.except_blk).copyMeta(m) } } diff --git a/src/main/scala/pipedsl/passes/ExpandCatchPass.scala b/src/main/scala/pipedsl/passes/ExpandCatchPass.scala new file mode 100644 index 00000000..fa841bde --- /dev/null +++ b/src/main/scala/pipedsl/passes/ExpandCatchPass.scala @@ -0,0 +1,35 @@ +package pipedsl.passes + +import pipedsl.common.Syntax._ +import pipedsl.passes.Passes.{ModulePass, ProgPass} + +class ExpandCatchPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ + override def run(m: ModuleDef): ModuleDef = + { + if(is_excepting(m)){ + m.copy(body = expandCatch(m.body), commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) + } else { + m + } + } + override def run(p: Prog): Prog = p.copy(moddefs = p.moddefs.map(m => run(m).copyMeta(m))) + + def expandCatch(c: Command): Command = { + c match { + case CSeq(c1, c2) => CSeq(expandCatch(c1), expandCatch(c2)).copyMeta(c) + case CTBar(c1, c2) => CTBar(expandCatch(c1), expandCatch(c2)).copyMeta(c) + case CSplit(cases, default) => + val newCases = cases.map(c => CaseObj(c.cond, expandCatch(c.body))) + CSplit(newCases, expandCatch(default)).copyMeta(c) + case CCatch(mod, onCatch) => { + val is_interrupt = EVar(Id("is_interrupt")).setPos(c.pos) + is_interrupt.typ = Some(TBool()) + is_interrupt.id.typ = is_interrupt.typ + val get_req = CAssign(is_interrupt, ECall(mod, Some(Id("req")), List[Expr](EVar(Id("pc"))), true)) + val ack = CExpr(ECall(mod, Some(Id("ack")), List[Expr](EVar(Id("pc"))), false)) + CSeq(get_req, CIf(is_interrupt, CSeq(ack, onCatch), CEmpty())) + } + case _ => c + } + } +} diff --git a/src/main/scala/pipedsl/passes/LockEliminationPass.scala b/src/main/scala/pipedsl/passes/LockEliminationPass.scala index 08b92a29..260c15d6 100644 --- a/src/main/scala/pipedsl/passes/LockEliminationPass.scala +++ b/src/main/scala/pipedsl/passes/LockEliminationPass.scala @@ -1,3 +1,4 @@ +/* LockEliminationPass.scala */ package pipedsl.passes import pipedsl.common.DAGSyntax.{IfStage, PStage} diff --git a/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala b/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala index 0cabb517..251ffb2a 100644 --- a/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala +++ b/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala @@ -1,3 +1,4 @@ +/* LockOpTranslationPass.scala */ package pipedsl.passes import pipedsl.common.Locks._ diff --git a/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala b/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala index c19d57ab..9ca062a3 100644 --- a/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala +++ b/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala @@ -1,3 +1,4 @@ +/* LockRegionInferencePass.scala */ package pipedsl.passes import pipedsl.common.Locks.Reserved diff --git a/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala b/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala index 09c3d245..352505c4 100644 --- a/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala +++ b/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala @@ -1,3 +1,4 @@ +/* MarkNonRecursiveModulePass.scala */ package pipedsl.passes import pipedsl.common.Syntax._ diff --git a/src/main/scala/pipedsl/passes/Passes.scala b/src/main/scala/pipedsl/passes/Passes.scala index bb26cc68..e0ec312f 100644 --- a/src/main/scala/pipedsl/passes/Passes.scala +++ b/src/main/scala/pipedsl/passes/Passes.scala @@ -1,3 +1,4 @@ +/* Passes.scala */ package pipedsl.passes import pipedsl.common.DAGSyntax.PStage diff --git a/src/main/scala/pipedsl/passes/PredicateGenerator.scala b/src/main/scala/pipedsl/passes/PredicateGenerator.scala index fe898bb9..31489e10 100644 --- a/src/main/scala/pipedsl/passes/PredicateGenerator.scala +++ b/src/main/scala/pipedsl/passes/PredicateGenerator.scala @@ -1,3 +1,4 @@ +/* PredicateGenerator.scala */ package pipedsl.passes import com.microsoft.z3.{AST => Z3AST, BoolExpr => Z3BoolExpr, Context => Z3Context, Expr => Z3Expr} diff --git a/src/main/scala/pipedsl/passes/RemoveReentrantPass.scala b/src/main/scala/pipedsl/passes/RemoveReentrantPass.scala index a10816f4..95eac3fe 100644 --- a/src/main/scala/pipedsl/passes/RemoveReentrantPass.scala +++ b/src/main/scala/pipedsl/passes/RemoveReentrantPass.scala @@ -1,3 +1,4 @@ +/* RemoveReentrantPass.scala */ package pipedsl.passes import pipedsl.common.DAGSyntax.PStage diff --git a/src/main/scala/pipedsl/passes/RemoveTimingPass.scala b/src/main/scala/pipedsl/passes/RemoveTimingPass.scala index 5f013838..26eb44a2 100644 --- a/src/main/scala/pipedsl/passes/RemoveTimingPass.scala +++ b/src/main/scala/pipedsl/passes/RemoveTimingPass.scala @@ -1,3 +1,4 @@ +/* RemoveTimingPass.scala */ package pipedsl.passes import pipedsl.common.Syntax._ diff --git a/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala b/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala index cbf97313..04bace35 100644 --- a/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala +++ b/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala @@ -1,3 +1,4 @@ +/* SimplifyRecvPass.scala */ package pipedsl.passes import Passes.{CommandPass, ModulePass, ProgPass} diff --git a/src/main/scala/pipedsl/passes/SplitStagesPass.scala b/src/main/scala/pipedsl/passes/SplitStagesPass.scala index 653188d2..fd037512 100644 --- a/src/main/scala/pipedsl/passes/SplitStagesPass.scala +++ b/src/main/scala/pipedsl/passes/SplitStagesPass.scala @@ -1,3 +1,4 @@ +/* SplitStagesPass.scala */ package pipedsl.passes import pipedsl.common.DAGSyntax.{IfStage, PStage, PipelineEdge} diff --git a/src/main/scala/pipedsl/typechecker/AnalysisProvider.scala b/src/main/scala/pipedsl/typechecker/AnalysisProvider.scala index 495d3b1e..4534c492 100644 --- a/src/main/scala/pipedsl/typechecker/AnalysisProvider.scala +++ b/src/main/scala/pipedsl/typechecker/AnalysisProvider.scala @@ -1,3 +1,4 @@ +/* AnalysisProvider.scala */ package pipedsl.typechecker import pipedsl.common.Syntax.Prog diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index 0b10dc07..7d0f59b3 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -1,3 +1,4 @@ +/* BaseTypeChecker.scala */ package pipedsl.typechecker import pipedsl.common.Errors._ @@ -400,6 +401,7 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { mtyp match { case TModType(inputs, _, _, _) => if (inputs.length != args.length) { + print(args) throw ArgLengthMismatch(c.pos, inputs.length, args.length) } if (inputs.length != preds.length) { diff --git a/src/main/scala/pipedsl/typechecker/CheckpointChecker.scala b/src/main/scala/pipedsl/typechecker/CheckpointChecker.scala index b204702e..f40ba3af 100644 --- a/src/main/scala/pipedsl/typechecker/CheckpointChecker.scala +++ b/src/main/scala/pipedsl/typechecker/CheckpointChecker.scala @@ -1,3 +1,4 @@ +/* CheckpointChecker.scala */ package pipedsl.typechecker import com.microsoft.z3.{AST => Z3AST, BoolExpr => Z3BoolExpr, Context => Z3Context, Solver => Z3Solver, Status => Z3Status} diff --git a/src/main/scala/pipedsl/typechecker/Environments.scala b/src/main/scala/pipedsl/typechecker/Environments.scala index ecfb5887..8f4106c0 100644 --- a/src/main/scala/pipedsl/typechecker/Environments.scala +++ b/src/main/scala/pipedsl/typechecker/Environments.scala @@ -1,3 +1,4 @@ +/* Environments.scala */ package pipedsl.typechecker import com.microsoft.z3.{AST => Z3AST, BoolExpr => Z3BoolExpr, Context => Z3Context} @@ -69,7 +70,8 @@ object Environments { override def add(name: Id, typ: Type): Environment[Id, Type] = typeMap.get(name) match { case Some(t) => throw AlreadyBoundType(name.pos, name.v, t, typ) - case None => this.copy(typeMap = typeMap + (name -> typ)) + case None => + this.copy(typeMap = typeMap + (name -> typ)) } override def remove(name: Id): Environment[Id, Type] = { TypeEnv(this.typeMap - name) diff --git a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala index d4bf2b52..6997aaf4 100644 --- a/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala +++ b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala @@ -1,3 +1,4 @@ +/* FinalblocksConstraintChecker.scala */ package pipedsl.typechecker import pipedsl.common.Syntax._ @@ -19,7 +20,7 @@ object FinalblocksConstraintChecker { m.except_blk match { case ExceptEmpty() => checkNormBody(m.body) case ExceptFull(_, c) => - checkExBody(m.body) + if(!checkExBody(m.body)) throw MustThrowWithExnPipe(c.pos) checkCommit(m.commit_blk.get) checkExceptingBlock(c) } @@ -43,14 +44,16 @@ object FinalblocksConstraintChecker { } - private def checkExBody(c :Command) :Unit = c match { - case CSeq(c1, c2) => checkExBody(c1); checkExBody(c2) - case CTBar(c1, c2) => checkExBody(c1); checkExBody(c2) - case CIf(_, cons, alt) => checkExBody(cons); checkExBody(alt) - case CRecv(EMemAccess(mem, _, _, _, _, isAtomic), _) if isAtomic || !isLockedMemory(mem)=> throw NoCommittingWriteInBody(c.pos) + private def checkExBody(c :Command) : Boolean = c match { + case CSeq(c1, c2) => checkExBody(c1) || checkExBody(c2) + case CTBar(c1, c2) => checkExBody(c1) || checkExBody(c2) + case CIf(_, cons, alt) => checkExBody(cons) || checkExBody(alt) + // TODO: (PDL Exception) Add Async Locked Memory for CheckpointQueue + case CRecv(EMemAccess(mem, _, _, _, _, isAtomic), _) if isAtomic && !isLockedMemory(mem)=> throw NoCommittingWriteInBody(c.pos) case c@CLockOp(mem, Released, _, _, _) if c.memOpType.contains(LockWrite) || c.granularity == General => throw NoWriteReleaseInBody(c.pos) - case CSplit(cases, default) => checkExBody(default); cases.foreach(co => checkExBody(co.body)) - case _ => () + case CSplit(cases, default) => checkExBody(default) || cases.foldLeft(false) { (acc, co) => acc || checkExBody(co.body) } + case CExcept(_) => true + case _ => false } private def checkExceptingBlock(c :Command) :Unit = checkNoThrow(c, PreCall) diff --git a/src/main/scala/pipedsl/typechecker/FunctionConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/FunctionConstraintChecker.scala index e9ae51ee..fbc27ab1 100644 --- a/src/main/scala/pipedsl/typechecker/FunctionConstraintChecker.scala +++ b/src/main/scala/pipedsl/typechecker/FunctionConstraintChecker.scala @@ -1,3 +1,4 @@ +/* FunctionConstraintChecker.scala */ package pipedsl.typechecker import com.microsoft.z3.{Status, Context => Z3Context, Solver => Z3Solver} diff --git a/src/main/scala/pipedsl/typechecker/LatencyChecker.scala b/src/main/scala/pipedsl/typechecker/LatencyChecker.scala index 2cfc5aa1..272b214c 100644 --- a/src/main/scala/pipedsl/typechecker/LatencyChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LatencyChecker.scala @@ -1,3 +1,4 @@ +/* LatencyChecker.scala */ /* package pipedsl.typechecker diff --git a/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala b/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala index 79a4e93b..43ae9343 100644 --- a/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala @@ -1,3 +1,4 @@ +/* LinearExecutionChecker.scala */ package pipedsl.typechecker import com.microsoft.z3.{ diff --git a/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala index 62cc0862..7bb025e3 100644 --- a/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala @@ -1,3 +1,4 @@ +/* LockConstraintChecker.scala */ package pipedsl.typechecker import com.microsoft.z3.{AST => Z3AST, BoolExpr => Z3BoolExpr, Context => Z3Context, Solver => Z3Solver, Status => Z3Status} @@ -63,7 +64,8 @@ class LockConstraintChecker(lockMap: Map[Id, Set[LockArg]], lockGranularityMap: override def checkModule(m: ModuleDef, env: Environment[LockArg, Z3AST]): Environment[LockArg, Z3AST] = { checkChunk(m.name, m.extendedBody(), env) - m.except_blk.foreach(checkChunk(m.name, _, env)) + //TODO - Exn : add new rule +// m.except_blk.foreach(checkChunk(m.name, _, env)) env } diff --git a/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala b/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala index 3cb4f551..55f01bc0 100644 --- a/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala @@ -1,3 +1,4 @@ +/* LockOperationTypeChecker.scala */ package pipedsl.typechecker; import pipedsl.common.Errors.{IllegalMemoryAccessOperation, MalformedLockTypes, UnexpectedCase} diff --git a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala index a47079a5..feab8bcf 100644 --- a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala @@ -1,3 +1,4 @@ +/* LockRegionChecker.scala */ package pipedsl.typechecker import pipedsl.common.Errors.{IllegalLockAcquisition, InvalidLockState, UnexpectedCase} diff --git a/src/main/scala/pipedsl/typechecker/LockReleaseChecker.scala b/src/main/scala/pipedsl/typechecker/LockReleaseChecker.scala index 1b0feb23..d5925210 100644 --- a/src/main/scala/pipedsl/typechecker/LockReleaseChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockReleaseChecker.scala @@ -1,3 +1,4 @@ +/* LockReleaseChecker.scala */ package pipedsl.typechecker import pipedsl.common.Errors.IllegalOOOLockRelease diff --git a/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala b/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala index 831f560e..9a5857d0 100644 --- a/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala @@ -1,3 +1,4 @@ +/* LockWellformedChecker.scala */ package pipedsl.typechecker import pipedsl.common.Errors.MalformedLockTypes diff --git a/src/main/scala/pipedsl/typechecker/PortChecker.scala b/src/main/scala/pipedsl/typechecker/PortChecker.scala index 1133730f..b23057eb 100644 --- a/src/main/scala/pipedsl/typechecker/PortChecker.scala +++ b/src/main/scala/pipedsl/typechecker/PortChecker.scala @@ -1,3 +1,4 @@ +/* PortChecker.scala */ package pipedsl.typechecker import pipedsl.common.{Locks, Syntax, Errors} diff --git a/src/main/scala/pipedsl/typechecker/SpeculationChecker.scala b/src/main/scala/pipedsl/typechecker/SpeculationChecker.scala index 73dac724..ab94a4c3 100644 --- a/src/main/scala/pipedsl/typechecker/SpeculationChecker.scala +++ b/src/main/scala/pipedsl/typechecker/SpeculationChecker.scala @@ -1,3 +1,4 @@ +/* SpeculationChecker.scala */ package pipedsl.typechecker import com.microsoft.z3.{AST => Z3AST, BoolExpr => Z3BoolExpr, Context => Z3Context, Solver => Z3Solver, Status => Z3Status} @@ -126,9 +127,10 @@ class SpeculationChecker(val ctx: Z3Context) extends TypeChecks[Id, Z3AST] { //TODO error that actually says something about checkpoints throw IllegalSpeculativeOperation(c.pos, NonSpeculative.toString) } - if (op == Released && (t.isEmpty || t.get == LockWrite) && s != NonSpeculative) { - throw IllegalSpeculativeOperation(c.pos, NonSpeculative.toString) - } +// TODO - Exn: Fix this check +// if (op == Released && (t.isEmpty || t.get == LockWrite) && s != NonSpeculative) { +// throw IllegalSpeculativeOperation(c.pos, NonSpeculative.toString) +// } //shouldn't do any potentially speculative lock ops w/o checking first if (s == Unknown) { throw IllegalSpeculativeOperation(c.pos, Speculative.toString) diff --git a/src/main/scala/pipedsl/typechecker/Subtypes.scala b/src/main/scala/pipedsl/typechecker/Subtypes.scala index 498d79fe..7d8cafb1 100644 --- a/src/main/scala/pipedsl/typechecker/Subtypes.scala +++ b/src/main/scala/pipedsl/typechecker/Subtypes.scala @@ -1,3 +1,4 @@ +/* Subtypes.scala */ package pipedsl.typechecker import pipedsl.common.Syntax._ diff --git a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala index 546bc29a..80b8c32b 100644 --- a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala @@ -1,3 +1,4 @@ +/* TimingTypeChecker.scala */ package pipedsl.typechecker import pipedsl.common.Syntax._ @@ -331,8 +332,8 @@ object TimingTypeChecker extends TypeChecks[Id, Type] { //calling another pipe case None => Asynchronous } - case EVar(id) => if(!vars(id) && isRhs && !(id == is_excepting_var)) { - throw UnavailableArgUse(e.pos, id.toString) } + case EVar(id) => if(!vars(id) && isRhs && !(id == is_excepting_var)) {throw UnavailableArgUse(e.pos, id.toString) } + //TODO - exn remove above line and fix this: throw UnavailableArgUse(e.pos, id.toString) } //TODO make this error message more clear about what's wrong when these are lock handle vars else { Combinational } case ECast(_, exp) => checkExpr(exp, vars, isRhs) diff --git a/src/main/scala/pipedsl/typechecker/TypeChecker.scala b/src/main/scala/pipedsl/typechecker/TypeChecker.scala index 170c738b..69b30870 100644 --- a/src/main/scala/pipedsl/typechecker/TypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/TypeChecker.scala @@ -1,3 +1,4 @@ +/* TypeChecker.scala */ package pipedsl.typechecker import pipedsl.common.Syntax._ diff --git a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala index 673c0148..355a448c 100644 --- a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala +++ b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala @@ -1,3 +1,4 @@ +/* TypeInferenceWrapper.scala */ package pipedsl.typechecker import pipedsl.common.{Errors, Syntax} @@ -230,7 +231,7 @@ object TypeInferenceWrapper case ces@CirExprStmt(ce) => val (_, nv, nce) = checkCirExpr(ce, tenv) (nv, ces.copy(ce = nce).setPos(ces.pos)) } - + // TODO - EXN: This need rewrite and fix bugs def checkModule(m: ModuleDef, env: TypeEnv): (Environment[Id, Type], ModuleDef) = { val inputTypes = m.inputs.map(p => p.typ) @@ -250,7 +251,8 @@ object TypeInferenceWrapper { case ExceptEmpty() => (ExceptEmpty(), subst1) //TODO IMPROVE PRECISION OF OUT_ENV, SUBST - case ExceptFull(args, c) => checkCommand(c, args.foldLeft(pipeEnv)((env, id) => env.add(id, id.typ.get).asInstanceOf[TypeEnv]), subst) |> + case ExceptFull(args, c) => + checkCommand(c, args.foldLeft(out_env)((env, id) => env.add(id, id.typ.get).asInstanceOf[TypeEnv]), subst) |> {case (cmd, _, s) => (ExceptFull(args, cmd), s)} } val hash = mutable.HashMap.from(final_subst) @@ -357,6 +359,7 @@ object TypeInferenceWrapper case b => throw UnexpectedType(mem.id.pos, c.toString, "Memory or Module Type", b) } case CEmpty() => (c, env, sub) + case CCatch(_, oc) => checkCommand(oc, env, sub) case CExcept(args) => (c, env, sub) //TODO IMPLEMENT case cr@CReturn(exp) => val (s, t, e, fixed) = infer(env, exp) diff --git a/src/test/scala/pipedsl/CSplitSuite.scala b/src/test/scala/pipedsl/CSplitSuite.scala index 1bac9c18..73bdbef1 100644 --- a/src/test/scala/pipedsl/CSplitSuite.scala +++ b/src/test/scala/pipedsl/CSplitSuite.scala @@ -1,3 +1,4 @@ +/* CSplitSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite diff --git a/src/test/scala/pipedsl/ExceptionSuite.scala b/src/test/scala/pipedsl/ExceptionSuite.scala index d74efe2b..979f9ef7 100644 --- a/src/test/scala/pipedsl/ExceptionSuite.scala +++ b/src/test/scala/pipedsl/ExceptionSuite.scala @@ -1,3 +1,4 @@ +/* ExceptionSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite diff --git a/src/test/scala/pipedsl/LockMergeSuite.scala b/src/test/scala/pipedsl/LockMergeSuite.scala index 382439b8..4e7d5124 100644 --- a/src/test/scala/pipedsl/LockMergeSuite.scala +++ b/src/test/scala/pipedsl/LockMergeSuite.scala @@ -1,3 +1,4 @@ +/* LockMergeSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite diff --git a/src/test/scala/pipedsl/LockTypecheckSuite.scala b/src/test/scala/pipedsl/LockTypecheckSuite.scala index ffc52762..41b6b948 100644 --- a/src/test/scala/pipedsl/LockTypecheckSuite.scala +++ b/src/test/scala/pipedsl/LockTypecheckSuite.scala @@ -1,3 +1,4 @@ +/* LockTypecheckSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite diff --git a/src/test/scala/pipedsl/MainSuite.scala b/src/test/scala/pipedsl/MainSuite.scala index 1a57c835..6c6c5405 100644 --- a/src/test/scala/pipedsl/MainSuite.scala +++ b/src/test/scala/pipedsl/MainSuite.scala @@ -1,3 +1,4 @@ +/* MainSuite.scala */ package pipedsl import java.io.File diff --git a/src/test/scala/pipedsl/MiscSimulationSuite.scala b/src/test/scala/pipedsl/MiscSimulationSuite.scala index 88ebaffd..8c258203 100644 --- a/src/test/scala/pipedsl/MiscSimulationSuite.scala +++ b/src/test/scala/pipedsl/MiscSimulationSuite.scala @@ -1,3 +1,4 @@ +/* MiscSimulationSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite diff --git a/src/test/scala/pipedsl/RegisterRenamingSuite.scala b/src/test/scala/pipedsl/RegisterRenamingSuite.scala index 696f6719..b291ed28 100644 --- a/src/test/scala/pipedsl/RegisterRenamingSuite.scala +++ b/src/test/scala/pipedsl/RegisterRenamingSuite.scala @@ -1,3 +1,4 @@ +/* RegisterRenamingSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite diff --git a/src/test/scala/pipedsl/RiscSuite.scala b/src/test/scala/pipedsl/RiscSuite.scala index f1f07106..ec9342e5 100644 --- a/src/test/scala/pipedsl/RiscSuite.scala +++ b/src/test/scala/pipedsl/RiscSuite.scala @@ -1,3 +1,4 @@ +/* RiscSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite @@ -26,18 +27,21 @@ class RiscSuite extends AnyFunSuite { //For each processor impl testFiles.foreach(t => { val testBaseName = getTestName(t) - test(testBaseName + " Typecheck") { - testTypecheck(testFolder, t) - } - test(testBaseName + " BSV Compile") { - testBlueSpecCompile(testFolder, t, None, Map()) - } - //For each program - sims.foreach(s => { - val simInputs = getInputMap(s) - test(testBaseName + " Simulate " + s) { - testBlueSpecSim(testFolder, t, None, simInputs, Some(s + ".simsol")) + if (testBaseName.contains("exn")) { + test(testBaseName + " Typecheck") { + testTypecheck(testFolder, t) + } + test(testBaseName + " BSV Compile") { + testBlueSpecCompile(testFolder, t, None, Map()) } - }) + //For each program + sims.foreach(s => { + val simInputs = getInputMap(s) + test(testBaseName + " Simulate " + s) { + testBlueSpecSim(testFolder, t, None, simInputs, Some(s + ".simsol")) + } + }) + } + }) } diff --git a/src/test/scala/pipedsl/SpeculationSuite.scala b/src/test/scala/pipedsl/SpeculationSuite.scala index e70a5d21..db7c86cd 100644 --- a/src/test/scala/pipedsl/SpeculationSuite.scala +++ b/src/test/scala/pipedsl/SpeculationSuite.scala @@ -1,3 +1,4 @@ +/* SpeculationSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite diff --git a/src/test/scala/pipedsl/TypeAutoCastSuite.scala b/src/test/scala/pipedsl/TypeAutoCastSuite.scala index 7049a449..d5636233 100644 --- a/src/test/scala/pipedsl/TypeAutoCastSuite.scala +++ b/src/test/scala/pipedsl/TypeAutoCastSuite.scala @@ -1,3 +1,4 @@ +/* TypeAutoCastSuite.scala */ package pipedsl import org.scalatest.funsuite.AnyFunSuite diff --git a/src/test/scala/pipedsl/package.scala b/src/test/scala/pipedsl/package.scala index a9f43b30..811874dd 100644 --- a/src/test/scala/pipedsl/package.scala +++ b/src/test/scala/pipedsl/package.scala @@ -1,3 +1,4 @@ +/* package.scala */ import java.io.File import java.nio.file.Paths diff --git a/src/test/tests/autocastTests/autocast-basic-pass.pdl b/src/test/tests/autocastTests/autocast-basic-pass.pdl index 28c7bc04..c88b20e7 100644 --- a/src/test/tests/autocastTests/autocast-basic-pass.pdl +++ b/src/test/tests/autocastTests/autocast-basic-pass.pdl @@ -1,3 +1,4 @@ +// autocast-basic-pass.pdl def helper1(a: int<32>, b:bool, c: String): int<32> { d = a + 1<16>; e = b && false; diff --git a/src/test/tests/autocastTests/risc-pipe-spec.pdl b/src/test/tests/autocastTests/risc-pipe-spec.pdl index 9e7b4adf..9b331ac2 100644 --- a/src/test/tests/autocastTests/risc-pipe-spec.pdl +++ b/src/test/tests/autocastTests/risc-pipe-spec.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec.pdl def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { uint<32> mag1 = cast(mag(arg1), uint<32>); uint<32> mag2 = cast(mag(arg2), uint<32>); diff --git a/src/test/tests/autocastTests/type-inference-basic-pass.pdl b/src/test/tests/autocastTests/type-inference-basic-pass.pdl index cdc50f37..d0311360 100644 --- a/src/test/tests/autocastTests/type-inference-basic-pass.pdl +++ b/src/test/tests/autocastTests/type-inference-basic-pass.pdl @@ -1,3 +1,4 @@ +// type-inference-basic-pass.pdl def helper1(a: int<32>, b:bool, c: String): int<32> { d = a + 1<32>; diff --git a/src/test/tests/autocastTests/type-inference-bit-width-tests.pdl b/src/test/tests/autocastTests/type-inference-bit-width-tests.pdl index 21410330..9f439464 100644 --- a/src/test/tests/autocastTests/type-inference-bit-width-tests.pdl +++ b/src/test/tests/autocastTests/type-inference-bit-width-tests.pdl @@ -1,3 +1,4 @@ +// type-inference-bit-width-tests.pdl def helper1(a: int<32>, b:bool, c: String): int<32> { d = a + 1; diff --git a/src/test/tests/autocastTests/type-inference-fail-base-type.pdl b/src/test/tests/autocastTests/type-inference-fail-base-type.pdl index 72889371..9cb9cdf4 100644 --- a/src/test/tests/autocastTests/type-inference-fail-base-type.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-base-type.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-base-type.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = input + 2<32>; if (a) { diff --git a/src/test/tests/autocastTests/type-inference-fail-bit-too-small-memAccessToosmall.pdl b/src/test/tests/autocastTests/type-inference-fail-bit-too-small-memAccessToosmall.pdl index dd313404..0843f4ff 100644 --- a/src/test/tests/autocastTests/type-inference-fail-bit-too-small-memAccessToosmall.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-bit-too-small-memAccessToosmall.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-bit-too-small-memAccessToosmall.pdl pipe test6()[rf: int<32>[32]] { int<64> a = 6 * 6; diff --git a/src/test/tests/autocastTests/type-inference-fail-bit-too-small-minus.pdl b/src/test/tests/autocastTests/type-inference-fail-bit-too-small-minus.pdl index 1149577f..d419151d 100644 --- a/src/test/tests/autocastTests/type-inference-fail-bit-too-small-minus.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-bit-too-small-minus.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-bit-too-small-minus.pdl pipe test6()[] { a = 6 - 6; diff --git a/src/test/tests/autocastTests/type-inference-fail-bit-too-small-mult.pdl b/src/test/tests/autocastTests/type-inference-fail-bit-too-small-mult.pdl index 737be003..e0a85b87 100644 --- a/src/test/tests/autocastTests/type-inference-fail-bit-too-small-mult.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-bit-too-small-mult.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-bit-too-small-mult.pdl pipe test6()[] { a = 6 * 6; diff --git a/src/test/tests/autocastTests/type-inference-fail-bit-too-small-plus.pdl b/src/test/tests/autocastTests/type-inference-fail-bit-too-small-plus.pdl index deabf477..8b0e693d 100644 --- a/src/test/tests/autocastTests/type-inference-fail-bit-too-small-plus.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-bit-too-small-plus.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-bit-too-small-plus.pdl pipe test6()[] { a = 6 + 6; diff --git a/src/test/tests/autocastTests/type-inference-fail-boolBinOp.pdl b/src/test/tests/autocastTests/type-inference-fail-boolBinOp.pdl index 3a302da6..974eca9f 100644 --- a/src/test/tests/autocastTests/type-inference-fail-boolBinOp.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-boolBinOp.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-boolBinOp.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = input; diff --git a/src/test/tests/autocastTests/type-inference-fail-call-args.pdl b/src/test/tests/autocastTests/type-inference-fail-call-args.pdl index 379def08..61f88a55 100644 --- a/src/test/tests/autocastTests/type-inference-fail-call-args.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-call-args.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-call-args.pdl pipe test10(a: bool, b: int<32>)[rf: int<32>[32]]: int<32> { output(5<32>); } diff --git a/src/test/tests/autocastTests/type-inference-fail-call.pdl b/src/test/tests/autocastTests/type-inference-fail-call.pdl index 6bc02fad..09d7de24 100644 --- a/src/test/tests/autocastTests/type-inference-fail-call.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-call.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-call.pdl pipe test10(a: bool, b: int<32>)[rf: int<32>[32]]: int<32> { output(5<32>); } diff --git a/src/test/tests/autocastTests/type-inference-fail-eqBinOp.pdl b/src/test/tests/autocastTests/type-inference-fail-eqBinOp.pdl index 0d4bae05..bf44b5e9 100644 --- a/src/test/tests/autocastTests/type-inference-fail-eqBinOp.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-eqBinOp.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-eqBinOp.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = true; b = a == input; diff --git a/src/test/tests/autocastTests/type-inference-fail-func-app-arg.pdl b/src/test/tests/autocastTests/type-inference-fail-func-app-arg.pdl index c2bb8609..7c811ae6 100644 --- a/src/test/tests/autocastTests/type-inference-fail-func-app-arg.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-func-app-arg.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-func-app-arg.pdl def func(a: bool, b: int<32>): bool { return b; } diff --git a/src/test/tests/autocastTests/type-inference-fail-funcApp.pdl b/src/test/tests/autocastTests/type-inference-fail-funcApp.pdl index f69d3e87..57730ebc 100644 --- a/src/test/tests/autocastTests/type-inference-fail-funcApp.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-funcApp.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-funcApp.pdl def func(a: bool, b: int<32>): bool { return b; } diff --git a/src/test/tests/autocastTests/type-inference-fail-numBinOp.pdl b/src/test/tests/autocastTests/type-inference-fail-numBinOp.pdl index 3096b3d3..20697e4d 100644 --- a/src/test/tests/autocastTests/type-inference-fail-numBinOp.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-numBinOp.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-numBinOp.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = true; b = a + a; diff --git a/src/test/tests/autocastTests/type-inference-fail-ternary.pdl b/src/test/tests/autocastTests/type-inference-fail-ternary.pdl index e635be6e..f1f6f027 100644 --- a/src/test/tests/autocastTests/type-inference-fail-ternary.pdl +++ b/src/test/tests/autocastTests/type-inference-fail-ternary.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-ternary.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = true; b = input; diff --git a/src/test/tests/branchesCheck/branch-1.pdl b/src/test/tests/branchesCheck/branch-1.pdl index 1161510d..04fda858 100644 --- a/src/test/tests/branchesCheck/branch-1.pdl +++ b/src/test/tests/branchesCheck/branch-1.pdl @@ -1,3 +1,4 @@ +// branch-1.pdl pipe test(inarg: int<32>)[rf: int<32>[5]] { start(rf); diff --git a/src/test/tests/branchesCheck/branch-2.pdl b/src/test/tests/branchesCheck/branch-2.pdl index 600f0410..fb16b4c1 100644 --- a/src/test/tests/branchesCheck/branch-2.pdl +++ b/src/test/tests/branchesCheck/branch-2.pdl @@ -1,3 +1,4 @@ +// branch-2.pdl pipe test(inarg: int<32>)[rf: int<32>[5]] { start(rf); if (inarg{0:0} == 1) { diff --git a/src/test/tests/branchesCheck/branch-3.pdl b/src/test/tests/branchesCheck/branch-3.pdl index 9a35e83c..c813443b 100644 --- a/src/test/tests/branchesCheck/branch-3.pdl +++ b/src/test/tests/branchesCheck/branch-3.pdl @@ -1,3 +1,4 @@ +// branch-3.pdl pipe test(cond: uint<2>, addr: uint<16>)[mem: int<32>[16]]: bool { start(mem); if (cond == 0) { diff --git a/src/test/tests/branchesCheck/nested-1.pdl b/src/test/tests/branchesCheck/nested-1.pdl index 64a3fb2f..9f7f1b6c 100644 --- a/src/test/tests/branchesCheck/nested-1.pdl +++ b/src/test/tests/branchesCheck/nested-1.pdl @@ -1,3 +1,4 @@ +// nested-1.pdl pipe test(inarg: int<32>)[] { if (inarg{0:0} == 1) { if (inarg{1:1} == 0) { diff --git a/src/test/tests/branchesCheck/nested-2.pdl b/src/test/tests/branchesCheck/nested-2.pdl index 6e6a46ad..dd5e14b4 100644 --- a/src/test/tests/branchesCheck/nested-2.pdl +++ b/src/test/tests/branchesCheck/nested-2.pdl @@ -1,3 +1,4 @@ +// nested-2.pdl pipe test(inarg: uint<32>)[] { if (cast (inarg{0:0}, bool)) { if (inarg{1:1} == u0) { diff --git a/src/test/tests/branchesCheck/nested-branches-1.pdl b/src/test/tests/branchesCheck/nested-branches-1.pdl index 0c55d066..365d609c 100644 --- a/src/test/tests/branchesCheck/nested-branches-1.pdl +++ b/src/test/tests/branchesCheck/nested-branches-1.pdl @@ -1,3 +1,4 @@ +// nested-branches-1.pdl pipe multi_stg_mul(a1: int<32>, a2: int<32>)[]: int<32> { int<32> rr = a1{15:0} * a2{15:0}; int<32> rl = a1{15:0} * a2{31:16}; diff --git a/src/test/tests/branchesCheck/split-1.pdl b/src/test/tests/branchesCheck/split-1.pdl index 47ad0a52..ce7f852b 100644 --- a/src/test/tests/branchesCheck/split-1.pdl +++ b/src/test/tests/branchesCheck/split-1.pdl @@ -1,3 +1,4 @@ +// split-1.pdl pipe test(inarg: int<32>)[] { split { case: (inarg{1:0} == 0<2>) { diff --git a/src/test/tests/branchesCheck/split-2.pdl b/src/test/tests/branchesCheck/split-2.pdl index 8888eb46..6586fd2c 100644 --- a/src/test/tests/branchesCheck/split-2.pdl +++ b/src/test/tests/branchesCheck/split-2.pdl @@ -1,3 +1,4 @@ +// split-2.pdl pipe test(inarg: int<32>)[rf: int<32>[5](Queue)] { start(rf); int<2> cond = inarg{1:0}; diff --git a/src/test/tests/branchesCheck/split-3.pdl b/src/test/tests/branchesCheck/split-3.pdl index ca3cc544..c57f5792 100644 --- a/src/test/tests/branchesCheck/split-3.pdl +++ b/src/test/tests/branchesCheck/split-3.pdl @@ -1,3 +1,4 @@ +// split-3.pdl pipe test(inarg: int<32>)[rf: int<32>[5](Queue)] { start(rf); int<2> cond = inarg{1:0}; diff --git a/src/test/tests/branchesCheck/split-4.pdl b/src/test/tests/branchesCheck/split-4.pdl index ab6028f8..0c06ebee 100644 --- a/src/test/tests/branchesCheck/split-4.pdl +++ b/src/test/tests/branchesCheck/split-4.pdl @@ -1,3 +1,4 @@ +// split-4.pdl pipe test(inarg: int<32>)[rf: int<32>[5](Queue)] { start(rf); int<2> cond = inarg{1:0}; diff --git a/src/test/tests/exception/exn-recovery-spec.pdl b/src/test/tests/exception/exn-recovery-spec.pdl index 52160cce..edbd4553 100644 --- a/src/test/tests/exception/exn-recovery-spec.pdl +++ b/src/test/tests/exception/exn-recovery-spec.pdl @@ -1,3 +1,4 @@ +// exn-recovery-spec.pdl //Expect 5 Success, 1 Exception, 1 Success post recovery exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { spec_check(); @@ -9,14 +10,16 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { spec_check(); s <- speccall cpu(pc + 1); --- - spec_barrier(); + spec_check(); block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; + --- + spec_barrier(); if(acc_val == 6) { invalidate(s); - except(u0<4>); + throw(u0<4>); } else { if(acc_val == 3) { @@ -31,7 +34,6 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { } } } - --- commit: release(acc); print("no exn at PC == %d! with acc_val of %d", pc, acc_val); diff --git a/src/test/tests/exception/exn-recovery.pdl b/src/test/tests/exception/exn-recovery.pdl index b7c78526..ed62abc2 100644 --- a/src/test/tests/exception/exn-recovery.pdl +++ b/src/test/tests/exception/exn-recovery.pdl @@ -1,3 +1,4 @@ +// exn-recovery.pdl //Expect 5 Success, 1 Exception, 1 Success post recovery exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { start(acc); @@ -7,17 +8,23 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { block(acc); acc_val = acc[0]; acc[0] <- acc_val + 1; - if(acc_val == 10){ - output(0); - } else { - call cpu(pc + 1); + bool done = pc == u16<16>; + if (!done) { + call cpu(pc + 1); } --- - if(acc_val == 6) - { - except(u0<4>); + if(done){ + output(0); + //print("Output called at PC == %d", pc); + } else { + if(acc_val == 6) + { + throw(u0<4>); + } + else{ + //do nothing + } } - --- commit: release(acc); print("no exn at PC == %d! with acc_val of %d", pc, acc_val); @@ -31,7 +38,7 @@ except(arg: uint<4>): acc[0] <- 9; --- release(acc); - call cpu(pc + 1); + call cpu(pc + 5); } diff --git a/src/test/tests/exception/exn-simple-spec.pdl b/src/test/tests/exception/exn-simple-spec.pdl index 94b6a09b..d7b51727 100644 --- a/src/test/tests/exception/exn-simple-spec.pdl +++ b/src/test/tests/exception/exn-simple-spec.pdl @@ -1,3 +1,4 @@ +// exn-simple-spec.pdl //Expected Success exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { spec_check(); @@ -15,7 +16,7 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { acc[0] <- acc_val + 1; if(acc_val == 6) { - except(u0<4>); + throw(u0<4>); } --- spec_barrier(); @@ -31,7 +32,6 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { verify(s, pc + 1); } } - --- commit: release(acc); print("no exn at PC == %d! with acc_val of %d", pc, acc_val); diff --git a/src/test/tests/exception/exn-simple.pdl b/src/test/tests/exception/exn-simple.pdl index 426bc48b..5cce8ed1 100644 --- a/src/test/tests/exception/exn-simple.pdl +++ b/src/test/tests/exception/exn-simple.pdl @@ -1,3 +1,4 @@ +// exn-simple.pdl //Expect 5 Success, 1 Exception exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { start(acc); @@ -11,9 +12,8 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { --- if(acc_val == 6) { - except(u0<4>); + throw(u0<4>); } - --- commit: release(acc); print("no exn at PC == %d! with acc_val of %d", pc, acc_val); diff --git a/src/test/tests/exception/solutions/exn-recovery.simsol b/src/test/tests/exception/solutions/exn-recovery.simsol index 1afe3744..d0004bba 100644 --- a/src/test/tests/exception/solutions/exn-recovery.simsol +++ b/src/test/tests/exception/solutions/exn-recovery.simsol @@ -5,4 +5,8 @@ no exn at PC == 4! with acc_val of 3 no exn at PC == 5! with acc_val of 4 no exn at PC == 6! with acc_val of 5 exception at PC == 7! with arg: 0 -no exn at PC == 8! with acc_val of 9 +no exn at PC == 12! with acc_val of 9 +no exn at PC == 13! with acc_val of 10 +no exn at PC == 14! with acc_val of 11 +no exn at PC == 15! with acc_val of 12 +no exn at PC == 16! with acc_val of 13 \ No newline at end of file diff --git a/src/test/tests/histogram/histogram.pdl b/src/test/tests/histogram/histogram.pdl index 622b74e6..f47b0855 100644 --- a/src/test/tests/histogram/histogram.pdl +++ b/src/test/tests/histogram/histogram.pdl @@ -1,3 +1,4 @@ +// histogram.pdl /* n = 128 void histogram ( int feature [] , float weight [] , float hist [] , int n ) { diff --git a/src/test/tests/histogram/histogram_bram.pdl b/src/test/tests/histogram/histogram_bram.pdl index 8fb21d8b..c7e2b347 100644 --- a/src/test/tests/histogram/histogram_bram.pdl +++ b/src/test/tests/histogram/histogram_bram.pdl @@ -1,3 +1,4 @@ +// histogram_bram.pdl /* n = 128 void histogram ( int feature [] , float weight [] , float hist [] , int n ) { diff --git a/src/test/tests/histogram/histogram_bram2.pdl b/src/test/tests/histogram/histogram_bram2.pdl index 69b17c5f..bc86fa17 100644 --- a/src/test/tests/histogram/histogram_bram2.pdl +++ b/src/test/tests/histogram/histogram_bram2.pdl @@ -1,3 +1,4 @@ +// histogram_bram2.pdl /* n = 128 void histogram ( int feature [] , float weight [] , float hist [] , int n ) { diff --git a/src/test/tests/histogram/histogram_nested.pdl b/src/test/tests/histogram/histogram_nested.pdl index f58af2a5..aca96a7f 100644 --- a/src/test/tests/histogram/histogram_nested.pdl +++ b/src/test/tests/histogram/histogram_nested.pdl @@ -1,3 +1,4 @@ +// histogram_nested.pdl /* n = 128 void histogram ( int feature [] , float weight [] , float hist [] , int n ) { diff --git a/src/test/tests/histogram/histogram_short.pdl b/src/test/tests/histogram/histogram_short.pdl index 76284355..e2a5bbc8 100644 --- a/src/test/tests/histogram/histogram_short.pdl +++ b/src/test/tests/histogram/histogram_short.pdl @@ -1,3 +1,4 @@ +// histogram_short.pdl /* n = 128 void histogram ( int feature [] , float weight [] , float hist [] , int n ) { diff --git a/src/test/tests/lockTests/lock-infer-1.pdl b/src/test/tests/lockTests/lock-infer-1.pdl index 522cb6cd..6ad9d9fa 100644 --- a/src/test/tests/lockTests/lock-infer-1.pdl +++ b/src/test/tests/lockTests/lock-infer-1.pdl @@ -1,3 +1,4 @@ +// lock-infer-1.pdl pipe ex1(in: bool)[r1: int<32>[5](Queue), r2: int<32>[5](Queue)] :bool { uint<5> addr = u1<5>; if (in) { diff --git a/src/test/tests/lockTests/lock-infer-2.pdl b/src/test/tests/lockTests/lock-infer-2.pdl index 0e19cd55..9a568ded 100644 --- a/src/test/tests/lockTests/lock-infer-2.pdl +++ b/src/test/tests/lockTests/lock-infer-2.pdl @@ -1,3 +1,4 @@ +// lock-infer-2.pdl pipe ex2(in: bool)[rf: int<32>[5](Queue)] :bool { uint<5> addr = u1<5>; if (in) { diff --git a/src/test/tests/lockTests/lock-infer-3.pdl b/src/test/tests/lockTests/lock-infer-3.pdl index a6ad01e2..22d2008d 100644 --- a/src/test/tests/lockTests/lock-infer-3.pdl +++ b/src/test/tests/lockTests/lock-infer-3.pdl @@ -1,3 +1,4 @@ +// lock-infer-3.pdl pipe ex4(inarg: int<32>)[rf: int<32>[5](Queue)] :int<32> { uint<5> a1 = u0<5>; diff --git a/src/test/tests/lockTests/lock-infer-4.pdl b/src/test/tests/lockTests/lock-infer-4.pdl index badf4d54..70f966d4 100644 --- a/src/test/tests/lockTests/lock-infer-4.pdl +++ b/src/test/tests/lockTests/lock-infer-4.pdl @@ -1,3 +1,4 @@ +// lock-infer-4.pdl pipe ex4(in: bool)[rf: int<32>[5](Queue)] :bool{ uint<5> addr = u1<5>; reserve(rf[addr],R); diff --git a/src/test/tests/lockTests/lock-merge-1.pdl b/src/test/tests/lockTests/lock-merge-1.pdl index 83e34f3d..7f5af686 100644 --- a/src/test/tests/lockTests/lock-merge-1.pdl +++ b/src/test/tests/lockTests/lock-merge-1.pdl @@ -1,3 +1,4 @@ +// lock-merge-1.pdl pipe ex1(in: bool)[r1: int<32>[5](Queue), r2: int<32>[5](Queue)] :bool { start(r1); start(r2); diff --git a/src/test/tests/lockTests/lock-merge-2.pdl b/src/test/tests/lockTests/lock-merge-2.pdl index 83c9fc98..a25ffbba 100644 --- a/src/test/tests/lockTests/lock-merge-2.pdl +++ b/src/test/tests/lockTests/lock-merge-2.pdl @@ -1,3 +1,4 @@ +// lock-merge-2.pdl pipe ex2(in: bool)[rf: int<32>[5](Queue)] :bool { start(rf); uint<5> addr = u1<5>; diff --git a/src/test/tests/lockTests/lock-merge-3.pdl b/src/test/tests/lockTests/lock-merge-3.pdl index 4170177e..beaab0ed 100644 --- a/src/test/tests/lockTests/lock-merge-3.pdl +++ b/src/test/tests/lockTests/lock-merge-3.pdl @@ -1,3 +1,4 @@ +// lock-merge-3.pdl pipe ex4(inarg: int<32>)[rf: int<32>[5](Queue)] :int<32> { start(rf); diff --git a/src/test/tests/lockTests/lock-merge-4.pdl b/src/test/tests/lockTests/lock-merge-4.pdl index bf990a07..0a4a6b7f 100644 --- a/src/test/tests/lockTests/lock-merge-4.pdl +++ b/src/test/tests/lockTests/lock-merge-4.pdl @@ -1,3 +1,4 @@ +// lock-merge-4.pdl pipe ex4(in: bool)[rf: int<32>[5](Queue)] :bool{ start(rf); uint<5> addr = u1<5>; diff --git a/src/test/tests/matpow/matpow.pdl b/src/test/tests/matpow/matpow.pdl index 84aeb432..d78d666d 100644 --- a/src/test/tests/matpow/matpow.pdl +++ b/src/test/tests/matpow/matpow.pdl @@ -1,3 +1,4 @@ +// matpow.pdl /* void matrix_power( inout_int_t x[20][20], in_int_t row[20], in_int_t col[20], in_int_t a[20] ) { diff --git a/src/test/tests/matpow/matpow_alt.pdl b/src/test/tests/matpow/matpow_alt.pdl index 03a229f5..08868a39 100644 --- a/src/test/tests/matpow/matpow_alt.pdl +++ b/src/test/tests/matpow/matpow_alt.pdl @@ -1,3 +1,4 @@ +// matpow_alt.pdl /* void matrix_power( inout_int_t x[20][20], in_int_t row[20], in_int_t col[20], in_int_t a[20] ) { diff --git a/src/test/tests/matpow/matpow_bram.pdl b/src/test/tests/matpow/matpow_bram.pdl index 1451992e..74e9ef69 100644 --- a/src/test/tests/matpow/matpow_bram.pdl +++ b/src/test/tests/matpow/matpow_bram.pdl @@ -1,3 +1,4 @@ +// matpow_bram.pdl /* void matrix_power( inout_int_t x[20][20], in_int_t row[20], in_int_t col[20], in_int_t a[20] ) { diff --git a/src/test/tests/multiExec/multiexec.pdl b/src/test/tests/multiExec/multiexec.pdl index 121dbfb2..279bd0ca 100644 --- a/src/test/tests/multiExec/multiexec.pdl +++ b/src/test/tests/multiExec/multiexec.pdl @@ -1,3 +1,4 @@ +// multiexec.pdl pipe multi_stg_mul(a1: int<32>, a2: int<32>)[]: int<32> { int<32> rr = a1{15:0} * a2{15:0}; int<32> rl = a1{15:0} * a2{31:16}; diff --git a/src/test/tests/multiExec/multiexec_alt.pdl b/src/test/tests/multiExec/multiexec_alt.pdl index 00e922bb..7e704e42 100644 --- a/src/test/tests/multiExec/multiexec_alt.pdl +++ b/src/test/tests/multiExec/multiexec_alt.pdl @@ -1,3 +1,4 @@ +// multiexec_alt.pdl pipe multi_stg_mul(a1: int<32>, a2: int<32>)[]: int<32> { int<32> rr = a1{15:0} * a2{15:0}; int<32> rl = a1{15:0} * a2{31:16}; diff --git a/src/test/tests/multiExec/multiexec_split.pdl b/src/test/tests/multiExec/multiexec_split.pdl index 92f19bd3..033484d8 100644 --- a/src/test/tests/multiExec/multiexec_split.pdl +++ b/src/test/tests/multiExec/multiexec_split.pdl @@ -1,3 +1,4 @@ +// multiexec_split.pdl pipe multi_stg_mul(a1: int<32>, a2: int<32>)[]: int<32> { int<32> rr = a1{15:0} * a2{15:0}; int<32> rl = a1{15:0} * a2{31:16}; diff --git a/src/test/tests/registerRenamingTests/3-stg-lsq.pdl b/src/test/tests/registerRenamingTests/3-stg-lsq.pdl index c98eb772..5c76638e 100644 --- a/src/test/tests/registerRenamingTests/3-stg-lsq.pdl +++ b/src/test/tests/registerRenamingTests/3-stg-lsq.pdl @@ -1,3 +1,4 @@ +// 3-stg-lsq.pdl pipe test(pc: uint<32>)[rf: int<32>[5](LSQ)]: bool { uint<5> rs1 = pc{4:0}; uint<5> rd = rs1 - u1<5>; diff --git a/src/test/tests/registerRenamingTests/3-stg-pipe.pdl b/src/test/tests/registerRenamingTests/3-stg-pipe.pdl index f161733e..b6694f17 100644 --- a/src/test/tests/registerRenamingTests/3-stg-pipe.pdl +++ b/src/test/tests/registerRenamingTests/3-stg-pipe.pdl @@ -1,3 +1,4 @@ +// 3-stg-pipe.pdl pipe test(pc: uint<32>)[rf: int<32>[5](RenameRF)]: bool { uint<5> rs1 = pc{4:0}; uint<5> rd = rs1 - u1<5>; diff --git a/src/test/tests/registerRenamingTests/lock-wrong-type-nested-fail.pdl b/src/test/tests/registerRenamingTests/lock-wrong-type-nested-fail.pdl index ea82bfa6..37cf0f40 100644 --- a/src/test/tests/registerRenamingTests/lock-wrong-type-nested-fail.pdl +++ b/src/test/tests/registerRenamingTests/lock-wrong-type-nested-fail.pdl @@ -1,3 +1,4 @@ +// lock-wrong-type-nested-fail.pdl pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; uint<5> rs2 = input{5:9}; diff --git a/src/test/tests/registerRenamingTests/lock-wrong-type-read-write-fail.pdl b/src/test/tests/registerRenamingTests/lock-wrong-type-read-write-fail.pdl index 6cef0698..f4553c21 100644 --- a/src/test/tests/registerRenamingTests/lock-wrong-type-read-write-fail.pdl +++ b/src/test/tests/registerRenamingTests/lock-wrong-type-read-write-fail.pdl @@ -1,3 +1,4 @@ +// lock-wrong-type-read-write-fail.pdl pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; uint<5> rs2 = input{5:9}; diff --git a/src/test/tests/registerRenamingTests/lock-wrong-type-write-read-fail.pdl b/src/test/tests/registerRenamingTests/lock-wrong-type-write-read-fail.pdl index 96053a53..1c560e4a 100644 --- a/src/test/tests/registerRenamingTests/lock-wrong-type-write-read-fail.pdl +++ b/src/test/tests/registerRenamingTests/lock-wrong-type-write-read-fail.pdl @@ -1,3 +1,4 @@ +// lock-wrong-type-write-read-fail.pdl pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; uint<5> rs2 = input{5:9}; diff --git a/src/test/tests/registerRenamingTests/validLockTypes.pdl b/src/test/tests/registerRenamingTests/validLockTypes.pdl index d7fe0a74..d77784c8 100644 --- a/src/test/tests/registerRenamingTests/validLockTypes.pdl +++ b/src/test/tests/registerRenamingTests/validLockTypes.pdl @@ -1,3 +1,4 @@ +// validLockTypes.pdl //Expected Success pipe test1(tinput: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = tinput{4:0}; diff --git a/src/test/tests/risc-pipe/risc-pipe-3stg.pdl b/src/test/tests/risc-pipe/risc-pipe-3stg.pdl index 342278f0..34c63164 100644 --- a/src/test/tests/risc-pipe/risc-pipe-3stg.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-3stg.pdl @@ -1,3 +1,4 @@ +// risc-pipe-3stg.pdl def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { uint<32> mag1 = cast(mag(arg1), uint<32>); uint<32> mag2 = cast(mag(arg2), uint<32>); diff --git a/src/test/tests/risc-pipe/risc-pipe-cache.pdl b/src/test/tests/risc-pipe/risc-pipe-cache.pdl index a8628f55..3cc26c96 100644 --- a/src/test/tests/risc-pipe/risc-pipe-cache.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-cache.pdl @@ -1,3 +1,4 @@ +// risc-pipe-cache.pdl def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { uint<5> shamt = cast(arg2{4:0}, uint<5>); if (op == u0<3>) { //000 == ADD , flip == sub diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-bypass-bht.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-bypass-bht.pdl index 48973476..b05c2039 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-bypass-bht.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-bypass-bht.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec-bypass-bht.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl new file mode 100644 index 00000000..4e34a1fb --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl @@ -0,0 +1,488 @@ +// risc-pipe-spec-write.pdl +extern BHT { + method req(pc: int, skip: int, take: int): int; + method upd(pc: int, taken: bool): (); +} + +// hardware interrupt controller +extern TimingInterruptController { + method req(pc: int): bool; + method ack(pc: int): (); +} + +def csr_map(csrAddr: uint<12>): uint<5> { + if (csrAddr == 0x300) { //mstatus: Machine status register + return u0<5>; + } else{ + if (csrAddr == 0x301) { //misa: ISA and extensions + return u1<5>; + } else{ + if (csrAddr == 0x302) { //medeleg: Machine exception delegation register + return u2<5>; + } else{ + if (csrAddr == 0x303) { //mideleg: Machine interrupt delegation register + return u3<5>; + } else{ + if (csrAddr == 0x304) { //mie: Machine interrupt-enable register + return u4<5>; + } else{ + if (csrAddr == 0x305) { //mtvec: Machine trap-handler base address + return u5<5>; + } else{ + if (csrAddr == 0x340) { //mscratch: Scratch register for machine trap handlers + return u6<5>; + } else{ + if (csrAddr == 0x341) { //mepc: Machine exception program counter + return u7<5>; + } else{ + if (csrAddr == 0x342) { //mcause: Machine trap cause + return u8<5>; + } else{ + if (csrAddr == 0x343) { //mtval: Machine bad address or instruction + return u9<5>; + } else{ + if (csrAddr == 0x344) { //mip: Machine interrupt pending + return u10<5>; + } else{ + if (csrAddr == 0x34A) { //mtinst: Machine trap instruction (transformed) + return u11<5>; + } else{ + return u31<5>;}}}}}}}}}}}} +} + +def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { + uint<32> mag1 = cast(mag(arg1), uint<32>); + uint<32> mag2 = cast(mag(arg2), uint<32>); + //MULHU => positive sign always + int<32> s1 = (op == u3<3>) ? 1<32> : sign(arg1); + //MULHU/MULHSU => positive sign always + int<32> s2 = (op >= u2<3>) ? 1<32> : sign(arg2); + int<64> magRes = cast((mag1 * mag2), int<64>); + int<64> m = (s1 == s2) ? (magRes) : -(magRes); + if (op == u0<3>) { //MUL + return m{31:0}; + } else { + return m{63:32}; + } +} + +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + if (op == u0<3>) { //BEQ + return (arg1 == arg2); + } else { + if (op == u1<3>) { //BNE + return (arg1 != arg2); + } else { + if (op == u4<3>) { //BLT + return (arg1 < arg2); + } else { + if (op == u5<3>) { //BGE + return (arg1 >= arg2); + } else { + if (op == u6<3>) { //BLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2); + } else { + if (op == u7<3>) { //BGEU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return(un1 >= un2); + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32>, cnt: uint<5>, retQuot: bool)[]: uint<32> { + uint<32> tmp = acc{30:0} ++ num{31:31}; + uint<32> na = (tmp >= denom) ? (tmp - denom) : (tmp); + uint<32> nq = (tmp >= denom) ? ((quot << 1){31:1} ++ u1<1>) : (quot << 1); + uint<32> nnum = num << 1; + bool done = (cnt == u31<5>); + if (done) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); + } +} + +// 0 is U-Mode, 3 is M-mode +// exn-pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), csrf: int<32>[5], imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT, irc: TimingInterruptController, acc: uint<4>[0](CheckpointQueue)]: bool { +exn-pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), csrf: int<32>[5], imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT, acc: uint<4>[0](CheckpointQueue)]: bool { + spec_check(); + start(imem); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + end(imem); + //print("PC %d -> Stg 0", pc); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + spec_check(); + bool done = insn == 0x0000006f<32>; + //print("PC %d -> Stg 1, insn %h, done? %b", pc, insn, done); + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + uint<12> csrAddr = cast(insn{31:20}, uint<12>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isCsr = opcode == 0b1110011<7>; + bool isSystem = opcode == 0b1110011<7>; + bool isCsrrw = isCsr && (funct3 == u1<3>); + bool isCsrrs = isCsr && (funct3 == u2<3>); + bool isCsrrc = isCsr && (funct3 == u3<3>); + bool isEcall = isSystem && (immI == 0<32>); + bool isEbreak = isSystem && (immI == 1<32>); + bool isMret = isSystem && (funct7 == u24<7>) && (rs2 == u2<5>); + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool isMul = isMDiv && (funct3 < u4<3>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui || isCsrrw); + // if (isCsr){ + // acquire(csrlock); + // } else { + // wait(csrlock); + // } + //print("PC %d -> Stg 2, insn %h, done? %b", pc, insn, done); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if (!done) { + if (notBranch) { + s2 <- s; + } else { + if (isBranch) { + s2 <- update(s, bht.req(pc, immB, 1<16>)); + } else { + s2 <- s; + invalidate(s); + }}} else { s2 <- s; invalidate(s); } + if (isEcall){ + throw(false, u8<4>); + } + if (isMret){ + throw(false, u3<4>); + } + start(rf); + if (!done && (notBranch || isBranch)) { checkpoint(rf); } + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); +// uint<5> ridx = csr_map(csrAddr); +// uint<5> widx = csr_map(csrAddr); + --- + //print("PC %d -> Stg 2", pc); + spec_check(); +// if(isCsrrs){ +// int<32> oldCsrVal = csrf[ridx]; +// } + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); // Read locks doesn't matter + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + bool take = br(funct3, rf1, rf2); + if (isBranch) { + //divide by 4 b/c we count instructions not bytes + int<16> offpc = pc + (immB >> 2); + int<16> npc = (take) ? (offpc) : (pc + 1<16>); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + int<32> alu_arg1 = (isAui) ? ((0<16> ++ pc) << 2) : rf1; + int<32> alu_arg2 = (isAui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : rf2)); + bool alu_flip = (isStore || isLoad || isAui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<16> tmppc = pc + 1<16>; + int<32> linkpc = 0<16> ++ (tmppc << 2); + int<32> mulres = mul(rf1, rf2, funct3); + if (writerd && (!isLoad) && (!isDiv)) { + block(rf[rd]); + int<32> rddata = (isLui) ? immU : ((isMul) ? mulres : ((isJal || isJalr) ? linkpc : alu_res)); + rf[rd] <- rddata; + } else { + int<32> rddata = 0<32>; + } + --- + //print("PC %d -> Stg 3", pc); + spec_barrier(); //delayed just to force writes to happen speculatively + if (!done) { + if (!notBranch) { + if (isBranch) { + verify(s2, npc) { bht.upd(pc, take) }; + } else { + call cpu(npc); + } + } else { + verify(s, pc + 1<16>); + } + } + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + bool invertRes <- isSignedDiv && (sdividend != sdivisor); + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } else { + bool invertRes <- false; + uint<32> udivout <- u0<32>; + } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + //print("PC %d -> Stg 4", pc); + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + if (isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + if (isDiv) { + block(rf[rd]); + int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + int<32> insnout = divout; + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + }} + print("Writing %d to r%d", insnout, rd); + } +// if (isCsrrw) { +// csrf[widx] <- rf1; +// } + + // print("reaching pre-commit stage for pc %d", pc); + // print(irc.req(pc)); + // catch(irc){throw(true, u1<4>)}; + // This gets expanded to: + + // bool is_interrupt = irc.req(pc); + // if (is_interrupt) { + // throw(true, exncode); + // irc.ack(pc); + // } + // Can change return value of req to be exncode +--- +commit: +// release(acc); + if (writerd) { + release(rf[rd]); + //print("written to rd %d at pc %d", rd, pc); + } + // print("Committing PC == %d", pc); +// if(isCsr){ +// release(csrlock); +// } + if (done) { output(true); } +except(interrupt: bool, exncode: uint<4>): + // mem.abort + // spec.abort + // fifos.abort + // IF - DC - EX - if(!exceptional) Commit - if(exceptional) Except + print("exception at PC == %d! with exncode: %d", pc, exncode); + --- + start(csrf); + if (!interrupt && exncode == u8<4>){ // 8 is ecall + uint<5> rdidx = u5<5>; // 5 is mtvec + print("ECALL"); + } else { + if (!interrupt && exncode == u3<4>){ // 3 is mret + uint<5> rdidx = u7<5>; // 7 is mepc + print("MRET"); + } else { + if (interrupt) {uint<5> rdidx = u7<5>;} + uint<5> rdidx = u0<5>; // undefined + }} + int<32> csrret = csrf[rdidx]; + int<16> tmppc = csrret{15:0}; + if (exncode == u8<4>){ + int<16> npc = tmppc; // Goto handler address + } else { + if (exncode == u3<4>){ + int<16> npc = tmppc + 1<16>; // Goto exceptional instruction address + } else { + int<16> npc = pc + 1<16>; + } + } + --- + uint<5> mepcidx = u7<5>; // 7 is mepc + csrf[mepcidx] <- cast(pc, int<32>); //write pc to mpec + --- + uint<5> mcauseidx = u8<5>; // 8 is mcause + csrf[mcauseidx] <- cast(exncode, int<32>); //write pc to mpec + end(csrf); + --- + print("GOTO PC: %d", npc); + call cpu(npc); +} + +circuit { + ti = memory(int<32>, 16); + td = memory(int<32>, 16); + rf = rflock CheckpointRF(int<32>, 5, 64); + csrf = regfile(int<32>, 5); + acc = register(uint<4>, 0); + locked = CheckpointQueue(acc); + div = new multi_stg_div[]; + b = new BHT<16>[](4); + //irc = new TimingInterruptController<16>[](); + //c = new cpu[rf, csrf, ti, td, div, b, irc, locked]; + c = new cpu[rf, csrf, ti, td, div, b, locked]; + + call c(0<16>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-rename-bht.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-rename-bht.pdl index a0ad485d..e33e6632 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-rename-bht.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-rename-bht.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec-rename-bht.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-rename-ooo-infer.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-rename-ooo-infer.pdl index 1d8e6bb2..b549446d 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-rename-ooo-infer.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-rename-ooo-infer.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec-rename-ooo-infer.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-rename-ooo.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-rename-ooo.pdl index d928bafa..8f3b8161 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-rename-ooo.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-rename-ooo.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec-rename-ooo.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-write-2.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-write-2.pdl index bccf398b..4b746f89 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-write-2.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-write-2.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec-write-2.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-write-infer.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-write-infer.pdl index 4cb07645..dc833643 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-write-infer.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-write-infer.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec-write-infer.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl index c36b366b..4a8641b4 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec-write.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/risc-pipe/risc-pipe-spec.pdl b/src/test/tests/risc-pipe/risc-pipe-spec.pdl index 35cb0d82..e81748e8 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec.pdl def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { uint<32> mag1 = cast(mag(arg1), uint<32>); uint<32> mag2 = cast(mag(arg2), uint<32>); @@ -233,7 +234,7 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](FAQueue), imem: int<32>[16](Queu } --- split { - case: (isLui) { + case: (isLui) { int<32> alu_res = immU; } case: (isAui) { @@ -252,7 +253,7 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](FAQueue), imem: int<32>[16](Queu } } split { - case: (isStore) { + case: (isStore) { //addresses also are word-sized int<32> tmp = immS + rf1; uint<32> ctmp = cast(tmp, uint<32>); @@ -269,7 +270,7 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](FAQueue), imem: int<32>[16](Queu default: { uint<16> memaddr = u0<16>; uint<2> boff = u0<2>; - } + } } --- start(dmem); diff --git a/src/test/tests/risc-pipe/risc-pipe.pdl b/src/test/tests/risc-pipe/risc-pipe.pdl index 79e37636..09c3e84a 100644 --- a/src/test/tests/risc-pipe/risc-pipe.pdl +++ b/src/test/tests/risc-pipe/risc-pipe.pdl @@ -1,3 +1,4 @@ +// risc-pipe.pdl def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { uint<32> mag1 = cast(mag(arg1), uint<32>); uint<32> mag2 = cast(mag(arg2), uint<32>); diff --git a/src/test/tests/risc-pipe/solutions/risc-pipe-spec-exn.typechecksol b/src/test/tests/risc-pipe/solutions/risc-pipe-spec-exn.typechecksol new file mode 100644 index 00000000..9fb4ec93 --- /dev/null +++ b/src/test/tests/risc-pipe/solutions/risc-pipe-spec-exn.typechecksol @@ -0,0 +1 @@ +Passed \ No newline at end of file diff --git a/src/test/tests/simtests/unlocked-reg.pdl b/src/test/tests/simtests/unlocked-reg.pdl index c9e3cdcb..65193fcf 100644 --- a/src/test/tests/simtests/unlocked-reg.pdl +++ b/src/test/tests/simtests/unlocked-reg.pdl @@ -1,3 +1,4 @@ +// unlocked-reg.pdl //Expected Success pipe unlock(tinput: int<32>)[rf: int<32>[0]]: bool { spec_check(); diff --git a/src/test/tests/speculation/3-stg-pipe-spec-2.pdl b/src/test/tests/speculation/3-stg-pipe-spec-2.pdl index 941ad62b..701265be 100644 --- a/src/test/tests/speculation/3-stg-pipe-spec-2.pdl +++ b/src/test/tests/speculation/3-stg-pipe-spec-2.pdl @@ -1,3 +1,4 @@ +// 3-stg-pipe-spec-2.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](RenameRF), imem: int<32>[8]]: bool { spec_check(); //nonblocking check start(imem); diff --git a/src/test/tests/speculation/3-stg-pipe-spec-3.pdl b/src/test/tests/speculation/3-stg-pipe-spec-3.pdl index 30d1d7bc..2e3b5de7 100644 --- a/src/test/tests/speculation/3-stg-pipe-spec-3.pdl +++ b/src/test/tests/speculation/3-stg-pipe-spec-3.pdl @@ -1,3 +1,4 @@ +// 3-stg-pipe-spec-3.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](FAQueue), imem: int<32>[8]]: bool { spec_check(); //nonblocking check start(imem); diff --git a/src/test/tests/speculation/3-stg-pipe-spec.pdl b/src/test/tests/speculation/3-stg-pipe-spec.pdl index 88166546..c43f5a65 100644 --- a/src/test/tests/speculation/3-stg-pipe-spec.pdl +++ b/src/test/tests/speculation/3-stg-pipe-spec.pdl @@ -1,3 +1,4 @@ +// 3-stg-pipe-spec.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](RenameRF), imem: int<32>[8]]: bool { spec_check(); //nonblocking check start(imem); diff --git a/src/test/tests/speculation/3-stg-pipe.pdl b/src/test/tests/speculation/3-stg-pipe.pdl index 87ed4ace..1945d315 100644 --- a/src/test/tests/speculation/3-stg-pipe.pdl +++ b/src/test/tests/speculation/3-stg-pipe.pdl @@ -1,3 +1,4 @@ +// 3-stg-pipe.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](RenameRF), imem: int<32>[8]]: bool { start(imem); int<32> insn <- imem[cast(pc, uint<8>)]; diff --git a/src/test/tests/speculation/bad-spec-1.pdl b/src/test/tests/speculation/bad-spec-1.pdl index fb3bd485..fca97ce6 100644 --- a/src/test/tests/speculation/bad-spec-1.pdl +++ b/src/test/tests/speculation/bad-spec-1.pdl @@ -1,3 +1,4 @@ +// bad-spec-1.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](RenameRF), imem: int<32>[8]]: bool { spec_check(); //nonblocking check start(imem); diff --git a/src/test/tests/speculation/bad-spec-2.pdl b/src/test/tests/speculation/bad-spec-2.pdl index 60b48359..6b35ac2e 100644 --- a/src/test/tests/speculation/bad-spec-2.pdl +++ b/src/test/tests/speculation/bad-spec-2.pdl @@ -1,3 +1,4 @@ +// bad-spec-2.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](RenameRF), imem: int<32>[8]]: bool { spec_check(); //nonblocking check start(imem); diff --git a/src/test/tests/speculation/bad-spec-3.pdl b/src/test/tests/speculation/bad-spec-3.pdl index ab482353..f095286d 100644 --- a/src/test/tests/speculation/bad-spec-3.pdl +++ b/src/test/tests/speculation/bad-spec-3.pdl @@ -1,3 +1,4 @@ +// bad-spec-3.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](RenameRF), imem: int<32>[8]]: bool { spec_check(); //nonblocking check start(imem); diff --git a/src/test/tests/speculation/bad-spec-4.pdl b/src/test/tests/speculation/bad-spec-4.pdl index fdf7485f..137cf73b 100644 --- a/src/test/tests/speculation/bad-spec-4.pdl +++ b/src/test/tests/speculation/bad-spec-4.pdl @@ -1,3 +1,4 @@ +// bad-spec-4.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](RenameRF), imem: int<32>[8]]: bool { //spec_check(); //nonblocking check //missing nonblocking check diff --git a/src/test/tests/speculation/bad-spec-5.pdl b/src/test/tests/speculation/bad-spec-5.pdl index d8020098..3547e3ae 100644 --- a/src/test/tests/speculation/bad-spec-5.pdl +++ b/src/test/tests/speculation/bad-spec-5.pdl @@ -1,3 +1,4 @@ +// bad-spec-5.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](RenameRF), imem: int<32>[8]]: bool { //spec_check(); //nonblocking check //missing nonblocking check diff --git a/src/test/tests/speculation/spec-write-2.pdl b/src/test/tests/speculation/spec-write-2.pdl index 9ac5d9da..4e66937a 100644 --- a/src/test/tests/speculation/spec-write-2.pdl +++ b/src/test/tests/speculation/spec-write-2.pdl @@ -1,3 +1,4 @@ +// spec-write-2.pdl pipe testwrite(pc: int<8>)[rf: int<32>[5](CheckpointQueue), imem: int<32>[8]]: bool { spec_check(); start(imem); diff --git a/src/test/tests/speculation/spec-write-fail.pdl b/src/test/tests/speculation/spec-write-fail.pdl index 54a79bdd..54d1c681 100644 --- a/src/test/tests/speculation/spec-write-fail.pdl +++ b/src/test/tests/speculation/spec-write-fail.pdl @@ -1,3 +1,4 @@ +// spec-write-fail.pdl pipe testwrite(pc: int<32>)[rf: int<32>[5](CheckpointQueue), imem: int<40>[8]]: bool { spec_check(); start(imem); diff --git a/src/test/tests/speculation/spec-write-fail2.pdl b/src/test/tests/speculation/spec-write-fail2.pdl index ebf9e812..721385c0 100644 --- a/src/test/tests/speculation/spec-write-fail2.pdl +++ b/src/test/tests/speculation/spec-write-fail2.pdl @@ -1,3 +1,4 @@ +// spec-write-fail2.pdl pipe testwrite(pc: int<32>)[rf: int<32>[5](CheckpointQueue), imem: int<40>[8]]: bool { spec_check(); start(imem); diff --git a/src/test/tests/speculation/spec-write-fail3.pdl b/src/test/tests/speculation/spec-write-fail3.pdl index 73a078eb..1aa38ca3 100644 --- a/src/test/tests/speculation/spec-write-fail3.pdl +++ b/src/test/tests/speculation/spec-write-fail3.pdl @@ -1,3 +1,4 @@ +// spec-write-fail3.pdl pipe testwrite(pc: int<32>)[rf: int<32>[5](CheckpointQueue), imem: int<40>[8]]: bool { spec_check(); start(imem); diff --git a/src/test/tests/speculation/spec-write-infer.pdl b/src/test/tests/speculation/spec-write-infer.pdl index ad5ce938..083b4aed 100644 --- a/src/test/tests/speculation/spec-write-infer.pdl +++ b/src/test/tests/speculation/spec-write-infer.pdl @@ -1,3 +1,4 @@ +// spec-write-infer.pdl pipe testwrite(pc: int<32>)[rf: int<32>[5](CheckpointQueue), imem: int<40>[8]]: bool { spec_check(); start(imem); diff --git a/src/test/tests/speculation/spec-write.pdl b/src/test/tests/speculation/spec-write.pdl index 20850641..a547a951 100644 --- a/src/test/tests/speculation/spec-write.pdl +++ b/src/test/tests/speculation/spec-write.pdl @@ -1,3 +1,4 @@ +// spec-write.pdl pipe testwrite(pc: int<32>)[rf: int<32>[5](CheckpointQueue), imem: int<40>[8]]: bool { spec_check(); start(imem); diff --git a/src/test/tests/speculation/unnecessary-checkpoint.pdl b/src/test/tests/speculation/unnecessary-checkpoint.pdl index 3785c6b9..5ddd9404 100644 --- a/src/test/tests/speculation/unnecessary-checkpoint.pdl +++ b/src/test/tests/speculation/unnecessary-checkpoint.pdl @@ -1,3 +1,4 @@ +// unnecessary-checkpoint.pdl pipe cpu(pc: int<8>)[rf: int<32>[5](CheckpointRF), imem: int<32>[8]]: bool { start(imem); int<32> insn <- imem[cast(pc, uint<8>)]; diff --git a/src/test/tests/typecheckTests/acquire-in-expr-fail.pdl b/src/test/tests/typecheckTests/acquire-in-expr-fail.pdl index fbcba745..b2f1d4b1 100644 --- a/src/test/tests/typecheckTests/acquire-in-expr-fail.pdl +++ b/src/test/tests/typecheckTests/acquire-in-expr-fail.pdl @@ -1,3 +1,4 @@ +// acquire-in-expr-fail.pdl //Expected Fail pipe test6(input: int<32>)[rf: int<32>[5]] { start(rf); diff --git a/src/test/tests/typecheckTests/acquire-in-expr.pdl b/src/test/tests/typecheckTests/acquire-in-expr.pdl index 9f900ac6..197b8e40 100644 --- a/src/test/tests/typecheckTests/acquire-in-expr.pdl +++ b/src/test/tests/typecheckTests/acquire-in-expr.pdl @@ -1,3 +1,4 @@ +// acquire-in-expr.pdl //Expected Success pipe test6(input: int<32>)[rf: int<32>[5](Queue)] { start(rf); diff --git a/src/test/tests/typecheckTests/boolean-mishap.pdl b/src/test/tests/typecheckTests/boolean-mishap.pdl index e357c28b..1e93a94d 100644 --- a/src/test/tests/typecheckTests/boolean-mishap.pdl +++ b/src/test/tests/typecheckTests/boolean-mishap.pdl @@ -1,3 +1,4 @@ +// boolean-mishap.pdl pipe mistake(input: int<32>)[rf: int<32>[5]] { bool a = input{0:0}; bool b = input{1:1}; diff --git a/src/test/tests/typecheckTests/double-call-fail.pdl b/src/test/tests/typecheckTests/double-call-fail.pdl index ef71f188..a6b73777 100644 --- a/src/test/tests/typecheckTests/double-call-fail.pdl +++ b/src/test/tests/typecheckTests/double-call-fail.pdl @@ -1,3 +1,4 @@ +// double-call-fail.pdl //cannot call twice in same pipe pipe call2(input: int<32>)[rf: int<32>[5]] { start(rf); diff --git a/src/test/tests/typecheckTests/double-call-guarded.pdl b/src/test/tests/typecheckTests/double-call-guarded.pdl index 2e3dba48..fb4fd46c 100644 --- a/src/test/tests/typecheckTests/double-call-guarded.pdl +++ b/src/test/tests/typecheckTests/double-call-guarded.pdl @@ -1,3 +1,4 @@ +// double-call-guarded.pdl pipe call_guard(input: int<32>)[rf: int<32>[5](Queue)] { start(rf); reserve(rf); diff --git a/src/test/tests/typecheckTests/exn-basic.pdl b/src/test/tests/typecheckTests/exn-basic.pdl index f6bd5b0f..11330731 100644 --- a/src/test/tests/typecheckTests/exn-basic.pdl +++ b/src/test/tests/typecheckTests/exn-basic.pdl @@ -1,3 +1,4 @@ +// exn-basic.pdl exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { reserve(acc); --- diff --git a/src/test/tests/typecheckTests/exn-no-end-after-call.pdl b/src/test/tests/typecheckTests/exn-no-end-after-call.pdl index 6d8243d0..cf01b48c 100644 --- a/src/test/tests/typecheckTests/exn-no-end-after-call.pdl +++ b/src/test/tests/typecheckTests/exn-no-end-after-call.pdl @@ -1,3 +1,4 @@ +// exn-no-end-after-call.pdl exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { reserve(acc); --- diff --git a/src/test/tests/typecheckTests/exn-no-release-main.pdl b/src/test/tests/typecheckTests/exn-no-release-main.pdl index dd63bb80..1dc7090d 100644 --- a/src/test/tests/typecheckTests/exn-no-release-main.pdl +++ b/src/test/tests/typecheckTests/exn-no-release-main.pdl @@ -1,3 +1,4 @@ +// exn-no-release-main.pdl exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { reserve(acc); --- diff --git a/src/test/tests/typecheckTests/exn-no-throw-commit.pdl b/src/test/tests/typecheckTests/exn-no-throw-commit.pdl index e7aa08d6..804b2641 100644 --- a/src/test/tests/typecheckTests/exn-no-throw-commit.pdl +++ b/src/test/tests/typecheckTests/exn-no-throw-commit.pdl @@ -1,3 +1,4 @@ +// exn-no-throw-commit.pdl exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { reserve(acc); --- diff --git a/src/test/tests/typecheckTests/exn-no-throw-except.pdl b/src/test/tests/typecheckTests/exn-no-throw-except.pdl index f4115bb4..38b9e0c2 100644 --- a/src/test/tests/typecheckTests/exn-no-throw-except.pdl +++ b/src/test/tests/typecheckTests/exn-no-throw-except.pdl @@ -1,3 +1,4 @@ +// exn-no-throw-except.pdl exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { reserve(acc); --- diff --git a/src/test/tests/typecheckTests/exn-no-throw-normal.pdl b/src/test/tests/typecheckTests/exn-no-throw-normal.pdl index 161111a1..a8ba6b14 100644 --- a/src/test/tests/typecheckTests/exn-no-throw-normal.pdl +++ b/src/test/tests/typecheckTests/exn-no-throw-normal.pdl @@ -1,3 +1,4 @@ +// exn-no-throw-normal.pdl pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue)] :uint<4> { reserve(acc); --- diff --git a/src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl b/src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl index 5d660687..757be875 100644 --- a/src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl +++ b/src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl @@ -1,3 +1,4 @@ +// exn-no-unlocked-write-main.pdl exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](Queue), oth :uint<4>[0](Queue), abc :uint<8>[16] ] :uint<4> { start(abc); abc[pc] <- 4; diff --git a/src/test/tests/typecheckTests/extern-synch-fail.pdl b/src/test/tests/typecheckTests/extern-synch-fail.pdl index 7c71407d..096c4b8a 100644 --- a/src/test/tests/typecheckTests/extern-synch-fail.pdl +++ b/src/test/tests/typecheckTests/extern-synch-fail.pdl @@ -1,3 +1,4 @@ +// extern-synch-fail.pdl extern myExt { method mySyncMethod(a :int<32>) :int<32>; method myCombMethod(a :int<32>) :int<32>; diff --git a/src/test/tests/typecheckTests/extern_pass.pdl b/src/test/tests/typecheckTests/extern_pass.pdl index d4238c42..8a55d636 100644 --- a/src/test/tests/typecheckTests/extern_pass.pdl +++ b/src/test/tests/typecheckTests/extern_pass.pdl @@ -1,3 +1,4 @@ +// extern_pass.pdl extern myExt { method mySyncMethod(a :int<32>) :int<32>; method myCombMethod(a :int<32>) :int<32>; diff --git a/src/test/tests/typecheckTests/generic-bht-fail.pdl b/src/test/tests/typecheckTests/generic-bht-fail.pdl index 7d5b7e34..597f9c84 100644 --- a/src/test/tests/typecheckTests/generic-bht-fail.pdl +++ b/src/test/tests/typecheckTests/generic-bht-fail.pdl @@ -1,3 +1,4 @@ +// generic-bht-fail.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/typecheckTests/generic-bht.pdl b/src/test/tests/typecheckTests/generic-bht.pdl index a0ad485d..d107bdb8 100644 --- a/src/test/tests/typecheckTests/generic-bht.pdl +++ b/src/test/tests/typecheckTests/generic-bht.pdl @@ -1,3 +1,4 @@ +// generic-bht.pdl extern BHT { method req(pc: int, skip: int, take: int): int; method upd(pc: int, taken: bool): (); diff --git a/src/test/tests/typecheckTests/generic_adder.pdl b/src/test/tests/typecheckTests/generic_adder.pdl index 9c60fce5..b3e69f88 100644 --- a/src/test/tests/typecheckTests/generic_adder.pdl +++ b/src/test/tests/typecheckTests/generic_adder.pdl @@ -1,3 +1,4 @@ +// generic_adder.pdl def adder(x :int, y :int) :int { return x + y; diff --git a/src/test/tests/typecheckTests/generic_adder_unsigned.pdl b/src/test/tests/typecheckTests/generic_adder_unsigned.pdl index f9dec48d..a229e258 100644 --- a/src/test/tests/typecheckTests/generic_adder_unsigned.pdl +++ b/src/test/tests/typecheckTests/generic_adder_unsigned.pdl @@ -1,3 +1,4 @@ +// generic_adder_unsigned.pdl def adder(x :uint, y :uint) :int { return cast(x + y, int); diff --git a/src/test/tests/typecheckTests/generic_func_fail.pdl b/src/test/tests/typecheckTests/generic_func_fail.pdl index cd562211..3e399db8 100644 --- a/src/test/tests/typecheckTests/generic_func_fail.pdl +++ b/src/test/tests/typecheckTests/generic_func_fail.pdl @@ -1,3 +1,4 @@ +// generic_func_fail.pdl def indexing(x :int, y :int) :int<6> { return x{J - 1:0}; diff --git a/src/test/tests/typecheckTests/generic_funcs_pass.pdl b/src/test/tests/typecheckTests/generic_funcs_pass.pdl index 9daaae43..a79f2930 100644 --- a/src/test/tests/typecheckTests/generic_funcs_pass.pdl +++ b/src/test/tests/typecheckTests/generic_funcs_pass.pdl @@ -1,3 +1,4 @@ +// generic_funcs_pass.pdl def fixed_1(inpt :int<10>) :bool { shamt = cast(inpt{4:0}, uint<5>); diff --git a/src/test/tests/typecheckTests/generic_funcs_passz3.pdl b/src/test/tests/typecheckTests/generic_funcs_passz3.pdl index e33594cc..d8271fd3 100644 --- a/src/test/tests/typecheckTests/generic_funcs_passz3.pdl +++ b/src/test/tests/typecheckTests/generic_funcs_passz3.pdl @@ -1,3 +1,4 @@ +// generic_funcs_passz3.pdl def extract(inpt :uint<32>) :bool { diff --git a/src/test/tests/typecheckTests/generic_unify_fail.pdl b/src/test/tests/typecheckTests/generic_unify_fail.pdl index 26abcd7a..4858a1db 100644 --- a/src/test/tests/typecheckTests/generic_unify_fail.pdl +++ b/src/test/tests/typecheckTests/generic_unify_fail.pdl @@ -1,3 +1,4 @@ +// generic_unify_fail.pdl def adder(x :int, y :int) :int { return x + y; diff --git a/src/test/tests/typecheckTests/input-smt-fail.pdl b/src/test/tests/typecheckTests/input-smt-fail.pdl index f9db0238..a5271630 100644 --- a/src/test/tests/typecheckTests/input-smt-fail.pdl +++ b/src/test/tests/typecheckTests/input-smt-fail.pdl @@ -1,3 +1,4 @@ +// input-smt-fail.pdl pipe should_fail(input : int<32>)[] { if(input{1:1} == 1) diff --git a/src/test/tests/typecheckTests/lock-acquire-in-split-case.pdl b/src/test/tests/typecheckTests/lock-acquire-in-split-case.pdl index 06e2edb4..5a7e7c03 100644 --- a/src/test/tests/typecheckTests/lock-acquire-in-split-case.pdl +++ b/src/test/tests/typecheckTests/lock-acquire-in-split-case.pdl @@ -1,3 +1,4 @@ +// lock-acquire-in-split-case.pdl pipe test22(input: uint<32>, randomBool: bool, randomBool2: bool)[rf: int<32>[5](Queue)] { start(rf); split { diff --git a/src/test/tests/typecheckTests/lock-fail-acquire-before-access.pdl b/src/test/tests/typecheckTests/lock-fail-acquire-before-access.pdl index c9072d52..36379eec 100644 --- a/src/test/tests/typecheckTests/lock-fail-acquire-before-access.pdl +++ b/src/test/tests/typecheckTests/lock-fail-acquire-before-access.pdl @@ -1,3 +1,4 @@ +// lock-fail-acquire-before-access.pdl pipe test6(input: uint<32>)[rf: int<32>[5]] { start(rf); diff --git a/src/test/tests/typecheckTests/lock-fail-branch-acquire.pdl b/src/test/tests/typecheckTests/lock-fail-branch-acquire.pdl index 16542ffe..b570f116 100644 --- a/src/test/tests/typecheckTests/lock-fail-branch-acquire.pdl +++ b/src/test/tests/typecheckTests/lock-fail-branch-acquire.pdl @@ -1,3 +1,4 @@ +// lock-fail-branch-acquire.pdl pipe test1(input: int<32>)[rf: int<32>[5]] { start(rf); if (input{0:0} == 1) { diff --git a/src/test/tests/typecheckTests/lock-fail-branch-release.pdl b/src/test/tests/typecheckTests/lock-fail-branch-release.pdl index d101186f..29c69364 100644 --- a/src/test/tests/typecheckTests/lock-fail-branch-release.pdl +++ b/src/test/tests/typecheckTests/lock-fail-branch-release.pdl @@ -1,3 +1,4 @@ +// lock-fail-branch-release.pdl pipe test3(input: int<32>)[rf: int<32>[5]] { start(rf); acquire(rf); diff --git a/src/test/tests/typecheckTests/lock-fail-double-write.pdl b/src/test/tests/typecheckTests/lock-fail-double-write.pdl index 8f506d7a..37f9cc44 100644 --- a/src/test/tests/typecheckTests/lock-fail-double-write.pdl +++ b/src/test/tests/typecheckTests/lock-fail-double-write.pdl @@ -1,3 +1,4 @@ +// lock-fail-double-write.pdl pipe test3(input: uint<32>)[rf: int<32>[5], m:int<32>[5]] { uint<5> rs1 = input{0:4}; uint<5> rs2 = input{5:9}; diff --git a/src/test/tests/typecheckTests/lock-fail-no-acquire-before-release.pdl b/src/test/tests/typecheckTests/lock-fail-no-acquire-before-release.pdl index d3775348..e2b45ce8 100644 --- a/src/test/tests/typecheckTests/lock-fail-no-acquire-before-release.pdl +++ b/src/test/tests/typecheckTests/lock-fail-no-acquire-before-release.pdl @@ -1,3 +1,4 @@ +// lock-fail-no-acquire-before-release.pdl pipe test7(input: int<32>)[rf: int<32>[5]] { start(rf); diff --git a/src/test/tests/typecheckTests/lock-fail-no-acquire-in-split-case.pdl b/src/test/tests/typecheckTests/lock-fail-no-acquire-in-split-case.pdl index 053ddd4f..d9ab1a2d 100644 --- a/src/test/tests/typecheckTests/lock-fail-no-acquire-in-split-case.pdl +++ b/src/test/tests/typecheckTests/lock-fail-no-acquire-in-split-case.pdl @@ -1,3 +1,4 @@ +// lock-fail-no-acquire-in-split-case.pdl pipe test22(input: int<32>, randomBool: bool, randomBool2: bool)[rf: int<32>[5]] { start(rf); split { diff --git a/src/test/tests/typecheckTests/lock-fail-no-default-acquire-split.pdl b/src/test/tests/typecheckTests/lock-fail-no-default-acquire-split.pdl index 84cb835e..adcaa388 100644 --- a/src/test/tests/typecheckTests/lock-fail-no-default-acquire-split.pdl +++ b/src/test/tests/typecheckTests/lock-fail-no-default-acquire-split.pdl @@ -1,3 +1,4 @@ +// lock-fail-no-default-acquire-split.pdl pipe test21(input: int<32>, randomBool: bool, randomBool2: bool)[rf: int<32>[5]] { start(rf); split { diff --git a/src/test/tests/typecheckTests/lock-fail-read-after-writes-branch.pdl b/src/test/tests/typecheckTests/lock-fail-read-after-writes-branch.pdl index b9bb0746..02e6252b 100644 --- a/src/test/tests/typecheckTests/lock-fail-read-after-writes-branch.pdl +++ b/src/test/tests/typecheckTests/lock-fail-read-after-writes-branch.pdl @@ -1,3 +1,4 @@ +// lock-fail-read-after-writes-branch.pdl //Expected Fail pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-fail-read-after-writes-release.pdl b/src/test/tests/typecheckTests/lock-fail-read-after-writes-release.pdl index b9bb0746..fa654cd8 100644 --- a/src/test/tests/typecheckTests/lock-fail-read-after-writes-release.pdl +++ b/src/test/tests/typecheckTests/lock-fail-read-after-writes-release.pdl @@ -1,3 +1,4 @@ +// lock-fail-read-after-writes-release.pdl //Expected Fail pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-fail-reads-after-writes.pdl b/src/test/tests/typecheckTests/lock-fail-reads-after-writes.pdl index 6e2b7354..5f38657d 100644 --- a/src/test/tests/typecheckTests/lock-fail-reads-after-writes.pdl +++ b/src/test/tests/typecheckTests/lock-fail-reads-after-writes.pdl @@ -1,3 +1,4 @@ +// lock-fail-reads-after-writes.pdl //Expected Fail pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-fail-reserve-without-write.pdl b/src/test/tests/typecheckTests/lock-fail-reserve-without-write.pdl index fd00b84d..b3db7255 100644 --- a/src/test/tests/typecheckTests/lock-fail-reserve-without-write.pdl +++ b/src/test/tests/typecheckTests/lock-fail-reserve-without-write.pdl @@ -1,3 +1,4 @@ +// lock-fail-reserve-without-write.pdl //Expected Success pipe test3(input: uint<32>)[rf: int<32>[5], m:int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-fail-top-branch.pdl b/src/test/tests/typecheckTests/lock-fail-top-branch.pdl index b807b76b..e3671f83 100644 --- a/src/test/tests/typecheckTests/lock-fail-top-branch.pdl +++ b/src/test/tests/typecheckTests/lock-fail-top-branch.pdl @@ -1,3 +1,4 @@ +// lock-fail-top-branch.pdl pipe test16(input: int<32>)[rf: int<32>[5]] { int<32> y = 3<32>; diff --git a/src/test/tests/typecheckTests/lock-fail-wrong-branch-acquire.pdl b/src/test/tests/typecheckTests/lock-fail-wrong-branch-acquire.pdl index e5dbfe42..669c7685 100644 --- a/src/test/tests/typecheckTests/lock-fail-wrong-branch-acquire.pdl +++ b/src/test/tests/typecheckTests/lock-fail-wrong-branch-acquire.pdl @@ -1,3 +1,4 @@ +// lock-fail-wrong-branch-acquire.pdl pipe test18(input: int<32>, randomBool: bool, randomBool2: bool)[rf: int<32>[5]] { bool a = true; bool b = false; diff --git a/src/test/tests/typecheckTests/lock-release-OOO-different-address-fail.pdl b/src/test/tests/typecheckTests/lock-release-OOO-different-address-fail.pdl index e3bb00ef..e1e91255 100644 --- a/src/test/tests/typecheckTests/lock-release-OOO-different-address-fail.pdl +++ b/src/test/tests/typecheckTests/lock-release-OOO-different-address-fail.pdl @@ -1,3 +1,4 @@ +// lock-release-OOO-different-address-fail.pdl //Expected Fail pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-release-OOO-fail.pdl b/src/test/tests/typecheckTests/lock-release-OOO-fail.pdl index 955f981a..311df403 100644 --- a/src/test/tests/typecheckTests/lock-release-OOO-fail.pdl +++ b/src/test/tests/typecheckTests/lock-release-OOO-fail.pdl @@ -1,3 +1,4 @@ +// lock-release-OOO-fail.pdl //Expected Fail pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-release-OOO-nested-branches-fail.pdl b/src/test/tests/typecheckTests/lock-release-OOO-nested-branches-fail.pdl index d4a17165..1ab2c657 100644 --- a/src/test/tests/typecheckTests/lock-release-OOO-nested-branches-fail.pdl +++ b/src/test/tests/typecheckTests/lock-release-OOO-nested-branches-fail.pdl @@ -1,3 +1,4 @@ +// lock-release-OOO-nested-branches-fail.pdl //Expected Fail pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-release-OOO-nested-if-fail.pdl b/src/test/tests/typecheckTests/lock-release-OOO-nested-if-fail.pdl index 23002833..e70f816b 100644 --- a/src/test/tests/typecheckTests/lock-release-OOO-nested-if-fail.pdl +++ b/src/test/tests/typecheckTests/lock-release-OOO-nested-if-fail.pdl @@ -1,3 +1,4 @@ +// lock-release-OOO-nested-if-fail.pdl //Expected Fail pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-release-OOO-split-fail.pdl b/src/test/tests/typecheckTests/lock-release-OOO-split-fail.pdl index dc2a0c1a..5812166e 100644 --- a/src/test/tests/typecheckTests/lock-release-OOO-split-fail.pdl +++ b/src/test/tests/typecheckTests/lock-release-OOO-split-fail.pdl @@ -1,3 +1,4 @@ +// lock-release-OOO-split-fail.pdl //Expected Fail pipe test3(input: uint<32>)[rf: int<32>[5]] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-success-read-write-order.pdl b/src/test/tests/typecheckTests/lock-success-read-write-order.pdl index 1295499b..15a4015e 100644 --- a/src/test/tests/typecheckTests/lock-success-read-write-order.pdl +++ b/src/test/tests/typecheckTests/lock-success-read-write-order.pdl @@ -1,3 +1,4 @@ +// lock-success-read-write-order.pdl //Expected Success pipe test3(input: uint<32>)[rf: int<32>[5](RenameRF), m:int<32>[5](RenameRF)] { uint<5> rs1 = input{4:0}; diff --git a/src/test/tests/typecheckTests/lock-tests-general.pdl b/src/test/tests/typecheckTests/lock-tests-general.pdl index 29fb707c..25fd3649 100644 --- a/src/test/tests/typecheckTests/lock-tests-general.pdl +++ b/src/test/tests/typecheckTests/lock-tests-general.pdl @@ -1,3 +1,4 @@ +// lock-tests-general.pdl // Expected Success pipe test2(input: int<32>)[rf: int<32>[5](Queue)] { start(rf); diff --git a/src/test/tests/typecheckTests/lock-tests-specific.pdl b/src/test/tests/typecheckTests/lock-tests-specific.pdl index bb57a4e3..291a863e 100644 --- a/src/test/tests/typecheckTests/lock-tests-specific.pdl +++ b/src/test/tests/typecheckTests/lock-tests-specific.pdl @@ -1,3 +1,4 @@ +// lock-tests-specific.pdl //Expected Success pipe test1(input: uint<32>)[rf: int<32>[5](Queue)] { uint<5> rs1 = input{0:4}; diff --git a/src/test/tests/typecheckTests/lock-wellformedness-fail.pdl b/src/test/tests/typecheckTests/lock-wellformedness-fail.pdl index 0c4980e3..e78a18ac 100644 --- a/src/test/tests/typecheckTests/lock-wellformedness-fail.pdl +++ b/src/test/tests/typecheckTests/lock-wellformedness-fail.pdl @@ -1,3 +1,4 @@ +// lock-wellformedness-fail.pdl pipe test1(input: uint<32>)[rf: int<32>[5]] { uint<5> rs2 = input{13:9}; if (input{0:0} == u1) { diff --git a/src/test/tests/typecheckTests/missing-one-fail.pdl b/src/test/tests/typecheckTests/missing-one-fail.pdl index 9ca9b1dd..fc03bda7 100644 --- a/src/test/tests/typecheckTests/missing-one-fail.pdl +++ b/src/test/tests/typecheckTests/missing-one-fail.pdl @@ -1,3 +1,4 @@ +// missing-one-fail.pdl pipe quad_call(input: int<32>)[rf: int<32>[5]] { bool a = input{0:0}; diff --git a/src/test/tests/typecheckTests/more_generic_tests.pdl b/src/test/tests/typecheckTests/more_generic_tests.pdl index ec97f65b..c352c9bf 100644 --- a/src/test/tests/typecheckTests/more_generic_tests.pdl +++ b/src/test/tests/typecheckTests/more_generic_tests.pdl @@ -1,3 +1,4 @@ +// more_generic_tests.pdl // def error(inpt :int<10>) :bool // { // shamt = cast(inpt{4:0}, uint<5>); diff --git a/src/test/tests/typecheckTests/nested_generic.pdl b/src/test/tests/typecheckTests/nested_generic.pdl index ab13071b..a3d08079 100644 --- a/src/test/tests/typecheckTests/nested_generic.pdl +++ b/src/test/tests/typecheckTests/nested_generic.pdl @@ -1,3 +1,4 @@ +// nested_generic.pdl def iden(a :int) :int { return a; diff --git a/src/test/tests/typecheckTests/pipe-lock-fail1.pdl b/src/test/tests/typecheckTests/pipe-lock-fail1.pdl index 7fc4e8a6..be5980c0 100644 --- a/src/test/tests/typecheckTests/pipe-lock-fail1.pdl +++ b/src/test/tests/typecheckTests/pipe-lock-fail1.pdl @@ -1,3 +1,4 @@ +// pipe-lock-fail1.pdl pipe cache(addr: uint<5>, data: int<32>)[dmem: int<32>[5](Queue)]: bool { //spec_check(); start(dmem); diff --git a/src/test/tests/typecheckTests/pipe-lock-fail2.pdl b/src/test/tests/typecheckTests/pipe-lock-fail2.pdl index 48878382..499d35a8 100644 --- a/src/test/tests/typecheckTests/pipe-lock-fail2.pdl +++ b/src/test/tests/typecheckTests/pipe-lock-fail2.pdl @@ -1,3 +1,4 @@ +// pipe-lock-fail2.pdl pipe cache(addr: uint<5>, data: int<32>)[dmem: int<32>[5](Queue)]: bool { //spec_check(); start(dmem); diff --git a/src/test/tests/typecheckTests/pipe-lock.pdl b/src/test/tests/typecheckTests/pipe-lock.pdl index 4883c71c..07de4c8b 100644 --- a/src/test/tests/typecheckTests/pipe-lock.pdl +++ b/src/test/tests/typecheckTests/pipe-lock.pdl @@ -1,3 +1,4 @@ +// pipe-lock.pdl pipe cache(addr: uint<5>, data: int<32>)[dmem: int<32>[5](Queue)]: bool { //spec_check(); start(dmem); diff --git a/src/test/tests/typecheckTests/quad-call-disjoint.pdl b/src/test/tests/typecheckTests/quad-call-disjoint.pdl index 90341ad5..9b9b4034 100644 --- a/src/test/tests/typecheckTests/quad-call-disjoint.pdl +++ b/src/test/tests/typecheckTests/quad-call-disjoint.pdl @@ -1,3 +1,4 @@ +// quad-call-disjoint.pdl pipe quad_call(input: uint<32>)[rf: int<32>[5]] { bool a = input{0:0}; bool b = input{1:1}; diff --git a/src/test/tests/typecheckTests/risc-pipe-spec-generic.pdl b/src/test/tests/typecheckTests/risc-pipe-spec-generic.pdl index 74db42a1..d5d04ed4 100644 --- a/src/test/tests/typecheckTests/risc-pipe-spec-generic.pdl +++ b/src/test/tests/typecheckTests/risc-pipe-spec-generic.pdl @@ -1,3 +1,4 @@ +// risc-pipe-spec-generic.pdl def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { uint<32> mag1 = cast(mag(arg1), uint<32>); uint<32> mag2 = cast(mag(arg2), uint<32>); diff --git a/src/test/tests/typecheckTests/signedInts.pdl b/src/test/tests/typecheckTests/signedInts.pdl index 66b38c4c..33bea80f 100644 --- a/src/test/tests/typecheckTests/signedInts.pdl +++ b/src/test/tests/typecheckTests/signedInts.pdl @@ -1,3 +1,4 @@ +// signedInts.pdl //Expected Success pipe signtest(input: int<8>)[]: bool { int<8> x = input + 1<8>; diff --git a/src/test/tests/typecheckTests/superscalar-fail.pdl b/src/test/tests/typecheckTests/superscalar-fail.pdl index f66d71ec..b3b8a1d9 100644 --- a/src/test/tests/typecheckTests/superscalar-fail.pdl +++ b/src/test/tests/typecheckTests/superscalar-fail.pdl @@ -1,3 +1,4 @@ +// superscalar-fail.pdl pipe pp(val: int<8>)[]:int<8> { int<8> a = val + 1<8>; diff --git a/src/test/tests/typecheckTests/type-inference-basic-pass.pdl b/src/test/tests/typecheckTests/type-inference-basic-pass.pdl index 42533572..82e6686f 100644 --- a/src/test/tests/typecheckTests/type-inference-basic-pass.pdl +++ b/src/test/tests/typecheckTests/type-inference-basic-pass.pdl @@ -1,3 +1,4 @@ +// type-inference-basic-pass.pdl def helper1(a: int<32>, b:bool, c: String): int<32> { d = a + 1<32>; diff --git a/src/test/tests/typecheckTests/type-inference-bit-width-tests.pdl b/src/test/tests/typecheckTests/type-inference-bit-width-tests.pdl index 5b5a1470..f51662da 100644 --- a/src/test/tests/typecheckTests/type-inference-bit-width-tests.pdl +++ b/src/test/tests/typecheckTests/type-inference-bit-width-tests.pdl @@ -1,3 +1,4 @@ +// type-inference-bit-width-tests.pdl def helper1(a: int<32>, b:bool, c: String): int<32> { d = a + 1; diff --git a/src/test/tests/typecheckTests/type-inference-fail-base-type.pdl b/src/test/tests/typecheckTests/type-inference-fail-base-type.pdl index 72889371..9cb9cdf4 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-base-type.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-base-type.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-base-type.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = input + 2<32>; if (a) { diff --git a/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-memAccessToosmall.pdl b/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-memAccessToosmall.pdl index dd313404..0843f4ff 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-memAccessToosmall.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-memAccessToosmall.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-bit-too-small-memAccessToosmall.pdl pipe test6()[rf: int<32>[32]] { int<64> a = 6 * 6; diff --git a/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-minus.pdl b/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-minus.pdl index 1149577f..d419151d 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-minus.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-minus.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-bit-too-small-minus.pdl pipe test6()[] { a = 6 - 6; diff --git a/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-mult.pdl b/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-mult.pdl index 737be003..e0a85b87 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-mult.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-mult.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-bit-too-small-mult.pdl pipe test6()[] { a = 6 * 6; diff --git a/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-plus.pdl b/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-plus.pdl index deabf477..8b0e693d 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-plus.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-bit-too-small-plus.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-bit-too-small-plus.pdl pipe test6()[] { a = 6 + 6; diff --git a/src/test/tests/typecheckTests/type-inference-fail-boolBinOp.pdl b/src/test/tests/typecheckTests/type-inference-fail-boolBinOp.pdl index 3a302da6..974eca9f 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-boolBinOp.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-boolBinOp.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-boolBinOp.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = input; diff --git a/src/test/tests/typecheckTests/type-inference-fail-call-args.pdl b/src/test/tests/typecheckTests/type-inference-fail-call-args.pdl index 379def08..61f88a55 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-call-args.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-call-args.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-call-args.pdl pipe test10(a: bool, b: int<32>)[rf: int<32>[32]]: int<32> { output(5<32>); } diff --git a/src/test/tests/typecheckTests/type-inference-fail-call.pdl b/src/test/tests/typecheckTests/type-inference-fail-call.pdl index 6bc02fad..09d7de24 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-call.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-call.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-call.pdl pipe test10(a: bool, b: int<32>)[rf: int<32>[32]]: int<32> { output(5<32>); } diff --git a/src/test/tests/typecheckTests/type-inference-fail-eqBinOp.pdl b/src/test/tests/typecheckTests/type-inference-fail-eqBinOp.pdl index 0d4bae05..bf44b5e9 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-eqBinOp.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-eqBinOp.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-eqBinOp.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = true; b = a == input; diff --git a/src/test/tests/typecheckTests/type-inference-fail-func-app-arg.pdl b/src/test/tests/typecheckTests/type-inference-fail-func-app-arg.pdl index c2bb8609..7c811ae6 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-func-app-arg.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-func-app-arg.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-func-app-arg.pdl def func(a: bool, b: int<32>): bool { return b; } diff --git a/src/test/tests/typecheckTests/type-inference-fail-funcApp.pdl b/src/test/tests/typecheckTests/type-inference-fail-funcApp.pdl index f69d3e87..57730ebc 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-funcApp.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-funcApp.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-funcApp.pdl def func(a: bool, b: int<32>): bool { return b; } diff --git a/src/test/tests/typecheckTests/type-inference-fail-numBinOp.pdl b/src/test/tests/typecheckTests/type-inference-fail-numBinOp.pdl index 3096b3d3..20697e4d 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-numBinOp.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-numBinOp.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-numBinOp.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = true; b = a + a; diff --git a/src/test/tests/typecheckTests/type-inference-fail-ternary.pdl b/src/test/tests/typecheckTests/type-inference-fail-ternary.pdl index e635be6e..f1f6f027 100644 --- a/src/test/tests/typecheckTests/type-inference-fail-ternary.pdl +++ b/src/test/tests/typecheckTests/type-inference-fail-ternary.pdl @@ -1,3 +1,4 @@ +// type-inference-fail-ternary.pdl pipe test1(input: int<32>)[rf: int<32>[32]] { a = true; b = input; diff --git a/src/test/tests/typecheckTests/unlocked-mem-1.pdl b/src/test/tests/typecheckTests/unlocked-mem-1.pdl index 5373d6b5..f0098c84 100644 --- a/src/test/tests/typecheckTests/unlocked-mem-1.pdl +++ b/src/test/tests/typecheckTests/unlocked-mem-1.pdl @@ -1,3 +1,4 @@ +// unlocked-mem-1.pdl //Expected Success pipe unlock(input: int<32>)[rf: int<32>[5]] { spec_check(); diff --git a/src/test/tests/typecheckTests/unlocked-mem-fail-1.pdl b/src/test/tests/typecheckTests/unlocked-mem-fail-1.pdl index e2eaeb24..727e8714 100644 --- a/src/test/tests/typecheckTests/unlocked-mem-fail-1.pdl +++ b/src/test/tests/typecheckTests/unlocked-mem-fail-1.pdl @@ -1,3 +1,4 @@ +// unlocked-mem-fail-1.pdl //Expected Success pipe unlock(input: int<32>)[rf: int<32>[5]] { start(rf); diff --git a/src/test/tests/typecheckTests/unlocked-mem-fail.pdl b/src/test/tests/typecheckTests/unlocked-mem-fail.pdl index e6c96a44..68b07011 100644 --- a/src/test/tests/typecheckTests/unlocked-mem-fail.pdl +++ b/src/test/tests/typecheckTests/unlocked-mem-fail.pdl @@ -1,3 +1,4 @@ +// unlocked-mem-fail.pdl //Expected Fail pipe unlock(input: int<32>)[rf: int<32>[5]] { spec_check(); diff --git a/src/test/tests/typecheckTests/unlocked-mem.pdl b/src/test/tests/typecheckTests/unlocked-mem.pdl index 1ee5d08c..7d0082fd 100644 --- a/src/test/tests/typecheckTests/unlocked-mem.pdl +++ b/src/test/tests/typecheckTests/unlocked-mem.pdl @@ -1,3 +1,4 @@ +// unlocked-mem.pdl //Expected Success pipe unlock(input: int<32>)[rf: int<32>[5]] { start(rf); diff --git a/src/test/tests/typecheckTests/unlocked-reg.pdl b/src/test/tests/typecheckTests/unlocked-reg.pdl index dbf6b2e0..104887b8 100644 --- a/src/test/tests/typecheckTests/unlocked-reg.pdl +++ b/src/test/tests/typecheckTests/unlocked-reg.pdl @@ -1,3 +1,4 @@ +// unlocked-reg.pdl //Expected Success pipe unlock(tinput: int<32>)[rf: int<32>[0]] { spec_check(); From ef2f70f06666c1011126e318b33294f56703f8c6 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 11 Oct 2023 14:06:04 -0400 Subject: [PATCH 36/38] fix problem wrt iverilog version --- bin/runbsc | 4 ++-- src/test/scala/pipedsl/RiscSuite.scala | 26 ++++++++++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/bin/runbsc b/bin/runbsc index 87521883..a462ce6c 100755 --- a/bin/runbsc +++ b/bin/runbsc @@ -91,13 +91,13 @@ case "$CMD" in #Run simulation in Bluesim "$BSC" $ARGS -sim $BPATH "$TOP".bsv "$BSC" $ARGS $BPATH -sim -o "$TB".bexe -e "$TB" "$TB".ba - timeout "$TOUT"s ./"$TB".bexe | grep -v "WARNING" > "$SIMOUT" + timeout "$TOUT"s ./"$TB".bexe | grep -v "WARNING" | grep -v "\$finish" > "$SIMOUT" ;; "s") #Run simulation in Verilog "$BSC" $ARGS $BPATH $VPATH $VSIM -vdir $VDIR -simdir $SDIR -u "$TOP".bsv "$BSC" $ARGS $VPATH $VSIM -verilog -vdir $VDIR -simdir $SDIR -o "$TB".bexe -e "$TB" "$VDIR"/"$TB".v - timeout "$TOUT"s ./"$TB".bexe | grep -v "WARNING" > "$SIMOUT" + timeout "$TOUT"s ./"$TB".bexe | grep -v "WARNING" | grep -v "\$finish" > "$SIMOUT" ;; "c") rm -f *.bi *.bo *.ba diff --git a/src/test/scala/pipedsl/RiscSuite.scala b/src/test/scala/pipedsl/RiscSuite.scala index ec9342e5..96c570b6 100644 --- a/src/test/scala/pipedsl/RiscSuite.scala +++ b/src/test/scala/pipedsl/RiscSuite.scala @@ -27,21 +27,19 @@ class RiscSuite extends AnyFunSuite { //For each processor impl testFiles.foreach(t => { val testBaseName = getTestName(t) - if (testBaseName.contains("exn")) { - test(testBaseName + " Typecheck") { - testTypecheck(testFolder, t) - } - test(testBaseName + " BSV Compile") { - testBlueSpecCompile(testFolder, t, None, Map()) - } - //For each program - sims.foreach(s => { - val simInputs = getInputMap(s) - test(testBaseName + " Simulate " + s) { - testBlueSpecSim(testFolder, t, None, simInputs, Some(s + ".simsol")) - } - }) + test(testBaseName + " Typecheck") { + testTypecheck(testFolder, t) } + test(testBaseName + " BSV Compile") { + testBlueSpecCompile(testFolder, t, None, Map()) + } + //For each program + sims.foreach(s => { + val simInputs = getInputMap(s) + test(testBaseName + " Simulate " + s) { + testBlueSpecSim(testFolder, t, None, simInputs, Some(s + ".simsol")) + } + }) }) } From 5176c08fb08ec00265f872f342e3cfde64aea8d1 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Mon, 16 Oct 2023 16:24:08 -0400 Subject: [PATCH 37/38] some fixes and testcases --- .../typechecker/TypeInferenceWrapper.scala | 4 +- .../tests/risc-pipe/risc-pipe-spec-exn-1.pdl | 370 ++++++++++++++++ .../tests/risc-pipe/risc-pipe-spec-exn-2.pdl | 419 ++++++++++++++++++ .../tests/risc-pipe/risc-pipe-spec-exn-4.pdl | 359 +++++++++++++++ .../tests/risc-pipe/risc-pipe-spec-exn-5.pdl | 362 +++++++++++++++ .../tests/risc-pipe/risc-pipe-spec-exn.pdl | 36 +- 6 files changed, 1524 insertions(+), 26 deletions(-) create mode 100644 src/test/tests/risc-pipe/risc-pipe-spec-exn-1.pdl create mode 100644 src/test/tests/risc-pipe/risc-pipe-spec-exn-2.pdl create mode 100644 src/test/tests/risc-pipe/risc-pipe-spec-exn-4.pdl create mode 100644 src/test/tests/risc-pipe/risc-pipe-spec-exn-5.pdl diff --git a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala index 355a448c..d32592e0 100644 --- a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala +++ b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala @@ -250,9 +250,9 @@ object TypeInferenceWrapper val (fixed_except, final_subst) = m.except_blk match { case ExceptEmpty() => (ExceptEmpty(), subst1) - //TODO IMPROVE PRECISION OF OUT_ENV, SUBST + //TODO - EXN: IMPROVE PRECISION OF OUT_ENV, SUBST case ExceptFull(args, c) => - checkCommand(c, args.foldLeft(out_env)((env, id) => env.add(id, id.typ.get).asInstanceOf[TypeEnv]), subst) |> + checkCommand(c, args.foldLeft(pipeEnv)((env, id) => env.add(id, id.typ.get).asInstanceOf[TypeEnv]), subst) |> {case (cmd, _, s) => (ExceptFull(args, cmd), s)} } val hash = mutable.HashMap.from(final_subst) diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-exn-1.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-exn-1.pdl new file mode 100644 index 00000000..d2817a97 --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn-1.pdl @@ -0,0 +1,370 @@ +// risc-pipe-spec-write.pdl +extern BHT { + method req(pc: int, skip: int, take: int): int; + method upd(pc: int, taken: bool): (); +} + +def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { + uint<32> mag1 = cast(mag(arg1), uint<32>); + uint<32> mag2 = cast(mag(arg2), uint<32>); + //MULHU => positive sign always + int<32> s1 = (op == u3<3>) ? 1<32> : sign(arg1); + //MULHU/MULHSU => positive sign always + int<32> s2 = (op >= u2<3>) ? 1<32> : sign(arg2); + int<64> magRes = cast((mag1 * mag2), int<64>); + int<64> m = (s1 == s2) ? (magRes) : -(magRes); + if (op == u0<3>) { //MUL + return m{31:0}; + } else { + return m{63:32}; + } +} + +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + if (op == u0<3>) { //BEQ + return (arg1 == arg2); + } else { + if (op == u1<3>) { //BNE + return (arg1 != arg2); + } else { + if (op == u4<3>) { //BLT + return (arg1 < arg2); + } else { + if (op == u5<3>) { //BGE + return (arg1 >= arg2); + } else { + if (op == u6<3>) { //BLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2); + } else { + if (op == u7<3>) { //BGEU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return(un1 >= un2); + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32>, cnt: uint<5>, retQuot: bool)[]: uint<32> { + uint<32> tmp = acc{30:0} ++ num{31:31}; + uint<32> na = (tmp >= denom) ? (tmp - denom) : (tmp); + uint<32> nq = (tmp >= denom) ? ((quot << 1){31:1} ++ u1<1>) : (quot << 1); + uint<32> nnum = num << 1; + bool done = (cnt == u31<5>); + if (done) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); + } +} + + +exn-pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT, csrf: int<32>[2]]: bool { + spec_check(); + start(imem); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool isMul = isMDiv && (funct3 < u4<3>); + bool isSystem = opcode == 0b1110011<7>; + bool isEcall = isSystem && (immI == 0<32>); + bool isMret = isSystem && (funct7 == u24<7>) && (rs2 == u2<5>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + spec_check(); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if (!done) { + if (notBranch) { + s2 <- s; + } else { + if (isBranch) { + s2 <- update(s, bht.req(pc, immB, 1<16>)); + } else { + s2 <- s; + invalidate(s); + }}} else { s2 <- s; invalidate(s); } + if (isEcall){ + throw(u8<4>); + } + if (isMret){ + throw(u3<4>); + } + start(rf); + if (!done && (notBranch || isBranch)) { checkpoint(rf); } + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + --- + spec_check(); + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + bool take = br(funct3, rf1, rf2); + if (isBranch) { + //divide by 4 b/c we count instructions not bytes + int<16> offpc = pc + (immB >> 2); + int<16> npc = (take) ? (offpc) : (pc + 1<16>); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + int<32> alu_arg1 = (isAui) ? ((0<16> ++ pc) << 2) : rf1; + int<32> alu_arg2 = (isAui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : rf2)); + bool alu_flip = (isStore || isLoad || isAui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<16> tmppc = pc + 1<16>; + int<32> linkpc = 0<16> ++ (tmppc << 2); + int<32> mulres = mul(rf1, rf2, funct3); + if (writerd && (!isLoad) && (!isDiv)) { + block(rf[rd]); + int<32> rddata = (isLui) ? immU : ((isMul) ? mulres : ((isJal || isJalr) ? linkpc : alu_res)); + rf[rd] <- rddata; + } else { + int<32> rddata = 0<32>; + } + --- + spec_barrier(); //delayed just to force writes to happen speculatively + if (!done) { + if (!notBranch) { + if (isBranch) { + verify(s2, npc) { bht.upd(pc, take) }; + } else { + call cpu(npc); + } + } else { + verify(s, pc + 1<16>); + } + } + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + bool invertRes <- isSignedDiv && (sdividend != sdivisor); + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } else { + bool invertRes <- false; + uint<32> udivout <- u0<32>; + } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + if (isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + if (isDiv) { + block(rf[rd]); + int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + int<32> insnout = divout; + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + }} + print("Writing %d to r%d", insnout, rd); + } + --- +commit: + if (writerd) { + release(rf[rd]); + } + if (done) { output(true); } +except(exncode: uint<4>): // mepc = csrf[0], mtvec = csrf[1], mcause = csrf[2] + print("exception at PC == %d! with exncode: %d", pc, exncode); + start(csrf); + if (exncode == u8<4>){ + csrf[0] <- cast(pc, int<32>); // write to mepc + int<32> csrret = csrf[1]; // read from mtvec + int<16> npc = csrret{15:0}; + } else { if (exncode == u3<4>){ + int<32> csrret = csrf[0]; // read from mepc + int<16> npc = csrret{15:0} + 1; + } else { int<16> npc = pc + 1; }} + --- + csrf[2] <- cast(exncode, int<32>); // write to mcause + end(csrf); + --- + print("GOTO PC: %d", npc); + call cpu(npc); +} + +circuit { + ti = memory(int<32>, 16); + td = memory(int<32>, 16); + rf = rflock CheckpointRF(int<32>, 5, 64); + csrf = regfile(int<32>, 2); + div = new multi_stg_div[]; + b = new BHT<16>[](4); + c = new cpu[rf, ti, td, div, b, csrf]; + call c(0<16>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-exn-2.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-exn-2.pdl new file mode 100644 index 00000000..1ef051fa --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn-2.pdl @@ -0,0 +1,419 @@ +// risc-pipe-spec-write.pdl +extern BHT { + method req(pc: int, skip: int, take: int): int; + method upd(pc: int, taken: bool): (); +} + +def csr_map(csrAddr: uint<12>): uint<5> { + if (csrAddr == 0x300) { //mstatus: Machine status register + return u0<5>; } else { + if (csrAddr == 0x301) { //misa: ISA and extensions + return u1<5>; } else { + if (csrAddr == 0x302) { //medeleg: Machine exception delegation register + return u2<5>; } else { + if (csrAddr == 0x303) { //mideleg: Machine interrupt delegation register + return u3<5>; } else { + if (csrAddr == 0x304) { //mie: Machine interrupt-enable register + return u4<5>; } else { + if (csrAddr == 0x305) { //mtvec: Machine trap-handler base address + return u5<5>; } else { + if (csrAddr == 0x340) { //mscratch: Scratch register for machine trap handlers + return u6<5>; } else { + if (csrAddr == 0x341) { //mepc: Machine exception program counter + return u7<5>; } else { + if (csrAddr == 0x342) { //mcause: Machine trap cause + return u8<5>; } else { + if (csrAddr == 0x343) { //mtval: Machine bad address or instruction + return u9<5>; } else { + if (csrAddr == 0x344) { //mip: Machine interrupt pending + return u10<5>; } else { + if (csrAddr == 0x34A) { //mtinst: Machine trap instruction (transformed) + return u11<5>; } else { + return u31<5>;}}}}}}}}}}}} +} + +def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { + uint<32> mag1 = cast(mag(arg1), uint<32>); + uint<32> mag2 = cast(mag(arg2), uint<32>); + //MULHU => positive sign always + int<32> s1 = (op == u3<3>) ? 1<32> : sign(arg1); + //MULHU/MULHSU => positive sign always + int<32> s2 = (op >= u2<3>) ? 1<32> : sign(arg2); + int<64> magRes = cast((mag1 * mag2), int<64>); + int<64> m = (s1 == s2) ? (magRes) : -(magRes); + if (op == u0<3>) { //MUL + return m{31:0}; + } else { + return m{63:32}; + } +} + +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + if (op == u0<3>) { //BEQ + return (arg1 == arg2); + } else { + if (op == u1<3>) { //BNE + return (arg1 != arg2); + } else { + if (op == u4<3>) { //BLT + return (arg1 < arg2); + } else { + if (op == u5<3>) { //BGE + return (arg1 >= arg2); + } else { + if (op == u6<3>) { //BLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2); + } else { + if (op == u7<3>) { //BGEU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return(un1 >= un2); + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32>, cnt: uint<5>, retQuot: bool)[]: uint<32> { + uint<32> tmp = acc{30:0} ++ num{31:31}; + uint<32> na = (tmp >= denom) ? (tmp - denom) : (tmp); + uint<32> nq = (tmp >= denom) ? ((quot << 1){31:1} ++ u1<1>) : (quot << 1); + uint<32> nnum = num << 1; + bool done = (cnt == u31<5>); + if (done) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); + } +} + +exn-pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT, csrf: int<32>[5]]: bool { + spec_check(); + start(imem); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool isMul = isMDiv && (funct3 < u4<3>); + bool isCsr = opcode == 0b1110011<7>; + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + spec_check(); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if (!done) { + if (notBranch) { + s2 <- s; + } else { + if (isBranch) { + s2 <- update(s, bht.req(pc, immB, 1<16>)); + } else { + s2 <- s; + invalidate(s); + }}} else { s2 <- s; invalidate(s); } + if (isCsr){ + throw(u15<4>, insn); + } + start(rf); + if (!done && (notBranch || isBranch)) { checkpoint(rf); } + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + --- + spec_check(); + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + bool take = br(funct3, rf1, rf2); + if (isBranch) { + //divide by 4 b/c we count instructions not bytes + int<16> offpc = pc + (immB >> 2); + int<16> npc = (take) ? (offpc) : (pc + 1<16>); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + int<32> alu_arg1 = (isAui) ? ((0<16> ++ pc) << 2) : rf1; + int<32> alu_arg2 = (isAui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : rf2)); + bool alu_flip = (isStore || isLoad || isAui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<16> tmppc = pc + 1<16>; + int<32> linkpc = 0<16> ++ (tmppc << 2); + int<32> mulres = mul(rf1, rf2, funct3); + if (writerd && (!isLoad) && (!isDiv)) { + block(rf[rd]); + int<32> rddata = (isLui) ? immU : ((isMul) ? mulres : ((isJal || isJalr) ? linkpc : alu_res)); + rf[rd] <- rddata; + } else { + int<32> rddata = 0<32>; + } + --- + spec_barrier(); //delayed just to force writes to happen speculatively + if (!done) { + if (!notBranch) { + if (isBranch) { + verify(s2, npc) { bht.upd(pc, take) }; + } else { + call cpu(npc); + } + } else { + verify(s, pc + 1<16>); + } + } + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + bool invertRes <- isSignedDiv && (sdividend != sdivisor); + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } else { + bool invertRes <- false; + uint<32> udivout <- u0<32>; + } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + if (isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + if (isDiv) { + block(rf[rd]); + int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + int<32> insnout = divout; + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + }} + print("Writing %d to r%d", insnout, rd); + } + --- +commit: + if (writerd) { + release(rf[rd]); + } + if (done) { output(true); } +except(exncode: uint<4>, insn: int<32>): + print("exception at PC == %d! with exncode: %d", pc, exncode); + start(csrf); + start(rf); + uint<5> rs1_exn = cast(insn{19:15}, uint<5>); + uint<5> rd_exn = cast(insn{11:7}, uint<5>); + uint<12> csr_addr = cast(insn{31:20}, uint<12>); + uint<3> funct3_exn = cast(insn{14:12}, uint<3>); + bool isCsrrw = (funct3_exn == u1<3>); + bool isCsrrs = (funct3_exn == u2<3>); + bool isCsrrc = (funct3_exn == u3<3>); + if (exncode == u15<4>){ // Decode CSR instruction + reserve(rf[rs1_exn], R); + reserve(rf[rd_exn], W); + } + end(rf); + --- + uint<5> csr_idx = csr_map(csr_addr); + int<32> old_csr_val = csrf[csr_idx]; + if (exncode == u15<4>){ // CSR instruction + block(rf[rs1_exn]); + int<32> rf1_val = rf[rs1_exn]; + release(rf[rs1_exn]); + if (isCsrrw){ + csrf[csr_idx] <- rf1_val; + } else { if (isCsrrs) { + int<32> masked_val = rf1_val | old_csr_val; + csrf[csr_idx] <- masked_val; + } else { if (isCsrrc) { + int<32> masked_val = (~rf1_val) & old_csr_val; + csrf[csr_idx] <- masked_val; + }}} + int<16> npc = pc + 1; + } else { int<16> npc = pc + 1; } + end(csrf); + --- + if (exncode == u15<4>){ // RF writeback + block(rf[rd_exn]); + rf[rd_exn] <- old_csr_val; + release(rf[rd_exn]); + } + --- + print("GOTO PC: %d", npc); + call cpu(npc); +} + +circuit { + ti = memory(int<32>, 16); + td = memory(int<32>, 16); + rf = rflock CheckpointRF(int<32>, 5, 64); + csrf = regfile(int<32>, 5); + div = new multi_stg_div[]; + b = new BHT<16>[](4); + c = new cpu[rf, ti, td, div, b, csrf]; + call c(0<16>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-exn-4.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-exn-4.pdl new file mode 100644 index 00000000..5be8d3f1 --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn-4.pdl @@ -0,0 +1,359 @@ +// risc-pipe-spec-write.pdl +extern BHT { + method req(pc: int, skip: int, take: int): int; + method upd(pc: int, taken: bool): (); +} + +def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { + uint<32> mag1 = cast(mag(arg1), uint<32>); + uint<32> mag2 = cast(mag(arg2), uint<32>); + //MULHU => positive sign always + int<32> s1 = (op == u3<3>) ? 1<32> : sign(arg1); + //MULHU/MULHSU => positive sign always + int<32> s2 = (op >= u2<3>) ? 1<32> : sign(arg2); + int<64> magRes = cast((mag1 * mag2), int<64>); + int<64> m = (s1 == s2) ? (magRes) : -(magRes); + if (op == u0<3>) { //MUL + return m{31:0}; + } else { + return m{63:32}; + } +} + +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + if (op == u0<3>) { //BEQ + return (arg1 == arg2); + } else { + if (op == u1<3>) { //BNE + return (arg1 != arg2); + } else { + if (op == u4<3>) { //BLT + return (arg1 < arg2); + } else { + if (op == u5<3>) { //BGE + return (arg1 >= arg2); + } else { + if (op == u6<3>) { //BLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2); + } else { + if (op == u7<3>) { //BGEU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return(un1 >= un2); + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32>, cnt: uint<5>, retQuot: bool)[]: uint<32> { + uint<32> tmp = acc{30:0} ++ num{31:31}; + uint<32> na = (tmp >= denom) ? (tmp - denom) : (tmp); + uint<32> nq = (tmp >= denom) ? ((quot << 1){31:1} ++ u1<1>) : (quot << 1); + uint<32> nnum = num << 1; + bool done = (cnt == u31<5>); + if (done) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); + } +} + +exn-pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT, csrf: int<32>[1]]: bool { + spec_check(); + start(imem); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool isMul = isMDiv && (funct3 < u4<3>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + bool isExcluded = isJalr || isJal || isBranch; + bool isInvalid = (opcode <= 0<7>); + if (isInvalid && !isExcluded){ + throw(u0<4>); // Fatal and terminate exec if illegal instr + } + spec_check(); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if (!done) { + if (notBranch) { + s2 <- s; + } else { + if (isBranch) { + s2 <- update(s, bht.req(pc, immB, 1<16>)); + } else { + s2 <- s; + invalidate(s); + }}} else { s2 <- s; invalidate(s); } + start(rf); + if (!done && (notBranch || isBranch)) { checkpoint(rf); } + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + --- + spec_check(); + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + bool take = br(funct3, rf1, rf2); + if (isBranch) { + //divide by 4 b/c we count instructions not bytes + int<16> offpc = pc + (immB >> 2); + int<16> npc = (take) ? (offpc) : (pc + 1<16>); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + int<32> alu_arg1 = (isAui) ? ((0<16> ++ pc) << 2) : rf1; + int<32> alu_arg2 = (isAui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : rf2)); + bool alu_flip = (isStore || isLoad || isAui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<16> tmppc = pc + 1<16>; + int<32> linkpc = 0<16> ++ (tmppc << 2); + int<32> mulres = mul(rf1, rf2, funct3); + if (writerd && (!isLoad) && (!isDiv)) { + block(rf[rd]); + int<32> rddata = (isLui) ? immU : ((isMul) ? mulres : ((isJal || isJalr) ? linkpc : alu_res)); + rf[rd] <- rddata; + } else { + int<32> rddata = 0<32>; + } + --- + spec_barrier(); //delayed just to force writes to happen speculatively + if (!done) { + if (!notBranch) { + if (isBranch) { + verify(s2, npc) { bht.upd(pc, take) }; + } else { + call cpu(npc); + } + } else { + verify(s, pc + 1<16>); + } + } + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + bool invertRes <- isSignedDiv && (sdividend != sdivisor); + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } else { + bool invertRes <- false; + uint<32> udivout <- u0<32>; + } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + if (isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + if (isDiv) { + block(rf[rd]); + int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + int<32> insnout = divout; + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + }} + print("Writing %d to r%d", insnout, rd); + } + --- +commit: + if (writerd) { + release(rf[rd]); + } + if (done) { output(true); } +except(exncode: uint<4>): + print("exception at PC == %d! with exncode: %d", pc, exncode); + start(csrf); + csrf[0] <- cast(exncode, int<32>); // Store Exncode + --- + csrf[1] <- cast(pc, int<32>); // Store ErrPC + end(csrf); + --- + if (exncode == u0<4>){ + output(false); // Terminate execution + } else { call cpu(pc + 1<16>); } +} + +circuit { + ti = memory(int<32>, 16); + td = memory(int<32>, 16); + rf = rflock CheckpointRF(int<32>, 5, 64); + csrf = regfile(int<32>, 1); + div = new multi_stg_div[]; + b = new BHT<16>[](4); + c = new cpu[rf, ti, td, div, b, csrf]; + call c(0<16>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-exn-5.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-exn-5.pdl new file mode 100644 index 00000000..17d6675a --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn-5.pdl @@ -0,0 +1,362 @@ +// risc-pipe-spec-write.pdl +extern BHT { + method req(pc: int, skip: int, take: int): int; + method upd(pc: int, taken: bool): (); +} + +def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { + uint<32> mag1 = cast(mag(arg1), uint<32>); + uint<32> mag2 = cast(mag(arg2), uint<32>); + //MULHU => positive sign always + int<32> s1 = (op == u3<3>) ? 1<32> : sign(arg1); + //MULHU/MULHSU => positive sign always + int<32> s2 = (op >= u2<3>) ? 1<32> : sign(arg2); + int<64> magRes = cast((mag1 * mag2), int<64>); + int<64> m = (s1 == s2) ? (magRes) : -(magRes); + if (op == u0<3>) { //MUL + return m{31:0}; + } else { + return m{63:32}; + } +} + +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + if (op == u0<3>) { //BEQ + return (arg1 == arg2); + } else { + if (op == u1<3>) { //BNE + return (arg1 != arg2); + } else { + if (op == u4<3>) { //BLT + return (arg1 < arg2); + } else { + if (op == u5<3>) { //BGE + return (arg1 >= arg2); + } else { + if (op == u6<3>) { //BLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2); + } else { + if (op == u7<3>) { //BGEU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return(un1 >= un2); + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32>, cnt: uint<5>, retQuot: bool)[]: uint<32> { + uint<32> tmp = acc{30:0} ++ num{31:31}; + uint<32> na = (tmp >= denom) ? (tmp - denom) : (tmp); + uint<32> nq = (tmp >= denom) ? ((quot << 1){31:1} ++ u1<1>) : (quot << 1); + uint<32> nnum = num << 1; + bool done = (cnt == u31<5>); + if (done) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); + } +} + +exn-pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT, csrf: int<32>[1]]: bool { + spec_check(); + start(imem); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool isMul = isMDiv && (funct3 < u4<3>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + bool isExcluded = isJalr || isJal || isBranch; + bool isInvalid = (opcode <= 0<7>); + if (isInvalid && !isExcluded){ + throw(u0<4>); // Fatal and terminate exec if illegal instr + } + spec_check(); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if (!done) { + if (notBranch) { + s2 <- s; + } else { + if (isBranch) { + s2 <- update(s, bht.req(pc, immB, 1<16>)); + } else { + s2 <- s; + invalidate(s); + }}} else { s2 <- s; invalidate(s); } + start(rf); + if (!done && (notBranch || isBranch)) { checkpoint(rf); } + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + --- + spec_check(); + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + bool take = br(funct3, rf1, rf2); + if (isBranch) { + //divide by 4 b/c we count instructions not bytes + int<16> offpc = pc + (immB >> 2); + int<16> npc = (take) ? (offpc) : (pc + 1<16>); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + int<32> alu_arg1 = (isAui) ? ((0<16> ++ pc) << 2) : rf1; + int<32> alu_arg2 = (isAui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : rf2)); + bool alu_flip = (isStore || isLoad || isAui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<16> tmppc = pc + 1<16>; + int<32> linkpc = 0<16> ++ (tmppc << 2); + int<32> mulres = mul(rf1, rf2, funct3); + if (writerd && (!isLoad) && (!isDiv)) { + block(rf[rd]); + int<32> rddata = (isLui) ? immU : ((isMul) ? mulres : ((isJal || isJalr) ? linkpc : alu_res)); + rf[rd] <- rddata; + } else { + int<32> rddata = 0<32>; + } + --- + spec_barrier(); //delayed just to force writes to happen speculatively + if (!done) { + if (!notBranch) { + if (isBranch) { + verify(s2, npc) { bht.upd(pc, take) }; + } else { + call cpu(npc); + } + } else { + verify(s, pc + 1<16>); + } + } + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + bool invertRes <- isSignedDiv && (sdividend != sdivisor); + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } else { + bool invertRes <- false; + uint<32> udivout <- u0<32>; + } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + if (memaddr == u65535<16>){ // Some random address that leads to Fatal state if R/W + throw(u1<4>); + } + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + if (isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + if (isDiv) { + block(rf[rd]); + int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + int<32> insnout = divout; + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + }} + print("Writing %d to r%d", insnout, rd); + } + --- +commit: + if (writerd) { + release(rf[rd]); + } + if (done) { output(true); } +except(exncode: uint<4>): + print("exception at PC == %d! with exncode: %d", pc, exncode); + start(csrf); + csrf[0] <- cast(exncode, int<32>); // Store Exncode + ---// using 2 write port version + csrf[1] <- cast(pc, int<32>); // Store ErrPC + end(csrf); + --- + if ((exncode == u0<4>) || (exncode == u1<4>)){ + output(false); // Terminate execution + } else { call cpu(pc + 1<16>); } +} + +circuit { + ti = memory(int<32>, 16); + td = memory(int<32>, 16); + rf = rflock CheckpointRF(int<32>, 5, 64); + csrf = regfile(int<32>, 1); + div = new multi_stg_div[]; + b = new BHT<16>[](4); + c = new cpu[rf, ti, td, div, b, csrf]; + call c(0<16>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl index 4e34a1fb..28726b2d 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl @@ -12,41 +12,29 @@ extern TimingInterruptController { def csr_map(csrAddr: uint<12>): uint<5> { if (csrAddr == 0x300) { //mstatus: Machine status register - return u0<5>; - } else{ + return u0<5>; } else { if (csrAddr == 0x301) { //misa: ISA and extensions - return u1<5>; - } else{ + return u1<5>; } else { if (csrAddr == 0x302) { //medeleg: Machine exception delegation register - return u2<5>; - } else{ + return u2<5>; } else { if (csrAddr == 0x303) { //mideleg: Machine interrupt delegation register - return u3<5>; - } else{ + return u3<5>; } else { if (csrAddr == 0x304) { //mie: Machine interrupt-enable register - return u4<5>; - } else{ + return u4<5>; } else { if (csrAddr == 0x305) { //mtvec: Machine trap-handler base address - return u5<5>; - } else{ + return u5<5>; } else { if (csrAddr == 0x340) { //mscratch: Scratch register for machine trap handlers - return u6<5>; - } else{ + return u6<5>; } else { if (csrAddr == 0x341) { //mepc: Machine exception program counter - return u7<5>; - } else{ + return u7<5>; } else { if (csrAddr == 0x342) { //mcause: Machine trap cause - return u8<5>; - } else{ + return u8<5>; } else { if (csrAddr == 0x343) { //mtval: Machine bad address or instruction - return u9<5>; - } else{ + return u9<5>; } else { if (csrAddr == 0x344) { //mip: Machine interrupt pending - return u10<5>; - } else{ + return u10<5>; } else { if (csrAddr == 0x34A) { //mtinst: Machine trap instruction (transformed) - return u11<5>; - } else{ + return u11<5>; } else { return u31<5>;}}}}}}}}}}}} } From 6cc3a76607461e46cc5cea709c0ddfdf4c0b81ad Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 25 Oct 2023 13:25:18 -0400 Subject: [PATCH 38/38] fix chkp + some ad hoc stuff --- bscRuntime/memories/Locks.bsv | 4 +- bscRuntime/memories/Memories.bsv | 51 ++- .../codegen/bsv/BSVPrettyPrinter.scala | 6 +- .../scala/pipedsl/codegen/bsv/BSVSyntax.scala | 6 +- .../codegen/bsv/BluespecGeneration.scala | 10 +- .../pipedsl/common/LockImplementation.scala | 15 +- src/main/scala/pipedsl/common/Syntax.scala | 2 +- src/main/scala/pipedsl/common/Utilities.scala | 9 +- .../pipedsl/passes/ConvertAsyncPass.scala | 14 +- .../tests/exception/exn-recovery-spec.pdl | 8 +- src/test/tests/exception/exn-simple-chkp.pdl | 32 ++ src/test/tests/exception/exn-simple-spec.pdl | 14 +- src/test/tests/exception/memInputs/acc | 1 + .../tests/risc-pipe/risc-pipe-pldi-5-stg.pdl | 276 ++++++++++++ .../tests/risc-pipe/risc-pipe-spec-exn-3.pdl | 392 ++++++++++++++++++ .../tests/risc-pipe/risc-pipe-spec-write.pdl | 32 +- 16 files changed, 833 insertions(+), 39 deletions(-) create mode 100644 src/test/tests/exception/exn-simple-chkp.pdl create mode 100644 src/test/tests/exception/memInputs/acc create mode 100644 src/test/tests/risc-pipe/risc-pipe-pldi-5-stg.pdl create mode 100644 src/test/tests/risc-pipe/risc-pipe-spec-exn-3.pdl diff --git a/bscRuntime/memories/Locks.bsv b/bscRuntime/memories/Locks.bsv index 4c9af97c..8dbc14e7 100644 --- a/bscRuntime/memories/Locks.bsv +++ b/bscRuntime/memories/Locks.bsv @@ -159,8 +159,8 @@ module mkCheckpointQueueLock(Put#(winfo) mem, CheckpointQueueLock#(LockId#(d), L method Action abort(); nextId[0] <= 0; - owner <= 0; - empty <= True; + owner <= 0; + empty <= True; wdata <= tagged Invalid; endmethod diff --git a/bscRuntime/memories/Memories.bsv b/bscRuntime/memories/Memories.bsv index 28188d94..509cf149 100644 --- a/bscRuntime/memories/Memories.bsv +++ b/bscRuntime/memories/Memories.bsv @@ -22,6 +22,7 @@ export AsyncMem(..); export AsyncMem2(..); export QueueLockCombMem(..); export CheckpointQueueLockCombMem(..); +export CheckpointQueueLockAsyncMem(..); export QueueLockAsyncMem(..); export QueueLockAsyncMem2(..); export BypassLockCombMem(..); @@ -38,6 +39,7 @@ export mkAsyncMem; export mkAsyncMem2; export mkQueueLockCombMem; export mkCheckpointQueueLockCombMem; +export mkCheckpointQueueLockAsyncMem; export mkQueueLockAsyncMem; export mkQueueLockAsyncMem2; export mkFAAddrLockCombMem; @@ -62,6 +64,14 @@ function Bool isNewer(UInt#(sz) a, UInt#(sz) b, UInt#(sz) h); return !isOlder(a, b, h); endfunction +function Put#(Tuple3#(Bit#(nsz), addr, elem)) asyncMemToPut (AsyncMem#(addr, elem, MemId#(inflight), nsz) amem); + return (interface Put; + method Action put(Tuple3#(Bit#(nsz), addr, elem) x); + amem.silentReq1(tpl_2(x), tpl_3(x), tpl_1(x)); + endmethod + endinterface); +endfunction + function Put#(Tuple2#(addr, elem)) rfToPut (RegFile#(addr, elem) rf); return (interface Put; method Action put(Tuple2#(addr, elem) x); @@ -84,6 +94,7 @@ endinterface interface AsyncMem#(type addr, type elem, type mid, numeric type nsz); method ActionValue#(mid) req1(addr a, elem b, Bit#(nsz) wmask); + method Action silentReq1(addr a, elem b, Bit#(nsz) wmask); method elem peekResp1(mid a); method Bool checkRespId1(mid a); method Action resp1(mid a); @@ -130,6 +141,14 @@ interface CheckpointQueueLockCombMem#(type addr, type elem, type id, type cid); method Action atom_w(addr a, elem b); endinterface +interface CheckpointQueueLockAsyncMem#(type addr, type elem, type rid, numeric type nsz, type id, type cid); + interface AsyncMem#(addr, elem, rid, nsz) mem; + interface CheckpointQueueLock#(id, cid, Tuple3#(Bit#(nsz), addr, elem)) lock; + method Action write(addr a, elem b, Bit#(nsz) wmask); + method Bool canAtom1(addr a); + method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); +endinterface + interface QueueLockAsyncMem#(type addr, type elem, type rid, numeric type nsz, type lid); interface AsyncMem#(addr, elem, rid, nsz) mem; interface QueueLock#(lid) lock; @@ -243,7 +262,7 @@ module mkBramPort#(parameter Bool init, parameter String file)(BramPort#(addr, e interface Server bram_server; interface Put request; method Action put (Tuple3#(Bit#(nsz), addr, elem) req); - // $display("Sending request %t", $time()); + //$display("Sending request %t %d %d ", $time(), tpl_1(req), tpl_3(req)); p.put(tpl_1(req), tpl_2(req), tpl_3(req)); doRead <= True; endmethod @@ -251,6 +270,7 @@ module mkBramPort#(parameter Bool init, parameter String file)(BramPort#(addr, e interface Get response; method ActionValue#(elem) get(); + //$display("Returning data %t %d", nextData); return nextData; endmethod endinterface @@ -378,6 +398,11 @@ module mkAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) _unused_) return head; endmethod + method Action silentReq1(addr a, elem b, Bit#(n) wmask) if (okToRequest); + toMem <= tuple3(wmask, a, b); + head <= head + 1; + endmethod + method elem peekResp1(MemId#(inflight) a); return outData[a][1]; endmethod @@ -681,6 +706,30 @@ module mkDMAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, interface lock = l; endmodule +module mkCheckpointQueueLockAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), nsz) amem, CheckpointQueueLockAsyncMem#(addr, elem, MemId#(inflight), nsz, LockId#(d), LockId#(d)) _unused_) +provisos(Bits#(Tuple3#(Bit#(nsz), addr, elem), tuplsz)); + + Put#(Tuple3#(Bit#(nsz), addr, elem)) doWrite = asyncMemToPut(amem); + CheckpointQueueLock#(LockId#(d), LockId#(d), Tuple3#(Bit#(nsz), addr, elem)) l <- mkCheckpointQueueLock(doWrite); + + interface lock = l; + interface mem = amem; + + method Action write(addr a, elem b, Bit#(nsz) wmask); + l.write(tuple3(wmask, a, b)); + endmethod + + method Bool canAtom1(addr a); + return l.isEmpty; + endmethod + + method ActionValue#(MemId#(inflight)) atom_req1(addr a, elem b, Bit#(nsz) wmask); + let r <- amem.req1(a, b, wmask); + return r; + endmethod + +endmodule + module mkQueueLockAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) amem, QueueLockAsyncMem#(addr, elem, MemId#(inflight), n, LockId#(d)) _unused_) provisos(Bits#(addr, szAddr), Bits#(elem, szElem)); diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala index c1274a1a..bda66356 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala @@ -2,6 +2,7 @@ package pipedsl.codegen.bsv import java.io.{File, FileOutputStream, OutputStreamWriter, Writer} +import java.math.BigInteger import pipedsl.codegen.bsv.BSVSyntax._ import pipedsl.common.Errors.BaseError @@ -69,7 +70,7 @@ object BSVPrettyPrinter { case BInteger() => "Integer" } - private def toIntString(base: Int, value: Int): String = base match { + private def toIntString(base: Int, value: Int, bits: Int): String = base match { case 16 => "h" + value.toHexString case 10 => "d" + value.toString case 8 => "o" + value.toOctalString @@ -97,7 +98,7 @@ object BSVPrettyPrinter { "False" } case BUnsizedInt(v) => v.toString - case BIntLit(v, base, bits) => bits.toString + "'" + toIntString(base, v) + case BIntLit(v, base, bits) => bits.toString + "'" + toIntString(base, v, bits) case BStringLit(v) => "\"" + v + "\"" case BStructLit(typ, fields) => val fieldStr = fields.keys.map(k => { @@ -129,6 +130,7 @@ object BSVPrettyPrinter { val argstring = args.map(a => toBSVExprStr(a)).mkString(", ") mkExprString(name, "(", argstring, ")") case BMethodInvoke(mod, method, args) => + println(mod, method, args) val argstring = args.map(a => toBSVExprStr(a)).mkString(", ") val argStringFull = if (argstring.isEmpty) "" else "(" + argstring + ")" toBSVExprStr(mod) + "." + method + argStringFull diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index 89c9c0c4..cbd24917 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -183,7 +183,11 @@ object BSVSyntax { } def toExpr(e: Expr): BExpr = e match { - case EInt(v, base, bits) => BIntLit(v, base, bits) + case EInt(v, base, bits) => bits match { + case -1 if v == 0 => BZero + case -1 if v == 1 => BAllOnes + case _ => BIntLit(v, base, bits) + } // TODO - EXN: Very ad-hoc stuff.. need Fix case EBool(v) => BBoolLit(v) case EString(v) => BStringLit(v) case eu@EUop(_, _) => translateUOp(eu) diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index 1f4cd9da..d1b72e35 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -717,7 +717,7 @@ object BluespecGeneration { } else { l } - case im@IMemWrite(mem, addr, data, _, _, isAtomic) if isAtomic => + case im@IMemWrite(mem, addr, data, writeMask, _, _, isAtomic) if isAtomic => val methodInfo = LockImplementation.getCanAtomicWrite(mem, addr, data, im.portNum) if (methodInfo.isDefined) { l :+ translateMethod(getLockName(mem), methodInfo.get) @@ -1058,7 +1058,7 @@ object BluespecGeneration { private def getCombinationalDeclaration(cmd: Command): Option[BDecl] = cmd match { case CAssign(lhs, _) => Some(BDecl(translator.toVar(lhs), None)) case IMemSend(_, _, _, _, _, _, outH, _) if outH.isDefined => Some(BDecl(translator.toVar(outH.get), None)) - case IMemWrite(_, _, _, _, outH, _) if outH.isDefined => Some(BDecl(translator.toVar(outH.get), None)) + case IMemWrite(_, _, _, _, _, outH, _) if outH.isDefined => Some(BDecl(translator.toVar(outH.get), None)) case IMemRecv(_, _, data) => data match { case Some(v) => Some(BDecl(translator.toVar(v), None)) case None => None @@ -1104,7 +1104,7 @@ object BluespecGeneration { case CExpr(exp) => Some(BExprStmt(translator.toExpr(exp))) case IMemSend(_, _, _, _, _, inH, outH, _) if inH.isDefined && outH.isDefined => Some(BAssign(translator.toVar(outH.get), translator.toExpr(inH.get))) - case IMemWrite(_, _, _, inH, outH, _) if inH.isDefined && outH.isDefined => + case IMemWrite(_, _, _, _, inH, outH, _) if inH.isDefined && outH.isDefined => Some(BAssign(translator.toVar(outH.get), translator.toExpr(inH.get))) case IMemRecv(mem: Id, handle: EVar, data: Option[EVar]) => data match { case Some(v) => Some(BAssign(translator.toVar(v), @@ -1253,7 +1253,7 @@ object BluespecGeneration { //This is an effectful op b/c is modifies the mem queue its reading from case IMemRecv(mem: Id, handle: EVar, _: Option[EVar]) => Some(BExprStmt(bsInts.getMemResp(modParams(mem), translator.toVar(handle), cmd.portNum, isLockedMemory(mem)))) - case IMemWrite(mem, addr, data, lHandle, _, isAtomic) => + case IMemWrite(mem, addr, data, writeMask, lHandle, _, isAtomic) => val portNum = mem.typ.get match { case memType: TLockedMemType => if (memType.limpl.usesWritePortNum) cmd.portNum else None case _ => None //In the future we may allow unlocked mems with port annotations @@ -1261,7 +1261,7 @@ object BluespecGeneration { Some(BExprStmt( if (isLockedMemory(mem)) { //ask lock for its translation - translateMethod(modParams(mem), LockImplementation.getWriteInfo(mem, addr, lHandle, data, portNum, isAtomic).get) + translateMethod(modParams(mem), LockImplementation.getWriteInfo(mem, addr, lHandle, data, writeMask, portNum, isAtomic).get) } else { //use unlocked translation bsInts.getUnlockedCombWrite(modParams(mem), translator.toExpr(addr), translator.toExpr(data), portNum) diff --git a/src/main/scala/pipedsl/common/LockImplementation.scala b/src/main/scala/pipedsl/common/LockImplementation.scala index e7782ab9..083b591d 100644 --- a/src/main/scala/pipedsl/common/LockImplementation.scala +++ b/src/main/scala/pipedsl/common/LockImplementation.scala @@ -1,10 +1,12 @@ /* LockImplementation.scala */ package pipedsl.common +import pipedsl.codegen.bsv.BSVSyntax.BPack import pipedsl.common.Errors.{MissingType, UnexpectedLockImpl} import pipedsl.common.Locks.{General, LockGranularity, Specific} import pipedsl.common.Syntax.Latency.{Combinational, Latency, Sequential} import pipedsl.common.Syntax._ +import pipedsl.codegen.bsv.BluespecInterfaces object LockImplementation { @@ -31,6 +33,7 @@ object LockImplementation { private val dataType = TNamedType(Id("data")) private val handleType = TNamedType(Id("handle")) private val checkType = TNamedType(Id("checkHandle")) + private val maskType = TNamedType(Id("wmask")) //Lock Object Method Names private val canResName = "canRes" private val canResReadName = canResName + "_r" @@ -235,10 +238,10 @@ object LockImplementation { } } - def getWriteInfo(mem: Id, addr: Expr, inHandle: Option[Expr], data: Expr, portNum: Option[Int], isAtomic: Boolean): Option[MethodInfo] = { + def getWriteInfo(mem: Id, addr: Expr, inHandle: Option[Expr], data: Expr, writeMask: Option[Expr], portNum: Option[Int], isAtomic: Boolean): Option[MethodInfo] = { val interface = getLockImplFromMemTyp(mem) val (funTyp, latency) = getAccess(interface, Some(LockWrite), isAtomic).get - val args = getArgs(funTyp, Some(addr), inHandle, Some(data)) + val args = getArgs(funTyp, Some(addr), inHandle, Some(data), writeMask) val methodName = getAccessName(Some(LockWrite), isAtomic).v + toPortString(portNum) Some(MethodInfo(methodName, latency != Combinational, args)) } @@ -304,13 +307,14 @@ object LockImplementation { e } private def getArgs(fun: TFun, addr: Option[Expr] = None, - handle: Option[Expr] = None, data: Option[Expr] = None): List[Expr] = { + handle: Option[Expr] = None, data: Option[Expr] = None, writeMask: Option[Expr] = None): List[Expr] = { fun.args.foldLeft(List[Expr]())((l, argTyp) => { argTyp match { //TODO throw better exception if missing arg case t: TNamedType if t == dataType => l :+ data.get case t: TNamedType if t == addrType => l :+ addr.get case t: TNamedType if t == handleType => l :+ extractHandle(handle.get) + case t: TNamedType if t == maskType && writeMask.isDefined => l :+ writeMask.get case _ => l //should be unreachable TODO throw badly formatted type } }) @@ -430,6 +434,8 @@ object LockImplementation { //LSQ doesn't need a separate lock id so use this to differentiate def useUniqueLockId(): Boolean = true + def canSilentWrite(): Boolean = false + def getLockIdSize: Int = defaultLockHandleSize def getChkIdSize(lidSize: Int): Option[Int] = None @@ -492,6 +498,8 @@ object LockImplementation { val parent = super.getType TObject(queueLockName, List(), parent.methods ++ Map( + Id(writeName) -> (TFun(List(addrType, dataType, maskType), TVoid()), Combinational), + Id(atomicAccessName) -> (TFun(List(addrType), TVoid()), Combinational), Id(checkpointName) -> (TFun(List(), checkType), Sequential), Id(rollbackName) -> (TFun(List(checkType), TVoid()), Sequential), Id(abortName) -> (TFun(List(), TVoid()), Sequential) @@ -507,6 +515,7 @@ object LockImplementation { override def getModInstArgs(m: TMemType, szParams: List[Int]): List[Int] = List() + override def canSilentWrite(): Boolean = true //Checkpoint id must equal the lock id size override def getChkIdSize(lidSize: Int): Option[Int] = Some(lidSize) } diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 7e2d26ec..d1e167e6 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -670,7 +670,7 @@ object Syntax { } case class IMemRecv(mem: Id, handle: EVar, data: Option[EVar]) extends InternalCommand with LockInfoAnnotation //used for sequential memories that don't commit writes immediately but don't send a response - case class IMemWrite(mem: Id, addr: EVar, data: EVar, + case class IMemWrite(mem: Id, addr: EVar, data: EVar, writeMask: Option[Expr], inHandle: Option[EVar], outHandle: Option[EVar], isAtomic: Boolean) extends InternalCommand with LockInfoAnnotation case class ICheckLockOwned(mem: LockArg, inHandle: EVar, outHandle :EVar) extends InternalCommand with LockInfoAnnotation case class IReserveLock(outHandle: EVar, mem: LockArg) extends InternalCommand with LockInfoAnnotation diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index 970f9a07..24f25c9e 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -180,8 +180,13 @@ object Utilities { Set() }) case IMemRecv(_, handle, _) => Set(handle.id) - case IMemWrite(_, addr, data, inHandle, _, _) => - Set(addr.id, data.id).union(inHandle.map(h => Set(h.id)).getOrElse(Set())) + case IMemWrite(_, addr, data, writeMask, inHandle, _, _) => + Set(addr.id, data.id).union(inHandle.map(h => Set(h.id)).getOrElse(Set())) ++ ( + if (writeMask.isDefined) { + getUsedVars(writeMask.get) + } else { + Set() + }) case IRecv(handle, _, _) => Set(handle.id) case ISend(_, _, args) => args.map(a => a.id).toSet case IReserveLock(_, larg) => larg.evar match { diff --git a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala index 720cf2cd..f2d2bb15 100644 --- a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala +++ b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala @@ -4,6 +4,7 @@ package pipedsl.passes import pipedsl.common.Syntax._ import pipedsl.common.DAGSyntax.PStage import pipedsl.common.Errors.{UnexpectedExpr, UnexpectedType} +import pipedsl.common.LockImplementation import pipedsl.common.Utilities.flattenStageList import pipedsl.passes.Passes.StagePass @@ -77,12 +78,12 @@ class ConvertAsyncPass(modName: Id) extends StagePass[List[PStage]] { recv.portNum = c.portNum (send, recv) case _ :TMemType => - val write = IMemWrite(mem, index, data, inHandle, outHandle, isAtomic).setPos(e.pos) + val write = IMemWrite(mem, index, data, wm, inHandle, outHandle, isAtomic).setPos(e.pos) write.memOpType = e.memOpType write.granularity = e.granularity write.portNum = c.portNum (write, CEmpty()) - case TLockedMemType(TMemType(_, _, _, Latency.Asynchronous, _, _),_, _) => + case TLockedMemType(TMemType(_, _, _, Latency.Asynchronous, _, _),_, lock) if !lock.canSilentWrite() => val handle = freshMessage(mem) val send = IMemSend(handle, writeMask = wm, mem, Some(data), index, inHandle, outHandle, isAtomic) val recv = IMemRecv(mem, handle, None) @@ -95,8 +96,13 @@ class ConvertAsyncPass(modName: Id) extends StagePass[List[PStage]] { (send, recv) //if the memory is sequential we don't use handle since it //is assumed to complete at the end of the cycle - case TLockedMemType(_,_,_) => - val write = IMemWrite(mem, index, data, inHandle, outHandle, isAtomic).setPos(e.pos) + case TLockedMemType(TMemType(_, _, _, lat, _, _),_, lock) => + val newwm = wm match { + case _: Expr => wm + case _ if lat == Latency.Asynchronous => Some(EInt(1, 2, -1)) + case _ => None + } + val write = IMemWrite(mem, index, data, newwm, inHandle, outHandle, isAtomic).setPos(e.pos) write.memOpType = e.memOpType write.granularity = e.granularity write.portNum = c.portNum diff --git a/src/test/tests/exception/exn-recovery-spec.pdl b/src/test/tests/exception/exn-recovery-spec.pdl index edbd4553..45ac90c0 100644 --- a/src/test/tests/exception/exn-recovery-spec.pdl +++ b/src/test/tests/exception/exn-recovery-spec.pdl @@ -1,6 +1,6 @@ // exn-recovery-spec.pdl //Expect 5 Success, 1 Exception, 1 Success post recovery -exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { +exn-pipe cpu(pc :uint<16>)[acc :uint<8>[0](CheckpointQueue)] :uint<4> { spec_check(); start(acc); reserve(acc); @@ -12,7 +12,9 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { --- spec_check(); block(acc); - acc_val = acc[0]; + acc_val <- acc[0]; + --- + spec_check(); acc[0] <- acc_val + 1; --- spec_barrier(); @@ -53,7 +55,7 @@ except(arg: uint<4>): circuit { ti = memory(uint<8>, 16); - acc = register(uint<4>, 0); + acc = memory(uint<8>, 0); locked = CheckpointQueue(acc); c = new cpu[locked]; call c(u1<16>); diff --git a/src/test/tests/exception/exn-simple-chkp.pdl b/src/test/tests/exception/exn-simple-chkp.pdl new file mode 100644 index 00000000..5cce8ed1 --- /dev/null +++ b/src/test/tests/exception/exn-simple-chkp.pdl @@ -0,0 +1,32 @@ +// exn-simple.pdl +//Expect 5 Success, 1 Exception +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { + start(acc); + reserve(acc); + end(acc); + --- + block(acc); + acc_val = acc[0]; + acc[0] <- acc_val + 1; + call cpu(pc + 1); + --- + if(acc_val == 6) + { + throw(u0<4>); + } +commit: + release(acc); + print("no exn at PC == %d! with acc_val of %d", pc, acc_val); +except(arg :uint<4>): + print("exception at PC == %d! with arg: %d", pc, arg); + output(1); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 0); + locked = CheckpointQueue(acc); + c = new cpu[locked]; + call c(u1<16>); +} diff --git a/src/test/tests/exception/exn-simple-spec.pdl b/src/test/tests/exception/exn-simple-spec.pdl index d7b51727..074813f9 100644 --- a/src/test/tests/exception/exn-simple-spec.pdl +++ b/src/test/tests/exception/exn-simple-spec.pdl @@ -1,6 +1,6 @@ // exn-simple-spec.pdl //Expected Success -exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { +exn-pipe cpu(pc :uint<16>)[acc :uint<8>[0](CheckpointQueue)] :uint<4> { spec_check(); start(acc); reserve(acc); @@ -12,9 +12,11 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { --- spec_check(); block(acc); - acc_val = acc[0]; + acc_val <- acc[0]; + --- + spec_check(); acc[0] <- acc_val + 1; - if(acc_val == 6) + if(acc_val == u6<8>) { throw(u0<4>); } @@ -37,13 +39,17 @@ commit: print("no exn at PC == %d! with acc_val of %d", pc, acc_val); except(arg: uint<4>): print("exception at PC == %d! with arg: %d", pc, arg); + --- + exn_acc_val <- acc[0]; + --- + print(exn_acc_val); output(1); } circuit { ti = memory(uint<8>, 16); - acc = register(uint<4>, 0); + acc = memory(uint<8>, 0); locked = CheckpointQueue(acc); c = new cpu[locked]; call c(u1<16>); diff --git a/src/test/tests/exception/memInputs/acc b/src/test/tests/exception/memInputs/acc new file mode 100644 index 00000000..5b290d00 --- /dev/null +++ b/src/test/tests/exception/memInputs/acc @@ -0,0 +1 @@ +00000000 diff --git a/src/test/tests/risc-pipe/risc-pipe-pldi-5-stg.pdl b/src/test/tests/risc-pipe/risc-pipe-pldi-5-stg.pdl new file mode 100644 index 00000000..b8aa42d7 --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-pldi-5-stg.pdl @@ -0,0 +1,276 @@ +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + bool eq = arg1 == arg2; + bool lt = arg1 < arg2; + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + bool ltu = un1 < un2; + if (op == u0<3>) { //BEQ + return eq; + } else { + if (op == u1<3>) { //BNE + return !eq; + } else { + if (op == u4<3>) { //BLT + return lt; + } else { + if (op == u5<3>) { //BGE + return !lt; + } else { + if (op == u6<3>) { //BLTU + return ltu; + } else { + if (op == u7<3>) { //BGEU + return !ltu; + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe cpu(pc: int<32>)[rf: int<32>[5](BypassRF), imem: int<32>[32], dmem: int<32>[32]]: bool { + spec_check(); + start(imem); + uint<32> pcaddr = cast(pc, uint<32>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<32>); + --- + spec_barrier(); + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<32> immB = cast(immBTmp, int<32>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<32> immJR = cast(immJRTmp, int<32>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + start(rf); + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + bool useRf1 = (!isAui) && (!isLui); + int<32> alu_arg1_tmp = (isAui) ? (pc << 2) : 0<32>; + bool useRf2 = (!isAui) && (!isLui) && (!isStore) && (!isOpImm) && (!isLoad) && (!isJalr); + int<32> alu_arg2_tmp = (isAui || isLui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : ((isJalr) ? immJR : 0<32>))); + int<32> pcOff = ((isBranch) ? immB : immJ) >> 2; + --- + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + + int<32> alu_arg1 = (useRf1) ? rf1 : alu_arg1_tmp; + int<32> alu_arg2 = (useRf2) ? rf2 : alu_arg2_tmp; + bool take = br(funct3, alu_arg1, alu_arg2); + int<32> tmppc = pc + 1<32>; + if (!done) { + if ((isBranch && take) || isJal || isJalr) { + invalidate(s); + } else { + verify(s, tmppc); + }} else { + invalidate(s); + } + bool alu_flip = (isStore || isLoad || isAui || isLui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui || isLui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<32> linkpc = tmppc << 2; + int<32> rddata = (isJal || isJalr) ? linkpc : alu_res; + int<32> takePc = pc + pcOff; + split { + case: (isBranch) { + int<32> npc = (take) ? (takePc) : (tmppc); + } + case: (isJal) { + int<32> npc = takePc; + } + case: (isJalr) { + int<32> npc = alu_res >> 2; + } + default: { + int<32> npc = tmppc; + } + } + if ((!done)) { + if ((isBranch && take) || isJal || isJalr) { + call cpu(npc); + } + } + int<32> stdata = rf2; + --- + if (writerd && (!isLoad)) { + block(rf[rd]); + rf[rd] <- rddata; + } + uint<32> tmpaddr = cast(rddata, uint<32>); + uint<32> memaddr = (tmpaddr >> 2); + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<32> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<32> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (stdata << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd && isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + } + if (writerd) { + print("Writing %d to r%d", insnout, rd); + } + --- + if (writerd) { + release(rf[rd]); + } + if (done) { + output(true); + } +} + +circuit { + ti = memory(int<32>, 32); + td = memory(int<32>, 32); + rf = rflock BypassRF(int<32>, 5, 8); + c = new cpu[rf, ti, td]; + call c(0<32>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-exn-3.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-exn-3.pdl new file mode 100644 index 00000000..03a20ec8 --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn-3.pdl @@ -0,0 +1,392 @@ +// risc-pipe-spec-write.pdl +extern BHT { + method req(pc: int, skip: int, take: int): int; + method upd(pc: int, taken: bool): (); +} + +def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { + uint<32> mag1 = cast(mag(arg1), uint<32>); + uint<32> mag2 = cast(mag(arg2), uint<32>); + //MULHU => positive sign always + int<32> s1 = (op == u3<3>) ? 1<32> : sign(arg1); + //MULHU/MULHSU => positive sign always + int<32> s2 = (op >= u2<3>) ? 1<32> : sign(arg2); + int<64> magRes = cast((mag1 * mag2), int<64>); + int<64> m = (s1 == s2) ? (magRes) : -(magRes); + if (op == u0<3>) { //MUL + return m{31:0}; + } else { + return m{63:32}; + } +} + +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + if (op == u0<3>) { //BEQ + return (arg1 == arg2); + } else { + if (op == u1<3>) { //BNE + return (arg1 != arg2); + } else { + if (op == u4<3>) { //BLT + return (arg1 < arg2); + } else { + if (op == u5<3>) { //BGE + return (arg1 >= arg2); + } else { + if (op == u6<3>) { //BLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2); + } else { + if (op == u7<3>) { //BGEU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return(un1 >= un2); + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32>, cnt: uint<5>, retQuot: bool)[]: uint<32> { + uint<32> tmp = acc{30:0} ++ num{31:31}; + uint<32> na = (tmp >= denom) ? (tmp - denom) : (tmp); + uint<32> nq = (tmp >= denom) ? ((quot << 1){31:1} ++ u1<1>) : (quot << 1); + uint<32> nnum = num << 1; + bool done = (cnt == u31<5>); + if (done) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); + } +} + + +exn-pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT, csrf: int<32>[3]]: bool { + spec_check(); + start(imem); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool isMul = isMDiv && (funct3 < u4<3>); + bool isSystem = opcode == 0b1110011<7>; + bool isEcall = isSystem && (immI == 0<32>); + bool isMret = isSystem && (funct7 == u24<7>) && (rs2 == u2<5>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + spec_check(); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if (!done) { + if (notBranch) { + s2 <- s; + } else { + if (isBranch) { + s2 <- update(s, bht.req(pc, immB, 1<16>)); + } else { + s2 <- s; + invalidate(s); + }}} else { s2 <- s; invalidate(s); } + if (isEcall){ + throw(0, u8<4>); + } + if (isMret){ + throw(0, u3<4>); + } + start(rf); + if (!done && (notBranch || isBranch)) { checkpoint(rf); } + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + --- + spec_check(); + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + bool take = br(funct3, rf1, rf2); + if (isBranch) { + //divide by 4 b/c we count instructions not bytes + int<16> offpc = pc + (immB >> 2); + int<16> npc = (take) ? (offpc) : (pc + 1<16>); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + int<32> alu_arg1 = (isAui) ? ((0<16> ++ pc) << 2) : rf1; + int<32> alu_arg2 = (isAui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : rf2)); + bool alu_flip = (isStore || isLoad || isAui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<16> tmppc = pc + 1<16>; + int<32> linkpc = 0<16> ++ (tmppc << 2); + int<32> mulres = mul(rf1, rf2, funct3); + if (writerd && (!isLoad) && (!isDiv)) { + block(rf[rd]); + int<32> rddata = (isLui) ? immU : ((isMul) ? mulres : ((isJal || isJalr) ? linkpc : alu_res)); + rf[rd] <- rddata; + } else { + int<32> rddata = 0<32>; + } + --- + spec_barrier(); //delayed just to force writes to happen speculatively + if (!done) { + if (!notBranch) { + if (isBranch) { + verify(s2, npc) { bht.upd(pc, take) }; + } else { + call cpu(npc); + } + } else { + verify(s, pc + 1<16>); + } + } + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + bool invertRes <- isSignedDiv && (sdividend != sdivisor); + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } else { + bool invertRes <- false; + uint<32> udivout <- u0<32>; + } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + if (isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + if (isDiv) { + block(rf[rd]); + int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + int<32> insnout = divout; + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + }} + print("Writing %d to r%d", insnout, rd); + } + int<32> enable = csrf[4]; + --- + int<32> pending = csrf[3]; + int<32> masked_pending = pending | enable; + bool isExtInt = (masked_pending{11:11} == 1<1>); + if (isExtInt) { + throw(1, u11<4>); + } +commit: + if (writerd) { + release(rf[rd]); + } + if (done) { output(true); } +except(is_interrupt: uint<1>, exncode: uint<4>): // mepc = csrf[0], mtvec = csrf[1], mcause = csrf[2] + print("exception at PC == %d! with exncode: %d", pc, exncode); + start(csrf); // mip = csrf[3], mie = csrf[4], mstatus = csrf[5] + bool isStartContext = (is_interrupt == u1<1>) || exncode == u8<4>; + bool isRestoreContext = (exncode == u3<4>); + if (isStartContext) { + csrf[0] <- cast(pc, int<32>); // write to mepc + int<32> csrret = csrf[1]; // read from mtvec + int<16> npc = csrret{15:0}; + } else { if (isRestoreContext) { + int<32> csrret = csrf[0]; // read from mepc + int<16> npc = csrret{15:0} + 1; + } else { int<16> npc = pc + 1; }} + --- + int<32> oldmcause = csrf[2]; + bool wasHandlingInterrupt = oldmcause{31:31} == 1; + int<32> newmcause = cast(is_interrupt, int<1>) ++ cast(exncode, int<31>); + if (isStartContext) { + csrf[2] <- cast(newmcause, int<32>); // write to mcause + } else { if (isRestoreContext) { csrf[4] <- 1<32>; }} // enable mie + --- + if (isStartContext && (is_interrupt == u1<1>)) { + csrf[4] <- 0<32>; // disable mie + } else { if (isRestoreContext && wasHandlingInterrupt) { + int<32> oldmip = csrf[3]; + int<32> newmip = oldmip{31:12} ++ 0<1> ++ oldmip{10:0}; + csrf[3] <- newmip; // unset mip + }} + end(csrf); + --- + print("GOTO PC: %d", npc); + call cpu(npc); +} + +circuit { + ti = memory(int<32>, 16); + td = memory(int<32>, 16); + rf = rflock CheckpointRF(int<32>, 5, 64); + csrf = regfile(int<32>, 3); + div = new multi_stg_div[]; + b = new BHT<16>[](4); + c = new cpu[rf, ti, td, div, b, csrf]; + call c(0<16>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl index 4a8641b4..0c7cb83b 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl @@ -141,7 +141,7 @@ pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32> } -pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT]: bool { +pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16](CheckpointQueue), div: multi_stg_div, bht: BHT]: bool { spec_check(); start(imem); uint<16> pcaddr = cast(pc, uint<16>); @@ -255,6 +255,13 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16] } else { int<32> rddata = 0<32>; } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + start(dmem); + if (isLoad || isStore){ + reserve(dmem); + } + end(dmem); --- spec_barrier(); //delayed just to force writes to happen speculatively if (!done) { @@ -283,16 +290,16 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16] bool invertRes <- false; uint<32> udivout <- u0<32>; } - uint<32> tmpaddr = cast(alu_res, uint<32>); - uint<16> memaddr = (tmpaddr >> 2){15:0}; + uint<2> boff = cast(alu_res{1:0}, uint<2>); - start(dmem); split { - case: (isLoad) { - uint<16> raddr = memaddr; - int<32> wdata <- dmem[raddr]; + case: (isLoad) { + block(dmem); + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; } case: (isStore) { + block(dmem); uint<16> waddr = memaddr; //use bottom bits of data and place in correct offset //shift by boff*8 @@ -304,13 +311,12 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16] int<32> wdata <- 0<32>; } } - end(dmem); --- print("PC: %h", pc << 2); print("INSN: %h", insn); if (writerd) { if (isLoad) { - block(rf[rd]); + block(rf[rd]); int<32> insnout = maskLoad(wdata, funct3, boff); rf[rd] <- insnout; } else { @@ -327,7 +333,10 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16] --- if (writerd) { release(rf[rd]); - } + } + if (isStore || isLoad) { + release(dmem); + } if (done) { output(true); } } @@ -337,6 +346,7 @@ circuit { rf = rflock CheckpointRF(int<32>, 5, 64); div = new multi_stg_div[]; b = new BHT<16>[](4); - c = new cpu[rf, ti, td, div, b]; + lockedtd = CheckpointQueue(td); + c = new cpu[rf, ti, lockedtd, div, b]; call c(0<16>); } \ No newline at end of file