SAPsim.utils package

Submodules

SAPsim.utils.exceptions module

Custom exceptions.

exception SAPsim.utils.exceptions.ARegisterNegativeInt[source]

Bases: Exception

There’s somehow a negative number in unsigned register A.

exception SAPsim.utils.exceptions.ARegisterNotEnoughBits[source]

Bases: Exception

The unsigned value in register A can’t be stored in NUM_BITS_IN_REGISTERS bits.

exception SAPsim.utils.exceptions.BRegisterNegativeInt[source]

Bases: Exception

There’s somehow a negative number in unsigned register B.

exception SAPsim.utils.exceptions.BRegisterNotEnoughBits[source]

Bases: Exception

The unsigned value in register B can’t be stored in NUM_BITS_IN_REGISTERS bits.

exception SAPsim.utils.exceptions.ChangeAddressGreaterThan15(addr: int)[source]

Bases: Exception

exception SAPsim.utils.exceptions.ChangeAddressNegative(addr: int)[source]

Bases: Exception

exception SAPsim.utils.exceptions.ChangeValueInvalid(value: int)[source]

Bases: Exception

exception SAPsim.utils.exceptions.DroppedOffBottom(message='PC is greater than max address in RAM. Your program does not always HLT.')[source]

Bases: Exception

Raised if PC > max address in RAM.

exception SAPsim.utils.exceptions.DuplicateAddress(address)[source]

Bases: Exception

exception SAPsim.utils.exceptions.FileNotCSV(path: Path, message='Invalid filepath provided. Extension must be .csv')[source]

Bases: Exception

exception SAPsim.utils.exceptions.FirstHexitGreaterThan15(address)[source]

Bases: Exception

exception SAPsim.utils.exceptions.FirstHexitNegative(address)[source]

Bases: Exception

exception SAPsim.utils.exceptions.InstructionRequiresArg(instruction: str)[source]

Bases: Exception

exception SAPsim.utils.exceptions.InvalidAddress(row)[source]

Bases: Exception

exception SAPsim.utils.exceptions.InvalidFirstHexit(address)[source]

Bases: Exception

exception SAPsim.utils.exceptions.InvalidInstructionString(instruction: str)[source]

Bases: Exception

exception SAPsim.utils.exceptions.InvalidSecondHexit(address)[source]

Bases: Exception

exception SAPsim.utils.exceptions.JumpToNegativeAddress(message='Attempted to jump to a negative address.')[source]

Bases: Exception

exception SAPsim.utils.exceptions.LoadFromUnmappedAddress[source]

Bases: Exception

Raised if attempting to Mem(addr), but Addr is not mapped.

exception SAPsim.utils.exceptions.MoreThan16MappedAddresses[source]

Bases: Exception

exception SAPsim.utils.exceptions.NegativeAddress(row)[source]

Bases: Exception

exception SAPsim.utils.exceptions.NoFirstHexit(address)[source]

Bases: Exception

exception SAPsim.utils.exceptions.NoSecondHexit(address)[source]

Bases: Exception

exception SAPsim.utils.exceptions.NonNumericalAddress(row)[source]

Bases: Exception

exception SAPsim.utils.exceptions.RowWithNoAddress(row)[source]

Bases: Exception

exception SAPsim.utils.exceptions.SecondHexitGreaterThan15(address)[source]

Bases: Exception

exception SAPsim.utils.exceptions.SecondHexitNegative(address)[source]

Bases: Exception

SAPsim.utils.exceptions.print_debug_info() None[source]

When most Exceptions (not DroppedOffBottom) occur, this function is called to print the instruction that caused the Exception and program state (RAM and registers and flags)

SAPsim.utils.execute module

Execute instructions in RAM.

SAPsim.utils.execute.execute_full_speed() None[source]

Execute instructions in RAM at full speed until EXECUTING is False or PC > max addr.

Returns:

None

SAPsim.utils.execute.execute_next() None[source]

Execute a single instruction at the current PC value if EXECUTING. If attempting to execute an empty address, PC += 1 (i.e., doesn’t skip to next filled address).

Returns:

None

SAPsim.utils.execute.run(prog_path: str, **kwargs) None | dict[str, Any][source]

Run given .csv program in SAPsim format.

Parameters:
  • prog_path (str) – .csv file in SAPsim format.

  • **kwargs – See below

