n00b Verilog Questions

Topics relating to PALs, CPLDs, FPGAs, and other PLDs used for the support or creation of 65-family processors, both hardware and HDL.
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Re: n00b Verilog Questions

Post by ElEctric_EyE »

In Verilog, is there a way to pass a Parameter value from a top_level project into the lower modules?

Or at this point must it become a register?
User avatar
MichaelM
Posts: 761
Joined: 23 Apr 2012
Location: Huntsville, AL

Re: n00b Verilog Questions

Post by MichaelM »

EEyE:

I am sure that there must be a more effective way than the way that I use, but for me, it is a reliable method.

In a lower level module, I use the parameter keyword to define various parameters that allow me to define desired configurations. In the top most module, I define a similar parameter, and pass that down through all of the instantiated sub-modules to the desired sub-modules.

The defparam keyword may also be used. It can be used to reach all the way to the desired sub-module using the hierarchical path name of the sub-module. It can be used from the top-level module.

The following three code segments illustrate the method that I use for passing parameters from the top-level module to sub-modules. The first code segment is the parameters in my Dual Core M65C02 top level module, the second is instantiation of one of the UART sub-modules, and the third is the definition of the UART sub-module.

Code: Select all

module M65C02Duo #(
    parameter pIRQ_Vector      = 16'hFFFE,  // Maskable Interrupt Vector
    parameter pBRK_Vector      = 16'hFFFE,  // BRK Instruction Trap Vector
    parameter pRST_Vector      = 16'hFFFC,  // Reset Vector
    parameter pNMI_Vector      = 16'hFFFA,  // Non-Maskable Interrupt Vector

    parameter pStkPtr_Rst      = 8'hFF,     // Stk Ptr Value after Reset
    parameter pInt_Hndlr       = 9'h021,    // _Int microroutine address

    parameter p_uP_AddrWidth   = 8'd9,
    parameter p_uP_Width       = 8'd36,
    parameter p_uP_Init        = "Src/M65C02_uPgm_V3b.coe",
    
    parameter pDEC_AddrWidth   = 8'd8,
    parameter pDEC_Width       = 8'd36,
    parameter pDEC_Init        = "Src/M65C02_IDEC_v3.coe",

    parameter pMMU_A_Init      = "Src/M65C02_MMU_CPU0.coe", // MMU Init. File
    parameter pMMU_B_Init      = "Src/M65C02_MMU_CPU1.coe", // MMU Init. File
    
    parameter pRAM_A_AddrWidth = 8'd14,     // 16384 x 8 Block RAM
    parameter pROM_A_AddrWidth = 8'd11,     //  2048 x 8 Block RAM
    parameter pRAM_B_AddrWidth = 8'd13,     //  8192 x 8 Block RAM
    parameter pROM_B_AddrWidth = 8'd11,     //  2048 x 8 Block RAM
    parameter pBus_Width       = 8'd8,      // Bus Width = 8 bits
    parameter pRAM_A_Init      = "Src/65C02_ft.txt",    // Functional Test Pgm
    parameter pROM_A_Init      = "Src/Mon6502_sbc25.txt",   // (0xFFFC)=0x0400
    parameter pRAM_B_Init      = "Src/M65C02_Tst6.txt",     // Here: JMP Here
    parameter pROM_B_Init      = "Src/Mon6502_sbc25.txt",   // (0xFFFC)=0x0400
    
    parameter pFrequency       = 29491200,  // (14.7456 MHz * 2)

    parameter pDefault_LCR_A   = 8'h40, // ~BRRE, RTSo, 232 w/o HS, 8N1
    parameter pDefault_IER_A   = 8'h00, // No interrupts enabled
    parameter pBaudrate_A      = 115200,
    parameter pRTOChrDlyCnt_A  = 3,     // RTO asserted on Rx idle 3 char times
    parameter pTF_Depth_A      = 0,     // Tx FIFO Depth = (2**(0+4))=16
    parameter pRF_Depth_A      = 0,     // Rx FIFO Depth = (2**(0+4))=16
    parameter pTF_Init_A       = "Src/UART_TF_16.coe",
    parameter pRF_Init_A       = "Src/UART_RF_16.coe",
    
    parameter pDefault_LCR_B   = 8'h40, // ~BRRE, RTSo, 232 w/o HS, 8N1 
    parameter pDefault_IER_B   = 8'h00, // No interrupts enabled
    parameter pBaudrate_B      = 115200,
    parameter pRTOChrDlyCnt_B  = 3,     // RTO asserted on Rx idle 3 char times
    parameter pTF_Depth_B      = 0,     // Tx FIFO Depth = (2**(0+4))=16
    parameter pRF_Depth_B      = 0,     // Rx FIFO Depth = (2**(0+4))=16
    parameter pTF_Init_B       = "Src/UART_TF_16.coe",
    parameter pRF_Init_B       = "Src/UART_RF_16.coe",

    parameter pDefault_CR      = 8'h30,  // Rate=1/16, Mode=0, Dir=MSB, Sel=0 
    parameter pSPI_FIFO_Depth  = 8'd4,   // Depth = (1 << 4) = 16
    parameter pSPI_FIFO_Init   = "Src/SPI_FIFO_Init_16.coe"
)(
    input   nRst,               // System Reset Input
    input   ClkIn,              // System Clk Input
    
    output  nRstO,              // Internal System Reset Output (OC w/ PU)

    //  M65C02 Clock Outputs

    output  Phi2O,              // Clock Phase 2 Output
    output  Phi1O,              // Clock Phase 1 Output - complement of Phi2O
    
    //  M65C02 External Bus Enable

    input   BE_In,              // Bus Enable: tri-states address, data, control
    
    //  M65C02 Special Interface Signals
    
    //input   nSO,                // Set oVerflow: currently unimplemented
    output  nWAI,               // Driven low by Wait instruction (ASIC-only)

    //  M65C02 External Interrupt Bus
    
    input   nNMI,               // Non-Maskable Interrupt Request: edge sense
    input   nIRQ,               // Maskable Interrupt Request: level sense
    output  nVP,                // Vector Pull: asserted to indicate ISR taken
    
    //  M65C02 Memory Interface Bus

    output  Sync,               // Synchronize: asserted during opcode fetch
    output  nML,                // Memory Lock: asserted during RMW instructions

    output  [3:0] nCE,          // Chip Enable for External RAM/ROM Memory
    output  RnW,                // Read/nWrite cycle control output signal
    output  nOE,                // External Asynchronous Bus
    output  nWE,                // External Asynchronous Bus Write Strobe
    inout   Rdy,                // Bus cycle Ready, drive low to extend cycle
    output  [ 3:0] XA,          // Extended Address Output for External Memory
    output  [15:0] A,           // External Memory Address Bus
    inout   [ 7:0] DB,          // External, Bidirectional Data Bus
    
    //  M65C02 Asynchronous Serial Port Interface
    
    output  reg TxD_A,          // Port A: Transmit Serial Data (Common 232/485)
    input   RxD_A,              // Port A: Receive Serial Data (AND Rx232/Rx485)
    output  reg nRTS_A,         // Port A: Ready To Send Flow Control Output
    input   nCTS_A,             // Port A: Clear To Send Flow Control Input
    
    output  reg DE_A,           // Port A: RS485 Drive Enable
    
    output  reg TxD_B,          // Port B: Transmit Serial Data (Common 232/485)
    input   RxD_B,              // Port B: Receive Serial Data (AND Rx232/Rx485)
    output  reg nRTS_B,         // Port B: Ready To Send Flow Control Output
    input   nCTS_B,             // Port B: Clear To Send Flow Control Input
    
    output  reg DE_B,           // Port B: RS485 Drive Enable

    //  M65C02 SPI Port Interface
    
    output  [1:0] nCSO,         // SPI I/F Chip Select
    output  SCK,                // SPI I/F Serial Clock
    output  MOSI,               // SPI I/F Master Out/Slave In Serial Data
    input   MISO,               // SPI I/F Master In/Slave Out Serial Data

    //  Non-65C02 Special Interface Signals

    output  nCore,              // nCSO[2]: 0 (On) - Core 1; 1 (Off) - Core 0
    input   nWP                 // Internal Boot/Monitor RAM write protect
);
The instantiation of one of the UARTs in the top-level module

