commit 37f253c1f97d413213e7f532287b39bf588b01ca Author: Romain Dolbeau Date: Thu Nov 5 09:26:16 2020 +0100 First version of the plugin generator for B diff --git a/BitManipAllPlugin.scala b/BitManipAllPlugin.scala new file mode 100644 index 0000000..65689e7 --- /dev/null +++ b/BitManipAllPlugin.scala @@ -0,0 +1,549 @@ +package vexriscv.plugin +import spinal.core._ +import vexriscv.{Stageable, DecoderService, VexRiscv} +object BitManipAllPlugin { + object BitManipAllCtrlbitwiseEnum extends SpinalEnum(binarySequential) { + val CTRL_ANDN, CTRL_ORN, CTRL_XNOR = newElement() + } + object BitManipAllCtrlshiftEnum extends SpinalEnum(binarySequential) { + val CTRL_SLO, CTRL_SRO = newElement() + } + object BitManipAllCtrlrotationEnum extends SpinalEnum(binarySequential) { + val CTRL_ROL, CTRL_ROR = newElement() + } + object BitManipAllCtrlsh_addEnum extends SpinalEnum(binarySequential) { + val CTRL_SH1ADD, CTRL_SH2ADD, CTRL_SH3ADD = newElement() + } + object BitManipAllCtrlsinglebitEnum extends SpinalEnum(binarySequential) { + val CTRL_SBCLR, CTRL_SBEXT, CTRL_SBINV, CTRL_SBSET = newElement() + } + object BitManipAllCtrlgrevrocEnum extends SpinalEnum(binarySequential) { + val CTRL_GORC, CTRL_GREV = newElement() + } + object BitManipAllCtrlminmaxEnum extends SpinalEnum(binarySequential) { + val CTRL_MAX, CTRL_MAXU, CTRL_MIN, CTRL_MINU = newElement() + } + object BitManipAllCtrlshuffleEnum extends SpinalEnum(binarySequential) { + val CTRL_SHFL, CTRL_UNSHFL = newElement() + } + object BitManipAllCtrlpackEnum extends SpinalEnum(binarySequential) { + val CTRL_PACK, CTRL_PACKH, CTRL_PACKU = newElement() + } + object BitManipAllCtrlxpermEnum extends SpinalEnum(binarySequential) { + val CTRL_XPERMdotB, CTRL_XPERMdotH, CTRL_XPERMdotN = newElement() + } + object BitManipAllCtrlgrevorcEnum extends SpinalEnum(binarySequential) { + val CTRL_GORC, CTRL_GREV = newElement() + } + object BitManipAllCtrlcountzeroesEnum extends SpinalEnum(binarySequential) { + val CTRL_CLZ, CTRL_CTZ, CTRL_PCNT = newElement() + } + object BitManipAllCtrlsignextendEnum extends SpinalEnum(binarySequential) { + val CTRL_SEXTdotB, CTRL_SEXTdotH = newElement() + } + object BitManipAllCtrlEnum extends SpinalEnum(binarySequential) { + val CTRL_bitwise, CTRL_shift, CTRL_rotation, CTRL_sh_add, CTRL_singlebit, CTRL_grevroc, CTRL_minmax, CTRL_shuffle, CTRL_pack, CTRL_xperm, CTRL_grevorc, CTRL_countzeroes, CTRL_signextend = newElement() + } + object BitManipAllCtrlbitwise extends Stageable(BitManipAllCtrlbitwiseEnum()) + object BitManipAllCtrlshift extends Stageable(BitManipAllCtrlshiftEnum()) + object BitManipAllCtrlrotation extends Stageable(BitManipAllCtrlrotationEnum()) + object BitManipAllCtrlsh_add extends Stageable(BitManipAllCtrlsh_addEnum()) + object BitManipAllCtrlsinglebit extends Stageable(BitManipAllCtrlsinglebitEnum()) + object BitManipAllCtrlgrevroc extends Stageable(BitManipAllCtrlgrevrocEnum()) + object BitManipAllCtrlminmax extends Stageable(BitManipAllCtrlminmaxEnum()) + object BitManipAllCtrlshuffle extends Stageable(BitManipAllCtrlshuffleEnum()) + object BitManipAllCtrlpack extends Stageable(BitManipAllCtrlpackEnum()) + object BitManipAllCtrlxperm extends Stageable(BitManipAllCtrlxpermEnum()) + object BitManipAllCtrlgrevorc extends Stageable(BitManipAllCtrlgrevorcEnum()) + object BitManipAllCtrlcountzeroes extends Stageable(BitManipAllCtrlcountzeroesEnum()) + object BitManipAllCtrlsignextend extends Stageable(BitManipAllCtrlsignextendEnum()) + object BitManipAllCtrl extends Stageable(BitManipAllCtrlEnum()) +// Prologue + + // function implementing the semantic of 32-bits generalized reverse + def fun_grev( a:Bits, b:Bits ) : Bits = { + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? (((a & B"32'x55555555") |<< 1) | ((a & B"32'xAAAAAAAA") |>> 1)) | a + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? (((x1 & B"32'x33333333") |<< 2) | ((x1 & B"32'xCCCCCCCC") |>> 2)) | x1 + val x4 = ((b&B"32'x00000004")===B"32'x00000004") ? (((x2 & B"32'x0F0F0F0F") |<< 4) | ((x2 & B"32'xF0F0F0F0") |>> 4)) | x2 + val x8 = ((b&B"32'x00000008")===B"32'x00000008") ? (((x4 & B"32'x00FF00FF") |<< 8) | ((x4 & B"32'xFF00FF00") |>> 8)) | x4 + val x16 = ((b&B"32'x00000010")===B"32'x00000010") ? (((x8 & B"32'x0000FFFF") |<<16) | ((x8 & B"32'xFFFF0000") |>>16)) | x8 + x16 // return value + } + // function implementing the semantic of 32-bits generalized OR-combine + def fun_gorc( a:Bits, b:Bits ) : Bits = { + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? (a | ((a & B"32'x55555555") |<< 1) | ((a & B"32'xAAAAAAAA") |>> 1)) | a + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? (x1 | ((x1 & B"32'x33333333") |<< 2) | ((x1 & B"32'xCCCCCCCC") |>> 2)) | x1 + val x4 = ((b&B"32'x00000004")===B"32'x00000004") ? (x2 | ((x2 & B"32'x0F0F0F0F") |<< 4) | ((x2 & B"32'xF0F0F0F0") |>> 4)) | x2 + val x8 = ((b&B"32'x00000008")===B"32'x00000008") ? (x4 | ((x4 & B"32'x00FF00FF") |<< 8) | ((x4 & B"32'xFF00FF00") |>> 8)) | x4 + val x16 = ((b&B"32'x00000010")===B"32'x00000010") ? (x8 | ((x8 & B"32'x0000FFFF") |<<16) | ((x8 & B"32'xFFFF0000") |>>16)) | x8 + x16 // return value + } + + // helper function for the implementation of the generalized shuffles + def fun_shuffle32_stage(src:Bits, maskL:Bits, maskR:Bits, N:Int) : Bits = { + val x = src & ~(maskL | maskR) + val x2 = x | ((src |<< N) & maskL) | ((src |>> N) & maskR); + x2 // return value + } + // function implementing the semantic of 32-bits generalized shuffle + def fun_shfl32(a:Bits, b:Bits) : Bits = { + val x = a; + val x1 = ((b&B"32'x00000008")===B"32'x00000008") ? fun_shuffle32_stage(x , B"32'x00FF0000", B"32'x0000FF00", 8) | x; + val x2 = ((b&B"32'x00000004")===B"32'x00000004") ? fun_shuffle32_stage(x1, B"32'x0F000F00", B"32'x00F000F0", 4) | x1; + val x3 = ((b&B"32'x00000002")===B"32'x00000002") ? fun_shuffle32_stage(x2, B"32'x30303030", B"32'x0C0C0C0C", 2) | x2; + val x4 = ((b&B"32'x00000001")===B"32'x00000001") ? fun_shuffle32_stage(x3, B"32'x44444444", B"32'x22222222", 1) | x3; + x4 // return value + } + // function implementing the semantic of 32-bits generalized unshuffle + def fun_unshfl32(a:Bits, b:Bits) : Bits = { + val x = a; + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? fun_shuffle32_stage(x , B"32'x44444444", B"32'x22222222", 1) | x; + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? fun_shuffle32_stage(x1, B"32'x30303030", B"32'x0C0C0C0C", 2) | x1; + val x3 = ((b&B"32'x00000004")===B"32'x00000004") ? fun_shuffle32_stage(x2, B"32'x0F000F00", B"32'x00F000F0", 4) | x2; + val x4 = ((b&B"32'x00000008")===B"32'x00000008") ? fun_shuffle32_stage(x3, B"32'x00FF0000", B"32'x0000FF00", 8) | x3; + x4 // return value + } + + + // this is trying to look like DOI 10.2478/jee-2015-0054 + def fun_clz_NLCi(x:Bits): Bits = { + val r2 = (~(x(0) | x(1) | x(2) | x(3))) + val r1 = (~(x(2) | x(3))) + val r0 = (~(x(3) | (x(1) & ~x(2)))) + val r = r2 ## r1 ## r0 + r // return value + } + def fun_clz_BNE(a:Bits) : Bits = { + val a01 = ~(a(0) & a(1)) + val a23 = ~(a(2) & a(3)) + + val a45 = ~(a(4) & a(5)) + val a67 = ~(a(6) & a(7)) + + val a0123 = ~(a01 | a23) // also r(2) + val a4567 = ~(a45 | a67) + + val a56 = ~(a(5) & ~a(6)) + val a024 = (a(0) & a(2) & a(4)) // AND not NAND + val a13 = ~(a(1) & a(3)) + val a12 = ~(a(1) & ~a(2)) + + val r3 = ((a0123 & a4567)) // AND not NAND + val r2 = (a0123) + val r1 = (~(a01 | (~a23 & a45))) + val r0 = (~((~((a56) & (a024))) & (~((a13) & (a12) & (a(0)))))) + + val r = r3 ## r2 ## r1 ##r0 + + r // return value + } + def fun_clz(in:Bits) : Bits = { + val nlc7 = fun_clz_NLCi(in(31 downto 28)) + val nlc6 = fun_clz_NLCi(in(27 downto 24)) + val nlc5 = fun_clz_NLCi(in(23 downto 20)) + val nlc4 = fun_clz_NLCi(in(19 downto 16)) + val nlc3 = fun_clz_NLCi(in(15 downto 12)) + val nlc2 = fun_clz_NLCi(in(11 downto 8)) + val nlc1 = fun_clz_NLCi(in( 7 downto 4)) + val nlc0 = fun_clz_NLCi(in( 3 downto 0)) + val a = nlc0(2) ## nlc1(2) ## nlc2(2) ## nlc3(2) ## nlc4(2) ## nlc5(2) ## nlc6(2) ## nlc7(2) + val bne = fun_clz_BNE(a) + + val muxo = (bne(2 downto 0)).mux( + B"3'b000" -> nlc7(1 downto 0), + B"3'b001" -> nlc6(1 downto 0), + B"3'b010" -> nlc5(1 downto 0), + B"3'b011" -> nlc4(1 downto 0), + B"3'b100" -> nlc3(1 downto 0), + B"3'b101" -> nlc2(1 downto 0), + B"3'b110" -> nlc1(1 downto 0), + B"3'b111" -> nlc0(1 downto 0) + ) + val r = (bne(3)) ? B"6'b100000" | (B"1'b0" ## bne(2 downto 0) ## muxo(1 downto 0)) // 6 bits + + r.resize(32) // return value + } + // For trailing count, count using use leading count on bit-reversed value + def fun_ctz(in:Bits) : Bits = { + val inr = in(0) ## in(1) ## in(2) ## in(3) ## in(4) ## in(5) ## in(6) ## in(7) ## in(8) ## in(9) ## in(10) ## in(11) ## in(12) ## in(13) ## in(14) ## in(15) ## in(16) ## in(17) ## in(18) ## in(19) ## in(20) ## in(21) ## in(22) ## in(23) ## in(24) ## in(25) ## in(26) ## in(27) ## in(28) ## in(29) ## in(30) ## in(31) + fun_clz(inr) // return value + } + + // naive popcnt + def fun_popcnt(in:Bits) : Bits = { + val r = in(0).asBits.resize(6).asUInt + in(1).asBits.resize(6).asUInt + in(2).asBits.resize(6).asUInt + in(3).asBits.resize(6).asUInt + + in(4).asBits.resize(6).asUInt + in(5).asBits.resize(6).asUInt + in(6).asBits.resize(6).asUInt + in(7).asBits.resize(6).asUInt + + in(8).asBits.resize(6).asUInt + in(9).asBits.resize(6).asUInt + in(10).asBits.resize(6).asUInt + in(11).asBits.resize(6).asUInt + + in(12).asBits.resize(6).asUInt + in(13).asBits.resize(6).asUInt + in(14).asBits.resize(6).asUInt + in(15).asBits.resize(6).asUInt + + in(16).asBits.resize(6).asUInt + in(17).asBits.resize(6).asUInt + in(18).asBits.resize(6).asUInt + in(19).asBits.resize(6).asUInt + + in(20).asBits.resize(6).asUInt + in(21).asBits.resize(6).asUInt + in(22).asBits.resize(6).asUInt + in(23).asBits.resize(6).asUInt + + in(24).asBits.resize(6).asUInt + in(25).asBits.resize(6).asUInt + in(26).asBits.resize(6).asUInt + in(27).asBits.resize(6).asUInt + + in(28).asBits.resize(6).asUInt + in(29).asBits.resize(6).asUInt + in(30).asBits.resize(6).asUInt + in(31).asBits.resize(6).asUInt + + r.asBits.resize(32) // return value + } + + //XPERMs + def fun_xperm_n(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(3 downto 0).asUInt + val i1 = rs2(7 downto 4).asUInt + val i2 = rs2(11 downto 8).asUInt + val i3 = rs2(15 downto 12).asUInt + val i4 = rs2(19 downto 16).asUInt + val i5 = rs2(23 downto 20).asUInt + val i6 = rs2(27 downto 24).asUInt + val i7 = rs2(31 downto 28).asUInt + val r0 = (i0).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r1 = (i1).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r2 = (i2).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r3 = (i3).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r4 = (i4).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r5 = (i5).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r6 = (i6).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r7 = (i7).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + r7 ## r6 ## r5 ## r4 ## r3 ## r2 ## r1 ## r0 // return value + } + def fun_xperm_b(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(7 downto 0).asUInt; + val i1 = rs2(15 downto 0).asUInt; + val i2 = rs2(23 downto 0).asUInt; + val i3 = rs2(31 downto 0).asUInt; + val r0 = (i0).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r1 = (i1).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r2 = (i2).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r3 = (i3).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + r3 ## r2 ## r1 ## r0 // return value + } + def fun_xperm_h(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(15 downto 0).asUInt; + val i1 = rs2(31 downto 16).asUInt; + val r0 = (i0).mux( + 0 -> rs1(15 downto 0), + 1 -> rs1(31 downto 16), + default -> B"16'x0000" + ) + val r1 = (i1).mux( + 0 -> rs1(15 downto 0), + 1 -> rs1(31 downto 16), + default -> B"16'x0000" + ) + r1 ## r0 // return value + } + +// End prologue +} // object Plugin +class BitManipAllPlugin extends Plugin[VexRiscv] { + import BitManipAllPlugin._ + object IS_BitManipAll extends Stageable(Bool) + override def setup(pipeline: VexRiscv): Unit = { + import pipeline.config._ + val immediateActions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC2_CTRL -> Src2CtrlEnum.IMI, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> True, + BYPASSABLE_MEMORY_STAGE -> True, + RS1_USE -> True, + IS_BitManipAll -> True + ) + val binaryActions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC2_CTRL -> Src2CtrlEnum.RS, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> True, + BYPASSABLE_MEMORY_STAGE -> True, + RS1_USE -> True, + RS2_USE -> True, + IS_BitManipAll -> True + ) + val unaryActions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> True, + BYPASSABLE_MEMORY_STAGE -> True, + RS1_USE -> True, + IS_BitManipAll -> True + ) + def ANDN_KEY = M"0100000----------111-----0110011" + def ORN_KEY = M"0100000----------110-----0110011" + def XNOR_KEY = M"0100000----------100-----0110011" + def SLO_KEY = M"0010000----------001-----0110011" + def SRO_KEY = M"0010000----------101-----0110011" + def ROL_KEY = M"0110000----------001-----0110011" + def ROR_KEY = M"0110000----------101-----0110011" + def SH1ADD_KEY = M"0010000----------010-----0110011" + def SH2ADD_KEY = M"0010000----------100-----0110011" + def SH3ADD_KEY = M"0010000----------110-----0110011" + def SBCLR_KEY = M"0100100----------001-----0110011" + def SBSET_KEY = M"0010100----------001-----0110011" + def SBINV_KEY = M"0110100----------001-----0110011" + def SBEXT_KEY = M"0100100----------101-----0110011" + def GORC_KEY = M"0010100----------101-----0110011" + def GREV_KEY = M"0110100----------101-----0110011" + def MIN_KEY = M"0000101----------100-----0110011" + def MINU_KEY = M"0000101----------101-----0110011" + def MAX_KEY = M"0000101----------110-----0110011" + def MAXU_KEY = M"0000101----------111-----0110011" + def SHFL_KEY = M"0000100----------001-----0110011" + def UNSHFL_KEY = M"0000100----------101-----0110011" + def PACK_KEY = M"0000100----------100-----0110011" + def PACKU_KEY = M"0100100----------100-----0110011" + def PACKH_KEY = M"0000100----------111-----0110011" + def XPERMdotN_KEY = M"0010100----------010-----0110011" + def XPERMdotB_KEY = M"0010100----------100-----0110011" + def XPERMdotH_KEY = M"0010100----------110-----0110011" + def SLOI_KEY = M"00100------------001-----0010011" + def SROI_KEY = M"00100------------101-----0010011" + def RORI_KEY = M"01100------------101-----0010011" + def SBCLRI_KEY = M"01001------------001-----0010011" + def SBSETI_KEY = M"00101------------001-----0010011" + def SBINVI_KEY = M"01101------------001-----0010011" + def SBEXTI_KEY = M"01001------------101-----0010011" + def GORCI_KEY = M"00101------------101-----0010011" + def GREVI_KEY = M"01101------------101-----0010011" + def SHFLI_KEY = M"000010-----------001-----0010011" + def UNSHFLI_KEY = M"000010-----------101-----0010011" + def CLZ_KEY = M"011000000000-----001-----0010011" + def CTZ_KEY = M"011000000001-----001-----0010011" + def PCNT_KEY = M"011000000010-----001-----0010011" + def SEXTdotB_KEY = M"011000000100-----001-----0010011" + def SEXTdotH_KEY = M"011000000101-----001-----0010011" + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(IS_BitManipAll, False) + decoderService.add(List( + ANDN_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_bitwise, BitManipAllCtrlbitwise -> BitManipAllCtrlbitwiseEnum.CTRL_ANDN)), + ORN_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_bitwise, BitManipAllCtrlbitwise -> BitManipAllCtrlbitwiseEnum.CTRL_ORN)), + XNOR_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_bitwise, BitManipAllCtrlbitwise -> BitManipAllCtrlbitwiseEnum.CTRL_XNOR)), + SLO_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_shift, BitManipAllCtrlshift -> BitManipAllCtrlshiftEnum.CTRL_SLO)), + SRO_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_shift, BitManipAllCtrlshift -> BitManipAllCtrlshiftEnum.CTRL_SRO)), + SLOI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_shift, BitManipAllCtrlshift -> BitManipAllCtrlshiftEnum.CTRL_SLO)), + SROI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_shift, BitManipAllCtrlshift -> BitManipAllCtrlshiftEnum.CTRL_SRO)), + ROL_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_rotation, BitManipAllCtrlrotation -> BitManipAllCtrlrotationEnum.CTRL_ROL)), + ROR_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_rotation, BitManipAllCtrlrotation -> BitManipAllCtrlrotationEnum.CTRL_ROR)), + RORI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_rotation, BitManipAllCtrlrotation -> BitManipAllCtrlrotationEnum.CTRL_ROR)), + SH1ADD_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_sh_add, BitManipAllCtrlsh_add -> BitManipAllCtrlsh_addEnum.CTRL_SH1ADD)), + SH2ADD_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_sh_add, BitManipAllCtrlsh_add -> BitManipAllCtrlsh_addEnum.CTRL_SH2ADD)), + SH3ADD_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_sh_add, BitManipAllCtrlsh_add -> BitManipAllCtrlsh_addEnum.CTRL_SH3ADD)), + SBCLR_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_singlebit, BitManipAllCtrlsinglebit -> BitManipAllCtrlsinglebitEnum.CTRL_SBCLR)), + SBSET_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_singlebit, BitManipAllCtrlsinglebit -> BitManipAllCtrlsinglebitEnum.CTRL_SBSET)), + SBINV_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_singlebit, BitManipAllCtrlsinglebit -> BitManipAllCtrlsinglebitEnum.CTRL_SBINV)), + SBEXT_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_singlebit, BitManipAllCtrlsinglebit -> BitManipAllCtrlsinglebitEnum.CTRL_SBEXT)), + SBCLRI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_singlebit, BitManipAllCtrlsinglebit -> BitManipAllCtrlsinglebitEnum.CTRL_SBCLR)), + SBSETI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_singlebit, BitManipAllCtrlsinglebit -> BitManipAllCtrlsinglebitEnum.CTRL_SBSET)), + SBINVI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_singlebit, BitManipAllCtrlsinglebit -> BitManipAllCtrlsinglebitEnum.CTRL_SBINV)), + SBEXTI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_singlebit, BitManipAllCtrlsinglebit -> BitManipAllCtrlsinglebitEnum.CTRL_SBEXT)), + GORC_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_grevroc, BitManipAllCtrlgrevroc -> BitManipAllCtrlgrevrocEnum.CTRL_GORC)), + GREV_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_grevroc, BitManipAllCtrlgrevroc -> BitManipAllCtrlgrevrocEnum.CTRL_GREV)), + MIN_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_minmax, BitManipAllCtrlminmax -> BitManipAllCtrlminmaxEnum.CTRL_MIN)), + MINU_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_minmax, BitManipAllCtrlminmax -> BitManipAllCtrlminmaxEnum.CTRL_MINU)), + MAX_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_minmax, BitManipAllCtrlminmax -> BitManipAllCtrlminmaxEnum.CTRL_MAX)), + MAXU_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_minmax, BitManipAllCtrlminmax -> BitManipAllCtrlminmaxEnum.CTRL_MAXU)), + SHFL_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_shuffle, BitManipAllCtrlshuffle -> BitManipAllCtrlshuffleEnum.CTRL_SHFL)), + UNSHFL_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_shuffle, BitManipAllCtrlshuffle -> BitManipAllCtrlshuffleEnum.CTRL_UNSHFL)), + SHFLI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_shuffle, BitManipAllCtrlshuffle -> BitManipAllCtrlshuffleEnum.CTRL_SHFL)), + UNSHFLI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_shuffle, BitManipAllCtrlshuffle -> BitManipAllCtrlshuffleEnum.CTRL_UNSHFL)), + PACK_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_pack, BitManipAllCtrlpack -> BitManipAllCtrlpackEnum.CTRL_PACK)), + PACKU_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_pack, BitManipAllCtrlpack -> BitManipAllCtrlpackEnum.CTRL_PACKU)), + PACKH_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_pack, BitManipAllCtrlpack -> BitManipAllCtrlpackEnum.CTRL_PACKH)), + XPERMdotN_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_xperm, BitManipAllCtrlxperm -> BitManipAllCtrlxpermEnum.CTRL_XPERMdotN)), + XPERMdotB_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_xperm, BitManipAllCtrlxperm -> BitManipAllCtrlxpermEnum.CTRL_XPERMdotB)), + XPERMdotH_KEY -> (binaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_xperm, BitManipAllCtrlxperm -> BitManipAllCtrlxpermEnum.CTRL_XPERMdotH)), + GORCI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_grevorc, BitManipAllCtrlgrevorc -> BitManipAllCtrlgrevorcEnum.CTRL_GORC)), + GREVI_KEY -> (immediateActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_grevorc, BitManipAllCtrlgrevorc -> BitManipAllCtrlgrevorcEnum.CTRL_GREV)), + CLZ_KEY -> (unaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_countzeroes, BitManipAllCtrlcountzeroes -> BitManipAllCtrlcountzeroesEnum.CTRL_CLZ)), + CTZ_KEY -> (unaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_countzeroes, BitManipAllCtrlcountzeroes -> BitManipAllCtrlcountzeroesEnum.CTRL_CTZ)), + PCNT_KEY -> (unaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_countzeroes, BitManipAllCtrlcountzeroes -> BitManipAllCtrlcountzeroesEnum.CTRL_PCNT)), + SEXTdotB_KEY -> (unaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_signextend, BitManipAllCtrlsignextend -> BitManipAllCtrlsignextendEnum.CTRL_SEXTdotB)), + SEXTdotH_KEY -> (unaryActions ++ List(BitManipAllCtrl -> BitManipAllCtrlEnum.CTRL_signextend, BitManipAllCtrlsignextend -> BitManipAllCtrlsignextendEnum.CTRL_SEXTdotH)) + )) + } // override def setup + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + execute plug new Area{ + import execute._ + val val_bitwise = input(BitManipAllCtrlbitwise).mux( + BitManipAllCtrlbitwiseEnum.CTRL_ANDN -> (input(SRC1) & ~input(SRC2)), + BitManipAllCtrlbitwiseEnum.CTRL_ORN -> (input(SRC1) | ~input(SRC2)), + BitManipAllCtrlbitwiseEnum.CTRL_XNOR -> (input(SRC1) ^ ~input(SRC2)) + ) // mux bitwise + val val_shift = input(BitManipAllCtrlshift).mux( + BitManipAllCtrlshiftEnum.CTRL_SLO -> ~((~input(SRC1)) |<< (input(SRC2)&31).asUInt), + BitManipAllCtrlshiftEnum.CTRL_SRO -> ~((~input(SRC1)) |>> (input(SRC2)&31).asUInt) + ) // mux shift + val val_rotation = input(BitManipAllCtrlrotation).mux( + BitManipAllCtrlrotationEnum.CTRL_ROL -> input(SRC1).rotateLeft((input(SRC2)&31)(4 downto 0).asUInt), + BitManipAllCtrlrotationEnum.CTRL_ROR -> input(SRC1).rotateRight((input(SRC2)&31)(4 downto 0).asUInt) + ) // mux rotation + val val_sh_add = input(BitManipAllCtrlsh_add).mux( + BitManipAllCtrlsh_addEnum.CTRL_SH1ADD -> ((input(SRC1) |<< 1).asUInt + input(SRC2).asUInt), + BitManipAllCtrlsh_addEnum.CTRL_SH2ADD -> ((input(SRC1) |<< 2).asUInt + input(SRC2).asUInt), + BitManipAllCtrlsh_addEnum.CTRL_SH3ADD -> ((input(SRC1) |<< 3).asUInt + input(SRC2).asUInt) + ) // mux sh_add + val val_singlebit = input(BitManipAllCtrlsinglebit).mux( + BitManipAllCtrlsinglebitEnum.CTRL_SBCLR -> (input(SRC1) & ~(B"32'x00000001"|<<((input(SRC2)&31).asUInt))), + BitManipAllCtrlsinglebitEnum.CTRL_SBEXT -> ((input(SRC1) |>> ((input(SRC2)&31).asUInt)) & B"32'x00000001"), + BitManipAllCtrlsinglebitEnum.CTRL_SBINV -> (input(SRC1) ^ (B"32'x00000001"|<<((input(SRC2)&31).asUInt))), + BitManipAllCtrlsinglebitEnum.CTRL_SBSET -> (input(SRC1) | (B"32'x00000001"|<<((input(SRC2)&31).asUInt))) + ) // mux singlebit + val val_grevroc = input(BitManipAllCtrlgrevroc).mux( + BitManipAllCtrlgrevrocEnum.CTRL_GORC -> fun_gorc(input(SRC1), input(SRC2)), + BitManipAllCtrlgrevrocEnum.CTRL_GREV -> fun_grev(input(SRC1), input(SRC2)) + ) // mux grevroc + val val_minmax = input(BitManipAllCtrlminmax).mux( + BitManipAllCtrlminmaxEnum.CTRL_MAX -> ((input(SRC1).asSInt > input(SRC2).asSInt) ? input(SRC1) | input(SRC2)), + BitManipAllCtrlminmaxEnum.CTRL_MAXU -> ((input(SRC1).asUInt > input(SRC2).asUInt) ? input(SRC1) | input(SRC2)), + BitManipAllCtrlminmaxEnum.CTRL_MIN -> ((input(SRC1).asSInt < input(SRC2).asSInt) ? input(SRC1) | input(SRC2)), + BitManipAllCtrlminmaxEnum.CTRL_MINU -> ((input(SRC1).asUInt < input(SRC2).asUInt) ? input(SRC1) | input(SRC2)) + ) // mux minmax + val val_shuffle = input(BitManipAllCtrlshuffle).mux( + BitManipAllCtrlshuffleEnum.CTRL_SHFL -> fun_shfl32(input(SRC1), input(SRC2)), + BitManipAllCtrlshuffleEnum.CTRL_UNSHFL -> fun_unshfl32(input(SRC1), input(SRC2)) + ) // mux shuffle + val val_pack = input(BitManipAllCtrlpack).mux( + BitManipAllCtrlpackEnum.CTRL_PACK -> (input(SRC2)(15 downto 0) ## input(SRC1)(15 downto 0)), + BitManipAllCtrlpackEnum.CTRL_PACKH -> B"16'x0000" ## (input(SRC2)(7 downto 0) ## input(SRC1)(7 downto 0)), + BitManipAllCtrlpackEnum.CTRL_PACKU -> (input(SRC2)(31 downto 16) ## input(SRC1)(31 downto 16)) + ) // mux pack + val val_xperm = input(BitManipAllCtrlxperm).mux( + BitManipAllCtrlxpermEnum.CTRL_XPERMdotB -> fun_xperm_b(input(SRC1), input(SRC2)), + BitManipAllCtrlxpermEnum.CTRL_XPERMdotH -> fun_xperm_h(input(SRC1), input(SRC2)), + BitManipAllCtrlxpermEnum.CTRL_XPERMdotN -> fun_xperm_n(input(SRC1), input(SRC2)) + ) // mux xperm + val val_grevorc = input(BitManipAllCtrlgrevorc).mux( + BitManipAllCtrlgrevorcEnum.CTRL_GORC -> fun_gorc(input(SRC1), input(SRC2)), + BitManipAllCtrlgrevorcEnum.CTRL_GREV -> fun_grev(input(SRC1), input(SRC2)) + ) // mux grevorc + val val_countzeroes = input(BitManipAllCtrlcountzeroes).mux( + BitManipAllCtrlcountzeroesEnum.CTRL_CLZ -> fun_clz(input(SRC1)), + BitManipAllCtrlcountzeroesEnum.CTRL_CTZ -> fun_ctz(input(SRC1)), + BitManipAllCtrlcountzeroesEnum.CTRL_PCNT -> fun_popcnt(input(SRC1)) + ) // mux countzeroes + val val_signextend = input(BitManipAllCtrlsignextend).mux( + BitManipAllCtrlsignextendEnum.CTRL_SEXTdotB -> (Bits(24 bits).setAllTo(input(SRC1)(7)) ## input(SRC1)(7 downto 0)), + BitManipAllCtrlsignextendEnum.CTRL_SEXTdotH -> (Bits(16 bits).setAllTo(input(SRC1)(15)) ## input(SRC1)(15 downto 0)) + ) // mux signextend + when (input(IS_BitManipAll)) { + execute.output(REGFILE_WRITE_DATA) := input(BitManipAllCtrl).mux( + BitManipAllCtrlEnum.CTRL_bitwise -> val_bitwise.asBits, + BitManipAllCtrlEnum.CTRL_shift -> val_shift.asBits, + BitManipAllCtrlEnum.CTRL_rotation -> val_rotation.asBits, + BitManipAllCtrlEnum.CTRL_sh_add -> val_sh_add.asBits, + BitManipAllCtrlEnum.CTRL_singlebit -> val_singlebit.asBits, + BitManipAllCtrlEnum.CTRL_grevroc -> val_grevroc.asBits, + BitManipAllCtrlEnum.CTRL_minmax -> val_minmax.asBits, + BitManipAllCtrlEnum.CTRL_shuffle -> val_shuffle.asBits, + BitManipAllCtrlEnum.CTRL_pack -> val_pack.asBits, + BitManipAllCtrlEnum.CTRL_xperm -> val_xperm.asBits, + BitManipAllCtrlEnum.CTRL_grevorc -> val_grevorc.asBits, + BitManipAllCtrlEnum.CTRL_countzeroes -> val_countzeroes.asBits, + BitManipAllCtrlEnum.CTRL_signextend -> val_signextend.asBits + ) // primary mux + } // when input is + } // execute plug newArea + } // override def build +} // class Plugin diff --git a/BitManipZbpPlugin.scala b/BitManipZbpPlugin.scala new file mode 100644 index 0000000..ef22370 --- /dev/null +++ b/BitManipZbpPlugin.scala @@ -0,0 +1,441 @@ +package vexriscv.plugin +import spinal.core._ +import vexriscv.{Stageable, DecoderService, VexRiscv} +object BitManipZbpPlugin { + object BitManipZbpCtrlbitwiseEnum extends SpinalEnum(binarySequential) { + val CTRL_ANDN, CTRL_ORN, CTRL_XNOR = newElement() + } + object BitManipZbpCtrlrotationEnum extends SpinalEnum(binarySequential) { + val CTRL_ROL, CTRL_ROR = newElement() + } + object BitManipZbpCtrlgrevrocEnum extends SpinalEnum(binarySequential) { + val CTRL_GORC, CTRL_GREV = newElement() + } + object BitManipZbpCtrlshuffleEnum extends SpinalEnum(binarySequential) { + val CTRL_SHFL, CTRL_UNSHFL = newElement() + } + object BitManipZbpCtrlpackEnum extends SpinalEnum(binarySequential) { + val CTRL_PACK, CTRL_PACKH, CTRL_PACKU = newElement() + } + object BitManipZbpCtrlxpermEnum extends SpinalEnum(binarySequential) { + val CTRL_XPERMdotB, CTRL_XPERMdotH, CTRL_XPERMdotN = newElement() + } + object BitManipZbpCtrlgrevorcEnum extends SpinalEnum(binarySequential) { + val CTRL_GORC, CTRL_GREV = newElement() + } + object BitManipZbpCtrlEnum extends SpinalEnum(binarySequential) { + val CTRL_bitwise, CTRL_rotation, CTRL_grevroc, CTRL_shuffle, CTRL_pack, CTRL_xperm, CTRL_grevorc = newElement() + } + object BitManipZbpCtrlbitwise extends Stageable(BitManipZbpCtrlbitwiseEnum()) + object BitManipZbpCtrlrotation extends Stageable(BitManipZbpCtrlrotationEnum()) + object BitManipZbpCtrlgrevroc extends Stageable(BitManipZbpCtrlgrevrocEnum()) + object BitManipZbpCtrlshuffle extends Stageable(BitManipZbpCtrlshuffleEnum()) + object BitManipZbpCtrlpack extends Stageable(BitManipZbpCtrlpackEnum()) + object BitManipZbpCtrlxperm extends Stageable(BitManipZbpCtrlxpermEnum()) + object BitManipZbpCtrlgrevorc extends Stageable(BitManipZbpCtrlgrevorcEnum()) + object BitManipZbpCtrl extends Stageable(BitManipZbpCtrlEnum()) +// Prologue + + // function implementing the semantic of 32-bits generalized reverse + def fun_grev( a:Bits, b:Bits ) : Bits = { + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? (((a & B"32'x55555555") |<< 1) | ((a & B"32'xAAAAAAAA") |>> 1)) | a + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? (((x1 & B"32'x33333333") |<< 2) | ((x1 & B"32'xCCCCCCCC") |>> 2)) | x1 + val x4 = ((b&B"32'x00000004")===B"32'x00000004") ? (((x2 & B"32'x0F0F0F0F") |<< 4) | ((x2 & B"32'xF0F0F0F0") |>> 4)) | x2 + val x8 = ((b&B"32'x00000008")===B"32'x00000008") ? (((x4 & B"32'x00FF00FF") |<< 8) | ((x4 & B"32'xFF00FF00") |>> 8)) | x4 + val x16 = ((b&B"32'x00000010")===B"32'x00000010") ? (((x8 & B"32'x0000FFFF") |<<16) | ((x8 & B"32'xFFFF0000") |>>16)) | x8 + x16 // return value + } + // function implementing the semantic of 32-bits generalized OR-combine + def fun_gorc( a:Bits, b:Bits ) : Bits = { + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? (a | ((a & B"32'x55555555") |<< 1) | ((a & B"32'xAAAAAAAA") |>> 1)) | a + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? (x1 | ((x1 & B"32'x33333333") |<< 2) | ((x1 & B"32'xCCCCCCCC") |>> 2)) | x1 + val x4 = ((b&B"32'x00000004")===B"32'x00000004") ? (x2 | ((x2 & B"32'x0F0F0F0F") |<< 4) | ((x2 & B"32'xF0F0F0F0") |>> 4)) | x2 + val x8 = ((b&B"32'x00000008")===B"32'x00000008") ? (x4 | ((x4 & B"32'x00FF00FF") |<< 8) | ((x4 & B"32'xFF00FF00") |>> 8)) | x4 + val x16 = ((b&B"32'x00000010")===B"32'x00000010") ? (x8 | ((x8 & B"32'x0000FFFF") |<<16) | ((x8 & B"32'xFFFF0000") |>>16)) | x8 + x16 // return value + } + + // helper function for the implementation of the generalized shuffles + def fun_shuffle32_stage(src:Bits, maskL:Bits, maskR:Bits, N:Int) : Bits = { + val x = src & ~(maskL | maskR) + val x2 = x | ((src |<< N) & maskL) | ((src |>> N) & maskR); + x2 // return value + } + // function implementing the semantic of 32-bits generalized shuffle + def fun_shfl32(a:Bits, b:Bits) : Bits = { + val x = a; + val x1 = ((b&B"32'x00000008")===B"32'x00000008") ? fun_shuffle32_stage(x , B"32'x00FF0000", B"32'x0000FF00", 8) | x; + val x2 = ((b&B"32'x00000004")===B"32'x00000004") ? fun_shuffle32_stage(x1, B"32'x0F000F00", B"32'x00F000F0", 4) | x1; + val x3 = ((b&B"32'x00000002")===B"32'x00000002") ? fun_shuffle32_stage(x2, B"32'x30303030", B"32'x0C0C0C0C", 2) | x2; + val x4 = ((b&B"32'x00000001")===B"32'x00000001") ? fun_shuffle32_stage(x3, B"32'x44444444", B"32'x22222222", 1) | x3; + x4 // return value + } + // function implementing the semantic of 32-bits generalized unshuffle + def fun_unshfl32(a:Bits, b:Bits) : Bits = { + val x = a; + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? fun_shuffle32_stage(x , B"32'x44444444", B"32'x22222222", 1) | x; + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? fun_shuffle32_stage(x1, B"32'x30303030", B"32'x0C0C0C0C", 2) | x1; + val x3 = ((b&B"32'x00000004")===B"32'x00000004") ? fun_shuffle32_stage(x2, B"32'x0F000F00", B"32'x00F000F0", 4) | x2; + val x4 = ((b&B"32'x00000008")===B"32'x00000008") ? fun_shuffle32_stage(x3, B"32'x00FF0000", B"32'x0000FF00", 8) | x3; + x4 // return value + } + + + // this is trying to look like DOI 10.2478/jee-2015-0054 + def fun_clz_NLCi(x:Bits): Bits = { + val r2 = (~(x(0) | x(1) | x(2) | x(3))) + val r1 = (~(x(2) | x(3))) + val r0 = (~(x(3) | (x(1) & ~x(2)))) + val r = r2 ## r1 ## r0 + r // return value + } + def fun_clz_BNE(a:Bits) : Bits = { + val a01 = ~(a(0) & a(1)) + val a23 = ~(a(2) & a(3)) + + val a45 = ~(a(4) & a(5)) + val a67 = ~(a(6) & a(7)) + + val a0123 = ~(a01 | a23) // also r(2) + val a4567 = ~(a45 | a67) + + val a56 = ~(a(5) & ~a(6)) + val a024 = (a(0) & a(2) & a(4)) // AND not NAND + val a13 = ~(a(1) & a(3)) + val a12 = ~(a(1) & ~a(2)) + + val r3 = ((a0123 & a4567)) // AND not NAND + val r2 = (a0123) + val r1 = (~(a01 | (~a23 & a45))) + val r0 = (~((~((a56) & (a024))) & (~((a13) & (a12) & (a(0)))))) + + val r = r3 ## r2 ## r1 ##r0 + + r // return value + } + def fun_clz(in:Bits) : Bits = { + val nlc7 = fun_clz_NLCi(in(31 downto 28)) + val nlc6 = fun_clz_NLCi(in(27 downto 24)) + val nlc5 = fun_clz_NLCi(in(23 downto 20)) + val nlc4 = fun_clz_NLCi(in(19 downto 16)) + val nlc3 = fun_clz_NLCi(in(15 downto 12)) + val nlc2 = fun_clz_NLCi(in(11 downto 8)) + val nlc1 = fun_clz_NLCi(in( 7 downto 4)) + val nlc0 = fun_clz_NLCi(in( 3 downto 0)) + val a = nlc0(2) ## nlc1(2) ## nlc2(2) ## nlc3(2) ## nlc4(2) ## nlc5(2) ## nlc6(2) ## nlc7(2) + val bne = fun_clz_BNE(a) + + val muxo = (bne(2 downto 0)).mux( + B"3'b000" -> nlc7(1 downto 0), + B"3'b001" -> nlc6(1 downto 0), + B"3'b010" -> nlc5(1 downto 0), + B"3'b011" -> nlc4(1 downto 0), + B"3'b100" -> nlc3(1 downto 0), + B"3'b101" -> nlc2(1 downto 0), + B"3'b110" -> nlc1(1 downto 0), + B"3'b111" -> nlc0(1 downto 0) + ) + val r = (bne(3)) ? B"6'b100000" | (B"1'b0" ## bne(2 downto 0) ## muxo(1 downto 0)) // 6 bits + + r.resize(32) // return value + } + // For trailing count, count using use leading count on bit-reversed value + def fun_ctz(in:Bits) : Bits = { + val inr = in(0) ## in(1) ## in(2) ## in(3) ## in(4) ## in(5) ## in(6) ## in(7) ## in(8) ## in(9) ## in(10) ## in(11) ## in(12) ## in(13) ## in(14) ## in(15) ## in(16) ## in(17) ## in(18) ## in(19) ## in(20) ## in(21) ## in(22) ## in(23) ## in(24) ## in(25) ## in(26) ## in(27) ## in(28) ## in(29) ## in(30) ## in(31) + fun_clz(inr) // return value + } + + // naive popcnt + def fun_popcnt(in:Bits) : Bits = { + val r = in(0).asBits.resize(6).asUInt + in(1).asBits.resize(6).asUInt + in(2).asBits.resize(6).asUInt + in(3).asBits.resize(6).asUInt + + in(4).asBits.resize(6).asUInt + in(5).asBits.resize(6).asUInt + in(6).asBits.resize(6).asUInt + in(7).asBits.resize(6).asUInt + + in(8).asBits.resize(6).asUInt + in(9).asBits.resize(6).asUInt + in(10).asBits.resize(6).asUInt + in(11).asBits.resize(6).asUInt + + in(12).asBits.resize(6).asUInt + in(13).asBits.resize(6).asUInt + in(14).asBits.resize(6).asUInt + in(15).asBits.resize(6).asUInt + + in(16).asBits.resize(6).asUInt + in(17).asBits.resize(6).asUInt + in(18).asBits.resize(6).asUInt + in(19).asBits.resize(6).asUInt + + in(20).asBits.resize(6).asUInt + in(21).asBits.resize(6).asUInt + in(22).asBits.resize(6).asUInt + in(23).asBits.resize(6).asUInt + + in(24).asBits.resize(6).asUInt + in(25).asBits.resize(6).asUInt + in(26).asBits.resize(6).asUInt + in(27).asBits.resize(6).asUInt + + in(28).asBits.resize(6).asUInt + in(29).asBits.resize(6).asUInt + in(30).asBits.resize(6).asUInt + in(31).asBits.resize(6).asUInt + + r.asBits.resize(32) // return value + } + + //XPERMs + def fun_xperm_n(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(3 downto 0).asUInt + val i1 = rs2(7 downto 4).asUInt + val i2 = rs2(11 downto 8).asUInt + val i3 = rs2(15 downto 12).asUInt + val i4 = rs2(19 downto 16).asUInt + val i5 = rs2(23 downto 20).asUInt + val i6 = rs2(27 downto 24).asUInt + val i7 = rs2(31 downto 28).asUInt + val r0 = (i0).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r1 = (i1).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r2 = (i2).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r3 = (i3).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r4 = (i4).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r5 = (i5).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r6 = (i6).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r7 = (i7).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + r7 ## r6 ## r5 ## r4 ## r3 ## r2 ## r1 ## r0 // return value + } + def fun_xperm_b(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(7 downto 0).asUInt; + val i1 = rs2(15 downto 0).asUInt; + val i2 = rs2(23 downto 0).asUInt; + val i3 = rs2(31 downto 0).asUInt; + val r0 = (i0).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r1 = (i1).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r2 = (i2).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r3 = (i3).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + r3 ## r2 ## r1 ## r0 // return value + } + def fun_xperm_h(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(15 downto 0).asUInt; + val i1 = rs2(31 downto 16).asUInt; + val r0 = (i0).mux( + 0 -> rs1(15 downto 0), + 1 -> rs1(31 downto 16), + default -> B"16'x0000" + ) + val r1 = (i1).mux( + 0 -> rs1(15 downto 0), + 1 -> rs1(31 downto 16), + default -> B"16'x0000" + ) + r1 ## r0 // return value + } + +// End prologue +} // object Plugin +class BitManipZbpPlugin extends Plugin[VexRiscv] { + import BitManipZbpPlugin._ + object IS_BitManipZbp extends Stageable(Bool) + override def setup(pipeline: VexRiscv): Unit = { + import pipeline.config._ + val immediateActions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC2_CTRL -> Src2CtrlEnum.IMI, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> True, + BYPASSABLE_MEMORY_STAGE -> True, + RS1_USE -> True, + IS_BitManipZbp -> True + ) + val binaryActions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC2_CTRL -> Src2CtrlEnum.RS, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> True, + BYPASSABLE_MEMORY_STAGE -> True, + RS1_USE -> True, + RS2_USE -> True, + IS_BitManipZbp -> True + ) + val unaryActions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> True, + BYPASSABLE_MEMORY_STAGE -> True, + RS1_USE -> True, + IS_BitManipZbp -> True + ) + def ANDN_KEY = M"0100000----------111-----0110011" + def ORN_KEY = M"0100000----------110-----0110011" + def XNOR_KEY = M"0100000----------100-----0110011" + def ROL_KEY = M"0110000----------001-----0110011" + def ROR_KEY = M"0110000----------101-----0110011" + def GORC_KEY = M"0010100----------101-----0110011" + def GREV_KEY = M"0110100----------101-----0110011" + def SHFL_KEY = M"0000100----------001-----0110011" + def UNSHFL_KEY = M"0000100----------101-----0110011" + def PACK_KEY = M"0000100----------100-----0110011" + def PACKU_KEY = M"0100100----------100-----0110011" + def PACKH_KEY = M"0000100----------111-----0110011" + def XPERMdotN_KEY = M"0010100----------010-----0110011" + def XPERMdotB_KEY = M"0010100----------100-----0110011" + def XPERMdotH_KEY = M"0010100----------110-----0110011" + def RORI_KEY = M"01100------------101-----0010011" + def GORCI_KEY = M"00101------------101-----0010011" + def GREVI_KEY = M"01101------------101-----0010011" + def SHFLI_KEY = M"000010-----------001-----0010011" + def UNSHFLI_KEY = M"000010-----------101-----0010011" + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(IS_BitManipZbp, False) + decoderService.add(List( + ANDN_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_bitwise, BitManipZbpCtrlbitwise -> BitManipZbpCtrlbitwiseEnum.CTRL_ANDN)), + ORN_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_bitwise, BitManipZbpCtrlbitwise -> BitManipZbpCtrlbitwiseEnum.CTRL_ORN)), + XNOR_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_bitwise, BitManipZbpCtrlbitwise -> BitManipZbpCtrlbitwiseEnum.CTRL_XNOR)), + ROL_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_rotation, BitManipZbpCtrlrotation -> BitManipZbpCtrlrotationEnum.CTRL_ROL)), + ROR_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_rotation, BitManipZbpCtrlrotation -> BitManipZbpCtrlrotationEnum.CTRL_ROR)), + RORI_KEY -> (immediateActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_rotation, BitManipZbpCtrlrotation -> BitManipZbpCtrlrotationEnum.CTRL_ROR)), + GORC_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_grevroc, BitManipZbpCtrlgrevroc -> BitManipZbpCtrlgrevrocEnum.CTRL_GORC)), + GREV_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_grevroc, BitManipZbpCtrlgrevroc -> BitManipZbpCtrlgrevrocEnum.CTRL_GREV)), + SHFL_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_shuffle, BitManipZbpCtrlshuffle -> BitManipZbpCtrlshuffleEnum.CTRL_SHFL)), + UNSHFL_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_shuffle, BitManipZbpCtrlshuffle -> BitManipZbpCtrlshuffleEnum.CTRL_UNSHFL)), + SHFLI_KEY -> (immediateActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_shuffle, BitManipZbpCtrlshuffle -> BitManipZbpCtrlshuffleEnum.CTRL_SHFL)), + UNSHFLI_KEY -> (immediateActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_shuffle, BitManipZbpCtrlshuffle -> BitManipZbpCtrlshuffleEnum.CTRL_UNSHFL)), + PACK_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_pack, BitManipZbpCtrlpack -> BitManipZbpCtrlpackEnum.CTRL_PACK)), + PACKU_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_pack, BitManipZbpCtrlpack -> BitManipZbpCtrlpackEnum.CTRL_PACKU)), + PACKH_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_pack, BitManipZbpCtrlpack -> BitManipZbpCtrlpackEnum.CTRL_PACKH)), + XPERMdotN_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_xperm, BitManipZbpCtrlxperm -> BitManipZbpCtrlxpermEnum.CTRL_XPERMdotN)), + XPERMdotB_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_xperm, BitManipZbpCtrlxperm -> BitManipZbpCtrlxpermEnum.CTRL_XPERMdotB)), + XPERMdotH_KEY -> (binaryActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_xperm, BitManipZbpCtrlxperm -> BitManipZbpCtrlxpermEnum.CTRL_XPERMdotH)), + GORCI_KEY -> (immediateActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_grevorc, BitManipZbpCtrlgrevorc -> BitManipZbpCtrlgrevorcEnum.CTRL_GORC)), + GREVI_KEY -> (immediateActions ++ List(BitManipZbpCtrl -> BitManipZbpCtrlEnum.CTRL_grevorc, BitManipZbpCtrlgrevorc -> BitManipZbpCtrlgrevorcEnum.CTRL_GREV)) + )) + } // override def setup + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + execute plug new Area{ + import execute._ + val val_bitwise = input(BitManipZbpCtrlbitwise).mux( + BitManipZbpCtrlbitwiseEnum.CTRL_ANDN -> (input(SRC1) & ~input(SRC2)), + BitManipZbpCtrlbitwiseEnum.CTRL_ORN -> (input(SRC1) | ~input(SRC2)), + BitManipZbpCtrlbitwiseEnum.CTRL_XNOR -> (input(SRC1) ^ ~input(SRC2)) + ) // mux bitwise + val val_rotation = input(BitManipZbpCtrlrotation).mux( + BitManipZbpCtrlrotationEnum.CTRL_ROL -> input(SRC1).rotateLeft((input(SRC2)&31)(4 downto 0).asUInt), + BitManipZbpCtrlrotationEnum.CTRL_ROR -> input(SRC1).rotateRight((input(SRC2)&31)(4 downto 0).asUInt) + ) // mux rotation + val val_grevroc = input(BitManipZbpCtrlgrevroc).mux( + BitManipZbpCtrlgrevrocEnum.CTRL_GORC -> fun_gorc(input(SRC1), input(SRC2)), + BitManipZbpCtrlgrevrocEnum.CTRL_GREV -> fun_grev(input(SRC1), input(SRC2)) + ) // mux grevroc + val val_shuffle = input(BitManipZbpCtrlshuffle).mux( + BitManipZbpCtrlshuffleEnum.CTRL_SHFL -> fun_shfl32(input(SRC1), input(SRC2)), + BitManipZbpCtrlshuffleEnum.CTRL_UNSHFL -> fun_unshfl32(input(SRC1), input(SRC2)) + ) // mux shuffle + val val_pack = input(BitManipZbpCtrlpack).mux( + BitManipZbpCtrlpackEnum.CTRL_PACK -> (input(SRC2)(15 downto 0) ## input(SRC1)(15 downto 0)), + BitManipZbpCtrlpackEnum.CTRL_PACKH -> B"16'x0000" ## (input(SRC2)(7 downto 0) ## input(SRC1)(7 downto 0)), + BitManipZbpCtrlpackEnum.CTRL_PACKU -> (input(SRC2)(31 downto 16) ## input(SRC1)(31 downto 16)) + ) // mux pack + val val_xperm = input(BitManipZbpCtrlxperm).mux( + BitManipZbpCtrlxpermEnum.CTRL_XPERMdotB -> fun_xperm_b(input(SRC1), input(SRC2)), + BitManipZbpCtrlxpermEnum.CTRL_XPERMdotH -> fun_xperm_h(input(SRC1), input(SRC2)), + BitManipZbpCtrlxpermEnum.CTRL_XPERMdotN -> fun_xperm_n(input(SRC1), input(SRC2)) + ) // mux xperm + val val_grevorc = input(BitManipZbpCtrlgrevorc).mux( + BitManipZbpCtrlgrevorcEnum.CTRL_GORC -> fun_gorc(input(SRC1), input(SRC2)), + BitManipZbpCtrlgrevorcEnum.CTRL_GREV -> fun_grev(input(SRC1), input(SRC2)) + ) // mux grevorc + when (input(IS_BitManipZbp)) { + execute.output(REGFILE_WRITE_DATA) := input(BitManipZbpCtrl).mux( + BitManipZbpCtrlEnum.CTRL_bitwise -> val_bitwise.asBits, + BitManipZbpCtrlEnum.CTRL_rotation -> val_rotation.asBits, + BitManipZbpCtrlEnum.CTRL_grevroc -> val_grevroc.asBits, + BitManipZbpCtrlEnum.CTRL_shuffle -> val_shuffle.asBits, + BitManipZbpCtrlEnum.CTRL_pack -> val_pack.asBits, + BitManipZbpCtrlEnum.CTRL_xperm -> val_xperm.asBits, + BitManipZbpCtrlEnum.CTRL_grevorc -> val_grevorc.asBits + ) // primary mux + } // when input is + } // execute plug newArea + } // override def build +} // class Plugin diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..98c1232 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Romain Dolbeau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e7224d9 --- /dev/null +++ b/Makefile @@ -0,0 +1,53 @@ +SRCXX=gen_plugin.cpp unparse.cpp +OBJXX=$(SRCXX:.cpp=.o) +DEPXX=$(SRCXX:.cpp=.d) +OBJ=inst_par.o inst_lex.o + + +LEX=flex +YACC=bison -d #--report-file=bison.log --report=all + + +CXX=g++ +CXXFLAGS=-O2 + +all: gen_plugin + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $< -c -o $@ + +gen_plugin: $(OBJXX) $(OBJ) + $(CXX) $(CXXFLAGS) $^ -o $@ + +inst_par.h: inst_par.o + +inst_par.o: inst_par.y + $(YACC) -o $(<:%.y=%.c) $< + $(CC) $(CFLAGS) $(<:%.y=%.c) -c -o $@ + +inst_lex.o: inst_lex.l inst_par.h + $(LEX) -o $(<:%.l=%.c) $< + $(CC) $(CFLAGS) $(<:%.l=%.c) -c -o $@ + +%.d: %.cpp + $(CXX) -MM $< -o $@ + +clean: + rm -f $(OBJXX) $(OBJ) gen_plugin + +veryclean: + rm -f $(OBJXX) $(OBJ) gen_plugin *~ inst_lex.c inst_par.c *.d + +ultraclean: + rm -f $(OBJXX) $(OBJ) gen_plugin *~ inst_lex.c inst_par.c *.d *.scala + +BitManipZbpPlugin.scala: gen_plugin data_bitmanip.txt + ./gen_plugin BitManipZbp data_bitmanip.txt Zbp >| $@ + +BitManipAllPlugin.scala: gen_plugin data_bitmanip.txt + ./gen_plugin BitManipAll data_bitmanip.txt '*' >| $@ + +scala: BitManipZbpPlugin.scala BitManipAllPlugin.scala + + +include $(DEPXX) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ca0409 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# B plugin generator for VexRiscv + +## This repostory + +This is a quick'n'dirty plugin generator to add a subset of the [https://github.com/riscv/riscv-bitmanip](B) extension to the [https://github.com/SpinalHDL/VexRiscv](VexRiscv) core. + +The generated plugin is for RV32 only. It doesn't yet support all instructions; missing instructions are: + +* all instructions ending in 'W', as they are RV64-only +* BMAT*, as they are RV64-only +* CLMUL* +* BDEP/BEXT/BFP +* CRC32* +* Three-operands instrutioncs (CMIX, CMOV, FS[RL]*) + +There is no support for 'partial' instruction - implementing only a subset of the functionality of one instruction. So `grev` is supported, but `rev8` alone isn't. Subextension are defined without 'partial' instructions - so Zbb doesn't have `rev8` or `orc.B`. + +This has received limited testing in a [https://github.com/litex-hub/linux-on-litex-vexriscv](Linux-on-Litex-VexRiscv) SoC. YMMV. + +Also, the implementations of the instructions in SpinalHDL are written for tuncitonality, and not tuned or optimized in any way for performance/area/... (file usage.txt has some numbers). + +## How to use + +There shouldn't be any dependency beyond gcc, g++, flex and bison. Instructions are defined in `data_bitmanip.txt`, look at the header of that file for the format - it should be fairly easy to add custom instructions if needed (as long as they are register-register, register-immediate, or unary and execute in one cycle). + +The tool need an extension name, the data file and the list of instructions and/or sub-extension to support in the plugin: + +``` +./gen_plugin BitManipZbpZba data_bitmanip.txt Zba Zbb GORC GREV > BitManipZbbZba.scala +``` + +Will generate a plugin supporting Zbb (using the full version of `grev` and `gorc`) and Zba. You can use a star to say 'all supported instructions': + +``` +./gen_plugin BitManipAll data_bitmanip.txt '*' > BitManipAllPlugin.scala +``` diff --git a/data_bitmanip.txt b/data_bitmanip.txt new file mode 100644 index 0000000..af8a8ec --- /dev/null +++ b/data_bitmanip.txt @@ -0,0 +1,438 @@ +// First field (first character in the line): I (instruction), S (semantic), P (prologue, only one) +// Starting with // is a comment +// Fields are separated by any number of spaces and tabs +// For S: Followed by a single field in double-quotes (space allowed but not carriage return), the instruction semantic in SpinalHDL +// For P : Followed by a single field in triple double-quotes (anything allowed), extra code to add +// For I : Followed by 4-8 Fields: +// 1) instruction name +// 2) semantic name (usually idential between R and I form) +// 3) pattern to match +// 4) mux (group) name +// 5-8) optional, (sub-)extension the instruction belongs to +// Avoids non-ASCII (7 bit) characters, as some string ends up in SpinalHDL code +// +// INSTRUCTIONS +// register-register +// inst semant pattern group/mux ext1 ext2 ext3 ext4 +// ---- ----- ------- --------- ---- ---- ---- ---- +I ANDN ANDN 0100000----------111-----0110011 bitwise Zbb Zbp +I ORN ORN 0100000----------110-----0110011 bitwise Zbb Zbp +I XNOR XNOR 0100000----------100-----0110011 bitwise Zbb Zbp +I SLO SLO 0010000----------001-----0110011 shift Zxx +I SRO SRO 0010000----------101-----0110011 shift Zxx +I ROL ROL 0110000----------001-----0110011 rotation Zbp +I ROR ROR 0110000----------101-----0110011 rotation Zbb Zbp +I SH1ADD SH1ADD 0010000----------010-----0110011 sh_add Zba +I SH2ADD SH2ADD 0010000----------100-----0110011 sh_add Zba +I SH3ADD SH3ADD 0010000----------110-----0110011 sh_add Zba +I SBCLR SBCLR 0100100----------001-----0110011 singlebit Zbs +I SBSET SBSET 0010100----------001-----0110011 singlebit Zbs +I SBINV SBINV 0110100----------001-----0110011 singlebit Zbs +I SBEXT SBEXT 0100100----------101-----0110011 singlebit Zbs +I GORC GORC 0010100----------101-----0110011 grevroc Zbp +I GREV GREV 0110100----------101-----0110011 grevroc Zbp +I CLMUL CLMUL 0000101----------001-----0110011 CLMUL +I CLMULR CLMULR 0000101----------010-----0110011 CLMULR +I CLMULH CLMULH 0000101----------011-----0110011 CLMULH +I MIN MIN 0000101----------100-----0110011 minmax Zbb +I MINU MINU 0000101----------101-----0110011 minmax Zbb +I MAX MAX 0000101----------110-----0110011 minmax Zbb +I MAXU MAXU 0000101----------111-----0110011 minmax Zbb +I SHFL SHFL 0000100----------001-----0110011 shuffle Zbp +I UNSHFL UNSHFL 0000100----------101-----0110011 shuffle Zbp +I BDEP BDEP 0100100----------110-----0110011 BDEP +I BEXT BEXT 0000100----------110-----0110011 BEXT +I PACK PACK 0000100----------100-----0110011 pack Zbb Zbp Zbe Zbf +I PACKU PACKU 0100100----------100-----0110011 pack Zbp +I BMATOR BMATOR 0000100----------011-----0110011 BMATOR +I BMATXOR BMATXOR 0100100----------011-----0110011 BMATXOR +I PACKH PACKH 0000100----------111-----0110011 pack Zbp Zbe Zbf +I BFP BFP 0100100----------111-----0110011 BFP +I ADDUdotW ADDUdotW 0000100----------000-----0111011 ADDUdotW +I SLOW SLOW 0010000----------001-----0111011 shift +I SROW SROW 0010000----------101-----0111011 shift +I ROLW ROLW 0110000----------001-----0111011 rotation Zbb Zbp +I RORW RORW 0110000----------101-----0111011 rotation Zbb Zbp +I SH1ADDUdotW SH1ADDUdotW 0010000----------010-----0111011 SH1ADDUdotW +I SH2ADDUdotW SH2ADDUdotW 0010000----------100-----0111011 SH2ADDUdotW +I SH3ADDUdotW SH3ADDUdotW 0010000----------110-----0111011 SH3ADDUdotW +I SBCLRW SBCLRW 0100100----------001-----0111011 singlebit Zbs +I SBSETW SBSETW 0010100----------001-----0111011 singlebit Zbs +I SBINVW SBINVW 0110100----------001-----0111011 singlebit Zbs +I SBEXTW SBEXTW 0100100----------101-----0111011 singlebit Zbs +I GORCW GORCW 0010100----------101-----0111011 grevroc +I GREVW GREVW 0110100----------101-----0111011 grevroc +I SHFLW SHFLW 0000100----------001-----0111011 shuffle Zbp +I UNSHFLW UNSHFLW 0000100----------101-----0111011 shuffle Zbp +I BDEPW BDEPW 0100100----------110-----0111011 BDEPW +I BEXTW BEXTW 0000100----------110-----0111011 BEXTW +I PACKW PACKW 0000100----------100-----0111011 pack +I PACKUW PACKUW 0100100----------100-----0111011 pack +I BFPW BFPW 0100100----------111-----0111011 BFPW +I XPERMdotN XPERMdotN 0010100----------010-----0110011 xperm Zbp +I XPERMdotB XPERMdotB 0010100----------100-----0110011 xperm Zbp +I XPERMdotH XPERMdotH 0010100----------110-----0110011 xperm Zbp +I XPERMdotW XPERMdotW 0010100----------000-----0110011 XPERMdotW +// register-immediate (7bits) +I SLOI SLO 00100------------001-----0010011 shift Zxx +I SROI SRO 00100------------101-----0010011 shift Zxx +I RORI ROR 01100------------101-----0010011 rotation Zbb Zbp +I SBCLRI SBCLR 01001------------001-----0010011 singlebit Zbs +I SBSETI SBSET 00101------------001-----0010011 singlebit Zbs +I SBINVI SBINV 01101------------001-----0010011 singlebit Zbs +I SBEXTI SBEXT 01001------------101-----0010011 singlebit Zbs +I GORCI GORC 00101------------101-----0010011 grevorc Zbp +I GREVI GREV 01101------------101-----0010011 grevorc Zbp +I SLLIUdotW SLLIUdotW 00001------------001-----0011011 SLLIUdotW +// register-immediate (6bits) +I SHFLI SHFL 000010-----------001-----0010011 shuffle Zbp +I UNSHFLI UNSHFL 000010-----------101-----0010011 shuffle Zbp +// register-immediate (5bits) +I SLOIW SLOW 0010000----------001-----0011011 shift +I SROIW SROW 0010000----------101-----0011011 shift +I RORIW RORW 0110000----------101-----0011011 rotation +I SBCLRIW SBCLRW 0100100----------001-----0011011 singlebit +I SBSETIW SBSETW 0010100----------001-----0011011 singlebit +I SBINVIW SBINVW 0110100----------001-----0011011 singlebit +I GORCIW GORCW 0010100----------101-----0011011 grevroc +I GREVIW GREVW 0110100----------101-----0011011 grevroc +// unary register +I CLZ CLZ 011000000000-----001-----0010011 countzeroes Zbb +I CTZ CTZ 011000000001-----001-----0010011 countzeroes Zbb +I PCNT PCNT 011000000010-----001-----0010011 countzeroes Zbb +I BMATFLIP BMATFLIP 011000000011-----001-----0010011 BMATFLIP +I SEXTdotB SEXTdotB 011000000100-----001-----0010011 signextend Zbe Zbb +I SEXTdotH SEXTdotH 011000000101-----001-----0010011 signextend Zbe Zbb +I CRC32dotB CRC32dotB 011000010000-----001-----0010011 CRC32dotB +I CRC32dotH CRC32dotH 011000010001-----001-----0010011 CRC32dotH +I CRC32dotW CRC32dotW 011000010010-----001-----0010011 CRC32dotW +I CRC32dotD CRC32dotD 011000010011-----001-----0010011 CRC32dotD +I CRC32CdotB CRC32CdotB 011000011000-----001-----0010011 CRC32CdotB +I CRC32CdotH CRC32CdotH 011000011001-----001-----0010011 CRC32CdotH +I CRC32CdotW CRC32CdotW 011000011010-----001-----0010011 CRC32CdotW +I CRC32CdotD CRC32CdotD 011000011011-----001-----0010011 CRC32CdotD +I CLZW CLZW 011000000000-----001-----0011011 countzeroes +I CTZW CTZW 011000000001-----001-----0011011 countzeroes +I PCNTW PCNTW 011000000010-----001-----0011011 countzeroes +// register-register-register +I CMIX CMIX -----11----------001-----0110011 CMIX +I CMOV CMOV -----11----------101-----0110011 CMOV +I FSL FSL -----10----------001-----0110011 FSL +I FSR FSR -----10----------101-----0110011 FSR +I FSRI FSRI -----1-----------101-----0010011 FSRI +I FSLW FSLW -----10----------001-----0111011 FSLW +I FSRW FSRW -----10----------101-----0111011 FSRW +I FSRIW FSRIW -----10----------101-----0011011 FSRIW + +// SEMANTIC +S ROR "input(SRC1).rotateRight((input(SRC2)&31)(4 downto 0).asUInt)" +S ROL "input(SRC1).rotateLeft((input(SRC2)&31)(4 downto 0).asUInt)" +S GREV "fun_grev(input(SRC1), input(SRC2))" +S GORC "fun_gorc(input(SRC1), input(SRC2))" +S PACK "(input(SRC2)(15 downto 0) ## input(SRC1)(15 downto 0))" +S PACKU "(input(SRC2)(31 downto 16) ## input(SRC1)(31 downto 16))" +S PACKH "B"16'x0000" ## (input(SRC2)(7 downto 0) ## input(SRC1)(7 downto 0))" +S SHFL "fun_shfl32(input(SRC1), input(SRC2))" +S UNSHFL "fun_unshfl32(input(SRC1), input(SRC2))" +S ANDN "(input(SRC1) & ~input(SRC2))" +S ORN "(input(SRC1) | ~input(SRC2))" +S XNOR "(input(SRC1) ^ ~input(SRC2))" +S SH1ADD "((input(SRC1) |<< 1).asUInt + input(SRC2).asUInt)" +S SH2ADD "((input(SRC1) |<< 2).asUInt + input(SRC2).asUInt)" +S SH3ADD "((input(SRC1) |<< 3).asUInt + input(SRC2).asUInt)" +S SBSET "(input(SRC1) | (B"32'x00000001"|<<((input(SRC2)&31).asUInt)))" +S SBCLR "(input(SRC1) & ~(B"32'x00000001"|<<((input(SRC2)&31).asUInt)))" +S SBINV "(input(SRC1) ^ (B"32'x00000001"|<<((input(SRC2)&31).asUInt)))" +S SBEXT "((input(SRC1) |>> ((input(SRC2)&31).asUInt)) & B"32'x00000001")" +S SLO "~((~input(SRC1)) |<< (input(SRC2)&31).asUInt)" +S SRO "~((~input(SRC1)) |>> (input(SRC2)&31).asUInt)" +S MIN "((input(SRC1).asSInt < input(SRC2).asSInt) ? input(SRC1) | input(SRC2))" +S MAX "((input(SRC1).asSInt > input(SRC2).asSInt) ? input(SRC1) | input(SRC2))" +S MINU "((input(SRC1).asUInt < input(SRC2).asUInt) ? input(SRC1) | input(SRC2))" +S MAXU "((input(SRC1).asUInt > input(SRC2).asUInt) ? input(SRC1) | input(SRC2))" +S XPERMdotN "fun_xperm_n(input(SRC1), input(SRC2))" +S XPERMdotB "fun_xperm_b(input(SRC1), input(SRC2))" +S XPERMdotH "fun_xperm_h(input(SRC1), input(SRC2))" +// if 'SRC2' doesn't appear in the semantic, the code assume unary +S SEXTdotB "(Bits(24 bits).setAllTo(input(SRC1)(7)) ## input(SRC1)(7 downto 0))" +S SEXTdotH "(Bits(16 bits).setAllTo(input(SRC1)(15)) ## input(SRC1)(15 downto 0))" +S CLZ "fun_clz(input(SRC1))" +S CTZ "fun_ctz(input(SRC1))" +S PCNT "fun_popcnt(input(SRC1))" + +// PROLOGUE +P """ + // function implementing the semantic of 32-bits generalized reverse + def fun_grev( a:Bits, b:Bits ) : Bits = { + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? (((a & B"32'x55555555") |<< 1) | ((a & B"32'xAAAAAAAA") |>> 1)) | a + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? (((x1 & B"32'x33333333") |<< 2) | ((x1 & B"32'xCCCCCCCC") |>> 2)) | x1 + val x4 = ((b&B"32'x00000004")===B"32'x00000004") ? (((x2 & B"32'x0F0F0F0F") |<< 4) | ((x2 & B"32'xF0F0F0F0") |>> 4)) | x2 + val x8 = ((b&B"32'x00000008")===B"32'x00000008") ? (((x4 & B"32'x00FF00FF") |<< 8) | ((x4 & B"32'xFF00FF00") |>> 8)) | x4 + val x16 = ((b&B"32'x00000010")===B"32'x00000010") ? (((x8 & B"32'x0000FFFF") |<<16) | ((x8 & B"32'xFFFF0000") |>>16)) | x8 + x16 // return value + } + // function implementing the semantic of 32-bits generalized OR-combine + def fun_gorc( a:Bits, b:Bits ) : Bits = { + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? (a | ((a & B"32'x55555555") |<< 1) | ((a & B"32'xAAAAAAAA") |>> 1)) | a + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? (x1 | ((x1 & B"32'x33333333") |<< 2) | ((x1 & B"32'xCCCCCCCC") |>> 2)) | x1 + val x4 = ((b&B"32'x00000004")===B"32'x00000004") ? (x2 | ((x2 & B"32'x0F0F0F0F") |<< 4) | ((x2 & B"32'xF0F0F0F0") |>> 4)) | x2 + val x8 = ((b&B"32'x00000008")===B"32'x00000008") ? (x4 | ((x4 & B"32'x00FF00FF") |<< 8) | ((x4 & B"32'xFF00FF00") |>> 8)) | x4 + val x16 = ((b&B"32'x00000010")===B"32'x00000010") ? (x8 | ((x8 & B"32'x0000FFFF") |<<16) | ((x8 & B"32'xFFFF0000") |>>16)) | x8 + x16 // return value + } + + // helper function for the implementation of the generalized shuffles + def fun_shuffle32_stage(src:Bits, maskL:Bits, maskR:Bits, N:Int) : Bits = { + val x = src & ~(maskL | maskR) + val x2 = x | ((src |<< N) & maskL) | ((src |>> N) & maskR); + x2 // return value + } + // function implementing the semantic of 32-bits generalized shuffle + def fun_shfl32(a:Bits, b:Bits) : Bits = { + val x = a; + val x1 = ((b&B"32'x00000008")===B"32'x00000008") ? fun_shuffle32_stage(x , B"32'x00FF0000", B"32'x0000FF00", 8) | x; + val x2 = ((b&B"32'x00000004")===B"32'x00000004") ? fun_shuffle32_stage(x1, B"32'x0F000F00", B"32'x00F000F0", 4) | x1; + val x3 = ((b&B"32'x00000002")===B"32'x00000002") ? fun_shuffle32_stage(x2, B"32'x30303030", B"32'x0C0C0C0C", 2) | x2; + val x4 = ((b&B"32'x00000001")===B"32'x00000001") ? fun_shuffle32_stage(x3, B"32'x44444444", B"32'x22222222", 1) | x3; + x4 // return value + } + // function implementing the semantic of 32-bits generalized unshuffle + def fun_unshfl32(a:Bits, b:Bits) : Bits = { + val x = a; + val x1 = ((b&B"32'x00000001")===B"32'x00000001") ? fun_shuffle32_stage(x , B"32'x44444444", B"32'x22222222", 1) | x; + val x2 = ((b&B"32'x00000002")===B"32'x00000002") ? fun_shuffle32_stage(x1, B"32'x30303030", B"32'x0C0C0C0C", 2) | x1; + val x3 = ((b&B"32'x00000004")===B"32'x00000004") ? fun_shuffle32_stage(x2, B"32'x0F000F00", B"32'x00F000F0", 4) | x2; + val x4 = ((b&B"32'x00000008")===B"32'x00000008") ? fun_shuffle32_stage(x3, B"32'x00FF0000", B"32'x0000FF00", 8) | x3; + x4 // return value + } + + + // this is trying to look like DOI 10.2478/jee-2015-0054 + def fun_clz_NLCi(x:Bits): Bits = { + val r2 = (~(x(0) | x(1) | x(2) | x(3))) + val r1 = (~(x(2) | x(3))) + val r0 = (~(x(3) | (x(1) & ~x(2)))) + val r = r2 ## r1 ## r0 + r // return value + } + def fun_clz_BNE(a:Bits) : Bits = { + val a01 = ~(a(0) & a(1)) + val a23 = ~(a(2) & a(3)) + + val a45 = ~(a(4) & a(5)) + val a67 = ~(a(6) & a(7)) + + val a0123 = ~(a01 | a23) // also r(2) + val a4567 = ~(a45 | a67) + + val a56 = ~(a(5) & ~a(6)) + val a024 = (a(0) & a(2) & a(4)) // AND not NAND + val a13 = ~(a(1) & a(3)) + val a12 = ~(a(1) & ~a(2)) + + val r3 = ((a0123 & a4567)) // AND not NAND + val r2 = (a0123) + val r1 = (~(a01 | (~a23 & a45))) + val r0 = (~((~((a56) & (a024))) & (~((a13) & (a12) & (a(0)))))) + + val r = r3 ## r2 ## r1 ##r0 + + r // return value + } + def fun_clz(in:Bits) : Bits = { + val nlc7 = fun_clz_NLCi(in(31 downto 28)) + val nlc6 = fun_clz_NLCi(in(27 downto 24)) + val nlc5 = fun_clz_NLCi(in(23 downto 20)) + val nlc4 = fun_clz_NLCi(in(19 downto 16)) + val nlc3 = fun_clz_NLCi(in(15 downto 12)) + val nlc2 = fun_clz_NLCi(in(11 downto 8)) + val nlc1 = fun_clz_NLCi(in( 7 downto 4)) + val nlc0 = fun_clz_NLCi(in( 3 downto 0)) + val a = nlc0(2) ## nlc1(2) ## nlc2(2) ## nlc3(2) ## nlc4(2) ## nlc5(2) ## nlc6(2) ## nlc7(2) + val bne = fun_clz_BNE(a) + + val muxo = (bne(2 downto 0)).mux( + B"3'b000" -> nlc7(1 downto 0), + B"3'b001" -> nlc6(1 downto 0), + B"3'b010" -> nlc5(1 downto 0), + B"3'b011" -> nlc4(1 downto 0), + B"3'b100" -> nlc3(1 downto 0), + B"3'b101" -> nlc2(1 downto 0), + B"3'b110" -> nlc1(1 downto 0), + B"3'b111" -> nlc0(1 downto 0) + ) + val r = (bne(3)) ? B"6'b100000" | (B"1'b0" ## bne(2 downto 0) ## muxo(1 downto 0)) // 6 bits + + r.resize(32) // return value + } + // For trailing count, count using use leading count on bit-reversed value + def fun_ctz(in:Bits) : Bits = { + val inr = in(0) ## in(1) ## in(2) ## in(3) ## in(4) ## in(5) ## in(6) ## in(7) ## in(8) ## in(9) ## in(10) ## in(11) ## in(12) ## in(13) ## in(14) ## in(15) ## in(16) ## in(17) ## in(18) ## in(19) ## in(20) ## in(21) ## in(22) ## in(23) ## in(24) ## in(25) ## in(26) ## in(27) ## in(28) ## in(29) ## in(30) ## in(31) + fun_clz(inr) // return value + } + + // naive popcnt + def fun_popcnt(in:Bits) : Bits = { + val r = in(0).asBits.resize(6).asUInt + in(1).asBits.resize(6).asUInt + in(2).asBits.resize(6).asUInt + in(3).asBits.resize(6).asUInt + + in(4).asBits.resize(6).asUInt + in(5).asBits.resize(6).asUInt + in(6).asBits.resize(6).asUInt + in(7).asBits.resize(6).asUInt + + in(8).asBits.resize(6).asUInt + in(9).asBits.resize(6).asUInt + in(10).asBits.resize(6).asUInt + in(11).asBits.resize(6).asUInt + + in(12).asBits.resize(6).asUInt + in(13).asBits.resize(6).asUInt + in(14).asBits.resize(6).asUInt + in(15).asBits.resize(6).asUInt + + in(16).asBits.resize(6).asUInt + in(17).asBits.resize(6).asUInt + in(18).asBits.resize(6).asUInt + in(19).asBits.resize(6).asUInt + + in(20).asBits.resize(6).asUInt + in(21).asBits.resize(6).asUInt + in(22).asBits.resize(6).asUInt + in(23).asBits.resize(6).asUInt + + in(24).asBits.resize(6).asUInt + in(25).asBits.resize(6).asUInt + in(26).asBits.resize(6).asUInt + in(27).asBits.resize(6).asUInt + + in(28).asBits.resize(6).asUInt + in(29).asBits.resize(6).asUInt + in(30).asBits.resize(6).asUInt + in(31).asBits.resize(6).asUInt + + r.asBits.resize(32) // return value + } + + //XPERMs + def fun_xperm_n(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(3 downto 0).asUInt + val i1 = rs2(7 downto 4).asUInt + val i2 = rs2(11 downto 8).asUInt + val i3 = rs2(15 downto 12).asUInt + val i4 = rs2(19 downto 16).asUInt + val i5 = rs2(23 downto 20).asUInt + val i6 = rs2(27 downto 24).asUInt + val i7 = rs2(31 downto 28).asUInt + val r0 = (i0).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r1 = (i1).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r2 = (i2).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r3 = (i3).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r4 = (i4).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r5 = (i5).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r6 = (i6).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + val r7 = (i7).mux( + 0 -> rs1(3 downto 0), + 1 -> rs1(7 downto 4), + 2 -> rs1(11 downto 8), + 3 -> rs1(15 downto 12), + 4 -> rs1(19 downto 16), + 5 -> rs1(23 downto 20), + 6 -> rs1(27 downto 24), + 7 -> rs1(31 downto 28), + default -> B"4'b0000" + ) + r7 ## r6 ## r5 ## r4 ## r3 ## r2 ## r1 ## r0 // return value + } + def fun_xperm_b(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(7 downto 0).asUInt; + val i1 = rs2(15 downto 0).asUInt; + val i2 = rs2(23 downto 0).asUInt; + val i3 = rs2(31 downto 0).asUInt; + val r0 = (i0).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r1 = (i1).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r2 = (i2).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + val r3 = (i3).mux( + 0 -> rs1(7 downto 0), + 1 -> rs1(15 downto 8), + 2 -> rs1(23 downto 16), + 3 -> rs1(31 downto 24), + default -> B"8'b00000000" + ) + r3 ## r2 ## r1 ## r0 // return value + } + def fun_xperm_h(rs1:Bits, rs2:Bits) : Bits = { + val i0 = rs2(15 downto 0).asUInt; + val i1 = rs2(31 downto 16).asUInt; + val r0 = (i0).mux( + 0 -> rs1(15 downto 0), + 1 -> rs1(31 downto 16), + default -> B"16'x0000" + ) + val r1 = (i1).mux( + 0 -> rs1(15 downto 0), + 1 -> rs1(31 downto 16), + default -> B"16'x0000" + ) + r1 ## r0 // return value + } +""" diff --git a/extract_bitmanip.sh b/extract_bitmanip.sh new file mode 100755 index 0000000..310dcc5 --- /dev/null +++ b/extract_bitmanip.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +FILE=texsrc/bext.tex + +# 2 ops +#echo "// register-register" +#grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep rs2.*rs1 | grep -v rs3 | sed -e 's/rs2/-----/' -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "def "$14"_key =\tM\""$2$4$6$8$10$12"\"" }' + +# 7bit simm +#echo "// register-immediate (7bits)" +#grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep '^| [01][01][01][01][01] *|' | grep imm.*rs1 | sed -e 's/imm/-------/' -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "def "$14"_key =\tM\""$2$4$6$8$10$12"\"" }' + +# 6bit simm +#echo "// register-immediate (6bits)" +#grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep '^| [01][01][01][01][01][01] *|' | grep imm.*rs1 | sed -e 's/imm/------/' -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "def "$14"_key =\tM\""$2$4$6$8$10$12"\"" }' + +# 5bit simm +#echo "// register-immediate (5bits)" +#grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep '^| [01][01][01][01][01][01][01] *|' | grep imm.*rs1 | sed -e 's/imm/-----/' -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "def "$14"_key =\tM\""$2$4$6$8$10$12"\"" }' + + + + +echo "// register-register" +grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep rs2.*rs1 | grep -v rs3 | sed -e 's/rs2/-----/' -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "I""\t"$14"\t"$14"\t"$2$4$6$8$10$12"\t"$14 }' | sed -e 's/\./dot/g' + +echo "// register-immediate (7bits)" +grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep '^| [01][01][01][01][01] *|' | grep imm.*rs1 | sed -e 's/imm/-------/' -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "I""\t"$14"\t"$14"\t"$2$4$6$8$10$12"\t"$14 }' | sed -e 's/\./dot/g' + +echo "// register-immediate (6bits)" +grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep '^| [01][01][01][01][01][01] *|' | grep imm.*rs1 | sed -e 's/imm/------/' -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "I""\t"$14"\t"$14"\t"$2$4$6$8$10$12"\t"$14 }' | sed -e 's/\./dot/g' + +echo "// register-immediate (5bits)" +grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep '^| [01][01][01][01][01][01][01] *|' | grep imm.*rs1 | sed -e 's/imm/-----/' -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "I""\t"$14"\t"$14"\t"$2$4$6$8$10$12"\t"$14 }' | sed -e 's/\./dot/g' + +echo "// unary register" +grep '^|.*| [A-Z][A-Z]' $FILE |grep -v '\*$' | grep '^| [01][01][01][01][01][01][01] *| [01][01][01][01][01] |' | sed -e 's/rs1/-----/' -e 's/rd/-----/' | awk '{ print "I""\t"$14"\t"$14"\t"$2$4$6$8$10$12"\t"$14 }' | sed -e 's/\./dot/g' + +echo "// register-register-register" +grep '^|.*| [A-Z][A-Z]' $FILE | grep rs3 | sed -e 's/rs3/-----/' -e 's/rs2/-----/' -e 's/rs1/-----/' -e 's/rd/-----/' -e 's/ //g' -e 's/|1|imm/|1|------/' -e 's/|10|imm/|10|-----/' | awk '-F|' '{ print "I""\t"$9"\t"$9"\t"$2$3$4$5$6$7$8"\t"$9 }' | sed -e 's/\./dot/g' + + diff --git a/gen_plugin.cpp b/gen_plugin.cpp new file mode 100644 index 0000000..77bf529 --- /dev/null +++ b/gen_plugin.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ + +#include +#include +#include + +#include "inst.hpp" + +#include "unparse.hpp" + +#include "gen_plugin.hpp" + +#include + +// yucc +extern "C" { +#include "inst_par.h" +extern FILE *yyin, *yyout; +extern int yydebug; +} + +std::set instructions; +std::map semantics; +const char* prologue; + +void add_inst0(const char* name, const char* opname, const char* key, const char* group) { + instruction* i = new instruction(name, opname, key, group); + instructions.insert(i); +} +void add_inst1(const char* name, const char* opname, const char* key, const char* group, const char* e1) { + instruction* i = new instruction(name, opname, key, group); + i->addExt(e1); + instructions.insert(i); +} +void add_inst2(const char* name, const char* opname, const char* key, const char* group, const char* e1, const char* e2) { + instruction* i = new instruction(name, opname, key, group); + i->addExt(e1); + i->addExt(e2); + instructions.insert(i); +} +void add_inst3(const char* name, const char* opname, const char* key, const char* group, const char* e1, const char* e2, const char *e3) { + instruction* i = new instruction(name, opname, key, group); + i->addExt(e1); + i->addExt(e2); + i->addExt(e3); + instructions.insert(i); +} +void add_inst4(const char* name, const char* opname, const char* key, const char* group, const char* e1, const char* e2, const char *e3, const char *e4) { + instruction* i = new instruction(name, opname, key, group); + i->addExt(e1); + i->addExt(e2); + i->addExt(e3); + i->addExt(e4); + instructions.insert(i); +} +void add_sem(const char* name, const char* sem) { + semantics[std::string(name)] = std::string(sem); +} +void add_prol(const char *prol) { + prologue = prol; +} + + +int main(int argc, char **argv) { + +// std::set instructions; +// std::map semantics; + +// instruction* andn = new instruction("andn", "andn", "0100000----------111-----0110011", "bitwise", false); +// instruction* xnor = new instruction("xnor", "xnor", "0100000----------100-----0110011", "bitwise", false); + +// instruction* ror = new instruction("ror" , "ror" , "0110000----------101-----0110011", "rotation", false); +// instruction* rori = new instruction("rori", "ror" , "01100------------101-----0010011", "rotation", true); + +// semantics["andn"] = "(input(SRC1) & ~input(SRC2)"; +// semantics["xnor"] = "(input(SRC1) ^ ~input(SRC2)"; +// semantics["ror"] = "input(SRC1).rotateRight((input(SRC2)&31)(4 downto 0).asUInt)"; + +// instructions.insert(andn); +// instructions.insert(xnor); +// instructions.insert(ror); +// instructions.insert(rori); + + if (argc > 2) { + FILE *myfile; + myfile = fopen(argv[2], "r"); + if (!myfile) { + fprintf(stderr, "no file\n"); + return -1; + } + yyin = myfile; + do { + yyparse(); + } while (!feof(yyin)); + fclose(myfile); + } else { + std::cerr << "Should have a datafile as second argument" << std::endl; + exit(-1); + } + + + std::set filtered_instructions; + + for (const instruction* inst : instructions) { + if (inst->isWord()) + continue; + if (semantics[inst->opname] == "") + continue; + bool addinst = false; + for (int i = 3 ; i < argc; i++) { + if (inst->match(argv[i]) || (strncmp(argv[i], "*", 1)==0)) { +// printf("%s is in %s\n", inst->name.c_str(), argv[i]); + addinst = true; + } else { +// printf("%s is NOT in %s\n", inst->name.c_str(), argv[i]); + } + } + if (addinst) + filtered_instructions.insert(inst); + //printf("adding %s\n", inst->name.c_str()); + } + + unparse(std::cout, argv[1], filtered_instructions, semantics, prologue); + + return 0; +} diff --git a/gen_plugin.hpp b/gen_plugin.hpp new file mode 100644 index 0000000..53532f6 --- /dev/null +++ b/gen_plugin.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ + +#ifndef __GEN_PLUGIN_HP__ +#define __GEN_PLUGIN_HP__ + +#ifdef __cplusplus +extern "C" { +#endif + void add_inst0(const char* name, const char* opname, const char* key, const char* group); + void add_inst1(const char* name, const char* opname, const char* key, const char* group, const char* e1); + void add_inst2(const char* name, const char* opname, const char* key, const char* group, const char* e1, const char* e2); + void add_inst3(const char* name, const char* opname, const char* key, const char* group, const char* e1, const char* e2, const char *e3); + void add_inst4(const char* name, const char* opname, const char* key, const char* group, const char* e1, const char* e2, const char *e3, const char *e4); + void add_sem(const char* name, const char* sem); + void add_prol(const char *prol); + +#ifdef __cplusplus +} +#endif + +#endif // __GEN_PLUGIN_HP__ diff --git a/group.hpp b/group.hpp new file mode 100644 index 0000000..ab54bb6 --- /dev/null +++ b/group.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ + +#ifndef __GROUP_HPP__ +#define __GROUP_HPP__ + +#include +#include "inst.hpp" + +class group { +public: + const std::string name; + std::set instructions; + std::set opnames; + + group(std::string n) : name(n) { + } + + void add(const instruction *inst) { + instructions.insert(inst); + opnames.insert(inst->opname); + } + bool match(const instruction *inst) { + return inst->group.compare(name) == 0; + } + + bool contains(const instruction *inst) { + for (const instruction* check : instructions) { + if (*check == *inst) + return true; + } + return false; + } + + bool operator ==(const group &b) const { + return name.compare(b.name) == 0; + } + + std::string ctrlName() const { + return "CTRL_" + name; + } +}; +#endif // __GROUP_HPP__ diff --git a/inst.hpp b/inst.hpp new file mode 100644 index 0000000..b7fe98e --- /dev/null +++ b/inst.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ + +#ifndef __INST_HPP__ +#define __INST_HPP__ + +#include +#include + + +class instruction { +public: + const std::string name; + const std::string opname; + const std::string key; + const std::string group; + std::set extensions; + +public: + instruction(std::string n, + std::string o, + std::string k, + std::string g + ) : name(n), opname(o), key(k), group(g) { + } + + void addExt(std::string e) { + extensions.insert(e); + } + + bool operator ==(const instruction &b) const { + return name.compare(b.name) == 0; + } + + bool match(const std::string toadd) const { + if (toadd.compare(name) == 0) + return true; + for (const std::string extension : extensions) + if (toadd.compare(extension) == 0) + return true; + + return false; + } + + bool isWord(void) const { + return name[name.length()-1] == 'W'; + } + + bool isImm(void) const { + if (isWord()) + return name[name.length()-2] == 'I'; + else + return name[name.length()-1] == 'I'; + } + + std::string ctrlName() const { + return "CTRL_" + group + "_" + opname; + } + std::string keyName() const { + return name + "_KEY"; + } +}; + +#endif // __INST_HPP__ diff --git a/inst_lex.l b/inst_lex.l new file mode 100644 index 0000000..216bd4c --- /dev/null +++ b/inst_lex.l @@ -0,0 +1,35 @@ +%{ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ +#include +#include "inst_par.h" +%} + +CHAR [[:alnum:] ,'&./()-] +CHARNAME [[:alnum:]_+-] +SPACE [ \t] + +%% + +^"I" { return INST; } + +^"S" { return SEM; } + +^"P" { return PROL; } + +"//".* { } + +{CHARNAME}{CHARNAME}{CHARNAME}* { yylval.string = strdup(yytext); return NAME; } + +"\"\"\""[^ù]*"\"\"\"" { yylval.string = strndup(yytext+3, strlen(yytext)-6); return STRING; } + +"\"".*"\"" { yylval.string = strndup(yytext+1, strlen(yytext)-2); return STRING; } + +\n { return yytext[0]; } + +{SPACE}+ { } + +%% diff --git a/inst_par.h b/inst_par.h new file mode 100644 index 0000000..e4d97ce --- /dev/null +++ b/inst_par.h @@ -0,0 +1,82 @@ +/* A Bison parser, made by GNU Bison 3.3.2. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Undocumented macros, especially those whose name start with YY_, + are private implementation details. Do not rely on them. */ + +#ifndef YY_YY_INST_PAR_H_INCLUDED +# define YY_YY_INST_PAR_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + NAME = 258, + STRING = 259, + INST = 260, + SEM = 261, + PROL = 262 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 9 "inst_par.y" /* yacc.c:1921 */ + + char* string; + +#line 70 "inst_par.h" /* yacc.c:1921 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE yylval; + +int yyparse (void); + +#endif /* !YY_YY_INST_PAR_H_INCLUDED */ diff --git a/inst_par.y b/inst_par.y new file mode 100644 index 0000000..e157dbd --- /dev/null +++ b/inst_par.y @@ -0,0 +1,53 @@ +%{ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ +#include +#include +#define YYDEBUG 1 +#include "gen_plugin.hpp" +%} + +%union +{ + char* string; +} + +%token NAME +%token STRING + +%token INST +%token SEM +%token PROL + + +%% +input: /* empty */ { } +| pattern input { } +; +pattern: +INST NAME NAME NAME NAME { /* printf("0 - %s\n", $2); */ add_inst0($2, $3, $4, $5); } +| INST NAME NAME NAME NAME NAME { /* printf("1 - %s\n", $2); */ add_inst1($2, $3, $4, $5, $6); } +| INST NAME NAME NAME NAME NAME NAME { /* printf("2 - %s\n", $2); */ add_inst2($2, $3, $4, $5, $6, $7); } +| INST NAME NAME NAME NAME NAME NAME NAME { /* printf("3 - %s\n", $2); */ add_inst3($2, $3, $4, $5, $6, $7, $8); } +| INST NAME NAME NAME NAME NAME NAME NAME NAME { /* printf("4 - %s\n", $2); */ add_inst4($2, $3, $4, $5, $6, $7, $8, $9); } +| SEM NAME STRING { add_sem($2, $3); } +| PROL STRING { add_prol($2); } +| '\n' +; +%% + +int +yyerror(char *s) +{ + fprintf(stderr, "error: %s\n", s); + return(0); +} + +int +yywrap(void) +{ + return(-1); +} diff --git a/test_b.c b/test_b.c new file mode 100644 index 0000000..422a9bf --- /dev/null +++ b/test_b.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ + +/* + * test file for some B instructions. + * a) Get the B-supporting toolchain from , as explained in directory of that repository + * b) Fix the assembler for the bug in (swap the value of MATCH_MAX and MATCH_MINU unless the fix was integrated since) + * c) Get the official toolchain for RISC-V (e.g. see 'Installing a RISC-V toolchain' in https://github.com/litex-hub/linux-on-litex-vexriscv) + * c) Copy the header from bitmanip in here + * d) to simulate on your host: + * gcc -I. -DRVINTRIN_EMULATE test_b.c && ./a.out | tee check.txt + * e) to geenrate a binary for a RV32IMAB linux platform like Linux-on-Litex-Vexriscv: + * Generate ao object with B support: + * /opt/riscv64b/bin/riscv64-unknown-elf-gcc -I. -march=rv32imab -mabi=ilp32 -Os test_b.c -c + * Link with the official toolchain: + * /opt/riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-gcc -march=rv32ima -mabi=ilp32 test_b.o -o check + * Running the 'check' binary on the VexRiscv core should give the same results as running in simulation on the host. + * You can pass parameters to the binary to change input values. + * If you don't implement some instructions, remove them from the test. + */ + + +#include +#include +#include + +/* typedef uint32_t uint_xlen_t; */ +/* #define XLEN 32 */ +#include + + +typedef uint32_t uint_xlen_t; +#ifdef __riscv + //when missing in toolchain +#define FUN(NAME, OPC) \ + static inline uint_xlen_t NAME(uint_xlen_t rs1, uint_xlen_t rs2) { \ + uint32_t r; \ + asm inline("or x17, %1 ,%1\n" \ + "or x18, %2, %2\n" \ + ".word " #OPC "\n" \ + "or %0, x19, x19\n" \ + : "=r" (r) \ + : "r" (rs1), "r" (rs2) \ + : "x17", "x18", "x19"); \ + return r; \ + } +FUN(xperm_n,0x2928a9b3) +FUN(xperm_b,0x2928c9b3) +FUN(xperm_h,0x2928e9b3) +FUN(sh1add,0x2128a9b3) +FUN(sh2add,0x2128c9b3) +FUN(sh3add,0x2128e9b3) +#else +#define xperm_n _rv32_xperm_n +#define xperm_b _rv32_xperm_b +#define xperm_h _rv32_xperm_h +uint_xlen_t sh1add(uint_xlen_t rs1, uint_xlen_t rs2) +{ + return (rs1 << 1) + rs2; +} +uint_xlen_t sh2add(uint_xlen_t rs1, uint_xlen_t rs2) +{ + return (rs1 << 2) + rs2; +} +uint_xlen_t sh3add(uint_xlen_t rs1, uint_xlen_t rs2) +{ + return (rs1 << 3) + rs2; +} +#endif + +int main(int argc, char **argv) { + unsigned int a = 0x01234567; + unsigned int b = 0xdeadbeef; + unsigned int c; + unsigned int index; + + if (argc > 1) + a = strtoul(argv[1], NULL, 16); + if (argc > 2) + b = strtoul(argv[2], NULL, 16); + +#define T2(X) \ + c = X(a,b);printf(#X "(0x%08x, 0x%08x) -> 0x%08x\n", a, b, c) +#define T1(X) \ + c = X(a);printf(#X "(0x%08x) -> 0x%08x\n", a, c) + + for (index = 0 ; index < 32 ; index++) { + + T2(_rv32_ror); + T2(_rv32_rol); + + T2(_rv32_grev); + T2(_rv32_gorc); + + T2(_rv32_pack); + T2(_rv32_packu); + T2(_rv32_packh); + + T2(_rv32_shfl); + T2(_rv32_unshfl); + + T2(_rv_andn); + T2(_rv_xnor); + T2(_rv_orn); + + // T2(_rv32_sh1add); + // T2(_rv32_sh2add); + // T2(_rv32_sh3add); + + T2(_rv32_sbset); + T2(_rv32_sbclr); + T2(_rv32_sbinv); + T2(_rv32_sbext); + + T2(_rv32_min); + T2(_rv32_minu); + T2(_rv32_max); + T2(_rv32_maxu); + + T2(_rv32_slo); + T2(_rv32_sro); + + //T2(_rv32_xperm_b); + + T1(_rv32_sext_b); + T1(_rv32_sext_h); + + T1(_rv32_clz); + T1(_rv32_ctz); + T1(_rv32_pcnt); + + // extra stuff + T2(sh1add); + T2(sh2add); + T2(sh3add); + + T2(xperm_n); + T2(xperm_b); + T2(xperm_h); + + b = index; + } + + return 0; +} diff --git a/unparse.cpp b/unparse.cpp new file mode 100644 index 0000000..00afbb7 --- /dev/null +++ b/unparse.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ + +#include +#include +#include + + +#include "inst.hpp" +#include "group.hpp" + +std::set* createGroups(const std::set instructions) { + std::set* groups = new std::set(); + + for (const instruction* inst : instructions) { + bool done = false; + for (group* g : *groups) { + if (g->match(inst)) { + g->add(inst); + done = true; + } + } + if (!done) { + group* g = new group(inst->group); + g->add(inst); + groups->insert(g); + } + } + + return groups; +} + + +void unparse(std::ostream& output, + const std::string prefix, + const std::set instructions, + std::map semantics, + std::string prologue) { + std::set* groups = createGroups(instructions); + + output << "package vexriscv.plugin" << std::endl; + output << "import spinal.core._" << std::endl; + output << "import vexriscv.{Stageable, DecoderService, VexRiscv}" << std::endl; + + output << "object " << prefix << "Plugin {" << std::endl; + + // objects for second-level MUXes + for (group* g : *groups) { + if (g->opnames.size() > 1) { + output << '\t' << "object " << prefix << "Ctrl" << g->name << "Enum extends SpinalEnum(binarySequential) {" << std::endl; + output << '\t' << '\t' << " val "; + bool comma = false; + for (std::string opname : g->opnames) { + if (comma) output << ", "; + output << "CTRL_" << opname; + comma = true; + } + output << " = newElement()" << std::endl; + output << '\t' << "}" << std::endl; + } + } + + // object for first-level MUX + output << '\t' << "object " << prefix << "Ctrl" << "Enum extends SpinalEnum(binarySequential) {" << std::endl; + output << '\t' << '\t' << " val "; + bool comma = false; + for (group* g : *groups) { + if (comma) output << ", "; + if (g->opnames.size() > 1) + output << g->ctrlName(); + else + output << "CTRL_" << (*g->opnames.begin()); + comma = true; + } + output << " = newElement()" << std::endl; + output << '\t' << "}" << std::endl; + + // Stageable objects + + for (group* g : *groups) { + if (g->opnames.size() > 1) + output << '\t' << "object " << prefix << "Ctrl" << g->name << " extends Stageable(" << prefix << "Ctrl" << g->name << "Enum())" << std::endl; + } + output << '\t' << "object " << prefix << "Ctrl" << " extends Stageable(" << prefix << "Ctrl" << "Enum())" << std::endl; + + output << "// Prologue" << std::endl; + output << prologue; + output << std::endl << "// End prologue" << std::endl; + + output << "} // object Plugin" << std::endl; + + output << "class " << prefix << "Plugin extends Plugin[VexRiscv] {" << std::endl; + output << '\t' << "import " << prefix << "Plugin._" << std::endl; + output << '\t' << "object IS_" << prefix << " extends Stageable(Bool)" << std::endl; + + output << '\t' << "override def setup(pipeline: VexRiscv): Unit = {" << std::endl; + output << '\t' << '\t' << "import pipeline.config._" << std::endl; + + // define standard actions + output << '\t' << '\t' << "val immediateActions = List[(Stageable[_ <: BaseType],Any)](" << std::endl; + output << '\t' << '\t' << "\tSRC1_CTRL -> Src1CtrlEnum.RS," << std::endl; + output << '\t' << '\t' << "\tSRC2_CTRL -> Src2CtrlEnum.IMI," << std::endl; + output << '\t' << '\t' << "\tREGFILE_WRITE_VALID -> True," << std::endl; + output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> True," << std::endl; + output << '\t' << '\t' << "\tBYPASSABLE_MEMORY_STAGE -> True," << std::endl; + output << '\t' << '\t' << "\tRS1_USE -> True," << std::endl; + output << '\t' << '\t' << "\tIS_" << prefix << " -> True" << std::endl; + output << '\t' << '\t' << "\t)" << std::endl; + + output << '\t' << '\t' << "val binaryActions = List[(Stageable[_ <: BaseType],Any)](" << std::endl; + output << '\t' << '\t' << "\tSRC1_CTRL -> Src1CtrlEnum.RS," << std::endl; + output << '\t' << '\t' << "\tSRC2_CTRL -> Src2CtrlEnum.RS," << std::endl; + output << '\t' << '\t' << "\tREGFILE_WRITE_VALID -> True," << std::endl; + output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> True," << std::endl; + output << '\t' << '\t' << "\tBYPASSABLE_MEMORY_STAGE -> True," << std::endl; + output << '\t' << '\t' << "\tRS1_USE -> True," << std::endl; + output << '\t' << '\t' << "\tRS2_USE -> True," << std::endl; + output << '\t' << '\t' << "\tIS_" << prefix << " -> True" << std::endl; + output << '\t' << '\t' << "\t)" << std::endl; + + output << '\t' << '\t' << "val unaryActions = List[(Stageable[_ <: BaseType],Any)](" << std::endl; + output << '\t' << '\t' << "\tSRC1_CTRL -> Src1CtrlEnum.RS," << std::endl; + output << '\t' << '\t' << "\tREGFILE_WRITE_VALID -> True," << std::endl; + output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> True," << std::endl; + output << '\t' << '\t' << "\tBYPASSABLE_MEMORY_STAGE -> True," << std::endl; + output << '\t' << '\t' << "\tRS1_USE -> True," << std::endl; + output << '\t' << '\t' << "\tIS_" << prefix << " -> True" << std::endl; + output << '\t' << '\t' << "\t)" << std::endl; + + // inst keys + for (const instruction* inst : instructions) { + output << '\t' << '\t' << "def " << inst->keyName() << " = M\"" << inst->key << "\"" << std::endl; + } + + output << '\t' << '\t' << "val decoderService = pipeline.service(classOf[DecoderService])" << std::endl; + output << '\t' << '\t' << "decoderService.addDefault(IS_" << prefix << ", False)" << std::endl; + + // add actions + output << '\t' << '\t' << "decoderService.add(List(" << std::endl; + // for (const group* g : *groups) { + for (auto it = groups->begin() ; it != groups->end() ; it++) { + group* g = *it; + for (auto it2 = g->instructions.begin() ; it2 != g->instructions.end() ; it2++) { + const instruction* inst = *it2; + std::string control; + if (g->opnames.size() > 1) + control = prefix + "Ctrl -> " + prefix + "CtrlEnum." + g->ctrlName() + ", " + prefix + "Ctrl" + g->name + " -> " + prefix + "Ctrl" + g->name + "Enum.CTRL_" + inst->opname; + else + control = prefix + "Ctrl -> " + prefix + "CtrlEnum.CTRL_" + inst->opname; + if (!inst->isImm()) { + if (semantics[inst->opname].find("SRC2") != std::string::npos) + output << '\t' << '\t' << "\t" << inst->keyName() << "\t-> (binaryActions ++ List("<< control << "))"; + else + output << '\t' << '\t' << "\t" << inst->keyName() << "\t-> (unaryActions ++ List("<< control << "))"; + } else { + output << '\t' << '\t' << "\t" << inst->keyName() << "\t-> (immediateActions ++ List("<< control << "))"; + } + if ((std::next(it,1) == groups->end()) && (std::next(it2,1) == g->instructions.end())) + output << std::endl; + else + output << "," << std::endl; + } + } + output << '\t' << '\t' << "))" << std::endl; + output << '\t' << "} // override def setup" << std::endl; + + output << '\t' << "override def build(pipeline: VexRiscv): Unit = {" << std::endl; + output << '\t' << '\t' << "import pipeline._" << std::endl; + output << '\t' << '\t' << "import pipeline.config._" << std::endl; + output << '\t' << '\t' << "execute plug new Area{" << std::endl; + output << '\t' << '\t' << '\t' << "import execute._" << std::endl; + + // 2nd level MUXes + for (const group* g : *groups) { + if (g->opnames.size() > 1) { + output << '\t' << '\t' << '\t' << "val val_" << g->name << " = input("<< prefix << "Ctrl" << g->name << ").mux(" << std::endl; + for (auto it = g->opnames.begin() ; it != g->opnames.end() ; it++) { + std::string opname = *it; + output << '\t' << '\t' << '\t' << '\t' << prefix << "Ctrl" << g->name << "Enum.CTRL_" << opname << " -> " << semantics[opname]; + if (std::next(it, 1) == g->opnames.end()) + output << std::endl; + else + output << "," << std::endl; + } + output << '\t' << '\t' << '\t' << ") // mux " << g->name << std::endl; + } + } + + // conditional last level mux + output << '\t' << '\t' << '\t' << "when (input(IS_" << prefix << ")) {" << std::endl; + output << '\t' << '\t' << '\t' << '\t' << "execute.output(REGFILE_WRITE_DATA) := input(" << prefix << "Ctrl" << ").mux(" << std::endl; + for (auto it = groups->begin() ; it != groups->end() ; it++) { + group* g = *it; + if (g->opnames.size() > 1) { + output << '\t' << '\t' << '\t' << '\t' << '\t' << prefix << "CtrlEnum." << g->ctrlName() << " -> val_" << g->name << ".asBits"; + } else { + output << '\t' << '\t' << '\t' << '\t' << '\t' << prefix << "CtrlEnum.CTRL_" << (*g->opnames.begin()) << " -> " << semantics[*g->opnames.begin()] << ".asBits"; + } + if (std::next(it, 1) == groups->end()) + output << std::endl; + else + output << "," << std::endl; + } + output << '\t' << '\t' << '\t' << '\t' << ") // primary mux " << std::endl; + output << '\t' << '\t' << '\t' << "} // when input is " << std::endl; + + output << '\t' << '\t' << "} // execute plug newArea" << std::endl; + output << '\t' << "} // override def build" << std::endl; + output << "} // class Plugin" << std::endl; +} diff --git a/unparse.hpp b/unparse.hpp new file mode 100644 index 0000000..23f9506 --- /dev/null +++ b/unparse.hpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 Romain Dolbeau + * MIT License + * See the LICENSE file at the top level of this software distribution for details. + */ + +#ifndef __UNPARSE_HPP__ +#define __UNPARSE_HPP__ + +void unparse(std::ostream& output, + const std::string prefix, + const std::set instructions, + std::map semantics, + std::string prologue); + +#endif // __UNPARSE_HPP__ diff --git a/usage.txt b/usage.txt new file mode 100644 index 0000000..44ea407 --- /dev/null +++ b/usage.txt @@ -0,0 +1,31 @@ +Usage in Artix-7 35T for the whole LiteX SoC without B: ++----------------------------+------+-------+-----------+-------+ +| Site Type | Used | Fixed | Available | Util% | ++----------------------------+------+-------+-----------+-------+ +| Slice LUTs | 5400 | 0 | 20800 | 25.96 | +| LUT as Logic | 5230 | 0 | 20800 | 25.14 | +| LUT as Memory | 170 | 0 | 9600 | 1.77 | +| LUT as Distributed RAM | 168 | 0 | | | +| LUT as Shift Register | 2 | 0 | | | +| Slice Registers | 4660 | 0 | 41600 | 11.20 | +| Register as Flip Flop | 4660 | 0 | 41600 | 11.20 | +| Register as Latch | 0 | 0 | 41600 | 0.00 | +| F7 Muxes | 78 | 0 | 16300 | 0.48 | +| F8 Muxes | 13 | 0 | 8150 | 0.16 | ++----------------------------+------+-------+-----------+-------+ + +Usage in Artix-7 35T for the whole LiteX SoC with 44 B instructions (all implemented now): ++----------------------------+------+-------+-----------+-------+ +| Site Type | Used | Fixed | Available | Util% | ++----------------------------+------+-------+-----------+-------+ +| Slice LUTs | 6731 | 0 | 20800 | 32.36 | +| LUT as Logic | 6561 | 0 | 20800 | 31.54 | +| LUT as Memory | 170 | 0 | 9600 | 1.77 | +| LUT as Distributed RAM | 168 | 0 | | | +| LUT as Shift Register | 2 | 0 | | | +| Slice Registers | 4674 | 0 | 41600 | 11.24 | +| Register as Flip Flop | 4674 | 0 | 41600 | 11.24 | +| Register as Latch | 0 | 0 | 41600 | 0.00 | +| F7 Muxes | 134 | 0 | 16300 | 0.82 | +| F8 Muxes | 13 | 0 | 8150 | 0.16 | ++----------------------------+------+-------+-----------+-------+