Source code for eight_bit_computer.operations.addc_op

"""
The ADDC operation

Adds a value to the accumulator, adding an extra 1 if the overflow flag
is set.
"""

import copy

from ..language_defs import (
    INSTRUCTION_GROUPS,
    MODULE_CONTROL,
    ALU_OPERANDS,
    ALU_OPERATIONS,
    ALU_CONTROL_FLAGS,
    FLAGS,
    instruction_byte_from_bitdefs,
)
from ..operation_utils import assemble_instruction, match_and_parse_line
from ..data_structures import (
    get_arg_def_template, get_machine_code_byte_template
)


_NAME = "ADDC"

[docs]def generate_microcode_templates(): """ Generate microcode for the ADDC instruction. Returns: list(DataTemplate): DataTemplates for all the ADDC instructions. """ data_templates = [] signatures = generate_signatures() for signature in signatures: templates = generate_operation_templates(signature) data_templates.extend(templates) return data_templates
[docs]def generate_signatures(): """ Generate all the argument signatures for the ADDC operation. Returns: list(list(dict)): All possible signatures, See :func:`~.get_arg_def_template` for more information on an argument definition dictionary. """ signatures = [] alu_args = ("A", "B", "C") for alu_arg in alu_args: arg_def = get_arg_def_template() arg_def["value_type"] = "module_name" arg_def["is_memory_location"] = False arg_def["value"] = alu_arg signatures.append([arg_def]) arg_def = get_arg_def_template() arg_def["value_type"] = "constant" arg_def["is_memory_location"] = False signatures.append([arg_def]) return signatures
[docs]def generate_operation_templates(signature): """ Create the DataTemplates to define a ADDC with the given signature. Args: signature (list(dict)): List of argument definitions that specify which particular ADDC operation to generate templates for. Returns: list(DataTemplate) : DataTemplates that define the operation with this signature. """ data_templates = [] instruction_byte_bitdefs = generate_instruction_byte_bitdefs(signature) initial_control_steps = get_calculation_control_steps(signature) data_templates.extend( generate_true_data_templates( instruction_byte_bitdefs, initial_control_steps ) ) data_templates.extend( generate_false_data_templates( instruction_byte_bitdefs, initial_control_steps ) ) return data_templates
[docs]def get_calculation_control_steps(signature): """ Get control steps that calcuate the new value. Args: signature (list(dict)): List of argument definitions that specify which particular ADDC operation to generate templates for. Returns: list(list(str)): List of list of bitdefs that specify the control steps. Raises: ValueError: When the signature's first argument type is not a module name or constant. """ control_steps = [] # If we're adding a module to ACC if signature[0]["value_type"] == "module_name": step_0 = [ MODULE_CONTROL[signature[0]["value"]]["OUT"], MODULE_CONTROL["ALU"]["STORE_RESULT"], MODULE_CONTROL["ALU"]["STORE_FLAGS"], ] control_steps.append(step_0) # Else if we're adding a constant to ACC elif signature[0]["value_type"] == "constant": step_0 = [ MODULE_CONTROL["PC"]["OUT"], MODULE_CONTROL["MAR"]["IN"], ] step_1 = [ MODULE_CONTROL["RAM"]["SEL_PROG_MEM"], MODULE_CONTROL["RAM"]["OUT"], MODULE_CONTROL["ALU"]["STORE_RESULT"], MODULE_CONTROL["ALU"]["STORE_FLAGS"], MODULE_CONTROL["PC"]["COUNT"], ] control_steps.append(step_0) control_steps.append(step_1) # Else something odd has happened else: raise ValueError("ADDC argument 0 is not a module name or constant") return control_steps
[docs]def generate_true_data_templates( instruction_byte_bitdefs, initial_control_steps ): """ Create datatemplates for an ADDC where an extra bit is needed. Args: instruction_byte_bitdefs (list(str)): List of the bitdefs that make up the instruction byte. initial_control_steps (list(list(str))) : List of list of bitdefs that specify the control steps. Returns: list(DataTemplate): : List of DataTemplates that describe the ADDC for this signature when the carry flag is high. """ initial_control_steps_copy = copy.deepcopy(initial_control_steps) initial_control_steps_copy[-1].extend( ALU_CONTROL_FLAGS["A_PLUS_B_PLUS_1"] ) update_acc_control_step = [ MODULE_CONTROL["ALU"]["OUT"], MODULE_CONTROL["ACC"]["IN"], ] control_steps = [] control_steps.extend(initial_control_steps) control_steps.append(update_acc_control_step) return assemble_instruction( instruction_byte_bitdefs, [FLAGS["CARRY_BORROW"]["HIGH"]], control_steps )
[docs]def generate_false_data_templates( instruction_byte_bitdefs, initial_control_steps ): """ Create datatemplates for an ADDC where an extra bit is not needed. Args: instruction_byte_bitdefs (list(str)): List of the bitdefs that make up the instruction byte. initial_control_steps (list(list(str))) : List of list of bitdefs that specify the control steps. Returns: list(DataTemplate): : List of DataTemplates that describe the ADDC for this signature when the carry flag is low. """ initial_control_steps_copy = copy.deepcopy(initial_control_steps) initial_control_steps_copy[-1].extend( ALU_CONTROL_FLAGS["A_PLUS_B"] ) update_acc_control_step = [ MODULE_CONTROL["ALU"]["OUT"], MODULE_CONTROL["ACC"]["IN"], ] control_steps = [] control_steps.extend(initial_control_steps_copy) control_steps.append(update_acc_control_step) return assemble_instruction( instruction_byte_bitdefs, [FLAGS["CARRY_BORROW"]["LOW"]], control_steps )
[docs]def generate_instruction_byte_bitdefs(signature): """ Generate bitdefs to specify the instruction byte for this signature. Args: signature (list(dict)): List of argument definitions that specify which particular simple ALU operation to generate the instruction byte bitdefs for. Returns: list(str): Bitdefs that make up the instruction_byte """ if signature[0]["value_type"] == "module_name": bitdefs = [ INSTRUCTION_GROUPS["ALU"], ALU_OPERATIONS["ADDC"], ALU_OPERANDS[signature[0]["value"]], ] elif signature[0]["value_type"] == "constant": bitdefs = [ INSTRUCTION_GROUPS["ALU"], ALU_OPERATIONS["ADDC"], ALU_OPERANDS["ACC/CONST"], ] return bitdefs
[docs]def parse_line(line): """ Parse a line of assembly code to create machine code byte templates. If a line is not identifiably an ADDC assembly line, return an empty list instead. Args: line (str): Assembly line to be parsed. Returns: list(dict): List of machine code byte template dictionaries or an empty list. """ match, signature = match_and_parse_line( line, _NAME, generate_signatures() ) if not match: return [] instruction_byte = instruction_byte_from_bitdefs( generate_instruction_byte_bitdefs(signature) ) mc_bytes = [] mc_byte = get_machine_code_byte_template() mc_byte["byte_type"] = "instruction" mc_byte["bitstring"] = instruction_byte mc_bytes.append(mc_byte) if signature[0]["value_type"] == "constant": mc_byte = get_machine_code_byte_template() mc_byte["byte_type"] = "constant" mc_byte["constant"] = signature[0]["value"] mc_bytes.append(mc_byte) return mc_bytes