Skip to content

Commit ef7093e

Browse files
committed
First stab at datapath grader capabilities
1 parent cc2ba18 commit ef7093e

18 files changed

Lines changed: 947 additions & 315 deletions
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package edu.gatech.cs2110.circuitsim.api;
2+
3+
import java.io.InputStream;
4+
import java.util.Scanner;
5+
6+
public abstract class BaseMemory {
7+
public abstract void store(int address, int value);
8+
9+
/**
10+
* Loads a stream of a dat file into this component's memory. Format
11+
* is the same as the .dat files saved in the CircuitSim memory
12+
* editor window.
13+
*/
14+
public void load(InputStream stream) {
15+
Scanner scanner = new Scanner(stream);
16+
17+
int address = 0;
18+
while (scanner.hasNext()) {
19+
String word = scanner.next();
20+
21+
if (word.contains("-")) {
22+
// Roi's world-famous patented run-length encoding
23+
// `x-y', where x is the number of occurrences and y is a
24+
// hex word
25+
String[] pieces = word.split("-");
26+
if (pieces.length != 2) {
27+
throw new IllegalArgumentException("invalid run-length encoded word " + word);
28+
}
29+
int length = Integer.parseInt(pieces[0]);
30+
int value = Integer.parseInt(pieces[1], 16);
31+
32+
for (int i = 0; i < length; i++) {
33+
store(address++, value);
34+
}
35+
} else {
36+
int value = Integer.parseInt(word, 16);
37+
store(address++, value);
38+
}
39+
}
40+
}
41+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package edu.gatech.cs2110.circuitsim.api;
2+
3+
import java.util.function.Supplier;
4+
5+
/**
6+
* Provides useful bit twiddling operations.
7+
*/
8+
class Bits {
9+
/**
10+
* Sign-extends a value.
11+
*/
12+
static int sext(int orig, int bits) {
13+
// x << 32 == x if x is a java int, so exclude that case
14+
if (bits < 32 && (orig & (1 << (bits - 1))) != 0) {
15+
return orig | (-1 << bits);
16+
} else {
17+
return orig;
18+
}
19+
}
20+
21+
/**
22+
* An IllegalStateException is thrown when at least one bit is floating.
23+
* But it just says "Invalid value," so throw a more human-friendly error
24+
* message for the sake of students' mental stability.
25+
*/
26+
static <T> T betterFloatingErrorMessage(Supplier<T> x) {
27+
try {
28+
return x.get();
29+
} catch (IllegalStateException err) {
30+
if (err.getMessage().equals("Invalid value")) {
31+
throw new IllegalStateException(
32+
"At least one output bit is floating (undefined, or blue " +
33+
"in CircuitSim). Is the output pin connected to anything?", err);
34+
} else {
35+
throw err;
36+
}
37+
}
38+
}
39+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package edu.gatech.cs2110.circuitsim.api;
2+
3+
// TODO FIXME document
4+
public class Button extends MockPulser {
5+
public Button(InputPin mockPin, Subcircuit subcircuit) {
6+
super(mockPin, subcircuit);
7+
}
8+
9+
public void press() {
10+
pulse();
11+
}
12+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package edu.gatech.cs2110.circuitsim.api;
2+
3+
import java.util.function.BooleanSupplier;
4+
5+
// TODO FIXME document
6+
public class Clock extends MockPulser {
7+
public Clock(InputPin mockPin, Subcircuit subcircuit) {
8+
super(mockPin, subcircuit);
9+
}
10+
11+
public void tick() {
12+
pulse();
13+
}
14+
15+
public long tickUntil(long maxCycleCount, BooleanSupplier stopWhen) {
16+
long ticks = 0;
17+
while (!stopWhen.getAsBoolean()) {
18+
if (ticks > maxCycleCount) {
19+
throw new IllegalStateException(
20+
"Ticked clock more than " + maxCycleCount + " times without finishing. " +
21+
"Please check for errors in your logic");
22+
}
23+
24+
tick();
25+
}
26+
return ticks;
27+
}
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package edu.gatech.cs2110.circuitsim.api;
2+
3+
// TODO FIXME document
4+
public abstract class MockPulser {
5+
protected InputPin mockPin;
6+
protected Subcircuit subcircuit;
7+
8+
public MockPulser(InputPin mockPin, Subcircuit subcircuit) {
9+
this.mockPin = mockPin;
10+
this.subcircuit = subcircuit;
11+
}
12+
13+
public InputPin getMockPin() {
14+
return mockPin;
15+
}
16+
17+
public Subcircuit getSubcircuit() {
18+
return subcircuit;
19+
}
20+
21+
protected void pulse() {
22+
mockPin.set(0b0);
23+
mockPin.set(0b1);
24+
mockPin.set(0b0);
25+
}
26+
}

src/main/java/edu/gatech/cs2110/circuitsim/api/OutputPin.java

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,9 @@ public OutputPin(Pin pin, Subcircuit subcircuit) {
2828
* @see getSext
2929
*/
3030
public int get() {
31-
try {
32-
return subcircuit.getCircuitState().getLastReceived(pin.getPort(Pin.PORT)).getValue();
33-
} catch (IllegalStateException err) {
34-
// An IllegalStateException is thrown when at least one bit
35-
// is floating. But it just says "Invalid value," so throw a
36-
// more human-friendly error message
37-
throw new IllegalStateException(
38-
"At least one output bit is floating (undefined, or blue in CircuitSim). " +
39-
"Is the output pin connected to anything?");
40-
}
31+
return Bits.betterFloatingErrorMessage(() ->
32+
subcircuit.getCircuitState().getLastReceived(pin.getPort(Pin.PORT))
33+
.getValue());
4134
}
4235

4336
/**
@@ -49,14 +42,6 @@ public int get() {
4942
* @see get
5043
*/
5144
public int getSext() {
52-
int got = get();
53-
int bits = pin.getBitSize();
54-
55-
// x << 32 == x if x is a java int, so exclude that case
56-
if (bits < 32 && (got & (1 << (bits - 1))) != 0) {
57-
return got | (-1 << bits);
58-
} else {
59-
return got;
60-
}
45+
return Bits.sext(get(), pin.getBitSize());
6146
}
6247
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package edu.gatech.cs2110.circuitsim.api;
2+
3+
import com.ra4king.circuitsim.simulator.components.memory.RAM;
4+
5+
/**
6+
* Wraps a CircuitSim RAM component.
7+
*
8+
* @author Austin Adams
9+
*/
10+
public class Ram extends BaseMemory {
11+
private RAM ram;
12+
private Subcircuit subcircuit;
13+
14+
/**
15+
* Creates a new Ram which wraps the provided {@code RAM}
16+
* component and which lives in the provided {@code Subcircuit}.
17+
*
18+
* @param ram {@code RAM} component to wrap
19+
* @param subcircuit where this pin lives
20+
*/
21+
public Ram(RAM ram, Subcircuit subcircuit) {
22+
this.ram = ram;
23+
this.subcircuit = subcircuit;
24+
}
25+
26+
@Override
27+
public void store(int address, int value) {
28+
ram.store(subcircuit.getCircuitState(), address, value);
29+
}
30+
31+
/**
32+
* Returns the internal CircuitSim {@code RAM} component this
33+
* object wraps.
34+
* <p>
35+
* <b>This exposes an internal CircuitSim API. Do not use unless you
36+
* know what you are doing.</b>
37+
*
38+
* @return the CircuitSim {@code RAM} component wrapped by this
39+
* object.
40+
*/
41+
public RAM getRAM() {
42+
return ram;
43+
}
44+
45+
/**
46+
* Returns the {@link Subcircuit}, a wrapper around a CircuitSim
47+
* {@code CircuitBoard} where this Pin lives.
48+
*
49+
* @return the {@link Subcircuit} where this pin lives
50+
*/
51+
public Subcircuit getSubcircuit() {
52+
return subcircuit;
53+
}
54+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package edu.gatech.cs2110.circuitsim.api;
2+
3+
import static com.ra4king.circuitsim.simulator.components.memory.Register.PORT_OUT;
4+
5+
/**
6+
* Wraps a CircuitSim Register component. Currently changing the value
7+
* of the register is not supported, but you can observe its value.
8+
*
9+
* @author Austin Adams
10+
*/
11+
public class Register {
12+
private com.ra4king.circuitsim.simulator.components.memory.Register reg;
13+
private Subcircuit subcircuit;
14+
15+
/**
16+
* Creates a new Register which wraps the provided {@code Register}
17+
* component and which lives in the provided {@code Subcircuit}.
18+
*
19+
* @param reg {@code Register} component to wrap
20+
* @param subcircuit where this pin lives
21+
*/
22+
public Register(com.ra4king.circuitsim.simulator.components.memory.Register reg,
23+
Subcircuit subcircuit) {
24+
this.reg = reg;
25+
this.subcircuit = subcircuit;
26+
}
27+
28+
/**
29+
* Returns the current value of the register. This value is not sign
30+
* extended.
31+
*/
32+
public int getQ() {
33+
return Bits.betterFloatingErrorMessage(() ->
34+
subcircuit.getCircuitState().getLastPushed(reg.getPort(PORT_OUT)).getValue());
35+
}
36+
37+
/**
38+
* Returns the current value of the register, sign-extended to 32
39+
* bits. Like {@code getQ()} except sign-extended.
40+
*/
41+
public int getQSext() {
42+
return Bits.sext(getQ(), reg.getBitSize());
43+
}
44+
45+
/**
46+
* Returns the internal CircuitSim {@code Register} component this
47+
* object wraps.
48+
* <p>
49+
* <b>This exposes an internal CircuitSim API. Do not use unless you
50+
* know what you are doing.</b>
51+
*
52+
* @return the CircuitSim {@code Register} component wrapped by this
53+
* object.
54+
*/
55+
public com.ra4king.circuitsim.simulator.components.memory.Register getRegister() {
56+
return reg;
57+
}
58+
59+
// TODO FIXME document
60+
public MockRegister mock() {
61+
return subcircuit.mockRegister(reg);
62+
}
63+
64+
/**
65+
* Returns the {@link Subcircuit}, a wrapper around a CircuitSim
66+
* {@code CircuitBoard} where this Register lives.
67+
*
68+
* @return the {@link Subcircuit} where this pin lives
69+
*/
70+
public Subcircuit getSubcircuit() {
71+
return subcircuit;
72+
}
73+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package edu.gatech.cs2110.circuitsim.api;
2+
3+
import com.ra4king.circuitsim.simulator.components.memory.ROM;
4+
5+
/**
6+
* Wraps a CircuitSim RAM component.
7+
*
8+
* @author Austin Adams
9+
*/
10+
public class Rom extends BaseMemory {
11+
private ROM rom;
12+
private Subcircuit subcircuit;
13+
14+
/**
15+
* Creates a new Ram which wraps the provided {@code RAM}
16+
* component and which lives in the provided {@code Subcircuit}.
17+
*
18+
* @param rom {@code RAM} component to wrap
19+
* @param subcircuit where this pin lives
20+
*/
21+
public Rom(ROM rom, Subcircuit subcircuit) {
22+
this.rom = rom;
23+
this.subcircuit = subcircuit;
24+
}
25+
26+
@Override
27+
public void store(int address, int value) {
28+
rom.getMemory()[address] = value;
29+
subcircuit.getCircuit().forEachState(state -> rom.valueChanged(state, null, 0));
30+
}
31+
32+
/**
33+
* Returns the internal CircuitSim {@code RAM} component this
34+
* object wraps.
35+
* <p>
36+
* <b>This exposes an internal CircuitSim API. Do not use unless you
37+
* know what you are doing.</b>
38+
*
39+
* @return the CircuitSim {@code RAM} component wrapped by this
40+
* object.
41+
*/
42+
public ROM getROM() {
43+
return rom;
44+
}
45+
46+
/**
47+
* Returns the {@link Subcircuit}, a wrapper around a CircuitSim
48+
* {@code CircuitBoard} where this Pin lives.
49+
*
50+
* @return the {@link Subcircuit} where this pin lives
51+
*/
52+
public Subcircuit getSubcircuit() {
53+
return subcircuit;
54+
}
55+
}

0 commit comments

Comments
 (0)