Example #1
0
def test_move_left():
    from machine import move_left

    base: State
    result: State

    base = move_left(State(acc=None, index=0, array=[None], array_len=1))
    result = State(acc=None, index=0, array=[None], array_len=1)
    assert base == result, "Move left trivial Case"

    base = move_left(State(acc=None, index=1, array=[None, None, None], array_len=3))
    result = State(acc=None, index=0, array=[None, None, None], array_len=3)
    assert base == result, "Moving to left"
Example #2
0
def test_init( mem, debug ):

  # instantiate architectural state with memory and reset address

  state = State( mem, debug, reset_addr=0x200 )

  return state
Example #3
0
def test_init(mem, debug):

    # inject bootstrap code into the memory

    for i, data in enumerate(bootstrap_code):
        mem.write(bootstrap_addr + i, 1, data)
    for i, data in enumerate(rewrite_code):
        mem.write(rewrite_addr + i, 1, data)

    # instantiate architectural state with memory and reset address

    state = State(mem, debug, reset_addr=0x0400)

    return state
Example #4
0
def test_set_cell():
    from machine import set_cell

    base: State
    result: State

    base = set_cell(State(acc=None, index=0, array=[1], array_len=1))
    result = State(acc=None, index=0, array=[None], array_len=1)
    assert base == result, "Set trivial case"

    base = set_cell(State(acc=1, index=0, array=[None], array_len=1))
    result = State(acc=1, index=0, array=[1], array_len=1)
    assert base == result, "Set a blank cell -> acc value"

    base = set_cell(State(acc="b", index=1, array=["a", None, "c"], array_len=3))
    result = State(acc="b", index=1, array=["a", "b", "c"], array_len=3)
    assert base == result, "Setting a cell"
Example #5
0
def test_erase_cell():
    from machine import erase_cell

    base: State
    result: State

    base = erase_cell(State(acc=None, index=0, array=[1], array_len=1))
    result = State(acc=None, index=0, array=[None], array_len=1)
    assert base == result, "Erase trivial case"

    base = erase_cell(State(acc=None, index=0, array=[None], array_len=1))
    result = State(acc=None, index=0, array=[None], array_len=1)
    assert base == result, "Erase a blank cell -> blank cell"

    base = erase_cell(State(acc=None, index=1, array=["a", "b", "c"], array_len=3))
    result = State(acc=None, index=1, array=["a", None, "c"], array_len=3)
    assert base == result, "Erasing cell value"
Example #6
0
def test_copy_cell():
    from machine import copy_cell

    base: State
    result: State

    base = copy_cell(State(acc=None, index=0, array=[1], array_len=1))
    result = State(acc=1, index=0, array=[1], array_len=1)
    assert base == result, "Copy trivial case"

    base = copy_cell(State(acc=1, index=0, array=[None], array_len=1))
    result = State(acc=None, index=0, array=[None], array_len=1)
    assert base == result, "Copy a blank cell -> blank acc"

    base = copy_cell(State(acc="a", index=1, array=["a", "b", "c"], array_len=3))
    result = State(acc="b", index=1, array=["a", "b", "c"], array_len=3)
    assert base == result, "Copying cell value to acc"
