I used these examples to help teach myself Verilog. They are in the order I did them. The later examples are more fluent.
List of projects included on this page:
"CU EE" on HEX7-HEX4.assign SRAM_DQ = (KEY[1]? 16'hzzzz : SW[15:0]); PC=02 which contains 16'h8104, which is the instruction LI r1,4 (load-immediate register1 with value 4). This cpu is mostly intended for me to teach myself Verilog in an Altera context. // data memory: // single read and write // taken from Altera HDL style manual page 6-17 // Synchronous RAM with Read-Through-Write Behavior // and modified for 16 bit access // of 256 words module ram_infer (q, a, d, we, clk); output [15:0] q; input [15:0] d; input [7:0] a; input we, clk; reg [7:0] read_add; reg [15:0] mem [255:0]; always @ (posedge clk) begin if (we) mem[a] <= d; read_add <= a; end assign q = mem[read_add]; endmoduleThree port, dual-read, single write RAM (for registers)
// 16x16 register array // with dual-read + write // taken from Altera HDL style manual page 6-20 // modified for synchronous RAM with Read-Through-Write Behavior // and modified for 16 bit access // of 16 words module dual_ram_infer (q, q2, write_address, read_address, read_address2, d, we, clk); output [15:0] q; output [15:0] q2; input [15:0] d; input [3:0] write_address; input [3:0] read_address; input [3:0] read_address2; input we, clk; reg [3:0] a1, a2; reg [15:0] mem [15:0]; always @ (posedge clk) begin if (we) mem[write_address] <= d; a1 <= read_address; a2 <= read_address2; end assign q = mem[a1]; assign q2 = mem[a2]; endmodule
assembler instruction memory LI r0, 1 8001 ;need to NOP first inst out of reset LI r0, 1 8001 LI r1, 4 8104 SUB r1 ,r1, r0 1110 BNZ r1, -1 C1FF ;PC update timing implies that this jump is to the SUB JMP -3 E0Fd ;This jump is to the second LIA short mpeg of this program executing. The finger entering the frame from the lower right is running the clock. The blinking green LED is illuminated during the FETCH state. The left-most 2 digit 7-seg display is showing the PC. The 4 digit 7-seg display is showing the instruction being fetched/executed. The program loops through the subtract 4 times, then jumps back, reloads the counters and down-counts again.


I2C_AV_config module sends out data to configure eleven 9-bit registers in the audio codec using the I2C_controller communication module. The following table shows the configuration bit and the configuration used in the example.Audio_DAC module The example uses audio samples generated by DDS. Register num -- address -- Name |
Functions |
Example design data |
| R0 (00h) Left Line In | b4:0 is line volume. b7=1 mutes. b8=1 locks line vol together. |
data=1a; almost full volume, no mute |
| R1 (02h) Right Line In | b4:0 is line volume. b7=1 mutes. b8=1 locks line vol together. |
data=1a; almost full volume, no mute |
| R2 (04h) Left headphone out | b6:0 is volume. b7=1 enables zero crossing. b8=1 locks vol together. |
data=7b; almost full volume. Lineout on the DE2 is connected to this output. |
| R3 (06h) Right headphone out | b6:0 is volume. b7=1 enables zero crossing. b8=1 locks vol together. |
data=7b; almost full volume. Lineout on the DE2 is connected to this output. |
| R4 (08h) Analog Audio Path Control | b0=1 is mic boost. |
data=f8; no mic boost, no mic mute, line input to ADC, enable bypass, enable DAC, enable sidetone |
| R5 (0ah) Digital Audio Path Control | b0=1 disables highpass filter b2:1 is de-emphasis control 11=48kHz, 10=44kHz, 01=32kHz, 00=disable b3=1 is DAC soft mute b4=1 stores DC offset |
data=06; enable highpass, 48kHz filter |
| R6 (0ch) Power Down Control | see data sheet | data=00; turn it all on |
| R7 (0eh) Digital Audio Interface Format | b1:0 is format, use 01=MSB-first, left-justified b3:2 is bit length, use 00=16 bits |
data=01; MSB, left, 16-bits |
| R8 (10h) Sampling control | b0=0 normal mode b1=1 for best oversampling |
data=02; oversample |
| R9 (12h) Active control | b0=1 turns on codec | data=01; crank it up! |
| R15 (1eh) Reset control | writing 0x00 resets | not used |
Audio_DAC module allows stereo output. The output variable oAUD_LRCK sends left-channel data when high and right-channel data when low. In this simple example, the phase of the DDS is shifted 90 degrees.
ADCLRCK signals right-channel when low and left-channel when high.
top_level module was modifed slightly to simplify the interface to the new Audio_DAC_ADC module. The I2C_AV_config module LUT was modified to turn on the ADC with line-input. Note that one word of dummy data must be sent across the I2C interface before the first actual setup parameter. The central part of the Audio_DAC_ADC module is shown below.
Data is clocked in/out on the negative edge of AUD_BCLK. The 16-bit, serial data is 2's complement, MSB first. The LRCK_1X signal represents the locally generated ADCLRCK.
always@(negedge oAUD_BCK or negedge iRST_N) begin if(!iRST_N) SEL_Cont <= 0; else begin SEL_Cont <= SEL_Cont+1; //BIT SELECTOR: 4 bit counter, so it wraps at 16 if (LRCK_1X) //ADCLRCK AUD_inL[~(SEL_Cont)] <= iAUD_ADCDAT; else AUD_inR[~(SEL_Cont)] <= iAUD_ADCDAT; end end // output the DAC bit-stream assign oAUD_DATA = (LRCK_1X)? AUD_outL[~SEL_Cont]: AUD_outR[~SEL_Cont] ; // Filter the input sample and register output always@(negedge LRCK_1X ) //oAUD_LRCK begin // 1-pole lowpass at about 200 Hz. The >>> operator is SIGNED shift right AUD_outR <= (AUD_inR>>>6) + AUD_outR - (AUD_outR>>>6); // just pass through left channel AUD_outL <= AUD_inL ; end
References
JO Hamblen, TS Hall and MD Furman, Rapid protoyping of digital systems, Springer 2005