# version 2.0 27/1/19
# Lots of bugs corrected, see update2.0.pdf


# The stores are lists of positive integers, the least significant 20 bits 
# are used
#
# r, s and t are stored as integers in modifier[1] to modifier[3] and only the 
# lowest 11 bits are used.  modifier[0] is used to implement the 2, 3, 4, 
# and 5 orders. The main store modifier b is modifier[4]
#
# M, L are stored as positive long integers with 40 bits used; A is M and the 
# least significant 39 bits of L: A = (M<<39) + (L & 0x7FFFFFFFFF)
#
# For fixed point arithmetic M and A are converted to signed long integers 
# equal to fixed point fractional value scaled by 2**39 or 2**78
#
# For floating arithmetic M and A are converted to python floats which are
# implemented with 64 bit C floats.
#
# The function report() is used to display the cause of an error in the
# emulator control panel before entering the report routine.
import time

def op0(m):
    report("non-existant order")

def op1(m):
    report("non-existant order")

def op2(m):
    "add m to address part of next instruction"
    modifier[0]=m

def op3(m):
    "subtract m from address part of next instruction"
    modifier[0]=(2048 - m) & 0x7FF

def op4(m):
    "add a(m) to address part of next instruction"
    modifier[0]=get_a(m)

def op5(m):
    "subtract a(m) from address part of next instruction"
    modifier[0]=(2048 - get_a(m)) & 0x7FF

def op6(m):
    "left shift double length accumulator"
    global M, L, alpha
# set A as unsigned positive integer
    A = (M << 39) + (L & 0x7FFFFFFFFF)
# left shift, need to check overflow
    if m<1024:
        for i in range(0,m):
            (carrybit, A) = (A & signA, A << 1)
            alpha = alpha or ((A & signA) != carrybit)
# right shift, need to regenerate sign bit
    if m>=1024:
        for i in range(0,2048-m):
            A = A | ((A & signA) << 1)
            A = A >> 1
    L = (A & 0x7FFFFFFFFF) | (L & 0x8000000000)
    M = (A >> 39) & 0xFFFFFFFFFF

def op7(m):
    "right shift double length accumulator"
    global M, L, alpha
    A = (M << 39) + (L & 0x7FFFFFFFFF)
# right shift, need to propagate sign digit
    if m<1024:
        for i in range(0,m):
            A = A | ((A & signA) << 1)
            A = A >> 1
# left shift, need to check overflow
    if m>=1024:
        for i in range(0,2048-m):
            (carrybit, A) = (A & signA, A << 1)
            alpha = alpha or ((A & signA) != carrybit)

    L = (A & 0x7FFFFFFFFF) | (L & 0x8000000000)
    M = (A >> 39) & 0xFFFFFFFFFF

def op8(m):
    "swap rounded accumulator and store"
# stores in free store not the current  store
    global store, M, L, alpha
    if alpha==True: report("overflow")
    temp=round_accumulator(M, L)
    copy=store
    store=free
    M=get_M_from_store(m)
    put_M_to_store(temp, m)
    store=copy
    L=0

def op9(m):
    "clear store"
    put_M_to_store(0, m)

def op10(m):
    "load accumulator"
# uses current store as opposed to 30 order
    global M, L, alpha
    M=get_M_from_store(m)
    L=0
    alpha=False

def op11(m):
    "load M floating negative"
    global M, L, alpha
    alpha=False
    M=float2M(-M2float(get_M_from_store(m)))
    L=0

def op12(m):
    "floating add"
    global M, L
    M1=M2float(M)
    M2=M2float(get_M_from_store(m))
    M=float2M(M1+M2)
    L=0

def op13(m):
    "floating subtract"
    global M, L
    M1=M2float(M)
    M2=M2float(get_M_from_store(m))
    M=float2M(M1-M2)
    L=0

def op14(m):
    "floating multiply"
    global M, L
    M1=M2float(M)
    M2=M2float(get_M_from_store(m))
    M=float2M(M1*M2)
    L=0

def op15(m):
    "floating divide"
    global M, L, alpha
    M1=M2float(M)
    M2=M2float(get_M_from_store(m))
# prevent division by zero in emulator
    if M2==0.0: alpha=True
    else:       M=float2M(M1/M2)
    L=0

def op16(m):
    "add double length product"
    global K, M, L
    M1=M2float(K)
    K=M
    M2=M2float(get_M_from_store(m))
    M=float2M(M2float(M) + M1*M2)
    L=0

