-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to create Bi-Directional IO in a JavaComponent #3
Comments
When you create the
Thank you very much! :-) |
Fantastic. Thanks I'll give that a try tonight and let you know how I get on. I'm considering donating my components to the project once I finish converting them, would you like to include them? For reference (I may not convert them all) but to date I have: 6502 CPU 6522 Via Simple Edge triggered counter/register Switchable register (IE: DUal load, rapid switching between to preset values) Real Time Clock (Pulse it's trigger and it reads and returns the PC's real time hour/minute/seconds value on it outputs. Pixel based 320x256 24bit bitmapped display 4x4 Keypad, with high pulse on key press and hex nibble of key on 4 bit output Binary file writer Binary file reader |
Well I now have a two way data bus, and it works great :-) Now I understand how it works, I'm going to wire up all the other parts, port, control lines etc. This should also allow me to simplify the 6502 CPU Too, doing bi-directional in Logisim was big pain, in Digital it's very easy. I think though, the project might benefit fro having a wiki here on the custom component project, that documents these things, sort of like a mini SDK documentation. |
If you are implementing/porting many components the most important rules are:
If you do not follow these rules, all kinds of hard-to-find errors can occur. Unfortunately, compliance with these rules cannot be enforced. You have to remember that yourself. |
Yep, picked that up quite quickly from your sample code :-) Good first rule too, that caused all kinds of mess in Logisim. Couple of things that did occur to me as I've been working however, just food for thought mainly.
In the 6522 model I'm building, it has 2 8 bit ports on it. Iv'e currently implemented them as one pin with an 8-bit width, however, the I/O port on the device has a register that can set individual pins on the port as either an IN or an OUT. I could easily just model it as 8 1 bit pins, but it would make for much more tidy connections if individual bit's could be set different ways at the same time on a multi bit connection.
In the 6522 for example, there are 3 input pins that are important, the clock, the R/W and the reset. It would be good to be able to say (If call was trigger by "clock" do xx else if trigger was "rw" do yyy) instead of checking every applicable pin every time. For the 6522 for example, if reset is pressed, then once that's done it's thing, it's not worth checking anything else, so we return, but in some cases order can be important, and reset might have to be checked last. Both of these are just ideas however, things that would make building new components for Digital even easier :-) I have a lot of experience building JavaSimulations for Logisim, and have built a lot of additions to it over the years, these are all lessons I learned the hard way :-) |
You don't need to call
It's possible to register your own listener to an input value by calling |
One important thing I forgot to mention: There are no real bidirectional splitters. And that is unfortunately a point that is very difficult to fix. Therefore it may not be useful to configure single bits as output or input. |
How on earth did I miss that one :-) I've been digging into the sources of Digital like crazy, and it was right under my nose.
Yes, I agree, for most components one would write, checking state in The port I/O and control on the device, are often used to connect other devices to a secondary data or I/O bus, for example the BBC Model B Micro uses one to pass data to/from it's sound hardware and keyboard controller. The Port Data and Control lines can change at any time, independent of the CPU interface, so in the case of this specific case, being able to seperate and handle the pins differently from the main input routine makes coding of the device simpler. Once again, fantastic... :-) If I was to volunteer to write these notes up for you, to go into a github Wiki how would you want me to do that? |
SO it's probably better for me to model the I/O pins as individual 1 bit connections then. I'll do some experimenting :-) |
I'll close this issue if it's ok with you. You answered things very fast and efficiently in the first couple of answers :-) |
In this case there is a more elegant solution: The base classes which are created if a model is generated is a |
Here is an example of a chip that contains three NOT gates. Each NOT gate is implemented as an isolated node that operates independently of the other nodes: package de.neemann.digital.plugin;
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 static de.neemann.digital.core.element.PinInfo.input;
public class MultiNot implements Element {
public static final ElementTypeDescription DESCRIPTION =
new ElementTypeDescription(MultiNot.class,
input("I_0"),
input("I_1"),
input("I_2"))
.addAttribute(Keys.BITS);
private final int bits;
private final ObservableValue out0;
private final ObservableValue out1;
private final ObservableValue out2;
private ObservableValues inputs;
public MultiNot(ElementAttributes attr) {
bits = attr.getBits();
out0 = new ObservableValue("O_0", bits);
out1 = new ObservableValue("O_1", bits);
out2 = new ObservableValue("O_2", bits);
}
@Override
public void setInputs(ObservableValues inputs) throws NodeException {
this.inputs = inputs;
for (ObservableValue i : inputs)
i.checkBits(bits, null);
}
@Override
public ObservableValues getOutputs() {
return new ObservableValues(out0, out1, out2);
}
@Override
public void registerNodes(Model model) {
model.add(new MyNotNode(inputs.get(0), out0));
model.add(new MyNotNode(inputs.get(1), out1));
model.add(new MyNotNode(inputs.get(2), out2));
}
private static class MyNotNode extends Node {
private final ObservableValue in;
private final ObservableValue out;
private long value;
private MyNotNode(ObservableValue in, ObservableValue out) {
this.in = in.addObserverToValue(this);
this.out = out;
}
@Override
public void readInputs() {
value = in.getValue();
}
@Override
public void writeOutputs() {
out.setValue(~value);
}
@Override
public ObservableValues getOutputs() {
return out.asList();
}
}
} |
oh cool. More experimenting for me to do :-) I've actually come up with a method based on your previous notes, that I'm quite pleased with and which works quite efficiently. First I created a "PinNameObserver"
And an interface to implement it:
Then I implmented my component as follows:
NOTE: This is still work in progress, so it's not complete. You can see however, that I now do the following for each pin I care about:
Order doesn't seem to matter, but essentially what happens is that, my new PinNameObserver fires first, and that calls back to the parent class, via this method (Implemented in accordance witht he interface)
This passes back the name I passed in when I added the observer, and then calls the regular Cheers |
It is possible that two pins have changed if rw.addObserver(() -> rwHasChanged = true);
clock.addObserver(() -> clockHasChanged = true);
reset.addObserver(() -> resetHasChanged = true);
portbIN.addObserver(() -> portbINHasChanged = true); Using one boolean flag for each input you care about. |
oh that looks neater. :-) More wood added to the fire, and yes totally get your point about being called twice, just finished debugging EXACTLY that scenario. Here's the current state of play, with what I'm attempting. Component Sources are in one Zip, and test Dig file in the other attached to excercise it. (I'm working in Netbeans 8.x by the way) 6522test.zip And for reference, the datasheet I'm working from can be found here: http://archive.6502.org/datasheets/mos_6522_preliminary_nov_1977.pdf and the rockwell version here: http://archive.6502.org/datasheets/rockwell_r6522_via.pdf (I'm mostly working from the rockwell version of the chip) To test: setting RS=2, Databus=255, RW=0 and toggling the clock line to 1, should write 255 into the datadirection register thus setting PortB as an output port (Make sure you change the dip switch first), once reg 2 is set, then change RS=0 and any value you then put on the databus, followed by a clock toggle to 1, should put that value on the PortB output. Setting reg2 (RS=2) back to 0 will switch portb back to input mode (Remember to change this to input, before you change the dipswitch on portb's wires, otherwise you'll end up in an invalid state.) You should be able to see now, from what I've done so far, why some of the inputs have to be independent, PortB when set as an input for example, has to latch it's data in register 0, ready for the processor interface to want to read it onto the databus at it's own lesiure. I'll do some experimenting with your ideas tomorrow. :-) |
I have looked into your code: This way you can use the build-in generic shape more flexible. In this case the width is set to 5: public class ShawtysComponentSource implements ComponentSource {
@Override
public void registerComponents(ComponentManager manager) throws InvalidNodeException {
manager.addComponent("shawty", RealTimeClock.DESCRIPTION,
(attr, in, out) -> new GenericShape("RTC", in, out,
attr.getLabel(), true, 5));
manager.addComponent("shawty", R6522Via.DESCRIPTION,
(attr, in, out) -> new GenericShape("R6522Via", in, out,
attr.getLabel(), true, 5));
}
public static void main(String[] args) {
new Main.MainBuilder()
.setLibrary(new ElementLibrary().registerComponentSource(new ShawtysComponentSource()))
.openLater();
}
} In contrast to my proposal yesterday, I think such a solution to detect a pin change is easier to understand and also faster in comparison to adding an additional observer to the value: final boolean thisRW = rw.getBool();
if (thisRW != lastRW) {
lastRW = thisRW;
...
} |
Great stuff, will look at implementing that today. Yet another great addition :-) I was going to ask if there was a way just to increase the default rectangle size, but I was going to leave that until after the main dev was finished. Once again, great work :-) |
Latest version. Uses bools to detect pins now instead of extra Observable, and used the change to the component loader to increase the rectangle size. PortA and PortB now work correctly, still all or nothing though, 0 in the DDRA/DDRB register makes all inputs, anything greater makes All Outputs, but again this is beacuse I've not really thought of a good way to handle this other than making single I/O lines. R/W on the chip behaves as expected, and changes on the ports when they are set to inputs loads the internal registers etc. Next on my list, is the reset pin, and the timer functionality. :-) |
PS: Feel free to add the code for these to this Github if you wish, as a more complex example. |
JUst a quck note. Sorry been no updates, Windows Update deaded my main PC, only just got the thing fixed and the OS reinstalled, now to re-inst all my software ... |
First off Great Project @hneemann I loved Logisim, and used to use it extensively for helping design arduino and PicMicro circuits.
I'm porting all of my Custom Logisim Components over to Digital, and the one I'm on with at the moment (A rockwell 6522 VIA) requires me to have a 2 way data bus, controlled from a r/w line on the device.
From what I can see so far, once an input is set as an input, and an output is set as an output, they can't be changed.
I understand the mathod of connecting two sets of pins together in a circuit based component, but I can't see a clean way to perform the same thing in a Java Component.
Is this by design, something your planning on addressing, or just not possible?
Do you have any advice on how to do this?
Shawty
PS: I'm really pleased with your simplification of the Java Component base class, it's wonderfull compared to the way Logisim did things.
The text was updated successfully, but these errors were encountered: