def test_docol_ram(emulator, return_stack, ip, mode, return_stack_depth): """Test the docol implementation for RAM mode On entry: IP holds the RAM address after the one we've just come from W holds the address of our NOP instruction mode holds the mode On exit: IP holds the first address of the thread mode holds the address of NEXT3-ROM-Mode The return stack holds: Top: The address of restore-mode (little-endian) 2: The previous mode 3: The old ip (little endian) """ # Arrange return_stack.set_depth_in_bytes(return_stack_depth) set_IP(ip) set_mode(mode) set_W(asm.symbol("forth.NOP")) # Act do_test_word(emulator, "forth.NOP") # Assert assert end_of_docol == get_IP() assert asm.symbol("forth.next3.rom-mode") & 0xFF == get_mode() assert [asm.symbol("forth.RESTORE-MODE"), mode, ip] == [ return_stack.pop_u16(), return_stack.pop_u8(), return_stack.pop_u16(), ] assert len(return_stack) == return_stack_depth
def test_docol_rom(emulator, return_stack, ip, return_stack_depth): """Test the docol implementation for RAM mode On entry: IP holds the ROM address after the one we've just come from W holds the address of our NOP instruction mode holds ROM mode On exit: IP holds the first address of the thread mode holds the address of NEXT3-ROM-Mode The return stack holds the old ip (little endian) """ # Arrange return_stack.set_depth_in_bytes(return_stack_depth) set_IP(ip) set_mode(asm.symbol("forth.next3.rom-mode") & 0xFF) set_W(nop_start_rom) # Act do_test_word(emulator, nop_start_rom) # Assert assert end_of_docol == get_IP() assert asm.symbol("forth.next3.rom-mode") & 0xFF == get_mode() assert [ip] == [return_stack.pop_u16()] assert len(return_stack) == return_stack_depth
def test_branch_rom_mode(emulator, address, target): # Arrange # Jump target must not intersect with jump assume(not set(range(address, address + 2)) & set(range(target, target + 3))) # Jump address cannot be encoded right at the end of a page. # In practice this is not a problem, it's a two instruction encoding, and we # already have a requirement that threads can't cross pages. assume(address & 0xFF != 0xFF) set_IP(address) ip_movement = target - address + 3 ROM[target:target + 3] = [ b"\xdc\x42", # st $42,[y, x++] [0xE0, asm.symbol("forth.move-ip")], # jmp [y,] b"\xdc\x82", # $82,[y, x++] ] ROM[address:address + 2] = [ # Encoding for data [0xFC, target & 0xFF], # bra target [0x00, ip_movement & 0xFF], # ld ip_movement ] # Act do_test_word(emulator, "forth.internal.rom-mode.BRANCH", continue_on_reenter=False) # Assert assert (target + 3) & 0xFF == get_IP( ) & 0xFF # low-byte equality, because move-ip doesn't handle page crossings assert 0x8242 == get_W()
def test_exit(emulator, return_stack, return_address, return_stack_depth): # Arrange return_stack.set_depth_in_bytes(return_stack_depth) return_stack.push_word(return_address) # Act do_test_word(emulator, "forth.core.EXIT") # Assert assert return_address == get_IP() assert len(return_stack) == return_stack_depth
def test_next3_ram_rom(emulator, ip): # Arrange emulator.next_instruction = "forth.next3.ram-rom-mode" set_IP(ip) RAM[ip:ip + 2] = bytearray(struct.pack("<H", WORD_START)) # Act do_test_word(emulator, continue_on_reenter=False) # Assert assert get_W() == WORD_START assert get_IP() == ip + 2
def test_question_branch_rom_mode(emulator, data_stack, address, target, data_stack_depth, tos): # Arrange # Jump target must not intersect with jump assume(not set(range(address, address + 5)) & set(range(target, target + 3))) # We need to not be within the last five bytes of the page, # as there needs to be an instruction after us to run into if we don't branch. assume((address & 0xFF) + 5 <= 0xFF) data_stack.set_depth_in_bytes(data_stack_depth) data_stack.push_word(tos) set_IP(address) ip_movement = target - address + 3 ROM[target:target + 3] = [ b"\xdc\x00", # st $00,[y, x++] [0xE0, asm.symbol("forth.move-ip")], # jmp [y,] b"\xdc\x00", # $00,[y, x++] ] ROM[address:address + 5] = [ # Encoding for data [0xFC, target & 0xFF], # bra target [0x00, ip_movement & 0xFF], # ld ip_movement # Encoding for following word b"\xdc\xff", # st $ff,[y, x++] [0xE0, asm.symbol("forth.move-ip")], # jmp [y,] b"\xdc\xff", # $ff,[y, x++] ] # Act do_test_word(emulator, "forth.internal.rom-mode.?BRANCH", continue_on_reenter=False) # Assert if not tos: # IP should point after target address assert (target + 3) & 0xFF == get_IP( ) & 0xFF # low-byte equality, because move-ip doesn't handle page crossings # Target instruction should be about to run assert 0x0000 == get_W() else: # We run into the encoding of the next instruction, so IP should point after it. assert (address + 5) & 0xFF == get_IP() & 0xFF # Next instruction should be about to run assert 0xFFFF == get_W()
def test_next3_ram_ram(emulator, ip, target): # Arrange # Address IP and target address can't intersect assume(not set(range(target, target + 2)) & set(range(ip, ip + 2))) emulator.next_instruction = "forth.next3.ram-ram-mode" RAM[target:target + 2] = bytearray(struct.pack("<H", WORD_START)) set_IP(ip) RAM[ip:ip + 2] = bytearray(struct.pack("<H", target)) # Act do_test_word(emulator, continue_on_reenter=False) # Assert assert get_W() == WORD_START assert get_IP() == ip + 2
def test_next3_rom(emulator): emulator.next_instruction = "forth.next3.rom-mode" set_IP(WORD_START) ROM[WORD_START:WORD_START + 3] = [ b"\xdc\x42", # st $42,[y, x++] [0xE0, asm.symbol("forth.move-ip")], # jmp [y,] b"\xdc\x82", # $82,[y, x++] ] do_test_word(emulator, continue_on_reenter=False) assert get_W() == 0x8242 assert get_IP() == WORD_START + 3
def test_exit_to_ram_mode(emulator, return_stack, return_address, mode, return_stack_depth): # Arrange return_stack.set_depth_in_bytes(return_stack_depth) return_stack.push_word(return_address) return_stack.push_byte(mode) return_stack.push_word(asm.symbol("forth.RESTORE-MODE")) # Act do_test_word(emulator, "forth.core.EXIT") # Exit should have left restore-mode in IP, so next should DTRT do_test_word(emulator, "forth.next3.rom-mode") # Assert assert mode == get_mode() assert return_address == get_IP() assert len(return_stack) == return_stack_depth
def test_rom_mode_char_literal(emulator, data_stack, data_stack_depth, data): # Arrange data_stack.set_depth_in_bytes(data_stack_depth) set_IP(WORD_START) ROM[WORD_START : WORD_START + 5] = [ # Encoding for data [0xDC, data & 0xFF], [0x10, W], # ld $00,x # Encoding for next word b"\xdc\x42", # st $42,[y, x++] [0xE0, asm.symbol("forth.move-ip")], # jmp [y,] b"\xdc\x82", # $82,[y, x++] ] # Act do_test_word(emulator, "forth.internal.C-LIT", continue_on_reenter=False) # Assert assert data == data_stack.pop_i16() assert data_stack_depth == len(data_stack) assert WORD_START + 5 == get_IP() assert 0x8242 == get_W()
def test_docol_ram_ram(emulator, return_stack, ip, target, return_stack_depth): """Test jumping from one thread in RAM to another""" # Arrange emulator.zero_memory() return_stack.set_depth_in_bytes(return_stack_depth) assume(not {ip, ip + 1} & {target, target + 1}) set_IP(ip) set_mode(asm.symbol("forth.next3.ram-ram-mode") & 0xFF) RAM[target:target + 2] = [ asm.symbol("forth.DOCOL") & 0xFF, asm.symbol("forth.DOCOL") >> 8, ] RAM[ip:ip + 2] = [ target & 0xFF, target >> 8, ] # Act do_test_word(emulator, "forth.next3.ram-ram-mode") # Assert assert len(return_stack) == return_stack_depth + 2 assert [ip + 2] == [return_stack.pop_u16()] assert target + 2 == get_IP()
def _do_test_thread(emulator, label): set_IP(0x4282) set_W(symbol(label)) do_test_word(emulator, get_W()) while get_IP() != 0x4282: do_test_word(emulator, "forth.next3.rom-mode")