def bench(): opcode = Signal(alu_opcode_t.alu_add) operand_0 = Signal(data_bus(0)) operand_1 = Signal(data_bus(0)) result = Signal(data_bus(0)) alu = ALU(opcode, operand_0, operand_1, result) @instance def stimulus(): for i in range(100): for operator, compute_result in ( (alu_opcode_t.alu_add, lambda a, b: a + b), (alu_opcode_t.alu_sub, lambda a, b: a - b), ): a = random.randrange(-2 ** 30, 2 ** 30) b = random.randrange(-2 ** 30, 2 ** 30) expect = compute_result(a, b) opcode.next = operator operand_0.next = data_bus(a) operand_1.next = data_bus(b) yield delay(10) assert result.signed() == expect return alu, stimulus
def bench(number_of_registers = 32, ram_from_file = False): def ClockDriver(clock, period = 100): @always(delay(period / 2)) def drive_clock(): clock.next = not clock return drive_clock clock = Signal(False) clock_driver = ClockDriver(clock) abus = Signal(data_bus(0)) dbus = Signal(data_bus(0)) data_in = Signal(data_bus(0)) write_enabled = Signal(False) ram = Ram( clock, dbus, data_in, abus, write_enabled, from_file = ram_from_file, ) processor = Processor(clock, dbus, abus) return clock_driver, ram, processor
def logic(): opcode.next = opcode_t.add operand_0.next = data_bus(1) operand_1.next = data_bus(1) update_select_a.next = 0 update_value_a.next = 0 update_select_b.next = 0 update_value_b.next = 0 write_enabled.next = False select_a.next = 0 select_b.next = 0
def bench(number_of_registers = 32): update_select_a = Signal(intbv(min = 0, max = number_of_registers)) update_value_a = Signal(data_bus(0)) update_select_b = Signal(intbv(min = 0, max = number_of_registers)) update_value_b = Signal(data_bus(0)) write_enabled = Signal(False) select_a = Signal(intbv(min = 0, max = number_of_registers)) result_a = Signal(data_bus(0)) select_b = Signal(intbv(min = 0, max = number_of_registers)) result_b = Signal(data_bus(0)) clock = Signal(False) register_bank = RegisterBank( update_select_a, update_value_a, update_select_b, update_value_b, write_enabled, select_a, result_a, select_b, result_b, clock, number_of_registers, ) @instance def stimulus(): for i in range(number_of_registers): for v in range(100): update_select_a.next = i update_value_a.next = v update_select_b.next = i update_value_b.next = v write_enabled.next = True clock.next = True yield delay(10) clock.next = False yield delay(10) write_enabled.next = False select_a.next = i select_b.next = i clock.next = True yield delay(10) clock.next = False yield delay(10) assert result.signed() == v return register_bank, stimulus
def stimulus(): for i in range(100): for operator, compute_result in ( (alu_opcode_t.alu_add, lambda a, b: a + b), (alu_opcode_t.alu_sub, lambda a, b: a - b), ): a = random.randrange(-2 ** 30, 2 ** 30) b = random.randrange(-2 ** 30, 2 ** 30) expect = compute_result(a, b) opcode.next = operator operand_0.next = data_bus(a) operand_1.next = data_bus(b) yield delay(10) assert result.signed() == expect
def bench(number_of_ram=128): address = Signal(intbv(min = 0, max = number_of_ram)) data_in = Signal(data_bus(0)) data_out = Signal(data_bus(0)) write_enabled = Signal(False) clock = Signal(False) ram = Ram( clock, data_out, data_in, address, write_enabled, number_of_ram, ) @instance def stimulus(): for i in range(number_of_ram): for v in range(100): write_enabled.next = True address.next = i data_in.next = v clock.next = True yield delay(10) clock.next = False yield delay(10) write_enabled.next = False address.next = i clock.next = True yield delay(10) clock.next = False yield delay(10) result = data_out.next assert result.signed() == v return ram, stimulus
def Processor(clock, dbus, abus): number_of_registers = 32 alu_opcode = Signal(alu_opcode_t.alu_add) operand_0 = Signal(data_bus(0)) operand_1 = Signal(data_bus(0)) result = Signal(data_bus(0)) alu = ALU(alu_opcode, operand_0, operand_1, result) update_select_a = Signal(intbv(min = 0, max = number_of_registers)) update_value_a = Signal(data_bus(0)) update_select_b = Signal(intbv(min = 0, max = number_of_registers)) update_value_b = Signal(data_bus(0)) write_enabled = Signal(False) select_a = Signal(intbv(min = 0, max = number_of_registers)) value_a = Signal(data_bus(0)) select_b = Signal(intbv(min = 0, max = number_of_registers)) value_b = Signal(data_bus(0)) register_bank = RegisterBank( update_select_a, update_value_a, update_select_b, update_value_b, write_enabled, select_a, value_a, select_b, value_b, clock, ) opcode = Signal(data_bus(0)) control_unit = ControlUnit( clock, opcode, alu_opcode, operand_0, operand_1, result, update_select_a, update_value_a, update_select_b, update_value_b, write_enabled, select_a, value_a, select_b, value_b, dbus, abus, ) return alu, register_bank, control_unit
def RegisterBank( update_select_a, update_value_a, update_select_b, update_value_b, write_enabled, select_a, value_a, select_b, value_b, clock, number_of_registers = 32): ''' Comment ''' registers = [Signal(data_bus(0)) for i in range(number_of_registers)] @always_comb def read_logic(): ''' Handles reads to the register bank. ''' if select_a == ZERO_REGISTER: value_a.next = 0 else: value_a.next = registers[select_a] if select_b == ZERO_REGISTER: value_b.next = 0 else: value_b.next = registers[select_b] @always(clock.posedge) def logic(): ''' Updates the values stored in the register bank. ''' if write_enabled: if update_select_a != ZERO_REGISTER: registers[update_select_a].next = update_value_a if update_select_b != ZERO_REGISTER: registers[update_select_b].next = update_value_b return logic, read_logic
def Processor(clock): number_of_registers = 32 opcode = Signal(opcode_t.add) operand_0 = Signal(data_bus(0)) operand_1 = Signal(data_bus(0)) result = Signal(data_bus(0)) alu = ALU(opcode, operand_0, operand_1, result) update_select_a = Signal(intbv(min = 0, max = number_of_registers)) update_value_a = Signal(data_bus(0)) update_select_b = Signal(intbv(min = 0, max = number_of_registers)) update_value_b = Signal(data_bus(0)) write_enabled = Signal(False) select_a = Signal(intbv(min = 0, max = number_of_registers)) value_a = Signal(data_bus(0)) select_b = Signal(intbv(min = 0, max = number_of_registers)) value_b = Signal(data_bus(0)) register_bank = RegisterBank( update_select_a, update_value_a, update_select_b, update_value_b, write_enabled, select_a, value_a, select_b, value_b, clock, ) @always(clock.posedge) def logic(): opcode.next = opcode_t.add operand_0.next = data_bus(1) operand_1.next = data_bus(1) update_select_a.next = 0 update_value_a.next = 0 update_select_b.next = 0 update_value_b.next = 0 write_enabled.next = False select_a.next = 0 select_b.next = 0 return alu, register_bank, logic
def RegisterBank( update_select_a, update_value_a, update_select_b, update_value_b, write_enabled, select_a, value_a, select_b, value_b, clock, number_of_registers = 32): ''' Comment ''' registers = [Signal(data_bus(0)) for i in range(number_of_registers)] @always_comb def read_logic(): value_a.next = registers[select_a] value_b.next = registers[select_b] @always_comb def read_logic(): value_a.next = registers[select_a] value_b.next = registers[select_b] @always(clock.posedge) def logic(): ''' Updates the values stored in the register bank. Also handles reads. ''' if write_enabled: registers[update_select_a] = update_value_a registers[update_select_b] = update_value_b return logic, read_logic
assert result.signed() == v return ram, stimulus def test_bench(): sim = Simulation(traceSignals(bench)) sim.run() if __name__ == '__main__': from myhdl import toVHDL number_of_ram=128 addressess = Signal(intbv(min = 0, max = number_of_ram)) data_in = Signal(data_bus(0)) data_out = Signal(data_bus(0)) write_enabled = Signal(False) clock = Signal(False) toVHDL( Ram, data_in, data_out, addressess, write_enabled, clock, number_of_ram, )
write_enabled, from_file = ram_from_file, ) processor = Processor(clock, dbus, abus) return clock_driver, ram, processor def test_bench(ram_from_file): sim = Simulation(traceSignals(bench, ram_from_file = ram_from_file)) sim.run() if __name__ == '__main__': import sys if sys.argv[1] == 'convert': from myhdl import toVHDL clock = Signal(False) abus = Signal(data_bus(0)) dbus = Signal(data_bus(0)) toVHDL( Processor, clock, dbus, abus, ) else: test_bench(open(sys.argv[1]))
assert result.signed() == v return register_bank, stimulus def test_bench(): sim = Simulation(traceSignals(bench)) sim.run() if __name__ == '__main__': from myhdl import toVHDL number_of_registers = 32 update_select_a = Signal(intbv(min = 0, max = number_of_registers)) update_value_a = Signal(data_bus(0)) update_select_b = Signal(intbv(min = 0, max = number_of_registers)) update_value_b = Signal(data_bus(0)) write_enabled = Signal(False) select_a = Signal(intbv(min = 0, max = number_of_registers)) result_a = Signal(data_bus(0)) select_b = Signal(intbv(min = 0, max = number_of_registers)) result_b = Signal(data_bus(0)) clock = Signal(False) toVHDL( RegisterBank, update_select_a, update_value_a, update_select_b, update_value_b,
(alu_opcode_t.alu_add, lambda a, b: a + b), (alu_opcode_t.alu_sub, lambda a, b: a - b), ): a = random.randrange(-2 ** 30, 2 ** 30) b = random.randrange(-2 ** 30, 2 ** 30) expect = compute_result(a, b) opcode.next = operator operand_0.next = data_bus(a) operand_1.next = data_bus(b) yield delay(10) assert result.signed() == expect return alu, stimulus def test_bench(): sim = Simulation(traceSignals(bench)) sim.run() if __name__ == '__main__': from myhdl import toVHDL opcode = Signal(alu_opcode_t.alu_add) operand_0 = Signal(data_bus(0)) operand_1 = Signal(data_bus(0)) result = Signal(data_bus(0)) toVHDL(ALU, opcode, operand_0, operand_1, result)
def ControlUnit( clock, instruction, alu_opcode, operand_0, operand_1, result, update_select_a, update_value_a, update_select_b, update_value_b, write_enabled, select_a, value_a, select_b, value_b, dbus, abus, ): ''' Pipeline stages: 0 - decode instruction 1 - load operands 2 - compute 3 - store result ''' # todo: find a more appropriate name for this variable depth = 4 p_opcode = [Signal(opcode_t.op_nop) for i in range(depth)] p_conditional = [Signal(conditional_t.al) for i in range(depth)] p_alu_opcode = [Signal(alu_opcode_t.alu_sub) for i in range(depth)] p_is_alu_opcode = [Signal(False) for i in range(depth)] p_modify_status = [Signal(False) for i in range(depth)] p_argument_0 = [Signal(intbv()[5:]) for i in range(depth)] p_argument_1 = [Signal(intbv()[19:]) for i in range(depth)] p_argument_2 = [Signal(intbv()[5:]) for i in range(depth)] p_argument_3 = [Signal(intbv()[9:]) for i in range(depth)] p_result = [Signal(data_bus(0)) for i in range(depth)] p_is_valid = [Signal(True) for i in range(depth)] d_instruction = Signal(data_bus(0)) d_opcode = Signal(opcode_t.op_nop) d_conditional = Signal(conditional_t.al) d_modify_status = Signal(False) d_is_alu_opcode = Signal(False) d_alu_opcode = Signal(alu_opcode_t.alu_add) d_argument_0 = Signal(intbv()[5:]) d_argument_1 = Signal(intbv()[19:]) d_argument_2 = Signal(intbv()[5:]) d_argument_3 = Signal(intbv()[9:]) instruction_register = Signal(intbv()[32:]) instruction_decoder = InstructionDecoder( d_instruction, d_opcode, d_conditional, d_modify_status, d_is_alu_opcode, d_alu_opcode, d_argument_0, d_argument_1, d_argument_2, d_argument_3) @always(clock.posedge) def logic(): ''' push pipeline register values ''' for i in range(depth - 1): p_opcode[i + 1].next = p_opcode[i] p_alu_opcode[i + 1].next = p_alu_opcode[i] p_is_alu_opcode[i + 1].next = p_is_alu_opcode[i] p_modify_status[i + 1].next = p_modify_status[i] p_argument_0[i + 1].next = p_argument_0[i] p_argument_1[i + 1].next = p_argument_1[i] p_argument_2[i + 1].next = p_argument_2[i] p_argument_3[i + 1].next = p_argument_3[i] p_result[i + 1].next = p_result[i] p_is_valid[i + 1].next = p_is_valid[i] ''' increment instruction register ''' instruction_register.next = instruction_register + 1 ''' 0th stage - fetch instruction ''' abus.next = instruction_register ''' 1st stage - decode instruction ''' d_instruction.next = dbus ''' 2nd stage - load operands ''' # note the index is 1 b/c of signal semantics! ''' - remember decoding result ''' p_opcode[1].next = d_opcode p_alu_opcode[1].next = d_alu_opcode p_is_alu_opcode[1].next = d_is_alu_opcode p_modify_status[1].next = d_modify_status p_argument_0[1].next = d_argument_0 p_argument_1[1].next = d_argument_1 p_argument_2[1].next = d_argument_2 p_argument_3[1].next = d_argument_3 ''' - load operands ''' select_a.next = d_argument_0 select_b.next = d_argument_1 ''' 3rd stage - execute ''' alu_opcode.next = p_alu_opcode[2] operand_0.next = value_a operand_1.next = value_b p_result[3].next = result ''' - handle branches ''' if p_opcode[2] == opcode_t.op_br: for i in range(1, 3): p_is_valid[i].next = False # todo: this is a quick and dirty absolute jump instruction_register.next = p_argument_0[2] ''' 4th stage - store result ''' write_enabled.next = False if not p_is_valid[3]: return if p_is_alu_opcode[3]: update_select_a.next = p_argument_2[3] update_value_a.next = p_result[3] write_enabled.next = True elif p_opcode[3] == opcode_t.op_li: update_select_a.next = p_argument_0[3] update_value_a.next = p_argument_1[3] write_enabled.next = True return instruction_decoder, logic