From e37cbd10704a8babc4d2123cc1680a09c7f32986 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Thu, 28 Oct 2021 13:48:52 -0400 Subject: [PATCH 1/5] add test --- .../tests/risc-pipe/pipeline-interface.pdl | 468 ++++++++++++++++++ .../tests/risc-pipe/risc-pipe-microcoded.pdl | 359 ++++++++++++++ 2 files changed, 827 insertions(+) create mode 100644 src/test/tests/risc-pipe/pipeline-interface.pdl create mode 100644 src/test/tests/risc-pipe/risc-pipe-microcoded.pdl diff --git a/src/test/tests/risc-pipe/pipeline-interface.pdl b/src/test/tests/risc-pipe/pipeline-interface.pdl new file mode 100644 index 00000000..3e7d0587 --- /dev/null +++ b/src/test/tests/risc-pipe/pipeline-interface.pdl @@ -0,0 +1,468 @@ +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); + } +} + + +pipe cpu(pc: int<16>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div]: bool { + spec_check(); + start(imem); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + end(imem); + s <- speccall cpu(pc + 1<16>); + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + uint<3> doAdd = u0<3>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool isMul = isMDiv && (funct3 < u4<3>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + spec_barrier(); + bool notBranch = (!isBranch) && (!isJal) && (!isJalr); + if ((!done) && (notBranch)) { + verify(s, pc + 1<16>); + } else { + invalidate(s); + } + start(rf); + if (needrs1) { + int<32> rf1 = rf[rs1]; + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + int<32> rf2 = rf[rs2]; + } else { + int<32> rf2 = 0<32>; + } + if (writerd) { + reserve(rf[rd], W); + } + end(rf); + 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>; + }}} + + if (!done) { + if (!notBranch) { + call cpu(npc); + } + } + 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>; + } + 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) && (isLoad || isDiv)) { + block(rf[rd]); + if (isLoad) { + int<32> insnout = maskLoad(wdata, funct3, boff); + } else { + int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + int<32> insnout = divout; + } + rf[rd] <- insnout; + } else { + int<32> insnout = rddata; + } + if (writerd) { + print("Writing %d to r%d", insnout, rd); + release(rf[rd]); + } + if (done) { output(true); } +} + +pipe cisc5(pc: int<16>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div, c: cpu, fifo: int<32>[5](Queue)]: bool { + spec_check(); + //inst fetch + --- + //decode + s <- spec call cisc4(pc+1); + c1 <- async call cpu(mc1); + --- + c2 <- async call cpu(mc2); + + +} +pipe cisc4(pc: int<16>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div, c: cpu, fifo: int<32>[5](Queue)]: bool { + spec_check(); + //inst fetch + --- + //decode + s <- spec call cisc4(pc+1); + --- + uint<32> c1_out <- call cpu(mc1); //seq call cpu([mc1, mc2, mc3]); + --- + uint<32> c2_out <- spec call cpu(mc2); //cond call cpu(mc2, c1_out); + --- + uint<32> c3_out <- spec call cpu(mc3); //cond call cpu(mc3, c2_out); + --- + //check c3 success + verify(s, pc+1); + +} + +pipe cisc2(pc: int<16>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div, c: cpu, fifo: int<32>[5](Queue)]: bool { + acquire(imem, R); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + release(imem); + --- + uint<32> cpu_call_output <- call cpu(pc); + call cisc2(pc + 1<16>); + reserve(fifo); + --- + block(fifo); + fifo[0] <- cpu_call_output; + release(fifo); + // I think we should be able to describe some snoopy signals across module boundary (which I currently implement with shared memory) + // But introducing that might break PDL's current security guarentees. (Not sure about this) + // Maybe do something like the spec call where we just add a handle to the thread to indicate whether to kill or revert the thread to limit the scope so we can verify correctness +} + +pipe cisc(pc: int<16>, robhead: uint<4>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div, c: cpu, rob: int<32>[4](Queue)]: bool{ + acquire(imem, R); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + release(imem); + --- + bool isOccupied = rob[robhead]{31:31} == 1<1>; + bool isException = rob[robhead]{30:26} == 0b11111<5>; + if(isOccupied){ + if(isException){ + call cisc(pc-16, robhead); + // And also load checkpoints and revert changes? + // For cache load I guess this is good enough + }else{ + call cisc(pc, robhead); + // Ideally we just want to stall. But there arent ways of explicitly forcing stalls here. + // So we load the same pc + } + }else{ + acquire(rob); + rob[robhead] <- 1<1> ++ 0<15> ++ pc; + release(rob); + uint<5> newrobhead = (robhead + u1<5>) % u16<5>; + + uint<32> cpu_call_output <- call cpu(pc<16>); + call cisc(pc+1<32>, newrobhead); + // This is the actual inner pipeline call. + } + --- + acquire(rob); + + bool isPos0 = cast(rob[0], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos1 = cast(rob[1], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos2 = cast(rob[2], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos3 = cast(rob[3], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos4 = cast(rob[4], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos5 = cast(rob[5], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos6 = cast(rob[6], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos7 = cast(rob[7], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos8 = cast(rob[8], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos9 = cast(rob[9], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos10 = cast(rob[10], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos11 = cast(rob[11], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos12 = cast(rob[12], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos14 = cast(rob[13], uint<32>){15:0} == cpu_call_output{15:0}; + bool isPos15 = cast(rob[14], uint<32>){15:0} == cpu_call_output{15:0}; + + if(isPos0){ + rob[0] <- cpu_call_output; + } + if(isPos1){ + rob[1] <- cpu_call_output; + } + if(isPos2){ + rob[2] <- cpu_call_output; + } + if(isPos3){ + rob[3] <- cpu_call_output; + } + if(isPos4){ + rob[4] <- cpu_call_output; + } + if(isPos5){ + rob[5] <- cpu_call_output; + } + if(isPos6){ + rob[6] <- cpu_call_output; + } + if(isPos7){ + rob[7] <- cpu_call_output; + } + if(isPos8){ + rob[8] <- cpu_call_output; + } + if(isPos9){ + rob[9] <- cpu_call_output; + } + if(isPos10){ + rob[10] <- cpu_call_output; + } + if(isPos11){ + rob[11] <- cpu_call_output; + } + if(isPos12){ + rob[12] <- cpu_call_output; + } + if(isPos13){ + rob[13] <- cpu_call_output; + } + if(isPos14){ + rob[14] <- cpu_call_output; + } + if(isPos15){ + rob[15] <- cpu_call_output; + } + + release(rob); +} + +pipe cisc3(){ + acquire(imem, R); + uint<16> pcaddr = cast(pc, uint<16>); + int<32> insn <- imem[pcaddr]; + release(imem); + --- + //decode + speccall(cpu(mc1), ); +} +circuit { + ti = memory(int<32>, 16); + i = Queue(ti); + tb = memory(int<32>, 4); + rob = Queue(ti); + td = memory(int<32>, 16); + rf = regfile(int<32>, 5); +// sr = rflock ForwardRenameRF(int<32>, 5, 64); + r = BypassQueue(rf); + div = new multi_stg_div[]; + c = new cpu[r, i, td, div]; + cisc_cpu = new cisc[r, i, td, div, c, rob]; + call cisc_cpu(0<16>); +} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-microcoded.pdl b/src/test/tests/risc-pipe/risc-pipe-microcoded.pdl new file mode 100644 index 00000000..e90e0ebd --- /dev/null +++ b/src/test/tests/risc-pipe/risc-pipe-microcoded.pdl @@ -0,0 +1,359 @@ +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; + }}}}}}} + +} + +def br(pc: int<16>, off:int<16>, op:uint<3>, arg1:int<32>, arg2:int<32>): int<16> { + //divide by 4 b/c we count instructions not bytes + int<16> offpc = pc + (off >> 2); + int<16> npc = pc + 1<16>; + if (op == u0<3>) { //BEQ + if (arg1 == arg2) { return offpc; } else { return npc; } + } else { + if (op == u1<3>) { //BNE + if (arg1 != arg2) { return offpc; } else { return npc; } + } else { + if (op == u4<3>) { //BLT + if (arg1 < arg2) { return offpc; } else { return npc; } + } else { + if (op == u5<3>) { //BGE + if (arg1 >= arg2) { return offpc; } else { return npc; } + } else { + if (op == u6<3>) { //BLTU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + if (un1 < un2) { return offpc; } else { return npc; } + } else { + if (op == u7<3>) { //BGEU + uint<32> un1 = cast(arg1, uint<32>); + uint<32> un2 = cast(arg2, uint<32>); + if (un1 >= un2) { return offpc; } else { return npc; } + } else { + return npc; + }}}}}} +} + + +def storeMask(off: uint<2>, op: uint<3>): uint<4> { + if (op == u0<3>) { //SB + return (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; + if (cnt == u31<5>) { + output( (retQuot) ? nq : na ); + } else { + call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); + } +} + + +pipe cpu(pc: int<16>, mcQueuePos: uint<2>)[rf: int<32>[5](FAQueue), imem: int<32>[16], dmem: int<32>[16], mcQueue: int<32>[2], div: multi_stg_div]: bool { + if (mcQueuePos == 0b00<2>){ + start(imem); + int<32> insn <- imem[cast(pc, uint<16>)]; + end(imem); + } else { + start(mcQueue); + acquire(mcQueue); + int<32> insn <- mcQueue[mcQueuePos]; + release(mcQueue); + end(mcQueue); + } + --- + int<7> orig_opcode = insn{6:0}; + if (mcQueuePos == 0b00<2>){ + bool isADDS = orig_opcode == 0b1000000<7>; + bool isBRS = orig_opcode == 0b1000001<7>; + split { //breakdown original instruction into existing instructions + case: (isADDS){ + int<5> add_rs1 = insn{19:15}; + int<5> add_rd = insn{11:7}; + + int<32> inst1 = 0b0000000<7> ++ adds_rd ++ adds_rs1 ++ 0b000<3> ++ 0b0110011<7>; // add rd, rs, rd + uint<2> newMcQueuePos = mcQueuePos; + } + case: (isBRS){ + int<5> common_rd = insn{11:7}; + + int<32> inst1 = 0xfff<12> ++ common_rd ++ 0b100<3> ++ common_rd ++ 0b0010011<7>; // xori rd, rd, 0xffffffff (load 0xfffff to first 20 bits) + int<32> inst2 = insn{12} ++ insn{10:5} ++ 0b00000<5> ++ common_rd ++ 0b000<3> ++ insn{4:1} ++ insn {11} ++ 0b0010011<7> // beq rd, x0, imm + + // Save new insts to the mccode queue + acquire(mcQueue); + mcQueue[u0<2>] <- inst2; + release(mcQueue); + + // Set mcqueue length/ which inst to read next thread + uint<2> newMcQueuePos = u1<2>; // Indicates 2 instructions are saved in queue + } + default: { + uint<2> newMcQueuePos = mcQueuePos; // No change to queue pos + //do nothing, keep the original instruction + } + } + } else { + uint<2> newMcQueuePos = mcQueuePos - u1<2>; // Decrease queue pos by 1 since we poped 1 inst in IF + //do nothing, already fetched from microcode queue + } + --- + //This OPCODE is J Self and thus we're using it to signal termination + bool done = insn == 0x0000006f<32>; + int<7> opcode = insn{6:0}; + uint<5> rs1 = cast(insn{19:15}, uint<5>); + uint<5> rs2 = cast(insn{24:20}, uint<5>); + uint<5> rd = cast(insn{11:7}, uint<5>); + uint<7> funct7 = cast(insn{31:25}, uint<7>); + uint<3> funct3 = cast(insn{14:12}, uint<3>); + int<1> flipBit = insn{30:30}; + int<32> immI = cast(insn{31:20}, int<32>); + int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); + int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; + int<16> immB = cast(immBTmp, int<16>); + int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; + int<32> immJ = cast(immJTmp, int<32>); + int<12> immJRTmp = insn{31:20}; + int<16> immJR = cast(immJRTmp, int<16>); + int<32> immU = insn{31:12} ++ 0<12>; + bool isOpImm = opcode == 0b0010011<7>; + bool flip = (!isOpImm) && (flipBit == 1<1>); + bool isLui = opcode == 0b0110111<7>; + bool isAui = opcode == 0b0010111<7>; + bool isOp = opcode == 0b0110011<7>; + bool isJal = opcode == 0b1101111<7>; + bool isJalr = opcode == 0b1100111<7>; + bool isBranch = opcode == 0b1100011<7>; + bool isStore = opcode == 0b0100011<7>; + bool isLoad = opcode == 0b0000011<7>; + bool isMDiv = (funct7 == u1<7>) && isOp; + bool isDiv = isMDiv && (funct3 >= u4<3>); + bool needrs1 = !isJal; + bool needrs2 = isOp || isBranch || isStore || isJalr; + bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); + start(rf); + if (needrs1) { + int<32> rf1 = rf[rs1]; + } else { + int<32> rf1 = 0<32>; + } + if (needrs2) { + int<32> rf2 = rf[rs2]; + } else { + int<32> rf2 = 0<32>; + } + if (writerd) { + reserve(rf[rd]); + } + end(rf); + --- + if (isBranch) { + int<16> npc = br(pc, immB, funct3, rf1, rf2); + } else { + if (isJal) { + //divide by 4 since it counts bytes instead of insns + int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); + int<16> npc = npc32{15:0}; + } else { + if (isJalr) { + int<16> npc = (rf1{15:0} + immJR) >> 2; + } else { + int<16> npc = pc + 1<16>; + }}} + if (!done) { call cpu(npc, newMcQueuePos); } + + int<32> alu_arg2 = (isOpImm) ? immI : rf2; + + if (isDiv) { + int<32> sdividend = sign(rf1); + //For REM, ignore sign of divisor + int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); + bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); + bool invertRes = isSignedDiv && (sdividend != sdivisor); + uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); + uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); + bool retQuot = funct3 <= u5<3>; + uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); + } else { + uint<32> udivout <- u0<32>; + bool invertRes = false; + } + --- + split { + case: (isLui) { + int<32> alu_res = immU; + } + case: (isAui) { + //all pc computation needs to be multiplied by 4 + int<32> pc32 = (0<16> ++ pc) << 2; + int<32> alu_res = pc32 + immU; + } + case: (isDiv) { + int<32> alu_res = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); + } + case: (isMDiv) { + int<32> alu_res = mul(rf1, rf2, funct3); + } + default: { + int<32> alu_res = alu(rf1, alu_arg2, funct3, flip); + } + } + split { + case: (isStore) { + //addresses also are word-sized + int<32> tmp = immS + rf1; + uint<32> ctmp = cast(tmp, uint<32>); + uint<16> memaddr = (ctmp >> 2){15:0}; + uint<2> boff = ctmp{1:0}; + } + case: (isLoad) { + //addresses also are word-sized + int<32> tmp = immI + rf1; + uint<32> ctmp = cast(tmp, uint<32>); + uint<16> memaddr = (ctmp >> 2){15:0}; + uint<2> boff = ctmp{1:0}; + } + default: { + uint<16> memaddr = u0<16>; + uint<2> boff = u0<2>; + } + } + --- + start(dmem); + split { + case: (isLoad) { + uint<16> raddr = memaddr; + int<32> wdata <- dmem[raddr]; + } + case: (isStore) { + uint<16> waddr = memaddr; + //use bottom bits of data and place in correct offset + //shift by boff*8 + uint<5> nboff = boff ++ u0<3>; + dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); + int<32> wdata <- 0<32>; + } + default: { + int<32> wdata <- 0<32>; + } + } + end(dmem); + --- + print("PC: %h", pc << 2); + print("INSN: %h", insn); + if (writerd) { + block(rf[rd]); + if (isLoad) { + int<32> insnout = maskLoad(wdata, funct3, boff); + } else { + if (isJal || isJalr) { + //need to multiply by 4 b/c it is arch visible. + int<16> nextpc = pc + 1<16>; + int<32> insnout = 0<16> ++ (nextpc << 2); //todo make pc 32 bits + } else { + int<32> insnout = alu_res; + }} + print("Writing %d to r%d", insnout, rd); + rf[rd] <- insnout; + release(rf[rd]); + } + if (done) { output(true); } +} + +circuit { + ti = memory(int<32>, 16); + td = memory(int<32>, 16); + rf = regfile(int<32>, 5); + r = FAQueue(rf); + div = new multi_stg_div[]; + c = new cpu[r, ti, td, div]; + call c(0<16>, 0); +} \ No newline at end of file From 4d8ae29a37dd15c18ffd871375eb6302e5418fab Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Tue, 30 Nov 2021 16:30:26 -0500 Subject: [PATCH 2/5] init lock checking for pipe: --- examples/cache-call.pdl | 0 examples/test.pdl | 0 src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala | 8 ++++++++ .../scala/pipedsl/typechecker/BaseTypeChecker.scala | 5 +++++ .../scala/pipedsl/typechecker/LockRegionChecker.scala | 10 ++++++++-- src/main/scala/pipedsl/typechecker/PortChecker.scala | 1 + 6 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 examples/cache-call.pdl create mode 100644 examples/test.pdl 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..e69de29b diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index 044de8df..7a14bd6d 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 diff --git a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index 5b36dbd3..b388bc11 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -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,9 @@ 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) + tenv } case CVerify(handle, args, preds, upd, cHandles) => //if there's an update clause check that stuff: diff --git a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala index 19b5ec0a..800194ef 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) => { + if (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..06569fb5 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()) From c62e9d133063ef3f20d7b95cded66df79a511fbe Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 1 Dec 2021 15:17:04 -0500 Subject: [PATCH 3/5] fix --- examples/test.pdl | 46 ++ src/main/scala/pipedsl/Interpreter.scala | 2 +- src/main/scala/pipedsl/Parser.scala | 4 +- .../scala/pipedsl/codegen/bsv/BSVSyntax.scala | 2 +- .../codegen/bsv/BluespecGeneration.scala | 2 +- .../scala/pipedsl/common/PrettyPrinter.scala | 2 +- src/main/scala/pipedsl/common/Syntax.scala | 2 +- src/main/scala/pipedsl/common/Utilities.scala | 6 +- .../pipedsl/passes/CanonicalizePass.scala | 4 +- .../pipedsl/passes/ConvertAsyncPass.scala | 4 +- .../passes/LockOpTranslationPass.scala | 4 +- .../passes/MarkNonRecursiveModulePass.scala | 2 +- .../pipedsl/passes/RemoveTimingPass.scala | 4 +- .../pipedsl/passes/SimplifyRecvPass.scala | 8 +- .../pipedsl/typechecker/BaseTypeChecker.scala | 2 +- .../pipedsl/typechecker/LatencyChecker.scala | 2 +- .../typechecker/LinearExecutionChecker.scala | 2 +- .../typechecker/LockConstraintChecker.scala | 4 +- .../LockOperationTypeChecker.scala | 4 +- .../typechecker/LockRegionChecker.scala | 4 +- .../pipedsl/typechecker/PortChecker.scala | 2 +- .../typechecker/TimingTypeChecker.scala | 8 +- .../typechecker/TypeInferenceWrapper.scala | 4 +- .../tests/risc-pipe/pipeline-interface.pdl | 468 ------------------ .../tests/risc-pipe/risc-pipe-microcoded.pdl | 359 -------------- 25 files changed, 85 insertions(+), 866 deletions(-) delete mode 100644 src/test/tests/risc-pipe/pipeline-interface.pdl delete mode 100644 src/test/tests/risc-pipe/risc-pipe-microcoded.pdl diff --git a/examples/test.pdl b/examples/test.pdl index e69de29b..a72ef9d5 100644 --- a/examples/test.pdl +++ 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..03bc08c5 100644 --- a/src/main/scala/pipedsl/Parser.scala +++ b/src/main/scala/pipedsl/Parser.scala @@ -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 7a14bd6d..5d5335fc 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -199,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..fa42c4a2 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala @@ -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/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index de853e93..3c3b3c7b 100644 --- a/src/main/scala/pipedsl/common/PrettyPrinter.scala +++ b/src/main/scala/pipedsl/common/PrettyPrinter.scala @@ -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..b306e90a 100644 --- a/src/main/scala/pipedsl/common/Syntax.scala +++ b/src/main/scala/pipedsl/common/Syntax.scala @@ -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..8c6b14e5 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) @@ -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 b388bc11..b1e844a7 100644 --- a/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala +++ b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala @@ -593,7 +593,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 800194ef..613f23c9 100644 --- a/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala +++ b/src/main/scala/pipedsl/typechecker/LockRegionChecker.scala @@ -129,8 +129,8 @@ 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(mod, _, args) => { - if (env(mod) != Acquired) { + 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)) diff --git a/src/main/scala/pipedsl/typechecker/PortChecker.scala b/src/main/scala/pipedsl/typechecker/PortChecker.scala index 06569fb5..1de95609 100644 --- a/src/main/scala/pipedsl/typechecker/PortChecker.scala +++ b/src/main/scala/pipedsl/typechecker/PortChecker.scala @@ -299,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) diff --git a/src/test/tests/risc-pipe/pipeline-interface.pdl b/src/test/tests/risc-pipe/pipeline-interface.pdl deleted file mode 100644 index 3e7d0587..00000000 --- a/src/test/tests/risc-pipe/pipeline-interface.pdl +++ /dev/null @@ -1,468 +0,0 @@ -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); - } -} - - -pipe cpu(pc: int<16>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div]: bool { - spec_check(); - start(imem); - uint<16> pcaddr = cast(pc, uint<16>); - int<32> insn <- imem[pcaddr]; - end(imem); - s <- speccall cpu(pc + 1<16>); - --- - //This OPCODE is J Self and thus we're using it to signal termination - bool done = insn == 0x0000006f<32>; - int<7> opcode = insn{6:0}; - uint<5> rs1 = cast(insn{19:15}, uint<5>); - uint<5> rs2 = cast(insn{24:20}, uint<5>); - uint<5> rd = cast(insn{11:7}, uint<5>); - uint<7> funct7 = cast(insn{31:25}, uint<7>); - uint<3> funct3 = cast(insn{14:12}, uint<3>); - int<1> flipBit = insn{30:30}; - int<32> immI = cast(insn{31:20}, int<32>); - int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); - int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; - int<16> immB = cast(immBTmp, int<16>); - int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; - int<32> immJ = cast(immJTmp, int<32>); - int<12> immJRTmp = insn{31:20}; - int<16> immJR = cast(immJRTmp, int<16>); - int<32> immU = insn{31:12} ++ 0<12>; - uint<3> doAdd = u0<3>; - bool isOpImm = opcode == 0b0010011<7>; - bool flip = (!isOpImm) && (flipBit == 1<1>); - bool isLui = opcode == 0b0110111<7>; - bool isAui = opcode == 0b0010111<7>; - bool isOp = opcode == 0b0110011<7>; - bool isJal = opcode == 0b1101111<7>; - bool isJalr = opcode == 0b1100111<7>; - bool isBranch = opcode == 0b1100011<7>; - bool isStore = opcode == 0b0100011<7>; - bool isLoad = opcode == 0b0000011<7>; - bool isMDiv = (funct7 == u1<7>) && isOp; - bool isDiv = isMDiv && (funct3 >= u4<3>); - bool isMul = isMDiv && (funct3 < u4<3>); - bool needrs1 = !isJal; - bool needrs2 = isOp || isBranch || isStore || isJalr; - bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); - spec_barrier(); - bool notBranch = (!isBranch) && (!isJal) && (!isJalr); - if ((!done) && (notBranch)) { - verify(s, pc + 1<16>); - } else { - invalidate(s); - } - start(rf); - if (needrs1) { - int<32> rf1 = rf[rs1]; - } else { - int<32> rf1 = 0<32>; - } - if (needrs2) { - int<32> rf2 = rf[rs2]; - } else { - int<32> rf2 = 0<32>; - } - if (writerd) { - reserve(rf[rd], W); - } - end(rf); - 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>; - }}} - - if (!done) { - if (!notBranch) { - call cpu(npc); - } - } - 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>; - } - 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) && (isLoad || isDiv)) { - block(rf[rd]); - if (isLoad) { - int<32> insnout = maskLoad(wdata, funct3, boff); - } else { - int<32> divout = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); - int<32> insnout = divout; - } - rf[rd] <- insnout; - } else { - int<32> insnout = rddata; - } - if (writerd) { - print("Writing %d to r%d", insnout, rd); - release(rf[rd]); - } - if (done) { output(true); } -} - -pipe cisc5(pc: int<16>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div, c: cpu, fifo: int<32>[5](Queue)]: bool { - spec_check(); - //inst fetch - --- - //decode - s <- spec call cisc4(pc+1); - c1 <- async call cpu(mc1); - --- - c2 <- async call cpu(mc2); - - -} -pipe cisc4(pc: int<16>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div, c: cpu, fifo: int<32>[5](Queue)]: bool { - spec_check(); - //inst fetch - --- - //decode - s <- spec call cisc4(pc+1); - --- - uint<32> c1_out <- call cpu(mc1); //seq call cpu([mc1, mc2, mc3]); - --- - uint<32> c2_out <- spec call cpu(mc2); //cond call cpu(mc2, c1_out); - --- - uint<32> c3_out <- spec call cpu(mc3); //cond call cpu(mc3, c2_out); - --- - //check c3 success - verify(s, pc+1); - -} - -pipe cisc2(pc: int<16>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div, c: cpu, fifo: int<32>[5](Queue)]: bool { - acquire(imem, R); - uint<16> pcaddr = cast(pc, uint<16>); - int<32> insn <- imem[pcaddr]; - release(imem); - --- - uint<32> cpu_call_output <- call cpu(pc); - call cisc2(pc + 1<16>); - reserve(fifo); - --- - block(fifo); - fifo[0] <- cpu_call_output; - release(fifo); - // I think we should be able to describe some snoopy signals across module boundary (which I currently implement with shared memory) - // But introducing that might break PDL's current security guarentees. (Not sure about this) - // Maybe do something like the spec call where we just add a handle to the thread to indicate whether to kill or revert the thread to limit the scope so we can verify correctness -} - -pipe cisc(pc: int<16>, robhead: uint<4>)[rf: int<32>[5](BypassQueue), imem: int<32>[16](Queue), dmem: int<32>[16], div: multi_stg_div, c: cpu, rob: int<32>[4](Queue)]: bool{ - acquire(imem, R); - uint<16> pcaddr = cast(pc, uint<16>); - int<32> insn <- imem[pcaddr]; - release(imem); - --- - bool isOccupied = rob[robhead]{31:31} == 1<1>; - bool isException = rob[robhead]{30:26} == 0b11111<5>; - if(isOccupied){ - if(isException){ - call cisc(pc-16, robhead); - // And also load checkpoints and revert changes? - // For cache load I guess this is good enough - }else{ - call cisc(pc, robhead); - // Ideally we just want to stall. But there arent ways of explicitly forcing stalls here. - // So we load the same pc - } - }else{ - acquire(rob); - rob[robhead] <- 1<1> ++ 0<15> ++ pc; - release(rob); - uint<5> newrobhead = (robhead + u1<5>) % u16<5>; - - uint<32> cpu_call_output <- call cpu(pc<16>); - call cisc(pc+1<32>, newrobhead); - // This is the actual inner pipeline call. - } - --- - acquire(rob); - - bool isPos0 = cast(rob[0], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos1 = cast(rob[1], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos2 = cast(rob[2], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos3 = cast(rob[3], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos4 = cast(rob[4], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos5 = cast(rob[5], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos6 = cast(rob[6], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos7 = cast(rob[7], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos8 = cast(rob[8], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos9 = cast(rob[9], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos10 = cast(rob[10], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos11 = cast(rob[11], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos12 = cast(rob[12], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos14 = cast(rob[13], uint<32>){15:0} == cpu_call_output{15:0}; - bool isPos15 = cast(rob[14], uint<32>){15:0} == cpu_call_output{15:0}; - - if(isPos0){ - rob[0] <- cpu_call_output; - } - if(isPos1){ - rob[1] <- cpu_call_output; - } - if(isPos2){ - rob[2] <- cpu_call_output; - } - if(isPos3){ - rob[3] <- cpu_call_output; - } - if(isPos4){ - rob[4] <- cpu_call_output; - } - if(isPos5){ - rob[5] <- cpu_call_output; - } - if(isPos6){ - rob[6] <- cpu_call_output; - } - if(isPos7){ - rob[7] <- cpu_call_output; - } - if(isPos8){ - rob[8] <- cpu_call_output; - } - if(isPos9){ - rob[9] <- cpu_call_output; - } - if(isPos10){ - rob[10] <- cpu_call_output; - } - if(isPos11){ - rob[11] <- cpu_call_output; - } - if(isPos12){ - rob[12] <- cpu_call_output; - } - if(isPos13){ - rob[13] <- cpu_call_output; - } - if(isPos14){ - rob[14] <- cpu_call_output; - } - if(isPos15){ - rob[15] <- cpu_call_output; - } - - release(rob); -} - -pipe cisc3(){ - acquire(imem, R); - uint<16> pcaddr = cast(pc, uint<16>); - int<32> insn <- imem[pcaddr]; - release(imem); - --- - //decode - speccall(cpu(mc1), ); -} -circuit { - ti = memory(int<32>, 16); - i = Queue(ti); - tb = memory(int<32>, 4); - rob = Queue(ti); - td = memory(int<32>, 16); - rf = regfile(int<32>, 5); -// sr = rflock ForwardRenameRF(int<32>, 5, 64); - r = BypassQueue(rf); - div = new multi_stg_div[]; - c = new cpu[r, i, td, div]; - cisc_cpu = new cisc[r, i, td, div, c, rob]; - call cisc_cpu(0<16>); -} \ No newline at end of file diff --git a/src/test/tests/risc-pipe/risc-pipe-microcoded.pdl b/src/test/tests/risc-pipe/risc-pipe-microcoded.pdl deleted file mode 100644 index e90e0ebd..00000000 --- a/src/test/tests/risc-pipe/risc-pipe-microcoded.pdl +++ /dev/null @@ -1,359 +0,0 @@ -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; - }}}}}}} - -} - -def br(pc: int<16>, off:int<16>, op:uint<3>, arg1:int<32>, arg2:int<32>): int<16> { - //divide by 4 b/c we count instructions not bytes - int<16> offpc = pc + (off >> 2); - int<16> npc = pc + 1<16>; - if (op == u0<3>) { //BEQ - if (arg1 == arg2) { return offpc; } else { return npc; } - } else { - if (op == u1<3>) { //BNE - if (arg1 != arg2) { return offpc; } else { return npc; } - } else { - if (op == u4<3>) { //BLT - if (arg1 < arg2) { return offpc; } else { return npc; } - } else { - if (op == u5<3>) { //BGE - if (arg1 >= arg2) { return offpc; } else { return npc; } - } else { - if (op == u6<3>) { //BLTU - uint<32> un1 = cast(arg1, uint<32>); - uint<32> un2 = cast(arg2, uint<32>); - if (un1 < un2) { return offpc; } else { return npc; } - } else { - if (op == u7<3>) { //BGEU - uint<32> un1 = cast(arg1, uint<32>); - uint<32> un2 = cast(arg2, uint<32>); - if (un1 >= un2) { return offpc; } else { return npc; } - } else { - return npc; - }}}}}} -} - - -def storeMask(off: uint<2>, op: uint<3>): uint<4> { - if (op == u0<3>) { //SB - return (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; - if (cnt == u31<5>) { - output( (retQuot) ? nq : na ); - } else { - call multi_stg_div(nnum, denom, nq, na, cnt + u1<5>, retQuot); - } -} - - -pipe cpu(pc: int<16>, mcQueuePos: uint<2>)[rf: int<32>[5](FAQueue), imem: int<32>[16], dmem: int<32>[16], mcQueue: int<32>[2], div: multi_stg_div]: bool { - if (mcQueuePos == 0b00<2>){ - start(imem); - int<32> insn <- imem[cast(pc, uint<16>)]; - end(imem); - } else { - start(mcQueue); - acquire(mcQueue); - int<32> insn <- mcQueue[mcQueuePos]; - release(mcQueue); - end(mcQueue); - } - --- - int<7> orig_opcode = insn{6:0}; - if (mcQueuePos == 0b00<2>){ - bool isADDS = orig_opcode == 0b1000000<7>; - bool isBRS = orig_opcode == 0b1000001<7>; - split { //breakdown original instruction into existing instructions - case: (isADDS){ - int<5> add_rs1 = insn{19:15}; - int<5> add_rd = insn{11:7}; - - int<32> inst1 = 0b0000000<7> ++ adds_rd ++ adds_rs1 ++ 0b000<3> ++ 0b0110011<7>; // add rd, rs, rd - uint<2> newMcQueuePos = mcQueuePos; - } - case: (isBRS){ - int<5> common_rd = insn{11:7}; - - int<32> inst1 = 0xfff<12> ++ common_rd ++ 0b100<3> ++ common_rd ++ 0b0010011<7>; // xori rd, rd, 0xffffffff (load 0xfffff to first 20 bits) - int<32> inst2 = insn{12} ++ insn{10:5} ++ 0b00000<5> ++ common_rd ++ 0b000<3> ++ insn{4:1} ++ insn {11} ++ 0b0010011<7> // beq rd, x0, imm - - // Save new insts to the mccode queue - acquire(mcQueue); - mcQueue[u0<2>] <- inst2; - release(mcQueue); - - // Set mcqueue length/ which inst to read next thread - uint<2> newMcQueuePos = u1<2>; // Indicates 2 instructions are saved in queue - } - default: { - uint<2> newMcQueuePos = mcQueuePos; // No change to queue pos - //do nothing, keep the original instruction - } - } - } else { - uint<2> newMcQueuePos = mcQueuePos - u1<2>; // Decrease queue pos by 1 since we poped 1 inst in IF - //do nothing, already fetched from microcode queue - } - --- - //This OPCODE is J Self and thus we're using it to signal termination - bool done = insn == 0x0000006f<32>; - int<7> opcode = insn{6:0}; - uint<5> rs1 = cast(insn{19:15}, uint<5>); - uint<5> rs2 = cast(insn{24:20}, uint<5>); - uint<5> rd = cast(insn{11:7}, uint<5>); - uint<7> funct7 = cast(insn{31:25}, uint<7>); - uint<3> funct3 = cast(insn{14:12}, uint<3>); - int<1> flipBit = insn{30:30}; - int<32> immI = cast(insn{31:20}, int<32>); - int<32> immS = cast((insn{31:25} ++ insn{11:7}), int<32>); - int<13> immBTmp = insn{31:31} ++ insn{7:7} ++ insn{30:25} ++ insn{11:8} ++ 0<1>; - int<16> immB = cast(immBTmp, int<16>); - int<21> immJTmp = insn{31:31} ++ insn{19:12} ++ insn{20:20} ++ insn{30:21} ++ 0<1>; - int<32> immJ = cast(immJTmp, int<32>); - int<12> immJRTmp = insn{31:20}; - int<16> immJR = cast(immJRTmp, int<16>); - int<32> immU = insn{31:12} ++ 0<12>; - bool isOpImm = opcode == 0b0010011<7>; - bool flip = (!isOpImm) && (flipBit == 1<1>); - bool isLui = opcode == 0b0110111<7>; - bool isAui = opcode == 0b0010111<7>; - bool isOp = opcode == 0b0110011<7>; - bool isJal = opcode == 0b1101111<7>; - bool isJalr = opcode == 0b1100111<7>; - bool isBranch = opcode == 0b1100011<7>; - bool isStore = opcode == 0b0100011<7>; - bool isLoad = opcode == 0b0000011<7>; - bool isMDiv = (funct7 == u1<7>) && isOp; - bool isDiv = isMDiv && (funct3 >= u4<3>); - bool needrs1 = !isJal; - bool needrs2 = isOp || isBranch || isStore || isJalr; - bool writerd = (rd != u0<5>) && (isOp || isOpImm || isLoad || isJal || isJalr || isLui || isAui); - start(rf); - if (needrs1) { - int<32> rf1 = rf[rs1]; - } else { - int<32> rf1 = 0<32>; - } - if (needrs2) { - int<32> rf2 = rf[rs2]; - } else { - int<32> rf2 = 0<32>; - } - if (writerd) { - reserve(rf[rd]); - } - end(rf); - --- - if (isBranch) { - int<16> npc = br(pc, immB, funct3, rf1, rf2); - } else { - if (isJal) { - //divide by 4 since it counts bytes instead of insns - int<32> npc32 = cast(pc, int<32>) + (immJ >> 2); - int<16> npc = npc32{15:0}; - } else { - if (isJalr) { - int<16> npc = (rf1{15:0} + immJR) >> 2; - } else { - int<16> npc = pc + 1<16>; - }}} - if (!done) { call cpu(npc, newMcQueuePos); } - - int<32> alu_arg2 = (isOpImm) ? immI : rf2; - - if (isDiv) { - int<32> sdividend = sign(rf1); - //For REM, ignore sign of divisor - int<32> sdivisor = (funct3 == u6<3>) ? 1<32> : sign(rf2); - bool isSignedDiv = ((funct3 == u4<3>) || (funct3 == u6<3>)); - bool invertRes = isSignedDiv && (sdividend != sdivisor); - uint<32> dividend = (isSignedDiv) ? cast(mag(rf1), uint<32>) : cast(rf1, uint<32>); - uint<32> divisor = (isSignedDiv) ? cast(mag(rf2), uint<32>) : cast(rf2, uint<32>); - bool retQuot = funct3 <= u5<3>; - uint<32> udivout <- call div(dividend, divisor, u0<32>, u0<32>, u0<5>, retQuot); - } else { - uint<32> udivout <- u0<32>; - bool invertRes = false; - } - --- - split { - case: (isLui) { - int<32> alu_res = immU; - } - case: (isAui) { - //all pc computation needs to be multiplied by 4 - int<32> pc32 = (0<16> ++ pc) << 2; - int<32> alu_res = pc32 + immU; - } - case: (isDiv) { - int<32> alu_res = (invertRes) ? -(cast(udivout, int<32>)) : cast(udivout, int<32>); - } - case: (isMDiv) { - int<32> alu_res = mul(rf1, rf2, funct3); - } - default: { - int<32> alu_res = alu(rf1, alu_arg2, funct3, flip); - } - } - split { - case: (isStore) { - //addresses also are word-sized - int<32> tmp = immS + rf1; - uint<32> ctmp = cast(tmp, uint<32>); - uint<16> memaddr = (ctmp >> 2){15:0}; - uint<2> boff = ctmp{1:0}; - } - case: (isLoad) { - //addresses also are word-sized - int<32> tmp = immI + rf1; - uint<32> ctmp = cast(tmp, uint<32>); - uint<16> memaddr = (ctmp >> 2){15:0}; - uint<2> boff = ctmp{1:0}; - } - default: { - uint<16> memaddr = u0<16>; - uint<2> boff = u0<2>; - } - } - --- - start(dmem); - split { - case: (isLoad) { - uint<16> raddr = memaddr; - int<32> wdata <- dmem[raddr]; - } - case: (isStore) { - uint<16> waddr = memaddr; - //use bottom bits of data and place in correct offset - //shift by boff*8 - uint<5> nboff = boff ++ u0<3>; - dmem[waddr, storeMask(boff, funct3)] <- (rf2 << nboff); - int<32> wdata <- 0<32>; - } - default: { - int<32> wdata <- 0<32>; - } - } - end(dmem); - --- - print("PC: %h", pc << 2); - print("INSN: %h", insn); - if (writerd) { - block(rf[rd]); - if (isLoad) { - int<32> insnout = maskLoad(wdata, funct3, boff); - } else { - if (isJal || isJalr) { - //need to multiply by 4 b/c it is arch visible. - int<16> nextpc = pc + 1<16>; - int<32> insnout = 0<16> ++ (nextpc << 2); //todo make pc 32 bits - } else { - int<32> insnout = alu_res; - }} - print("Writing %d to r%d", insnout, rd); - rf[rd] <- insnout; - release(rf[rd]); - } - if (done) { output(true); } -} - -circuit { - ti = memory(int<32>, 16); - td = memory(int<32>, 16); - rf = regfile(int<32>, 5); - r = FAQueue(rf); - div = new multi_stg_div[]; - c = new cpu[r, ti, td, div]; - call c(0<16>, 0); -} \ No newline at end of file From c5f6eea710fc24450900f848e9ef437ea9c26b6a Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Wed, 1 Dec 2021 15:46:03 -0500 Subject: [PATCH 4/5] recursive call checking --- src/main/scala/pipedsl/common/Errors.scala | 3 +++ .../pipedsl/typechecker/BaseTypeChecker.scala | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) 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/typechecker/BaseTypeChecker.scala b/src/main/scala/pipedsl/typechecker/BaseTypeChecker.scala index b1e844a7..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) => { @@ -326,6 +326,9 @@ object BaseTypeChecker extends TypeChecks[Id, Type] { } case t: TModType => mem.id.typ = Some(t) + if(mem.id == modId){ + throw RecursiveCallLockAcquisition(mem.pos) + } tenv } case CVerify(handle, args, preds, upd, cHandles) => From daeddb121191d7f6dd2091270f0f3bb453562363 Mon Sep 17 00:00:00 2001 From: Yulun Yao Date: Thu, 2 Dec 2021 14:24:57 -0500 Subject: [PATCH 5/5] deal with eint --- src/main/scala/pipedsl/Parser.scala | 10 +++++----- src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala | 2 +- .../pipedsl/codegen/bsv/BluespecGeneration.scala | 2 +- src/main/scala/pipedsl/common/DAGSyntax.scala | 12 ++++++------ src/main/scala/pipedsl/common/PrettyPrinter.scala | 8 ++++---- src/main/scala/pipedsl/common/Syntax.scala | 2 +- src/main/scala/pipedsl/common/Utilities.scala | 10 +++++----- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main/scala/pipedsl/Parser.scala b/src/main/scala/pipedsl/Parser.scala index 03bc08c5..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 ^^ diff --git a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala index 5d5335fc..6017e3c9 100644 --- a/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala +++ b/src/main/scala/pipedsl/codegen/bsv/BSVSyntax.scala @@ -164,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) diff --git a/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala b/src/main/scala/pipedsl/codegen/bsv/BluespecGeneration.scala index fa42c4a2..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) } 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/PrettyPrinter.scala b/src/main/scala/pipedsl/common/PrettyPrinter.scala index 3c3b3c7b..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) + ")" diff --git a/src/main/scala/pipedsl/common/Syntax.scala b/src/main/scala/pipedsl/common/Syntax.scala index b306e90a..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 diff --git a/src/main/scala/pipedsl/common/Utilities.scala b/src/main/scala/pipedsl/common/Utilities.scala index 8c6b14e5..585a1439 100644 --- a/src/main/scala/pipedsl/common/Utilities.scala +++ b/src/main/scala/pipedsl/common/Utilities.scala @@ -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)