Moving data into a case statement

I have tried and think proved that rx.data cannot cross the case (state.q) boundary. I can use led = rx.data; before the case statement and the appropriate bits light up. If I put the same led = rx.data after the case statement, it will not light any lights.

So,

led = rx.data; /lights appropriate bits

case(state.q) {
mig.mem_in.en = 1;
mig.mem_in.cmd = 0;
mig.mem_in.wr_data = rx.data;
led = rx.data; //does nothing!

Please explain. I have spent over a week trying this and that and the only conclusion is there is a problem with Lucid. If it’s a bug, please let me know so I stop spinning my wheels.

Thank you,
howdyrichard

It looks like this is just a snippet of your code, so I don’t think I have the full picture. I am much more familiar with verilog than lucid, but after a quick look at https://alchitry.com/lucid-reference, I think you are using case statements incorrectly.

It is just a snippet. It is from DDR3 tutorial using memory interface generator (mig) and the wrapper, etc.: https://alchitry.com/ddr3-memory
The whole top_module:

module au_top (
input clk, // 100MHz clock
input rst_n, // reset button (active low)
output led [8], // 8 user controllable LEDs
input usb_rx, // USB->Serial input
output usb_tx, // USB->Serial output
/* DDR3 Connections */
inout ddr3_dq[16],
inout ddr3_dqs_n[2],
inout ddr3_dqs_p[2],
output ddr3_addr[14],
output ddr3_ba[3],
output ddr3_ras_n,
output ddr3_cas_n,
output ddr3_we_n,
output ddr3_reset_n,
output ddr3_ck_p,
output ddr3_ck_n,
output ddr3_cke,
output ddr3_cs_n,
output ddr3_dm[2],
output ddr3_odt
) {

sig rst; // reset signal

clk_wiz_0 clk_wiz;

// DDR3 Interface - connect inouts directly
mig_wrapper mig (.ddr3_dq(ddr3_dq), .ddr3_dqs_n(ddr3_dqs_n), .ddr3_dqs_p(ddr3_dqs_p));

.clk(mig.ui_clk) {
.rst(rst) {
fsm state = {WRITE_DATA, WRITE_CMD, READ_CMD, WAIT_READ, DELAY};
dff ctr[24];
dff address[8];
dff led_reg[8];
}
}

always {
/* Clock Wizard Connections */
clk_wiz.clk_in1 = clk; // 100MHz in
clk_wiz.reset = !rst_n; // reset signal

/* DDR3 Connections */
ddr3_addr = mig.ddr3_addr;
ddr3_ba = mig.ddr3_ba;
ddr3_ras_n = mig.ddr3_ras_n;
ddr3_cas_n = mig.ddr3_cas_n;
ddr3_we_n = mig.ddr3_we_n;
ddr3_reset_n = mig.ddr3_reset_n;
ddr3_ck_p = mig.ddr3_ck_p;
ddr3_ck_n = mig.ddr3_ck_n;
ddr3_cke = mig.ddr3_cke;
ddr3_cs_n = mig.ddr3_cs_n;
ddr3_dm = mig.ddr3_dm;
ddr3_odt = mig.ddr3_odt;
 
mig.sys_clk = clk_wiz.clk_out1; // 100MHz clock
mig.clk_ref = clk_wiz.clk_out2; // 200MHz clock
mig.sys_rst = !clk_wiz.locked;  // reset when clk_wiz isn't locked
rst = mig.sync_rst;             // use the reset signal from the mig core
 
led = led_reg.q;        // set leds to show led_reg value
 
usb_tx = usb_rx;        // echo the serial data
 
// default values
mig.mem_in.en = 0;
mig.mem_in.cmd = 3bx;
mig.mem_in.addr = 28bx;
mig.mem_in.wr_data = 128bx;
mig.mem_in.wr_mask = 0;
mig.mem_in.wr_en = 0;
 
case (state.q) {
  state.WRITE_DATA:
    mig.mem_in.wr_en = 1;
    mig.mem_in.wr_data = address.q;
    if (mig.mem_out.wr_rdy)
      state.d = state.WRITE_CMD;
   
  state.WRITE_CMD:
    mig.mem_in.en = 1;
    mig.mem_in.cmd = 0; // 0 = write
    mig.mem_in.addr = c{address.q, 3b000}; // first three bits of addr are for the 8 words in wr_data
    if (mig.mem_out.rdy) {
      address.d = address.q + 1;
      state.d = state.WRITE_DATA;
      if (address.q == 8hFF) {
        state.d = state.READ_CMD;
        address.d = 0;
      }
    }
   
  state.READ_CMD:
    mig.mem_in.en = 1;
    mig.mem_in.cmd = 1; // 1 = read
    mig.mem_in.addr = c{address.q, 3b000};
    if (mig.mem_out.rdy)
      state.d = state.WAIT_READ;
   
  state.WAIT_READ:
    if (mig.mem_out.rd_valid) {
      led_reg.d = mig.mem_out.rd_data[7:0];
      state.d = state.DELAY;
      address.d = address.q + 1;
    }
   
  state.DELAY:
    ctr.d = ctr.q + 1; // delay so we can see the value
    if (&ctr.q)
      state.d = state.READ_CMD;
}

}
}

In the case statement, state.WRITE_DATA, the author writes an address (address.q) to memory and after 256 times it ‘replays’ them from memory and shows on the LED’s.
In the tutorial it says that address.q can be replaced with other values which is true if they are assigned directly as in: mig.mem_in.wr_data = 8hAA; or any other 8-bit value. But when I try bring a byte received from the UART receive module it does not work, mig.mem_in.wr_data = rx.data;. But the data is actually there! I can light the LED’s with that value anywhere in the top module as long as it is not in a case or if statement. The byte will not pass through an obvious barrier. I can better explain this on a phone call. After reading about the attempts to correct issues with the 1.2.7 Alchitry Labs to Lucid V2, it looks like this issue is being corrected. I’ve spent a lot of time trying every which was to get the case statement to work with a variable value (rx.data) and it does not work; even if I assign rx.data = 8hAA in the always{} code and try to use it in the case statement, it will not work but it does if I use LED=rx.data; outside the case statement! It just won’t cross some sort of barrier. If I’m using the case statement wrong then how would you do it?

The idea I thought was to use Lucid as a beginner way to learn FPGA’s. What I am trying to do would be very easy if it worked like the tutorials that present it. I’m certain that Lucid is not what I expected it to be. So what do you advise me to do? I don’t mind learning Verilog since that seems to be the only sure way of accomplishing my end goal. What do you recommend as a learning tool?