Beispiel #1
0
def restart_or_quit():
    assert pc() & 0xFF == 0, "restart_or_quit must be placed at the start of a page"
    label("forth.restart-or-quit")
    bra([W_lo])  # 6
    ble(pc() + 1)  # 7
    # 8 happens in start of thread again
    label(".quit")
    ld(hi("forth.exit"), Y)  # 9
    C("jmp forth.exit.from-failed-test")
    jmp(Y, lo("forth.exit.from-failed-test"))  # 10
Beispiel #2
0
def shift(vtmp):
    """Place all of the code required for 2*, LSHIFT, RSHIFT and 2/

    Needs a page to itself.
    """
    # Customized restart or quit trampoline which loads Y and X so that
    # they point at the data stack. This saves space at no runtime cost.
    assert pc(
    ) & 0xFF == 0, "restart_or_quit must be placed at the start of a page"
    label("forth.restart-or-quit")
    ble(pc() + 3)  # 6
    ld(data_stack_page, Y)  # 7
    bra([W_lo])
    ld([data_stack_pointer], X)  # 8; nop for purposes of .quit
    label(".quit")
    ld(hi("forth.exit"), Y)  # 9
    C("jmp forth.exit.from-failed-test")
    jmp(Y, lo("forth.exit.from-failed-test"))  # 10
    # 11, overlap with whatever comes next - hopefully not a branch or jump!

    _two_times()
    offset_start = pc()
    _lshift()
    offset_of_shift_by_8 = pc() - offset_start
    _lshift__amount_eq_8()
    offset_of_shift_by_gt_8 = pc() - offset_start
    _lshift__amount_gt_8()
    offset_of_shift_by_lt_8 = pc() - offset_start
    _lshift__amount_lt_8()

    rshift_offset_start = pc()
    _rshift()
    assert pc() - rshift_offset_start <= offset_of_shift_by_8
    fillers(until=(rshift_offset_start + offset_of_shift_by_8) & 255)
    _rshift__amount_eq_8()
    assert pc() - rshift_offset_start <= offset_of_shift_by_gt_8
    fillers(until=(rshift_offset_start + offset_of_shift_by_gt_8) & 255)
    _rshift__amount_gt_8()
    assert pc() - rshift_offset_start <= offset_of_shift_by_lt_8
    fillers(until=(rshift_offset_start + offset_of_shift_by_lt_8) & 255)
    _rshift__amount_lt_8()
    _shift_entry(
        offset_to_amount_eq_8=offset_of_shift_by_8,
        offset_to_amount_gt_8=offset_of_shift_by_gt_8,
        offset_to_amount_lt_8=offset_of_shift_by_lt_8,
    )
    _left_shift_by_n()
    _right_shift_by_n(vtmp)
    _two_div(vtmp)
Beispiel #3
0
def next3_ram_rom():
    """NEXT3 to use when in RAM->ROM mode"""
    label("forth.next3.ram-rom-mode")
    adda(-(cost_of_next3_ram_rom / 2))  # 1
    ld([IP_hi], Y)  # 2
    C("W <- [IP]")
    ld([IP_lo], X)  # 3
    ld([Y, X])  # 4
    st([W_lo])  # 5
    ld([IP_lo])  # 6
    adda(1)  # 7
    ld(AC, X)  # 8
    ld([Y, X])  # 9
    # Increment IP
    st([W_hi])  # 10
    C("IP <- IP + 2")
    ld([IP_lo])  # 11
    adda(2)  # 12
    beq(pc() + 5)  # 13
    st([IP_lo])  # 14
    REENTER(14)
    label(".page-boundary")
    ld([IP_hi])  # 15
    adda(1)  # 16
    st([IP_hi])  # 17
    REENTER(17)
