//
// File: filter_sample.v
// Date: 10-Dec-05
// Author: I. Chuang <ichuang@mit.edu>
//
// Example for MIT 6.111 labkit: Xilinx distributed FIR filter module.
//
// This example demonstrates a 15-point single rate distributed arithmetic
// FIR filter generated using the Xilinx IP coregen tools. The filter is
// employed to process audio data, a sine wave generated by a 20 bit DDS.
// Switch[7] lets you choose between the unfiltered DDS output and the filter
// output, routing the output to the AC97 audio jack.
//
// The up and down buttons are used to select the DDS output frequency;
// switches[3:0] select the digit to change. The frequency is displayed
// on the hex displays.
//
// The 15 filter coefficients are 8-bits each (signed). The default values
// are 60 60 60 70 70 78 78 7f 78 78 70 70 60 60 60 which produces a low
// pass filter.
//
// You can also load in the filter coefficients from a PC connected to the
// FPGA via a Xilinx parallel port programming cable, using the jtag2mem
// interface. For example, to set the coefficients run
//
// xtclsh jtag2mem.tcl write 0
//
// Then type in 16 hex bytes (15 coefficients, one dummy byte). Writing
// to the 16th address location triggers a reload of the coefficients
// in the FIR filter.
`include "display_16hex.v"
`include "dds_20bit.v"
`include "ac97_audio.v"
`include "user_updown3.v"
`include "debounce.v"
`include "fir_filter.v"
`include "jtag2mem.v"
/////////////////////////////////////////////////////////////////////////////
// top level module
module filter_sample(
beep, audio_reset_b, ac97_sdata_out, ac97_sdata_in, ac97_synch,
ac97_bit_clock,
vga_out_red, vga_out_green, vga_out_blue, vga_out_sync_b,
vga_out_blank_b, vga_out_pixel_clock, vga_out_hsync,
vga_out_vsync,
tv_out_ycrcb, tv_out_reset_b, tv_out_clock, tv_out_i2c_clock,
tv_out_i2c_data, tv_out_pal_ntsc, tv_out_hsync_b,
tv_out_vsync_b, tv_out_blank_b, tv_out_subcar_reset,
tv_in_ycrcb, tv_in_data_valid, tv_in_line_clock1,
tv_in_line_clock2, tv_in_aef, tv_in_hff, tv_in_aff,
tv_in_i2c_clock, tv_in_i2c_data, tv_in_fifo_read,
tv_in_fifo_clock, tv_in_iso, tv_in_reset_b, tv_in_clock,
ram0_data, ram0_address, ram0_adv_ld, ram0_clk, ram0_cen_b,
ram0_ce_b, ram0_oe_b, ram0_we_b, ram0_bwe_b,
ram1_data, ram1_address, ram1_adv_ld, ram1_clk, ram1_cen_b,
ram1_ce_b, ram1_oe_b, ram1_we_b, ram1_bwe_b,
clock_feedback_out, clock_feedback_in,
flash_data, flash_address, flash_ce_b, flash_oe_b, flash_we_b,
flash_reset_b, flash_sts, flash_byte_b,
rs232_txd, rs232_rxd, rs232_rts, rs232_cts,
mouse_clock, mouse_data, keyboard_clock, keyboard_data,
clock_27mhz, clock1, clock2,
disp_blank, disp_data_out, disp_clock, disp_rs, disp_ce_b,
disp_reset_b, disp_data_in,
button0, button1, button2, button3, button_enter, button_right,
button_left, button_down, button_up,
switch,
led,
user1, user2, user3, user4,
daughtercard,
systemace_data, systemace_address, systemace_ce_b,
systemace_we_b, systemace_oe_b, systemace_irq, systemace_mpbrdy,
analyzer1_data, analyzer1_clock,
analyzer2_data, analyzer2_clock,
analyzer3_data, analyzer3_clock,
analyzer4_data, analyzer4_clock
);
output beep, audio_reset_b, ac97_synch, ac97_sdata_out;
input ac97_bit_clock, ac97_sdata_in;
output [7:0] vga_out_red, vga_out_green, vga_out_blue;
output vga_out_sync_b, vga_out_blank_b, vga_out_pixel_clock,
vga_out_hsync, vga_out_vsync;
output [9:0] tv_out_ycrcb;
output tv_out_reset_b, tv_out_clock, tv_out_i2c_clock, tv_out_i2c_data,
tv_out_pal_ntsc, tv_out_hsync_b, tv_out_vsync_b, tv_out_blank_b,
tv_out_subcar_reset;
input [19:0] tv_in_ycrcb;
input tv_in_data_valid, tv_in_line_clock1, tv_in_line_clock2, tv_in_aef,
tv_in_hff, tv_in_aff;
output tv_in_i2c_clock, tv_in_fifo_read, tv_in_fifo_clock, tv_in_iso,
tv_in_reset_b, tv_in_clock;
inout tv_in_i2c_data;
inout [35:0] ram0_data;
output [18:0] ram0_address;
output ram0_adv_ld, ram0_clk, ram0_cen_b, ram0_ce_b, ram0_oe_b, ram0_we_b;
output [3:0] ram0_bwe_b;
inout [35:0] ram1_data;
output [18:0] ram1_address;
output ram1_adv_ld, ram1_clk, ram1_cen_b, ram1_ce_b, ram1_oe_b, ram1_we_b;
output [3:0] ram1_bwe_b;
input clock_feedback_in;
output clock_feedback_out;
inout [15:0] flash_data;
output [23:0] flash_address;
output flash_ce_b, flash_oe_b, flash_we_b, flash_reset_b, flash_byte_b;
input flash_sts;
output rs232_txd, rs232_rts;
input rs232_rxd, rs232_cts;
inout mouse_clock, mouse_data;
//input mouse_clock, mouse_data;
input keyboard_clock, keyboard_data;
input clock_27mhz, clock1, clock2;
output disp_blank, disp_clock, disp_rs, disp_ce_b, disp_reset_b;
input disp_data_in;
output disp_data_out;
input button0, button1, button2, button3, button_enter, button_right,
button_left, button_down, button_up;
input [7:0] switch;
output [7:0] led;
inout [31:0] user1, user2, user3, user4;
inout [43:0] daughtercard;
inout [15:0] systemace_data;
output [6:0] systemace_address;
output systemace_ce_b, systemace_we_b, systemace_oe_b;
input systemace_irq, systemace_mpbrdy;
output [15:0] analyzer1_data, analyzer2_data, analyzer3_data,
analyzer4_data;
output analyzer1_clock, analyzer2_clock, analyzer3_clock, analyzer4_clock;
////////////////////////////////////////////////////////////////////////////
//
// I/O Assignments
//
////////////////////////////////////////////////////////////////////////////
// Audio Input and Output
assign beep= 1'b0;
// assign audio_reset_b = 1'b0;
// assign ac97_synch = 1'b0;
// assign ac97_sdata_out = 1'b0;
// ac97_sdata_in is an input
// VGA Output
assign vga_out_red = 10'h0;
assign vga_out_green = 10'h0;
assign vga_out_blue = 10'h0;
assign vga_out_sync_b = 1'b1;
assign vga_out_blank_b = 1'b1;
assign vga_out_pixel_clock = 1'b0;
assign vga_out_hsync = 1'b0;
assign vga_out_vsync = 1'b0;
// Video Output
assign tv_out_ycrcb = 10'h0;
assign tv_out_reset_b = 1'b0;
assign tv_out_clock = 1'b0;
assign tv_out_i2c_clock = 1'b0;
assign tv_out_i2c_data = 1'b0;
assign tv_out_pal_ntsc = 1'b0;
assign tv_out_hsync_b = 1'b1;
assign tv_out_vsync_b = 1'b1;
assign tv_out_blank_b = 1'b1;
assign tv_out_subcar_reset = 1'b0;
// Video Input
assign tv_in_i2c_clock = 1'b0;
assign tv_in_fifo_read = 1'b0;
assign tv_in_fifo_clock = 1'b0;
assign tv_in_iso = 1'b0;
assign tv_in_reset_b = 1'b0;
assign tv_in_clock = 1'b0;
assign tv_in_i2c_data = 1'bZ;
// tv_in_ycrcb, tv_in_data_valid, tv_in_line_clock1, tv_in_line_clock2,
// tv_in_aef, tv_in_hff, and tv_in_aff are inputs
// SRAMs
assign ram0_data = 36'hZ;
assign ram0_address = 19'h0;
assign ram0_adv_ld = 1'b0;
assign ram0_clk = 1'b0;
assign ram0_cen_b = 1'b1;
assign ram0_ce_b = 1'b1;
assign ram0_oe_b = 1'b1;
assign ram0_we_b = 1'b1;
assign ram0_bwe_b = 4'hF;
assign ram1_data = 36'hZ;
assign ram1_address = 19'h0;
assign ram1_adv_ld = 1'b0;
assign ram1_clk = 1'b0;
assign ram1_cen_b = 1'b1;
assign ram1_ce_b = 1'b1;
assign ram1_oe_b = 1'b1;
assign ram1_we_b = 1'b1;
assign ram1_bwe_b = 4'hF;
assign clock_feedback_out = 1'b0;
// clock_feedback_in is an input
// Flash ROM
assign flash_data = 16'hZ;
assign flash_address = 24'h0;
assign flash_ce_b = 1'b1;
assign flash_oe_b = 1'b1;
assign flash_we_b = 1'b1;
assign flash_reset_b = 1'b0;
assign flash_byte_b = 1'b1;
// flash_sts is an input
// RS-232 Interface
assign rs232_txd = 1'b1;
assign rs232_rts = 1'b1;
// rs232_rxd and rs232_cts are inputs
// PS/2 Ports
// mouse_clock, mouse_data, keyboard_clock, and keyboard_data are inputs
// LED Displays
/*
assign disp_blank = 1'b1;
assign disp_clock = 1'b0;
assign disp_rs = 1'b0;
assign disp_ce_b = 1'b1;
assign disp_reset_b = 1'b0;
assign disp_data_out = 1'b0;
*/
// disp_data_in is an input
// Buttons, Switches, and Individual LEDs
//lab3 assign led = 8'hFF;
// button0, button1, button2, button3, button_enter, button_right,
// button_left, button_down, button_up, and switches are inputs
// User I/Os
assign user1 = 32'hZ;
assign user2 = 32'hZ;
assign user3 = 32'hZ;
assign user4 = 32'hZ;
// Daughtercard Connectors
assign daughtercard = 44'hZ;
// SystemACE Microprocessor Port
assign systemace_data = 16'hZ;
assign systemace_address = 7'h0;
assign systemace_ce_b = 1'b1;
assign systemace_we_b = 1'b1;
assign systemace_oe_b = 1'b1;
// systemace_irq and systemace_mpbrdy are inputs
// Logic Analyzer
assign analyzer1_data = 16'h0;
assign analyzer1_clock = 1'b1;
assign analyzer2_data = 16'h0;
assign analyzer2_clock = 1'b1;
assign analyzer3_data = 16'h0;
assign analyzer3_clock = 1'b1;
assign analyzer4_data = 16'h0;
assign analyzer4_clock = 1'b1;
////////////////////////////////////////
// master clock for this system is the clock_27mhz
wire clk;
BUFG vclk2(.O(clk),.I(clock_27mhz));
wire power_on_reset;
SRL16 reset_sr (.D(1'b0), .CLK(clk), .Q(power_on_reset),
.A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1));
defparam reset_sr.INIT = 16'hFFFF;
wire user_reset;
debounce dbreset(1'b0,clk,~button_enter,user_reset);
wire reset = power_on_reset | user_reset;
////////////////////////////////////////
// The dds example
// dds
//
// The output frequency is freq * 48000 / (2^21) Hz
// assuming clk_dds is 48 kHz. clk_dds is fed to the clock enable
// pin of the dds module. Beware! The output is encoded as a two's
// complement value!
wire [31:0] freq; // phase increment value (sets output freq)
wire we; // write enable
wire [4:0] dds_a = 5'b0; // used for multiple output channels (not here)
wire rfd; // not used by DDS, always high
wire rdy; // high when output samples ready
wire [19:0] sine,cosine; // quadrature outputs of DDS
reg clk_dds; // DDS output clock
dds_20bit dds1(freq,we,dds_a,clk,clk_dds,rdy,sine,cosine);
reg [31:0] old_freq;
always @(posedge clk) old_freq <= freq;
assign we = ~(freq == old_freq);
// AC97 driver
wire [19:0] from_ac97_data, to_ac97_data;
wire audio_ready;
audio myaudio(clk, power_on_reset, from_ac97_data, to_ac97_data,
audio_ready, audio_reset_b, ac97_sdata_out, ac97_sdata_in,
ac97_synch, ac97_bit_clock);
defparam myaudio.VOLUME = 4'd8;
// FIR filter module
wire [31:0] filter_out;
wire frdy, frfd;
wire fld_we;
wire fcoef_ld;
reg [7:0] fld_din;
wire [19:0] filter_in = sine;
fir_filter ff1(clk_dds, frdy, clk, frfd, fld_we, fcoef_ld, fld_din,
filter_in, filter_out);
// FIR filter coefficients
reg [7:0] coeftab[15:0];
reg load_coefs;
wire [3:0] jtag_addr;
reg [4:0] ccount;
assign fld_we = (ccount>0); // write enable for coefs to filter
wire jtag_we;
wire [7:0] jtag_write;
wire [7:0] jtag_read = coeftab[jtag_addr];
reg loaded_flag;
assign fcoef_ld = load_coefs;
wire [4:0] idx = ccount-1;
always @(posedge clk) // start load of coefs if addr=F is written
begin
load_coefs <= reset ? 0
: ((jtag_addr==4'hF) & jtag_we) ? 1
: 0;
loaded_flag <= (ccount==16) ? ~loaded_flag : loaded_flag;
ccount <= load_coefs ? 4'b1
: (ccount==0) ? ccount
: (ccount==16) ? 4'b0
: ccount+1;
fld_din <= coeftab[idx[3:0]];
if (jtag_we)
coeftab[jtag_addr] <= jtag_write;
end
// output either DDS output or filter output, depending on switch[7]
// wire [19:0] pcm_data;
// tone750hz tone(clk, audio_ready, pcm_data);
assign to_ac97_data = switch[7] ? filter_out[31:31-19] : sine;
// generate DDS clock from ac'97 audio_ready signal
reg old_ready;
always @(posedge clk)
begin
old_ready <= audio_ready;
clk_dds <= audio_ready & ~old_ready; // one cycle delayed ok
end
// user input of frequency
wire [3:0] digselect = switch[3:0];
wire [30:0] data;
wire [30:0] initval = 31'h03db_aaed;
user_updown3 uud1(clk,reset,data,~button_up,~button_down,initval,digselect);
defparam uud1.NBIT = 31;
defparam uud1.NMAX = 31'h8fff_ffff;
defparam uud1.NDIGIT = 4; // number of bits in digselect
// frequency sweep
reg [31:0] freq_sweep;
always @(posedge clk)
freq_sweep <= (freq_sweep >= 32'h0fff_0000) ? 0 : freq_sweep + 1;
// select DDS frequency based on switch[6]: user input or sweep
assign freq = switch[6] ? {freq_sweep[31:8],8'b0} : {1'b0,data};
// JTAG interface to change filter coefficients
wire [3:0] state; // for debugging
jtag2mem #(.DBITS(8),.ABITS(4))
j2m(reset, clk, jtag_read, jtag_write, jtag_addr, jtag_we, state);
// display frequency on hex dot display
assign led = ~{ loaded_flag, 3'b0, digselect };
wire [63:0] dispdata = {digselect,cosine[19:19-11],4'b0,jtag_write,
4'b0,jtag_addr,4'b0,data};
display_16hex d1(reset, clk, dispdata,
disp_blank, disp_clock, disp_rs, disp_ce_b,
disp_reset_b, disp_data_out);
endmodule