def test_hdd_write_sector_0(self, cpu): value_1 = dec_to_bin(234) value_2 = dec_to_bin(52) hdd_address_1 = ZEROS hdd_address_2 = INT_ONE instructions = [move_opcode + a_address + constant_address, hdd_address_1, hdd_opcode + hdd_write + a_address + constant_address, value_1, move_opcode + a_address + constant_address, hdd_address_2, hdd_opcode + hdd_write + a_address + constant_address, value_2 ] self.load_instructions(cpu.ram, instructions) cpu() cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.hdd.data[:16] == value_1 cpu() cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.hdd.data[:16] == value_1 assert cpu.hdd.data[16:32] == value_2
def test_push_constant_then_pop_to_memory(self, cpu, stack_frame_dec): stack_frame = dec_to_bin(stack_frame_dec) value_1 = INT_ONE memory_address = dec_to_bin(10) instructions = [move_opcode + sp_address + constant_address, stack_frame, move_opcode + a_address + constant_address, memory_address, push_opcode + spp_address + constant_address, value_1, pop_opcode + ap_address + spp_address] self.load_instructions(cpu.ram, instructions) cpu() cpu.tick() cpu() cpu.tick() assert cpu() == 0 cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.sp.value == stack_frame assert cpu.ram_bus(UNUSED, memory_address, 0) == value_1
def test_hdd_write_sector_1(self, cpu): value_1 = dec_to_bin(453) value_2 = dec_to_bin(531) hdd_address_1 = ZEROS hdd_address_2 = INT_ONE instructions = [hdd_opcode + hdd_set_sector + unused_opcode + constant_address, INT_ONE, move_opcode + a_address + constant_address, hdd_address_1, hdd_opcode + hdd_write + a_address + constant_address, value_1, move_opcode + a_address + constant_address, hdd_address_2, hdd_opcode + hdd_write + a_address + constant_address, value_2 ] self.load_instructions(cpu.ram, instructions) assert cpu() == 0 cpu.tick() cpu() cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.hdd.data[512:512+16] == value_1 cpu() cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.hdd.data[512:512+16] == value_1 assert cpu.hdd.data[512+16:512+32] == value_2
def test_push_constant_twice(self, cpu, stack_frame_dec): stack_frame = dec_to_bin(stack_frame_dec) stack_frame_p1 = dec_to_bin(stack_frame_dec - 1) stack_frame_p2 = dec_to_bin(stack_frame_dec - 2) value_1 = INT_ONE value_2 = INT_TWO instructions = [move_opcode + sp_address + constant_address, stack_frame, push_opcode + spp_address + constant_address, value_1, push_opcode + spp_address + constant_address, value_2] self.load_instructions(cpu.ram, instructions) assert cpu() == 0 cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.sp.value == stack_frame_p1 assert cpu.ram_bus(UNUSED, stack_frame, 0) == value_1 assert cpu() == 0 cpu.tick() assert cpu.sp.value == stack_frame_p2 assert cpu.ram_bus(UNUSED, stack_frame, 0) == value_1 assert cpu.ram_bus(UNUSED, stack_frame_p1, 0) == value_2
def test_push_twice_then_pop_twice(self, cpu, stack_frame_dec): stack_frame = dec_to_bin(stack_frame_dec) stack_frame_p1 = dec_to_bin(stack_frame_dec - 1) value_1 = INT_ONE value_2 = INT_TWO instructions = [move_opcode + sp_address + constant_address, stack_frame, push_opcode + spp_address + constant_address, value_1, push_opcode + spp_address + constant_address, value_2, pop_opcode + a_address + spp_address, pop_opcode + b_address + spp_address] self.load_instructions(cpu.ram, instructions) assert cpu() == 0 cpu.tick() assert cpu() == 0 cpu.tick() assert cpu() == 0 cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.sp.value == stack_frame_p1 assert cpu.a.value == value_2 assert cpu() == 0 cpu.tick() assert cpu.sp.value == stack_frame assert cpu.b.value == value_1
def test_empty_program(self): instructions = [] labels = {} variables = {} linked = link(instructions, labels, variables) assert linked == [dec_to_bin(2), dec_to_bin(0)]
def parse_address(self): if not self.tokens: raise ParserError('Expected an address. Got end of file.') token = self.get_next_token() value = None is_pointer = False if token.type == Delimiter.LeftBracket: is_pointer = True token = self.get_next_token() if token.type in [Label.Name, Literal.Int]: address = constantp_address if is_pointer else constant_address if token.type == Label.Name: if token.value in self.built_ins: value = dec_to_bin(self.built_ins[token.value]) else: value = token if token.type == Literal.Int: if type(token.value) != int: raise ParserError( f"Expected literal int value.\nGot '{token.value}'") value = dec_to_bin(token.value) elif token.type in registers: _registers = pointer_registers if is_pointer else registers address = _registers[token.type] else: raise ParserError( f"Got unexpected token on line {token.line} while parsing address.\n" f"Expected: 'constant', 'register' or '['.\n" f"Got: '{token.value}'.") if is_pointer: self.eat_token(Delimiter.RightBracket) return address, value
def test_no_labels_as_boot(self): instructions = [move_opcode+a_address+constant_address, dec_to_bin(1)] labels = {} variables = {} linked = link(instructions, labels, variables, mode='boot') assert linked == [move_opcode+a_address+constant_address, dec_to_bin(1)]
def test_no_labels(self): instructions = [move_opcode+a_address+constant_address, dec_to_bin(1)] labels = {} variables = {} linked = link(instructions, labels, variables) assert linked == [dec_to_bin(4), dec_to_bin(0), move_opcode+a_address+constant_address, dec_to_bin(1)]
def test_one_label_as_boot(self): instructions = [move_opcode + a_address + constant_address, dec_to_bin(1), jump_opcode + unused_opcode + constant_address, Token(Label.Name, 'start', 4)] labels = {'start': 0} variables = {} linked = link(instructions, labels, variables, mode='boot') assert linked == [move_opcode + a_address + constant_address, dec_to_bin(1), jump_opcode + unused_opcode + constant_address, dec_to_bin(0)]
def test_double_alloc_size_2_as_boot(self): instructions = [move_opcode+constantp_address+a_address, Token(Label.Name, 'var_1', 1), move_opcode + constantp_address + b_address, Token(Label.Name, 'var_2', 2) ] labels = {} variables = {'var_1': 2, 'var_2': 2} linked = link(instructions, labels, variables, mode='boot') assert linked == [move_opcode+constantp_address+a_address, dec_to_bin(4), move_opcode + constantp_address + b_address, dec_to_bin(6)]
def test_multiple_calls(self): instructions = [jump_opcode + unused_opcode + constant_address, Token(Label.Name, 'end', 1), move_opcode + a_address + constant_address, dec_to_bin(1), jump_opcode + unused_opcode + constant_address, Token(Label.Name, 'end', 2), ] labels = {'end': 4} variables = {} linked = link(instructions, labels, variables) assert linked == [dec_to_bin(17), # Program length dec_to_bin(0), # ALlocated space # Loader pop_opcode+a_address+spp_address, move_opcode + b_address + constant_address, # move b literal dec_to_bin(10), # location of first jump to end alu_opcode + alu_add + b_address + a_address, # add b a alu_opcode + alu_add + bp_address + a_address, # add [b] a move_opcode + b_address + constant_address, # move b literal dec_to_bin(14), # location of second jump to end alu_opcode + alu_add + b_address + a_address, # add b a alu_opcode + alu_add + bp_address + a_address, # add [b] a # Program jump_opcode + unused_opcode + constant_address, dec_to_bin(13), # jump to end move_opcode + a_address + constant_address, dec_to_bin(1), # literal jump_opcode + unused_opcode + constant_address, dec_to_bin(13) # jump to end ]
def test_alloc_size_1_with_label_as_boot(self): instructions = [move_opcode+constantp_address+a_address, Token(Label.Name, 'var', 1), jump_opcode + unused_opcode + constant_address, Token(Label.Name, 'start', 2) ] labels = {'start': 0} variables = {'var': 1} linked = link(instructions, labels, variables, mode='boot') assert linked == [move_opcode+constantp_address+a_address, dec_to_bin(4), # accessing var jump_opcode + unused_opcode + constant_address, dec_to_bin(0) # jump to label start ]
def test_jump_loop(self, cpu): instructions = [move_opcode + a_address + constant_address, ZEROS, alu_opcode + alu_inc + a_address + unused_opcode, jump_opcode + unused_opcode + constant_address, dec_to_bin(2)] self.load_instructions(cpu.ram, instructions) cpu() cpu.tick() for i in range(10): for _ in range(2): cpu() cpu.tick() assert cpu.a.value == dec_to_bin(10)
def load_binary(self, binary): size = int(len(binary) / 16) for i in range(size): instruction = binary[i * 16:(i + 1) * 16] address = dec_to_bin(i) self.cpu.ram(instruction, address, 1) self.cpu.ram.tick()
def test_move_from_register_to_constant_as_pointer(self, cpu): memory_address = dec_to_bin(1024) value = INT_ONE instructions = [move_opcode + a_address + constant_address, value, move_opcode + constantp_address + a_address, memory_address, ] self.load_instructions(cpu.ram, instructions) assert cpu() == 0 cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.ram_bus(UNUSED, memory_address, 0) == value assert cpu.pc(UNUSED, 0, 0, 0) == dec_to_bin(4)
def test_call_constant(self, cpu): stack_frame = dec_to_bin(1024) function_address = dec_to_bin(52) instructions = [move_opcode + sp_address + constant_address, stack_frame, call_opcode + spp_address + constant_address, function_address] self.load_instructions(cpu.ram, instructions) cpu() cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.pc.register.value == function_address assert cpu.ram_bus(UNUSED, stack_frame, 0) == dec_to_bin(4) assert cpu.sp.value == dec_to_bin(1023)
def test_push_or_call_literal(self, parser, keyword_token, opcode, literal): tokens = [keyword_token, Token(Literal.Int, literal, 1)] instructions = parser.parse(tokens) assert instructions == [ opcode + spp_address + constant_address, dec_to_bin(literal) ]
def test_BP_label(self, parser): token_bp_label = Token(Label.Name, 'BP', 1) tokens = [token_move, token_sp, token_bp_label] instructions = parser.parse(tokens) base_pointer_address = dec_to_bin(32767) assert instructions == [ move_opcode + sp_address + constant_address, base_pointer_address ]
def test_source_address_command_literal(self, parser, command_token, opcode, literal): tokens = [command_token, Token(Literal.Int, literal, 1)] instructions = parser.parse(tokens) assert instructions == [ opcode + unused_opcode + constant_address, dec_to_bin(literal) ]
def test_two_address_command_literal_to_register(self, parser, command_token, opcode, token, address, value): tokens = [command_token, token, Token(Literal.Int, value, 1)] instructions = parser.parse(tokens) assert instructions == [ opcode + address + constant_address, dec_to_bin(value) ]
def test_alloc_size_1_as_boot(self): instructions = [move_opcode+constantp_address+a_address, Token(Label.Name, 'var', 1) ] labels = {} variables = {'var': 1} linked = link(instructions, labels, variables, mode='boot') assert linked == [move_opcode+constantp_address+a_address, dec_to_bin(2)]
def make_loader(relative_locations): loader = [pop_opcode + a_address + spp_address] # pop a offset = len(loader) + 4 * len(relative_locations) for access_location in relative_locations: loader.append(move_opcode + b_address + constant_address) # move b literal loader.append(dec_to_bin(access_location + offset)) loader.append(alu_opcode + alu_add + b_address + a_address) # add b a loader.append(alu_opcode + alu_add + bp_address + a_address) # add [b] a return loader
def test_two_address_command_literal_pointer_to_register( self, parser, command_token, opcode, token, address, value): tokens = [ command_token, token, token_left_bracket, Token(Literal.Int, value, 1), token_right_bracket ] instructions = parser.parse(tokens) assert instructions == [ opcode + address + constantp_address, dec_to_bin(value) ]
def test_SCREEN_label(self, parser): token_screen_label = Token(Label.Name, 'SCREEN', 1) tokens = [ token_move, token_a, token_left_bracket, token_screen_label, token_right_bracket ] instructions = parser.parse(tokens) screen_address = dec_to_bin(32768) assert instructions == [ move_opcode + a_address + constantp_address, screen_address ]
def test_KEYBOARD_label(self, parser): token_keyboard_label = Token(Label.Name, 'KEYBOARD', 1) tokens = [ token_move, token_a, token_left_bracket, token_keyboard_label, token_right_bracket ] instructions = parser.parse(tokens) keyboard_address = dec_to_bin(40960) assert instructions == [ move_opcode + a_address + constantp_address, keyboard_address ]
def test_alloc_size_1(self): instructions = [move_opcode+constantp_address+a_address, Token(Label.Name, 'var', 1)] labels = {} variables = {'var': 1} linked = link(instructions, labels, variables) assert linked == [dec_to_bin(9), # Length of program dec_to_bin(1), # Allocated memory # Loader pop_opcode + a_address + spp_address, move_opcode + b_address + constant_address, # move b literal dec_to_bin(6), # location of var access alu_opcode + alu_add + b_address + a_address, # add b a alu_opcode + alu_add + bp_address + a_address, # add [b] a # Program move_opcode+constantp_address+a_address, dec_to_bin(7), # Accessing var ]
def test_push_from_register(self, cpu, stack_frame_dec): stack_frame = dec_to_bin(stack_frame_dec) stack_frame_p1 = dec_to_bin(stack_frame_dec - 1) value_1 = INT_ONE instructions = [move_opcode + sp_address + constant_address, stack_frame, move_opcode + a_address + constant_address, value_1, push_opcode + spp_address + a_address] self.load_instructions(cpu.ram, instructions) cpu() cpu.tick() cpu() cpu.tick() assert cpu() == 0 cpu.tick() assert cpu.sp.value == stack_frame_p1 assert cpu.ram_bus(UNUSED, stack_frame, 0) == value_1
def test_double_alloc_size_2(self): instructions = [move_opcode+constantp_address+a_address, Token(Label.Name, 'var_1', 1), move_opcode + constantp_address + b_address, Token(Label.Name, 'var_2', 2) ] labels = {} variables = {'var_1': 2, 'var_2': 2} linked = link(instructions, labels, variables) assert linked == [dec_to_bin(15), # Length of program dec_to_bin(4), # Allocated memory # Loader pop_opcode + a_address + spp_address, move_opcode + b_address + constant_address, # move b literal dec_to_bin(10), # location of var_1 access alu_opcode + alu_add + b_address + a_address, # add b a alu_opcode + alu_add + bp_address + a_address, # add [b] a move_opcode + b_address + constant_address, # move b literal dec_to_bin(12), # location of var_2 access alu_opcode + alu_add + b_address + a_address, # add b a alu_opcode + alu_add + bp_address + a_address, # add [b] a # Program move_opcode+constantp_address+a_address, dec_to_bin(13), # Accessing var_1 move_opcode + constantp_address + b_address, dec_to_bin(15), # Accessing var_2 ]
def test_alloc_size_1_with_label(self): instructions = [move_opcode+constantp_address+a_address, Token(Label.Name, 'var', 1), jump_opcode + unused_opcode + constant_address, Token(Label.Name, 'start', 2) ] labels = {'start': 0} variables = {'var': 1} linked = link(instructions, labels, variables) assert linked == [dec_to_bin(15), # Length of program dec_to_bin(1), # Allocated memory # Loader pop_opcode + a_address + spp_address, move_opcode + b_address + constant_address, # move b literal dec_to_bin(10), # location of var access alu_opcode + alu_add + b_address + a_address, # add b a alu_opcode + alu_add + bp_address + a_address, # add [b] a move_opcode + b_address + constant_address, # move b literal dec_to_bin(12), # location of jump to start alu_opcode + alu_add + b_address + a_address, # add b a alu_opcode + alu_add + bp_address + a_address, # add [b] a # Program move_opcode+constantp_address+a_address, dec_to_bin(13), # accessing var jump_opcode + unused_opcode + constant_address, dec_to_bin(9) # jump to label start ]