Skip to content

How to add new instruction to the decoder

UlisesLuzius edited this page Feb 13, 2019 · 1 revision

In order to add instructions, we will follow the process of adding ADD/SUB immediate instructions. Steps of this process are present in the commit https://github.com/UlisesLuzius/protoflex-chisel/commit/67339e7e45d8bc81d016aa6001e7abf0d4a05107

  1. Get instructions bitcodes from common/bitcodes.scala and add Bitpats to common/instructions.scala
object INSTRUCTIONS
{
  def INST_X = BitPat.dontCare(32)
  ...
  // Add/subtract (immediate)                                                                                                                  
  // I_ASImm                                                                                                                                   
  // 31 | 30 | 29 | 28 27 26 25 24 | 23 22 | 21 20 19 18 17 16 15 14 13 12 11 10 | 09 08 07 06 05 | 04 03 02 01 00 | Instruction Page | Variant
  //  1 |  0 |  0 |  1  0  0  0  1 |   -   |               imm12                 |      Rn        |        Rd      | ADD              | 64-bit 
  //  1 |  0 |  1 |  1  0  0  0  1 |   -   |               imm12                 |      Rn        |        Rd      | ADDS             | 64-bit 
  //  1 |  1 |  0 |  1  0  0  0  1 |   -   |               imm12                 |      Rn        |        Rd      | SUB              | 64-bit 
  //  1 |  1 |  1 |  1  0  0  0  1 |   -   |               imm12                 |      Rn        |        Rd      | SUBS             | 64-bit 
+ def ADD_I  = BitPat("b10010001????????????????????????")                                                                                     
+ def ADDS_I = BitPat("b10110001????????????????????????")                                                                                     
+ def SUB_I  = BitPat("b11010001????????????????????????")                                                                                     
+ def SUBS_I = BitPat("b11110001????????????????????????")      
...
}                                                                               
  1. Add instruction constant to DEC_LITS in common/decode_consts.scala
object DEC_LITS
{
  // Valault Defues
  val IMM_W = 26
  ...
  // Types
  val TYPE_W = 3 // Log2ceil(nb_insts)
  val I_X = 0
  val I_LogSR = 1
  val I_BImm  = 2
  val I_BCImm = 3
+ val I_ASImm = 4
  ...
}
  1. Add instruction to DEC_LITS.decode_table
object DEC_LITS
{
  // Valault Defues
  val IMM_W = 26
  ...
  def decode_table(inst_type : Int ): List[BigInt] =
    inst_type match {
      //                   RD            INSTRUCTION
      //                   EN              VALID
      //                   | RS1        COND |
      //                   |  EN          EN |
      //                   |  | RS2  SHIFT|  |
      //                   |  |  EN    EN |  |
      //                   |  |  | IMM |  |  |
      //                   |  |  |  EN |  |  |
      //                   |  |  |  |  |  |  |
      //                   |  |  |  |  |  |  |
      //                   |  |  |  |  |  |  |
      case I_X     => List(N, N, N, N, N, N, N)
      case I_LogSR => List(Y, Y, Y, N, Y, N, Y)
      case I_BImm  => List(N, N, N, Y, N, N, Y)
      case I_BCImm => List(N, N, N, Y, N, Y, Y)
+     case I_ASImm => List(Y, Y, N, Y, N, Y, Y)
    }
}

In case a new control field is created, add it to the list (E.G field) :

object DEC_LITS
{
...
  def decode_table(inst_type : Int): List[BigInt] =
    inst match {
    //                   RD              INSTRUCTION
    //                   EN                 VALID
    //                   | RS1        COND    |
    //                   |  EN          EN    |
    //                   |  | RS2  SHIFT|     |
    //                   |  |  EN    EN |     |
    //                   |  |  | IMM |  |     |
    //                   |  |  |  EN |  | E.G |
    //                   |  |  |  |  |  | FIELD
    //                   |  |  |  |  |  |  |  |
    //                   |  |  |  |  |  |  |  |
    case I_X     => List(N, N, N, N, N, N, N, N)
    ...
}}
  1. Add instruction to BitPattern decoder in common/decode_consts.DECODE_MATCHING_TABLES
