Example #1
0
    def __init__(self, panel_desc, led_domain="sync"):
        self.pd = panel_desc
        self.gp = GammaParameters(gamma=2.5, bpp=8)

        self.panel = FramebufferedHUB75Driver(self.pd,
                                              led_domain=led_domain,
                                              gamma_params=self.gp)

        self.cpu_rom = Memory(width=16,
                              depth=256,
                              init=Instr.assemble(firmware(self.gp.bpp)))
        self.cpu_core = CoreFSM(alsru_cls=ALSRU_4LUT, memory=self.cpu_rom)
Example #2
0
    def __init__(self, panel_shape):
        # panel shape: physical (width, height) in LEDs
        # i.e. width is how many pixels to shift out per row
        # and height is 2**(addr_bits)/2 (assuming two rows are driven at once)
        self.panel_shape = panel_shape

        self.ftg = FrameTimingGenerator(panel_shape)
        self.pbr0 = PixelBuffer(panel_shape)

        self.cpu_rom = Memory(width=16,
                              depth=256,
                              init=Instr.assemble(firmware()))
        self.cpu_core = CoreFSM(alsru_cls=ALSRU_4LUT, memory=self.cpu_rom)
Example #3
0
 def firmware(self, fw=None):
     log.info("Attach firmware")
     # compile and attach the firmware
     if fw is None:
         raise BuildException("No firmware")
     fw = Instr.assemble(fw)
     self.fw = fw
     if len(fw) > self.mem_size - 4 * 8:  # some space for the window stack
         raise BuildException("Firmware too long")
     log.info("Firmware is {:d}/{:d} ({:.2f}% of mem) words long".format(
         len(fw), self.mem_size,
         100.0 * (float(len(fw)) / float(self.mem_size))))
     self.fw = fw
     self.memory.init = fw
Example #4
0
    def __init__(self, panel_desc, led_domain="sync"):
        self.pd = panel_desc
        self.gp = GammaParameters(gamma=2.5, bpp=8)

        self.panel = FramebufferedHUB75Driver(self.pd,
                                              led_domain=led_domain,
                                              gamma_params=self.gp)

        self.cpu_rom = Memory(width=16,
                              depth=512,
                              init=Instr.assemble(firmware(self.gp.bpp)))
        self.cpu_ram = SPRAM()
        self.cpu_core = CoreFSM(alsru_cls=ALSRU_4LUT)

        self.uart = uart.SimpleUART(
            default_divisor=uart.calculate_divisor(12e6, 115200))
