File size: 2,724 Bytes
324ecd2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import random
import unittest
import torch
from beamboot.large_cpu import LargeCPU, LargeRuntime, encode_event


class LargeCPUEquivalenceTests(unittest.TestCase):
    def test_random_programs_against_independent_interpreter(self):
        rng = random.Random(2401)
        ops = ('LDI', 'ADD', 'SUB', 'LOAD', 'STORE', 'ADDM', 'SUBM', 'OUT')
        for _ in range(4):
            program = [(rng.choice(ops), rng.randrange(16)) for _ in range(70)] + [('HALT', 0)]
            machine = LargeRuntime(LargeCPU(program))
            memory, accumulator = [0]*16, 0
            for pc, (op, arg) in enumerate(program):
                step = machine.step()
                if op == 'LDI': accumulator = arg
                elif op == 'ADD': accumulator = (accumulator + arg) & 15
                elif op == 'SUB': accumulator = (accumulator - arg) & 15
                elif op == 'LOAD': accumulator = memory[arg]
                elif op == 'STORE': memory[arg] = accumulator
                elif op == 'ADDM': accumulator = (accumulator + memory[arg]) & 15
                elif op == 'SUBM': accumulator = (accumulator - memory[arg]) & 15
                self.assertEqual(step.acc, accumulator)
                self.assertEqual(step.pc, pc if op == 'HALT' else pc + 1)
                self.assertEqual(step.write, op == 'STORE')
                self.assertEqual(step.output, op == 'OUT')
                self.assertEqual(step.halt, op == 'HALT')
                if step.write: self.assertEqual((step.address, step.value), (arg, accumulator))

    def test_branches_and_high_rom_address(self):
        program = [('LDI', 3), ('SUB', 1), ('JZ', 40), ('JMP', 1)]
        program += [('HALT', 0)] * (40-len(program))
        program += [('LDI', 9), ('OUT', 0), ('HALT', 0)]
        runtime = LargeRuntime(LargeCPU(program))
        trace = []
        for _ in range(20):
            step = runtime.step(); trace.append(step)
            if step.halt: break
        self.assertTrue(runtime.halted)
        self.assertTrue(any(step.pc == 40 for step in trace))
        self.assertEqual([step.acc for step in trace if step.output], [9])

    def test_future_event_is_not_visible(self):
        model = LargeCPU([('LOAD', 1), ('HALT', 0)])
        events = [encode_event(address=i, valid=True) for i in range(16)]
        events += [encode_event(position=16), encode_event(address=1, value=14, valid=True, position=17)]
        original = torch.tensor([events], dtype=torch.float32)
        changed = original.clone(); changed[0, -1, 17:21] = 0
        with torch.inference_mode():
            one, two = model(original, last_only=False), model(changed, last_only=False)
        self.assertTrue(torch.equal(one[:, :-1], two[:, :-1]))