Assembler

Miki Tebeka’s Clever Idea http://pythonwise.blogspot.com/2012/06/python-based-assembler.html https://raw.githubusercontent.com/tebeka/pythonwise/master/assembler.pdf

class oberon.assembler.ASM[source]

Collect the individual bit-pattern generator functions.

static Add(a, b, c, u=0)[source]
static Add_imm(a, b, K, v=0, u=0)[source]
static And(a, b, c, u=0)[source]
static And_imm(a, b, K, v=0, u=0)[source]
static Ann(a, b, c, u=0)[source]
static Ann_imm(a, b, K, v=0, u=0)[source]
static Asr(a, b, c, u=0)[source]
static Asr_imm(a, b, K, v=0, u=0)[source]
static CC(c)[source]
static CC_imm(offset)[source]
static CS(c)[source]
static CS_imm(offset)[source]
static Div(a, b, c, u=0)[source]
static Div_imm(a, b, K, v=0, u=0)[source]
static EQ(c)[source]
static EQ_imm(offset)[source]
static F(c)[source]
static F_imm(offset)[source]
static GE(c)[source]
static GE_imm(offset)[source]
static GT(c)[source]
static GT_imm(offset)[source]
static HI(c)[source]
static HI_imm(offset)[source]
static Ior(a, b, c, u=0)[source]
static Ior_imm(a, b, K, v=0, u=0)[source]
static LE(c)[source]
static LE_imm(offset)[source]
static LS(c)[source]
static LS_imm(offset)[source]
static LT(c)[source]
static LT_imm(offset)[source]
static Load_byte(a, b, offset=0)[source]
static Load_word(a, b, offset=0)[source]
static Lsl(a, b, c, u=0)[source]
static Lsl_imm(a, b, K, v=0, u=0)[source]
static MI(c)[source]
static MI_imm(offset)[source]
static Mov(a, c, v=0, u=0)[source]
static Mov_imm(a, K, v=0, u=0)[source]
static Mul(a, b, c, u=0)[source]
static Mul_imm(a, b, K, v=0, u=0)[source]
static NE(c)[source]
static NE_imm(offset)[source]
static PL(c)[source]
static PL_imm(offset)[source]
static Ror(a, b, c, u=0)[source]
static Ror_imm(a, b, K, v=0, u=0)[source]
static Store_byte(a, b, offset=0)[source]
static Store_word(a, b, offset=0)[source]
static Sub(a, b, c, u=0)[source]
static Sub_imm(a, b, K, v=0, u=0)[source]
static T(c)[source]
static T_imm(offset)[source]
static VC(c)[source]
static VC_imm(offset)[source]
static VS(c)[source]
static VS_imm(offset)[source]
static Xor(a, b, c, u=0)[source]
static Xor_imm(a, b, K, v=0, u=0)[source]
class oberon.assembler.Assembler[source]
Add(a, b, c, u=0)[source]
Add_imm(a, b, K, v=0, u=0)[source]
And(a, b, c, u=0)[source]
And_imm(a, b, K, v=0, u=0)[source]
Ann(a, b, c, u=0)[source]
Ann_imm(a, b, K, v=0, u=0)[source]
Asr(a, b, c, u=0)[source]
Asr_imm(a, b, K, v=0, u=0)[source]
CC(c)[source]
CC_imm(offset)[source]
CS(c)[source]
CS_imm(offset)[source]
Div(a, b, c, u=0)[source]
Div_imm(a, b, K, v=0, u=0)[source]
EQ(c)[source]
EQ_imm(offset)[source]
F(c)[source]
F_imm(offset)[source]
GE(c)[source]
GE_imm(offset)[source]
GT(c)[source]
GT_imm(offset)[source]
HERE()[source]

Return the current address.

HI(c)[source]
HI_imm(offset)[source]
Ior(a, b, c, u=0)[source]
Ior_imm(a, b, K, v=0, u=0)[source]
LE(c)[source]
LE_imm(offset)[source]
LS(c)[source]
LS_imm(offset)[source]
LT(c)[source]
LT_imm(offset)[source]
Load_byte(a, b, offset=0)[source]
Load_word(a, b, offset=0)[source]
Lsl(a, b, c, u=0)[source]
Lsl_imm(a, b, K, v=0, u=0)[source]
MI(c)[source]
MI_imm(offset)[source]
Mov(a, c, v=0, u=0)[source]
Mov_imm(a, K, v=0, u=0)[source]
Mul(a, b, c, u=0)[source]
Mul_imm(a, b, K, v=0, u=0)[source]
NE(c)[source]
NE_imm(offset)[source]
PL(c)[source]
PL_imm(offset)[source]
Ror(a, b, c, u=0)[source]
Ror_imm(a, b, K, v=0, u=0)[source]
Store_byte(a, b, offset=0)[source]
Store_word(a, b, offset=0)[source]
Sub(a, b, c, u=0)[source]
Sub_imm(a, b, K, v=0, u=0)[source]
T(c)[source]
T_imm(offset)[source]
VC(c)[source]
VC_imm(offset)[source]
VS(c)[source]
VS_imm(offset)[source]
Xor(a, b, c, u=0)[source]
Xor_imm(a, b, K, v=0, u=0)[source]
dw(data)[source]

