Source code for eight_bit_computer.rom

"""
Create and export roms for the computer
"""

import os

from .operations import get_all_operations, fetch
from .language_defs import (
    EMPTY_ADDRESS, MODULE_CONTROLS_DEFAULT, DECIMAL_ROM_DEFAULT
)
from .decimal_display import gen_display_romdatas
from .data_structures import RomData
from . import bitdef
from . import number_utils


[docs]def get_rom(): """ Get complete representation of the rom. Returns: list(RomData): All the defined microcode. Raises: RuntimeError: When the romdata dataset has duplicate addresses. """ language_templates = collect_language_datatemplates() romdatas = collapse_datatemplates_to_romdatas(language_templates) if romdatas_have_duplicate_addresses(romdatas): raise RuntimeError("Romdata set has duplicate addresses") all_addresses = bitdef.collapse(EMPTY_ADDRESS) default_data = MODULE_CONTROLS_DEFAULT full_rom = populate_empty_addresses(romdatas, all_addresses, default_data) full_rom.sort(key=lambda romdata: romdata.address) return full_rom
[docs]def collect_language_datatemplates(): """ Get all the datatemplates from all the defined operations. Returns: list(DataTemplate): All the data templates from the defined operations """ operations = get_all_operations() operations.append(fetch) templates = [] for operation in operations: templates.extend(operation.generate_microcode_templates()) return templates
[docs]def collapse_datatemplates_to_romdatas(datatemplates): """ Collapse any addresses in datatemplates to real values. If an address does need collapsing the original data is copied out to all the collapsed addresses. Args: datatemplates list(DataTemplates): A list of templates to collapse. Returns: list(RomData): The expanded datatemplates """ romdatas = [] for datatemplate in datatemplates: addresses = bitdef.collapse(datatemplate.address_range) for address in addresses: romdatas.append( RomData(address=address, data=datatemplate.data) ) return romdatas
[docs]def populate_empty_addresses(romdatas, all_addresses, default_data): """ Form a complete set of rom data by filling any undefined addresses. Args: romdatas list(RomData): The romdatas defined by the instructions. all_addresses (list(str)): List of bitdefs representing every address in the rom default_data (str): The value to set for any address that isn't in romdatas. Returns: list(RomData): List of RomDatas representing a completely full rom """ filled_addresses = {romdata.address: romdata.data for romdata in romdatas} complete_rom = [] for address in all_addresses: if address in filled_addresses: complete_rom.append( RomData(address=address, data=filled_addresses[address]) ) else: complete_rom.append( RomData(address=address, data=default_data) ) return complete_rom
[docs]def romdatas_have_duplicate_addresses(romdatas): """ Check if any of the romdatas have duplicate addresses. Args: romdatas list(RomData): List of romdatas to check. Returns: Bool: Whether or not there were any duplicated addresses. """ duplicates = False addresses = [] for romdata in romdatas: if romdata.address in addresses: duplicates = True break else: addresses.append(romdata.address) return duplicates
[docs]def slice_rom(rom): """ Slice a rom into chunks 8 bits wide. This is to prepare the data to write into the roms. To take a single RomData as an example, if it looked like this (spaces added for clarity):: RomData( address="0000000 0000 000", data="10101010 11111111 00000000 11001100" ) We would end up with:: { 0: RomData( address="0000000 0000 000", data="11001100" ), 1: RomData( address="0000000 0000 000", data="00000000" ), 2: RomData( address="0000000 0000 000", data="11111111" ), 3: RomData( address="0000000 0000 000", data="10101010" ) } Args: rom (list(RomData)): The complete ROM Returns: dict(int:list(RomData)) Dictionary of ROM slices """ rom_slices = {} for rom_index in range(get_num_bytes(rom[0].data)): rom_offset = 8 * rom_index rom_slice = get_romdata_slice(rom, rom_offset + 7, rom_offset) rom_slices[rom_index] = rom_slice return rom_slices
[docs]def get_num_bytes(bitstring): """ Get the number of bytes needed to store this bitdef. Args: bitstring (str): Bitstring representing the bits to store. Returns: int: The number of bytes needed to store the bitstring. """ num_bits = bitdef.length(bitstring) num_bytes = num_bits // 8 if num_bits % 8: num_bytes += 1 return num_bytes
[docs]def get_romdata_slice(romdatas, end, start): """ Get a slice of the data in the romdatas. Args: romdatas (list(RomData)): The romdatas to get a slice from end (int): The index for the end of the slice. Starts at zero at the rightmost (least significant) bit. start (int): The index for the start of the slice. Starts at zero at the rightmost (least significant) bit. Returns: list(RomData): The sliced list of romdatas """ sliced_romdatas = [] for romdata in romdatas: data_slice = bitdef.extract_bits(romdata.data, end, start) sliced_romdata = RomData(address=romdata.address, data=data_slice) sliced_romdatas.append(sliced_romdata) return sliced_romdatas
[docs]def get_decimal_rom(): """ Get complete representation of the decimal rom. Returns: list(RomData): All the defined data for the decima rom. Raises: RuntimeError: When the decimal romdata dataset has duplicate addresses. """ decimal_romdatas = gen_display_romdatas() if romdatas_have_duplicate_addresses(decimal_romdatas): raise RuntimeError("Decimal romdata set has duplicate addresses") all_addresses = bitdef.collapse(EMPTY_ADDRESS) default_data = DECIMAL_ROM_DEFAULT full_rom = populate_empty_addresses( decimal_romdatas, all_addresses, default_data ) full_rom.sort(key=lambda romdata: romdata.address) return full_rom