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)