def make_firmware(controllers, priming_latches,
        apu_freq_basic=None,
        apu_freq_advanced=None):

    num_controllers = len(controllers)
    buf_size = calc_buf_size(num_controllers)
    # convert controllers from list of names to list of absolute register
    # addresses because that's what the system writes to
    controller_addrs = []
    for controller in controllers:
        try:
            addr = controller_name_to_addr[controller]
        except IndexError:
            raise ValueError("unknown controller name '{}'".format(
                controller)) from None
        controller_addrs.append(addr)

    if apu_freq_basic is None and apu_freq_advanced is not None:
        raise ValueError("must set apu basic before advanced")

    num_priming_latches = len(priming_latches)//num_controllers
    if len(priming_latches) % num_controllers != 0:
        raise ValueError("priming latches must have {} words per latch".format(
            num_controllers))
    if num_priming_latches == 0:
        raise ValueError("must have at least one priming latch")

    if num_priming_latches > buf_size:
        raise ValueError("too many priming latches: got {}, max is {}".format(
            num_priming_latches, buf_size))

    fw = [
        # start from "reset" (i.e. download is finished)
        
        # set up initial register window. we get a free one from the bootloader
        # (so that we can load a register with the window address), but we can't
        # keep using it.
        MOVI(R0, INITIAL_REGISTER_WINDOW),
        STW(R0),

        # set UART receive timeout to about 2ms. we can't afford to be waiting!
        MOVI(R0, int((12e6*(2/1000))/256)),
        STXA(R0, p_map.uart.w_rt_timer),
        # same timeout for the status timer, just cause it's already in the
        # register. once it expires, the correct value will be loaded.
        STXA(R0, p_map.timer.timer[0].w_value),
    ]

    # out of reset, the button registers are all zero, the APU frequency is
    # 24.607104MHz, and latching is disabled. as long as latching remains
    # disabled, the frequency won't change and the console will see no buttons
    # no matter how much it latches.

    # set the initial APU frequency values
    if apu_freq_basic is not None:
        fw.append([
            MOVI(R2, int(apu_freq_basic) & 0xFFFF),
            STXA(R2, p_map.snes.w_apu_freq_basic),
        ])
    if apu_freq_advanced is not None:
        fw.append([
            MOVI(R2, int(apu_freq_advanced) & 0xFFFF),
            STXA(R2, p_map.snes.w_apu_freq_advanced),
        ])
    # force a latch so the APU clock generator gets updated
    fw.append(STXA(R2, p_map.snes.w_force_latch))

    # load the initial buttons into the registers
    for controller_i, controller_addr in enumerate(controller_addrs):
        fw.append([
            MOVI(R2, priming_latches[controller_i]),
            STXA(R2, controller_addr),
        ])

    # now that the registers are loaded, we can turn latching back on. this
    # setup guarantees the console will transition directly from seeing no
    # buttons to seeing the first set of buttons once it latches. there can't be
    # any intermediate states.
    fw.append([
        MOVI(R2, 1),
        STXA(R2, p_map.snes.w_enable_latch),
    ])

    # initialization is done. let's get the party started!
    fw.append(J("main_loop"))

    fw.append(send_status_packet(buf_size))
    fw.append(main_loop_body())
    fw.append(rx_comm_word())
    fw.append(cmd_send_latches(controller_addrs, buf_size))

    # define all the variables
    defs = [0]*len(Vars)
    # the buffer is primed with some latches so that we can start before
    # communication gets reestablished. but we put one in the interface at the
    # beginning
    defs[Vars.buf_head] = num_priming_latches-1
    defs[Vars.stream_pos] = num_priming_latches
    fw.append([
    L("vars"),
        defs
    ])

    # include all the functions
    fw.append([
    L("handle_error"),
        f_handle_error(),
    L("update_interface"),
        f_update_interface(controller_addrs, buf_size),
    ])

    # header reception is called once so we stick it far away
    fw.append(rx_header())

    # assemble just the code region
    assembled_fw = Instr.assemble(fw)
    fw_len = len(assembled_fw)
    if len(assembled_fw) > FW_MAX_LENGTH:
        raise ValueError(
            "firmware length {} is over max of {} by {} words".format(
                fw_len, FW_MAX_LENGTH, fw_len-FW_MAX_LENGTH))
    elif False:
        print("firmware length {} is under max of {} by {} words".format(
            fw_len, FW_MAX_LENGTH, FW_MAX_LENGTH-fw_len))

    # pad it out until the latch buffer starts
    assembled_fw.extend([0]*(LATCH_BUF_START-len(assembled_fw)))
    # then fill it with the priming latches (skipping the one we stuck in the
    # interface at the beginning)
    assembled_fw.extend(priming_latches[num_controllers:])

    return assembled_fw
Example #6
0
            Rem("Jump table select"),
            sel(),
            ll("exit"),
        ]


if __name__ == "__main__":
    r = CharPad.SplitChomp()
    print(r.code())
    if False:
        log.critical("TESTING")
        console = Console()
        w = Window()
        w.req("val")
        ll = LocalLabels()
        s.test = "this is a test"
        w.req(["pad", "value"])
        cs = Switch(w, w.val)
        cs.add(("c", [ll("a")]))
        cs.add(("r", [ll("b")]))
        cs.add(("s", [ll("c")]))
        cs.add((43, [ll("d")]))
        cs.add((10, [ll("e")]))
        cs.add((13, [ll("f")]))
        d = cs.dump()
        print(d)
        r = Instr.assemble(d)
        d = Instr.disassemble(r)
        print(r)
        print(d)
