Source code for eight_bit_computer.operations.rot_left_op

"""
The ROT_LEFT operation.

Moves all the bits in the number one place to the left (most
significant side). If the most significant bit was a 1, then after the
rotation this is set back on the least significant side.

This operation will generate and store (clobber) ALU flags.
"""

from ..language_defs import (
    INSTRUCTION_GROUPS,
    MODULE_CONTROL,
    MODULE_CONTROLS_NONE,
    DEST_REGISTERS,
    SRC_REGISTERS,
    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 = "ROT_LEFT"


[docs]def generate_microcode_templates(): """ Generate microcode for all the ROT_LEFT operations. Returns: list(DataTemplate): DataTemplates for all the ROT_LEFT microcode. """ 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 the definitions of all possible arguments passable. Returns: list(list(dict)): All possible arguments. See :func:`~.get_arg_def_template` for more information. """ signatures = [] # Add module arguments for dest in ("ACC", "A", "B", "C"): signature = [] arg0_def = get_arg_def_template() arg0_def["value_type"] = "module_name" arg0_def["is_memory_location"] = False arg0_def["value"] = dest signature.append(arg0_def) signatures.append(signature) return signatures
[docs]def generate_operation_templates(signature): """ Create the DataTemplates to define a ROT_LEFT with the given args. Args: signature (list(dict)): List of argument definitions that specify which particular operation to generate templates for. Returns: list(DataTemplate) : Datatemplates that define this ROT_LEFT. """ data_templates = [] data_templates.extend(generate_no_carry_datatemplates(signature)) data_templates.extend(generate_with_carry_datatemplates(signature)) return data_templates
[docs]def generate_no_carry_datatemplates(signature): """ Create DataTemplates to define a rottate left with no carry. This is the case where the most significant bit was a zero. Args: signature (list(dict)): List of argument definitions that specify which particular operation to generate templates for. Returns: list(DataTemplate) : Datatemplates that define the "no carry half" of a ROT_LEFT operation. """ control_steps = [] lshift_step = [ MODULE_CONTROL[signature[0]["value"]]["OUT"], MODULE_CONTROL["ALU"]["A_IS_BUS"], MODULE_CONTROL["ALU"]["STORE_FLAGS"], MODULE_CONTROL["ALU"]["STORE_RESULT"], ] lshift_step.extend(ALU_CONTROL_FLAGS["A_PLUS_A"]) control_steps.append(lshift_step) # This is so that the carry and no carry version of this instruction # take the same number of instruction cycles. rot_no_carry_step0 = [ MODULE_CONTROLS_NONE, ] control_steps.append(rot_no_carry_step0) rot_no_carry_step1 = [ MODULE_CONTROL["ALU"]["OUT"], MODULE_CONTROL[signature[0]["value"]]["IN"], ] control_steps.append(rot_no_carry_step1) instruction_byte_bitdefs = generate_instruction_byte_bitdefs(signature) flags_bitdefs = [FLAGS["CARRY_BORROW"]["LOW"]] return assemble_instruction( instruction_byte_bitdefs, flags_bitdefs, control_steps )
[docs]def generate_instruction_byte_bitdefs(signature): """ Generate bitdefs to specify the instruction byte for these args. Args: signature (list(dict)): List of argument definitions that specify which particular operation to generate the instruction byte bitdefs for. Returns: list(str): Bitdefs that make up the instruction_byte """ src_map = { "ACC": SRC_REGISTERS["SP"], "A": SRC_REGISTERS["SP"], "B": SRC_REGISTERS["SP+/-"], "C": SRC_REGISTERS["CONST"], } dest_map = { "ACC": DEST_REGISTERS["SP+/-"], "A": DEST_REGISTERS["CONST"], "B": DEST_REGISTERS["ACC"], "C": DEST_REGISTERS["SP+/-"], } return [ INSTRUCTION_GROUPS["STORE"], src_map[signature[0]["value"]], dest_map[signature[0]["value"]], ]
[docs]def generate_with_carry_datatemplates(signature): """ Create DataTemplates to define a rottate left with a carry. This is the case where the most significant bit was a one. Args: signature (list(dict)): List of argument definitions that specify which particular operation to generate templates for. Returns: list(DataTemplate) : Datatemplates that define the "carry half" of a ROT_LEFT operation. """ control_steps = [] lshift_step = [ MODULE_CONTROL[signature[0]["value"]]["OUT"], MODULE_CONTROL["ALU"]["A_IS_BUS"], MODULE_CONTROL["ALU"]["STORE_FLAGS"], MODULE_CONTROL["ALU"]["STORE_RESULT"], ] lshift_step.extend(ALU_CONTROL_FLAGS["A_PLUS_A"]) control_steps.append(lshift_step) add_one_step = [ MODULE_CONTROL["ALU"]["OUT"], MODULE_CONTROL["ALU"]["A_IS_BUS"], MODULE_CONTROL["ALU"]["STORE_RESULT"], ] add_one_step.extend(ALU_CONTROL_FLAGS["A_PLUS_1"]) control_steps.append(add_one_step) write_back_step = [ MODULE_CONTROL["ALU"]["OUT"], MODULE_CONTROL[signature[0]["value"]]["IN"], ] control_steps.append(write_back_step) instruction_byte_bitdefs = generate_instruction_byte_bitdefs(signature) flags_bitdefs = [FLAGS["CARRY_BORROW"]["HIGH"]] return assemble_instruction( instruction_byte_bitdefs, flags_bitdefs, control_steps )
[docs]def parse_line(line): """ Parse a line of assembly code to create machine code byte templates. If a line is not identifiably an ROT_LEFT assembly line, return an empty list instead. Args: line (str): Assembly line to be parsed. Returns: list(dict): List of instruction byte template dictionaries or an empty list. """ match, signature = match_and_parse_line( line, _NAME, generate_signatures() ) if not match: return [] instruction_byte_bitstring = instruction_byte_from_bitdefs( generate_instruction_byte_bitdefs(signature) ) mc_bytes = [] instruction_byte = get_machine_code_byte_template() instruction_byte["byte_type"] = "instruction" instruction_byte["bitstring"] = instruction_byte_bitstring mc_bytes.append(instruction_byte) return mc_bytes