Example #7
0
def syscall_init(mem, breakpoint, argv, debug):

    #---------------------------------------------------------------------
    # memory map initialization
    #---------------------------------------------------------------------

    # TODO: for multicore allocate 8MB for each process
    #proc_stack_base[pid] = stack_base - pid * 8 * 1024 * 1024

    # top of heap (breakpoint)  # TODO: handled in load program

    # memory maps: 1GB above top of heap
    # mmap_start = mmap_end = break_point + 0x40000000

    #---------------------------------------------------------------------
    # stack argument initialization
    #---------------------------------------------------------------------
    # http://articles.manugarg.com/aboutelfauxiliaryvectors.html
    #
    #                contents         size
    #
    #   0x7FFF.FFFF  [ end marker ]               4    (NULL)
    #                [ environment str data ]   >=0
    #                [ arguments   str data ]   >=0
    #                [ padding ]               0-16
    #                [ auxv[n]  data ]            8    (AT_NULL Vector)
    #                                             8*x
    #                [ auxv[0]  data ]            8
    #                [ envp[n]  pointer ]         4    (NULL)
    #                                             4*x
    #                [ envp[0]  pointer ]         4
    #                [ argv[n]  pointer ]         4    (NULL)
    #                                             4*x
    #                [ argv[0]  pointer ]         4    (program name)
    #   stack ptr->  [ argc ]                     4    (size of argv)
    #
    #                (stack grows down!!!)
    #
    #   0x7F7F.FFFF  < stack limit for pid 0 >
    #

    # auxv variables initialized by gem5, are these needed?
    #
    # - PAGESZ:    system page size
    # - PHDR:      virtual addr of program header tables
    #              (for statically linked binaries)
    # - PHENT:     size of program header entries in elf file
    # - PHNUM:     number of program headers in elf file
    # - AT_ENRTY:  program entry point
    # - UID:       user ID
    # - EUID:      effective user ID
    # - GID:       group ID
    # - EGID:      effective group ID

    # TODO: handle auxv, envp variables
    auxv = []
    envp = []
    argc = len(argv)

    def sum_(x):
        val = 0
        for i in x:
            val += i
        return val

    # calculate sizes of sections
    # TODO: parameterize auxv/envp/argv calc for variable int size?
    stack_nbytes = [
        4,  # end mark nbytes
        sum_([len(x) + 1 for x in envp]),  # envp_str nbytes
        sum_([len(x) + 1 for x in argv]),  # argv_str nbytes
        0,  # padding  nbytes
        8 * (len(auxv) + 1),  # auxv     nbytes
        4 * (len(envp) + 1),  # envp     nbytes
        4 * (len(argv) + 1),  # argv     nbytes
        4
    ]  # argc     nbytes

    # calculate padding to align boundary
    # TODO: gem5 doesn't do this step, temporarily remove it. There should
    #       really be padding to align argv to a 16 byte boundary!!!
    #stack_nbytes[3] = 16 - (sum_(stack_nbytes[:3]) % 16)

    def round_down(val):
        return val & ~(page_size - 1)

    # calculate stack pointer based on size of storage needed for args
    # TODO: round to nearest page size?
    stack_ptr = round_down(stack_base - sum_(stack_nbytes))
    offset = stack_ptr + sum_(stack_nbytes)
    stack_off = []
    for nbytes in stack_nbytes:
        offset -= nbytes
        stack_off.append(offset)
    assert offset == stack_ptr

    #print 'stack min', hex( stack_ptr )
    #print 'stack size', stack_base - stack_ptr

    #print 'argv', stack_nbytes[-2]
    #print 'envp', stack_nbytes[-3]
    #print 'auxv', stack_nbytes[-4]
    #print 'argd', stack_nbytes[-6]
    #print 'envd', stack_nbytes[-7]

    # utility functions

    # TODO: we can do more efficient versions of these using Memory object
    # (writing 4 bytes at once etc.)

    def str_to_mem(mem, val, addr):
        for i, char in enumerate(val + '\0'):
            mem.write(addr + i, 1, ord(char))
        return addr + len(val) + 1

    def int_to_mem(mem, val, addr):
        # TODO properly handle endianess
        for i in range(4):
            mem.write(addr + i, 1, (val >> 8 * i) & 0xFF)
        return addr + 4

    # write end marker to memory
    int_to_mem(mem, 0, stack_off[0])

    # write environment strings to memory
    envp_ptrs = []
    offset = stack_off[1]
    for x in envp:
        envp_ptrs.append(offset)
        offset = str_to_mem(mem, x, offset)
    assert offset == stack_off[0]

    # write argument strings to memory
    argv_ptrs = []
    offset = stack_off[2]
    for x in argv:
        argv_ptrs.append(offset)
        offset = str_to_mem(mem, x, offset)
    assert offset == stack_off[1]

    # write auxv vectors to memory
    offset = stack_off[4]
    for type_, value in auxv + [(0, 0)]:
        offset = int_to_mem(mem, type_, offset)
        offset = int_to_mem(mem, value, offset)
    assert offset == stack_off[3]

    # write envp pointers to memory
    offset = stack_off[5]
    for env in envp_ptrs + [0]:
        offset = int_to_mem(mem, env, offset)
    assert offset == stack_off[4]

    # write argv pointers to memory
    offset = stack_off[6]
    for arg in argv_ptrs + [0]:
        offset = int_to_mem(mem, arg, offset)
    assert offset == stack_off[5]

    # write argc to memory
    offset = stack_off[7]
    offset = int_to_mem(mem, argc, offset)
    assert offset == stack_off[6]

    # initialize processor state
    state = State(mem, debug, reset_addr=0x1000)

    # TODO: where should this go?
    state.breakpoint = breakpoint

    #print '---'
    #print 'argc = %d (%x)' % ( argc,         stack_off[-1] )
    #for i, ptr in enumerate(argv_ptrs):
    #  print 'argv[%d] = %x (%x)' % ( i, argv_ptrs[i], stack_off[-2]+4*i ),
    #  print len( argv[i] ), argv[i]
    #print 'argd = %s (%x)' % ( argv[0],      stack_off[-6] )
    #print '---'
    #print 'argv-base', hex(stack_off[-2])
    #print 'envp-base', hex(stack_off[-3])
    #print 'auxv-base', hex(stack_off[-4])
    #print 'argd-base', hex(stack_off[-6])
    #print 'envd-base', hex(stack_off[-7])

    # initialize processor registers
    state.rf[reg_map['a0']] = argc  # argument 0 reg = argc
    state.rf[reg_map['a1']] = stack_off[6]  # argument 1 reg = argv ptr addr
    state.rf[reg_map['sp']] = stack_ptr  # stack pointer reg

    return state
