From 6cc3a76607461e46cc5cea709c0ddfdf4c0b81ad Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 25 Oct 2023 13:25:18 -0400 Subject: [PATCH] fix chkp + some ad hoc stuff --- bscRuntime/memories/Locks.bsv | 4 +- bscRuntime/memories/Memories.bsv | 51 ++- .../codegen/bsv/BSVPrettyPrinter.scala | 6 +- .../scala/pipedsl/codegen/bsv/BSVSyntax.scala | 6 +- .../codegen/bsv/BluespecGeneration.scala | 10 +- .../pipedsl/common/LockImplementation.scala | 15 +- src/main/scala/pipedsl/common/Syntax.scala | 2 +- src/main/scala/pipedsl/common/Utilities.scala | 9 +- .../pipedsl/passes/ConvertAsyncPass.scala | 14 +- .../tests/exception/exn-recovery-spec.pdl | 8 +- src/test/tests/exception/exn-simple-chkp.pdl | 32 ++ src/test/tests/exception/exn-simple-spec.pdl | 14 +- src/test/tests/exception/memInputs/acc | 1 + .../tests/risc-pipe/risc-pipe-pldi-5-stg.pdl | 276 ++++++++++++ .../tests/risc-pipe/risc-pipe-spec-exn-3.pdl | 392 ++++++++++++++++++ .../tests/risc-pipe/risc-pipe-spec-write.pdl | 32 +- 16 files changed, 833 insertions(+), 39 deletions(-) create mode 100644 src/test/tests/exception/exn-simple-chkp.pdl create mode 100644 src/test/tests/exception/memInputs/acc create mode 100644 src/test/tests/risc-pipe/risc-pipe-pldi-5-stg.pdl create mode 100644 src/test/tests/risc-pipe/risc-pipe-spec-exn-3.pdl diff --git a/bscRuntime/memories/Locks.bsv b/bscRuntime/memories/Locks.bsv index 4c9af97c..8dbc14e7 100644 --- a/bscRuntime/memories/Locks.bsv +++ b/bscRuntime/memories/Locks.bsv @@ -159,8 +159,8 @@ module mkCheckpointQueueLock(Put#(winfo) mem, CheckpointQueueLock#(LockId#(d), L method Action abort(); nextId[0] <= 0; - owner <= 0; - empty <= True; + owner <= 0; + empty <= True; wdata <= tagged Invalid; endmethod diff --git a/bscRuntime/memories/Memories.bsv b/bscRuntime/memories/Memories.bsv index 28188d94..509cf149 100644 --- a/bscRuntime/memories/Memories.bsv +++ b/bscRuntime/memories/Memories.bsv @@ -22,6 +22,7 @@ export AsyncMem(..); export AsyncMem2(..); export QueueLockCombMem(..); export CheckpointQueueLockCombMem(..); +export CheckpointQueueLockAsyncMem(..); export QueueLockAsyncMem(..); export QueueLockAsyncMem2(..); export BypassLockCombMem(..); @@ -38,6 +39,7 @@ export mkAsyncMem; export mkAsyncMem2; export mkQueueLockCombMem; export mkCheckpointQueueLockCombMem; +export mkCheckpointQueueLockAsyncMem; export mkQueueLockAsyncMem; export mkQueueLockAsyncMem2; export mkFAAddrLockCombMem; @@ -62,6 +64,14 @@ function Bool isNewer(UInt#(sz) a, UInt#(sz) b, UInt#(sz) h); return !isOlder(a, b, h); endfunction +function Put#(Tuple3#(Bit#(nsz), addr, elem)) asyncMemToPut (AsyncMem#(addr, elem, MemId#(inflight), nsz) amem); + return (interface Put; + method Action put(Tuple3#(Bit#(nsz), addr, elem) x); + amem.silentReq1(tpl_2(x), tpl_3(x), tpl_1(x)); + endmethod + endinterface); +endfunction + function Put#(Tuple2#(addr, elem)) rfToPut (RegFile#(addr, elem) rf); return (interface Put; method Action put(Tuple2#(addr, elem) x); @@ -84,6 +94,7 @@ endinterface interface AsyncMem#(type addr, type elem, type mid, numeric type nsz); method ActionValue#(mid) req1(addr a, elem b, Bit#(nsz) wmask); + method Action silentReq1(addr a, elem b, Bit#(nsz) wmask); method elem peekResp1(mid a); method Bool checkRespId1(mid a); method Action resp1(mid a); @@ -130,6 +141,14 @@ interface CheckpointQueueLockCombMem#(type addr, type elem, type id, type cid); method Action atom_w(addr a, elem b); endinterface +interface CheckpointQueueLockAsyncMem#(type addr, type elem, type rid, numeric type nsz, type id, type cid); + interface AsyncMem#(addr, elem, rid, nsz) mem; + interface CheckpointQueueLock#(id, cid, Tuple3#(Bit#(nsz), addr, elem)) lock; + method Action write(addr a, elem b, Bit#(nsz) wmask); + method Bool canAtom1(addr a); + method ActionValue#(rid) atom_req1(addr a, elem b, Bit#(nsz) wmask); +endinterface + interface QueueLockAsyncMem#(type addr, type elem, type rid, numeric type nsz, type lid); interface AsyncMem#(addr, elem, rid, nsz) mem; interface QueueLock#(lid) lock; @@ -243,7 +262,7 @@ module mkBramPort#(parameter Bool init, parameter String file)(BramPort#(addr, e interface Server bram_server; interface Put request; method Action put (Tuple3#(Bit#(nsz), addr, elem) req); - // $display("Sending request %t", $time()); + //$display("Sending request %t %d %d ", $time(), tpl_1(req), tpl_3(req)); p.put(tpl_1(req), tpl_2(req), tpl_3(req)); doRead <= True; endmethod @@ -251,6 +270,7 @@ module mkBramPort#(parameter Bool init, parameter String file)(BramPort#(addr, e interface Get response; method ActionValue#(elem) get(); + //$display("Returning data %t %d", nextData); return nextData; endmethod endinterface @@ -378,6 +398,11 @@ module mkAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) _unused_) return head; endmethod + method Action silentReq1(addr a, elem b, Bit#(n) wmask) if (okToRequest); + toMem <= tuple3(wmask, a, b); + head <= head + 1; + endmethod + method elem peekResp1(MemId#(inflight) a); return outData[a][1]; endmethod @@ -681,6 +706,30 @@ module mkDMAddrLockCombMem(RegFile#(addr, elem) rf, AddrLockCombMem#(addr, elem, interface lock = l; endmodule +module mkCheckpointQueueLockAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), nsz) amem, CheckpointQueueLockAsyncMem#(addr, elem, MemId#(inflight), nsz, LockId#(d), LockId#(d)) _unused_) +provisos(Bits#(Tuple3#(Bit#(nsz), addr, elem), tuplsz)); + + Put#(Tuple3#(Bit#(nsz), addr, elem)) doWrite = asyncMemToPut(amem); + CheckpointQueueLock#(LockId#(d), LockId#(d), Tuple3#(Bit#(nsz), addr, elem)) l <- mkCheckpointQueueLock(doWrite); + + interface lock = l; + interface mem = amem; + + method Action write(addr a, elem b, Bit#(nsz) wmask); + l.write(tuple3(wmask, a, b)); + endmethod + + method Bool canAtom1(addr a); + return l.isEmpty; + endmethod + + method ActionValue#(MemId#(inflight)) atom_req1(addr a, elem b, Bit#(nsz) wmask); + let r <- amem.req1(a, b, wmask); + return r; + endmethod + +endmodule + module mkQueueLockAsyncMem(AsyncMem#(addr, elem, MemId#(inflight), n) amem, QueueLockAsyncMem#(addr, elem, MemId#(inflight), n, LockId#(d)) _unused_) provisos(Bits#(addr, szAddr), Bits#(elem, szElem)); diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala index c1274a1a..bda66356 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVPrettyPrinter.scala @@ -2,6 +2,7 @@ package pipedsl.codegen.bsv import java.io.{File, FileOutputStream, OutputStreamWriter, Writer} +import java.math.BigInteger import pipedsl.codegen.bsv.BSVSyntax._ import pipedsl.common.Errors.BaseError @@ -69,7 +70,7 @@ object BSVPrettyPrinter { case BInteger() => "Integer" } - private def toIntString(base: Int, value: Int): String = base match { + private def toIntString(base: Int, value: Int, bits: Int): String = base match { case 16 => "h" + value.toHexString case 10 => "d" + value.toString case 8 => "o" + value.toOctalString @@ -97,7 +98,7 @@ object BSVPrettyPrinter { "False" } case BUnsizedInt(v) => v.toString - case BIntLit(v, base, bits) => bits.toString + "'" + toIntString(base, v) + case BIntLit(v, base, bits) => bits.toString + "'" + toIntString(base, v, bits) case BStringLit(v) => "\"" + v + "\"" case BStructLit(typ, fields) => val fieldStr = fields.keys.map(k => { @@ -129,6 +130,7 @@ object BSVPrettyPrinter { val argstring = args.map(a => toBSVExprStr(a)).mkString(", ") mkExprString(name, "(", argstring, ")") case BMethodInvoke(mod, method, args) => + println(mod, method, args) val argstring = args.map(a => toBSVExprStr(a)).mkString(", ") val argStringFull = if (argstring.isEmpty) "" else "(" + argstring + ")" toBSVExprStr(mod) + "." + method + argStringFull diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index 89c9c0c4..cbd24917 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -183,7 +183,11 @@ object BSVSyntax { } def toExpr(e: Expr): BExpr = e match { - case EInt(v, base, bits) => BIntLit(v, base, bits) + case EInt(v, base, bits) => bits match { + case -1 if v == 0 => BZero + case -1 if v == 1 => BAllOnes + case _ => BIntLit(v, base, bits) + } // TODO - EXN: Very ad-hoc stuff.. need Fix case EBool(v) => BBoolLit(v) case EString(v) => BStringLit(v) case eu@EUop(_, _) => translateUOp(eu) diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index 1f4cd9da..d1b72e35 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -717,7 +717,7 @@ object BluespecGeneration { } else { l } - case im@IMemWrite(mem, addr, data, _, _, isAtomic) if isAtomic => + case im@IMemWrite(mem, addr, data, writeMask, _, _, isAtomic) if isAtomic => val methodInfo = LockImplementation.getCanAtomicWrite(mem, addr, data, im.portNum) if (methodInfo.isDefined) { l :+ translateMethod(getLockName(mem), methodInfo.get) @@ -1058,7 +1058,7 @@ object BluespecGeneration { private def getCombinationalDeclaration(cmd: Command): Option[BDecl] = cmd match { case CAssign(lhs, _) => Some(BDecl(translator.toVar(lhs), None)) case IMemSend(_, _, _, _, _, _, outH, _) if outH.isDefined => Some(BDecl(translator.toVar(outH.get), None)) - case IMemWrite(_, _, _, _, outH, _) if outH.isDefined => Some(BDecl(translator.toVar(outH.get), None)) + case IMemWrite(_, _, _, _, _, outH, _) if outH.isDefined => Some(BDecl(translator.toVar(outH.get), None)) case IMemRecv(_, _, data) => data match { case Some(v) => Some(BDecl(translator.toVar(v), None)) case None => None @@ -1104,7 +1104,7 @@ object BluespecGeneration { case CExpr(exp) => Some(BExprStmt(translator.toExpr(exp))) case IMemSend(_, _, _, _, _, inH, outH, _) if inH.isDefined && outH.isDefined => Some(BAssign(translator.toVar(outH.get), translator.toExpr(inH.get))) - case IMemWrite(_, _, _, inH, outH, _) if inH.isDefined && outH.isDefined => + case IMemWrite(_, _, _, _, inH, outH, _) if inH.isDefined && outH.isDefined => Some(BAssign(translator.toVar(outH.get), translator.toExpr(inH.get))) case IMemRecv(mem: Id, handle: EVar, data: Option[EVar]) => data match { case Some(v) => Some(BAssign(translator.toVar(v), @@ -1253,7 +1253,7 @@ object BluespecGeneration { //This is an effectful op b/c is modifies the mem queue its reading from case IMemRecv(mem: Id, handle: EVar, _: Option[EVar]) => Some(BExprStmt(bsInts.getMemResp(modParams(mem), translator.toVar(handle), cmd.portNum, isLockedMemory(mem)))) - case IMemWrite(mem, addr, data, lHandle, _, isAtomic) => + case IMemWrite(mem, addr, data, writeMask, lHandle, _, isAtomic) => val portNum = mem.typ.get match { case memType: TLockedMemType => if (memType.limpl.usesWritePortNum) cmd.portNum else None case _ => None //In the future we may allow unlocked mems with port annotations @@ -1261,7 +1261,7 @@ object BluespecGeneration { Some(BExprStmt( if (isLockedMemory(mem)) { //ask lock for its translation - translateMethod(modParams(mem), LockImplementation.getWriteInfo(mem, addr, lHandle, data, portNum, isAtomic).get) + translateMethod(modParams(mem), LockImplementation.getWriteInfo(mem, addr, lHandle, data, writeMask, portNum, isAtomic).get) } else { //use unlocked translation bsInts.getUnlockedCombWrite(modParams(mem), translator.toExpr(addr), translator.toExpr(data), portNum) diff --git a/src/main/scala/pipedsl/common/LockImplementation.scala b/src/main/scala/pipedsl/common/LockImplementation.scala index e7782ab9..083b591d 100644 --- a/src/main/scala/pipedsl/common/LockImplementation.scala +++ b/src/main/scala/pipedsl/common/LockImplementation.scala @@ -1,10 +1,12 @@ /* LockImplementation.scala */ package pipedsl.common +import pipedsl.codegen.bsv.BSVSyntax.BPack import pipedsl.common.Errors.{MissingType, UnexpectedLockImpl} import pipedsl.common.Locks.{General, LockGranularity, Specific} import pipedsl.common.Syntax.Latency.{Combinational, Latency, Sequential} import pipedsl.common.Syntax._ +import pipedsl.codegen.bsv.BluespecInterfaces object LockImplementation { @@ -31,6 +33,7 @@ object LockImplementation { private val dataType = TNamedType(Id("data")) private val handleType = TNamedType(Id("handle")) private val checkType = TNamedType(Id("checkHandle")) + private val maskType = TNamedType(Id("wmask")) //Lock Object Method Names private val canResName = "canRes" private val canResReadName = canResName + "_r" @@ -235,10 +238,10 @@ object LockImplementation { } } - def getWriteInfo(mem: Id, addr: Expr, inHandle: Option[Expr], data: Expr, portNum: Option[Int], isAtomic: Boolean): Option[MethodInfo] = { + def getWriteInfo(mem: Id, addr: Expr, inHandle: Option[Expr], data: Expr, writeMask: Option[Expr], portNum: Option[Int], isAtomic: Boolean): Option[MethodInfo] = { val interface = getLockImplFromMemTyp(mem) val (funTyp, latency) = getAccess(interface, Some(LockWrite), isAtomic).get - val args = getArgs(funTyp, Some(addr), inHandle, Some(data)) + val args = getArgs(funTyp, Some(addr), inHandle, Some(data), writeMask) val methodName = getAccessName(Some(LockWrite), isAtomic).v + toPortString(portNum) Some(MethodInfo(methodName, latency != Combinational, args)) } @@ -304,13 +307,14 @@ object LockImplementation { e } private def getArgs(fun: TFun, addr: Option[Expr] = None, - handle: Option[Expr] = None, data: Option[Expr] = None): List[Expr] = { + handle: Option[Expr] = None, data: Option[Expr] = None, writeMask: Option[Expr] = None): List[Expr] = { fun.args.foldLeft(List[Expr]())((l, argTyp) => { argTyp match { //TODO throw better exception if missing arg case t: TNamedType if t == dataType => l :+ data.get case t: TNamedType if t == addrType => l :+ addr.get case t: TNamedType if t == handleType => l :+ extractHandle(handle.get) + case t: TNamedType if t == maskType && writeMask.isDefined => l :+ writeMask.get case _ => l //should be unreachable TODO throw badly formatted type } }) @@ -430,6 +434,8 @@ object LockImplementation { //LSQ doesn't need a separate lock id so use this to differentiate def useUniqueLockId(): Boolean = true + def canSilentWrite(): Boolean = false + def getLockIdSize: Int = defaultLockHandleSize def getChkIdSize(lidSize: Int): Option[Int] = None @@ -492,6 +498,8 @@ object LockImplementation { val parent = super.getType TObject(queueLockName, List(), parent.methods ++ Map( + Id(writeName) -> (TFun(List(addrType, dataType, maskType), TVoid()), Combinational), + Id(atomicAccessName) -> (TFun(List(addrType), TVoid()), Combinational), Id(checkpointName) -> (TFun(List(), checkType), Sequential), Id(rollbackName) -> (TFun(List(checkType), TVoid()), Sequential), Id(abortName) -> (TFun(List(), TVoid()), Sequential) @@ -507,6 +515,7 @@ object LockImplementation { override def getModInstArgs(m: TMemType, szParams: List[Int]): List[Int] = List() + override def canSilentWrite(): Boolean = true //Checkpoint id must equal the lock id size override def getChkIdSize(lidSize: Int): Option[Int] = Some(lidSize) } diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index 7e2d26ec..d1e167e6 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -670,7 +670,7 @@ object Syntax { } case class IMemRecv(mem: Id, handle: EVar, data: Option[EVar]) extends InternalCommand with LockInfoAnnotation //used for sequential memories that don't commit writes immediately but don't send a response - case class IMemWrite(mem: Id, addr: EVar, data: EVar, + case class IMemWrite(mem: Id, addr: EVar, data: EVar, writeMask: Option[Expr], inHandle: Option[EVar], outHandle: Option[EVar], isAtomic: Boolean) extends InternalCommand with LockInfoAnnotation case class ICheckLockOwned(mem: LockArg, inHandle: EVar, outHandle :EVar) extends InternalCommand with LockInfoAnnotation case class IReserveLock(outHandle: EVar, mem: LockArg) extends InternalCommand with LockInfoAnnotation diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index 970f9a07..24f25c9e 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -180,8 +180,13 @@ object Utilities { Set() }) case IMemRecv(_, handle, _) => Set(handle.id) - case IMemWrite(_, addr, data, inHandle, _, _) => - Set(addr.id, data.id).union(inHandle.map(h => Set(h.id)).getOrElse(Set())) + case IMemWrite(_, addr, data, writeMask, inHandle, _, _) => + Set(addr.id, data.id).union(inHandle.map(h => Set(h.id)).getOrElse(Set())) ++ ( + if (writeMask.isDefined) { + getUsedVars(writeMask.get) + } else { + Set() + }) case IRecv(handle, _, _) => Set(handle.id) case ISend(_, _, args) => args.map(a => a.id).toSet case IReserveLock(_, larg) => larg.evar match { diff --git a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala index 720cf2cd..f2d2bb15 100644 --- a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala +++ b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala @@ -4,6 +4,7 @@ package pipedsl.passes import pipedsl.common.Syntax._ import pipedsl.common.DAGSyntax.PStage import pipedsl.common.Errors.{UnexpectedExpr, UnexpectedType} +import pipedsl.common.LockImplementation import pipedsl.common.Utilities.flattenStageList import pipedsl.passes.Passes.StagePass @@ -77,12 +78,12 @@ class ConvertAsyncPass(modName: Id) extends StagePass[List[PStage]] { recv.portNum = c.portNum (send, recv) case _ :TMemType => - val write = IMemWrite(mem, index, data, inHandle, outHandle, isAtomic).setPos(e.pos) + val write = IMemWrite(mem, index, data, wm, inHandle, outHandle, isAtomic).setPos(e.pos) write.memOpType = e.memOpType write.granularity = e.granularity write.portNum = c.portNum (write, CEmpty()) - case TLockedMemType(TMemType(_, _, _, Latency.Asynchronous, _, _),_, _) => + case TLockedMemType(TMemType(_, _, _, Latency.Asynchronous, _, _),_, lock) if !lock.canSilentWrite() => val handle = freshMessage(mem) val send = IMemSend(handle, writeMask = wm, mem, Some(data), index, inHandle, outHandle, isAtomic) val recv = IMemRecv(mem, handle, None) @@ -95,8 +96,13 @@ class ConvertAsyncPass(modName: Id) extends StagePass[List[PStage]] { (send, recv) //if the memory is sequential we don't use handle since it //is assumed to complete at the end of the cycle - case TLockedMemType(_,_,_) => - val write = IMemWrite(mem, index, data, inHandle, outHandle, isAtomic).setPos(e.pos) + case TLockedMemType(TMemType(_, _, _, lat, _, _),_, lock) => + val newwm = wm match { + case _: Expr => wm + case _ if lat == Latency.Asynchronous => Some(EInt(1, 2, -1)) + case _ => None + } + val write = IMemWrite(mem, index, data, newwm, inHandle, outHandle, isAtomic).setPos(e.pos) write.memOpType = e.memOpType write.granularity = e.granularity write.portNum = c.portNum diff --git a/src/test/tests/exception/exn-recovery-spec.pdl b/src/test/tests/exception/exn-recovery-spec.pdl index edbd4553..45ac90c0 100644 --- a/src/test/tests/exception/exn-recovery-spec.pdl +++ b/src/test/tests/exception/exn-recovery-spec.pdl @@ -1,6 +1,6 @@ // exn-recovery-spec.pdl //Expect 5 Success, 1 Exception, 1 Success post recovery -exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { +exn-pipe cpu(pc :uint<16>)[acc :uint<8>[0](CheckpointQueue)] :uint<4> { spec_check(); start(acc); reserve(acc); @@ -12,7 +12,9 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { --- spec_check(); block(acc); - acc_val = acc[0]; + acc_val <- acc[0]; + --- + spec_check(); acc[0] <- acc_val + 1; --- spec_barrier(); @@ -53,7 +55,7 @@ except(arg: uint<4>): circuit { ti = memory(uint<8>, 16); - acc = register(uint<4>, 0); + acc = memory(uint<8>, 0); locked = CheckpointQueue(acc); c = new cpu[locked]; call c(u1<16>); diff --git a/src/test/tests/exception/exn-simple-chkp.pdl b/src/test/tests/exception/exn-simple-chkp.pdl new file mode 100644 index 00000000..5cce8ed1 --- /dev/null +++ b/src/test/tests/exception/exn-simple-chkp.pdl @@ -0,0 +1,32 @@ +// exn-simple.pdl +//Expect 5 Success, 1 Exception +exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { + start(acc); + reserve(acc); + end(acc); + --- + block(acc); + acc_val = acc[0]; + acc[0] <- acc_val + 1; + call cpu(pc + 1); + --- + if(acc_val == 6) + { + throw(u0<4>); + } +commit: + release(acc); + print("no exn at PC == %d! with acc_val of %d", pc, acc_val); +except(arg :uint<4>): + print("exception at PC == %d! with arg: %d", pc, arg); + output(1); +} + + +circuit { + ti = memory(uint<8>, 16); + acc = register(uint<4>, 0); + locked = CheckpointQueue(acc); + c = new cpu[locked]; + call c(u1<16>); +} diff --git a/src/test/tests/exception/exn-simple-spec.pdl b/src/test/tests/exception/exn-simple-spec.pdl index d7b51727..074813f9 100644 --- a/src/test/tests/exception/exn-simple-spec.pdl +++ b/src/test/tests/exception/exn-simple-spec.pdl @@ -1,6 +1,6 @@ // exn-simple-spec.pdl //Expected Success -exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { +exn-pipe cpu(pc :uint<16>)[acc :uint<8>[0](CheckpointQueue)] :uint<4> { spec_check(); start(acc); reserve(acc); @@ -12,9 +12,11 @@ exn-pipe cpu(pc :uint<16>)[acc :uint<4>[0](CheckpointQueue)] :uint<4> { --- spec_check(); block(acc); - acc_val = acc[0]; + acc_val <- acc[0]; + --- + spec_check(); acc[0] <- acc_val + 1; - if(acc_val == 6) + if(acc_val == u6<8>) { throw(u0<4>); } @@ -37,13 +39,17 @@ commit: print("no exn at PC == %d! with acc_val of %d", pc, acc_val); except(arg: uint<4>): print("exception at PC == %d! with arg: %d", pc, arg); + --- + exn_acc_val <- acc[0]; + --- + print(exn_acc_val); output(1); } circuit { ti = memory(uint<8>, 16); - acc = register(uint<4>, 0); + acc = memory(uint<8>, 0); locked = CheckpointQueue(acc); c = new cpu[locked]; call c(u1<16>); diff --git a/src/test/tests/exception/memInputs/acc b/src/test/tests/exception/memInputs/acc new file mode 100644 index 00000000..5b290d00 --- /dev/null +++ b/src/test/tests/exception/memInputs/acc @@ -0,0 +1 @@ +00000000 diff --git a/src/test/tests/risc-pipe/risc-pipe-pldi-5-stg.pdl b/src/test/tests/risc-pipe/risc-pipe-pldi-5-stg.pdl new file mode 100644 index 00000000..b8aa42d7 --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-pldi-5-stg.pdl @@ -0,0 +1,276 @@ +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + bool eq = arg1 == arg2; + bool lt = arg1 < arg2; + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + bool ltu = un1 < un2; + if (op == u0<3>) { //BEQ + return eq; + } else { + if (op == u1<3>) { //BNE + return !eq; + } else { + if (op == u4<3>) { //BLT + return lt; + } else { + if (op == u5<3>) { //BGE + return !lt; + } else { + if (op == u6<3>) { //BLTU + return ltu; + } else { + if (op == u7<3>) { //BGEU + return !ltu; + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe cpu(pc: int<32>)[rf: int<32>[5](BypassRF), imem: int<32>[32], dmem: int<32>[32]]: bool { + spec_check(); + start(imem); + uint<32> pcaddr = cast(pc, uint<32>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<32>); + --- + spec_barrier(); + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<32> immB = cast(immBTmp, int<32>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<32> immJR = cast(immJRTmp, int<32>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + start(rf); + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + bool useRf1 = (!isAui) && (!isLui); + int<32> alu_arg1_tmp = (isAui) ? (pc << 2) : 0<32>; + bool useRf2 = (!isAui) && (!isLui) && (!isStore) && (!isOpImm) && (!isLoad) && (!isJalr); + int<32> alu_arg2_tmp = (isAui || isLui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : ((isJalr) ? immJR : 0<32>))); + int<32> pcOff = ((isBranch) ? immB : immJ) >> 2; + --- + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + + int<32> alu_arg1 = (useRf1) ? rf1 : alu_arg1_tmp; + int<32> alu_arg2 = (useRf2) ? rf2 : alu_arg2_tmp; + bool take = br(funct3, alu_arg1, alu_arg2); + int<32> tmppc = pc + 1<32>; + if (!done) { + if ((isBranch && take) || isJal || isJalr) { + invalidate(s); + } else { + verify(s, tmppc); + }} else { + invalidate(s); + } + bool alu_flip = (isStore || isLoad || isAui || isLui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui || isLui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<32> linkpc = tmppc << 2; + int<32> rddata = (isJal || isJalr) ? linkpc : alu_res; + int<32> takePc = pc + pcOff; + split { + case: (isBranch) { + int<32> npc = (take) ? (takePc) : (tmppc); + } + case: (isJal) { + int<32> npc = takePc; + } + case: (isJalr) { + int<32> npc = alu_res >> 2; + } + default: { + int<32> npc = tmppc; + } + } + if ((!done)) { + if ((isBranch && take) || isJal || isJalr) { + call cpu(npc); + } + } + int<32> stdata = rf2; + --- + if (writerd && (!isLoad)) { + block(rf[rd]); + rf[rd] <- rddata; + } + uint<32> tmpaddr = cast(rddata, uint<32>); + uint<32> memaddr = (tmpaddr >> 2); + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<32> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<32> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (stdata << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd && isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + } + if (writerd) { + print("Writing %d to r%d", insnout, rd); + } + --- + if (writerd) { + release(rf[rd]); + } + if (done) { + output(true); + } +} + +circuit { + ti = memory(int<32>, 32); + td = memory(int<32>, 32); + rf = rflock BypassRF(int<32>, 5, 8); + c = new cpu[rf, ti, td]; + call c(0<32>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-exn-3.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-exn-3.pdl new file mode 100644 index 00000000..03a20ec8 --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-spec-exn-3.pdl @@ -0,0 +1,392 @@ +// risc-pipe-spec-write.pdl +extern BHT { + method req(pc: int, skip: int, take: int): int; + method upd(pc: int, taken: bool): (); +} + +def mul(arg1: int<32>, arg2: int<32>, op: uint<3>): int<32> { + uint<32> mag1 = cast(mag(arg1), uint<32>); + uint<32> mag2 = cast(mag(arg2), uint<32>); + //MULHU => positive sign always + int<32> s1 = (op == u3<3>) ? 1<32> : sign(arg1); + //MULHU/MULHSU => positive sign always + int<32> s2 = (op >= u2<3>) ? 1<32> : sign(arg2); + int<64> magRes = cast((mag1 * mag2), int<64>); + int<64> m = (s1 == s2) ? (magRes) : -(magRes); + if (op == u0<3>) { //MUL + return m{31:0}; + } else { + return m{63:32}; + } +} + +def alu(arg1: int<32>, arg2: int<32>, op: uint<3>, flip: bool): int<32> { + uint<5> shamt = cast(arg2{4:0}, uint<5>); + if (op == u0<3>) { //000 == ADD , flip == sub + if (!flip) { + return arg1 + arg2; + } else { + return arg1 - arg2; + } + } else { + if (op == u1<3>) { //001 == SLL + return arg1 << shamt; + } else { + if (op == u2<3>) { //010 == SLT + return (arg1 < arg2) ? 1<32> : 0<32>; + } else { + if (op == u3<3>) { //011 == SLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2) ? 1<32> : 0<32>; + } else { + if (op == u4<3>) { //100 == XOR + return arg1 ^ arg2; + } else { + if (op == u5<3>) { //101 == SRL / SRA + if (!flip) { + return cast((cast(arg1, uint<32>)) >> shamt, int<32>); //SRL + } else { + return arg1 >> shamt; //SRA + } + } else { + if (op == u6<3>) { //110 == OR + return arg1 | arg2; + } else { //111 == AND + return arg1 & arg2; + }}}}}}} + +} + +//true if taking branch +def br(op:uint<3>, arg1:int<32>, arg2:int<32>): bool { + if (op == u0<3>) { //BEQ + return (arg1 == arg2); + } else { + if (op == u1<3>) { //BNE + return (arg1 != arg2); + } else { + if (op == u4<3>) { //BLT + return (arg1 < arg2); + } else { + if (op == u5<3>) { //BGE + return (arg1 >= arg2); + } else { + if (op == u6<3>) { //BLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return (un1 < un2); + } else { + if (op == u7<3>) { //BGEU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + return(un1 >= un2); + } else { + return false; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (u0b0001<4> << off); + } else { + if (op == u1<3>) { //SH + uint<2> shamt = off{1:1} ++ u0<1>; + return (u0b0011<4> << shamt); + } else { //SW + return u0b1111<4>; + }} +} + +def maskLoad(data: int<32>, op: uint<3>, start: uint<2>): int<32> { + //start == offset in bytes, need to multiply by 8 + uint<5> boff = start ++ u0<3>; + int<32> tmp = data >> boff; + uint<8> bdata = cast(tmp, uint<8>); + uint<16> hdata = cast(tmp, uint<16>); + + if (op == u0<3>) { //LB + return cast(bdata, int<32>); + } else { + if (op == u1<3>) { //LH + return cast(hdata, int<32>); + } else { + if (op == u2<3>) { //LW + return data; + } else { + if (op == u4<3>) { //LBU + uint<32> zext = cast(bdata, uint<32>); + return cast(zext, int<32>); + } else { + if (op == u5<3>) { //LHU + uint<32> zext = cast(hdata, uint<32>); + return cast(zext, int<32>); + } else { + return 0<32>; + }}}}} +} + +pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32>, cnt: uint<5>, retQuot: bool)[]: uint<32> { + uint<32> tmp = acc{30:0} ++ num{31:31}; + uint<32> na = (tmp >= denom) ? (tmp - denom) : (tmp); + uint<32> nq = (tmp >= denom) ? ((quot << 1){31:1} ++ u1<1>) : (quot << 1); + uint<32> nnum = num << 1; + bool done = (cnt == u31<5>); + if (done) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); + } +} + + +exn-pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT, csrf: int<32>[3]]: bool { + spec_check(); + start(imem); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool isMul = isMDiv && (funct3 < u4<3>); + bool isSystem = opcode == 0b1110011<7>; + bool isEcall = isSystem && (immI == 0<32>); + bool isMret = isSystem && (funct7 == u24<7>) && (rs2 == u2<5>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + spec_check(); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if (!done) { + if (notBranch) { + s2 <- s; + } else { + if (isBranch) { + s2 <- update(s, bht.req(pc, immB, 1<16>)); + } else { + s2 <- s; + invalidate(s); + }}} else { s2 <- s; invalidate(s); } + if (isEcall){ + throw(0, u8<4>); + } + if (isMret){ + throw(0, u3<4>); + } + start(rf); + if (!done && (notBranch || isBranch)) { checkpoint(rf); } + if (needrs1) { + reserve(rf[rs1], R); + } + if (needrs2) { + reserve(rf[rs2], R); + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + --- + spec_check(); + if (needrs1) { + block(rf[rs1]); + int<32> rf1 = rf[rs1]; + release(rf[rs1]); + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + block(rf[rs2]); + int<32> rf2 = rf[rs2]; + release(rf[rs2]); + } else { + int<32> rf2 = 0<32>; + } + bool take = br(funct3, rf1, rf2); + if (isBranch) { + //divide by 4 b/c we count instructions not bytes + int<16> offpc = pc + (immB >> 2); + int<16> npc = (take) ? (offpc) : (pc + 1<16>); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + int<32> alu_arg1 = (isAui) ? ((0<16> ++ pc) << 2) : rf1; + int<32> alu_arg2 = (isAui) ? immU : ((isStore) ? immS : ((isOpImm || isLoad) ? immI : rf2)); + bool alu_flip = (isStore || isLoad || isAui) ? false : flip; + uint<3> alu_funct3 = (isStore || isLoad || isAui) ? doAdd : funct3; + int<32> alu_res = alu(alu_arg1, alu_arg2, alu_funct3, alu_flip); + int<16> tmppc = pc + 1<16>; + int<32> linkpc = 0<16> ++ (tmppc << 2); + int<32> mulres = mul(rf1, rf2, funct3); + if (writerd && (!isLoad) && (!isDiv)) { + block(rf[rd]); + int<32> rddata = (isLui) ? immU : ((isMul) ? mulres : ((isJal || isJalr) ? linkpc : alu_res)); + rf[rd] <- rddata; + } else { + int<32> rddata = 0<32>; + } + --- + spec_barrier(); //delayed just to force writes to happen speculatively + if (!done) { + if (!notBranch) { + if (isBranch) { + verify(s2, npc) { bht.upd(pc, take) }; + } else { + call cpu(npc); + } + } else { + verify(s, pc + 1<16>); + } + } + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + bool invertRes <- isSignedDiv && (sdividend != sdivisor); + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } else { + bool invertRes <- false; + uint<32> udivout <- u0<32>; + } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + uint<2> boff = cast(alu_res{1:0}, uint<2>); + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + if (isLoad) { + block(rf[rd]); + int<32> insnout = maskLoad(wdata, funct3, boff); + rf[rd] <- insnout; + } else { + if (isDiv) { + block(rf[rd]); + int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + int<32> insnout = divout; + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + }} + print("Writing %d to r%d", insnout, rd); + } + int<32> enable = csrf[4]; + --- + int<32> pending = csrf[3]; + int<32> masked_pending = pending | enable; + bool isExtInt = (masked_pending{11:11} == 1<1>); + if (isExtInt) { + throw(1, u11<4>); + } +commit: + if (writerd) { + release(rf[rd]); + } + if (done) { output(true); } +except(is_interrupt: uint<1>, exncode: uint<4>): // mepc = csrf[0], mtvec = csrf[1], mcause = csrf[2] + print("exception at PC == %d! with exncode: %d", pc, exncode); + start(csrf); // mip = csrf[3], mie = csrf[4], mstatus = csrf[5] + bool isStartContext = (is_interrupt == u1<1>) || exncode == u8<4>; + bool isRestoreContext = (exncode == u3<4>); + if (isStartContext) { + csrf[0] <- cast(pc, int<32>); // write to mepc + int<32> csrret = csrf[1]; // read from mtvec + int<16> npc = csrret{15:0}; + } else { if (isRestoreContext) { + int<32> csrret = csrf[0]; // read from mepc + int<16> npc = csrret{15:0} + 1; + } else { int<16> npc = pc + 1; }} + --- + int<32> oldmcause = csrf[2]; + bool wasHandlingInterrupt = oldmcause{31:31} == 1; + int<32> newmcause = cast(is_interrupt, int<1>) ++ cast(exncode, int<31>); + if (isStartContext) { + csrf[2] <- cast(newmcause, int<32>); // write to mcause + } else { if (isRestoreContext) { csrf[4] <- 1<32>; }} // enable mie + --- + if (isStartContext && (is_interrupt == u1<1>)) { + csrf[4] <- 0<32>; // disable mie + } else { if (isRestoreContext && wasHandlingInterrupt) { + int<32> oldmip = csrf[3]; + int<32> newmip = oldmip{31:12} ++ 0<1> ++ oldmip{10:0}; + csrf[3] <- newmip; // unset mip + }} + end(csrf); + --- + print("GOTO PC: %d", npc); + call cpu(npc); +} + +circuit { + ti = memory(int<32>, 16); + td = memory(int<32>, 16); + rf = rflock CheckpointRF(int<32>, 5, 64); + csrf = regfile(int<32>, 3); + div = new multi_stg_div[]; + b = new BHT<16>[](4); + c = new cpu[rf, ti, td, div, b, csrf]; + call c(0<16>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl b/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl index 4a8641b4..0c7cb83b 100644 --- a/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl +++ b/src/test/tests/risc-pipe/risc-pipe-spec-write.pdl @@ -141,7 +141,7 @@ pipe multi_stg_div(num: uint<32>, denom: uint<32>, quot: uint<32>, acc: uint<32> } -pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16], div: multi_stg_div, bht: BHT]: bool { +pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16], dmem: int<32>[16](CheckpointQueue), div: multi_stg_div, bht: BHT]: bool { spec_check(); start(imem); uint<16> pcaddr = cast(pc, uint<16>); @@ -255,6 +255,13 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16] } else { int<32> rddata = 0<32>; } + uint<32> tmpaddr = cast(alu_res, uint<32>); + uint<16> memaddr = (tmpaddr >> 2){15:0}; + start(dmem); + if (isLoad || isStore){ + reserve(dmem); + } + end(dmem); --- spec_barrier(); //delayed just to force writes to happen speculatively if (!done) { @@ -283,16 +290,16 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16] bool invertRes <- false; uint<32> udivout <- u0<32>; } - uint<32> tmpaddr = cast(alu_res, uint<32>); - uint<16> memaddr = (tmpaddr >> 2){15:0}; + uint<2> boff = cast(alu_res{1:0}, uint<2>); - start(dmem); split { - case: (isLoad) { - uint<16> raddr = memaddr; - int<32> wdata <- dmem[raddr]; + case: (isLoad) { + block(dmem); + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; } case: (isStore) { + block(dmem); uint<16> waddr = memaddr; //use bottom bits of data and place in correct offset //shift by boff*8 @@ -304,13 +311,12 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16] int<32> wdata <- 0<32>; } } - end(dmem); --- print("PC: %h", pc << 2); print("INSN: %h", insn); if (writerd) { if (isLoad) { - block(rf[rd]); + block(rf[rd]); int<32> insnout = maskLoad(wdata, funct3, boff); rf[rd] <- insnout; } else { @@ -327,7 +333,10 @@ pipe cpu(pc: int<16>)[rf: int<32>[5](CheckpointRF), imem: int<32>[16] --- if (writerd) { release(rf[rd]); - } + } + if (isStore || isLoad) { + release(dmem); + } if (done) { output(true); } } @@ -337,6 +346,7 @@ circuit { rf = rflock CheckpointRF(int<32>, 5, 64); div = new multi_stg_div[]; b = new BHT<16>[](4); - c = new cpu[rf, ti, td, div, b]; + lockedtd = CheckpointQueue(td); + c = new cpu[rf, ti, lockedtd, div, b]; call c(0<16>); } \ No newline at end of file