Example #7
0
            L(self.label),
            #            self.ref(self.next),
            Ref(self.next),
            self.commname.as_mem(),
            ADJW(-8),
            LDW(R6, 0),
            self.instr(),
            ADJW(8),
            JR(R7, 0),
        ]


if __name__ == "__main__":
    c = MetaCommand.code()
    print(c)
    fw = Instr.assemble(c)
    print(fw)

# working jump refs


def test():
    def jump_table(*args):
        def relocate(resolver):
            return [resolver(arg) for arg in args]

        return relocate

    def ref(val):
        def relocate(resolver):
            return resolver(val)
        m = Module()
        m.submodules.core = core = self.core

        leds = Cat(platform.request("led", n) for n in range(4))
        with m.If(core.o_ext_we & (core.o_bus_addr == 0x0000)):
            m.d.sync += leds.eq(core.o_ext_data)

        return m


def firmware():
    period = 3300000 // (4 * 3)  # 4 CPI, 3 instructions
    return [
        MOVI(R7, 0xa),
        L("blink"),
        XORI(R7, R7, 0xf),
        STXA(R7, 0),
        MOVI(R1, period & 0xffff),
        MOVI(R2, period >> 16),
        L("loop"),
        SUBI(R1, R1, 1),
        SBBI(R2, R2, 0),
        JNZ("loop"),
        J("blink"),
    ]


if __name__ == "__main__":
    design = BonelessDemo(firmware=Instr.assemble(firmware()))
    ICE40HX1KBlinkEVNPlatform().build(design, do_program=True)