Example #8
0
def syscall_init(mem, entrypoint, breakpoint, argv, envp, debug):

    #---------------------------------------------------------------------
    # memory map initialization
    #---------------------------------------------------------------------

    # TODO: for multicore allocate 8MB for each process
    #proc_stack_base[pid] = stack_base - pid * 8 * 1024 * 1024

    # top of heap (breakpoint)  # TODO: handled in load program

    # memory maps: 1GB above top of heap
    # mmap_start = mmap_end = break_point + 0x40000000

    #---------------------------------------------------------------------
    # stack argument initialization
    #---------------------------------------------------------------------
    # http://articles.manugarg.com/aboutelfauxiliaryvectors.html
    #
    #                contents         size
    #
    #   0x7FFF.FFFF  [ end marker ]               4    (NULL)
    #                [ environment str data ]   >=0
    #                [ arguments   str data ]   >=0
    #                [ padding ]               0-16
    #                [ auxv[n]  data ]            8    (AT_NULL Vector)
    #                                             8*x
    #                [ auxv[0]  data ]            8
    #                [ envp[n]  pointer ]         4    (NULL)
    #                                             4*x
    #                [ envp[0]  pointer ]         4
    #                [ argv[n]  pointer ]         4    (NULL)
    #                                             4*x
    #                [ argv[0]  pointer ]         4    (program name)
    #   stack ptr->  [ argc ]                     4    (size of argv)
    #
    #                (stack grows down!!!)
    #
    #   0x7F7F.FFFF  < stack limit for pid 0 >
    #

    # auxv variables initialized by gem5, are these needed?
    #
    # - PAGESZ:    system page size
    # - PHDR:      virtual addr of program header tables
    #              (for statically linked binaries)
    # - PHENT:     size of program header entries in elf file
    # - PHNUM:     number of program headers in elf file
    # - AT_ENRTY:  program entry point
    # - UID:       user ID
    # - EUID:      effective user ID
    # - GID:       group ID
    # - EGID:      effective group ID

    # TODO: handle auxv, envp variables
    auxv = []
    if EMULATE_GEM5:
        argv = argv[1:]
    argc = len(argv)

    def sum_(x):
        val = 0
        for i in x:
            val += i
        return val

    # calculate sizes of sections
    # TODO: parameterize auxv/envp/argv calc for variable int size?
    stack_nbytes = [
        4,  # end mark nbytes (sentry)
        sum_([len(x) + 1 for x in envp]),  # envp_str nbytes
        sum_([len(x) + 1 for x in argv]),  # argv_str nbytes
        0,  # padding  nbytes
        8 * (len(auxv) + 1),  # auxv     nbytes
        4 * (len(envp) + 1),  # envp     nbytes
        4 * (len(argv) + 1),  # argv     nbytes
        4
    ]  # argc     nbytes

    if EMULATE_SIMIT:
        stack_nbytes[4] = 0  # don't to auxv for simit

    def round_up(val):
        alignment = 16
        return (val + alignment - 1) & ~(alignment - 1)

    # calculate padding to align boundary
    # NOTE: MIPs approach (but ignored by gem5)
    #stack_nbytes[3] = 16 - (sum_(stack_nbytes[:3]) % 16)
    # NOTE: gem5 ARM approach
    stack_nbytes[3] = round_up(sum_(stack_nbytes)) - sum_(stack_nbytes)
    if EMULATE_SIMIT:
        stack_nbytes[3] = 0

    def round_down(val):
        alignment = 16
        return val & ~(alignment - 1)

    # calculate stack pointer based on size of storage needed for args
    # TODO: round to nearest page size?
    stack_ptr = round_down(stack_base - sum_(stack_nbytes))
    if EMULATE_SIMIT:
        stack_ptr = stack_base - MAX_ENVIRON

    offset = stack_ptr + sum_(stack_nbytes)
    # FIXME: this offset seems really wrong, but this is how gem5 does it!
    if EMULATE_GEM5:
        offset = stack_base

    print "XXX", offset

    stack_off = []
    for nbytes in stack_nbytes:
        offset -= nbytes
        stack_off.append(offset)
    # FIXME: this is fails for GEM5's hacky offset...
    if not EMULATE_GEM5:
        assert offset == stack_ptr

    if debug.enabled('bootstrap'):
        print 'stack base', hex(stack_base)
        print 'stack min ', hex(stack_ptr)
        print 'stack size', stack_base - stack_ptr
        print
        print 'sentry ', stack_nbytes[0]
        print 'env d  ', stack_nbytes[1]
        print 'arg d  ', stack_nbytes[2]
        print 'padding', stack_nbytes[3]
        print 'auxv   ', stack_nbytes[4]
        print 'envp   ', stack_nbytes[5]
        print 'argv   ', stack_nbytes[6]
        print 'argc   ', stack_nbytes[7]

    # utility functions

    def str_to_mem(mem, val, addr):
        for i, char in enumerate(val + '\0'):
            mem.write(addr + i, 1, ord(char))
        return addr + len(val) + 1

    def int_to_mem(mem, val, addr):
        # TODO properly handle endianess
        for i in range(4):
            mem.write(addr + i, 1, (val >> 8 * i) & 0xFF)
        return addr + 4

    # write end marker to memory
    int_to_mem(mem, 0, stack_off[0])

    # write environment strings to memory
    envp_ptrs = []
    offset = stack_off[1]
    for x in envp:
        envp_ptrs.append(offset)
        offset = str_to_mem(mem, x, offset)
    assert offset == stack_off[0]

    # write argument strings to memory
    argv_ptrs = []
    offset = stack_off[2]
    for x in argv:
        argv_ptrs.append(offset)
        offset = str_to_mem(mem, x, offset)
    assert offset == stack_off[1]

    # write auxv vectors to memory
    offset = stack_off[4]
    if not EMULATE_SIMIT:
        for type_, value in auxv + [(0, 0)]:
            offset = int_to_mem(mem, type_, offset)
            offset = int_to_mem(mem, value, offset)
    assert offset == stack_off[3]

    # write envp pointers to memory
    offset = stack_off[5]
    for env in envp_ptrs + [0]:
        offset = int_to_mem(mem, env, offset)
    assert offset == stack_off[4]

    # write argv pointers to memory
    offset = stack_off[6]
    for arg in argv_ptrs + [0]:
        offset = int_to_mem(mem, arg, offset)
    assert offset == stack_off[5]

    # write argc to memory
    offset = stack_off[7]
    offset = int_to_mem(mem, argc, offset)
    assert offset == stack_off[6]

    # write zeros to bottom of stack
    # TODO: why does gem5 do this?
    offset = stack_off[7] - 1
    while offset >= stack_ptr:
        mem.write(offset, 1, ord('\0'))
        offset -= 1

    # initialize processor state
    state = State(mem, debug, reset_addr=0x1000)

    if debug.enabled('bootstrap'):
        print '---'
        #print 'argc = %d (%x)' % ( argc,         stack_off[-1] )
        #for i, ptr in enumerate(argv_ptrs):
        #  print 'argv[%2d] = %x (%x)' % ( i, argv_ptrs[i], stack_off[-2]+4*i ),
        #  print len( argv[i] ), argv[i]
        #print 'argd = %s (%x)' % ( argv[0],      stack_off[-6] )
        print '---'
        print 'envd-base', hex(stack_off[-7])
        print 'argd-base', hex(stack_off[-6])
        print 'auxv-base', hex(stack_off[-4])
        print 'envp-base', hex(stack_off[-3])
        print 'argv-base', hex(stack_off[-2])
        print 'argc-base', hex(stack_off[-1])
        print 'STACK_PTR', hex(stack_ptr)

    # TODO: where should this go?
    #state.pc         = entrypoint
    state.breakpoint = r_uint(breakpoint)

    # initialize processor registers
    state.rf[0] = 0  # ptr to func to run when program exits, disable
    state.rf[1] = stack_off[6]  # argument 1 reg = argv ptr addr
    state.rf[2] = stack_off[5]  # argument 2 reg = envp ptr addr
    if EMULATE_SIMIT:
        state.rf[1] = argc  # argument 1 reg = argc
        state.rf[2] = stack_off[6]  # argument 2 reg = argv ptr addr
    state.rf[13] = stack_ptr  # stack pointer reg
    state.rf[15] = entrypoint  # program counter

    if debug.enabled('bootstrap'):
        state.rf.print_regs(per_row=4)
        print '=' * 20, 'end bootstrap', '=' * 20

    return state