mirror of
https://github.com/rdolbeau/VexRiscvBPluginGenerator.git
synced 2025-04-16 09:44:41 -04:00
First version of the plugin generator for B
This commit is contained in:
commit
37f253c1f9
18 changed files with 2426 additions and 0 deletions
549
BitManipAllPlugin.scala
Normal file
549
BitManipAllPlugin.scala
Normal 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
441
BitManipZbpPlugin.scala
Normal 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
21
LICENSE
Normal 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
53
Makefile
Normal 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
36
README.md
Normal 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
438
data_bitmanip.txt
Normal 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
42
extract_bitmanip.sh
Executable 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
130
gen_plugin.cpp
Normal 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
25
gen_plugin.hpp
Normal 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
46
group.hpp
Normal 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
67
inst.hpp
Normal 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
35
inst_lex.l
Normal 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
82
inst_par.h
Normal 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
53
inst_par.y
Normal 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
148
test_b.c
Normal 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
213
unparse.cpp
Normal 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
16
unparse.hpp
Normal 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
31
usage.txt
Normal 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 |
|
||||
+----------------------------+------+-------+-----------+-------+
|
Loading…
Add table
Reference in a new issue