hneemann / Digital

A digital logic designer and circuit simulator.
GNU General Public License v3.0
4.4k stars 443 forks source link

Sub 1 hertz clock #1113

Open nrivard opened 1 year ago

nrivard commented 1 year ago

Can we have a slower clock than 1 hertz? When I set it to 0.5 I get an integer underflow to a beyond fast clock but to me very slow clocks are perfectly valid. My circuit only appears to work while actually running and there are too many pins for me to change at the same time for a 1 hertz clock. I have tried the mode where you set the pins then advance, but the behavior is different to the running circuit.

hneemann commented 1 year ago

You can disable the real time clock and toggle it with a mouse click instead.

prlaba commented 1 year ago

Because Start real-time clock is a clock attribute, you can only change it when the simulation is stopped (like all other component attributes).

It would be very useful if you could enable and disable a clock's Start real-time clock attribute while the simulator is running. That would allow you stop a running clock, single-step it for a while, then restart it.

Is there another way to do this currently?

hneemann commented 1 year ago

There is a Break component. When such a component is connected to a signal in your circuit, the "Run To Break" button becomes active, and clicking this button clocks the circuit until a rising edge is detected on the break component. This is an efficient way to debug circuits. Only creating test cases is more efficient in my opinion.

prlaba commented 1 year ago

Hmm... I tried adding a Break component to my circuit, tied to an Input pin. The "Run to Break" button remained disabled (greyed out).

What am I doing wrong?

hneemann commented 1 year ago

First, the real-time clock must be deactivated. Using the break component means that the circuit must be controlled manually. It makes little sense to connect the Break component to an input. The break component is used to detect a specific state that occurs in the circuit that you want to examine and then jump to that state with a single click.

break.zip

prlaba commented 1 year ago

Having to disable the real time clock defeats what I'm trying to do: allow the clock to run in real time, at a relatively low frequency while I watch various signals, then stop (and restart) the clock at will. I assumed attaching the Break component's input pin to a button would do that, but apparently not. Having to manually advance the clock through hundreds of clock cycles while debugging is not an option.

I can do this easily in Logisim and Logisim-Evolution (including drilling down to subcircuits to see the state of all signals there), but apparently not in Digital.

If there is no way to do this in Digital, please consider providing this important capability.

By the way, the break.zip file you attached with your comment was empty. But I do now understand that the Run to Break button on the menu bar is enabled when I start a simulation that includes a Break component and a Clock component with its Start real time clock attribute disabled.

Thanks,

hneemann commented 1 year ago

The break component works similar to a breakpoint in a programming language. Here, too, you usually don't want to watch the program slowly work its way to the breakpoint, or click through the program line by line, but jump to the point of interest with one click.

I have updated the zip file.

nrivard commented 1 year ago

You can disable the real time clock and toggle it with a mouse click instead

This is also not really the same thing. In this mode, every action happens "at once" while if the clock were running i can do things in specific order, rather than "simultaneously".

prlaba commented 1 year ago

The break component works similar to a breakpoint in a programming language.

I fully understand breakpoints in software, I use them all the time.

But there's two problems using the Break component to debug simulated hardware in Digital:

1) It only breaks on signals derived from or synchronized with a clock. You can't break on asynchronous signals like the /INT control pin of a CPU. If you attach the Break component to such a signal, the break is never hit and the simulation stops with an error.

2) When the Run/Break button is pressed, the simulator iterates without updating the display until the break signal goes high. You can't watch the simulation progress until the break occurs.

Why not allow the Break component to be used with a clock whose Start in real mode attribute is checked? In that case, when the Run button is pressed the simulator runs as it does now, updating the display as signals change, but also checks the break input at each change of the clock output, and stops when the break input goes high. That would address both of the above issues.

The Run/Break button could continue working as it does now--enabled only if the clock's Start in real mode attribute is unchecked--and the simulator only updates the display when the break input goes high.

Is that possible to implement without a major redesign?

hneemann commented 1 year ago

It's not that hard! Here you can find a prototypical implementation (v0.30-9). But it has effects on many things and therefore it is very hard to test.

prlaba commented 1 year ago

Thank you! I'm not sure I understand what you mean re effects and hard to test, but I'll give it a try with some sample circuits.

prlaba commented 1 year ago

