0
\$\begingroup\$

I'm doing a simple seven segment display driver for class, using a MachXO3 dev board connected to 4 displays and 2 buttons on a breadboard. The 4 common-cathode displays have their anodes wired together so that the active display's cathode can be strobed to show a unique 4-digit number. Clock rate (input clk) is 12 MHz from the board's crystal oscillator, and I want to strobe the displays 250 times a second.

My first stab at the code to control strobing between the four displays is:

reg [15:0] strobe_count;
reg [1:0] current digit = 2'b00;
always@(posedge clk)
begin
   if (strobe_count >= 16'd47999)
   begin
      strobe_count <= 16'd0;
      current_digit <= current_digit + 1'b1;
   end
   else
      strobe_count <= strobe_count + 1'b1;
end

For some reason, with this code, the "strobe_count" counter works fine (resets to zero after 47999), but the "current_digit" register never updates, and thus the strobing never works. However, if I try to use Diamond Reveal debugger, it DOES work. That is, adding a Reveal core makes it strobe with that code...regardless of whether I actually use Reveal analyzer or not.

It's great that I can get it to work...but I'd really like to know why. I don't think adding a debug core should alter the behavior, and it really doesn't make sense to me. That code SHOULD just work without adding some unexplainable magic sauce, right?

Alternate coding works fine (with or without a debug loaded). For instance, if I remove the "current_digit" assignment from the conditional, and have a separate line like this:

always@(posedge clk)
begin
   current_digit <= current_digit + (strobe_count == 16'd47999);
   if (strobe_count >= 16'd47999) strobe_count <= 16'd0;
   else strobe_count <= strobe_count + 1'b1;
end

Breaking "current_digit" into its own separate always block also works fine.

I'm thinking it must be some quirk of Verilog, right? Sure enough, if I write a testbench to simulate that first try of the code, even in the simulation, it never updates "current_digit", so clearly Active-HDL knows something about this fabric that I don't. Also, if I try assigning these registers to output pins and check them with an external logic analyzer, I can see that "current_digit" never updates (and yet "strobe_count" DOES in fact successfully reset after 47999)...but using the integrated Reveal logic analyzer changes it to where it DOES work! I've also tried setting timing constraints (with zero reported timing errors in both map and place and route trace reports, and a fmax of 150.15 MHz in the map trace and 127.861 MHz in the P&R trace). I'm also not getting any unusual synthesis warnings, just the one I always get about no user .SDC file.

I'm sure it's got to be something really obvious that I'm missing here, and I'll feel real silly about it, but it's really driving me nuts! Why would it successfully perform one of two actions under a conditional, but not the other...unless a debug core is instantiated?

\$\endgroup\$
  • \$\begingroup\$ One thing I notice is that strobe_count (which works) is not assigned prior to the always block, whereas current_digit is (and with a blocking assignment). I would try not assigning the current_digit first and see what happens. \$\endgroup\$ – Peter Smith Apr 9 at 13:47
  • \$\begingroup\$ Thanks for the comment, Peter. It's not actually a "blocking assignment" (since it is part of the register definition, and not in an always block), but simply an initialization value. It's kind of like using "assign", in other words, but only as a starting value. Nonetheless, I have tried with and without the initialization (since it should initialize to zero anyways). It changes nothing, I'm afraid. \$\endgroup\$ – Justus Johnston Apr 9 at 13:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.