summaryrefslogtreecommitdiff
path: root/logiccircuitframework/components.py
blob: 9f6cbcdfacfc35bc45d73c76ff4bdbac68fb3359 (plain)
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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
'''
Copyright (C) 2008 Guillaume Seguin <guillaume@segu.in>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.

Authors:
    Guillaume Seguin <guillaume@segu.in>
'''

class Component(object):

    auto_id = 1

    _id = None

    symbol = ""
    outputs = 1
    min_inputs = 2
    max_inputs = 128
    fixed_inputs = False
    inputs = 0

    x = 0
    y = 0

    parent_links = None
    child_links = None

    __backed_links = None

    circuit = None
    is_simple = True

    outputs_status = None

    pool = None

    def __init__(self, **kwargs):
        self._id = "g%d" % Component.auto_id
        Component.auto_id += 1
        self.parent_links = []
        self.child_links = []
        self.__backed_links = []
        self.outputs_status = {}
        if self.fixed_inputs:
            self.min_inputs = self.max_inputs = self.inputs
        self.add_to_pool()
        for attr in kwargs:
            setattr(self, attr, kwargs[attr])

    def __str__(self):
        return "[%s %s]" % (self.__class__.__name__, self.id)

    def _set_component_id(self, id):
        old_id, self._id = self._id, id
        self.pool.set_component_id(self, old_id)

    def _get_component_id(self):
        return self._id

    id = property(_get_component_id, _set_component_id)

    def add_to_pool(self):
        self.pool.register_component(self)

    def drop_from_pool(self):
        self.pool.unregister_component(self)

    def links_to(self, end):
        def check_end(link):
            return link.input_gate == end
        return filter(check_end, self.child_links)

    def links_from(self, start):
        def check_start(link):
            return link.output_gate == end
        return filter(check_start, self.parent_links)

    def _get_first_available_input(self):
        used_inputs = [link.input_id for link in self.parent_links]
        r = range(1, self.inputs + 1)
        free_inputs = [i for i in r if i not in used_inputs]
        if not free_inputs:
            return -1
        return free_inputs[0]

    first_available_input = property(_get_first_available_input)

    def _get_first_available_output(self):
        used_outputs = [link.output_id for link in self.child_links]
        r = range(1, self.outputs + 1)
        free_inputs = [i for i in r if i not in used_outputs]
        if not free_outputs:
            return 1
        return free_outputs[0]

    first_available_output = property(_get_first_available_output)

    def add_link(self, link):
        if (link.output_gate == self):
            self.child_links.append(link)
        else:
            self.parent_links.append(link)

    def del_link(self, link):
        if (link.output_gate == self):
            self.child_links.remove(link)
        else:
            self.parent_links.remove(link)

    def restore_links(self):
        links = self.__backed_links
        for link in links:
            link.restore()
        self.__backed_links = []
        return links

    def destroy_links(self):
        self.__backed_links = self.child_links + self.parent_links
        for link in self.__backed_links:
            link.destroy()

class Not(Component):

    fixed_inputs = True
    inputs = 1

    symbol = "~"

class And(Component):

    symbol = "&"

class Or(Component):

    symbol = "|"

class Nand(Component):

    symbol = "~&"

class Nor(Component):

    symbol = "~|"

class Xor(Component):

    symbol = "^"

class BusIn(Component):

    symbol = "BI"
    outputs = 1

class BusOut8(Component):

    symbol = "BO8"
    fixed_inputs = True
    inputs = 1
    outputs = 8

class BusOut16(Component):

    symbol = "BO16"
    fixed_inputs = True
    inputs = 1
    outputs = 16

class BusOut32(Component):

    symbol = "BO32"
    fixed_inputs = True
    inputs = 1
    outputs = 32

class Input(Component):

    symbol = "i"
    _input_id = 0

    fixed_inputs = True
    inputs = 0
    outputs = 1

    def add_to_pool(self):
        super(Input, self).add_to_pool()
        self.pool.register_input(self)

    def drop_from_pool(self):
        super(Input, self).drop_from_pool()
        self.pool.unregister_input(self)

    def set_input_id(self, id):
        self.pool.set_input_id(self, id)
        self._input_id = id

    def get_input_id(self):
        return self._input_id

    input_id = property(get_input_id, set_input_id)

class Output(Component):

    symbol = "o"
    _output_id = 0

    fixed_inputs = True
    inputs = 1
    outputs = 0

    def add_to_pool(self):
        super(Output, self).add_to_pool()
        self.pool.register_output(self)

    def drop_from_pool(self):
        super(Output, self).drop_from_pool()
        self.pool.unregister_output(self)

    def _set_output_id(self, id):
        self.pool.set_output_id(self, id)
        self._output_id = id

    def _get_output_id(self):
        return self._output_id

    output_id = property(_get_output_id, _set_output_id)

class Reg(Component):

    symbol = "r"
    
    fixed_inputs = True
    inputs = 1

    is_simple = False

class RegInput(Component):

    symbol = "ri"
    
    fixed_inputs = True
    inputs = 1
    outputs = 0

class RegOutput(Component):

    symbol = "ro"
    
    fixed_inputs = True
    inputs = 0
    outputs = 1

class Mux(Component):

    symbol = "mux"
    inputs = 3

    min_inputs = 3