def op17(m):
    "double length product"
    global K, M, L
    M1=M2float(K)
    K=M
    M2=M2float(get_M_from_store(m))
    M=float2M(M2float(M) - M1*M2)
    L=0

def op18(m):
    "floating add to store"
    global M, L
    if alpha: report("overflow")
    M1=M2float(M)
    M2=M2float(get_M_from_store(m))
    M=float2M(M1+M2)
    put_M_to_store(M, m)
    L=0

def op19(m):
    "store accumulator"
    if alpha: report("overflow")
    put_M_to_store(M, m)

def op20(m):
    "load accumulator with |F(M)|"
    global M, L, alpha
    alpha=False
    M=float2M(abs(M2float(get_M_from_store(m))))
    L=0

def op21(m):
    "load accumulator minus |F(M)|"
    global M, L, alpha
    alpha=False
    M=float2M(-abs(M2float(get_M_from_store(m))))
    L=0

def op22(m):
    "add modulus of store to accumulator"
# apparently operates on free store not current
    global store, M, L
    copy=store
    store=free
    M1=M2float(M)
    M2=M2float(get_M_from_store(m))
    M=float2M(M1 + abs(M2))
    store=copy
    L=0

def op23(m):
    "subtract modulus of store from accumulator"
    global M, L
    M1=M2float(M)
    M2=M2float(get_M_from_store(m))
    M=float2M(M1 - abs(M2))
    L=0

def op24(m):
    "load K register"
# probably operates on current store
    global K
    K=get_M_from_store(m)

def op25(m):
    "floating multiply and change sign"
    global M, L
    M1=M2float(M)
    M2=M2float(get_M_from_store(m))
    M=float2M(-M1*M2)
    L=0

def op26(m):
    "load accumulator with m in floating point"
    global M, L, alpha
    M=float2M(float(m))
    L=0
    alpha=False

def op27(m):
    report("non-existant order")

def op28(m):
    report("non-existant order")

def op29(m):
    "logical or with store"
    M1=get_M_from_store(m)
    put_M_to_store(M1|M, m)

def op30(m):
    "load accumulator"
# operates on free store not current store
    global store, M, L, alpha
    copy=store
    store=free
    M=get_M_from_store(m)
    store=copy
    L=0
    alpha=False

def op31(m):
    "load accumulator negative"
    global M, L, alpha
    alpha=False
    M=signed_int_to_M(-M_to_signed_int(get_M_from_store(m)))
    L=0

def op32(m):
    "fixed add"
    global M, L
    A1=ML_to_signedA(M,L)
    A2=ML_to_signedA(get_M_from_store(m), 0)
    (M,L)=signedA_to_ML(A1 + A2)

def op33(m):
    "fixed subtract"
    global M, L
    A1=ML_to_signedA(M,L)
    A2=ML_to_signedA(get_M_from_store(m), 0)
    (M,L)=signedA_to_ML(A1 - A2)

def op34(m):
    "fixed multiply"
    global M, L, alpha
# special case
    if M==maxM and (L & 0x8000000000): M=get_M_from_store(m); clearL0(); return
    M1=M_to_signed_int(round_accumulator(M, L))
    M2=M_to_signed_int(get_M_from_store(m))
    (M,L)=signedA_to_ML(M1*M2)
    clearL0()

def op35(m):
    "fixed divide"
    global M, L, alpha
    A=ML_to_signedA(M, L)
    M2=M_to_signed_int(get_M_from_store(m))
# prevent division by zero in emulator
    if M2==0: alpha=True
