-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransfer.test.py
More file actions
213 lines (148 loc) · 7.37 KB
/
Copy pathtransfer.test.py
File metadata and controls
213 lines (148 loc) · 7.37 KB
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from mapper import transfer
class RegisterTest(unittest.TestCase):
def test_the_enable_register_belongs_to_the_processor_not_the_display(self) -> None:
self.assertEqual(transfer.ENABLE, 0x420B)
def test_the_indirect_enable_register_sits_beside_it(self) -> None:
self.assertEqual(transfer.ENABLE_INDIRECT, 0x420C)
def test_the_channel_registers_start_where_the_processor_puts_them(self) -> None:
self.assertEqual(transfer.CHANNEL_BASE, 0x4300)
def test_the_channel_registers_are_not_in_the_display_window(self) -> None:
self.assertFalse(0x2100 <= transfer.ENABLE < 0x2200)
self.assertFalse(0x2100 <= transfer.CHANNEL_BASE < 0x2200)
def test_a_channel_takes_sixteen_registers(self) -> None:
self.assertEqual(transfer.CHANNEL_STRIDE, 0x10)
def test_the_last_channel_ends_inside_the_window(self) -> None:
last = transfer.CHANNEL_BASE + (transfer.CHANNEL_COUNT - 1) * transfer.CHANNEL_STRIDE
self.assertLess(last + transfer.CHANNEL_STRIDE, 0x4400)
class ChannelIndexTest(unittest.TestCase):
def test_an_address_names_the_channel_it_belongs_to(self) -> None:
self.assertEqual(transfer.channel_of(0x4300), 0)
self.assertEqual(transfer.channel_of(0x4370), 7)
def test_the_index_comes_from_the_whole_nibble_not_three_bits(self) -> None:
self.assertIsNone(transfer.channel_of(0x4380))
def test_an_address_outside_the_window_belongs_to_no_channel(self) -> None:
for address in (0x420B, 0x2100, 0x4200, 0x4400):
self.assertIsNone(transfer.channel_of(address))
def test_every_register_of_a_channel_names_that_channel(self) -> None:
for offset in range(transfer.CHANNEL_STRIDE):
self.assertEqual(transfer.channel_of(0x4320 + offset), 2)
class ChannelTest(unittest.TestCase):
def test_a_channel_starts_holding_nothing_it_was_told(self) -> None:
self.assertEqual(transfer.Channel(0).count, 0)
def test_the_parameters_split_into_direction_and_step(self) -> None:
channel = transfer.Channel(0)
channel.write(0x00, 0x80)
self.assertTrue(channel.to_cpu)
def test_a_fixed_transfer_does_not_advance_its_source(self) -> None:
channel = transfer.Channel(0)
channel.write(0x00, 0x08)
self.assertEqual(channel.step, 0)
def test_a_decrementing_transfer_walks_backwards(self) -> None:
channel = transfer.Channel(0)
channel.write(0x00, 0x10)
self.assertEqual(channel.step, -1)
def test_the_source_is_assembled_from_three_registers(self) -> None:
channel = transfer.Channel(0)
channel.write(0x02, 0x34)
channel.write(0x03, 0x12)
channel.write(0x04, 0x7E)
self.assertEqual(channel.source, 0x7E1234)
def test_the_count_is_assembled_from_two_registers(self) -> None:
channel = transfer.Channel(0)
channel.write(0x05, 0x00)
channel.write(0x06, 0x08)
self.assertEqual(channel.count, 0x0800)
def test_a_count_of_zero_means_the_whole_range(self) -> None:
self.assertEqual(transfer.Channel(0).length, 0x10000)
def test_the_destination_register_is_kept_low(self) -> None:
channel = transfer.Channel(0)
channel.write(0x01, 0x18)
self.assertEqual(channel.destination, 0x2118)
class EngineTest(unittest.TestCase):
def test_an_engine_has_eight_channels(self) -> None:
self.assertEqual(len(transfer.Engine().channels), transfer.CHANNEL_COUNT)
def test_nothing_is_enabled_before_anything_is_asked(self) -> None:
self.assertEqual(transfer.Engine().enabled, [])
def test_enabling_a_channel_lists_it(self) -> None:
engine = transfer.Engine()
engine.write(transfer.ENABLE, 0x05)
self.assertEqual(engine.enabled, [0, 2])
def test_a_channel_that_was_never_configured_is_still_reported_when_enabled(self) -> None:
engine = transfer.Engine()
engine.write(transfer.ENABLE, 0x01)
self.assertEqual(engine.enabled, [0])
def test_a_configured_channel_that_is_not_enabled_is_left_out(self) -> None:
engine = transfer.Engine()
engine.write(0x4302, 0x00)
engine.write(0x4303, 0x80)
self.assertEqual(engine.enabled, [])
def test_the_indirect_enable_register_is_kept_apart_from_the_other(self) -> None:
engine = transfer.Engine()
engine.write(transfer.ENABLE_INDIRECT, 0xC0)
self.assertEqual(engine.enable_indirect, 0xC0)
self.assertEqual(engine.enable, 0x00)
def test_arming_indirect_channels_does_not_arm_the_ordinary_ones(self) -> None:
engine = transfer.Engine()
engine.write(transfer.ENABLE_INDIRECT, 0xFF)
self.assertEqual(engine.enabled, [])
def test_a_write_reaches_the_channel_it_addresses(self) -> None:
engine = transfer.Engine()
engine.write(0x4321, 0x18)
self.assertEqual(engine.channels[2].destination, 0x2118)
def test_a_write_outside_the_window_is_ignored(self) -> None:
engine = transfer.Engine()
engine.write(0x2100, 0xFF)
self.assertEqual(engine.channels[0].registers[0], 0)
def test_a_transfer_reports_what_it_would_move(self) -> None:
engine = transfer.Engine()
engine.write(0x4302, 0x00)
engine.write(0x4303, 0x00)
engine.write(0x4304, 0x7E)
engine.write(0x4305, 0x10)
engine.write(0x4306, 0x00)
engine.write(0x4301, 0x18)
engine.write(transfer.ENABLE, 0x01)
planned = engine.plans()
self.assertEqual(len(planned), 1)
self.assertEqual(planned[0].source, 0x7E0000)
self.assertEqual(planned[0].length, 0x0010)
def test_a_plan_names_the_addresses_a_transfer_would_read(self) -> None:
engine = transfer.Engine()
engine.write(0x4304, 0x7E)
engine.write(0x4305, 0x04)
engine.write(transfer.ENABLE, 0x01)
touched = engine.plans()[0].addresses()
self.assertEqual(touched, [0x7E0000, 0x7E0001, 0x7E0002, 0x7E0003])
def test_a_fixed_transfer_reads_one_address_over_and_over(self) -> None:
engine = transfer.Engine()
engine.write(0x4300, 0x08)
engine.write(0x4304, 0x7E)
engine.write(0x4305, 0x03)
engine.write(transfer.ENABLE, 0x01)
self.assertEqual(engine.plans()[0].addresses(), [0x7E0000] * 3)
def test_a_transfer_that_walks_backwards_does_so(self) -> None:
engine = transfer.Engine()
engine.write(0x4300, 0x10)
engine.write(0x4302, 0x10)
engine.write(0x4304, 0x7E)
engine.write(0x4305, 0x03)
engine.write(transfer.ENABLE, 0x01)
self.assertEqual(engine.plans()[0].addresses(), [0x7E0010, 0x7E000F, 0x7E000E])
def test_a_source_that_runs_off_a_bank_wraps_inside_it(self) -> None:
engine = transfer.Engine()
engine.write(0x4302, 0xFF)
engine.write(0x4303, 0xFF)
engine.write(0x4304, 0x7E)
engine.write(0x4305, 0x02)
engine.write(transfer.ENABLE, 0x01)
self.assertEqual(engine.plans()[0].addresses(), [0x7EFFFF, 0x7E0000])
def test_a_plan_prints_as_its_channel_and_reach(self) -> None:
engine = transfer.Engine()
engine.write(transfer.ENABLE, 0x02)
self.assertIn("channel 1", repr(engine.plans()[0]))
if __name__ == "__main__":
unittest.main()