PDP-1 FPGA Implementation in Verilog, with CRT, Teletype and Console
github.com
github.com
if(~old_download && ioctl_download) begin
cnt <= 8'b0;
timeout <= 32'b0;
end
timeout <= timeout + 1'b1;
That's why in Verilog RTL we generally try to keep always blocks as small as possible, so they focus on assigning the same small set of signals in all branches.It's hard to change your mindset from a programming language to a hardware description language and not make mistakes like these, especially when just starting to learn Verilog. :-)
This code would work just fine (many people would argue it's not very readable -- but it saves you a lot of else branches):
// Default
timeout <= timeout + 1'b1;
// Special cases
if(~old_download && ioctl_download) begin
cnt <= 8'b0;
timeout <= 32'b0;
endI hope my next project will have cleaner code, be more readable and have less issues like these. HDL languages seem to have a rather steep learning curve and it takes some effort to distance yourself from the usual programming mindset.
And you are mixing <= and = in the same code (look in execute() ) this should never happen.
In general use <= in places that are gated by an "always @(posedge clk)" and = in things gated by "always @(*)"
(with the exception that it's OK to assign a temp variable in a clocked always with '=' provided its lifetime doesn't extend past the block's execution (your use of SKIP_FLAG is an example of this being done correctly)
But it is ok to do something like:
cnt <= cnt + 1;
if (cnt > 100) cnt <= 0;
If not, how else should something like this be done?
Thanks for your help, I'm finding HDL to be anything but easy. :-)
if (cnt > 100)
cnt <= 0;
else
cnt <= cnt + 1;Essentially what happens is:
tmp_cnt1 = cnt + 1;
if (cnt > 100) tmp_cnt2 = 0;
some time later: cnt = tmp_cnt1;
and after that (if cnt >100) cnt = tmp_cnt2;
Better to say: if (cnt >= 99) {
cnt <= 0;
} else {
cnt <= cnt+1;
} always @(posedge clk)
r <= v;
and in some more complex cases where r is only set once in one always statement (or once in any path through an always statement) - but something like: always @(*)
r <= c;
is a nightmare that essentially means that r can have many changes scheduled in the same instant of time, more importantly it's a number of changes that can't be determined at compile time (could be 1000s of transitions) - resulting in code that's mallocing space to store all those changes - simulation can slow down if you use <= in a non-clocked place because the behaviour can't be determined staticallyAlso using <= a smart compiler can merge multiple always statements:
always @(posedge clk)
r1 <= c1;
always @(posedge clk)
r2 <= c2;
......
into a single always @(posedge clk) {
r1 <= c1;
r2 <= c2;
......
}
behind your back, effectively converting 2*N simulation events into 2 (a very good thing)These days I build embedded stuff, living on the hardware/software edge I still get to make the software/hardware tradeoffs that others often can't do
When performing boolean condition testing, eg "if (~a & b)", always use "!" for negation instead of "~", "&&" for logical and, and "||" for logical or for exactly the same reasons you should do it for C code.
If the operands are all 1 bit, either option works fine. But if you ever accidentally use a vector where you intended a bit, one generates a warning and the other doesn't.
There is a follow up - it can also play music, just like the original could. Check it out: https://www.youtube.com/watch?v=ROPyR-tV7A4
A quick question: Were the original PDP-1 manuals enough to implement the system from scratch? Were there details or hidden issues you had to "guess"?
The original instruction test tapes helped me a lot with debugging the various corner cases. For example, the multiply step opcode (MUS) is re-used in later versions which had full hardware multiply (MUL). The backwards compatibility was retained by flipping a switch inside the computer to selecting between MUS and MUL. I had some programs failing mysteriously because of this.
There were also various pixel brightness available and after implementing it, I discovered Spacewar actually uses that to make some stars brighter than others.
Music playing capability was very advanced for its time (having 4 voices) and after everything was a "silent movie" for a while, there was a rewarding moment when I finally fixed a bug and Mozart started playing from the speakers.
A cool machine, very advanced for its time...
Cheers!