Ejemplo n.º 1
0
def test_suboperation_get_opcodeinfo_scenario2(mnemonic):
    """Tests for get_opcodeinfo function."""
    chip = Processor()
    opcode = '{"opcode": -1, "mnemonic": "N/A"}'

    chip_opcode = str(get_opcodeinfo(chip, '', mnemonic)).replace('\'', '"')
    assert chip_opcode == opcode
Ejemplo n.º 2
0
def deal_with_custom_opcode(chip: Processor, parts: list, constant: bool,
                            opcode: str, address: int,
                            p_line: int) -> Tuple[str, int, int]:
    err = False
    if (parts[0][len(parts[0]) - 1] != ',' and not constant):
        if (opcode == 'ld()' or opcode[:2] == 'ld'):
            opcode = 'ld '
        if opcode not in ('org', '/', 'end', 'pin', '='):
            opcodeinfo = get_opcodeinfo(chip, 'S', opcode)
            if opcodeinfo == {'opcode': -1, 'mnemonic': 'N/A'}:
                err = "FATAL: Pass 1:  Invalid mnemonic '" + \
                    opcode + "' at line: " + str(p_line + 1)
            else:
                address = address + opcodeinfo['words']
    return err, opcode, address
Ejemplo n.º 3
0
def test_suboperation_get_opcodeinfo_scenario1(values):
    """Tests for get_opcodeinfo function."""
    chip = Processor()

    opcode = values[0]
    mnemonic = values[1]
    exetime = values[2]
    bit1 = values[3]
    bit2 = values[4]
    words = values[5]

    opcode = '{"opcode": ' + str(opcode) + ', "mnemonic": "' + \
        mnemonic + '", "exe": ' + str(exetime) + ','
    opcode = opcode + ' "bits": ["' + bit1 + '", "' + \
        bit2 + '"], "words": ' + str(words) + '}'

    chip_opcode = str(get_opcodeinfo(chip, '', mnemonic)).replace('\'', '"')
    assert chip_opcode == opcode
Ejemplo n.º 4
0
def assemble(program_name: str, object_file: str, chip: Processor,
             quiet: bool, type: str) -> bool:
    """
    Main two-pass assembler for i4004 code.

    Parameters
    ----------
    program_name: str, mandatory
        Name of the source file to load

    object_file: str, mandatory
        Name of the output file in which to place the object code

    chip: Processor, mandatory
        Instance of a processor to place the assembled code in.

    quiet: bool, mandatory
        Determines whether quiet mode is on i.e. no output.

    type: str, mandatory
        Determines the type of output file(s) to create.

    Returns
    -------
    True if the code assembles correctly
    False if there are errors in the code

    Raises
    ------
    N/A

    Notes
    -----
    N/A

    """

    #     mccabe: MC0001 / assemble is too complex (44) - start
    #     ...
    #     mccabe: MC0001 / assemble is too complex (10)
    #     SonarLint: S3776: assemble is too complex (25) - start

    # Pass 0 - Initialise label tables, program storage etc
    _labels, tps, tfile = pass0(chip)

    # Program Line Count
    count = 0

    # Pass 1
    err, _labels, tps, tfile, address = pass1(chip, program_name,
                                              _labels, tps, tfile, quiet)

    if err:
        do_error(err + "\nProgram Assembly halted @ Pass 1\n\n")
        return False

    # Pass 2
    print_messages(quiet, 'ASM', chip, '')

    org_found = False
    location = ''

    while True:
        line = tfile[count].strip()
        if len(line) == 0:
            break  # End of code
        x = line.split()
        label = ''

        # Check for initial comments
        if line[0] == '/':
            asm_comment(label, count, line, quiet)
        else:
            opcode = x[0]
            if x[0][-1] == ',':
                label = x[0]
                opcode = x[1]
                # Check to see if we are assembling a label
                if '0' <= str(opcode)[:1] <= '9':
                    tps = asm_label(tps, address, x, count, label)
                    break

            opcodeinfo = get_opcodeinfo(chip, 'S', opcode)
            chip, x, _labels, address, tps, opcodeinfo, label, count, \
                err, org_found, location = \
                asm_main(chip, x, _labels, address, tps, opcode,
                         opcodeinfo, label, count, org_found,
                         location, quiet)
        if err:
            do_error(err)
            break

        count = count + 1

    if err:
        print("Program Assembly halted")
        return False

    # Wrap up assembly process and write to file if necessary.
    chip = wrap_up(chip, location, tps, _labels, object_file, quiet, type)
    return True
