← back to the blog

pyLC3 Documentation

Posted in New LC3 Simulator


The simulator object can be created in python with:

import pylc3
sim = pylc3.simulator()

The following comments assume that this bit of code has been run in your python interperator or script file already.


stepN steps the simulated LC3 processor by n instructions including instructions taken by interrupt service routines and calls to functions. For example running the LC3 for 10 instructions starting at PC = 0x3000 would go like:



nextN steps the simulated LC3 processor by n instructions excluding instructions taken by interrupt service routines and calls to functions. For example running the LC3 for 15 instructions starting at PC = 0x4000 would go like:



+internal-ish+ doInst does the instruction proveded as the first parameter. for example, a no-op:



Memory is provided as an array in the mem attribute of all simulator objects, and can be sliced like a python array. for example reading the contents of memory location 0x1000, and setting it to 4:

oldval = sim.mem[0x1000]
sim.mem[0x1000] = 4

getReg(reg) and setReg(reg, val)

getReg and setReg get and set general purpose register in the simulated LC3. e.g.:

oldReg = sim.getReg(5)

getPcsrBit(bit) and setPcsrBit(bit, val)

getPcsrBit and setPcsrBit get and set the bits of the LC3's program status register. The availible bits at this time are:

  •  s - supervisor mode
  • n - negative condition code
  • z - zero condition code
  • p - positive condition code

NOTE: it is possible to put the processor into an invalid state with the use of this function; for example you can set all three of n, z, and p. As an example use of this API, the code below sets the n bit and clears the z bit if the z bit is set:

if sim.getPcsrBit('z') :
    sim.setPcsrBit('z', False)
    sim.setPcsrBit('n', True)

addWatchPoint(address, triggerOnRead, triggerOnWrite, callback_fn)

addWatchPoint adds a watch point to the simulator. Watchpoints in this LC3 simulator are setup for batch testing or programming and call a function when the program accesses a particular memory location, including for fetching instructions. This function acts as if it had been declared as follows in python:

class simulator:

def addWatchPoint(address, readP, writeP, callback):

The readP and writeP boolean values that tell the simulator to call the callback on a read or a write respectively. Both readP and writeP may be set. For example, we run the function watch1 when the program writes to the memory location 0x4000 and the function watch2 when the program reads from the memory location 0x5000:

def watch1(address, oldval, newval) :
    print("wachpoint 1: {:x}: {} -> {}".format(adderss
    , oldval
    , newval))

def watch2(address, oldval, newval) :
    print("wachpoint 2: {:x}: {} -> {}".format(adderss
    , oldval
    , newval))

sim.addWatchPoint(0x4000, False, True, watch1)
sim.addWatchPoint(0x5000, True, False, watch2)

addBreakPoint(address, callback_fn)

addBreakPoint adds a watch point to the simulator. Breakpoints in this LC3 simulator are setup for batch testing or programming and call a function when the program fetches a particular memory location. For example, if we wanted to run the function break1 when the program reaches 0x3010:

def break1(address) :
    print("program reached {}", address)

sim.addBreakPoint(0x3010, break1)


load a program in the LC3 object file format from disk and load it into memory. Does not cause watchpoints to trigger. e.g. loading the program iggy:



Run program until completion


Call this function when using the gui after modifying memory to refresh the memory view for example:

sim.mem[0x3000:0x4000] = range(0x1000)

getPC() and setPC(address)

getPC or setPC get or set the simulated LC3's progam counter example usage:

oldpc = sim.getPC()

addInterruptTrigger(IntVector, priority, callback_fn)

Interrupts in this LC3 simulator are generated by callbacks that execute every instruction and return a boolean indicating wheather either an interrupt should be triggered or not. Once an interrupt is triggered, the function triggering the interrupt will not be called again until the interrupt has been serviced by the processor. Example: suppose we want to trigger interrupt 0x85 with the python function interrupt1 with the priority 4:

counter = 0
def interrupt1 ():
    counter += 1
    if counter == 400:
        counter = 0
        return True
    return False

sim.addInterruptTrigger(0x85, 4, interrupt1)

getPriority() and setPriority(priority)

getPriority and setPriority get and set the interal priority that the simulated LC3 is running at. for example to set the proirity to 0:

oldpriority = sim.getPriority()