Example #9
0
def make_bootloader(info_words):
    cleaned_info_words = [int(info_word) & 0xFFFF for info_word in info_words]
    if len(cleaned_info_words) != 4:
        raise ValueError("expected exactly four info words")
    cleaned_info_words.append(0)
    cleaned_info_words.append(0)
    cleaned_info_words.append(GATEWARE_VERSION)
    cleaned_info_words.append(BOOTLOADER_VERSION)

    fw = [
        L("reset"),
        # start from reset. we are always going to start from reset, so we don't
        # have to worry about e.g. changing peripherals back to default modes.

        # set UART receive timeout to about 150ms
        MOVI(R0, int((12e6 * (150 / 1000)) / 256)),
        STXA(R0, p_map.uart.w_rt_timer),
    ]
    r = RegisterManager("R7:lr R6:comm_word R5:temp R4:cmd_status "
                        "R2:param2 R1:param1 R0:command")
    fw.append([
        L("main_loop"),
        # clear any UART errors and reset the receive timeout
        MOVI(r.temp, 0xFFFF),
        STXA(r.temp, p_map.uart.w_error_clear),
        L("rx_header_lo"),  # wait to get the header low byte (0x5A)
        # check for UART errors (timeouts, overflows, etc.)
        LDXA(r.temp, p_map.uart.r_error),
        AND(r.temp, r.temp, r.temp),  # set flags
        BZ0("main_loop"),
        # get a new byte and check if it matches. we don't bother checking if we
        # got anything because it won't match in that case and we just loop
        # until it does
        LDXA(r.temp, p_map.uart.r_rx_hi),
        CMPI(r.temp, 0x5A << 7),
        BNE("rx_header_lo"),
        L("rx_header_hi"),  # do the same for the header high byte (0x7A)
        # check for UART errors (timeouts, overflows, etc.)
        LDXA(r.temp, p_map.uart.r_error),
        AND(r.temp, r.temp, r.temp),  # set flags
        BZ0("main_loop"),
        # get a new byte and check if it matches. if we didn't get anything we
        # try to receive the high byte again.
        LDXA(r.temp, p_map.uart.r_rx_hi),
        ADD(r.temp, r.temp, r.temp),
        BC1("rx_header_hi"),
        # if we actually got the first byte, go back to looking for the second
        CMPI(r.temp, 0x5A << 8),
        BEQ("rx_header_hi"),
        CMPI(r.temp, 0x7A << 8),
        BNE("main_loop"),

        # we have confirmed both header bytes. who knows what the CRC is now.
        STXA(r.temp, p_map.uart.w_crc_reset),  # write something to reset it

        # receive the four packet words
        JAL(r.lr, "rx_word"),
        MOV(r.command, r.comm_word),
        JAL(r.lr, "rx_word"),
        MOV(r.param1, r.comm_word),
        JAL(r.lr, "rx_word"),
        MOV(r.param2, r.comm_word),
        JAL(r.lr, "rx_word"),
        # if the current CRC is x, then CRC(x) = 0, always. we use to reset the
        # CRC to 0 when we are done sending or receiving.
        # so, we've received all the data words and the CRC. if everything went
        # okay, the CRC should now be 0.
        LDXA(r.temp, p_map.uart.r_crc_value),
        AND(r.temp, r.temp, r.temp),
        BZ("crc_ok"),

        # aw heck, it didn't go okay. send the appropriate error.
        MOVI(r.cmd_status, 1),
        J("send_final_response_packet"),
        L("crc_ok"),
        # now we need to figure out the command.
        # the low 8 bits are the length, which is always 2.
        SUBI(r.command, r.command, 2),
        # the high 8 bits are the command number, starting from 1
        MOVI(r.temp, 0x100),
        # assume the handler wants to say success
        MOVI(r.cmd_status, 3),
        SUB(r.command, r.command, r.temp),  # command 1
        # hello command: we just need to transmit a success packet back, and the
        # status is already set accordingly
        BEQ("send_final_response_packet"),
        SUB(r.command, r.command, r.temp),  # command 2
        BEQ("sys_cmd_write_data"),
        SUB(r.command, r.command, r.temp),  # command 3
        BEQ("sys_cmd_jump_to_code"),
        SUB(r.command, r.command, r.temp),  # command 4
        BEQ("sys_cmd_read_data"),

        # if the command is unknown or the length is wrong, none of the above
        # will have matched. send the appropriate error.
        MOVI(r.cmd_status, 0),
        # fall through
    ])
    r -= "command"

    r += "R0:send_lr"
    fw.append([
        L("send_final_response_packet"),
        # return to main loop
        MOVR(r.lr, "main_loop"),
        L("send_response_packet"),
        # save LR because we need to reuse it to call the tx function
        MOV(r.send_lr, r.lr),
        # send out the header first
        MOVI(r.comm_word, 0x7A5A),
        JAL(r.lr, "tx_word"),
        # reset CRC so the packet CRC is calculated correctly
        STXA(r.send_lr, p_map.uart.w_crc_reset),  # we can write anything
        # the command is always the same: length 1 type 1
        MOVI(r.comm_word, 0x0101),
        JAL(r.lr, "tx_word"),
        # then the status code
        MOV(r.comm_word, r.cmd_status),
        JAL(r.lr, "tx_word"),
        # last is the CRC, but the CRC of the last byte is still being
        # calculated right now. reading it this instruction gives garbage.
        MOV(r.lr, r.send_lr),  # so prepare to return to our caller
        # now we can read and send it (and sending it resets the CRC to 0)
        LDXA(r.comm_word, p_map.uart.r_crc_value),
        # tx_word will return back to our caller in r.lr
        J("tx_word"),
    ])
    r -= "send_lr param2 param1"

    r += "R2:length R1:dest_addr"
    # generate random prefix so that we effectively can make local labels
    lp = "_{}_".format(random.randrange(2**32))
    fw.append([
        L("sys_cmd_write_data"),
        # transmit back a success packet. the status is already set correctly.
        JAL(r.lr, "send_response_packet"),
        # if the length is 0, we are already done. send the second response.
        AND(r.length, r.length, r.length),
        BZ("send_final_response_packet"),
        L(lp + "write"),
        JAL(r.lr, "rx_word"),
        ST(r.comm_word, r.dest_addr, 0),
        ADDI(r.dest_addr, r.dest_addr, 1),
        SUBI(r.length, r.length, 1),
        BNZ(lp + "write"),
        # receive the CRC too
        JAL(r.lr, "rx_word"),
        # now, if everything was correct, the CRC in the UART will be zero
        LDXA(r.temp, p_map.uart.r_crc_value),
        AND(r.temp, r.temp, r.temp),
        BZ("send_final_response_packet"),  # it was! (status already = success)
        # it wasn't. send the appropriate error
        MOVI(r.cmd_status, 1),
        J("send_final_response_packet"),
    ])
    r -= "length dest_addr"

    r += "R2:param2 R1:code_addr"
    fw.append([
        L("sys_cmd_jump_to_code"),
        # transmit back a success packet. the status is already set correctly.
        JAL(r.lr, "send_response_packet"),
        # then jump to the code and let it do its thing
        JR(r.code_addr, 0),
    ])
    r -= "param2 code_addr"

    r += "R2:length R1:source_addr"
    lp = "_{}_".format(random.randrange(2**32))
    fw.append([
        L("sys_cmd_read_data"),
        # transmit back a success packet. the status is already set correctly.
        JAL(r.lr, "send_response_packet"),
        # if the length is 0, we are already done. send the second response
        AND(r.length, r.length, r.length),
        BZ("send_final_response_packet"),
        L(lp + "read"),
        LD(r.comm_word, r.source_addr, 0),
        JAL(r.lr, "tx_word"),
        ADDI(r.source_addr, r.source_addr, 1),
        SUBI(r.length, r.length, 1),
        BNZ(lp + "read"),
        # send the CRC too (which resets the CRC to 0)
        LDXA(r.comm_word, p_map.uart.r_crc_value),
        JAL(r.lr, "tx_word"),
        # send the final success packet (status is already set)
        J("send_final_response_packet"),
    ])
    r -= "length source_addr"

    lp = "_{}_".format(random.randrange(2**32))
    fw.append([
        L("rx_word"),
        # check for UART errors (timeouts, overflows, etc.)
        LDXA(r.temp, p_map.uart.r_error),
        AND(r.temp, r.temp, r.temp),  # set flags
        BZ0(lp + "error"),
        # check if we have a new byte
        LDXA(r.temp, p_map.uart.r_rx_lo),
        ROLI(r.temp, r.temp, 1),
        BS1("rx_word"),
        # we have the low byte in temp
        L(lp + "rx_hi"),
        # check again for UART errors
        LDXA(r.comm_word, p_map.uart.r_error),
        AND(r.comm_word, r.comm_word, r.comm_word),
        BZ0(lp + "error"),
        # and see if we have the high byte yet
        LDXA(r.comm_word, p_map.uart.r_rx_hi),
        ADD(r.comm_word, r.comm_word, r.comm_word),
        BC1(lp + "rx_hi"),
        # put the bytes together
        OR(r.comm_word, r.comm_word, r.temp),
        # and we are done
        JR(r.lr, 0),
        L(lp + "error"),
        # load RX error status code
        MOVI(r.cmd_status, 2),
        # and send the error packet (it will return to the main loop)
        J("send_final_response_packet"),
    ])

    lp = "_{}_".format(random.randrange(2**32))
    fw.append([
        L("tx_word"),
        # wait for buffer space
        LDXA(r.temp, p_map.uart.r_tx_status),
        ANDI(r.temp, r.temp, 1),
        BZ0("tx_word"),
        # then send the low byte
        STXA(r.comm_word, p_map.uart.w_tx_lo),
        # and repeat for the high byte
        L(lp + "tx_hi"),
        LDXA(r.temp, p_map.uart.r_tx_status),
        ANDI(r.temp, r.temp, 1),
        BZ0(lp + "tx_hi"),
        STXA(r.comm_word, p_map.uart.w_tx_hi),
        # and we're done
        JR(r.lr, 0),
        # WARNING! the CRC is still being calculated, so reading it immediately
        # after this function returns will return garbage
    ])

    # assemble just the code region
    assembled_fw = Instr.assemble(fw)
    fw_len = len(assembled_fw)
    if len(assembled_fw) > FW_MAX_LENGTH:
        raise ValueError(
            "bootrom length {} is over max of {} by {} words".format(
                fw_len, FW_MAX_LENGTH, fw_len - FW_MAX_LENGTH))
    elif False:
        print("bootrom length {} is under max of {} by {} words".format(
            fw_len, FW_MAX_LENGTH, FW_MAX_LENGTH - fw_len))

    # pad the code region out to line up the info words
    assembled_fw.extend([0] * (FW_MAX_LENGTH - fw_len))

    # glue on the info words
    assembled_fw.extend(cleaned_info_words)
    # then the (initially zero) RAM region
    assembled_fw.extend([0] * 64)

    return assembled_fw