Keyword Arguments:
  • debug (bool) –
    • Whether to run in debug mode (True) or at full speed (False)

    • Default is full speed

  • change (dict[int, int]) –
    • dict[address, byte] of values to change in RAM

    • The value at each address (0 to 15) will be overwritten to that byte

    • Useful for debugging programs (edit a value without changing the CSV)

    • Useful for autograding programs (overwrite a reserved instruction/data value)

  • table_format (str) –
  • The rest of the parameters are pretty much exclusively for unit testing, and you should not use these
    • return_state (bool) –
      • If True, then program state will be returned

      • See utils.helpers.get_state()

      • Will probably cause type warnings since the return type is Union[None, dict[str, Any]]

      • To avoid type warnings, use run_and_return_state

    • non_blocking (bool) –
      • This is used to unit test debug mode of run(), you likely don’t have a need for this

      • If True, then run() won’t block on input

      • input() won’t be called in debug mode (i.e., don’t have to press enter to continue execution)

      • If this is True, then debug mode will be on even if debug isn’t in kwargs

    • no_print (bool) –
      • This is used to save computation time during unit testing

      • If True, then print_RAM() and print_info() won’t be called

      • In debug mode, “Program halted.” will still be printed

    • bits (int) –
      • You should not modify this

      • Number of bits in registers

      • Default value in global_vars is 8

      • 8 is also the maximum value since everything in RAM should fit in a byte

Returns:

None or program state if return_state

Return type:

Union[None, dict[str, Any]]

SAPsim.utils.execute.run_and_return_state(prog_path: str, **kwargs: Any) dict[str, Any][source]

Run given .csv program in SAPsim format.

Parameters:
  • prog_path (str) – .csv file in SAPsim format.

  • **kwargs – See below

Keyword Arguments:
  • debug (bool) –
    • Whether to run in debug mode (True) or at full speed (False)

    • Default is full speed

  • change (dict[int, int]) –
    • dict[address, byte] of values to change in RAM

    • The value at each address (0 to 15) will be overwritten to that byte

    • Useful for debugging programs (edit a value without changing the CSV)

    • Useful for autograding programs (overwrite a reserved instruction/data value)

  • table_format (str) –
  • The rest of the parameters are pretty much exclusively for unit testing, and you should not use these
    • return_state (bool) –
      • If True, then program state will be returned

      • See utils.helpers.get_state()

      • Will probably cause type warnings since the return type is Union[None, dict[str, Any]]

      • To avoid type warnings, use run_and_return_state

    • non_blocking (bool) –
      • This is used to unit test debug mode of run(), you likely don’t have a need for this

      • If True, then run() won’t block on input

      • input() won’t be called in debug mode (i.e., don’t have to press enter to continue execution)

      • If this is True, then debug mode will be on even if debug isn’t in kwargs

    • no_print (bool) –
      • This is used to save computation time during unit testing

      • If True, then print_RAM() and print_info() won’t be called

      • In debug mode, “Program halted.” will still be printed

    • bits (int) –
      • You should not modify this

      • Number of bits in registers

      • Default value in global_vars is 8

      • 8 is also the maximum value since everything in RAM should fit in a byte

Returns:

None or program state if return_state

Returns:

dict containing program state (see helpers.get_state)

Return type:

dict[str, Any]

SAPsim.utils.global_vars module

Global variables.

If changing anything in this file, also modify SAPsim/__init__.py and helpers.print_info.

SAPsim.utils.global_vars.A: int = 0

Register A, default value 0

SAPsim.utils.global_vars.B: int = 0

Register B, default value 0

SAPsim.utils.global_vars.EXECUTING: bool = True

Is the program executing? Set to False by hlt()

SAPsim.utils.global_vars.FLAG_C: bool = False

Carry-out bit, modified by add() and sub(). Default value False (0).

SAPsim.utils.global_vars.FLAG_Z: bool = False

Zero flag = NOR(Sum bits), modified by add() and sub(). Default value False (0).

Lab 3’s ALU has default value True (1) for FlagZ because the results register is initially 0.

However, it makes more sense in the simulation to set it to False by default.

SAPsim.utils.global_vars.MAX_PC: int = 15

Max PC value. 2**4-1

SAPsim.utils.global_vars.MNEMONIC_TO_OPCODE: bidict = bidict({'NOP': 0, 'LDA': 1, 'ADD': 2, 'SUB': 3, 'STA': 4, 'LDI': 5, 'JMP': 6, 'JC': 7, 'JZ': 8, 'OUT': 14, 'HLT': 15})