class One(Component):

    symbol = "1"

    fixed_inputs = True
    inputs = 0

class Zero(Component):

    symbol = "0"

    fixed_inputs = True
    inputs = 0

class RAMR(Component):

    symbol = "RAMR"

    fixed_inputs = True
    inputs = 16

    outputs = 32

    is_simple = False

class RAMW(Component):

    symbol = "RAMW"

    fixed_inputs = True
    inputs = 49

    outputs = 0

    is_simple = False

class ROMR(Component):

    symbol = "ROMR"

    fixed_inputs = True
    inputs = 16

    outputs = 32

    is_simple = False

DEFAULT_COMPONENT_TYPES = [Not, And, Or, Nand, Nor, Xor, Input, Output,
                           Reg, RegInput, RegOutput, Mux, One, Zero,
                           RAMR, RAMW, ROMR, BusIn, BusOut8, BusOut16, BusOut32]

class ComponentsPool(object):

    components = None

    inputs = None
    outputs = None

    def __init__(self):
        self.reset()

    def reset(self):
        self.components = {}
        self.inputs = {}
        self.outputs = {}

    def register_component(self, component):
        id = component.id
        if id not in self.components:
            self.components[id] = component
            return
        i = 1
        id = "%ss%d" % (component.id, i)
        while id in self.components:
            i += 1
            id = "%ss%d" % (component.id, i)
        component._id = id
        self.components[id] = component

    def register_input(self, input):
        id = self.min_free_input_id
        if input.input_id == 0:
            input._input_id = id
        self.inputs[id] = input

    def register_output(self, output):
        id = self.min_free_output_id
        if output.output_id == 0:
            output._output_id = id
        self.outputs[id] = output

    def unregister_component(self, component):
        del self.components[component.id]

    def unregister_input(self, input):
        del self.inputs[input.input_id]

    def unregister_output(self, output):
        del self.outputs[output.output_id]

    def set_component_id(self, component, old_id):
        del self.components[old_id]
        self.register_component(component)

    def set_input_id(self, input, id):
        if input.input_id == id:
            return
        if id in self.inputs:
            old_input = self.inputs[id]
            old_input._input_id = input.input_id
            self.inputs[input.input_id] = old_input
        self.inputs[id] = input

    def set_output_id(self, output, id):
        if output.output_id == id:
            return
        if id in self.outputs:
            old_output = self.outputs[id]
            old_output._output_id = output.output_id
            self.outputs[output.output_id] = old_output
        self.outputs[id] = output

    def get_min_free_input_id(self):
        ids = self.inputs.keys()
        r = range(1, max(self.max_input_id + 1, len(ids) + 1) + 1)
        free_ids = [i for i in r if i not in ids]
        return min(free_ids)

    min_free_input_id = property(get_min_free_input_id)

    def get_min_free_output_id(self):
        ids = self.outputs.keys()
        r = range(1, max(self.max_output_id + 1, len(ids) + 1) + 1)
        free_ids = [i for i in r if i not in ids]
        return min(free_ids)

    min_free_output_id = property(get_min_free_output_id)

    def get_max_input_id(self):
        if not self.inputs:
            return 0
        return max(self.inputs.keys())

    max_input_id = property(get_max_input_id)

    def get_max_output_id(self):
        if not self.outputs:
            return 0
        return max(self.outputs.keys())

    max_output_id = property(get_max_output_id)

class ComponentFactory(object):

    component_types = None

    pool = None

    __register_cb = None
    __create_cb = None
    __component_loader = None

    def __init__(self, component_loader,
                 register_cb = None, create_cb = None):
        self.component_types = {}
        self.pool = ComponentsPool()
        self.__register_cb = register_cb
        self.__create_cb = create_cb
        self.__component_loader = component_loader
        self.__register_default_types()

    def reset(self):
        Component.auto_id = 1
        self.pool.reset()

    def __register_default_types(self):
        for component_type in DEFAULT_COMPONENT_TYPES:
            self.register_component_type(component_type)

    def register_component_type(self, component_type):
        component_type.pool = self.pool
        self.component_types[component_type.__name__] = component_type
        if self.__register_cb:
            self.__register_cb(component_type)

    def get_component_class(self, component_type):
        if component_type not in self.component_types:
            data = self.__component_loader(searched_name = component_type)
            if not data:
                return None
            circuit, name, symbol, inputs, outputs = data
            if name != component_type:
                return None
            component_type_class = self.create_component_type(*data)
            self.register_component_type(component_type_class)
        return self.component_types[component_type]

    def create_component(self, component_type, initial_data = None):
        component_class = self.get_component_class(component_type)
        if not component_class:
            raise RuntimeError, "Couldn't get component class, aborting"
        if initial_data:
            component = component_class(**initial_data)
        else:
            component = component_class()
        if self.__create_cb:
            self.__create_cb(component)
        return component

    def create_component_type(self, circuit, name, symbol, inputs, outputs):
        component_type = type(name, (Component,), {"is_simple": False})
        component_type.pool = self.pool
        component_type.circuit = circuit
        component_type.symbol = symbol
        component_type.fixed_inputs = True
        component_type.inputs = int(inputs)
        component_type.outputs = int(outputs)
        return component_type