Ejemplo n.º 5
0
def asm_others(chip: Processor, x: list, count: int, opcode: str,
               tps: list, address: int, label: str, quiet: bool) \
                   -> Tuple[list, int]:
    """
    Assemble othe instructions.

    Parameters
    ----------
    chip : Processor, mandatory
        The instance of the processor containing the registers, accumulator etc

    x: list, mandatory
        Line of program code (split into component parts).

    count: int, mandatory
        Current assembly program line

    opcode: int, mandatory
       Value of the opcode for assembly

    tps: list, mandatory
        Assembled code

    address: int, mandatory
        address to assemble to

    label: str, mandatory
        Label of the current line (if any)

    quiet: bool, mandatory
        If quiet mode is on

    Returns
    -------
    tps: list
        Assembled code

    address: int
        the address to assemble to

    Raises
    ------
    N/A

    Notes
    -----
    N/A

    """
    d_type = ''
    if int(x[2]) <= 256:
        d_type = 'data8'
    val_left, val_right = split_address8(int(x[2]))
    address_left, address_right = split_address8(address)
    f_opcode = opcode + "(" + x[1] + "," + d_type + ")"
    opcodeinfo = get_opcodeinfo(chip, 'L', f_opcode)
    bit1, bit2 = get_bits(opcodeinfo)
    tps[address] = opcodeinfo['opcode']
    tps[address + 1] = int(x[2])
    if not quiet:
        print_ln(address, label, address_left, address_right, bit1, bit2,
                 val_left, val_right,
                 str(tps[address]) + "," + str(tps[address + 1]), '', '',
                 str(count), opcode, str(x[1]), str(x[2]), '', '')
    address = address + opcodeinfo['words']
    return tps, address
Ejemplo n.º 6
0
def work_with_a_line_of_asm(chip: Processor, line: str,
                            _labels: list, p_line: int,
                            address: int, tfile: list) \
        -> Tuple[Any, list, int, int, list]:
    """
    Analyse a single line of code.

    Parameters
    ----------
    chip: Processor, mandatory
        The instance of the processor containing the registers, accumulator etc

    line: str, mandatory
        line of assembly code read in from a file

    _labels: list, Mandatory
        List for containing labels

    p_line: int, mandatory
        numbered line of assembly language program

    address: int, Mandatory
        Current address of memory for assembly

    tfile: list, Mandatory
        Assembly language store

    Returns
    -------
    err:
        False if no error, error text if error

    tfile: list
        Assembly language store

    p_line: int
        numbered line of assembly language program

    address: int
        Current address of memory for assembly

    _labels: list
        List for containing labels

    Raises
    ------
    N/A

    Notes
    -----
    N/A

    """
    constant = False
    err = False
    # Work with a line of assembly code
    parts = line.split()
    if parts[0][len(parts[0]) - 1] == ',':
        # Found a label, now add it to the label table
        if add_label(_labels, parts[0]) == -1:
            err = ('FATAL: Pass 1: Duplicate label: ' + parts[0] +
                   ' at line ' + str(p_line + 1))
            return err, tfile, p_line, 0, _labels
        # Attach value to a label
        if '0' <= str(parts[1])[:1] <= '9':
            constant = True
            label_content = parts[1]
        else:
            label_content = address
        # An EQUATE statement (indicated by "=")
        if parts[1] == '=':
            constant = True
            label_content = int(parts[2])

        match_label(_labels, parts[0], label_content)
        # Set opcode
        opcode = parts[1][:3]
        if opcode != '=':
            opcodeinfo = get_opcodeinfo(chip, 'S', opcode)
            address = address + opcodeinfo['words']
    else:
        # Set opcode
        opcode = parts[0][:3]
    # Deal with custom opcode
    err, opcode, address = \
        deal_with_custom_opcode(chip, parts, constant, opcode, address, p_line)

    tfile[p_line] = line.strip()
    p_line = p_line + 1
    return err, tfile, p_line, address, _labels