Beispiel #4
0
 def wrapper(*args, **kwargs):
     if asm.pc() & 0xFF < 0xFF:
         # We haven't run out of space yet - Let's keep going!
         # Record this call for future playback
         _assembler_call_buffer.append((function, args, kwargs))
     else:
         # Oh no - this thread definition crosses a page boundary
         # Restore the asm.py state to what it was before the start
         # of the definition, start a new page, and replay the buffer
         _restart_definition()
     # Now do the operation we were asked to.
     # If the operation is PC relative, we need to pass it the current pc
     try:
         (arg, ) = args
         if callable(arg):
             args = (arg(asm.pc()), )
     except ValueError:
         pass
     return function(*args, **kwargs)
Beispiel #5
0
def zero_equal():
    """Logical not ( x -- flag )

    flag is true if and only if x is equal to zero.
    """
    label("forth.core.0=")
    adda(-add_cost_of_next(cost_of_zero_equal) / 2)  # 1
    ld(data_stack_page, Y)
    ld([data_stack_pointer], X)
    ld([Y, X])
    st([Y, Xpp])  # 5
    ora([Y, X])
    beq(pc() + 3)  # 7
    bra(pc() + 3)  # 8
    ld(0x00)  # 9 - If any bits were non-zero
    ld(0xFF)  # 9 - Otherwise
    ld([data_stack_pointer], X)  # 10
    st([Y, Xpp])
    st([Y, X])  # 12
    NEXT(cost_of_zero_equal)
Beispiel #6
0
def exit(vTicks, vReturn):
    label("forth.exit")  # Counting down
    label("forth.exit.from-failed-test")
    ld(-(cost_of_failed_next1 + 1) / 2)  # 7
    label("forth.exit.from-next1-reenter")
    label("forth.exit.from-next2")
    adda([vTicks])  # 6
    ld(hi("vBlankStart"), Y)  # 5
    bgt(pc() & 0xFF)  # 4
    suba(1)  # 3
    jmp(Y, [vReturn])  # 2
    nop()  # 1
Beispiel #7
0
def emit_entry_page(vticks, vreturn):
    """Emit the data for NEXT and some other core routines

    The first page does not have the 'restart-or-quit' trampoline at 0x00
    So we can't put any Forth word in here.
    """
    while pc() & 255 < 255:
        nop()
    assert _next.INTERPRETER_ENTER_PAGE == pc() >> 8
    label("FORTH_ENTER")
    C("You are now entering... Forth")
    adda(_next.INBOUND_TICK_CORRECTION)
    # --- Page boundary ---
    align(0x100, 0x100)
    st([vticks])
    _next.next1(vticks)
    _next.next1_reenter(vticks)
    _next.next2(vticks)
    _next.exit(vticks, vreturn)
    _docol_exit.do_docol_rom()
    _docol_exit.do_docol_ram()
Beispiel #8
0
def move_ip():
    """Page-Zero code to move the IP by the amount contained in AC

    This routine is used by the ROM mode next3, and also by literal, branch and zero_branch.
    As these routines all have different lengths, it uses a variable (tmp0) to tell it what length to return

    It always jumps to forth.next1.reenter.odd, and it has an odd length itself code calling it must have an even length
    """
    assert pc() >> 8 == 0
    label("forth.move-ip")
    adda([IP_lo])  # 1
    st([IP_lo])  # 2
    ld(hi("forth.next1.reenter"), Y)  # 3
    C("REENTER")
    jmp(Y, lo("forth.next1.reenter.odd"))  # 4
    ld([tmp0])  # 5