Example #10
0
def boneload(firmware, port, ram_only=True):
    import serial

    firmware = Instr.assemble(firmware)
    print("Connecting...")
    ser = serial.Serial(port, 115200, timeout=0.5)
    print("Identifying (reset board please)...")
    while True:
        try:
            ident = _bl_identify(ser)
            break
        except Timeout:
            pass

    if ident[0] != 1:
        raise Exception("incompatible version {}".format(ident[0]))

    print("Identified! Board ID=0x{:02X}, max length={}".format(*ident[1:]))
    print("Downloading program to RAM...")
    _bl_write_data(ser, 0, firmware, ident[2])
    print("Verifying RAM...")
    correct_crc = _crc(firmware)
    calc_crc = _bl_crc(ser, 0, len(firmware))
    if calc_crc != correct_crc:
        raise Exception("verification failed!", calc_crc, correct_crc)

    if ram_only:
        print("Beginning execution...")
        _bl_jump_to_code(ser, 0, 0xFFF)
        print("Complete!")
        return

    return  # hard return until the flash is safe
    print("Awakening flash...")
    _bl_flash_txn_imm(ser, ident[2], write_data=[0xAB], deassert_cs=True)
    # it takes a couple microseconds to wake up, which parsing this comment
    # has already wasted
    print("Reading flash ID...")
    _bl_flash_txn_imm(ser, ident[2], write_data=[0x9F])
    fid = _bl_flash_txn_imm(ser, ident[2], read_len=3, deassert_cs=True)
    print("it is: ", end="")
    for x in fid:
        print(hex(x), end=" ")
    print()

    def _flash_wait():
        # wait for BUSY to be off.
        # start reading BUSY register
        _bl_flash_txn_imm(ser, ident[2], write_data=[0x05])
        while True:
            # read its current value
            status = _bl_flash_txn_imm(ser, ident[2], read_len=1)[0]
            if status & 1 == 0:
                break
        # deassert CS and finish command
        _bl_flash_txn_imm(ser, ident[2], write_data=[], deassert_cs=True)

    print("Erasing flash sectors...")
    sector_size = 4096
    num_sectors = (len(firmware) * 2 + sector_size -
                   1) // sector_size  # round up
    for sector in range(num_sectors):
        # enable write access
        _bl_flash_txn_imm(ser, ident[2], write_data=[0x06], deassert_cs=True)
        # do the erase
        addr = ((sector + 32) * sector_size).to_bytes(3, byteorder="big")
        _bl_flash_txn_imm(ser,
                          ident[2],
                          write_data=[0x20, *addr],
                          deassert_cs=True)
        # and wait for it to finish
        _flash_wait()

    print("Programming flash pages...")
    page_size = 256
    num_pages = (len(firmware) * 2 + page_size - 1) // page_size  # round up
    for page in range(num_pages):
        # enable write access
        _bl_flash_txn_imm(ser, ident[2], write_data=[0x06], deassert_cs=True)
        # start program operation
        addr = ((page + 512) * page_size).to_bytes(3, byteorder="big")
        _bl_flash_txn_imm(ser, ident[2], write_data=[0x02, *addr])
        # send bytes from RAM to flash. remember that the flash is in bytes
        # and we count in words.
        _bl_flash_txn(
            ser,
            page * 128,
            write_len=min((len(firmware) - (page * 128)) * 2, 256),
            deassert_cs=True,
        )
        _flash_wait()

    print("Reloading flash data...")
    for page in range(num_pages):
        addr = ((page + 512) * page_size).to_bytes(3, byteorder="big")
        # start read operation
        _bl_flash_txn_imm(ser, ident[2], write_data=[0x0B, *addr, 0])
        # and actually read the data
        _bl_flash_txn(
            ser,
            page * 128,
            read_len=min((len(firmware) - (page * 128)) * 2, 256),
            deassert_cs=True,
        )
    print("Verifying flash...")
    calc_crc = _bl_crc(ser, 0, len(firmware))
    if calc_crc != correct_crc:
        raise Exception("verification failed!", calc_crc, correct_crc)

    print("Beginning execution...")
    _bl_jump_to_code(ser, 0)
    print("Complete!")