This is awesome! The Break component now works exactly as I wanted (breaks on both synchronous and asynchronous clock signals). And the new Pause button to start/stop the clock is even better. (Consider toggling the "pause" icon to a "play' icon when the clock is paused.) These two features make it so much easier to debug complex circuits.

Now all I need is a way to examine the state of subcircuits when the clock is paused. I'm guessing that one is not so easy.

Thanks again for your great support!

hneemann commented 1 year ago

I'm not sure I understand what you mean re effects and hard to test.

To increase the performance of the simulator, the model calculation and the model drawing run in different CPU threads. To pause and resume the running model, a complex interaction between the GUI thread and the model thread is necessary. This interaction is difficult to fully understand and difficult to test for correctness. And I don't want to release anything that I'm not reasonably sure is correct. That's why the Pause implementation is already six months old, and hasn't been merged yet.

prlaba commented 1 year ago

Ah yes, threads. Thanks for the explanation.

The new Pause/Resume button, whenever it's released, is a significant feature that reduces and sometimes eliminates the need for a Break component, as a user can now either step the clock or let it run until they manually pause it. And the real significance is being able to restart it without losing any state.

I created a simple circuit with a clock driving a 32-bit counter. A probe showed the counter's output in binary.

I connected the counter's output to the A input of a 32-bit comparator, and connected its B inputs to the constant 0xFFFFF. I connected its = output to a Break component.

With the clock's Start in real time attribute enabled and its frequency set to 500000, I started the simulation and was able to watch the counter's output advance toward the 0xFFFFF breakpoint. I was able to press the Pause/Resume button to pause and resume the clock as expected (I could pause the clock, advance it manually a few cycles, then resume it). The simulation paused when the counter reached 0xFFFFF.

If I disabled the clock's Start in real time attribute and started the simulation, I could press the Run to Break button and have the simulation run at its maximum speed until the break was hit. In my case that was about a second.

I did notice that the counter's display changed before the breakpoint was hit, suggesting that the simulation is still updating the display while sequencing to the breakpoint. (I thought the display would not be updated until the breakpoint was reached, for better performance.)

In the new design, is hitting the breakpoint the same as pressing the Pause button? It seems not, as when my circuit hit the breakpoint I could not manually toggle the clock. But if I then pressed the Pause/Resume button twice (pause and resume), I could.

I hope your testing of these new features goes well, and that you're able to release them soon--I'm sure others like me will reap the benefits.

If I can help in any way as an "end user", let me know.

hneemann commented 1 year ago

In the new design, is hitting the breakpoint the same as pressing the Pause button?

Yes, it is. Or at least it should be.

It seems not, as when my circuit hit the breakpoint I could not manually toggle the clock. But if I then pressed the Pause/Resume button twice (pause and resume), I could.

Could you provide me with an example? I can't reproduce this issue.

prlaba commented 1 year ago

Hi again. I think I misrepresented my bug. See the attached circuit.

I start the simulation with the Clock component's Start in real time attribute checked and its frequency set to 50000 (on my PC that gives me time to pause the clock before the breakpoint is hit).

When the 32-bit counter reaches 0x80000, the comparator triggers the Break component, which pauses the clock and simulation.

At that point, I can manually toggle the Clock component to advance the counter, but if I try to click the Reset pin to reset the counter, the pin's wire changes to 1 but the counter doesn't reset. The same thing happens if I use the Pause/Resume button to pause the simulation.

But if I click the Reset button while the clock is running (not paused), the counter resets.

This turned out to be "user error". I didn't realize that your two Counter components both use synchronous clear. I simply needed to advance the clock to the next low-to-high transition (with the Reset pin high) to reset the counter.

So the new Pause/Resume button seems to be working exactly as expected.

I was surprised that you chose to use Counter components with synchronous reset; IMHO the more commonly used counters use asynchronous reset. Perhaps you could add an advanced attribute checkbox to mark a Counter component's CLR pin as asynchronous? (The checkbox would be unchecked by default so as not to break backward compatibility.) Or I can just use the 74161 Counter IC, available in the DIL Chips library; that one uses asynchronous reset.

Thanks again for adding this great feature.

Break.zip

me-nkr commented 9 months ago

It would be very useful if you could enable and disable a clock's Start real-time clock attribute while the simulator is running. That would allow you stop a running clock, single-step it for a while, then restart it.

Is there another way to do this currently?

This is also not really the same thing. In this mode, every action happens "at once" while if the clock were running i can do things in specific order, rather than "simultaneously".

You might've already figured this out, but passing the clock through an AND gate where the second input i can be used as a run or pause button.

Or you could use a Mux where one input is a real-time clock, the other one is a manual clock and use the input i as select.

I know it's a hacky solution, but this does the trick for anyone using the official release version until the pause feature is officially released : )