Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

SPI slave to parallel out - a little help please!

Status
Not open for further replies.

Mark Baseggio

Junior Member level 2
Joined
Nov 2, 2013
Messages
22
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
249
Hello,

I am currently working on a project with an old C64 SID (Sound Interface Device) chip. I'm using a Xilinx SC9572XL CPLD along with an ESP8266 acting as SPI master. The CPLD performs clocking of the SID, as well as conversion of the SPI data to the SID's address and data lines. While the code seems to compile/generate I get tons of warnings I can't figure out.

**disclaimer** In terms of experience with logic, I'm a "total noob." I've done my best with Google and researching examples available, but please don't beat me over the head and tell me I'm dumb. Because I already know that :)

I have developed the following code to receive data from the SPI master (note it sends 200bits at a time, which is all of the SID's 25 one-byte registers). As you can see the code stores the data like a ROM, and throws up a flag when there is data ready to read and put on the bus. Race conditions are not an issue as writes go to the SPI bus very slowly at 50Hz, so the CPLD has lots of time to write the register values.

Code:
module spi_slave(
    input ss,
    input sclk,
    input mosi,
    input read_en,
    input [4:0] addr,
    output [7:0] data,
    output reg data_rdy = 1'b0
    );

reg [7:0] data_in;  
reg [7:0] bit_cnt = 8'd0;  
reg [7:0] sid_reg [24:0];   // store all SID registers

assign data = (read_en) ? sid_reg[addr] : 8'b0;

    always @(posedge sclk) begin
        if (!ss) begin
            data_in = {data_in[6:0], mosi}; // shift left
            bit_cnt = bit_cnt + 1;  
            if (!(bit_cnt % 8)) begin   // if # bits in is divisable by 8 we just got a full byte
                sid_reg[(bit_cnt/8)-1] <= data_in;  // store the current value 
                if (bit_cnt == 8'd200) bit_cnt <= 8'd0;  // once we reach 25 bytes reset the counter
            end
        end
    end
    
    always @(posedge ss or posedge read_en) begin
        if(!bit_cnt) data_rdy = 1;  // let the bus module know it's time to assert data
        if(read_en) data_rdy = 0;  // when read starts turn off ready
    end
    
endmodule

Here is the corresponding module that then takes the data and writes it to the SID data/addr bus. Note: the CPLD clk line is 20MHz, while the sid_clk is 1MHz. The SID accepts write while it's clock is high.

Code:
module sid_glue(
    input clk,
    input sid_clk,
    output sid_cs, // active low write
    output reg sid_rw = 1'b1, // hold low to write
    input data_rdy,
    output reg [4:0] addr = 4'b0,
    input [7:0] data, // incoming frame data from SPI
    output reg read_en = 1'b0,
    output reg [4:0] sid_addr = 5'b0,
    output reg [7:0] sid_data = 8'b0
    );
    
    reg [7:0] last_data [24:0];
    reg write_en = 1'b0; 

    // sync sid_clk to the FPGA clock using a 2-bit shift register
    reg [1:0] sid_clk_r;  always @(posedge clk) sid_clk_r <= {sid_clk_r[0], sid_clk};
    wire sid_clk_risingedge = (sid_clk_r==2'b01);  
    wire sid_clk_fallingedge = (sid_clk_r==2'b10);  
    
    // same for data ready, just need to detect pos edge
    reg [1:0] data_rdy_r;  always @(posedge clk) data_rdy_r <= {data_rdy_r[0], data_rdy};
    wire data_rdy_posedge = (data_rdy_r==2'b01);
    
    assign sid_cs = sid_rw; // tied together for now (we don't need read atm)
     
    always @(posedge clk) begin
        
        if ((write_en || data_rdy_posedge) && sid_clk_risingedge) begin
            if (!write_en) write_en <= 1'b1;
            read_en = 1;
            if ((data != last_data[addr]) || last_data[addr] === 8'bX) begin // don't write the data if it hasn't changed
                sid_addr = addr;    // put the address on the SID addr lines
                sid_data = data;   // data on the data line
                sid_rw = 0;
                last_data[addr] <= data; // copy data to the buffer for compare next time
           end
        end
        
        else if (write_en && sid_clk_fallingedge) begin
            sid_rw = 1;
            read_en = 0;
            addr = addr + 1;    // move to the next address
            if (addr == 25) begin write_en <= 0; addr = 5'b0; end // disable writes and reset counter
        end
        
    end
    
endmodule


From what I can tell by my hack-ish test-benches things are working as designed. But I get all these warnings that I'm not sure if I should be concerned about or not:

Code:
..snip..
WARNING:Xst:1710 - FF/Latch <last_data_8_0> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1710 - FF/Latch <last_data_9_7> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1710 - FF/Latch <last_data_9_6> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1710 - FF/Latch <last_data_9_5> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1710 - FF/Latch <last_data_9_4> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1710 - FF/Latch <last_data_9_3> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1710 - FF/Latch <last_data_9_2> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1710 - FF/Latch <last_data_9_1> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1710 - FF/Latch <last_data_9_0> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.
..snip..

WARNING:Xst:2677 - Node <data_in_7> of sequential type is unconnected in block <spi_slave>.
WARNING:Xst:2677 - Node <data_in_6> of sequential type is unconnected in block <spi_slave>.
WARNING:Xst:2677 - Node <data_in_5> of sequential type is unconnected in block <spi_slave>.
WARNING:Xst:2677 - Node <data_in_4> of sequential type is unconnected in block <spi_slave>.

...snip...

WARNING:Xst:864 - "sid_glue.v" line 33: Comparisons to 'X' or 'Z' are treated as always false.

If anyone feels like helping me out I'd be very appreciative! THANKS.

Mark
 

Using blocking assignments in Verilog code that is supposed to represent hardware flip-flops is a bad idea. Use non-blocking assignments when you write edge triggered always blocks (you will never go wrong doing that). Even worse (at least what I consider worse) is your using both a mixture of non-blocking (<=) and blocking (=) assignments in your code.

In this particular case you may end up with synthesis/simulation mismatches due to the difference in scheduling caused by the assignment ordering and the use of the assigned signals being read.

Code:
            addr = addr + 1;    // move to the next address
            if (addr == 25) begin write_en <= 0; addr = 5'b0; end // disable writes and reset counter
if addr is currently 24 and this code gets executed the value of addr should go to 25 as the assignment is BLOCKING and will force the update of addr before the comparison takes place. If the simulator is correctly scheduling this code you'll end up with a difference between the simulation 24 causing write_en going to 0 and addr going to 0 and the hardware which will result in addr == 25 causing the address to roll over and the write_en gettng assigned 0.

I also find code like you have above somewhat ambiguous even when coded correctly with non-blocking assignments. I would code the rollover counter as such:
Code:
always @(posedge clk) begin
    if (....) begin
    end else if (....) begin
        if (addr < 24) begin
            addr <= addr + 1;
        end else begin
            addr <= 0;
        end
    end
end

What bothers me about the warning is the fact that the 8 and 9 of the 25 byte wide register in the register file are indicated as being static 0's. This is obviously a problem as you've just trimmed those two (or more, you should have posted the entire log) registers.

I would get rid of all the assignments on the output ports. Nobody does that and it's not even supported for any synthesis tool out there (it's just ignored AFAIK). Also comparing last_data[addr] === 8'bx isn't going to synthesize either as there is no such thing as X in hardware.

Code:
    // same for data ready, just need to detect pos edge
    reg [1:0] data_rdy_r;  always @(posedge clk) data_rdy_r <= {data_rdy_r[0], data_rdy};
    wire data_rdy_posedge = (data_rdy_r==2'b01);
terrible coding style run-on declarations with sequential code followed by more declarations. :-(

There are a bunch more "problems" that I have with this code, but I'll stop now (I'm probably more critical of even minor stuff compared to others here, FYI if I found this code in our code repository...I would throw it away and rewrite it).
 
Hey ads-ee I appreciate the feedback. As I said, this is literally my second time working with programmable logic devices and Verilog. So of course the code is awful ;)

Your insights are helpful, I will clean up as best I can according to your advice. I am having a little trouble with the blocking vs non-blocking assignments. I find them a bit confusing, suppose I will learn more with time and practice!
 

Follow these two rules...

Block: use only when writing combinatonal logic
e.g.

Code Verilog - [expand]
1
2
3
always @* begin
    comb1 = sig1 & sig2 & (sig3 ^ sig4);
end



Non-block: use only in edge sensitive always blocks i.e. clocked logic
e.g.

Code Verilog - [expand]
1
2
3
always @ (posedge clk) begin  // this is edge sensitive
    flipflop <= d_input;
end

 

Ok here is a snippet of my code, I got confused here with blocking/non-blocking.

The code first shifts in a bit from the MOSI line, then adds to the bit count, then I test to see if I have received a full 8 bits.

I figured that it HAD to block there because if I didn't ensure that the addition of +1 to the bit count happened the if statement would be evaluated on the old bit_cnt... am I thinking of this entirely wrong?

Code:
always @(posedge sclk) begin
        if (!ss) begin
            data_in = {data_in[6:0], mosi}; // shift left
            bit_cnt = bit_cnt + 1;  
            if (!(bit_cnt % 8)) begin  
...

Thanks!
 

This is where you need to think in terms of hardware (ie gates and registers) and not code.
In the code above, what will happen is that yes - you are correct - you use the "new" version of bit_cnt. But this means that you've just increased the length of the logic path between bit_cnt and whatever you have in the if statement (which becomes an enable port on a register). At higher clock speeds this may cause the design to fail timing analysis.

bit_cnt tells you how many bits have already arrived, and you know that with !ss you've just recieved another bit. So why not just do this?


Code Verilog - [expand]
1
2
3
4
5
always @(posedge sclk) begin
        if (!ss) begin
            data_in <= {data_in[6:0], mosi}; // shift left
            bit_cnt <= bit_cnt + 1;  
            if (bit_cnt[2:0] == 3'h7) begin  //"old" value of bit_cnt, ie. the output of a register through a compare, without the extra adder in the logic path.

 
Blocking statements in a edge sensitive always block will generate extra combination logic in the design if that output is used in the always block, which is usually not what you want. If that is exactly what you want to do, then it's better to code it as a separate assignment that is outside the always block where it's used, i.e. as combinational logic.

Regardless it's always better to code things like Tricky shows.
 
In Verilog, it is rare to have blocking assignments in edge sensitive blocks. Even in most cases where it is justified and safe an alternative approach will be found. The remaining use-cases are specific to vendor tools or simulation issues.
 

Hello again.

Ok so I have done some work on the spi slave / rom code. I converted all my assignments to non-blocking, which required me to rethink how I was doing things -- thanks to everyone for the help. In my test-bench it seems to work, but I was wondering if you fine folks could give it a once over for me?

I have one question about declaring a reg in the module definition block, should I be doing that? Or should I be defining an output only and then creating a new reg in the code then assigning it procedurally? I have been looking around and can't really find a good answer on that one.

Again, this code is designed to take 200 bits of data each SPI transaction, break it up into the SID's 25 one-byte registers and then my bus module will read it and send it to the parallel bus.


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
module spi_slave(
    input ss,
    input sclk,
    input mosi,
    input read_en,
    input [4:0] addr,
    output [7:0] data,
    output reg data_rdy
    );
 
reg [7:0] bit_cnt = 8'd0;
reg [4:0] reg_cnt = 5'd0;  
reg [7:0] sid_reg [24:0];   // store all SID registers
 
assign data = (read_en) ? sid_reg[addr] : 8'b0;
 
    always @(posedge sclk) begin
        if (!ss) begin
            bit_cnt <= bit_cnt + 1;  
            if (bit_cnt[2:0] == 3'h7) begin
                sid_reg[reg_cnt] <= {sid_reg[reg_cnt][6:0], mosi}; // store the current value
                reg_cnt <= reg_cnt + 1;
                if (bit_cnt == 8'd199) begin 
                    bit_cnt <= 8'd0;    // once we reach 25 bytes reset the counters
                    reg_cnt <= 5'b0; 
                end  
            end
            else sid_reg[reg_cnt] <= {sid_reg[reg_cnt][6:0], mosi}; // shift left
        end
    end
    
    always @(posedge ss or posedge read_en) begin
        if(!bit_cnt) data_rdy <= 1;  
        if(read_en) data_rdy <= 0;      
    end
    
endmodule



Thanks again for your help,
Mark
 

You wont get very far with this:

Code:
    always @(posedge ss or posedge read_en) begin
        if(!bit_cnt) data_rdy <= 1;  
        if(read_en) data_rdy <= 0;      
    end

It implies that ss and read_en should be connected to the clock of the register - something it cant do in an FPGA (as you only get a single clock pin). Much better to make edge detectors and clock data_rdy with the system clock:

Code:
reg ss_d, read_en_d;

always @(posedge clk) begin
  ss_d <= ss;
  read_en_d <= read_en;

  if( (read_en & !read_en_d) || (ss & !ss_d) ) begin
    if(!bit_cnt) data_rdy <= 1;
    if(read_en) data_rdy <= 0;
  end
end
 
Thank you!

I am also getting a very puzzling message during generation:

Code:
WARNING:Cpld:1007 - Removing unused input(s) 'sclk'.  The input(s) are unused
   after optimization. Please verify functionality via simulation.

How the hell can sclk be "unused" it's clearly relied upon in my design. It's connected to a pin in the UCF... what is going on here? :) Thanks.
 

Can't see why it would claim that sclk is not used, unless you have some messages that say logic is being removed...like the entire design.
There is nothing wrong with using reg in the port declaration it saves having to retype the port name in another declaration you can also specify each output as wire too, though that is the default so no one except script generated code does that.

Something to note...
bit_cnt counts from 0-199 0-7 is a byte, which is the lower 3-bits. If you use sid_reg[bit_cnt[7:3]] it gets rid of the reg_cnt.

I wonder if you are aware that the code you wrote produces a register file (i.e. 25 8-bit wide flip-flops) It doesn't use memory and it will have a 25 to 1 multiplexer (i.e. assign data = (read_en) ? sid_reg[addr[ : 8'b0;), which also has an AND gate in the path to generate the 8'b0 based on the read_en. As you are using ISE have you considered using distributed RAM to implement this "memory"? It would make this portion of the design much smaller and much faster.

- - - Updated - - -

I'm assuming that the code if (!bit_cnt) is checking for bit_cnt of 0? You are trying to do a reduction operation with a bitwise operator.

I prefer the following code as it's explicitly checking for a 0 value with no ambiguity.
Code:
if (~|bit_cnt)

reduction OR operation (|) checks for a 1 in bit_cnt NOT inverts that reduction into looking for all 0's.

For completeness, checking for all 1's is simply
Code:
if (&bit_cnt)
 

Can't see why it would claim that sclk is not used, unless you have some messages that say logic is being removed...like the entire design.
There is nothing wrong with using reg in the port declaration it saves having to retype the port name in another declaration you can also specify each output as wire too, though that is the default so no one except script generated code does that.

Something to note...
bit_cnt counts from 0-199 0-7 is a byte, which is the lower 3-bits. If you use sid_reg[bit_cnt[7:3]] it gets rid of the reg_cnt.

I wonder if you are aware that the code you wrote produces a register file (i.e. 25 8-bit wide flip-flops) It doesn't use memory and it will have a 25 to 1 multiplexer (i.e. assign data = (read_en) ? sid_reg[addr[ : 8'b0;), which also has an AND gate in the path to generate the 8'b0 based on the read_en. As you are using ISE have you considered using distributed RAM to implement this "memory"? It would make this portion of the design much smaller and much faster.

- - - Updated - - -

I'm assuming that the code if (!bit_cnt) is checking for bit_cnt of 0? You are trying to do a reduction operation with a bitwise operator.

I prefer the following code as it's explicitly checking for a 0 value with no ambiguity.
Code:
if (~|bit_cnt)

reduction OR operation (|) checks for a 1 in bit_cnt NOT inverts that reduction into looking for all 0's.

For completeness, checking for all 1's is simply
Code:
if (&bit_cnt)

Thanks again, this stuff is so useful to me. I learn best by "doing" and to have feedback on the crap that I've done really helps. I knew there was a better way to keep track of the reg_cnt, I just couldn't brain it in the moment :) Your proposal to use the upper 8 bits seems like an elegant solution.

I've never used distributed ram, I've been kinda going on a ton of different examples I've found out there. I will have to do some Googling to figure out how to properly use it. *Anything* that makes the code better helps for sure! Please keep 'em coming.

One thing I have seen a lot are examples of shift registers or SPI code that use blocking assignments in always @(posedge clk) statements. They seem to be everywhere when I google for "verilog shift register" or "verilog spi slave" Is this always wrong?

- - - Updated - - -

Alright,

for those interested, because I could find hardly any decent examples of this, I figured I would post the ram module I made up:


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module dist_ram #(parameter RAM_WIDTH=8,RAM_ADDR_BITS=5)(
    input clk,
    input write_en,
    input [RAM_WIDTH-1:0] ram_in,
    input [RAM_ADDR_BITS-1:0] ram_addr,
    output [RAM_WIDTH-1:0] ram_out
    );
 
   (* RAM_STYLE="DISTRIBUTED" *)
   reg [RAM_WIDTH-1:0] sid_ram [(2**RAM_ADDR_BITS)-1:0];
 
   always @(posedge clk)
      if (write_en)
         sid_ram[ram_addr] <= ram_in;
 
   assign ram_out = sid_ram[ram_addr];   
 
endmodule



I embedded it into my top module like so:


Code Verilog - [expand]
1
2
3
4
5
6
7
dist_ram #(.RAM_WIDTH(8),.RAM_ADDR_BITS(5)) ram(
        .clk        (clk),
        .write_en   (write_en),
        .ram_addr   (ram_addr),
        .ram_in     (ram_in),
        .ram_out    (ram_out)
    );



Also, if anyone sees any issues with how I'm doing this please let me know ;)
 

One thing I have seen a lot are examples of shift registers or SPI code that use blocking assignments in always @(posedge clk) statements. They seem to be everywhere when I google for "verilog shift register" or "verilog spi slave" Is this always wrong?
That's because most of the code you find using gogole is garbage written by the "blind leading the blind". Or to put it bluntly, the majority of the code you find was written by students that have no clue what they are doing.

Very few working engineers put much of their code out there in the wild. Possible reasons for this might be:
1. Want to get paid for writing code.
2. Would rather write code they get paid for instead of code they never get paid to write.
3. Would rather hide their code on a personal blog.

Your distributed RAM code at a glance looks right, but I would have to try synthesizing it to make sure, but it looks like it does both the write synchronously and the read asynchronously like your supposed to do.
 

Quick question, besides this code being horrible:


Code Verilog - [expand]
1
2
3
4
// sync SCK to the FPGA clock using a 3-bits shift register
reg [2:0] SCKr;  always @(posedge clk) SCKr <= {SCKr[1:0], SCK};
wire SCK_risingedge = (SCKr[2:1]==2'b01);  // now we can detect SCK rising edges
wire SCK_fallingedge = (SCKr[2:1]==2'b10);  // and falling edges



Is there a good reason to use a 3 bit shift register to detect rising/falling edges?

Why not just store the last bit, and if the incoming bit has changed then you have an edge. Am I missing something critical?
 

If the bit you are trying to detect is on the same clock domain as the edge detect logic and is coming from a FF that you know won't be placed so far away it can't meet setup timing, then using the signal and a saved version of the bit is enough. i.e. you only have 1 FF to detect the edge and the worst case delay is from the source bit FF through the gate (a & !a_saved) to the output.

If the incoming bit is asynchronous then you need a minimum of 2 FFs for synchronizing the signal to the new clock domain, followed by another FF to save the old version of the bit, i.e. there are 3 FFs required to detect the edge. This is the case in the above code based on the comment.
 

Ugh. Having another weird problem.

I am trying to test my newest SPI code and RAM from my top module. My top module instantiates both something like this:


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
module espSID_top(
    input clk,  // 20MHz CPLD clock
    input rst,
    output led_d1,
    output led_d2,
    output sid_clk,  // 1MHz clock out from clock_divider module
    input ss,
    input sclk,
    input mosi
    );
 
..snip..
 
   // Storage for the incoming SID register data
   
    ram #(.RAM_WIDTH(8),.RAM_ADDR_BITS(5)) ram(
        .clk        (clk),
        .write_en   (write_en),
        .ram_addr   (ram_addr),
        .ram_in     (ram_in),
        .ram_out    (ram_out)
    );
 
    // SPI slave reads data from the ESP8266 and stores it to RAM
 
    spi_slave spi(
        .clk        (clk),
        .ss         (ss),
        .sclk       (sclk),
        .mosi       (mosi),
        .addr       (ram_addr),   
        .data       (ram_in),
        .write_en   (write_en),
        .data_rdy   (data_rdy)
    );



Then I have my module's declared like so...


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module spi_slave(
    input clk,
    input ss,
    input sclk,
    input mosi,
    output reg [4:0] addr,
    output reg [7:0] data,
    output reg write_en,
    output reg data_rdy
    );
 
...code...
 
module ram #(parameter RAM_WIDTH=8,RAM_ADDR_BITS=5)(
    input clk,
    input write_en,
    input [RAM_WIDTH-1:0] ram_in,
    input [RAM_ADDR_BITS-1:0] ram_addr,
    output [RAM_WIDTH-1:0] ram_out
    );
 
...code...



I am getting the following errors from my simulation:

Code:
WARNING:HDLCompiler:189 - "C:/Users/blark/Desktop/ESP8266_SID_Server/cpld/espSID/espSID_top.v" Line 37: Size mismatch in connection of port <ram_addr>. Formal port size is 5-bit while actual signal size is 1-bit.
WARNING:HDLCompiler:189 - "C:/Users/blark/Desktop/ESP8266_SID_Server/cpld/espSID/espSID_top.v" Line 38: Size mismatch in connection of port <ram_in>. Formal port size is 8-bit while actual signal size is 1-bit.
WARNING:HDLCompiler:189 - "C:/Users/blark/Desktop/ESP8266_SID_Server/cpld/espSID/espSID_top.v" Line 39: Size mismatch in connection of port <ram_out>. Formal port size is 8-bit while actual signal size is 1-bit.
WARNING:HDLCompiler:189 - "C:/Users/blark/Desktop/ESP8266_SID_Server/cpld/espSID/espSID_top.v" Line 49: Size mismatch in connection of port <addr>. Formal port size is 5-bit while actual signal size is 1-bit.
WARNING:HDLCompiler:189 - "C:/Users/blark/Desktop/ESP8266_SID_Server/cpld/espSID/espSID_top.v" Line 50: Size mismatch in connection of port <data>. Formal port size is 8-bit while actual signal size is 1-bit.

I can tell that the stupid simulator isn't transferring all the bits because I am monitoring the variables in the console:



Code:
 ram module: 
 410: sid_ram xxxxxxxxx..snip...xxxxx, addr zzzz0, data_in zzzzzzz1, ram_out xxxxxxxx, en 1
 spi module:
 410: tmp 0101010, bit_cnt 00001000, write_en 1, addr 00000, data 01010101

I've been staring at the screen for 2 hours, Googling and trying different things. Can't figure this one out -- anyone know what I'm doing wrong?

Thanks
 

You don't show any of the interconnecting wire declarations in espSID_top. The error is saying you either didn't define them or you made them all 1-bit wide instead of a bus.
 

You don't show any of the interconnecting wire declarations in espSID_top. The error is saying you either didn't define them or you made them all 1-bit wide instead of a bus.

Hmm. I must be really confused. I thought when you instantiated two modules the wires are automatically connected. Like so:


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
ram #(.RAM_WIDTH(8),.RAM_ADDR_BITS(5)) ram(
        ...
        .ram_addr   (ram_addr),
        ...
 
spi_slave spi(
      ...  
      .addr       (ram_addr),
      ...



Wouldn't the addr output of the spi module get connected to the ram_addr input automatically? What else needs to be done to properly connect them? Again. Sorry for the elementary questions -- I have been reading all about instantiation and I can't find the answer.
 

All signals need/should be defined first before use, just like every other language.
Code:
wire [4:0] ram_addr;

Unfortunately Verilog automatically creates a 1-bit implicit net for the undefined signals it finds in a design.

You can add
Code:
‘default_nettype none
to disable this implicit net creation and you'll then see a bunch of errors when you compile.

I actually never use it in my code.
 
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top