object DECODE_MATCHING_TABLES
{
  ...
  def decode_table: Array[(BitPat, List[UInt])]  =
    Array(
      // Logical (shifted register)
      AND    -> List(I_LogSR, OP_AND,   Y, Y, Y, N, Y, N, Y),
      BIC    -> List(I_LogSR, OP_BIC,   Y, Y, Y, N, Y, N, Y),
      ORR    -> List(I_LogSR, OP_ORR,   Y, Y, Y, N, Y, N, Y),
      ORN    -> List(I_LogSR, OP_ORN,   Y, Y, Y, N, Y, N, Y),
      EOR    -> List(I_LogSR, OP_EOR,   Y, Y, Y, N, Y, N, Y),
      EON    -> List(I_LogSR, OP_EON,   Y, Y, Y, N, Y, N, Y),
      ANDS   -> List(I_LogSR, OP_AND,   Y, Y, Y, N, Y, Y, Y),
      BICS   -> List(I_LogSR, OP_BIC,   Y, Y, Y, N, Y, Y, Y),
      // Unconditional branch (immediate)
      B      -> List(I_BImm , OP_B,     N, N, N, Y, N, N, Y),
      BL     -> List(I_BImm , OP_B,     N, N, N, Y, N, N, Y),
      // Compare & branch (immediate)
      BCond  -> List(I_BCImm, OP_BCOND, N, N, N, Y, N, Y, Y),

      // Add/subtract (immediate)
+     ADD_I  -> List(I_ASImm, OP_ADD,   Y, Y, N, Y, N, Y, Y), 
+     ADDS_I -> List(I_ASImm, OP_ADD,   Y, Y, N, Y, N, Y, Y),
+     SUB_I  -> List(I_ASImm, OP_SUB,   Y, Y, N, Y, N, Y, Y),
+     SUBS_I -> List(I_ASImm, OP_SUB,   Y, Y, N, Y, N, Y, Y),
    )
...

In case a control field was added, don't forget same as in last example and add the field to decode_table and decode_default lists.

  1. Add op related constants
object DECODE_CONTROL_SIGNALS
{
  ...
  // ALU Operation Signals
  val OP_AND = DEC_LITS.OP_AND.U(OP_W)
  val OP_BIC = DEC_LITS.OP_BIC.U(OP_W)
  val OP_ORR = DEC_LITS.OP_ORR.U(OP_W)
  val OP_ORN = DEC_LITS.OP_ORN.U(OP_W)
  val OP_EOR = DEC_LITS.OP_EOR.U(OP_W)
  val OP_EON = DEC_LITS.OP_EON.U(OP_W)
+ val OP_ADD = DEC_LITS.OP_ADD.U(OP_W)
+ val OP_SUB = DEC_LITS.OP_SUB.U(OP_W)
  ...
}
  1. Update decoded instruction signals such as directing bit ranges to corresponding structures; in this case no extra field was added but lets add a egField for the sake of the tutorial.
// 31 | 30 | 29 | 28 27 26 25 24 | 23 22 | 21 20 19 18 17 16 15 14 13 12 11 10 | 09 08 07 06 05 | 04 03 02 01 00 | Instruction Page | Variant
//  1 |  0 |  0 |  1  0  0  0  1 |   -   |               imm12                 |      Rn        |        Rd      | ADD              | 64-bit
 

From the bitpatterns of the instruction, we can see that we have 3 fields : rd (4,0); rs1 (9,5); imm(21,10) and flag_set (ADD VS ADDS) (nzcv_en is extracted by the decode table).

class DInst exetends Bundle
{
  // Data
  val rd = REG_T
  val rs1 = REG_T
  ...
  // New Inst field
+ val egField = EG_T
+ val egField_en = Bool()
  ...
  def decode(inst : UInt, tag : UInt) = {
    val decoder = ListLookup(inst, decode_default, decode_table)

    // Data
    val itype = decoder.head
    rd    := MuxLookup(itype,   REG_X, Array( I_LogSR -> inst( 4, 0),
+                                             I_ASImm -> inst( 4, 0)))
    rs1   := MuxLookup(itype,   REG_X, Array( I_LogSR -> inst( 9, 5),
+                                             I_ASImm -> inst( 9, 5)))
    rs2   := MuxLookup(itype,   REG_X, Array( I_LogSR -> inst(20,16) ))
    imm   := MuxLookup(itype,   IMM_X, Array( I_LogSR -> inst(15,10),
                                              I_BImm  -> inst(25, 0),
                                              I_BCImm -> inst(23, 5),
+                                             I_ASImm -> inst(21,10)))
    shift := MuxLookup(itype, SHIFT_X, Array( I_LogSR -> inst(23,22) ))
+   egField := MuxLookup(itype, egField_X, Array( I_egInst -> inst(n1, n2) )

    // Control
    val cdecoder = decoder.tail
    //                                                              Extrafield ---v
+   val csignals = Seq(op, rd_en, rs1_en, rs2_en, imm_en, shift_en, cond_en, egField_en, inst_en)
    csignals zip cdecoder map { case (s, d) => s:= d }

    this.tag := tag
    this.itype := itype

    this
  }

At this stage we got our decoded instruction ready and it's time to write verification.