Skip to content

Instantly share code, notes, and snippets.

@badocelot
Created March 28, 2018 04:03
Show Gist options
  • Save badocelot/c3b157d6ffdd352693f5d6ce766be709 to your computer and use it in GitHub Desktop.
Save badocelot/c3b157d6ffdd352693f5d6ce766be709 to your computer and use it in GitHub Desktop.
Little-Man Computer Simulator + 4-bit Rule110 program for it
class LMComputer:
class Memory:
def __init__(self):
self.__cells = [0] * 100
def __getitem__(self, key):
return self.__cells[key]
def __setitem__(self, key, value):
if isinstance(key, int) and 0 <= key <= 99:
if isinstance(value, int):
if 0 <= value <= 999:
self.__cells[key] = value
else:
raise ValueError(value)
else:
raise TypeError('value must be int')
else:
raise IndexError(key)
def __init__(self):
self.__memory = LMComputer.Memory()
self.__accumulator = 0
self.__program_counter = 0
self.__negative_flag = False
@property
def accumulator(self):
return self.__accumulator
@accumulator.setter
def accumulator(self, value):
if not isinstance(value, int):
raise TypeError(value)
self.negative_flag = False
self.overflow_flag = False
if value < 0:
self.__accumulator = 0
self.negative_flag = True
elif value > 999:
self.__accumulator = 999
self.overflow_flag = True
else:
self.__accumulator = value
@property
def memory(self):
return self.__memory
@property
def program_counter(self):
return self.__program_counter
@program_counter.setter
def program_counter(self, value):
if not isinstance(value, int):
raise TypeError(value)
elif not (0 <= value <= 99):
raise ValueError(value)
else:
self.__program_counter = value
def load(self, program):
for i in range(len(program)):
self.memory[i] = program[i]
@property
def negative_flag(self):
return self.__negative_flag
@negative_flag.setter
def negative_flag(self, value):
self.__negative_flag = bool(value)
def step(self):
instruction = self.memory[self.program_counter]
opcode = instruction // 100
address = instruction % 100
if instruction == 0:
return
elif instruction == 901:
self.accumulator = int(input())
elif instruction == 902:
print(self.accumulator)
elif opcode == 1:
self.accumulator += self.memory[address]
elif opcode == 2:
self.accumulator -= self.memory[address]
elif opcode == 3:
self.memory[address] = self.accumulator
elif opcode == 5:
self.accumulator = self.memory[address]
elif opcode == 6:
self.program_counter = address
return
elif opcode == 7:
if self.accumulator == 0 and not self.negative_flag:
self.program_counter = address
return
elif opcode == 8:
if self.accumulator != 0 or self.negative_flag:
self.program_counter = address
return
else:
raise ValueError("bad instruction at " + str(self.program_counter))
self.program_counter += 1
def reset(self):
self.accumulator = 0
self.program_counter = 0
self.negative_flag = False
self.__memory = LMComputer.Memory()
def run(self, address=99):
while self.program_counter != address and self.memory[self.program_counter] != 0:
self.step()
# dsl functions
add = lambda address: address + 100
sub = lambda address: address + 200
sta = lambda address: address + 300
lda = lambda address: address + 500
bra = lambda address: address + 600
brz = lambda address: address + 700
brp = lambda address: address + 800
inp = 901
out = 902
hlt = 0
rule110 = (
[bra(11)] + # 0 # jump past the data
[0] * 10 + # 1 - 10 # last row [1 - 5], next row [6 - 10]
[inp, sta(1)] + # 11 - 12 # get a number from input and store it @ 1
[inp, sta(2)] + # 13 - 14 # get a number from input and store it @ 2
[inp, sta(3)] + # 15 - 16 # get a number from input and store it @ 3
[inp, sta(4)] + # 17 - 18 # get a number from input and store it @ 4
[bra(22), 0] + # 19 - 20 #
[1] + # 21 # a one for use as data
# start: rule for first bit
[lda(4), brz(32)] + # 22 - 23 # test whether the left neighbor is 0
[lda(1), brz(29)] + # 24 - 25 # leading 1; check if leading 10 or 11
[sub(2), sta(6), bra(39)] + # 26 - 28 # leading 11
[lda(2), sta(6), bra(39)] + # 29 - 31 # leading 10
[add(1), add(2), brz(38)] + # 32 - 34 # leading 0; check if 000
[lda(21), sta(6), bra(39)] + # 35 - 37 # not 000 put a 1
[sta(6)] + # 38 # 000 - put a 0
# rule for second bit
[lda(1), brz(49)] + # 39 - 40 # test whether the left neighbor is 0
[lda(2), brz(46)] + # 41 - 42 # leading 1; check if leading 10 or 11
[sub(3), sta(7), bra(56)] + # 43 - 45 # leading 11
[lda(3), sta(7), bra(56)] + # 46 - 48 # leading 10
[add(2), add(3), brz(55)] + # 49 - 51 # leading 0; check if 000
[lda(21), sta(7), bra(56)] + # 52 - 54 # not 000 put a 1
[sta(7)] + # 55 # 000 - put a 0
# rule for third bit
[lda(2), brz(66)] + # 56 - 57 # test whether the left neighbor is 0
[lda(3), brz(63)] + # 58 - 59 # leading 1; check if leading 10 or 11
[sub(4), sta(8), bra(73)] + # 60 - 62 # leading 11
[lda(4), sta(8), bra(73)] + # 63 - 65 # leading 10
[add(3), add(4), brz(72)] + # 66 - 68 # leading 0; check if 000
[lda(21), sta(8), bra(73)] + # 69 - 71 # not 000 put a 1
[sta(8)] + # 72 # 000 - put a 0
# rule for fourth bit
[lda(3), brz(83)] + # 73 - 74 # test whether the left neighbor is 0
[lda(4), brz(80)] + # 75 - 76 # leading 1; check if leading 10 or 11
[sub(1), sta(9), bra(90)] + # 77 - 79 # leading 11
[lda(1), sta(9), bra(90)] + # 80 - 82 # leading 10
[add(4), add(1), brz(89)] + # 83 - 85 # leading 0; check if 000
[lda(21), sta(9), bra(90)] + # 86 - 88 # not 000 put a 1
[sta(9)] + # 89 # 000 - put a 0
# copy the new row over the last
[lda(6), sta(1)] + # 90 - 91 # copy value at 6 to 1
[lda(7), sta(2)] + # 92 - 93 # copy value at 7 to 2
[lda(8), sta(3)] + # 94 - 95 # copy value at 8 to 3
[lda(9), sta(4)] + # 96 - 97 # copy value at 9 to 4
[bra(22)] # 98 # go back to start
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment