8f4fe42819312f4a8aecbfca79065ecb9944207c
[Mograsim.git] / net.mograsim.logic.core / src / net / mograsim / logic / core / components / CoreDemux.java
1 package net.mograsim.logic.core.components;
2
3 import java.util.List;
4
5 import net.mograsim.logic.core.timeline.Timeline;
6 import net.mograsim.logic.core.timeline.TimelineEventHandler;
7 import net.mograsim.logic.core.types.BitVector;
8 import net.mograsim.logic.core.wires.CoreWire;
9 import net.mograsim.logic.core.wires.CoreWire.ReadEnd;
10 import net.mograsim.logic.core.wires.CoreWire.ReadWriteEnd;
11
12 /**
13  * Models a multiplexer. Takes an arbitrary amount of input {@link CoreWire}s, one of which, as determined by select, is put through to the
14  * output.
15  * 
16  * @author Fabian Stemmler
17  *
18  */
19 public class CoreDemux extends BasicCoreComponent
20 {
21         private final ReadEnd select, in;
22         private final ReadWriteEnd[] outputs;
23         private final int outputSize;
24         private int selected = -1;
25
26         /**
27          * Output {@link CoreWire}s and in must be of uniform width
28          * 
29          * @param in      Must be of uniform width with all outputs.
30          * @param select  Indexes the output array to which the input is mapped. Must have enough bits to index all outputs.
31          * @param outputs One of these outputs receives the input signal, depending on the select bits
32          */
33         public CoreDemux(Timeline timeline, int processTime, ReadEnd in, ReadEnd select, ReadWriteEnd... outputs)
34         {
35                 super(timeline, processTime);
36                 outputSize = in.width();
37
38                 this.in = in;
39                 this.outputs = outputs;
40                 for (int i = 0; i < this.outputs.length; i++)
41                 {
42                         if (outputs[i].width() != outputSize)
43                                 throw new IllegalArgumentException("All DEMUX wire arrays must be of uniform width!");
44                         this.outputs[i] = outputs[i];
45                 }
46
47                 this.select = select;
48                 select.registerObserver(this);
49
50                 int maxInputs = 1 << select.width();
51                 if (this.outputs.length > maxInputs)
52                         throw new IllegalArgumentException("There are more outputs (" + this.outputs.length + ") to the DEMUX than supported by "
53                                         + select.width() + " select bits (" + maxInputs + ").");
54                 in.registerObserver(this);
55         }
56
57         @Override
58         public TimelineEventHandler compute()
59         {
60                 int selectValue = select.getValues().isBinary() ? (int) select.getValues().getUnsignedValueLong() : -1;
61                 if (selectValue >= outputs.length)
62                         selectValue = -1;
63
64                 boolean hasOldSelection = selected != selectValue && selected != -1;
65                 int oldSelection = selected;
66                 boolean hasNewSelection = selectValue != -1;
67                 int newSelection = selectValue;
68                 BitVector inputValues = in.getValues();
69
70                 selected = selectValue;
71
72                 return e ->
73                 {
74                         if (hasOldSelection)
75                                 outputs[oldSelection].clearSignals();
76                         if (hasNewSelection)
77                                 outputs[newSelection].feedSignals(inputValues);
78                 };
79         }
80
81         @Override
82         public List<ReadEnd> getAllInputs()
83         {
84                 return List.of(in, select);
85         }
86
87         @Override
88         public List<ReadWriteEnd> getAllOutputs()
89         {
90                 return List.of(outputs);
91         }
92 }