# need to shift by 39 places to divide fractions
    else: A=(A*signM // M2)
    (M,L)=signedA_to_ML(A)
    M=round_accumulator(M,L)
    L=0
# special case requires alpha set
    if A==-signA: alpha=True

def op36(m):
    "add double length product"
    global K, M, L
    A=ML_to_signedA(M,L)
    M1=M_to_signed_int(K)
    K=M
    M2=M_to_signed_int(get_M_from_store(m))
    (M,L)=signedA_to_ML(A + M1*M2)
    clearL0()

def op37(m):
    "subtract double length product"
    global K, M, L, alpha
    A=ML_to_signedA(M,L)
    M1=M_to_signed_int(K)
    K=M
    M2=M_to_signed_int(get_M_from_store(m))
    (M,L)=signedA_to_ML(A - M1*M2)
    clearL0()

def op38(m):
    "fixed add and store"
    global M, L
    M1=M_to_signed_int(M)
    M2=M_to_signed_int(get_M_from_store(m))
    M=signed_int_to_M(M1+M2)
    put_M_to_store(round_accumulator(M, L), m)

def op39(m):
    "store rounded accumulator"
    global M, L
    if alpha: report("overflow")
# rounding cannot set overflow
    put_M_to_store(round_accumulator(M, L), m)

def op40(m):
    "load |N(m)| into A"
    global M, L, alpha
    alpha=False
    M=signed_int_to_M(abs(M_to_signed_int(get_M_from_store(m))))
    L=0

def op41(m):
    "load -|N(m)| into A"
    global M, L, alpha
    alpha=False
    M=signed_int_to_M(-abs(M_to_signed_int(get_M_from_store(m))))
    L=0

def op42(m):
    "adds |N(m)| to A"
    global M, L
    M1=M_to_signed_int(M)
    M2=M_to_signed_int(get_M_from_store(m))
    M=signed_int_to_M(M1 + abs(M2))

def op43(m):
    "subtracts |N(m)| from A"
    global M, L
    M1=M_to_signed_int(M)
    M2=M_to_signed_int(get_M_from_store(m))
    M=signed_int_to_M(M1 - abs(M2))

def op44(m):
    "load K register"
# appears to operate on free store not current
    global store, K
    copy=store
    store=free
    K=get_M_from_store(m)
    store=copy

def op45(m):
    "exact division"
    global M, L, alpha
    A=ML_to_signedA(M,L)
    M1=M_to_signed_int(get_M_from_store(m))
# prevent division by zero in emulator
    if M1==0: alpha=True
    else:
        (M,junk)=signedA_to_ML(2**39*(A%M1))
        (L,junk)=signedA_to_ML(2**39*(A//M1))
# special case requires alpha set
    if L==signM: alpha=True

def op46(m):
    "put m into M"
    global M, L, alpha
    M=m
    L=0
    alpha=False

def op47(m):
    "load L"
    global M, L
    L=get_M_from_store(m)

def op48(m):
    "store L"
    global M, L
    put_M_to_store(L, m)

def op49(m):
    "store L and M"
    global M, L, alpha
    if alpha: report("overflow")
    put_M_to_store(M, m)
    put_M_to_store(L, m+2)

def op50(m):
    "unconditional jump"
    modifier[r]=m-1

def op51(m):
    "unconditional jump and clear accumulator"
    global M, L, alpha
    modifier[r]=m-1
    M=0; L=0
    alpha=False

def op52(m):
    "jump if zero"
    if M==0: modifier[r]=m-1

def op53(m):
    "jump if not zero"
    if M!=0: modifier[r]=m-1

def op54(m):
    "jump if positive"
    if not (M & 0x8000000000): modifier[r]=m-1

def op55(m):
    "jump if negative"
    if M & 0x8000000000: modifier[r]=m-1

def op56(m):
    "jump if overflow"
    global alpha
    if alpha: modifier[r]=m-1
    alpha=False

def op57(m):
    "jump not overflow"
    global alpha
    if not alpha: modifier[r]=m-1
    alpha=False

def op58(m):
    "jump to subroutine"
    global free
# construct return address
    modifier[r]=(modifier[r]+1) & 0x7FF
# ensure function parts of 0 and 1 are clear
    free[0]=0
    free[1]=0
    put_a(0, s)
    put_a(1, r)
    modifier[r]=m-1

def op59(m):
    "jump to built-in subroutine in reserved store"
    global reserved, store
    if m>42: report("non-existant subroutine")
# construct return address
    modifier[r]=(modifier[r]+1) & 0x7FF
# ensure function parts of 0 and 1 are clear
    reserved[0]=0
    reserved[1]=0
    store=reserved
    set_store_neon(reserved)
    put_a(0, s)
    put_a(1, r)
    modifier[r]=512+m-1

def op60(m):
    "return from subroutine, always jumps to free store"
    global store
    modifier[s]=get_a(0)
    modifier[r]=(get_a(1) + m - 1) & 0x7FF
    store=free
    set_store_neon(free)

def op61(m):
    report("non-existant order")

def op62(m):
    "logical and"
    global M, L, alpha
    M = M & get_M_from_store(m)
    L=0

def op63(m):
    report("non-existant order")

def op64(m, q):
    report("non-existant order")

def op65(m, q):
    report("non-existant order")

def op66(m, q):
    "cyclic shift"
    global M, L
    L=0
    A = M << 39
    for i in range(0, m):
        cycle_bit=A & signA
        A = (A - cycle_bit) << 1
        if cycle_bit!=0: A = A | 1
    L = A & 0x7FFFFFFFFF
    M = (A >> 39) & 0xFFFFFFFFFF
    modifier[q]=int(L & 0x7FF)

def op67(m, q):
    report("non-existant order")

def op68(m, q):
    "split floating number"
    global M, L
    modifier[q] = (int(M & 0xFF) - 128) & 0x7FF
    M = M & 0xFFFFFFFF00
    put_M_to_store(M, m)
    L=0

def op69(m, q):
    "read tape"
    global input_tape_pos
    pos=input_tape_pos[tape_reader]
    x=input_tape[tape_reader][pos]
    input_tape_pos[tape_reader]=pos + 1
    if pos>=input_tape_len[tape_reader]: report("reading off end of tape")
    store[m]=x
    modifier[q]=x
# flash input busy light
    lamp_show(input_busy_light, True)
    gui.update()
    lamp_show(input_busy_light, False)

def op70(m, q):
    "set modifier"
    modifier[q]=m

def op71(m, q):
    "set modifier negative"
    modifier[q]=(2048 - m) & 0x7FF

def op72(m, q):
    "increment modifier"
    modifier[q]=(modifier[q] + m) & 0x7FF

def op73(m, q):
    "decrement modifier"
    modifier[q]=(modifier[q] - m) & 0x7FF

def op74(m, q):
    "increment, skip if zero"
    modifier[q]=(modifier[q] + 2) & 0x7FF
    if not (modifier[q]==0 or modifier[q]==1) : modifier[r]=m - 1

def op75(m, q):
    "decrement, skip if zero"
    modifier[q]=(modifier[q] - 2) & 0x7FF
    if  not (modifier[q]==0 or modifier[q]==2047): modifier[r]=m - 1

def op76(m, q):
    "skip if modifier >= m"
    if modifier[q]>=m: modifier[r]=modifier[r] + 1

def op77(m, q):
    "skip if modifier < m"
    if modifier[q]<m: modifier[r]=modifier[r] + 1

def op78(m, q):
    "add to modifier and store"
    modifier[q]=(modifier[q] + get_a(m)) & 0x7FF
    put_a(m, q)

def op79(m, q):
    "store modifier"
    put_a(m, q)

def op80(m, q):
    "set modifier from store"
    modifier[q]=get_a(m)

def op81(m, q):
    "set modifier negative from store"
    modifier[q]=(2048 - get_a(m)) & 0x7FF

def op82(m, q):
    "increment modifier by store"
    modifier[q]=(modifier[q] + get_a(m)) & 0x7FF

def op83(m, q):
    "decrement modifier by store"
    modifier[q]=(modifier[q] - get_a(m)) & 0x7FF

def op84(m,q ):
    report("non-existant order")

def op85(m, q):
    report("non-existant order")

def op86(m, q):
    "skip if modifier >= a(m)"
    if modifier[q]>=get_a(m): modifier[r]=modifier[r] + 1

def op87(m, q):
    "skip if modifier < a(m)"
    if modifier[q]<get_a(m): modifier[r]=modifier[r] + 1

def op88(m, q):
    "swap modifier and store"
# probably refers to free store not current store
    global store
    copy=store
    store=free
    temp=get_a(m)
    put_a(m, q)
    modifier[q]=temp
    store=copy

def op89(m, q):
    "store modifier as function bits of order"
    global store
    store[m] = ((modifier[q] & 0x1FF) << 11) + (store[m] & 0x7FF)

def op90(m, q):
    "scale"
    global M, L
    A=ML_to_signedA(M,L)
    if A==0: modifier[q]=2048-129; modifier[r]=m-1;  return
    n=0
    while 2*A<=maxA and 2*A>=minA: A=2*A; n=n+1
    (M,L)=signedA_to_ML(A)
    modifier[q]=2048 - n

def op91(m, q):
    report("non-existant order")

def op92(m, q):
    report("non-existant order")

def op93(m, q):
    report("non-existant order")

def op94(m, q):
    report("non-existant order")

def op95(m, q):
    report("non-existant order")

def op96(m):
    "float"
    global M, L
    A=ML_to_signedA(M,L)
    if m<1024:  A=float(A)*2**(m-78)
    if m>=1024: A=float(A)*2**(m-2048-78)
    M=float2M(A)
    L=0

def op97(m):
    report("non-existant order")

def op98(m):
    "same as 99 order but operating on reserved store"
# see 59f6 order
    global reserved
    if (m & 0x1)==0: reserved[m]=int((M & 0xFFFFF00000) >> 20)
    else:            reserved[m]=int(M & 0xFFFFF)

def op99(m):
    "store half accumulator in free store"
    global free
    if (m & 0x1)==0: free[m]=int((M & 0xFFFFF00000) >> 20)
    else:            free[m]=int(M & 0xFFFFF)

def op100(m):
    "load M from half registers"
# probably refers to free store not current store
    global store, M, L, alpha
    copy=store
    store=free
# case m even
    if (m & 0x1)==0: M=(store[m] << 20) + store[m+1]
# case m odd
    if (m & 0x1)==1: M=(store[m] << 20) + store[m]
    store=copy
    L=0
    alpha=False

def op101(m):
    "stop"
    global stop
    display_address(m)
    if store==free:     lamp_show(stop_light, True)
    if store==reserved: lamp_show(report_light, True)
    run_switch.set(0)
    stop=True

def op102(m):
    "wait"
    display_address(m)
    lamp_show(wait_light, True)
    run_switch.set(0)
# wait until run switch is lowered
    while run_switch.get()==0:
# check for new input tapes
        for i in [0, 1]:
            if new_input_tape[i]: read_input_tape(i)
        gui.update()
    display_address(0)
    lamp_show(wait_light, False)

def op103(m):
    report("non-existant order")

def op104(m):
    report("non-existant order")

def op105(m):
    "sets b from location m in free or main store as integer"
    global modifier
    if use_main_store: modifier[b]=int((main[main_store_address] >> 20) & 0x3FFF)
    else:
        even_m=m & 0x7FE
        modifier[b]=free[even_m] & 0x3FFF

def op106(m):
    "select input/output"
    global tape_reader, peripherals
    if m & 1:
        tape_reader=0
        peripherals = peripherals | 0x0008000000
    if m & 2:
        tape_reader=1
        peripherals = peripherals & 0xfff7ffffff
    if m & 4:  peripherals = peripherals | 0x0004000000
    if m & 8:  peripherals = peripherals & 0xfffbffffff
    if m & 16: peripherals = peripherals | 0x0002000000
    if m & 32: peripherals = peripherals & 0xfffdffffff

def op107(m):
    "output"
# 5 bits of m only, although manual does not mention the rest
    global outputchannel1, outputchannel2
    if peripherals & 0x0004000000: outputchannel1.append(m & 0x1F)
    if peripherals & 0x0002000000: outputchannel2.append(m & 0x1F)
# flash output busy light
    lamp_show(output_busy_light, True)
    gui.update()
    lamp_show(output_busy_light, False)

def op108(m):
    "stores modifier b in bits 6-19 of location m in free or main store"
    if use_main_store: main[main_store_address]=modifier[b] << 20
    else:
        even_m=m & 0x7FE
        free[even_m]=modifier[b]
        free[even_m+1]=0x00000

def op109(m):
    "store ignoring overflow"
    put_M_to_store(M,m)

def op110(m):
    "load M from reserved store"
    global M, L, alpha
# case m even
    if (m & 0x1)==0: M=(reserved[m] << 20) + reserved[m+1]
# case m odd
    if (m & 0x1)==1: M=(reserved[m] << 20) + reserved[m]
    L=0
    alpha=False

def op111(m):
    report("non-existant order")

def op112(m):
    "set or increment b"
    global modifier
    modifier[b]=int(main_store_address)

def op113(m):
    report("non-existant order")

def op114(m):
    "appears inaccessible and obsolete"
    report("non-existant order")

def op115(m):
    "start slave tape; not implemented, but mark slave movement finished"
    global reserved
    reserved[126]=0x80000

def op116(m):
    "control magtape motors"
    global magtape_number, magtape_speed, stop
#    print "start/stop mag tape", m
# edsac tapes are numbered 1,2,3,4 stored in array elements 0,1,2,3
    magtape_number=(m & 0x7) - 1
# software permits 8 tapes although only 4 exist
    if magtape_number >= 4:
        lamp_show(magtape_light, True)
        run_switch.set(0)
        stop=True
    motor=m & 0xFFFF8
    if motor==0:    magtape_speed=0
    if motor==1024: magtape_speed=1
    if motor==1152: magtape_speed=-1

def op117(m):
    "write block onto tape"
    global M, free, reserved, store
# if m odd get use reserved store, if even use free store
    if m & 0x1: store=reserved
    else:       store=free
    block=magtape[magtape_number][block_number]
    checksum=0
    datalength=modifier[t]/2 + 1
    for i in range(0, datalength):
        data=get_M_from_store(m+i+i)
        block[1][i]=data
        checksum+=data
# set checksum
    M=checksum  % (2**40 -1)
    block[2]=M
# set written block length
    block[0]=(block[0] & 0xFFFFFFF800) | 2*datalength 
# reset reserved store
    store=reserved
#    print "write", magtape_number, block_number, block[2], M

def op118(m):
    "read block from tape"
    global K, M, free, store
#    print "118 order", magtape_number, block_number, m
    block=magtape[magtape_number][block_number]
    datalength=modifier[t]//2 + 1
    data=block[1][0:datalength]
    K=sum(data) % (2**40 -1)
    checksum=block[2]
    M=K - checksum
# if m is odd do not store data
    if not (m & 0x1):
        store=free
        for i in range(0, datalength): put_M_to_store(data[i], m+i+i)
# reset store to reserved
    store=reserved
#    print "read", m, magtape_number, block_number, data, checksum

def op119(m):
    "read block label"
    global M
    put_M_to_store(magtape[magtape_number][block_number][0], 8)
    M=0
#    print magtape_number, block_number, store[8], store[9]

def op120(m):
    "optional stop"
    global M, L, alpha, reset
    M=0; L=0; alpha=False
    if m==16:
# digit 23 contains phase of mains cycle
        t=50.0*time.process_time()
        M=peripherals | (int(t - int(t) + 0.5) << 16)
    if m<8:
        lamp_show(optional_stop_light, True)
# wait until a key is raised or the reset button is pressed
        while (m==read_optstop_keys()) and (not reset):
            gui.update()
        lamp_show(optional_stop_light, False)
        reset=False
        if m & 1: M=read_manual_register()

def op121(m):
    "crt output"
    if not crt_exists: create_crt()
    if m==1:
# extract coords as signed integers in range +-512
        y=((M & 0x3FF) ^ 0x200) - 0x200
        x=(((M>>20) & 0x3FF) ^ 0x200) - 0x200
        brighten_spot(x,y)
    if m==2: report("Camera not implemented")

def op122(m):
    report("non-existant order")

def op123(m):
    report("non-existant order")

def op124(m):
    report("non-existant order")

# Need module struct here
import struct
import subprocess

def op125(m):
# This order does not exist on the real machine and is used by the music 
# playing progon only.
    global sound
    d32=((m ^ modifier[r]) & 0x20) << 2
    n=int((35+2*m)/9.5 + 0.5)
    for i in range(0,n): sound.append(0x0)
    sound.append(d32); sound.append(d32)

def op126(m):
# This order does not exist on the real machine and is used by the music 
# playing progon only.
    samples=len(sound)
    u=free[23]/35.0
    rate=int(1e6/(9.5*u))

    wavfile=open("sound.wav", 'wb')
    wavfile.write(b"RIFF")
    wavfile.write(struct.pack('<i', samples+36))
    wavfile.write(b'WAVEfmt ')
    wavfile.write(struct.pack('<i', 16))
    wavfile.write(struct.pack('<h', 1))
    wavfile.write(struct.pack('<h', 1))

    wavfile.write(struct.pack('<i', rate))
    wavfile.write(struct.pack('<i', rate))

    wavfile.write(struct.pack('<h', 1))
    wavfile.write(struct.pack('<h', 8))

    wavfile.write(b'data')
    wavfile.write(struct.pack('<i', samples))

    wavfile.write(sound)
    wavfile.close()

# The following line plays the sound file if 'sox' is installed.
# Edit the name of the player program or comment out the line if 
# no player is installed.
    subprocess.call(['play', "sound.wav"])

def op127(m):
    report("non-existant order")

# code to display cause of report in emulator, enters report routine
def report(x):
    global store
    set_cause_of_report(x)
    store=reserved
    set_store_neon(reserved)
    modifier[r]=511

# look-up table of functions
ops=[eval("op" + str(i)) for i in range(0,128)]

