NPL Tutorial - Step 4
Before proceeding, it might be a good idea to understand, what the new CPLD programming file will do to our Ethernut Board. For this we will now present the most incomplete introduction to Verilog HDL. ;-)
Verilog is very similar to the C programming language. A Verilog source consists of one or more modules, which can be called like C functions from within other modules. Our sample provides one module only:
module npltut01(NRESET, NMR, A, D, D15, P3, P4, P5, P6, P7, P8, P9, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, NOE, NWE, NCS0, NWAIT, NFBYTE, CAR, CDR, NCRD, NCWR, PNCS, CRD, CTD, CRTS, CCTS, CDTR, CDSR, CDCD, CRI, CFON, CNFOFF, CNINVAL, MDAT, MCLK, MCMD, MCD, MWP, ALARM, PLCLK1, PLCLK2, CLKS2, CLKOE, ULED, WAKEUP, FBUSY);
Like in the old C style, the parameter types are declared below the function declaration:
input NRESET; input NMR; input [23:0]A; inout [7:0]D; input D15; input P3; input P4; input P5; input P6; input P7; input P8; input P9; input P12; input P13; input P14; output P15; input P16; input P17; input P18; input P19; input P20; input P21; input P22; input P23; input P24; input P25; input P26; input P27; input NOE; input NWE; input NCS0; output NWAIT; output [15:0]CAR; inout [7:0]CDR; output NCRD; output NCWR; output PNCS; input CRD; output CTD; input CCTS; output CRTS; input CDSR; output CDTR; input CDCD; input CRI; input CNINVAL; output CFON; output CNFOFF; inout [3:0]MDAT; output MCLK; output MCMD; input MCD; input MWP; input ALARM; input WAKEUP; input PLCLK1; input PLCLK2; output CLKS2; output CLKOE; output ULED; input FBUSY; output NFBYTE;
The parameter names are exactly the same that we use in the [[../../../pdf/ethwm30d.pdf|Ethernut 3.0 Schematics]] for the signals traces. They represent the pins of our CPLD here. The following part of our module specifies the behaviour of the CPLD. In this simple module we use assignments only. Furthermore we will ignore most input signal, which produced the warnings in our previous step.
The first assign statement sets the data bus to Z-State. For those of you who are not too familiar with hardware: This is a high impedance state of an output. It means, that the output is neither low nor high and doesn't influence the connected signals in any way. More simple, these are switched-off outputs.
assign D = 8'bzzzzzzzz;
D is the name of the CPU data bus. If you check its declaration
there are 8 lines, indexed 0 to 7. Thus we have an 8-bit bi-directional (inout) data bus connected to the CPLD, which can be used to read from or write to the CPLD. This will be used later. For now we switch it off. The value on the right side of the assignment looks special, doesn't it? It starts with a length value followed by an apostrophe, followed by a radix (number base), followed by a constant. In this example we use binary numbers. To set the data bus low, we could have written
assign D = 8'b00000000; // Do not do this!
// Never ever do this! assign D = 1'b1; assign D = 1'b1; assign D = 1'b1; assign D = 1'b1; assign D = 1'b1; assign D = 1'b1; assign D = 1'b1; assign D = 1'b1;
forces all data bus pins to high, one by one in this case. Well, doing so would stop your Ethernut from working. The data bus is shared with the Ethernet Controller and the Flash Memory Chip. If one component pulls the data bus lines permanently low or high, the CPU will not be able to read and excecute the bootloader code. We also switch off the NWAIT output. This can be used to delay CPU access times for slow devices, which we do not need here.
assign NWAIT = 1'bz;
While looking to the schematics, you may have noticed, that the address and data busses of the [[../hardware/expansion.html|Ethernut expansion port]] are not directly connected to the CPU, but to the CPLD instead. This has two advantages. First the busses can be made compatible to the previous AVR based Ethernut versions. Second they can be used for different functions like I/O Ports, if no external memory bus is required. In out sample we set all lines to fixed levels.
assign CAR = 16'b0; assign CDR = 8'b0; assign NCRD = 1'b1; assign NCWR = 1'b1; assign PNCS = 1'b1;
A very special feature of Ethernut 3 is, that the complete RS232 interface is controlled by the CPLD. Sooner or later this will drive you crazy while experimenting with the CPLD. Doing something wrong may result in losing the RS232 output, leaving you completely in the dark. We will do it right here and connect the CPU lines for UART receive and transmit to the right RS232 lines.
assign P15 = CRD; assign CTD = P14;
Yes, internally connecting two pins of the CPLD is just that simple. P15 is the UART0 receive line of the CPU, which we connect to the receiver output of the RS232 interface. P14 is the transmitter line of the CPU and got connected to the transmitter input of the RS232 interface. Of course, the CPLD will not just route a wire internally, but use input and output drivers. Thus direction matters. The rest of our sample module doesn't present anything new. The RS232 handshake signals
assign CRTS = 1'b0; assign CDTR = 1'b0; assign CFON = 1'b1; assign CNFOFF = 1'b1;
and the MMC interface signals
assign MDAT = 4'b0000; assign MCLK = 1'b0; assign MCMD = 1'b0;
are all set to fixed values. For the remaining outputs some additional explanations might be helpful. The CLKS2 output selects the CPU main clock. If high, the CPU is running at full speed. Setting the CLKOE line to low would have the effect of switching all clocks off. This would be the most desastrous thing we could do and will completely disable the Ethernut. So better set it high.
assign CLKS2 = 1'b1; assign CLKOE = 1'b1;
The next output controls the green User LED, which is integrated in the reset button. Setting this line low will switch the LED on.
assign ULED = 1'b0;
Finally the NFBYTE signal controls the mode of the Flash Memory Chip, the one that contains the bootloader, for example. The CPU expects this chip in 16-bit mode, so we have to set this output to high.
assign NFBYTE = 1'b1;
Setting it to low would force the chip into 8-bit mode and would disable our bootloader, which we definitely must avoid. That's all our Verilog sample does. In summary, it switches on the User LED and routes UART0 to the RS232 interface. Most important, it will not disturb the basic functions of our Ethernut 3 board, so we will be able to replace the CPLD functions later with a more versatile version.