Beispiel #9
0
def next3_ram_ram():
    label("forth.next3.ram-ram-mode")
    adda(-add_cost_of_reenter(cost_of_next3_ram_ram) // 2)  # 1

    # Copy low byte to zero-page
    ld([IP_hi], Y)
    C("[tmp] <- [IP]")
    ld([IP_lo], X)
    ld([Y, X])
    st([Y, Xpp])  # 5; Advance X
    st([tmp0])
    # High byte to zero-page
    ld([Y, X])
    st([tmp1])

    # Update W
    ld(AC, Y)
    C("[W] <- [tmp]")
    ld([tmp0], X)  # 10
    ld([Y, X])
    st([W_lo])
    st([Y, Xpp])  # Advance X
    ld([Y, X])
    st([W_hi])  # 15

    # Increment IP
    ld([IP_lo])
    C("IP <- IP + 2")
    adda(2)
    bne(pc() + 8)  # 18
    st([IP_lo])  # 19

    ld([IP_hi])  # 20
    adda(1)
    st([IP_hi])

    REENTER(cost_of_next3_ram_ram__page_crossed)

    label(".not-page-boundary")
    REENTER(cost_of_next3_ram_ram__no_page_cross)
Beispiel #10
0
def bitwise():
    """Common implementation for all of the bitwise operators"""
    for name, target in [("AND", ".and"), ("OR", ".or"), ("XOR", ".xor")]:
        label(f"forth.core.{name}")
        adda(-add_cost_of_next(cost_of_binary_bitwise) / 2)  # 1
        bra(".copy-first-value")  # 2
        ld(lo(target))  # 3

    label(".copy-first-value")
    st([tmp0])  # 4
    adda(1)  # 5
    st([tmp1])
    ld(data_stack_page, Y)
    ld([data_stack_pointer], X)
    ld(2)
    adda([data_stack_pointer])  # 10
    st([data_stack_pointer])  # 11
    for tmp in [tmp2, tmp3]:
        ld([Y, X])
        st([tmp])
        st([Y, Xpp])  # 17 = 11 + 2 * 3
    ld([Y, X])
    bra([tmp0])
    bra(pc() + 1)  # 20
    # 21
    st([Y, Xpp])  # 22
    ld([Y, X])
    bra([tmp1])  # 24
    bra(".bitwise-done")  # 25
    # 26
    for label_, op in [(".and", anda), (".or", ora), (".xor", xora)]:
        label(label_)
        op([tmp2])
        op([tmp3])
    label(".bitwise-done")
    st([Y, X])  # 27
    NEXT(cost_of_binary_bitwise)
Beispiel #11
0
def _restart_definition():
    """Restart the current definition on a fresh page

    Restores the asm module internal state to what it was before the start
    of the definition, start a new page, and replay the buffer.
    """
    _restore_asm_state()
    _start_page()

    asm.label(_current_label)
    docol_rom_only()

    for function, args, kwargs in _assembler_call_buffer:
        # If the operation was PC relative, we need to pass it the current pc
        try:
            (arg, ) = args
            if callable(arg):
                args = (arg(asm.pc()), )
        except ValueError:
            pass
        function(*args, **kwargs)
    _assembler_call_buffer[:] = []  # Clear
    # Restart capturing
    _capture_asm_state()
# First the high-bytes.
# The table is shifted down by 32 places, as the first 32 high-bytes are all zero
# This allows us to have code later in the page which we can branch back to.
align(0x100, size=0x100)
label("Quarter-squares lookup table")
for i in range(32, 256):
    val = math.floor(i**2 / 4)
    ld(hi(val))
    C(f"${val:04x} = {val} = floor({i} ** 2 / 4); ${val:04x} >> 8 = ${val >> 8:02x}"
      )

# We jump back here after looking up the low-byte of the result.
label("low-byte return point")
ld(hi("multiply 7x7"), Y)
jmp(Y, [continuation])
ld(hi(pc()), Y)  # Make it easy to get back here!
cost_of_low_byte_return = 3
label("table entry.possibly-negative")
# AC is negative, if b > a. Find absolute value
blt(pc() + 3)  # 1
bra(pc() + 3)  # 2
suba(1)  # 3; if >= 0
xora(0xFF)  # 3;  if < 0
adda(1)  # 4
cost_of_absolute = 4
label("table entry")
# Calculate an index into the high-byte table.
# This is basically a matter of subtracting 32, and jumping in if the result >= 0.
# But values greater than 160 have the sign-bit set after subtraction,
# despite being >32.
# We test for the sign bit and jump after subtraction even if 'negative' in these cases.