First version of the plugin generator for B

This commit is contained in:
Romain Dolbeau 2020-11-05 09:26:16 +01:00
commit 37f253c1f9
18 changed files with 2426 additions and 0 deletions

549
BitManipAllPlugin.scala Normal file
View file

@ -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

441
BitManipZbpPlugin.scala Normal file
View file

@ -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

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
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.

53
Makefile Normal file
View file

@ -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)

36
README.md Normal file
View file

@ -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
```

438
data_bitmanip.txt Normal file
View file

@ -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
}
"""

42
extract_bitmanip.sh Executable file
View file

@ -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'

130
gen_plugin.cpp Normal file
View file

@ -0,0 +1,130 @@
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* MIT License
* See the LICENSE file at the top level of this software distribution for details.
*/
#include <iostream>
#include <set>
#include <map>
#include "inst.hpp"
#include "unparse.hpp"
#include "gen_plugin.hpp"
#include <cstring>
// yucc
extern "C" {
#include "inst_par.h"
extern FILE *yyin, *yyout;
extern int yydebug;
}
std::set<const instruction*> instructions;
std::map<std::string, std::string> 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<const instruction*> instructions;
// std::map<std::string, std::string> 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<const instruction*> 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;
}

25
gen_plugin.hpp Normal file
View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* 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__

46
group.hpp Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* MIT License
* See the LICENSE file at the top level of this software distribution for details.
*/
#ifndef __GROUP_HPP__
#define __GROUP_HPP__
#include <set>
#include "inst.hpp"
class group {
public:
const std::string name;
std::set<const instruction*> instructions;
std::set<std::string> 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__

67
inst.hpp Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* MIT License
* See the LICENSE file at the top level of this software distribution for details.
*/
#ifndef __INST_HPP__
#define __INST_HPP__
#include <string>
#include <set>
class instruction {
public:
const std::string name;
const std::string opname;
const std::string key;
const std::string group;
std::set<std::string> 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__

35
inst_lex.l Normal file
View file

@ -0,0 +1,35 @@
%{
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* MIT License
* See the LICENSE file at the top level of this software distribution for details.
*/
#include <stdio.h>
#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}+ { }
%%

82
inst_par.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>. */
/* 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 */

53
inst_par.y Normal file
View file

@ -0,0 +1,53 @@
%{
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* MIT License
* See the LICENSE file at the top level of this software distribution for details.
*/
#include <stdio.h>
#include <stdlib.h>
#define YYDEBUG 1
#include "gen_plugin.hpp"
%}
%union
{
char* string;
}
%token <string> NAME
%token <string> 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);
}

148
test_b.c Normal file
View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* 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 <https://github.com/riscv/riscv-bitmanip>, as explained in directory <tools/> of that repository
* b) Fix the assembler for the bug in <https://github.com/riscv/riscv-bitmanip/issues/93> (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 <cproofs/rvintrin.h> 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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>
/* typedef uint32_t uint_xlen_t; */
/* #define XLEN 32 */
#include <rvintrin.h>
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;
}

213
unparse.cpp Normal file
View file

@ -0,0 +1,213 @@
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* MIT License
* See the LICENSE file at the top level of this software distribution for details.
*/
#include <iostream>
#include <set>
#include <map>
#include "inst.hpp"
#include "group.hpp"
std::set<group*>* createGroups(const std::set<const instruction*> instructions) {
std::set<group*>* groups = new std::set<group*>();
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<const instruction*> instructions,
std::map<std::string,std::string> semantics,
std::string prologue) {
std::set<group*>* 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;
}

16
unparse.hpp Normal file
View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2020 Romain Dolbeau <romain.dolbeau@european-processor-initiative.eu>
* 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<const instruction*> instructions,
std::map<std::string,std::string> semantics,
std::string prologue);
#endif // __UNPARSE_HPP__

31
usage.txt Normal file
View file

@ -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 |
+----------------------------+------+-------+-----------+-------+