Ejemplo n.º 7
0
def assemble_2(chip: Processor, x: list, opcode: str, address: int,
               tps: list, _labels: list, address_left: str,
               address_right: str, label: str, count: int, quiet: bool) \
        -> Tuple[int, list, list]:
    """
    Function to assemble specific instructions.

    Parameters
    ----------
    chip : Processor, mandatory
        The instance of the processor containing the registers, accumulator etc

    x: list, mandatory
        The current line of code being assembled split into individual elements

    opcode: str, mandatory
        The textual opcode (LD, LDM etc..)

    address: int, mandatory
        Address in memory to place the newly assembled instruction

    tps: list, mandatory
        List representing the memory of the i4004 into which the
        newly assembled instructions will be placed.

    _labels: list, mandatory
        List of valid labels

    address_left, address_right: str, mandatory
        Binary representation of 2 4-bit words representing "address"

    label: str, mandatory
        If there is a label associated with this instruction, it will be here,
        "" otherwise.

    count: int, mandatory
        Assembly line number (used for printing during assembly)

    quiet: bool, mandatory
        If quiet mode is on

    Returns
    -------
    address: int
        After the instruction has been assembled, the incoming address
        is incremented by the number of words in the assembled instruction.

    tps: list
        List representing the memory of the i4004 into which the newly
        assembled instruction has just been placed.

    _labels: list
        Addresses of the labels (pass through only)

    Raises
    ------
    N/A

    Notes
    -----
    N/A

    """
    # pad out for the only 2-character mnemonic
    if opcode == 'ld':
        opcode = 'ld '
    addx = get_label_addr(_labels, x[1])
    if addx == -1:
        addx = x[1]
    f_opcode = opcode + '(' + str(addx) + ')'

    if opcode in ('jun', 'jms'):
        # Special case for JUN and JMS
        if opcode == 'jun':
            decimal_code = 64
        if opcode == 'jms':
            decimal_code = 80
        f_opcode = opcode + '(address12)'
        opcodeinfo = get_opcodeinfo(chip, 'L', f_opcode)
        label_addr = get_label_addr(_labels, x[1])
        label_addr12 = zfl(str(bin(decimal_code))[2:], 8)[:4] + \
            zfl(str(bin(label_addr)[2:]), 12)
        bit1 = label_addr12[:8]
        bit2 = label_addr12[8:]
        tps[address] = int(str(bit1), 2)
        tps[address + 1] = int(str(bit2), 2)
        if not quiet:
            print_ln(address, label, address_left, address_right, bit1[:4],
                     bit1[4:], bit2[:4], bit2[4:],
                     str(tps[address]) + ',' + str(tps[address + 1]), '', '',
                     str(count), opcode, str(x[1]), '', '', '')
        address = address + opcodeinfo['words']
    else:
        if opcode == 'src':
            register = x[1].lower().replace('p', '').replace('r', '')
            f_opcode = 'src(' + register + ')'
        opcodeinfo = get_opcodeinfo(chip, 'L', f_opcode)
        bit1, bit2 = get_bits(opcodeinfo)
        tps[address] = opcodeinfo['opcode']
        if not quiet:
            print_ln(address, label, address_left, address_right, bit1,
                     bit2, '', '', tps[address], '', '', str(count), opcode,
                     str(x[1]), '', '', '')
        address = address + opcodeinfo['words']
    return address, tps, _labels
