def get_imm_SB(imm10, lineno): try: imm10 = int(imm10) except: msg = "Invalid immediate specified." return False, imm10, msg ''' The SB type encodes instructions BEQ, BNE, BLT, BLTU, BGE, BGEU. The 12 bit immediate is encodes a signed offset in multiples of two. Hence the last bit will be 0 and we ignore this in the encoding effectively allowing encoding up to 13 bits. ''' # 13 bit encoding IMM_MAX = 0b0111111111110 IMM_MIN = -0b1000000000000 if (imm10 > IMM_MAX) or (imm10 < IMM_MIN): cp.cprint_warn("Warning:" + str(lineno) + ":" + "Immediate is too big, will overflow.") # Convert to 2's complement binary imm2 = format(imm10 if imm10 >= 0 else (1 << 13) + imm10, '013b') if imm2[-1] != '0': cp.cprint_warn("Warning:" + str(lineno) + ":" + "Immediate not 2 bytes aligned. Last bit will" + "be dropped.") imm2 = imm2[0:12] # Convert immediate back to base 10 from base 2 # p[0] = int(imm2, 2) assert (len(imm2) == 12) imm_12_10_5 = imm2[-12] + imm2[-10:-4] imm_4_1_11 = imm2[-4:] + imm2[-11] assert (len(imm_12_10_5) + len(imm_4_1_11) == 12) return True, (imm_12_10_5, imm_4_1_11), None
def get_imm_U(imm10, lineno): try: imm10 = int(imm10) except: msg = "Invalid immediate specified." return False, imm10, msg ''' The U type immediate occurs in LUI and AUIPC instructions. From the point of a compiler/assembler, there is nothing in particular that has to be checked about this immediate except that it fits into the 20 bit width. ''' IMM_MAX = 0b01111111111111111111 IMM_MIN = -0b10000000000000000000 if (imm10 > IMM_MAX) or (imm10 < IMM_MIN): cp.cprint_warn("Warning:" + str(p.lineno(1)) + ":" + "Immediate is too big, will overflow.") # Conver to 2's complement binary imm2 = format(imm10 if imm10 >= 0 else (1 << 20) + imm10, '020b') imm2 = imm2[-20:] # Convert immediate back to base 10 from base 2 # p[0] = int(imm2, 2) assert (len(imm2) == 20) return True, imm2, None
def op_arithi(self, tokens): ''' imm[11:0] rs1 funct3 rd opcode The immediate for SLLI and SRLI needs to have the upper 7 bets set to 0 and for SRAI, it needs to be set to 0100000 ''' opcode = tokens['opcode'] bin_opcode = None funct3 = None rs1 = None bin_rs1 = None bin_rd = None rd = None imm = None try: funct3 = self.CONST.FUNCT3_ARITHI[opcode] bin_opcode = self.CONST.BOP_ARITHI rs1 = tokens['rs1'] bin_rs1 = self.get_bin_register(rs1) rd = tokens['rd'] bin_rd = self.get_bin_register(rd) imm = tokens['imm'] except: cp.cprint_fail("Internal Error: ARITHI: could not parse" + "tokens in " + str(tokens['lineno'])) exit() bin_str = imm + bin_rs1 + funct3 + bin_rd + bin_opcode assert (len(bin_str) == 32) if opcode in (self.CONST.INSTR_SLLI, self.CONST.INSTR_SRLI): if imm[0:7] != '0000000': cp.cprint_warn("Warning:" + str(tokens['lineno']) + ": Upper 7 bits of immediate should be 0") if opcode in (self.CONST.INSTR_SRAI): if imm[0:7] != '0100000': cp.cprint_warn("Warning:" + str(tokens['lineno']) + ": Upper 7 bits of immediate should be " + "01000000") tok_dict = { 'opcode': bin_opcode, 'funct3': funct3, 'rs1': bin_rs1, 'rd': bin_rd, 'imm': imm } return bin_str, tok_dict
def get_imm_UJ(imm10, lineno): try: imm10 = int(imm10) except: msg = "Invalid immediate specified." return False, imm10, msg ''' The UJ Type immediate encodes a 2 byte aligned address. Hence its last bit has to be zero. We do not encode this last bit in the instruction and the CPU assumes the last bit to be zero. The immediate is reshuffled and looks like the following. imm[20] imm[10:1] imm[11] imm[19:12] Note that imm[0] is not encoded. From the parsers point of view, we accept an (21 bit) immediate check if its a multiple of 2 (report and error) and then shuffle it as required ''' # Effectively we are addressing 21 bits IMM_MAX = 0b011111111111111111110 IMM_MIN = -0b100000000000000000000 if (imm10 > IMM_MAX) or (imm10 < IMM_MIN): cp.cprint_warn("Warning:" + str(lineno) + ":" + "Immediate is too big, will overflow.") # Conver to 2's complement binary imm2 = format(imm10 if imm10 >= 0 else (1 << 21) + imm10, '021b') if imm2[-1:] != '0': cp.cprint_warn("Warning:" + str(lineno) + ":" + "Immediate not 2 bytes aligned. Last bit will" + "be dropped.") imm2 = imm2[0:-1] assert (len(imm2) == 20) # Shuffling the immediate # imm[20] imm[10:1] imm[11] imm[19:12] # Indexing in reverse order # imm[20] in is imm2[0] = imm2[-20] of imm string shf_imm = imm2[0] + imm2[10:20] + imm2[9] + imm2[1:9] assert (len(shf_imm) == 20) return True, shf_imm, None
def get_imm_I(imm10, lineno): try: imm10 = int(imm10) except: msg = "Invalid immediate specified." return False, imm10, msg ''' The I type immediates occur in all immediate arithmetic and logic operations, JALR, LW, LB, LH, LBU and LHU In the arithmetic/logic instructions, SLTUI is the only unsigned operation. Even in SLTUI, the immediate is sign extended first before an unsigned comparison is made hence for our purposes, the immediate is a signed 12 bit binary number. For JALR, the 12 bit immediate is sign extended and the CPU sets the lowest bit to 0 on its own before jumping. If a misaligned address is provided, it is the CPU's job to generate exceptions. Hence we check again for a 12 bit signed immediate. For LW, LB, LH, LBU and LHU, the address is a signed 12 bit number. Since the ISA allows misaligned loads, we need not check for alignment. Again, the CPU generates a misaligned instruction exception if required. Since I am generating a assembler for a 32 bit architecture, a warning is generated for misaligned loads in the binary generation phase. ''' IMM_MAX = 0b011111111111 IMM_MIN = -0b100000000000 if (imm10 > IMM_MAX) or (imm10 < IMM_MIN): cp.cprint_warn("Warning:" + str(lineno) + ":" + "Immediate is too big, will overflow.") # Conver to 2's complement binary imm2 = format(imm10 if imm10 >= 0 else (1 << 12) + imm10, '012b') imm2 = imm2[-12:] # Convert immediate back to base 10 from base 2 # p[0] = int(imm2, 2) assert (len(imm2) == 12) return True, imm2, p_statement_none
def get_imm_S(imm10, lineno): try: imm10 = int(imm10) except: msg = "Invalid immediate specified." return False, imm10, msg ''' The S type encodes instructions SW, SB and SH. Similar to loads, SW, SB and SH the address offset is a signed 12 bit number. Since the ISA allows misaligned stores, we need not check for alignment. Again, the CPU generates a misaligned instruction exception if required. Since I am generating a assembler for a 32 bit architecture, a warning is generated for misaligned stores in the binary generation phase. Also, in S type, the immediate is split into two parts - one part holding bits [11:5] in the immediate ordering(MSB-LSB from left to right) and the other part holding bits [4:0]. We split the immediate into two portions hence. ''' IMM_MAX = 0b011111111111 IMM_MIN = -0b100000000000 if (imm10 > IMM_MAX) or (imm10 < IMM_MIN): cp.cprint_warn("Warning:" + str(lineno) + ":" + " Immediate is too big, will overflow.") # Convert to 2's complement binary imm2 = format(imm10 if imm10 >= 0 else (1 << 12) + imm10, '012b') if imm2[-1] != 0: cp.cprint_warn("Warning:" + str(lineno) + ":" + "Immediate not 2 bytes aligned. Last bit will" + "be dropped.") imm2 = imm2[0:12] # Convert immediate back to base 10 from base 2 # p[0] = int(imm2, 2) assert (len(imm2) == 12) imm_11_5 = imm2[:7] imm_4_0 = imm2[7:] assert (len(imm_11_5) + len(imm_4_0) == 12) return True, (imm_11_5, imm_4_0), p_statement_none