Example #11
0
        _flash_wait()

    print("Reloading flash data...")
    for page in range(num_pages):
        addr = ((page + 512) * page_size).to_bytes(3, byteorder="big")
        # start read operation
        _bl_flash_txn_imm(ser, ident[2], write_data=[0x0B, *addr, 0])
        # and actually read the data
        _bl_flash_txn(
            ser,
            page * 128,
            read_len=min((len(firmware) - (page * 128)) * 2, 256),
            deassert_cs=True,
        )
    print("Verifying flash...")
    calc_crc = _bl_crc(ser, 0, len(firmware))
    if calc_crc != correct_crc:
        raise Exception("verification failed!", calc_crc, correct_crc)

    print("Beginning execution...")
    _bl_jump_to_code(ser, 0)
    print("Complete!")


if __name__ == "__main__":
    f = boneload_fw()
    for w in f:
        print(Instr.disassemble([w]))
    x = len(f)
    print("c:", x, "o:", x - 256, "r:", 512 - x)
Example #12
0
from boneless.arch.opcode import Instr
from boneless.arch.opcode import *

from ..gateware.periph_map import p_map
from ..host.bootload import do_bootload

# test program to confirm things are working
fw = [
    L("rx_wait"),
    LDXA(R1, p_map.uart.r_rx_lo),
    ROLI(R1, R1, 1),
    BS1("rx_wait"),
    MOVR(R0, "hi"),
    L("tx_wait"),
    LDXA(R1, p_map.uart.r_tx_status),
    ANDI(R1, R1, 1),
    BZ0("tx_wait"),
    LD(R1, R0, 0),
    CMPI(R1, 0),
    BEQ("rx_wait"),
    STXA(R1, p_map.uart.w_tx_lo),
    ADDI(R0, R0, 1),
    J("tx_wait"),
    L("hi"),
    list(ord(c) for c in "Hello, world!"), 0
]

