def decode_instruction(self, control, op): opcode = op[-7:] encodings, operands = self.get_encodings(op) self.precompute_base(op, operands) decoder = RiscDecoder(opcode) for code, encode_type, fct in self.get_op_mapping(): fct(control & decoder.get_control(code), *encodings[encode_type]) ### Specific parts ### rd = operands[0] # Shifts (c1, dec1), (c2, dec2) = self.left_shifts result = arith.left_shift(self.reg_rs1, mux(c1, dec2, dec1)) self.write_rd(c1 | c2, result) (c1, dec1, lead1), (c2, dec2, lead2) = self.right_shifts result = arith.right_shift(self.reg_rs1, mux(c1, dec2, dec1), False, mux(c1, lead2, lead1)) self.write_rd(c1 | c2, result) ## Write in rd control = self.all_rd_writes[0][0] val = self.all_rd_writes[0][1] for c, v in self.all_rd_writes[1:]: control = control | c val = mux(c, val, v) self.proc.registers.write_reg(control, rd, val)
def do_division(dividend, divisor, step): if step >= len(dividend): return (bit(size=0), dividend) quotient_up, dividend_up = do_division(dividend, divisor << 1, step + 1) # Don't overflow dividend = mux(divisor[1], dividend_up, dividend) quotient = mux(divisor[1], quotient_up, bit(0, size=len(quotient_up))) sub = hdl.simple_adder(dividend, hdl.negative_of_int(divisor))[0] return (mux(sub[0], quotient + '1', quotient + '0'), mux(sub[0], sub, dividend))
def left_shift(bits, shift, invert=False): shift = list(shift) k = -1 if invert else 1 while shift: bits = mux(shift.pop(), bits, bits << k) k *= 2 return bits
def comp(self, control, first, second, signed): self.signed.set(self.signed.get() | (control & signed)) if len(second) < self.word_size: second = mux(signed, hdl.extend(self.word_size, second), hdl.sign_extend(self.word_size, second)) self.add(control, first, second, True) return self.num_result[0]
def op_load(self, control, rd, width, rs1, offset): # Implements LW, LH, LHU, LB, LBU addr = self.alu.add(control, self.reg_rs1, hdl.sign_extend(self.word_size, offset))[0] result = self.proc.memory.read_at(control, addr) # First bit is 1 if unsigned r_16bits = mux(addr[-2], result[:16], result[16:]) r_16bits_ext = hdl.extend(self.word_size, r_16bits, (~width[0]) & r_16bits[0]) r_8bits = mux(addr[-1], r_16bits[:8], r_16bits[8:]) r_8bits_ext = hdl.extend(self.word_size, r_8bits, (~width[0]) & r_8bits[0]) result = mux(width[1], mux(width[2], r_8bits_ext, r_16bits_ext), result) # LW = 010, LH[U] = *01, LB[U] = *00 self.write_rd(control, result)
def op_branch(self, control, offset1, funct3, rs1_addr, rs2_addr, offset2): equality = ~hdl.merge_with_op(hdl.OrOp, self.reg_rs1 ^ self.reg_rs2) r1_m_r2 = self.alu.comp(control, self.reg_rs1, self.reg_rs2, ~funct3[1]) r = mux(funct3[0], equality, r1_m_r2[0]) r = r ^ funct3[2] # Invert if funct3[2] == 1 offset = hdl.sign_extend(self.word_size, offset1 + offset2) # Don't use the ALU 2 times jump_addr = self.proc.adder(self.proc.reg_pc, offset)[0] self.proc.reg_pc.add(control & r, jump_addr)
def write_at(self, control, addr, value): # Because it is 32bit-addressed value = arith.right_shift(value, addr[-5:]) addr = addr[:-5][-IO_SIGNIFICANT_BITS:] for i_out in range(len(self.outputs)): bit_eq = ~(addr ^ self.out_addresses[i_out]) is_eq = hdl.merge_with_op(hdl.AndOp, bit_eq) length = len(self.outputs[i_out]) self.outputs[i_out] = mux(is_eq & control, self.outputs[i_out], value[-length:])
def right_shift(bits, shift, invert=False, lead_bit=bit('0')): if invert: return left_shift(bits, shift) lead = lead_bit shift = list(shift) k = 1 while shift: bits = mux(shift.pop(), bits, lead + bits[:-k]) k *= 2 lead = lead + lead return bits
def op_m_ext(self, control, rd, funct3, rs1, rs2): if self.proc.MUL_ENABLED: # '000' -> mul # '011' -> mulhu # '001' -> mulh # '010' -> mulhsu mul_control = (~funct3[0]) & control hight_control = funct3[1] | funct3[2] sign1 = self.reg_rs1[0] & (funct3[1] ^ funct3[2]) sign2 = self.reg_rs2[0] & (~funct3[1]) num1 = hdl.extend(64, self.reg_rs1, sign1) num2 = hdl.extend(64, self.reg_rs2, sign2) m_ext_mul = hdl.simple_product(num1, num2) self.write_rd(mul_control & hight_control, m_ext_mul[:32]) self.write_rd(mul_control & (~hight_control), m_ext_mul[-32:]) if self.proc.DIV_ENABLED: # 100 -> div # 110 -> rem # 101 -> divu # 111 -> remu div_control = funct3[0] & control rem_control = funct3[1] is_signed = ~funct3[2] sign1 = is_signed & self.reg_rs1[0] sign2 = is_signed & self.reg_rs2[0] num1 = mux(sign1, self.reg_rs1, hdl.negative_of_int(self.reg_rs1)) num2 = mux(sign2, self.reg_rs2, hdl.negative_of_int(self.reg_rs2)) quotient, remainder = arith.simple_divide(num1, num2) quotient = mux(sign1 ^ sign2, quotient, hdl.negative_of_int(quotient)) remainder = mux(sign1, remainder, hdl.negative_of_int(remainder)) self.write_rd(div_control & rem_control, remainder) self.write_rd(div_control & (~rem_control), quotient)
def read_at(self, control: 'bit', addr: 32, memory_only=False): dest, addr = addr[:3], addr[3:][:-2] + bit('00000') self.used = self.used | (control & (~(dest[0] | dest[1]))) # RAM and ROM -> 00x output = bit(0, size=32) for dest_id, dest_obj, is_memory in self.sources: if not memory_only or is_memory: isdest = ~(bit(dest) ^ dest_id) isdest = isdest[0] & isdest[1] & isdest[2] dest_out = dest_obj.read_at(control & isdest, addr) if dest_out is not None: output = mux(isdest, output, dest_out) return output
def __init__(self, size, adder_function): self.input1 = MultiControl() self.input2 = MultiControl() self.inv = virtual(1, bit(0)) self.signed = virtual(1, bit(0)) self.word_size = size operand1 = virtual(size, self.input1) operand1 = mux( self.signed, hdl.extend(size + 1, operand1), hdl.sign_extend(size + 1, operand1), ) operand2 = virtual(size, self.input2) operand2 = mux( self.signed, hdl.extend(size + 1, operand2), hdl.sign_extend(size + 1, operand2), ) operand2 = mux(self.inv, operand2, hdl.negative_of_int(operand2)) self.num_result, self.carry = adder_function(operand1, operand2) self.result = self.num_result[1:], self.num_result[0]
def simple_divide(dividend: 'l', divisor: 'l') -> (Bit, Bit): """ Returns (quotient, remainder) """ sign = dividend[0] ^ divisor[0] dividend = '0' + mux(dividend[0], dividend, hdl.negative_of_int(dividend)) divisor = '0' + mux(divisor[0], divisor, hdl.negative_of_int(divisor)) def do_division(dividend, divisor, step): if step >= len(dividend): return (bit(size=0), dividend) quotient_up, dividend_up = do_division(dividend, divisor << 1, step + 1) # Don't overflow dividend = mux(divisor[1], dividend_up, dividend) quotient = mux(divisor[1], quotient_up, bit(0, size=len(quotient_up))) sub = hdl.simple_adder(dividend, hdl.negative_of_int(divisor))[0] return (mux(sub[0], quotient + '1', quotient + '0'), mux(sub[0], sub, dividend)) quotient, remain = do_division(dividend, divisor, 0) remain = remain[1:] remain = mux(sign, remain, hdl.negative_of_int(remain)) return quotient[1:], remain
def write_reg(self, control: 'bit', addr: 'bus', val: 'bus'): if len(addr) != self.reg_addr_size: raise hdl.BuildError( f"The size of the register address must be {self.reg_addr_size}, not {len(addr)}" ) if len(val) != self.word_size: raise hdl.BuildError( f"The size of the register value must be {self.word_size}, not {len(val)}" ) reg_controls = SimpleDecoder(addr) for i_reg, register in enumerate(self.registers): if i_reg: register.source( mux(control & reg_controls.get_control(i_reg), register, val))
def op_store(self, control, offset1, width, rs1_dest, rs2_src, offset2): # Implements SW, SH, SB addr = self.alu.add(control, self.reg_rs1, hdl.sign_extend(self.word_size, offset1 + offset2))[0] data_32 = self.reg_rs2 # SW : 010 # Do not overwrite previous data prev = self.proc.memory.read_at(control & (~width[1]), addr) p1 = mux((~addr[-1]) & (~addr[-2]), prev[0:8], data_32[24:]) p2 = mux(addr[-1] & (~addr[-2]), prev[8:16], data_32[24:]) p3 = mux((~addr[-1]) & addr[-2], prev[16:24], data_32[24:]) p4 = mux(addr[-1] & addr[-2], prev[24:], data_32[24:]) # SH : 001 # SB : 000 data_16 = mux(addr[-2], data_32[16:] + prev[16:], prev[0:16] + data_32[16:]) data_8 = p1 + p2 + p3 + p4 data = mux(width[1], mux(width[2], data_8, data_16), data_32) self.proc.memory.write_at(control, addr, data)