Bidirectional mapping str mnemonic : int opcode.

Use MNEMONIC_TO_OPCODE.inverse[opcode] to get mnemonic from opcode.

All mnemonics in this dict are in all caps.

SAPsim.utils.global_vars.NUM_BITS_IN_REGISTERS: int = 8

This variable is the #bits in registers and affects how add, sub, ldi, and lda work. Default value is 8. Max value is 8 since everything in RAM needs to fit in a byte.

SAPsim.utils.global_vars.PC: int = 0

Program counter that indexes into RAM, default value 0

SAPsim.utils.global_vars.RAM: dict[int, int] = {}

dict[int, int] mapping PC:byte, where byte can be instruction or data (indistinguishable, mostly)

SAPsim.utils.global_vars.table_format: str = 'simple_outline'

Tabulate table_fmt kwarg to customize pretty-printing. Defaults to simple_outline, see all options: https://github.com/astanin/python-tabulate#table-format

SAPsim.utils.helpers module

Miscellaneous helper functions.

SAPsim.utils.helpers.check_state(**kwargs)[source]

Compare the current state to expected values. Mostly used in testing functions.

Optional parameters RAM=, PC=, A=, B=, FLAG_C=, FLAG_Z=, EXECUTING=

SAPsim.utils.helpers.check_state_all(RAM, PC: int, A: int, B: int, FLAG_C: bool, FLAG_Z: bool, EXECUTING: bool)[source]

Compare all current state variables to expected values. Mostly used in testing functions.

SAPsim.utils.helpers.clone_dict(dict)[source]

Returns a deep clone of dict. Used to clone RAM.

SAPsim.utils.helpers.get_state() dict[str, Any][source]

Return a dict of global variables and their values. Mostly used in testing functions.

SAPsim.utils.helpers.i2b(instruction: str) int[source]

Alias for instruction_to_byte().

SAPsim.utils.helpers.instruction_to_byte(instruction: str) int[source]

Given an instruction in the form <Mnemonic> <Arg>, with a space, return the byte representation.

For NOP, OUT, and HLT, if an Arg is not given, then the right hexit will just be 0.

Haven’t yet tested exception handling.

SAPsim.utils.helpers.is_documented_by(original, lines_to_remove: int = 0, prepend: str = '', append: str = '')[source]

Use for wrapper functions that should have the original function’s docstring.

Parameters:
  • original – The original function

  • lines_to_remove (int) – How many lines to remove from the end of the docstring (i.e., to remove old return)

  • preprend – What to prepend to docstring. Pass in a docstring (i.e., triple quotation marks), and there should be a trailing newline

  • append (str) – What to append to docstring. Pass in a docstring (i.e., triple quotation marks), and there should be a leading newline

SAPsim.utils.helpers.pad_hex(hex: str, width: int)[source]

Pad given hex str with 0x prefix to width hexits. That is, 0x prefix not included in the width.

SAPsim.utils.helpers.parse_arg(byte: int) int[source]

Given a byte, return the 4-bit arg, just the bottom 4 bits.

Parameters:

byte (int)

Returns:

4-bit arg

Return type:

int

SAPsim.utils.helpers.parse_byte(byte: int)[source]

Given a byte (2 hexits), return the opcode (1 hexit) and arg (1 hexit). Return as dict for readability.

Parameters:

byte (int)

Returns:

{‘opcode’: opcode, ‘arg’: arg}

Return type:

dict[str, int]

SAPsim.utils.helpers.parse_opcode(byte: int)[source]

Given a byte, return the 4-bit opcode, just the top 4 bits.

Parameters:

byte (int)

Returns:

4-bit opcode

Return type:

int

SAPsim.utils.helpers.print_RAM()[source]

Pretty print the contents of RAM, sorted by address.

PC | Addr | Instruction | Dec | Hex |

Display byte in dec and hex format and attempt to display as instruction (except when opcode invalid) for all bytes since we can’t distinguish instructions from data.

Display arrow on current PC value.

Uses global_vars.table_format for table format passed to tabulate().

SAPsim.utils.helpers.print_info()[source]

Print the values of everything in global_vars.py except RAM.

SAPsim.utils.helpers.reset_globals()[source]

Reset global variables (not NUM_BITS_IN_REGISTERS) to default values.

SAPsim.utils.helpers.setup_state(bits: int = 8) None[source]