Lay in a data word literal value. Adds the current address to the data_addrs set attribute.

label(thunk, reserves=0)[source]

Enter a label in the symbol table, fix up any prior references to this label, and optionally reserve some RAM (reserves counts bytes, not words, and can only reserve whole words to maintain alignment, so this must be a multiple of four.)

print_program()[source]
class oberon.assembler.Context(symbol_table)[source]

Execution namespace for asm code.

When identifiers are referenced and are not being assigned to the namespace Context __getitem__ method will be called with the name.

The Context searches itself (and __builtins__) for the name and returns the value if found, otherwise it creates a new named LabelThunk with that name, enters it in the symbol_table, and returns it.

Later, when the named thunk is assigned a value, that value replaces the thunk in the symbol_table. This class will raise a RuntimeError if you attempt to assign a value to a label more than once.

class oberon.assembler.DebugDict[source]
get_line_for(addr)[source]
print_debug(out=None)[source]
class oberon.assembler.LabelThunk(name)[source]

Stand for an address that will be determined later.

oberon.assembler.assemble_file(in_file, out_file, sym_file=None, print_program=False, additional_data=None, epilog=None)[source]

Accept up to three file objects. The first is a source file, the second is the binary output file, and the optional third is a file to which to write symbols and other information (currently the other information is just a set of addresses that contain data, rather than machine code.)

The symbol file is a pickle of a symbol table dictionary that maps label names to addresses, and the set of data addresses.

The resulting binary file is suitable for loading over the serial port, you can pass it to the --serial-in command line option.

This is the Oberon bootloader function that will load the binary over the serial line:

PROCEDURE LoadFromLine;
  VAR len, adr, dat: INTEGER;
BEGIN
  RecInt(len);
  WHILE len > 0 DO
    RecInt(adr);
    REPEAT
      RecInt(dat);
      SYSTEM.PUT(adr, dat);
      adr := adr + 4;
      len := len - 4
    UNTIL len = 0;
    RecInt(len)
  END
END LoadFromLine;

It reads a (4-byte) int length and drops into a while loop the loop reads a (4-byte) int address at which to store the following data.

Then a second loop (repeat) is started to read the data. It reads a 4-byte word, stores it to the RAM, then increments the address and decrements the length (each by four. So the length is counting bytes, not words! N.B.)

Once the repeat loop is done patching RAM it reads one more (4-byte) int length and the while loop restarts if the length is non-zero, otherwise we’re done and the machine boots from there.

oberon.assembler.make_F0(u, op, a, b, c, v=0)[source]
oberon.assembler.make_F1(u, v, op, a, b, K)[source]
oberon.assembler.make_F2(u, v, a, b, offset)[source]
oberon.assembler.make_F3(cond, c, invert=False, v=False)[source]
oberon.assembler.make_F3_imm(cond, offset, invert=False, v=False)[source]
oberon.assembler.opof(op)[source]
oberon.assembler.ops = {'Add': 8, 'And': 4, 'Ann': 5, 'Asr': 2, 'Div': 11, 'Fad': 12, 'Fdv': 15, 'Fml': 14, 'Fsb': 13, 'Ior': 6, 'Lsl': 1, 'Mov': 0, 'Mul': 10, 'Ror': 3, 'Sub': 9, 'Xor': 7}

Operation names mapped to their values in instructions.

oberon.assembler.thunkify_arithmetic_logic(method)[source]

Wrap a method that uses ASM to make bits. If it’s called with a LabelThunk it sets up a fixup function that resolves the actual instuction when the label is assigned to a concrete address.

oberon.assembler.thunkify_branch(method)[source]

Wrap a branch method. If it’s called with a LabelThunk it sets up a fixup function that resolves the actual instuction when the label is assigned to a concrete address.