//////////////////////////////////////////////////////////////////////////////// // When the reset button is pressed, the game generates a random four-digit // number X. Players can use the keyboard to enter a four-digit number Y. When // the player finishes entering Y, it calculates A and B based on X and Y and // displays them on SSD. // X will be generated with LFSR. Y will be entered with 0~9 on the keyboard. // ESC on the keyboard will be used as the reset button. LCD will be used to // display the game log. //////////////////////////////////////////////////////////////////////////////// module final_project_TOP( // SSD output reg [7:0] ssd_cathode, output reg [3:0] ssd_anode, // LCD output [3:0] vgaRed, output [3:0] vgaGreen, output [3:0] vgaBlue, output hsync, output vsync, // I2S (speaker) output audio_mclk, // master clock output audio_lrck, // left-right clock output audio_sck, // serial clock output audio_sdin, // serial audio data input // LED output [15:0] led, // PS2 (keyboard) inout PS2_DATA, inout PS2_CLK, // button input reset_button, // global input clk_100mhz, input rst_n // active low reset ); ////////////////////////////////////////////////////////////////////////////// // global // // rst: // active high reset. // reset: // active high reset. // clk_freerun: // a free-run n-bit binary counter to generate 100M / 2^n Hz clock. ////////////////////////////////////////////////////////////////////////////// wire rst; wire reset; assign rst = ~rst_n; assign reset = ~rst_n; reg [99:0] clk_freerun; always @(posedge clk_100mhz or negedge rst_n) begin if (rst_n) clk_freerun <= 'b0; else clk_freerun <= clk_freerun + 100'b1; end ////////////////////////////////////////////////////////////////////////////// // keyboard IP // // wire: // // key_down: // status bits. Each bit indicates pressed (1) or released (0) of each // button of the keyboard. // last_change: // represent the key which has been pressed or released. // key_valid: // should be active for one clock period when any key is pressed or // released. ////////////////////////////////////////////////////////////////////////////// wire [511:0] key_down; wire [8:0] last_change; wire key_valid; KeyboardDecoder KeyboardDecoder( // output .key_down, .last_change, .key_valid, // inout .PS2_DATA, .PS2_CLK, // input .rst, .clk (clk_100mhz) // 100mhz clock ); ////////////////////////////////////////////////////////////////////////////// // SSD // The anodes of the seven LEDs forming each digit are tied together into one // "common anode" circuit node, but the LED cathodes remain separate. This // signal connection scheme creates a multiplexed display, where the cathode // signals are common to all digits but they can only illuminate the segments // of the digit whose corresponding anode signal is asserted. // // use free-run clock to create persistence of vision. drives the anode // signals and corresponding cathode patterns of each digit in a repeating, // continuous succession at an update rate that is faster than the human eye // can detect. Each digit is illuminated just one-fourth of the time, but // because the eye cannot perceive the darkening of a digit before it is // illuminated again, the digit appears continuously illuminated. If the // update, or "refresh", rate is slowed to around 45Hz, a flicker can be // noticed in the display. // // output: // // ssd_cathode: // The cathodes of similar segments on all four displays are connected into // seven circuit nodes labeled CA through CG. These seven cathode signals // are available as inputs to the 4-digit display. // ssd_anode: // The common anode signals are available as four "digit enable" input // signals to the 4-digit display. // // reg: // // ssd_digit0: // // ssd_digit1: // // ssd_digit2: // // ssd_digit3: // ////////////////////////////////////////////////////////////////////////////// reg [7:0] ssd_digit_0; reg [7:0] ssd_digit_1; reg [7:0] ssd_digit_2; reg [7:0] ssd_digit_3; // anode 1-hot enable always @* begin case (clk_freerun[19:18]) 2'd0: ssd_anode = 4'b1110; 2'd1: ssd_anode = 4'b1101; 2'd2: ssd_anode = 4'b1011; 2'd3: ssd_anode = 4'b0111; default: ssd_anode = 4'b0000; endcase end // cathode select always @* begin case (clk_freerun[19:18]) 2'd0: ssd_cathode = ssd_digit_0; 2'd1: ssd_cathode = ssd_digit_1; 2'd2: ssd_cathode = ssd_digit_2; 2'd3: ssd_cathode = ssd_digit_3; default: ssd_cathode = 'b0; endcase end ////////////////////////////////////////////////////////////////////////////// // I2S (speaker) // a stereo signal parallel-to-serial processor to generate the speaker // control signals. The I2S protocol outlines one specific type of PCM // digital audio communication with defined parameters outlined in the // Philips specification. // // output: // // audio_mclk: // master clock. (typically 256 x LRCLK) This is not part of the I2S // standard, but is commonly included for synchronizing the internal // operation of the analog/digital converters. // audio_lrck: // left-right clock. Officially "word select (WS)". Typically called // "left-right clock (LRCLK)" or "frame sync (FS)". 0 = Left channel, 1 = // Right channel. The word select clock lets the device know whether // channel 0 or channel 1 is currently being sent, because I2S allows two // channels to be sent on the same data line. It is a 50% duty-cycle signal // that has the same frequency as the sample frequency. For stereo material // the I2S specification states that left audio is transmitted on the low // cycle of the word select clock and the right channel is transmitted on // the high cycle. It is typically synchronized to the falling edge of the // serial clock, as the data is latched on the rising edge. // audio_sck: // serial clock. Officially "continuous serial clock (SCK)". Typically // written "bit clock (BCLK)". // The bit clock pulses once for each discrete bit of data on the data // lines. The bit clock frequency is the product of the sample rate, the // number of bits per channel and the number of channels. // audio_sdin: // serial audio data input. multiplexed data line. Officially "serial data // (SD)", but can be called SDATA, SDIN, SDOUT, DACDAT, ADCDAT, etc. // Data is signed, encoded as two's complement with the MSB first. This // allows the number of bits per frame to be arbitrary, with no negotiation // required between transmitter and receiver. // // wire: // // audio_left: // left channel audio data. // audio_right: // right channel audio data. // // reg: // // audio_lrck_delayed: // In order to delay the MSB of sdin by one SCK cycle compared with LRCK. // this signal (audio_lrck_delayed) is sync with lrck. // audio_lrck_delayed_delayed: // In order to delay the MSB of sdin by one SCK cycle compared with LRCK. // this signal (audio_lrck_delayed_delayed) is delay by one SCK cycle // compared with LRCK. // sdin_counter: // to encoded audio_sdin with the MSB first. ////////////////////////////////////////////////////////////////////////////// assign audio_mclk = clk_freerun[1]; // 25MHz (~24.5760MHz) assign audio_lrck = clk_freerun[8]; // 25MHz/128 (~192kHz) assign audio_sck = clk_freerun[3]; // 25MHz/128*32 (25MHz/4) reg audio_lrck_delayed; always @(negedge audio_sck or negedge rst_n) begin if (~rst_n) audio_lrck_delayed <= 'b0; else audio_lrck_delayed <= audio_lrck; end reg audio_lrck_delayed_delayed; always @(negedge audio_sck or negedge rst_n) begin if (~rst_n) audio_lrck_delayed_delayed <= 'b0; else audio_lrck_delayed_delayed <= audio_lrck_delayed; end reg [3:0] sdin_counter; always @(negedge audio_sck or negedge rst_n) begin if (~rst_n) sdin_counter <= 4'h0; else sdin_counter <= sdin_counter - 'b1; end wire [15:0] audio_left; wire [15:0] audio_right; assign audio_sdin = audio_lrck_delayed_delayed ? audio_left [sdin_counter] : audio_right[sdin_counter]; ////////////////////////////////////////////////////////////////////////////// // VGA // Video Graphics Array. Transmitting analog video signal. // // output: // // hsync: // horizontal sync (HS). used for video synchronization in the horizontal // direction. // vsync: // vertical sync (VS). used for video synchronization in the vertical // direction. // vgaRed: // used to control the red color, 0v (fully off) ~ 0.7v (fully on). // vgaGreen: // used to control the green color, 0v (fully off) ~ 0.7v (fully on). // vgaBlue: // used to control the blue color, 0v (fully off) ~ 0.7v (fully on). // // wire: // // valid: // in vga_controller.v assign valid = ((pixel_cnt < HD) && (line_cnt < VD)); // h_cnt: // in vga_controller.v assign h_cnt = (pixel_cnt < HD) ? pixel_cnt : 10'd0; // v_cnt: // in vga_controller.v assign v_cnt = (line_cnt < VD) ? line_cnt : 10'd0; ////////////////////////////////////////////////////////////////////////////// wire valid; wire h_cnt; wire v_cnt; vga_controller vga_controller( // output .hsync, .vsync, .valid, .h_cnt, .v_cnt, // input .pclk (clk_freerun[1]), // 800*525*60(frame/sec) = 25M (pixel/sec) .reset ); ////////////////////////////////////////////////////////////////////////////// // state transition FSM // // // // // ////////////////////////////////////////////////////////////////////////////// reg [99:0] state; reg [1:0] cursor_position; reg [3:0] x [3:0]; reg [3:0] y [3:0]; always @(posedge clk_100mhz or negedge rst_n) begin if (~rst_n) begin state <= 'b0; end else begin // if (~rst_n) begin if (key_valid) begin // backspace if (key_down[9'h066]) y[cursor_position] <= 4'hF; if (key_down[9'h066]) cursor_position <= cursor_position - 'b1; // left/right arrow if (key_down[9'h16B]) cursor_position <= cursor_position + 'b1; if (key_down[9'h174]) cursor_position <= cursor_position - 'b1; // store the number pressed if (key_down[9'h070]) y[cursor_position] <= 4'd0; if (key_down[9'h069]) y[cursor_position] <= 4'd1; if (key_down[9'h072]) y[cursor_position] <= 4'd2; if (key_down[9'h07A]) y[cursor_position] <= 4'd3; if (key_down[9'h06B]) y[cursor_position] <= 4'd4; if (key_down[9'h073]) y[cursor_position] <= 4'd5; if (key_down[9'h074]) y[cursor_position] <= 4'd6; if (key_down[9'h06C]) y[cursor_position] <= 4'd7; if (key_down[9'h075]) y[cursor_position] <= 4'd8; if (key_down[9'h07D]) y[cursor_position] <= 4'd9; // move the cursor after a number is pressed if (key_down[9'h070]) cursor_position <= cursor_position - 'b1; if (key_down[9'h069]) cursor_position <= cursor_position - 'b1; if (key_down[9'h072]) cursor_position <= cursor_position - 'b1; if (key_down[9'h07A]) cursor_position <= cursor_position - 'b1; if (key_down[9'h06B]) cursor_position <= cursor_position - 'b1; if (key_down[9'h073]) cursor_position <= cursor_position - 'b1; if (key_down[9'h074]) cursor_position <= cursor_position - 'b1; if (key_down[9'h06C]) cursor_position <= cursor_position - 'b1; if (key_down[9'h075]) cursor_position <= cursor_position - 'b1; if (key_down[9'h07D]) cursor_position <= cursor_position - 'b1; end // if (key_valid) begin end // always @(posedge clk_100mhz or negedge rst_n) begin endmodule