diff --git a/examples/cache-call.pdl b/examples/cache-call.pdl
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/test.pdl b/examples/test.pdl
new file mode 100644
index 00000000..a72ef9d5
--- /dev/null
+++ b/examples/test.pdl
@@ -0,0 +1,46 @@
+pipe cache(addr: uint<5>, data: int<32>)[dmem: int<32>[5](Queue)]: bool {
+ //spec_check();
+ start(dmem);
+ int<32> sdata <- dmem[addr];
+ //checkpoint(dmem);
+ reserve(dmem[addr], W); //stupid to put here, but doing it just for the sake of things
+ end(dmem);
+ ---
+ //spec_check();
+ wdata = data + sdata;
+ block(dmem[addr]);
+ dmem[addr] <- wdata;
+ release(dmem[addr]);
+ print("ADDR: %d, DATA: %h", addr, wdata);
+ ---
+ //spec_check();
+ output(true);
+}
+
+pipe cpu(pc: int<32>)[cache1: cache, imem: int<32>[16]]: bool {
+ start(imem);
+ int<32> insn <- imem[cast(pc, uint<16>)];
+ end(imem);
+
+ call cpu(pc + 1);
+
+ start(cache1);
+ reserve(cache1);
+ end(cache1);
+ ---
+ uint<5> addr = cast(insn{36:32}, uint<5>);
+
+ block(cache1);
+ cs <- call cache1(addr, 1<32>);
+ release(cache1);
+ ---
+ nextPc = (addr{0:0} == 0) ? pc + 2 : pc + 1;
+}
+circuit {
+ ti = memory(int<32>, 16);
+ td = memory(int<32>, 5);
+ d = Queue(td);
+ s = new cache[d];
+ c = new cpu[s, ti];
+ call c(0<32>);
+}
\ No newline at end of file
diff --git a/src/main/scala/pipedsl/Interpreter.scala b/src/main/scala/pipedsl/Interpreter.scala
index da116525..9fc6888d 100644
--- a/src/main/scala/pipedsl/Interpreter.scala
+++ b/src/main/scala/pipedsl/Interpreter.scala
@@ -69,7 +69,7 @@ class Interpreter(val maxIterations: Int) {
}
interp_function(func, newEnv)
}
- case ECall(id, name, args) => {
+ case ECall(id, name, args, _) => {
var newEnv = new immutable.HashMap[Id, Any]()
val moddef = modules(id)
for (index <- 0 until args.length) {
diff --git a/src/main/scala/pipedsl/Parser.scala b/src/main/scala/pipedsl/Parser.scala
index 6c567187..431e4a9e 100644
--- a/src/main/scala/pipedsl/Parser.scala
+++ b/src/main/scala/pipedsl/Parser.scala
@@ -72,7 +72,7 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers {
lazy val stringVal: P[EString] =
"\"" ~> "[^\"]*".r <~ "\"" ^^ {n => EString(n)}
- private def toInt(n: Int, base: Int, bits: Option[Int], isUnsigned: Boolean): EInt = {
+ private def toInt(n: String, base: Int, bits: Option[Int], isUnsigned: Boolean): EInt = {
val e = EInt(n, base, if (bits.isDefined) bits.get else -1)
e.typ = bits match {
case Some(b) => Some(TSizedInt(TBitWidthLen(b), SignFactory.ofBool(!isUnsigned)))
@@ -87,16 +87,16 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers {
// Atoms
lazy val dec: P[EInt] = positioned { "u".? ~ "-?[0-9]+".r ~ angular(posint).? ^^ {
- case u ~ n ~ bits => toInt(n.toInt, 10, bits, u.isDefined)
+ case u ~ n ~ bits => toInt(n, 10, bits, u.isDefined)
}}
lazy val hex: P[EInt] = positioned { "u".? ~ "0x-?[0-9a-fA-F]+".r ~ angular(posint).? ^^ {
- case u ~ n ~ bits => toInt(Integer.parseInt(n.substring(2), 16), 16, bits, u.isDefined)
+ case u ~ n ~ bits => toInt(n.substring(2), 16, bits, u.isDefined)
}}
lazy val octal: P[EInt] = positioned { "u".? ~ "0-?[0-7]+".r ~ angular(posint).? ^^ {
- case u ~ n ~ bits => toInt(Integer.parseInt(n.substring(1), 8), 8, bits, u.isDefined)
+ case u ~ n ~ bits => toInt(n.substring(1), 8, bits, u.isDefined)
}}
lazy val binary: P[EInt] = positioned { "u".? ~ "0b-?[0-1]+".r ~ angular(posint).? ^^ {
- case u ~ n ~ bits => toInt(Integer.parseInt(n.substring(2), 2), 2, bits, u.isDefined)
+ case u ~ n ~ bits => toInt(n.substring(2), 2, bits, u.isDefined)
}}
lazy val num: P[EInt] = binary | hex | octal | dec ^^
@@ -151,11 +151,11 @@ class Parser(rflockImpl: String) extends RegexParsers with PackratParsers {
}
lazy val methodCall: P[ECall] = positioned {
- iden ~ "." ~ iden ~ parens(repsep(expr, ",")) ^^ { case i ~ _ ~ n ~ args => ECall(i, Some(n), args) }
+ angular("atomic" | "a").? ~ iden ~ "." ~ iden ~ parens(repsep(expr, ",")) ^^ { case a ~ i ~ _ ~ n ~ args => ECall(i, Some(n), args, a.isDefined) }
}
lazy val simpleAtom: P[Expr] = positioned {
- "call" ~> iden ~ parens(repsep(expr, ",")) ^^ { case i ~ args => ECall(i, None, args) } |
+ "call" ~> angular("atomic" | "a").? ~ iden ~ parens(repsep(expr, ",")) ^^ { case a ~ i ~ args => ECall(i, None, args, a.isDefined) } |
not ~ simpleAtom ^^ { case n ~ e => EUop(n, e) } |
neg |
cast |
diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala
index 044de8df..6017e3c9 100644
--- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala
+++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala
@@ -115,7 +115,15 @@ object BSVSyntax {
case TRequestHandle(n, rtyp) => rtyp match {
//These are passed in the modmap rather than the handle map
case pipedsl.common.Syntax.RequestType.Lock if !n.typ.get.isInstanceOf[TMemType] =>
+ if(n.typ.get.isInstanceOf[TModType]) {
+ n.typ.get match {
+ case TModType(_, _, _, Some(n)) => modmap(n)
+ case _ => throw UnexpectedType(t.pos, "Module type", "A Some(mod name) typ", t)
+ }
+ }
+ else {
modmap(n)
+ }
case pipedsl.common.Syntax.RequestType.Checkpoint =>
lockIdToCheckId(modmap(n))
//TODO allow this to be specified somewhere
@@ -156,7 +164,7 @@ object BSVSyntax {
}
def toExpr(e: Expr): BExpr = e match {
- case EInt(v, base, bits) => BIntLit(v, base, bits)
+ case EInt(v, base, bits) => BIntLit(v.toInt, base, bits)
case EBool(v) => BBoolLit(v)
case EString(v) => BStringLit(v)
case eu@EUop(_, _) => translateUOp(eu)
@@ -191,7 +199,7 @@ object BSVSyntax {
case EInvalid => BInvalid
case EFromMaybe(ex) => BFromMaybe(BDontCare, toExpr(ex))
case EToMaybe(ex) => BTaggedValid(toExpr(ex))
- case ECall(mod, method, args) if method.isDefined =>
+ case ECall(mod, method, args, isAtomic) if method.isDefined =>
//type doesn't matter on the var
BMethodInvoke(BVar(mod.v, BVoid), method.get.v, args.map(a => toExpr(a)))
case _ => throw UnexpectedExpr(e)
diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala
index b4cd41a6..23ad2d4f 100644
--- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala
+++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala
@@ -185,7 +185,7 @@ object BluespecGeneration {
//TODO better for externs
val interface = if (modMap.contains(mod)) bsInts.getInterface(modMap(mod)) else extMap(mod)
val modName = if (modMap.contains(mod)) bsInts.getModuleName(modMap(mod)) else "mk" + mod.v
- val szParams = params.map(p => BUnsizedInt(p.v))
+ val szParams = params.map(p => BUnsizedInt(p.v.toInt))
(interface, BModule(name = modName, args = mods.map(m => env(m)) ++ szParams))
case CirCall(_, _) => throw UnexpectedExpr(c)
}
@@ -719,7 +719,7 @@ object BluespecGeneration {
case EApp(_, args) => args.foldLeft(List[BExpr]())((l, a) => {
l ++ getBlockConds(a)
})
- case ECall(_, _, args) => args.foldLeft(List[BExpr]())((l, a) => {
+ case ECall(_, _, args, isAtomic) => args.foldLeft(List[BExpr]())((l, a) => {
l ++ getBlockConds(a)
})
case ECast(_, exp) => getBlockConds(exp)
diff --git a/src/main/scala/pipedsl/common/DAGSyntax.scala b/src/main/scala/pipedsl/common/DAGSyntax.scala
index 36d0efea..7abdc622 100644
--- a/src/main/scala/pipedsl/common/DAGSyntax.scala
+++ b/src/main/scala/pipedsl/common/DAGSyntax.scala
@@ -242,17 +242,17 @@ object DAGSyntax {
val intSize = log2(defaultNum)
condVar.typ = Some(TSizedInt(TBitWidthLen(intSize), TUnsigned()))
condVar.id.typ = condVar.typ
- var eTernary = ETernary(conds(defaultNum - 1), EInt(defaultNum - 1, bits = intSize), EInt(defaultNum, bits = intSize))
+ var eTernary = ETernary(conds(defaultNum - 1), EInt((defaultNum - 1).toString, bits = intSize), EInt(defaultNum.toString, bits = intSize))
for(i <- defaultNum-2 to 0 by -1 ) {
- eTernary = ETernary(conds(i), EInt(i, bits = intSize), eTernary.copy())
+ eTernary = ETernary(conds(i), EInt(i.toString, bits = intSize), eTernary.copy())
}
this.addCmd(CAssign(condVar, eTernary))
for (i <- 0 until defaultNum) {
- this.addEdgeTo(condStages(i).head, condSend = Some (EBinop(EqOp("=="), condVar, EInt(i, bits = intSize))))
- condStages(i).last.addEdgeTo(joinStage, condRecv = Some (EBinop(EqOp("=="), condVar, EInt(i, bits = intSize))))
+ this.addEdgeTo(condStages(i).head, condSend = Some (EBinop(EqOp("=="), condVar, EInt(i.toString, bits = intSize))))
+ condStages(i).last.addEdgeTo(joinStage, condRecv = Some (EBinop(EqOp("=="), condVar, EInt(i.toString, bits = intSize))))
}
- this.addEdgeTo(defaultStages.head, condSend = Some( EBinop(EqOp("=="), condVar, EInt(defaultNum, bits = intSize))))
- defaultStages.last.addEdgeTo(joinStage, condRecv = Some( EBinop(EqOp("=="), condVar, EInt(defaultNum, bits = intSize))))
+ this.addEdgeTo(defaultStages.head, condSend = Some( EBinop(EqOp("=="), condVar, EInt(defaultNum.toString, bits = intSize))))
+ defaultStages.last.addEdgeTo(joinStage, condRecv = Some( EBinop(EqOp("=="), condVar, EInt(defaultNum.toString, bits = intSize))))
}
class PMemory(n: Id, t: TMemType) extends Process(n) {
diff --git a/src/main/scala/pipedsl/common/Errors.scala b/src/main/scala/pipedsl/common/Errors.scala
index d707199b..f55315d4 100644
--- a/src/main/scala/pipedsl/common/Errors.scala
+++ b/src/main/scala/pipedsl/common/Errors.scala
@@ -87,6 +87,9 @@ object Errors {
case class IllegalLockAcquisition(pos: Position) extends TypeError(
s"Cannot acquire or reserve locks inside multiple branches", pos)
+ case class RecursiveCallLockAcquisition(pos: Position) extends TypeError(
+ s"Cannot acquire or reserve locks for recursive calls", pos)
+
case class IllegalOOOLockRelease(pos: Position) extends TypeError(
s"Cannot release locks inside multiple branches", pos)
diff --git a/src/main/scala/pipedsl/common/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala
index de853e93..d7d5a15d 100644
--- a/src/main/scala/pipedsl/common/PrettyPrinter.scala
+++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala
@@ -114,10 +114,10 @@ class PrettyPrinter(output: Option[File]) {
def printExpr(e: Expr): Unit = pline(printExprToString(e))
def printExprToString(e: Expr): String = e match {
case Syntax.EInt(v, base, bits) => (base match {
- case 2 => "0b" + v.toBinaryString
- case 8 => "0" + v.toOctalString
- case 10 => v.toString
- case 16 => "0x" + v.toHexString
+ case 2 => "0b" + v
+ case 8 => "0" + v
+ case 10 => v
+ case 16 => "0x" + v
}) + "<" + bits.toString + ">"
case Syntax.EBool(v) => v.toString
case Syntax.EUop(op, ex) => op.op + "(" + printExprToString(ex) + ")"
@@ -131,7 +131,7 @@ class PrettyPrinter(output: Option[File]) {
case Syntax.EBitExtract(num, start, end) => printExprToString(num) + "{" + end.toString + ":" + start.toString + "}"
case Syntax.ETernary(cond, tval, fval) => printExprToString(cond) + " ? " + printExprToString(tval) + " : " + printExprToString(fval)
case Syntax.EApp(func, args) => func.v + "(" + args.map(a => printExprToString(a)).mkString(",") + ")"
- case Syntax.ECall(id, name, args) => "call " + id + "(" + 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.ECast(ctyp, exp) => "cast(" + printExprToString(exp) + "," + printTypeToString(ctyp) + ")"
case expr: Syntax.CirExpr => expr match {
diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala
index ad6e5afa..625a5e77 100644
--- a/src/main/scala/pipedsl/common/Syntax.scala
+++ b/src/main/scala/pipedsl/common/Syntax.scala
@@ -421,7 +421,7 @@ object Syntax {
case class EIsValid(ex: Expr) extends Expr
case class EFromMaybe(ex: Expr) extends Expr
case class EToMaybe(ex: Expr) extends Expr
- case class EInt(v: Int, base: Int = 10, bits: Int = 32) extends Expr
+ case class EInt(v: String, base: Int = 10, bits: Int = 32) extends Expr
case class EString(v: String) extends Expr
case class EBool(v: Boolean) extends Expr
case class EUop(op: UOp, ex: Expr) extends Expr
@@ -444,7 +444,7 @@ object Syntax {
case class EBitExtract(num: Expr, start: Int, end: Int) extends Expr
case class ETernary(cond: Expr, tval: Expr, fval: Expr) extends Expr
case class EApp(func: Id, args: List[Expr]) extends Expr
- case class ECall(mod: Id, method: Option[Id] = None, args: List[Expr]) extends Expr
+ case class ECall(mod: Id, method: Option[Id] = None, args: List[Expr], isAtomic: Boolean) extends Expr
case class EVar(id: Id) extends Expr
case class ECast(ctyp: Type, exp: Expr) extends Expr
{
diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala
index 744832ee..585a1439 100644
--- a/src/main/scala/pipedsl/common/Utilities.scala
+++ b/src/main/scala/pipedsl/common/Utilities.scala
@@ -232,7 +232,7 @@ object Utilities {
s ++ getUsedVars(a)
})
//functions are also externally defined
- case ECall(id, _, args) => args.foldLeft[Set[Id]](Set[Id]())((s, a) => {
+ case ECall(id, _, args, _) => args.foldLeft[Set[Id]](Set[Id]())((s, a) => {
s ++ getUsedVars(a)
})
case EVar(id) => id.typ = e.typ; Set(id)
@@ -494,7 +494,7 @@ object Utilities {
{
case FError => e1 match
{
- case EInt(v, _, _) => val sign: TSignedNess =
+ case EInt(v, _, bits) => val sign: TSignedNess =
e1.typ match {
case Some(TSizedInt(_, sign)) => sign match
{
@@ -504,18 +504,18 @@ object Utilities {
case Some(_) => TSigned()
case None => TSigned() //TODO error
}
- e1.typ = Some(TSizedInt(TBitWidthLen(log2(v)), sign))
+ e1.typ = Some(TSizedInt(TBitWidthLen(bits), sign))
case _ => throw LackOfConstraints(e1)
}
case t => e1.typ = t.toOptionUnsafe
}
e1 match
{
- case e@EInt(v, _, _) =>
+ case e@EInt(v, _, bits) =>
if(e.typ.isEmpty)
- e.typ = Some(TSizedInt(TBitWidthLen(log2(v)), TSigned()))
+ e.typ = Some(TSizedInt(TBitWidthLen(bits), TSigned()))
e.copy(bits = e.typ.get.matchOrError(e.pos, "Int", "TSizedInt")
- {case t :TSizedInt => t}.len.getLen).copyMeta(e)
+ {case t :TSizedInt => t}.len.getLen).copyMeta(e)
case e@EIsValid(ex) => e.copy(ex = typeMapExpr(ex, f_opt)).copyMeta(e)
case e@EFromMaybe(ex) => e.copy(ex = typeMapExpr(ex, f_opt)).copyMeta(e)
case e@EToMaybe(ex) => e.copy(ex = typeMapExpr(ex, f_opt)).copyMeta(e)
@@ -538,7 +538,7 @@ object Utilities {
fval = typeMapExpr(fval, f_opt)).copyMeta(e)
case e@EApp(func, args) =>
e.copy(func = typeMapId(func, f_opt), args = args.map(typeMapExpr(_, f_opt))).copyMeta(e)
- case e@ECall(mod, _, args) =>
+ case e@ECall(mod, _, args, _) =>
e.copy(mod = typeMapId(mod, f_opt), args = args.map(typeMapExpr(_, f_opt))).copyMeta(e)
case e@EVar(id) =>
e.copy(id = typeMapId(id, f_opt)).copyMeta(e)
@@ -671,7 +671,7 @@ object Utilities {
case EBitExtract(num, _, _) => getMemReads(num)
case ETernary(cond, tval, fval) => getMemReads(cond) ++ getMemReads(tval) ++ getMemReads(fval)
case EApp(_, args) => args.foldLeft(List[EMemAccess]())((l, a) => l ++ getMemReads(a))
- case ECall(_, _, args) => args.foldLeft(List[EMemAccess]())((l, a) => l ++ getMemReads(a))
+ case ECall(_, _, args, _) => args.foldLeft(List[EMemAccess]())((l, a) => l ++ getMemReads(a))
case ECast(_, exp) => getMemReads(exp)
case _ => List()
}
diff --git a/src/main/scala/pipedsl/passes/CanonicalizePass.scala b/src/main/scala/pipedsl/passes/CanonicalizePass.scala
index 0d1a48e0..e14d080b 100644
--- a/src/main/scala/pipedsl/passes/CanonicalizePass.scala
+++ b/src/main/scala/pipedsl/passes/CanonicalizePass.scala
@@ -159,8 +159,8 @@ class CanonicalizePass() extends CommandPass[Command] with ModulePass[ModuleDef]
(ETernary(ncond, net, nef).setPos(e.pos), CSeq(CSeq(nc, nct).setPos(e.pos), ncf).setPos(e.pos))
case EApp(func, args) => val (nargs, nc) = extractCastVars(args)
(EApp(func, nargs).setPos(e.pos), nc)
- case ECall(mod, name, args) => val (nargs, nc) = extractCastVars(args)
- (ECall(mod, name, nargs).setPos(e.pos), nc)
+ case ECall(mod, name, args, isAtomic) => val (nargs, nc) = extractCastVars(args)
+ (ECall(mod, name, nargs, isAtomic).setPos(e.pos), nc)
case ECast(ctyp, e) => val (ne, nc) = extractCastVars(e)
val ncast = ECast(ctyp, ne)
ncast.typ = Some(ctyp)
diff --git a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala
index 9653732f..6a420874 100644
--- a/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala
+++ b/src/main/scala/pipedsl/passes/ConvertAsyncPass.scala
@@ -103,7 +103,7 @@ class ConvertAsyncPass(modName: Id) extends StagePass[List[PStage]] {
case _ => throw UnexpectedType(mem.pos, "Memory Write Statement", "Memory Type", mem.typ.get)
}
//module calls
- case (lhs@EVar(_), call@ECall(_, _, _)) =>
+ case (lhs@EVar(_), call@ECall(_, _, _, _)) =>
val send = convertCall(call)
val recv = IRecv(send.handle, send.receiver, lhs)
(send, recv)
@@ -133,7 +133,7 @@ class ConvertAsyncPass(modName: Id) extends StagePass[List[PStage]] {
private def getCalls(stg: PStage): List[ECall] = {
stg.getCmds.foldLeft(List[ECall]())((l, c) => {
c match {
- case CExpr(call@ECall(_,_,_)) => l :+ call
+ case CExpr(call@ECall(_,_,_,_)) => l :+ call
case _ => l
}
})
diff --git a/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala b/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala
index 1d0d9f5b..ebd4331a 100644
--- a/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala
+++ b/src/main/scala/pipedsl/passes/LockOpTranslationPass.scala
@@ -117,9 +117,9 @@ object LockOpTranslationPass extends ProgPass[Prog] with CommandPass[Command] wi
val newapp = EApp(f, newargs).setPos(ea.pos)
newapp.typ = ea.typ
newapp
- case ec@ECall(p, name, args) =>
+ case ec@ECall(p, name, args, isAtomic) =>
val newargs = args.foldLeft(List[Expr]())((args, a) => args :+ modifyMemArg(a, isLhs))
- val newcall = ECall(p, name, newargs).setPos(ec.pos)
+ val newcall = ECall(p, name, newargs, isAtomic).setPos(ec.pos)
newcall.typ = ec.typ
newcall
case eb@EBinop(o, e1, e2) =>
diff --git a/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala b/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala
index 3989d1c0..c2301254 100644
--- a/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala
+++ b/src/main/scala/pipedsl/passes/MarkNonRecursiveModulePass.scala
@@ -54,7 +54,7 @@ object MarkNonRecursiveModulePass extends ModulePass[ModuleDef] with ProgPass[Pr
//no other subexpressions - the Timing Type Checker ensures this
@tailrec
private def hasRecCall(e: Expr, m: Id): Boolean = e match {
- case ECall(mod, _, _) => mod == m
+ case ECall(mod, _, _, _) => mod == m
case ECast(_, exp) => hasRecCall(exp, m)
case _ => false
}
diff --git a/src/main/scala/pipedsl/passes/RemoveTimingPass.scala b/src/main/scala/pipedsl/passes/RemoveTimingPass.scala
index 2723bada..e5bdec63 100644
--- a/src/main/scala/pipedsl/passes/RemoveTimingPass.scala
+++ b/src/main/scala/pipedsl/passes/RemoveTimingPass.scala
@@ -34,7 +34,7 @@ object RemoveTimingPass extends CommandPass[Command] with ModulePass[ModuleDef]
newCases :+ cases(index).copy(body = newBody)
}
CSplit(newCases, newDefault)
- case CExpr(ECall(id, _, args)) =>
+ case CExpr(ECall(id, _, args, isAtomic)) =>
val assigns: ListBuffer[Command] = new ListBuffer[Command]()
val newArgs: ListBuffer[Expr] = new ListBuffer[Expr]()
for (index <- args.indices) {
@@ -42,7 +42,7 @@ object RemoveTimingPass extends CommandPass[Command] with ModulePass[ModuleDef]
assigns.addOne(CAssign(arg, args(index)))
newArgs.addOne(arg)
}
- calls.addOne(CExpr(ECall(id, None, newArgs.toList)))
+ calls.addOne(CExpr(ECall(id, None, newArgs.toList, isAtomic)))
convertCListToCSeq(assigns, 0)
case _ => c
}
diff --git a/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala b/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala
index ea5c32b4..e4e3fbd0 100644
--- a/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala
+++ b/src/main/scala/pipedsl/passes/SimplifyRecvPass.scala
@@ -85,24 +85,24 @@ object SimplifyRecvPass extends CommandPass[Command] with ModulePass[ModuleDef]
CRecv(access, rhsAssgn.lhs).setPos(c.pos))
.setPos(c.pos))
.setPos(c.pos)
- case (EVar(_), ECall(id, name, args)) =>
+ case (EVar(_), ECall(id, name, args, isAtomic)) =>
//TODO cleanup and stop copying code
val argAssgns = args.foldLeft[(Command, List[Expr])]((CEmpty(), List()))((cs, a) => {
val argAssn = CAssign(newVar("carg", a.pos, a.typ), a).setPos(a.pos)
(CSeq(cs._1, argAssn).setPos(a.pos), cs._2 :+ argAssn.lhs)
})
- CSeq(argAssgns._1, CRecv(lhs, ECall(id, name, argAssgns._2).setPos(c.pos)).setPos(c.pos)).setPos(c.pos)
+ CSeq(argAssgns._1, CRecv(lhs, ECall(id, name, argAssgns._2, isAtomic).setPos(c.pos)).setPos(c.pos)).setPos(c.pos)
case (l@EVar(_), _) =>
CAssign(l, rhs).setPos(c.pos)
case _ => throw UnexpectedCase(c.pos)
}
//calls also get translated to send statements later
- case CExpr(ECall(id, name, args)) =>
+ case CExpr(ECall(id, name, args, isAtomic)) =>
val argAssgns = args.foldLeft[(Command, List[Expr])]((CEmpty(), List()))((cs, a) => {
val argAssn = CAssign(newVar("carg", a.pos, a.typ), a).setPos(a.pos)
(CSeq(cs._1, argAssn).setPos(a.pos), cs._2 :+ argAssn.lhs)
})
- CSeq(argAssgns._1, CExpr(ECall(id, name, argAssgns._2).setPos(c.pos)).setPos(c.pos)).setPos(c.pos)
+ CSeq(argAssgns._1, CExpr(ECall(id, name, argAssgns._2, isAtomic).setPos(c.pos)).setPos(c.pos)).setPos(c.pos)
case _ => c
}
diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala
index 5b36dbd3..58d21a36 100644
--- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala
+++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala
@@ -41,7 +41,7 @@ object BaseTypeChecker extends TypeChecks[Id, Type] {
val typList = f.args.foldLeft[List[Type]](List())((l, p) => { l :+ p.typ }) //TODO disallow memories as params
val fenv = f.args.foldLeft[Environment[Id, Type]](tenv)((env, p) => { env.add(p.name, p.typ)})
val ftyp = TFun(typList, f.ret)
- val e1 = checkCommand(f.body, fenv)
+ val e1 = checkCommand(f.name, f.body, fenv)
val rt = checkFuncWellFormed(f.body, e1)
if (rt.isEmpty) {
throw MalformedFunction(f.pos, "Missing return statement")
@@ -98,7 +98,7 @@ 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.body, bodyEnv)
+ checkCommand(m.name, m.body, bodyEnv)
outEnv
}
@@ -238,21 +238,21 @@ object BaseTypeChecker extends TypeChecks[Id, Type] {
* @param tenv
* @return
*/
- def checkCommand(c: Command, tenv: Environment[Id, Type]): Environment[Id, Type] = c match {
+ def checkCommand(modId: Id, c: Command, tenv: Environment[Id, Type]): Environment[Id, Type] = c match {
case CSeq(c1, c2) => {
- val e2 = checkCommand(c1, tenv)
- checkCommand(c2, e2)
+ val e2 = checkCommand(modId, c1, tenv)
+ checkCommand(modId, c2, e2)
}
case CTBar(c1, c2) => {
- val e2 = checkCommand(c1, tenv)
- checkCommand(c2, e2)
+ val e2 = checkCommand(modId, c1, tenv)
+ checkCommand(modId, c2, e2)
}
case CSplit(cases, default) => {
- var endEnv = checkCommand(default, tenv)
+ var endEnv = checkCommand(modId, default, tenv)
for (c <- cases) {
val (condTyp, cenv) = checkExpression(c.cond, tenv, None)
condTyp.matchOrError(c.cond.pos, "case condition", "boolean") { case _: TBool => () }
- val benv = checkCommand(c.body, cenv)
+ val benv = checkCommand(modId, c.body, cenv)
endEnv = endEnv.intersect(benv)
}
endEnv
@@ -260,8 +260,8 @@ object BaseTypeChecker extends TypeChecks[Id, Type] {
case CIf(cond, cons, alt) => {
val (condTyp, cenv) = checkExpression(cond, tenv, None)
condTyp.matchOrError(cond.pos, "if condition", "boolean") { case _: TBool => () }
- val etrue = checkCommand(cons, cenv)
- val efalse = checkCommand(alt, cenv)
+ val etrue = checkCommand(modId, cons, cenv)
+ val efalse = checkCommand(modId, alt, cenv)
etrue.intersect(efalse)
}
case CAssign(lhs, rhs) => {
@@ -302,11 +302,13 @@ object BaseTypeChecker extends TypeChecks[Id, Type] {
{
case _: TMemType => tenv
case _: TLockedMemType => tenv
+ case _: TModType => tenv
}
case CLockEnd(mod) => tenv(mod).matchOrError(mod.pos, "lock reservation start", "Locked Memory or Module Type")
{
case _: TMemType => tenv
case _: TLockedMemType => tenv
+ case _: TModType => tenv
}
case CLockOp(mem, _, _, _, _) =>
tenv(mem.id).matchOrError(mem.pos, "lock operation", "Locked Memory or Module Type")
@@ -322,6 +324,12 @@ object BaseTypeChecker extends TypeChecks[Id, Type] {
case _ => throw UnexpectedType(mem.pos, s"lock operation $c", "ubit<" + memt.addrSize + ">", idxt)
}
}
+ case t: TModType =>
+ mem.id.typ = Some(t)
+ if(mem.id == modId){
+ throw RecursiveCallLockAcquisition(mem.pos)
+ }
+ tenv
}
case CVerify(handle, args, preds, upd, cHandles) =>
//if there's an update clause check that stuff:
@@ -588,7 +596,7 @@ object BaseTypeChecker extends TypeChecks[Id, Type] {
case _ => throw UnexpectedType(func.pos, "function call", "function type", ftyp)
}
}
- case ECall(mod, name, args) => {
+ case ECall(mod, name, args, isAtomic) => {
val mtyp = tenv(mod)
mod.typ = Some(mtyp)
mtyp match {
diff --git a/src/main/scala/pipedsl/typechecker/LatencyChecker.scala b/src/main/scala/pipedsl/typechecker/LatencyChecker.scala
index 5c38a574..2cfc5aa1 100644
--- a/src/main/scala/pipedsl/typechecker/LatencyChecker.scala
+++ b/src/main/scala/pipedsl/typechecker/LatencyChecker.scala
@@ -69,7 +69,7 @@ object LatencyChecker
case EBitExtract(num, start, end) =>
case ETernary(cond, tval, fval) =>
case EApp(func, args) =>
- case ECall(mod, method, args) =>
+ case ECall(mod, method, args, isAtomic) =>
case EVar(id) =>
case ECast(ctyp, exp) =>
case expr: CirExpr =>
diff --git a/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala b/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala
index 322ef8d7..3eadefa4 100644
--- a/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala
+++ b/src/main/scala/pipedsl/typechecker/LinearExecutionChecker.scala
@@ -87,7 +87,7 @@ class LinearExecutionChecker(val ctx: Z3Context) extends TypeChecks[Id, Z3AST]
case EApp(_, args) =>
args.foreach(e => checkExpr(e, predicate))
case ECast(_, exp) => checkExpr(exp, predicate)
- case ECall(mod, name, args) =>
+ case ECall(mod, name, args, isAtomic) =>
args.foreach(a => checkExpr(a, predicate))
if(mod == currentPipe)
verifyRecursive(predicate, e.pos)
diff --git a/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala b/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala
index de57db66..88440b51 100644
--- a/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala
+++ b/src/main/scala/pipedsl/typechecker/LockConstraintChecker.scala
@@ -166,7 +166,7 @@ class LockConstraintChecker(lockMap: Map[Id, Set[LockArg]], lockGranularityMap:
} else {
env
}
- case (_, ECall(_, _, args)) =>
+ case (_, ECall(_, _, args, _)) =>
args.foldLeft(env)((e, a) => checkExpr(a, e, c.predicateCtx.get))
case _ => throw UnexpectedCase(c.pos)
}
@@ -211,7 +211,7 @@ class LockConstraintChecker(lockMap: Map[Id, Set[LockArg]], lockGranularityMap:
val env2 = checkExpr(tval, env1, predicates)
checkExpr(fval, env2, predicates)
case EApp(_, args) => args.foldLeft(env)((e, a) => checkExpr(a, e, predicates))
- case ECall(_, _, args) => args.foldLeft(env)((e, a) => checkExpr(a, e, predicates))
+ case ECall(_, _, args, _) => args.foldLeft(env)((e, a) => checkExpr(a, e, predicates))
case ECast(_, exp) => checkExpr(exp, env, predicates)
case _ => env
}
diff --git a/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala b/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala
index 87b6bb67..541dac5b 100644
--- a/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala
+++ b/src/main/scala/pipedsl/typechecker/LockOperationTypeChecker.scala
@@ -90,7 +90,7 @@ class LockOperationTypeChecker(val memGranularityMap:Map[Id, Map[Id, LockGranula
e.memOpType = Some(LockRead)
e.granularity = getLockGranularity(mem)
}
- case (_, ECall(_, _, _)) =>
+ case (_, ECall(_, _, _, _)) =>
case _ => throw UnexpectedCase(c.pos)
}
case CAssign(_, rhs) => checkExpr(rhs)
@@ -121,7 +121,7 @@ class LockOperationTypeChecker(val memGranularityMap:Map[Id, Map[Id, LockGranula
checkExpr(tval)
checkExpr(fval)
case EApp(_, args) => args.foreach(a => checkExpr(a))
- case ECall(_, _, args) => args.foreach(a => checkExpr(a))
+ case ECall(_, _, args, _) => args.foreach(a => checkExpr(a))
case ECast(_, exp) => checkExpr(exp)
case _ =>
}
diff --git a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala
index 19b5ec0a..613f23c9 100644
--- a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala
+++ b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala
@@ -29,10 +29,11 @@ object LockRegionChecker extends TypeChecks[Id, LockState] {
case TLockedMemType(_, _, _) => e.add(m.name, Free)
case TMemType(_, _, _,_ ,_ ,_) => e.add(m.name, Free)
//TODO eventually do need locks here
- case TModType(_, _, _, _) => e //no locks for modules , but they're an expected type
+ case TModType(_, _, _, _) => e.add(m.name, Free)
case TObject(_, _, _) => e //no locks here either
case _ => throw UnexpectedCase(m.pos)
})
+
val finalStates: Environment[Id, LockState] = checkLockRegions(m.body, nenv)
finalStates.getMappedKeys().foreach(m => finalStates(m) match {
case Locks.Reserved | Locks.Acquired => throw InvalidLockState(m.pos, m.v, finalStates(m), Locks.Released)
@@ -128,7 +129,12 @@ object LockRegionChecker extends TypeChecks[Id, LockState] {
case EBitExtract(num, _, _) => checkMemAccess(num, env)
case ETernary(cond, tval, fval) => checkMemAccess(cond, env); checkMemAccess(tval, env); checkMemAccess(fval, env)
case EApp(_, args) => args.foreach(a => checkMemAccess(a, env))
- case ECall(_, _, args) => args.foreach(a => checkMemAccess(a, env))
+ case ECall(mod, _, args, isAtomic) => {
+ if (isAtomic && env(mod) != Acquired) {
+ throw InvalidLockState(mod.pos, mod.v, env(mod), Acquired)
+ }
+ args.foreach(a => checkMemAccess(a, env))
+ }
case ECast(_, exp) => checkMemAccess(exp, env)
case _ => ()
}
diff --git a/src/main/scala/pipedsl/typechecker/PortChecker.scala b/src/main/scala/pipedsl/typechecker/PortChecker.scala
index 6c02bc8c..1de95609 100644
--- a/src/main/scala/pipedsl/typechecker/PortChecker.scala
+++ b/src/main/scala/pipedsl/typechecker/PortChecker.scala
@@ -59,6 +59,7 @@ class PortChecker(port_warn :Boolean) extends TypeChecks[Id, (Int, Int)]
case TMemType(_, _, _, _, r, w) => modLims.addOne((mod.name, (r, w)))
case TLockedMemType(TMemType(_, _, _, _, r, w), _, _) =>
modLims.addOne((mod.name, (r, w)))
+ case _ : TModType => modLims.addOne((mod.name, (1, 1)))
case _ =>
})
val port_map = checkPipe(m.body, emptyEnv())
@@ -298,7 +299,7 @@ class PortChecker(port_warn :Boolean) extends TypeChecks[Id, (Int, Int)]
.union(checkExpr(fval, cond_env, start_env))
case EApp(_, args) =>
args.foldLeft(env)((acc, e) => checkExpr(e, acc, start_env))
- case ECall(mod, _, args) =>
+ case ECall(mod, _, args, _) =>
/*perhaps we should have some restrictions on calling the same module*/
/*twice in a single cycle. I think I said that should be a nono*/
//callees += mod
diff --git a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala
index 65ef4296..744b0401 100644
--- a/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala
+++ b/src/main/scala/pipedsl/typechecker/TimingTypeChecker.scala
@@ -83,8 +83,8 @@ object TimingTypeChecker extends TypeChecks[Id, Type] {
case None => Set()
}
assignReadLocks(id, e, vars, nextVars)
- case (EVar(id), ECall(_,_,_)) if isRecv => (vars, nextVars + id)
- case (EVar(id), ECall(mod, Some(method), args)) =>
+ case (EVar(id), ECall(_,_,_,_)) if isRecv => (vars, nextVars + id)
+ case (EVar(id), ECall(mod, Some(method), args, _)) =>
args.foreach(a => checkExpr(a, vars))
mod.typ.get match {
case TObject(_, _, methods) => methods(method)._2 match {
@@ -93,7 +93,7 @@ object TimingTypeChecker extends TypeChecks[Id, Type] {
}
case t@_ => throw UnexpectedType(mod.pos, "External Call", "Object Type", t)
}
- case (EVar(_), ECall(_, None, _)) => //this is calling another PDL pipeline, not allowed in assign
+ case (EVar(_), ECall(_, None, _, _)) => //this is calling another PDL pipeline, not allowed in assign
throw UnexpectedAsyncReference(rhs.pos, "no calls in assign")
case (EVar(id), _) =>
val (t1, nt1) = if (isRecv) { (vars, nextVars + id) } else { (vars + id, nextVars) }
@@ -313,7 +313,7 @@ object TimingTypeChecker extends TypeChecks[Id, Type] {
throw UnexpectedAsyncReference(a.pos, a.toString)
})
Combinational
- case ECall(mod, name, args) =>
+ case ECall(mod, name, args, isAtomic) =>
args.foreach(a => if(checkExpr(a, vars) != Combinational) {
throw UnexpectedAsyncReference(a.pos, a.toString)
})
diff --git a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala
index 19201f3b..db55b7bc 100644
--- a/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala
+++ b/src/main/scala/pipedsl/typechecker/TypeInferenceWrapper.scala
@@ -684,11 +684,11 @@ object TypeInferenceWrapper
val retEnv = runningEnv.apply_subst_typeenv(retSubst)
val retTyp = apply_subst_typ(retSubst, retType)
(retSubst, retTyp, retEnv, ap.copy(args = fixed_arg_list).copyMeta(ap))
- case ca@ECall(mod, name, args) if name.isEmpty =>
+ case ca@ECall(mod, name, args, isAtomic) if name.isEmpty =>
if (!env(mod).isInstanceOf[TModType]) throw UnexpectedType(e.pos, "Module Call", "TModType", env(mod))
val expectedType = getArrowModType(env(mod).asInstanceOf[TModType])
substIntoCall(expectedType, ca, args, env)
- case ca@ECall(mod, method, args) if method.isDefined =>
+ case ca@ECall(mod, method, args, isAtomic) if method.isDefined =>
if (!env(mod).isInstanceOf[TObject]) throw UnexpectedType(e.pos, "Object Call", "TObject", env(mod))
val expectedType = env(mod).asInstanceOf[TObject].methods(method.get)._1
substIntoCall(expectedType, ca, args, env)