Verilog modules - weird behavior ignoring top.v code


#1

Hello, I learn Verilog with tinyFPGA. This question is maybe YOSYS or APIO related but I start here.

I started with tinyFPGA blink project and get it running. Then I wanted to learn more about modules so I created this example. Here is the code I have:

blink_project.zip (19.8 KB)

I have converted SOS morse example to the module. I also have uart_tx module I will try to use later in this post. The top module is in the file _top.v and is called top.

Now. If I use module module morse then the code compiles fine and I get blinking SOS on my tinyFPGA.

morse insta_a (
      .CLK    ( CLK ), // input
      .LED    ( LED ) // output
    );

I don’t even need to uncomment the include lines I have in my document, so this is kept commented:

/*
`include "morse.v"
`include "uart_tx.v"
*/

Now I would like to add uart_tx module to see UART frames on PIN_1. This module I have found on the Internets and there could be something wrong I overlooked because I’m a beginner in Verilog.
So I uncomment/add the lines

    wire [7:0] uart_data = 8'b00101010;
    uart_tx insta_tx (
        .i_Clock( CLK ),
        .i_Tx_DV( LED ),
        .i_Tx_Byte( uart_data ),
        .o_Tx_Active( PIN_1 )
      );
      defparam insta_tx.CLKS_PER_BIT = 500;

Now I get this ERROR

hub@hpnix:~/Desktop/fpga/blink_project$ apio build
[Mon Aug  6 21:41:36 2018] Processing TinyFPGA-BX
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
yosys -p "synth_ice40 -blif hardware.blif" -q _top.v morse.v uart_tx.v
ERROR: Module `\uart_tx' referenced in module `\top' in cell `\insta_tx' is not part of the design.
scons: *** [hardware.blif] Error 1
=========================================================================== [ ERROR ] Took 0.25 seconds ===========================================================================
hub@hpnix:~/Desktop/fpga/blink_project$ 

Which seems like I need to include the module, I do that by adding this on the begining my _top.v:

`include "uart_tx.v"

Then I recompile by calling apio build and this is the output:

hub@hpnix:~/Desktop/fpga/blink_project$ apio build
[Mon Aug  6 21:44:05 2018] Processing TinyFPGA-BX
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
yosys -p "synth_ice40 -blif hardware.blif" -q _top.v morse.v uart_tx.v
=========================================================================== [SUCCESS] Took 0.62 seconds ===========================================================================

The code compiles but don’t work. What is more interesting is this - now the compiler ignores everything in my _top.v after that include line. I can delete, edit, write errors in the _top.v file and it is happilly compiled.

What is more wierd that when I type any syntatic error to the uart_tx.v file then the compiles fine. But when I write any typo to the morse.v then the compiler throws an error.

So it seems like there’s something wrong with uart_tx module that ignores the top _top.v file.

Could it have relation with #(parameter CLKS_PER_BIT) in the uart_tx.v file? I have no experience with parameters.

I would be very grateful for any tip or code example which can help me to fix this behavior.
Thank you.

Here I add the final _top.v code:


/*
`include "morse.v"
*/
`include "uart_tx.v"

// look in pins.pcf for all the pin names on the TinyFPGA BX board
module top (
    input CLK,    // 16MHz clock
    output LED,   // User/boot LED next to power LED
    output USBPU,  // USB pull-up resistor
    output PIN_1 // uart output
);
    // drive USB pull-up resistor to '0' to disable USB
    assign USBPU = 0;

    morse insta_a (
      .CLK    ( CLK ), // input
      .LED    ( LED ) // output
    );

    assign PIN_1 = 0;


    wire [7:0] uart_data = 8'b00101010;
    uart_tx insta_tx (
        .i_Clock( CLK ),
        .i_Tx_DV( LED ),
        .i_Tx_Byte( uart_data ),
        .o_Tx_Active( PIN_1 )
      );
      defparam insta_tx.CLKS_PER_BIT = 500;

endmodule

#2

There are several problems with the uart_tx.v file. The one that is causing you most problems is the character set which is not ascii. If you display the file as ascii such as by using a cat command, you will see all the space characters display as an accented capital A. I believe that is stopping yosys from finding the module definition and causing the errors. You can fix that by changing the encoding to ascii in an editor and doing a global replace of the invalid character by space.The second problem is that the parameter definition in the first line of the file is invalid. It should have =default-value after the parameter name. If you fix those problems, you will find your call to uart_tx is wrong. The i_Tx_DV input won’t work with the output LED. You need to set the i_TX_DV to 1 to output a character, and then set it back to zero to avoid continuous output. It looks like you only have to set it for one clock cycle, or you can set it back to zero when o_Tx_Done is set or when o_Tx_Active is unset. Also your value of 500 for CLKS_PER_BIT will result in a baud rate of 32000, which is not one of the standard ones. Setting parameters using defparam is deprecated. You should set them by #(.parameter(value)) on the module instantiation.


#3

If you correct those errors and pass PIN_1 to the correct input (i_Tx_Serial) and don’t assign a fixed value to it, then the module works.

This top level module works for me to output a character about once per second:

module top (
input CLK, // 16MHz clock
output LED, // User/boot LED next to power LED
output USBPU, // USB pull-up resistor
output PIN_1 // uart output
);
// drive USB pull-up resistor to ‘0’ to disable USB
assign USBPU = 0;

morse insta_a (
  .CLK    ( CLK ), // input
  .LED    ( LED ) // output
);

wire dv;
reg [24:0] counter;

always @(posedge CLK) begin
counter <= counter + 1;
dv <= (counter == 0);
end

wire [7:0] uart_data = 8'b00101010;
uart_tx #(.CLKS_PER_BIT(139)) insta_tx (
    .i_Clock( CLK ),
    .i_Tx_DV(dv),
    .i_Tx_Byte( uart_data ),
    .o_Tx_Serial( PIN_1 )
  );

endmodule

The value of CLKS_PER_BIT is (16000000 / 115200) = 139.

I also renamed _top.v back to top.v, but that makes no difference.


#4

BTW, the quality of that uart implementation doesn’t seem to be too high. The s_CLEANUP state seems to be unnecessary, and it worked fine when I removed it. It causes the o_Tx_Done flag to be set for two clock cycles, which is odd.

Also have both o_Tx_Active and o_Tx_Done is redundant.


#5

Its working! Thank you so much @lawrie.griffiths. Now I’m printing character ‘A’ to my terminal.

I would never find that the uart_tx.v has bad encoding. I did copy/paste from website directly to ATOM. It’s like copy/paste protection :))

I will use different uart implementation, I just did not knew the basics of modules so I copyied the one that seemed would compile :slight_smile:
Also thanks for computing the 115200 baudrade clock divider and the nice 1 second transmit example. I have an oscilloscope so I check also that TX_DONE signals behavior.

Martin


#6

That uart implementation does work and the things I mentioned are not that serious and easily fixed. The fact that Tx_Done is set for two clock cycles probably does not matter unless the caller has code that relies on it only being set for one clock cycle. My example did not bother to check Tx_Done or Tx_Active, but real usage will need to detect Tx_Done, and update the character to send.

One reason why they might have the extra Cleanup state is that it allows you to do that without unsettingTx_DV, to get continuous sending of characters.