Code: Select all

UART    #(
            .pFrequency(pFrequency),
            .pDefault_LCR(pDefault_LCR_A),
            .pDefault_IER(pDefault_IER_A),
            .pBaudrate(pBaudrate_A),
            .pRTOChrDlyCnt(pRTOChrDlyCnt_A),
            .pTF_Depth(pTF_Depth_A),
            .pRF_Depth(pRF_Depth_A),
            .pTF_Init(pTF_Init_A),
            .pRF_Init(pRF_Init_A)
        ) COM_A (
            .Rst(Rst), 
            .Clk(Clk),
            
            .IRQ(COM_A_IRQ),
            
            .Sel(COM_A_CE), 
            .Reg(PA_A[1:0]), 
            .RE(Rd_A), 
            .WE(Wr_A), 
            .DI(DO_A), 
            .DO(COM_A_DO),
            
            .TxD_232(TxD_232_A), 
            .RxD_232(rRxD_A), 
            .xRTS(RTS_A), 
            .xCTS(CTS_A),
            
            .TxD_485(TxD_485_A), 
            .RxD_485(rRxD_A), 
            .xDE(iDE_A), 

            .TxIdle(), 
            .RxIdle()
        );
The definition of the UART module. Some parameters are passed down to other instantiated sub-modules such as the transmit and receive FIFO modules.