Resets global variables to default values. Also, set global_vars.NUM_BITS_IN_REGISTERS to bits.

Parameters:

bits (int) – Number of bits in registers, default 8

Returns:

None

SAPsim.utils.instructions module

SAP instruction implementation.

All function docstrings (and even most implementations) are ripped straight from the SAP Instruction Set, with only slight modifications.

This DOES NOT exist in actual SAP but for the purposes of simulation and testing, add(arg) and sub(arg) have optional kwargs direct_add= and direct_sub= that will cause A = A + arg, A = A - arg instead of A = A + Mem(arg), A = A - Mem(arg).

This DOES NOT exist in actual SAP but for implementation purposes, instructions that don’t need an arg (i.e. NOP, OUT, HLT) get a default parameter so that they can still be called with an argument. In actual SAP, all instructions (byte) have a required Arg, not a default or optional arg.

OPCODE_TO_INSTR_PROCEDURE dict that maps opcodes to procedures is defined at the bottom.

SAPsim.utils.instructions.OPCODE_TO_INSTR_PROCEDURE = {0: <function nop>, 1: <function lda>, 2: <function add>, 3: <function sub>, 4: <function sta>, 5: <function ldi>, 6: <function jmp>, 7: <function jc>, 8: <function jz>, 14: <function out>, 15: <function hlt>}

This dict maps opcodes to the procedures defined in this file.

The syntax OPCODE_TO_INSTR_PROCEDURE[opcode](arg) will execute the correct instruction with arg passed as argument! Very cool.

SAPsim.utils.instructions.add(arg: int, **kwargs) None[source]

A = A + Mem(arg). Accounts for NUM_BITS_IN_REGISTERS to set FLAG_C and FLAG_Z. Handles overflow.

Opcode 2

Parameters

arg: int

memory address, usually

kwarg
direct_add: bool

Set to True to directly add arg (i.e. A = A + arg instead of A = A + Mem(arg)), for testing purposes and use in sub.

This behavior does not exist in actual SAP.

SAPsim.utils.instructions.hlt(arg: int = 0) None[source]

Halt

Opcode 15

SAPsim.utils.instructions.jc(arg: int) None[source]

If FC=1 then PC=arg; else go on

Opcode 7

SAPsim.utils.instructions.jmp(arg: int) None[source]

PC = arg

Opcode 6

SAPsim.utils.instructions.jz(arg: int) None[source]

If FZ=1 then PC=arg; else go on

Opcode 8

SAPsim.utils.instructions.lda(arg: int) None[source]

A = Mem(arg)

Opcode 1

SAPsim.utils.instructions.ldi(arg: int) None[source]

A = arg

Opcode 5

SAPsim.utils.instructions.nop(arg: int = 0) None[source]

Nop

Opcode 0

SAPsim.utils.instructions.out(arg: int = 0) None[source]

Display = OUT = A. Prints | PC | A (dec) | A (hex) |

Opcode 14

SAPsim.utils.instructions.sta(arg: int) None[source]

Mem(Arg) = A. CAN store to unmapped addr, which will simply map the addr in RAM.

Opcode 4

SAPsim.utils.instructions.sub(arg: int, **kwargs) None[source]

A = A - Mem(arg). Accounts for NUM_BITS_IN_REGISTERS to set FLAG_C and FLAG_Z. Calls add() twice to perform 2’s complement subtraction.

Opcode 3

Parameters

arg: int

memory address, usually

kwarg
direct_sub: bool

set to True to directly sub arg (i.e. A = A - arg instead of A = A - Mem(arg)), for testing purposes.

This behavior does not exist in actual SAP.

SAPsim.utils.parser module

Parses a SAP program in the CSV format given in template.csv into global_vars.RAM.

SAPsim.utils.parser.parse_csv(file_path: Path | str) None[source]

Takes a .csv file path in SAPsim template.csv format and parses it into RAM.

Calls setup_state() if file_path is valid.

If an address is skipped (not in the .csv file), it is not mapped in RAM. If an address is mapped but First Hexit and Second Hexit are blank, a NOP 0 (0x00) is inserted.

The reasoning here is that if an addr is skipped completely in the CSV, it shouldn’t show up in RAM. If an addr is mapped but First Hexit and Second Hexit are blank, it should show up in RAM (as NOP 0).

Parameters:

file_path (Union[Path, str]) – The path to the .csv file to parse.

Raises:
Returns:

None

Module contents

Utilities for SAPsim.