Skip to content

Introduction: Syntax

Julian Oppermann edited this page Oct 25, 2021 · 13 revisions

The code below shows the CoreDSL2 description of a simple core implementing a subset of the RISC-V base ISA, shortened here for the purpose of highlighting the basic concepts used in the language.

The top-level entity, modelling a processor core, is the Core. It is split into several, optional sections. In this example, only the architectural_state (definition of implementation parameters, declarations of registers and address spaces) and instructions (definitions of instruction encoding and behavior) sections are used. Core definitions may also contain a functions section that encapsulates utility or blackbox functionality (not shown here).

In general, the syntax follows the conventions of the C/C++ language family. The manipulation of non-byte-sized data is common in the specification of instruction semantics, hence, we support arbitrary-precision integer types (with an explicit width specification in bits, e.g. unsigned<XLEN>), bit literals (3'b010), and bit-level operators such as bit ranges ([4:0]) and concatenation (::). We borrow C++'s attribute notation to augment declarations and instructions with additional information, e.g. marking a register as the core's program counter with the attribute [[is_pc]].

Core My32bitRISCVCore {
  architectural_state {
             unsigned int    REG_LEN = 32;  // implementation parameter
             unsigned int    XLEN = 32;     // implementation parameter
    register unsigned<XLEN>  X[REG_LEN];    // register file
    register unsigned<XLEN>  PC [[is_pc]];  // single register with attribute
             unsigned<XLEN>& ZERO = X[0];   // register alias
    extern   unsigned<8>     MEM[1<<XLEN];  // address space declaration
  }

  instructions {
    LUI {
      encoding: imm[31:12] :: rd[4:0] :: 7'b0110111;
      behavior: if (rd != 0) X[rd] = imm;
    }
    JAL [[no_cont]] {
      encoding: imm[20:20] :: imm[10:1] :: imm[11:11] :: imm[19:12] :: rd[4:0] :: 7'b1101111;
      behavior: {
        if (rd != 0)
          X[rd] = (unsigned<XLEN>) (PC + 4);
        PC += (signed) imm;
      }
    }
    LW {
      encoding: imm[11:0] :: rs1[4:0] :: 3'b010 :: rd[4:0] :: 7'b0000011;
      behavior: if (rd != 0) {
        unsigned<XLEN> base = (unsigned<XLEN>) (X[rs1] + (signed) imm);
        X[rd] = MEM[base] :: MEM[base + 1] :: MEM[base + 2] :: MEM[base + 3];
      }
    }
    XOR {
      encoding: 7'b0000000 :: rs2[4:0] :: rs1[4:0] :: 3'b100 :: rd[4:0] :: 7'b0110011;
      behavior: if (rd != 0) X[rd] = X[rs1] ^ X[rs2];
    }
    // ... many more instructions, omitted for brevity
  }
}
Clone this wiki locally