Code: Select all

module UART #( 
    // Default UART Settings
    
    parameter pDefault_LCR = 8'h80,     // RTSo, Tx Enable, 232 w/o HS, 8N1
    parameter pDefault_IER = 8'h00,     // All interrupts disabled
    
    //  Default UART Baud Rate Settings
    
    parameter pFrequency = 29491200,    // 29.4912 MHz
    parameter pBaudrate  = 115200,      // 115200 bps
    
    // Default Receive Time Out Character Delay Count

    parameter pRTOChrDlyCnt = 3,        // Default Number of Characters for RTO

    // FIFO Configuration Parameters

    parameter pTF_Depth = 0,            // Tx FIFO Depth: 2**(TF_Depth + 4)
    parameter pRF_Depth = 0,            // Rx FIFO Depth: 2**(RF_Depth + 4)
    parameter pTF_Init  = "Src/UART_TF_16.coe", // Tx FIFO Memory Initialization
    parameter pRF_Init  = "Src/UART_RF_16.coe"  // Rx FIFO Memory Initialization
)(
    input   Rst,                        // System Reset
    input   Clk,                        // System Clock
    
    //  External Interrupt Request
    
    output  reg IRQ,                    // Interrupt Request
    
    //  Parallel Interface
    
    input   Sel,                        // UART Select
    input   [1:0] Reg,                  // UART Register Select
    input   RE,                         // UART Read Strobe
    input   WE,                         // UART Write Strobe
    input   [7:0] DI,                   // UART Data Input Bus
    output  wor [7:0] DO,               // UART Data Output Bus
    
    //  External UART Interface
    
    output  TxD_232,                    // RS-232 Mode TxD
    input   RxD_232,                    // RS-232 Mode RxD
    output  reg xRTS,                   // RS-232 Mode RTS (Ready-To-Receive)
    input   xCTS,                       // RS-232 Mode CTS (Okay-To-Send)
    
    output  TxD_485,                    // RS-485 Mode TxD
    input   RxD_485,                    // RS-485 Mode RxD
    output  xDE,                        // RS-485 Mode Transceiver Drive Enable

    //  TxSM/RxSM Status
    
    output  TxIdle,                     // UART TxSM Idle Status Output
    output  RxIdle                      // UART RxSM Idle Status Output
); 
Hope this helps. I find that determining the parameterization that should be applied to a particular IP module is difficult. Too much parameterization leads to code that is hard to read, and an insufficient amount leads to code difficult to adapt without error prone edits to multiple applications. I generally develop the module first, and then I add parameterization.
Michael A.
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Re: n00b Verilog Questions

