adds a bit extender, see #76

This commit is contained in:
hneemann 2017-11-10 16:43:52 +01:00
parent 4053826889
commit d12fb1dfed
7 changed files with 157 additions and 1 deletions

View File

@ -22,10 +22,12 @@ public class Observable {
* Adds an observer to this observable.
*
* @param observer the observer to add
* @return observer the observer to add
*/
public void addObserver(Observer observer) {
public Observer addObserver(Observer observer) {
if (observer != null)
observers.add(observer);
return observer;
}
/**

View File

@ -0,0 +1,68 @@
package de.neemann.digital.core.arithmetic;
import de.neemann.digital.core.*;
import de.neemann.digital.core.element.Element;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.draw.elements.PinException;
import de.neemann.digital.lang.Lang;
import static de.neemann.digital.core.element.PinInfo.input;
/**
* Sign extension component
*/
public class BitExtender implements Element {
/**
* Description of the sign extend component.
*/
public static final ElementTypeDescription DESCRIPTION
= new ElementTypeDescription(BitExtender.class, input("in"))
.addAttribute(Keys.ROTATE)
.addAttribute(Keys.LABEL)
.addAttribute(Keys.OUTPUT_BITS);
private final ObservableValue out;
private final int outBits;
/**
* creates a new instance
*
* @param attr the components attributes
*/
public BitExtender(ElementAttributes attr) {
outBits = attr.get(Keys.OUTPUT_BITS);
out = new ObservableValue("out", outBits).setPinDescription(DESCRIPTION);
}
@Override
public void setInputs(ObservableValues inputs) throws NodeException {
final ObservableValue in = inputs.get(0);
final int inBits = in.getBits();
if (inBits >= outBits)
throw new NodeException(Lang.get("err_notMoreOutBitsThanInBits"));
final int signMask = 1 << (inBits - 1);
final int extendMask = ~((1 << inBits) - 1);
in.addObserver(() -> {
long inValue = in.getValue();
if ((inValue & signMask) == 0)
out.setValue(inValue);
else
out.setValue(inValue | extendMask);
}).hasChanged();
}
@Override
public ObservableValues getOutputs() throws PinException {
return out.asList();
}
@Override
public void registerNodes(Model model) {
// has no nodes! Is just wiring
}
}

View File

@ -31,6 +31,12 @@ public final class Keys {
public static final Key.KeyBits BITS
= new Key.KeyBits("Bits", 1);
/**
* output bits of sign extender
*/
public static final Key.KeyBits OUTPUT_BITS
= new Key.KeyBits("outputBits", 16);
/**
* number of inputs in simple gates like And and Or
*/

View File

@ -156,6 +156,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.add(BarrelShifter.DESCRIPTION)
.add(Comparator.DESCRIPTION)
.add(Neg.DESCRIPTION)
.add(BitExtender.DESCRIPTION)
.add(BitCount.DESCRIPTION))
.add(new LibraryNode(Lang.get("lib_switching"))
//.add(Diode.DESCRIPTION) // see class DiodeTest for further information

View File

@ -476,6 +476,13 @@
<string name="elem_Neg_pin_in">Eingang des Datenworts, welches im 2-er Komplement negiert werden soll.</string>
<string name="elem_Neg_pin_out">Gibt das Ergebnis der Negation im 2-er Komplement zurück.</string>
<string name="elem_Neg_tt">Ein Baustein für die Negation von Datenworten im 2-er Komplement.</string>
<string name="elem_BitExtender">Biterweiterung</string>
<string name="elem_BitExtender_tt">Erweitert die Bitanzahl eines vorzeichenbehafteten Eingangswertes unter
Erhalt des Vorzeichens.</string>
<string name="elem_BitExtender_pin_in">Einganswert.
Die Eingangsbitzahl muss kleiner sein als die Ausgangsbitzahl!</string>
<string name="elem_BitExtender_pin_out">Vorzeichenrichtig erweiterter Eingangswert.
Die Eingangsbitzahl muss kleiner sein als die Ausgangsbitzahl!</string>
<string name="elem_BitCount">Bitzähler</string>
<string name="elem_BitCount_tt">Gibt die Anzahl der 1-Bits im Eingangswert aus.</string>
<string name="elem_BitCount_pin_in">Die 1-Bits in diesem Datenwort werden gezählt.</string>
@ -717,6 +724,7 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="err_noMainFoundInManifest">Das Manifest enthält keinen Main-Class-Eintrag!</string>
<string name="err_mainClass_N_NotFound">Die Klasse {0} wurde nicht gefunden!</string>
<string name="err_couldNotInitializeMainClass_N">Es konnte keine Instanz der Klasse {0} erzeugt werden!</string>
<string name="err_notMoreOutBitsThanInBits">Es muss mehr Eingangsbits als Ausgangsbits geben!</string>
<string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Anzahl der Adress-Bits die verwendet werden.</string>
@ -896,6 +904,8 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="key_showWireBits">Zeigt die Anzahl der Leitungen auf einem Bus</string>
<string name="key_showWireBits_tt">Zeigt die Anzahl der Leitungen eines Bus an. ACHTUNG: Dieser Wert wird nur beim
Start der Simulation aktualisiert.</string>
<string name="key_outputBits">Anzahl Ausgangsbits</string><!-- BitExtender -->
<string name="key_outputBits_tt">Die Anzahl der Ausgangsbits muss größer sein als die Anzahl der Eingangsbits.</string>
<string name="mod_insertWire">Leitung eingefügt.</string>
<string name="mod_insertCopied">Aus Zwischenablage eingefügt.</string>

View File

@ -480,6 +480,12 @@
<string name="elem_Neg_tt">Negation in the 2th complement</string>
<string name="elem_Neg_pin_in">Input of the data word to be negated in 2th complement</string>
<string name="elem_Neg_pin_out">Returns the result of the negation in 2th complement.</string>
<string name="elem_BitExtender">SignExtend</string>
<string name="elem_BitExtender_tt">Increases the bit width of a signed value keeping the values sign.</string>
<string name="elem_BitExtender_pin_in">Input value.
The input bit width must be smaller than the output bit width!</string>
<string name="elem_BitExtender_pin_out">Extended input value.
The input bit width must be smaller than the output bit width!</string>
<string name="elem_BitCount">Bit counter</string>
<string name="elem_BitCount_tt">Returns the number of 1-bits in the input value.</string>
<string name="elem_BitCount_pin_in">The input which 1-bits are counted.</string>
@ -715,6 +721,7 @@ The names of the variables may not be unique.</string>
<string name="err_noMainFoundInManifest">The manifest does not contain a Main-Class entry!</string>
<string name="err_mainClass_N_NotFound">Could not find the class {0}!</string>
<string name="err_couldNotInitializeMainClass_N">Could not create an instance of the class {0}!</string>
<string name="err_notMoreOutBitsThanInBits">There must be more input bits than output bits!</string>
<string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Number of address bits used.</string>
@ -890,6 +897,8 @@ The names of the variables may not be unique.</string>
<string name="key_jarPath_tt">A jar file containing additional components implemented in java.</string>
<string name="key_showWireBits">Shows the number of wires on a bus.</string>
<string name="key_showWireBits_tt">CAUTION: The value is only updated when the simulation starts.</string>
<string name="key_outputBits">Output Bit Width</string><!-- BitExtender -->
<string name="key_outputBits_tt">The number of output bits must be greater than the number of input bits.</string>
<string name="mod_insertWire">Inserted wire.</string>
<string name="mod_insertCopied">Insert from clipboard.</string>

View File

@ -0,0 +1,60 @@
package de.neemann.digital.core.arithmetic;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.Keys;
import junit.framework.TestCase;
public class BitExtenderTest extends TestCase {
public void testSignExtend() throws Exception {
ObservableValue in = new ObservableValue("in", 4);
BitExtender bitExtender = new BitExtender(new ElementAttributes().set(Keys.OUTPUT_BITS, 8));
bitExtender.setInputs(in.asList());
assertEquals(1, bitExtender.getOutputs().size());
ObservableValue out = bitExtender.getOutputs().get(0);
check(in, out, 0, 0);
check(in, out, 1, 1);
check(in, out, 7, 7);
check(in, out, 8, -8);
check(in, out, 9, -7);
check(in, out, -1, -1);
check(in, out, -2, -2);
}
public void testSignExtendInit() throws Exception {
ObservableValue in = new ObservableValue("in", 4).setValue(1);
BitExtender bitExtender = new BitExtender(new ElementAttributes().set(Keys.OUTPUT_BITS, 8));
bitExtender.setInputs(in.asList());
assertEquals(1, bitExtender.getOutputs().get(0).getValue());
}
private void check(ObservableValue in, ObservableValue out, int inVal, int outVal) {
in.setValue(inVal);
assertEquals(outVal, (byte) out.getValue());
}
public void testSignExtendError() throws Exception {
try {
ObservableValue in = new ObservableValue("in", 4);
new BitExtender(new ElementAttributes().set(Keys.OUTPUT_BITS, 4)).setInputs(in.asList());
fail();
} catch (NodeException e) {
}
}
public void testSignExtendError2() throws Exception {
try {
ObservableValue in = new ObservableValue("in", 5);
new BitExtender(new ElementAttributes().set(Keys.OUTPUT_BITS, 4)).setInputs(in.asList());
fail();
} catch (NodeException e) {
}
}
}