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 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/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/PrioFifo.bsv b/bscRuntime/libs/PrioFifo.bsv index e1f39878..61341409 100644 --- a/bscRuntime/libs/PrioFifo.bsv +++ b/bscRuntime/libs/PrioFifo.bsv @@ -1,3 +1,4 @@ +// PrioFifo.bsv package PrioFifo; import FIFOF :: *; @@ -11,7 +12,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 +37,7 @@ module mkNBFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); method Bool notEmpty(); return f.notEmpty(); endmethod - + method Action clear(); f.clear(); endmethod 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 2832991b..8dbc14e7 100644 --- a/bscRuntime/memories/Locks.bsv +++ b/bscRuntime/memories/Locks.bsv @@ -1,9 +1,11 @@ +// Locks.bsv package Locks; import FIFOF :: *; import Ehr :: *; import Vector :: *; import ConfigReg :: *; +import GetPut :: *; export LockId(..); export QueueLock(..); export CheckpointQueueLock(..); @@ -25,14 +27,16 @@ interface QueueLock#(type id); 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); @@ -47,25 +51,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 +77,7 @@ module mkQueueLock(QueueLock#(LockId#(d))); held.deq(); end endmethod - + //Reserves the lock and returns the associated id method ActionValue#(LockId#(d)) res1(); held.enq(nextId); @@ -81,12 +85,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 +98,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,40 +113,42 @@ 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 - + //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))); +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(); - + //for when you're doing not rollback (*fire_when_enabled*) rule updateEmpty; @@ -149,38 +156,54 @@ 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 Action abort(); + nextId[0] <= 0; + owner <= 0; + empty <= True; + wdata <= tagged Invalid; + endmethod 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 - + + //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 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 +212,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 +229,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 +252,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 +260,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 +275,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 +298,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 +309,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 +335,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 +345,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/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 2586f886..509cf149 100644 --- a/bscRuntime/memories/Memories.bsv +++ b/bscRuntime/memories/Memories.bsv @@ -1,3 +1,4 @@ +// Memories.bsv package Memories; import GetPut :: *; @@ -21,6 +22,7 @@ export AsyncMem(..); export AsyncMem2(..); export QueueLockCombMem(..); export CheckpointQueueLockCombMem(..); +export CheckpointQueueLockAsyncMem(..); export QueueLockAsyncMem(..); export QueueLockAsyncMem2(..); export BypassLockCombMem(..); @@ -37,6 +39,7 @@ export mkAsyncMem; export mkAsyncMem2; export mkQueueLockCombMem; export mkCheckpointQueueLockCombMem; +export mkCheckpointQueueLockAsyncMem; export mkQueueLockAsyncMem; export mkQueueLockAsyncMem2; export mkFAAddrLockCombMem; @@ -61,6 +64,22 @@ 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); + rf.upd(tpl_1(x), tpl_2(x)); + endmethod + endinterface); +endfunction + //Types of memories X Locks: //For the built-in types of locks & mems: @@ -75,9 +94,11 @@ 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); + method Action clear(); interface Client#(Tuple3#(Bit#(nsz), addr, elem), elem) bram_client; endinterface @@ -86,8 +107,9 @@ 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); method elem peekResp2(mid a); method Bool checkRespId2(mid a); @@ -102,7 +124,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); @@ -111,19 +133,27 @@ 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 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); 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; + 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 +162,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 +191,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 +200,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 +217,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)) @@ -209,6 +239,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; @@ -219,7 +250,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,11 +258,11 @@ 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); - // $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 @@ -239,41 +270,42 @@ 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 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,41 +338,58 @@ 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(); - + + 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) ); - + 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 - + + (*conflict_free = "freeResp, doClearRule"*) (*fire_when_enabled*) rule freeResp; valid[freeEntry][1] <= False; endrule + + (*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; + end + endrule + + method Action clear(); + doClear.wset(True); + endmethod method ActionValue#(MemId#(inflight)) req1(addr a, elem b, Bit#(n) wmask) if (okToRequest); toMem <= tuple3(wmask, a, b); @@ -348,43 +397,48 @@ module mkAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) _unused_) nextData <= tagged Valid head; 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 - + 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 +448,133 @@ 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 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; 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 +582,38 @@ 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_); +module mkCheckpointQueueLockCombMem(RegFile#(addr, elem) rf, CheckpointQueueLockCombMem#(addr, elem, LockId#(d), LockId#(d)) _unused_) +provisos(Bits#(Tuple2#(addr, elem), tuplsz)); - CheckpointQueueLock#(LockId#(d), LockId#(d)) l <- mkCheckpointQueueLock(); + + 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); return rf.sub(a); endmethod - + method Action write(addr a, elem b); - rf.upd(a, b); + l.write(tuple2(a, b)); endmethod - + method Bool canAtom_r1(addr a); return l.isEmpty; endmethod @@ -554,19 +621,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 +643,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 +651,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 +659,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 +667,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 +678,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 +686,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 +694,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 +702,104 @@ 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 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)); - + 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 +808,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 +837,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 +913,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 +934,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 +956,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 +975,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 +985,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 +1008,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 +1025,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 +1046,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 +1064,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 +1082,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; @@ -1023,8 +1114,12 @@ module mkLSQ(LSQ#(addr, elem, MemId#(inflight), n) _unused_) provisos method Action resp1(MemId#(inflight) i); endmethod - endinterface + method Action clear(); + //TODO determine if there's really something to do here - I don't think so + endmethod + endinterface + interface Client bram_client; interface Get request; method ActionValue#(Tuple3#(Bit#(n), addr, elem)) get(); @@ -1048,14 +1143,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 +1165,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 +1188,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 +1218,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/bscRuntime/memories/SpecialQueues.bsv b/bscRuntime/memories/SpecialQueues.bsv index ccb66dd5..f7aa3214 100644 --- a/bscRuntime/memories/SpecialQueues.bsv +++ b/bscRuntime/memories/SpecialQueues.bsv @@ -1,3 +1,4 @@ +// SpecialQueues.bsv package SpecialQueues; import Ehr :: *; @@ -51,17 +52,26 @@ 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(); - + RWire#(Bool) doClear <- mkRWireSBR(); + + (*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()); enq_data.wset(a); @@ -82,11 +92,11 @@ module mkNBFIFOF(FIFOF#(dtyp)) provisos (Bits#(dtyp, szdtyp)); method Bool notEmpty(); return f.notEmpty(); endmethod - + method Action clear(); - f.clear(); + doClear.wset(True); endmethod - + endmodule diff --git a/bscRuntime/memories/Speculation.bsv b/bscRuntime/memories/Speculation.bsv index faaa1822..3702903d 100644 --- a/bscRuntime/memories/Speculation.bsv +++ b/bscRuntime/memories/Speculation.bsv @@ -1,3 +1,4 @@ +// Speculation.bsv package Speculation; import Vector :: *; @@ -12,6 +13,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)); @@ -40,19 +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(); + 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/docs/exceptions.md b/docs/exceptions.md new file mode 100644 index 00000000..4e221901 --- /dev/null +++ b/docs/exceptions.md @@ -0,0 +1,45 @@ +# 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. + -- 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. + -- 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 (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 + implicit stuff about them into explicit things, like the calls to abort, and + a couple of registers that are used, such as the `args`. + 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. + +## 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. + diff --git a/examples/exn.pdl b/examples/exn.pdl new file mode 100644 index 00000000..4e478779 --- /dev/null +++ b/examples/exn.pdl @@ -0,0 +1,51 @@ +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; + start(acc); + acc_val = acc[]; + reserve(acc); + end(acc); + --- + if(div){ + if(imm == 0){ + uint<4> err_code = 1; + except(); + } + } + --- + if (done) + { + output acc_val; + } else + { + call cpu(pc + 1); + } + block(acc); + acc = acc_val + opcode; //this should do a real thing + --- +commit: + print("commit"); + release(acc); +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 diff --git a/src/test/tests/histogram/histogram_nested.sim b/examples/exn_output.pdl similarity index 100% rename from src/test/tests/histogram/histogram_nested.sim rename to examples/exn_output.pdl 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 new file mode 100644 index 00000000..30f62064 --- /dev/null +++ b/except-new.pdl @@ -0,0 +1,52 @@ +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; + } + case: (ex) + { + except(); + } + } + if (done) + { + output acc_val; + } else + { + call cpu(pc + 1); + } + end(acc); + --- +commit: + print("no exn here!"); +except: + print("exception!"); +} + + +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..f7c4dba1 --- /dev/null +++ b/insns.hex @@ -0,0 +1,4 @@ +13 //add 3 +16 //add 6 +22 //sub 2 +00 //terminate \ No newline at end of file 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 b8b94862..f9b4a011 100644 --- a/src/main/scala/pipedsl/Main.scala +++ b/src/main/scala/pipedsl/Main.scala @@ -1,9 +1,9 @@ +/* Main.scala */ 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 @@ -14,7 +14,6 @@ import pipedsl.passes._ import pipedsl.typechecker.TypeInferenceWrapper.TypeInference import pipedsl.typechecker._ - object Main { val logger: Logger = Logger("main") @@ -72,8 +71,10 @@ object Main { 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) + try { + val pinfo = new ProgInfo(prog) + MarkNonRecursiveModulePass.run(prog) //First: add lock regions + checkpoints, then do other things val inferredProg = new LockRegionInferencePass().run(prog) @@ -90,28 +91,29 @@ 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) lockChecker.check(recvProg, None) LockReleaseChecker.check(recvProg) + FinalblocksConstraintChecker.check(recvProg) val linChecker = new LinearExecutionChecker(ctx) linChecker.check(recvProg, None) val specChecker = new SpeculationChecker(ctx) specChecker.check(recvProg, None) val lock_prog = LockOpTranslationPass.run(recvProg) TimingTypeChecker.check(lock_prog, Some(basetypes)) + val exnTranslationPass = new ExnTranslationPass() + val exnprog = exnTranslationPass.run(lock_prog) 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/Parser.scala b/src/main/scala/pipedsl/Parser.scala index 7862312c..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,6 +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 | + 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)) } | @@ -317,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) } } @@ -368,6 +379,20 @@ 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[ExceptBlock] = positioned { + "except" ~> parens(repsep(iden ~ ":" ~ typ, ",")) ~ (":" ~> cmd) ^^ {case id ~ cmd => id match + { + case args => ExceptFull(args.map({ case id ~ _ ~ tp => id.setType(tp)}), cmd) + }} + } + + 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))} | posint ^^ {i => TBitWidthLen(i)} @@ -488,7 +513,11 @@ lazy val genericName :P[Id] = iden ^^ {i => Id(generic_type_prefix + i.v)} 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 => ModuleDef(i, ps, mods, rt, c._1, Some(c._2), c._3) } })("module") 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 4a690b80..bda66356 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala @@ -1,6 +1,8 @@ +/* BSVPrettyPrinter.scala */ 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 @@ -68,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 @@ -96,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 => { @@ -110,8 +112,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 @@ -127,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 @@ -139,6 +143,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 = { @@ -206,6 +211,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) => @@ -249,7 +256,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 59b58573..cbd24917 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 @@ -62,8 +63,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 +109,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 @@ -182,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) @@ -311,8 +316,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)) + } } @@ -452,7 +462,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 @@ -460,6 +470,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 @@ -482,6 +493,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 af445856..d1b72e35 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -1,12 +1,13 @@ +/* BluespecGeneration.scala */ package pipedsl.codegen.bsv -import BSVSyntax._ +import BSVSyntax.{BBOp, BEmpty, _} import pipedsl.common.DAGSyntax.{PStage, PipelineEdge} 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 @@ -20,13 +21,15 @@ 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" 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, 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", @@ -397,7 +400,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 @@ -414,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) => { @@ -549,6 +553,7 @@ object BluespecGeneration { } private var stgSpecOrder: Int = 0 + /** * Given a pipeline stage and the necessary edge info, * generate a BSV module definition. @@ -568,8 +573,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) List(execRule, killRule.get) else List(execRule) + val killRule = getStageKillRules(stg, mod.maybeSpec, is_excepting(mod)) + val rules = if (killRule.isEmpty) List(execRule) else List(execRule) ++ killRule stgSpecOrder = 0 translator.setVariablePrefix("") (sBody, rules) @@ -590,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) } @@ -605,23 +616,45 @@ 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) - 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)) - } + private def getStageKillRules(stg: PStage, is_spec: Boolean, is_excepting: Boolean): List[BRuleDef] = { + val misspecKillConds = getMisspecKillConds(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)" + "%t"), + List(BTime)) + } else { BEmpty } + val deqStmts = getEdgeQueueStmts(stg, stg.inEdges) ++ getRecvCmds(stg.getCmds) + 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 + resultingKillRules + } + + private def getExnKillConds(cmds: Iterable[Command], disjoint_cond: Boolean): List[BExpr] = { + cmds.foldLeft(List[BExpr]())((l, c) => c match { + case ICheckExn() => { + if (disjoint_cond) { + l :+ BUOp("!", globalExnFlag) + } else { + l :+ globalExnFlag + } + } + case _ => l + }) } - private def getKillConds(cmds: Iterable[Command]): List[BExpr] = { + 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)) @@ -632,7 +665,7 @@ object BluespecGeneration { bsInts.getSpecCheck(specTable, getSpecIdVal, stgSpecOrder)))) //also need these in case we're waiting on responses we need to dequeue case ICondCommand(cond, cs) => - val condconds = getKillConds(cs) + val condconds = getMisspecKillConds(cs) if (condconds.nonEmpty) { val nestedConds = condconds.tail.foldLeft(condconds.head)((exp, n) => { BBOp("&&", exp, n) @@ -684,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) @@ -702,8 +735,8 @@ object BluespecGeneration { 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) + //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)) @@ -814,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 @@ -886,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 } @@ -917,12 +960,16 @@ 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]() @@ -1011,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 @@ -1057,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), @@ -1206,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 @@ -1214,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) @@ -1257,6 +1304,22 @@ object BluespecGeneration { } 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)) ) @@ -1357,6 +1420,9 @@ object BluespecGeneration { case CAssign(_, _) => None case CExpr(_) => None case CEmpty() => None + 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) @@ -1401,6 +1467,49 @@ 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 ICondCommand(_, cs) => found || cs.contains(ICheckExn()) + case ICheckExn() => 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 = Set[PStage](st) + var visited = Set[PStage]() + var currVisit = st + while(unvisited.nonEmpty){ + currVisit = unvisited.head + visited += currVisit + currVisit.inEdges.foreach(e => { + 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 b0f62ff7..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._ @@ -91,6 +92,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" @@ -98,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" @@ -224,6 +230,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 +282,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. @@ -285,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 = { @@ -307,6 +326,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 @@ -314,6 +336,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 +360,10 @@ class BluespecInterfaces() { BMethodInvoke(st, specFreeName, List(h)) } + def getSpecClear(st: BVar): BExpr = { + BMethodInvoke(st, specClearName, List()); + } + def getSpecCheck(st: BVar, h: BExpr, order: Int): BExpr = { BMethodInvoke(st, specCheckName, List(h, BUnsizedInt(order))) } @@ -363,6 +390,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/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 36d0efea..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 @@ -28,7 +29,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/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 16a049ec..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} @@ -213,4 +214,36 @@ 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) + ) + + 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) + ) + + 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) + ) + + 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 3d452493..083b591d 100644 --- a/src/main/scala/pipedsl/common/LockImplementation.scala +++ b/src/main/scala/pipedsl/common/LockImplementation.scala @@ -1,9 +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 { @@ -30,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" @@ -61,6 +65,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 +152,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] = { @@ -229,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)) } @@ -279,6 +288,17 @@ 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 + 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") { @@ -287,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 } }) @@ -413,8 +434,10 @@ 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): Int = defaultChkHandleSize + def getChkIdSize(lidSize: Int): Option[Int] = None def getTypeArgs(szParams: List[Int]): List[Int] = List() @@ -443,7 +466,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), @@ -469,14 +492,17 @@ 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 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(rollbackName) -> (TFun(List(checkType), TVoid()), Sequential), + Id(abortName) -> (TFun(List(), TVoid()), Sequential) ) ) } @@ -489,12 +515,13 @@ 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): 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 @@ -562,6 +589,7 @@ object LockImplementation { override def shortName: String = "BypassQueue" override def getModuleName(m: TMemType): String = "BypassLockCombMem" + } /** @@ -609,7 +637,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) } /** @@ -651,7 +679,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 @@ -662,6 +691,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 { 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 0fd50fdc..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} @@ -38,12 +39,31 @@ class PrettyPrinter(output: Option[File]) { printCmdToString(f.body, 2) + "\n}") } - def printModule(m: ModuleDef): Unit = { + def printModule(m :ModuleDef) : Unit = + 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" + printCmdToString(m.body, 2) + "\n}") } + 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_blk.get, 2) + "\n" + + printExnBlock(m.except_blk, 2) + "\n}" + ) + } + + def printExnBlock(block: Syntax.ExceptBlock, ident: Int): String = block match + { + case ExceptEmpty() => "" + 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}") def printCircuitToString(c: Circuit, indent: Int = 0): String = { @@ -108,6 +128,18 @@ 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).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.ICheckExn() => ins + "clearStgOnExn();" + 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" } } @@ -134,6 +166,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/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 2cf88a95..d1e167e6 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._ @@ -39,6 +40,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 @@ -643,10 +647,16 @@ 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 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 case class IUpdate(specId: Id, value: EVar, originalSpec: EVar) extends InternalCommand case class ICheck(specId: Id, value: EVar) extends InternalCommand @@ -660,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 @@ -688,28 +698,73 @@ object Syntax { lat :Latency ) 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 + sealed trait ExceptBlock extends Positional with HasCopyMeta + { + 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) + } + + + case class ExceptEmpty() extends ExceptBlock + { + 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(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 + } + + + 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 ExceptionAnnotation with HasCopyMeta { override val copyMeta: HasCopyMeta => ModuleDef = { case from :ModuleDef => maybeSpec = from.maybeSpec + isExcepting = from.isExcepting isRecursive = from.isRecursive pos = from.pos 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 + { + case ExceptEmpty() => false + case _ :ExceptFull => true + } + case class Param(name: Id, typ: Type) extends Positional 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 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 73d072ad..24f25c9e 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} @@ -83,6 +84,8 @@ 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(args) => args.foldLeft(Set[Id]())((set, arg) => set.union(getUsedVars(arg))) + case CCatch(m, c) => Set() case _ => throw UnexpectedCommand(c) } @@ -177,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 { @@ -196,6 +204,11 @@ object Utilities { case None => Set() }) case ILockNoOp(_) => 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)) @@ -209,6 +222,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() } /** @@ -680,10 +694,11 @@ 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 = 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= { diff --git a/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala b/src/main/scala/pipedsl/passes/AddCheckpointHandlesPass.scala index 419c4186..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._ @@ -26,7 +27,13 @@ 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) + 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/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 85bc641a..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 @@ -22,7 +23,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..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 911134f4..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._ @@ -41,7 +42,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,6 +115,9 @@ class CanonicalizePass() extends CommandPass[Command] with ModulePass[ModuleDef] case CLockEnd(_) => c case CLockOp(_, _, _, _, _) => c 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 new file mode 100644 index 00000000..950c8790 --- /dev/null +++ b/src/main/scala/pipedsl/passes/CheckExcepting.scala @@ -0,0 +1,43 @@ +/* CheckExcepting.scala */ +//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/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..f2d2bb15 100644 --- a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala +++ b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala @@ -1,8 +1,10 @@ +/* ConvertAsyncPass.scala */ 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 @@ -76,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) @@ -94,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/main/scala/pipedsl/passes/ExnTranslationPass.scala b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala new file mode 100644 index 00000000..45271459 --- /dev/null +++ b/src/main/scala/pipedsl/passes/ExnTranslationPass.scala @@ -0,0 +1,169 @@ +/* ExnTranslationPass.scala */ +package pipedsl.passes + +import pipedsl.common.Syntax._ +import pipedsl.passes.Passes.{ModulePass, ProgPass} +import pipedsl.typechecker.BaseTypeChecker.replaceNamedType + +class ExnTranslationPass extends ModulePass[ModuleDef] with ProgPass[Prog]{ + private var exnArgCallMap = Map[Int, EVar]() + private var exnArgApplyMap = Map[Id, EVar]() + + private val localExnFlag = EVar(Id("_localExnFlag")) + + override def run(m: ModuleDef): ModuleDef = + { + 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 + } + } + + override def run(p: Prog): Prog = p.copy(moddefs = p.moddefs.map(m => run(m).copyMeta(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 => { + 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 + case _ => + arg_count += 1 + } + }) + case ExceptEmpty() => CEmpty() + } + + m.copy(body = CSeq(ICheckExn(), convertBody(m.body)), commit_blk = m.commit_blk, except_blk = m.except_blk).copyMeta(m) + } + + def convertBody(c: Command): Command = { + c match { + 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, convertBody(c.body))) + CSplit(newCases, convertBody(default)).copyMeta(c) + case CExcept(args) => + val setLocalErrFlag = CAssign(localExnFlag, EBool(true)).copyMeta(c) + var arg_count = 0 + val setArgs: Command = args.foldLeft[Command](CSeq(setLocalErrFlag, CEmpty()))((c, arg) => { + arg.typ match { + case Some(t: Type) => + val translatedVar = exnArgCallMap.getOrElse(arg_count, EVar(Id("_Undefined_"))) + val setCurrArg = CAssign(translatedVar, arg).copyMeta(c) + arg_count += 1 + CSeq(c, setCurrArg).copyMeta(c) + case _ => c + } + }) + setArgs + case _ => c + } + } + + def convertExnArgsId(c: Command): Command = { + c match { + case CSeq(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 = 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)).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 { + case EVar(id) => + val newv = exnArgApplyMap.getOrElse(id, arg).setPos(e.pos) + l :+ newv + case _ => l :+ arg + } + }) + EApp(func, newArgs).setPos(e.pos) + } + case ECall(mod, name, args, isAtomic) => { + val newArgs = args.foldLeft(List[Expr]())((l, arg) => { + arg match { + case EVar(id) => + val newv = exnArgApplyMap.getOrElse(id, arg).setPos(e.pos) + l :+ newv + case _ => l :+ arg + } + }) + ECall(mod, name, newArgs, isAtomic).setPos(e.pos) + } + case ECast(ctyp, e) => ECast(ctyp, convertExnArgsId(e)).setPos(e.pos) + case EVar(id) => exnArgApplyMap.getOrElse(id, e).setPos(e.pos) + case _ => e + } + } + + 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) => c + case ExceptEmpty() => CEmpty() + } + + 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 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 = 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 ebd4331a..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._ @@ -62,13 +63,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)) - 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/LockRegionInferencePass.scala b/src/main/scala/pipedsl/passes/LockRegionInferencePass.scala index b80be63e..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 @@ -38,7 +39,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 +52,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..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._ @@ -25,7 +26,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/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 9e52c8bb..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} @@ -22,7 +23,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/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 e5bdec63..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._ @@ -13,7 +14,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..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} @@ -24,7 +25,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 = 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/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 4e29c450..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._ @@ -95,7 +96,16 @@ 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) + 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 + } + }) + m.except_blk.foreach(checkCommand(m.name, _, exnenv)) + } outEnv } @@ -391,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) { @@ -460,6 +471,7 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { }) tenv case CEmpty() => tenv + case CExcept(arg) => arg.foreach(checkExpression(_, tenv, None)); tenv case _ => throw UnexpectedCommand(c) } 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 new file mode 100644 index 00000000..6997aaf4 --- /dev/null +++ b/src/main/scala/pipedsl/typechecker/FinalblocksConstraintChecker.scala @@ -0,0 +1,107 @@ +/* FinalblocksConstraintChecker.scala */ +package pipedsl.typechecker + +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 + +object FinalblocksConstraintChecker { + + 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(_, c) => + if(!checkExBody(m.body)) throw MustThrowWithExnPipe(c.pos) + checkCommit(m.commit_blk.get) + checkExceptingBlock(c) + } + } + + private sealed trait ExnStatus + private case object NonExn extends ExnStatus + private case object PreCall extends ExnStatus + private case object PostCall extends ExnStatus + + + 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 after_call(e :ExnStatus) = e match { + case NonExn => NonExn + case _ => PostCall + } + + + 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.foldLeft(false) { (acc, co) => acc || checkExBody(co.body) } + case CExcept(_) => true + case _ => false + } + + private def checkExceptingBlock(c :Command) :Unit = checkNoThrow(c, PreCall) + + 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)) + 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 + } + } +} 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 3eadefa4..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.{ @@ -22,6 +23,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 +42,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 +96,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 +156,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..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} @@ -62,32 +63,40 @@ 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) + //TODO - Exn : add new rule +// 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 +105,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 +292,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/LockOperationTypeChecker.scala b/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala index 541dac5b..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} @@ -44,7 +45,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 d82b90f4..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} @@ -14,6 +15,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,11 +35,17 @@ object LockRegionChecker extends TypeChecks[Id, LockState] { case _ => throw UnexpectedCase(m.pos) }) - val finalStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv) + 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.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 _ => () + })) + env //no change to lock map after checking module } @@ -91,7 +99,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 +109,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 +147,5 @@ object LockRegionChecker extends TypeChecks[Id, LockState] { case _ => () } - override def checkCircuit(c: Circuit, env: Environment[Id, LockState]): Environment[Id, LockState] = env } 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 240ac510..9a5857d0 100644 --- a/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockWellformedChecker.scala @@ -1,7 +1,9 @@ +/* LockWellformedChecker.scala */ 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 +42,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/PortChecker.scala b/src/main/scala/pipedsl/typechecker/PortChecker.scala index 1de95609..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} @@ -62,7 +63,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 = if (is_excepting(m)) { checkPipe(m.except_blk.get, port_com) } else port_com; if(port_warn) port_map.getMappedKeys().foreach(mem => { 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 7847e507..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._ @@ -35,18 +36,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 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 } /** - * 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) = @@ -230,6 +231,9 @@ object TimingTypeChecker extends TypeChecks[Id, Type] { checkExpr(exp, vars) (vars, nextVars) case Syntax.CEmpty() => (vars, nextVars) + case CExcept(arg) => + arg.foreach(checkExpr(_, vars)) + (vars, nextVars) case CPrint(args) => args.foreach(a => { checkExpr(a, vars) @@ -328,8 +332,8 @@ object TimingTypeChecker extends TypeChecks[Id, Type] { //calling another pipe case None => Asynchronous } - case EVar(id) => if(!vars(id) && isRhs) { - 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 88d56d5d..d32592e0 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} @@ -7,7 +8,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._ @@ -187,7 +188,6 @@ object TypeInferenceWrapper } - def checkProgram(p: Prog): Prog = { val extEnv = p.exts.foldLeft[Environment[Id, Type]](TypeEnv())((env, ext) => { @@ -208,7 +208,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 @@ -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) @@ -239,10 +240,23 @@ 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, _, 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 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) + 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) + //TODO - EXN: 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))) val new_input = newMod.inputs.map(p => p.typ) val new_mod_tps = newMod.modules.map(m => replaceNamedType(m.typ, env)) @@ -345,6 +359,8 @@ 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) val tempSub = compose_subst(sub, s) 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 new file mode 100644 index 00000000..979f9ef7 --- /dev/null +++ b/src/test/scala/pipedsl/ExceptionSuite.scala @@ -0,0 +1,31 @@ +/* ExceptionSuite.scala */ +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/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..96c570b6 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 @@ -39,5 +40,6 @@ class RiscSuite extends AnyFunSuite { 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/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/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 new file mode 100644 index 00000000..45ac90c0 --- /dev/null +++ b/src/test/tests/exception/exn-recovery-spec.pdl @@ -0,0 +1,62 @@ +// exn-recovery-spec.pdl +//Expect 5 Success, 1 Exception, 1 Success post recovery +exn-pipe cpu(pc :uint<16>)[acc :uint<8>[0](CheckpointQueue)] :uint<4> { + spec_check(); + start(acc); + reserve(acc); + checkpoint(acc); + end(acc); + --- + spec_check(); + s <- speccall cpu(pc + 1); + --- + spec_check(); + block(acc); + acc_val <- acc[0]; + --- + spec_check(); + acc[0] <- acc_val + 1; + --- + spec_barrier(); + if(acc_val == 6) + { + invalidate(s); + throw(u0<4>); + } else { + if(acc_val == 3) + { + invalidate(s); + call cpu(pc + 3); + } else { + if(acc_val == 9){ + invalidate(s); + output(0); + } else { + verify(s, pc + 1); + } + } + } +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); + start(acc); + reserve(acc); + end(acc); + --- + block(acc); + acc[0] <- 9; + --- + release(acc); + call cpu(pc + 1); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = memory(uint<8>, 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..ed62abc2 --- /dev/null +++ b/src/test/tests/exception/exn-recovery.pdl @@ -0,0 +1,51 @@ +// 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); + reserve(acc); + end(acc); + --- + block(acc); + acc_val = acc[0]; + acc[0] <- acc_val + 1; + bool done = pc == u16<16>; + if (!done) { + call cpu(pc + 1); + } + --- + 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); +except(arg: uint<4>): + print("exception at PC == %d! with arg: %d", pc, arg); + start(acc); + reserve(acc); + end(acc); + --- + block(acc); + acc[0] <- 9; + --- + release(acc); + call cpu(pc + 5); +} + + +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.temp b/src/test/tests/exception/exn-risc-pipe-basic.pdl.temp new file mode 100644 index 00000000..5ca3ffe7 --- /dev/null +++ b/src/test/tests/exception/exn-risc-pipe-basic.pdl.temp @@ -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-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 new file mode 100644 index 00000000..074813f9 --- /dev/null +++ b/src/test/tests/exception/exn-simple-spec.pdl @@ -0,0 +1,56 @@ +// exn-simple-spec.pdl +//Expected Success +exn-pipe cpu(pc :uint<16>)[acc :uint<8>[0](CheckpointQueue)] :uint<4> { + spec_check(); + start(acc); + reserve(acc); + checkpoint(acc); + end(acc); + --- + spec_check(); + s <- speccall cpu(pc + 1); + --- + spec_check(); + block(acc); + acc_val <- acc[0]; + --- + spec_check(); + acc[0] <- acc_val + 1; + if(acc_val == u6<8>) + { + throw(u0<4>); + } + --- + spec_barrier(); + if(acc_val == 2) + { + invalidate(s); + call cpu(pc + 3); + } else { + if(acc_val == 8){ + invalidate(s); + output(0); + } else { + verify(s, pc + 1); + } + } +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); + --- + exn_acc_val <- acc[0]; + --- + print(exn_acc_val); + output(1); +} + + +circuit { + ti = memory(uint<8>, 16); + 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.pdl b/src/test/tests/exception/exn-simple.pdl new file mode 100644 index 00000000..5cce8ed1 --- /dev/null +++ b/src/test/tests/exception/exn-simple.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/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/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-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-recovery-spec.typechecksol b/src/test/tests/exception/solutions/exn-recovery-spec.typechecksol new file mode 100644 index 00000000..9fb4ec93 --- /dev/null +++ b/src/test/tests/exception/solutions/exn-recovery-spec.typechecksol @@ -0,0 +1 @@ +Passed \ No newline at end of file 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..d0004bba --- /dev/null +++ b/src/test/tests/exception/solutions/exn-recovery.simsol @@ -0,0 +1,12 @@ +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 == 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/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 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-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-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-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-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-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 new file mode 100644 index 00000000..28726b2d --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn.pdl @@ -0,0 +1,476 @@ +// 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..0c7cb83b 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): (); @@ -140,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>); @@ -254,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) { @@ -282,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 @@ -303,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 { @@ -326,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); } } @@ -336,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 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/.#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/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 new file mode 100644 index 00000000..11330731 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-basic.pdl @@ -0,0 +1,29 @@ +// exn-basic.pdl +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..cf01b48c --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-end-after-call.pdl @@ -0,0 +1,36 @@ +// 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); + --- + 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..1dc7090d --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-release-main.pdl @@ -0,0 +1,29 @@ +// 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); + --- + 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..804b2641 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-throw-commit.pdl @@ -0,0 +1,30 @@ +// 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); + --- + 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..38b9e0c2 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-throw-except.pdl @@ -0,0 +1,30 @@ +// 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); + --- + 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..a8ba6b14 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-throw-normal.pdl @@ -0,0 +1,24 @@ +// exn-no-throw-normal.pdl +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..757be875 --- /dev/null +++ b/src/test/tests/typecheckTests/exn-no-unlocked-write-main.pdl @@ -0,0 +1,33 @@ +// 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; + 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/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/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 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();