Post by ElEctric_EyE »

Thanks Michael, that does help to a degree. In my situation I have 'wires' in the top_level that use the parameter values as well, so when I try applying what you did in your example to my case, I get an error "such&such is not a constant".

You seem to pass the parameter values from a module to the top_level, then to other modules. I think I need something that will pass a parameter value from the top_level to other modules.
User avatar
MichaelM
Posts: 761
Joined: 23 Apr 2012
Location: Huntsville, AL

Re: n00b Verilog Questions

Post by MichaelM »

EEyE:

I declare the parameters for both the top module and any sub-modules at the start of the top module. I can then use the testbench to modify these parameters to test specific configurations. I do this so that by reading the parameter settings of the top module I can determine/recall how the top module and the sub-modules are configured for a particular synthesis/MAP/PAR session.

The ISE command line can be used to define macro and set parameter values. Thus, I expect, although I've never attempted to do this, that I can modify the parameters in a compile/synthesis script and parameterize the complete project without any edits to the source files. There's a limited capability to do this in the GUI, but that capability is what I use to configure/command Data2MEM to modify the contents of the block RAMs for the M65C02/M16C5x soft-core projects.

Look into the operation of the defparam keyword. It appears to be used by Xilinx to directly modify parameters within a sub-module without going through the top module. I've come across examples of its use in most of the IP that CoreGen produces.
ElEctric_EyE wrote:
In my situation I have 'wires' in the top_level that use the parameter values as well, so when I try applying what you did in your example to my case, I get an error "such&such is not a constant".
I am not clear on the issue that you are experiencing. parameters are treated as constants as far as I know. For you to be getting that error indicates to me that you are trying to use a variable to determine vector indices in some way.

I am not a power use of Verilog 2001, but it appears to have some specific constructs to allow accessing various parts of a vector. I dropped in on stackoverflow.com and saw an example of such a construct. The question was posed as something like: "what does vector[8:i] do?"
Michael A.
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Re: n00b Verilog Questions

Post by ElEctric_EyE »

I will investigate, that's good info. Thanks for passing your findings along!
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Re: n00b Verilog Questions

Post by ElEctric_EyE »

................................

Today I was looking back at some Verilog code written for the orsoc graphics accelerator which has been posted in the Arithmetic Core Section on opencores.org. I had first started learning Verilog from this project years ago and have built my current project around the structure of the state machine that I had found in the gfx_line module. Back then I was trying to learn Bresenham Line...

After comparing that module to some of the other modules in that project today, I had noticed that one of the comments of another module of identical construction to the one I currently use for all my graphic accelerated functions, that said it was a Mealy machine. I had heard of Mealy/Moore state machines before but knew nothing of them.

So now something clicked and I immediately knew (at least I think I do!) what the difference is between the two.

In a Mealy state machine it takes inputs into consideration and when state machine tells an output to change state during a rising edge of a CLK, it actually happens on the following rising edge as if it were a flip flop. I've noticed this in my simulations, especially when I was nailing down exact timing on the back to back Read/Write functions of the Sync RAM I'm using.

In a Moore state machine, there are no inputs?, but when an output signal is assigned a value it changes during that state as if it were a latch.

Is this correct thinking?
Post Reply