I come from very predominant background in VHDL and have recently been doing a lot more coding in SystemVerilog. I've noticed a couple of strange behaviours that I don't entirely understand.
Summary
In the following example, I am performing an addition of several signals. I know that this is particularly inefficient (and probably bad style), but I am using it to demonstrate the type of issue I've run into recently.
// Main add (inside synchronous process)
// all signals are 32b logic or reg (except for 64, which is a `define)
dma_ins.dest <= sdram_addr + slice_address + slice_offset - 64;
0x3800 0000 0x0001 0000 0x0000 0050
When I run this add in simulation, I get the correct result. In synthesis, it's incorrect.
Simulation: 0x38010010
Synthesis: 0x38008008
The synthesis value is one shift to the right (0x8008 instead of 0x10010).
In order to determine the synthesis value, I am writing all four signals to debug registers. The DMA also ends up at the wrong address in the SDRAM in hardware.
In order to fix this issue, I did the following:
dma_ins.dest <= sdram_addr;
dma_ins.dest[26:15] <= queue_prop_new[0].contig_head; // non-shifted versions of slice address
dma_ins.dest[14:4] <= queue_prop_new[0].contig_hoffset - 4; // and slice offset
I'm probably missing something in regards to the SystemVerilog type definitions, but I'm not sure what. I've added some details below.
Detail
The signals being added together are defined as follows:
// SDRAM ADDR (synchronus process, 32b reg)
sdram_addr <= 32'h38000000
// SLICE ADDRESS (asynchronus combinitorial assign)
// slice address: 32b logic
// queue_prop_new[0].contig_head: 12b logic: value of 0x02
// 32768 is a `define that has been substituted.
assign slice_address = (queue_prop_new[0].contig_head <<($clog2(32768)-1));
// (slice_address = 0x02 << 15 = 0x10000)
// SLICE OFFSET
// slice_offset: 32b logic
// queue_prop_new[0].contig_hoffset: 11b logic: value of 0x05
// 16 is a substituted `define
assign slice_offset = (queue_prop_new[0].contig_hoffset<<($clog2(16)-1));
// (slice_offset = 0x05 << 4 = 0x50)