# bootload the program to the board on the given port
do_bootload(sys.argv[1], Instr.assemble(fw))
Example #13
0
def make_firmware():
    r = RegisterManager("R6:comm_word R5:rxlr R4:temp "
                        "R2:param2 R1:param1 R0:command")
    fw = [
        # start from "reset" (i.e. download is finished)
        # we just use the free register window the bootloader gives us

        # set UART receive timeout to about 100ms. this way reception will be
        # reset if we don't receive a complete command.
        MOVI(R0, int((12e6 * (100 / 1000)) / 256)),
        STXA(R0, p_map.uart.w_rt_timer),
        L("main_loop"),
        # clear any UART errors and reset the receive timeout
        MOVI(r.temp, 0xFFFF),
        STXA(r.temp, p_map.uart.w_error_clear),
        L("rx_header_lo"),  # wait to get the header low byte (0x5A)
        # check for UART errors (timeouts, overflows, etc.)
        LDXA(r.temp, p_map.uart.r_error),
        AND(r.temp, r.temp, r.temp),  # set flags
        BZ0("main_loop"),
        # get a new byte and check if it matches. we don't bother checking if we
        # got anything because it won't match in that case and we just loop
        # until it does
        LDXA(r.temp, p_map.uart.r_rx_hi),
        CMPI(r.temp, 0x5A << 7),
        BNE("rx_header_lo"),
        L("rx_header_hi"),  # do the same for the header high byte (0x7A)
        # check for UART errors (timeouts, overflows, etc.)
        LDXA(r.temp, p_map.uart.r_error),
        AND(r.temp, r.temp, r.temp),  # set flags
        BZ0("main_loop"),
        # get a new byte and check if it matches. if we didn't get anything we
        # try to receive the high byte again.
        LDXA(r.temp, p_map.uart.r_rx_hi),
        ADD(r.temp, r.temp, r.temp),
        BC1("rx_header_hi"),
        # if we actually got the first byte, go back to looking for the second
        CMPI(r.temp, 0x5A << 8),
        BEQ("rx_header_hi"),
        CMPI(r.temp, 0x7A << 8),
        BNE("main_loop"),

        # we have confirmed both header bytes. who knows what the CRC is now.
        STXA(r.temp, p_map.uart.w_crc_reset),  # write something to reset it

        # receive the command packet
        JAL(r.rxlr, "rx_comm_word"),
        MOV(r.command, r.comm_word),
        JAL(r.rxlr, "rx_comm_word"),
        MOV(r.param1, r.comm_word),
        JAL(r.rxlr, "rx_comm_word"),
        MOV(r.param2, r.comm_word),
        JAL(r.rxlr, "rx_comm_word"),
        LDXA(r.temp, p_map.uart.r_crc_value),
        AND(r.temp, r.temp, r.temp),
        BNZ("main_loop"),  # ignore packets with incorrect CRC
        CMPI(r.command, 0x0102),
        BEQ("handle_hello"),
        CMPI(r.command, 0x2002),
        BNE("main_loop"),  # invalid command

        # update APU registers with command values
        STXA(r.param1, p_map.snes.w_apu_freq_basic),
        STXA(r.param2, p_map.snes.w_apu_freq_advanced),
        # write something (anything) to force a latch so the clock generator
        # gets updated with the values we just wrote
        STXA(R0, p_map.snes.w_force_latch),
        J("main_loop"),
        L("handle_hello"),
        # we got a valid hello. reset into the bootloader.
        MOVI(R0, 0xFADE),
        MOVI(R1, 0xDEAD),
        STXA(R0, p_map.reset_req.w_enable_key_fade),
        STXA(R1, p_map.reset_req.w_perform_key_dead),
        J(-1),  # hang until it happens
        L("rx_comm_word"),
        # check for UART errors (timeouts, overflows, etc.)
        LDXA(r.temp, p_map.uart.r_error),
        AND(r.temp, r.temp, r.temp),  # set flags
        BZ0("main_loop"),  # ignore errors and reset reception
        # check if we have a new byte
        LDXA(r.comm_word, p_map.uart.r_rx_lo),
        ROLI(r.comm_word, r.comm_word, 1),
        BS1("rx_comm_word"),
        L("rcw_hi"),
        # check again for UART errors
        LDXA(r.temp, p_map.uart.r_error),
        AND(r.temp, r.temp, r.temp),
        BZ0("main_loop"),
        # and see if we have the high byte yet
        LDXA(r.temp, p_map.uart.r_rx_hi),
        ADD(r.temp, r.temp, r.temp),
        BC1("rcw_hi"),
        # put the bytes together
        OR(r.comm_word, r.comm_word, r.temp),
        # and we are done
        JR(r.rxlr, 0),
    ]

    assembled_fw = Instr.assemble(fw)
    # don't bother measuring the length, it's assuredly less than 16,384 words

    return assembled_fw
Example #14
0
def boneload_fw(uart_addr=0, spi_addr=16):
    return Instr.assemble(_bfw_main(uart_addr, spi_addr))