Ejemplo n.º 8
0
def assemble_jcn(self: Processor, x: list, _labels: list, tps: list,
                 address: int, address_left: str, address_right: str,
                 label: str, count: int,
                 quiet: bool) -> Tuple[int, list, list]:
    """
    Function to assemble JCN instructions.

    Parameters
    ----------
    self : Processor, mandatory
        The instance of the processor containing the registers, accumulator etc

    x: list, mandatory
        The current line of code being assembled split into individual elements

    _labels: list, mandatory
        List of valid labels

    tps: list, mandatory
        List representing the memory of the i4004 into which the
        newly assembled instructions will be placed.

    address: int, mandatory
        Address in memory to place the newly assembled instruction

    address_left, address_right: str, mandatory
        Binary representation of 2 4-bit words representing "address"

    label: str, mandatory
        If there is a label associated with this instruction, it will be here,
        "" otherwise.

    count: int, mandatory
        Assembly line number (used for printing during assembly)

    quiet: bool, mandatory
        If quiet mode is on

    Returns
    -------
    address: int
        After the instruction has been assembled, the incoming address
        is incremented by the number of words in the assembled instruction.

    tps: list
        List representing the memory of the i4004 into which the newly
        assembled instruction has just been placed.

    _labels: list
        Addresses of the labels (pass through only)

    Raises
    ------
    N/A

    Notes
    -----
    N/A

    """
    conditions = x[1].upper()
    dest_label = x[2]
    if '0' <= conditions <= '9':
        bin_conditions = conditions
    else:
        bin_conditions = decode_conditions(conditions)
    f_opcode = 'jcn(' + str(bin_conditions) + ',address8)'
    opcodeinfo = get_opcodeinfo(self, 'L', f_opcode)
    label_addr = int(get_label_addr(_labels, dest_label))
    vl, vr = split_address8(label_addr)
    bit1, bit2 = get_bits(opcodeinfo)
    tps[address] = opcodeinfo['opcode']
    tps[address + 1] = label_addr
    if not quiet:
        print_ln(address, label, address_left, address_right, bit1, bit2, vl,
                 vr,
                 str(tps[address]) + "," + str(tps[address + 1]), '', '',
                 str(count), x[0], str(x[1]), str(x[2]), '', '')
    address = address + opcodeinfo['words']
    return address, tps, _labels
Ejemplo n.º 9
0
def assemble_fim(self: Processor, x: list, _labels: list, tps: list,
                 address: int, label: str, count: int,
                 quiet: bool) -> Tuple[int, list, list]:
    """
    Function to assemble FIM instruction.

    Parameters
    ----------
    self : Processor, mandatory
        The instance of the processor containing the registers, accumulator etc

    x: list, mandatory
        The current line of code being assembled split into individual elements

    _labels: list, mandatory
        List of valid labels

    tps: list, mandatory
        List representing the memory of the i4004 into which the
        newly assembled instructions will be placed.

    address: int, mandatory
        Current program counter address

    label: str, mandatory
        If there is a label associated with this instruction, it will be here,
        "" otherwise.

    count: int, mandatory
        Assembly line number (used for printing during assembly)

    quiet: bool, mandatory
        If quiet mode is on

    Returns
    -------
    address: int
        After the instruction has been assembled, the incoming address
        is incremented by the number of words in the assembled instruction.

    tps: list
        List representing the memory of the i4004 into which the newly
        assembled instruction has just been placed.

    _labels: list
        Addresses of the labels (pass through only)

    Raises
    ------
    N/A

    Notes
    -----
    N/A

    """
    f_opcode = x[0] + '(' + x[1] + ',data8)'
    opcodeinfo = get_opcodeinfo(self, 'L', f_opcode)
    tps[address] = opcodeinfo['opcode']
    tps[address + 1] = int(x[2])
    bit1, bit2 = get_bits(opcodeinfo)
    if not quiet:
        print_ln(address, label, '', '', bit1, bit2, '', '',
                 str(tps[address]) + "," + str(tps[address + 1]), '', '',
                 str(count), x[0], str(x[1]), '', str(x[2]), '')
    address = address + opcodeinfo['words']
    return address, tps, _labels