///////////////////////////////////////// // // mdlring.v with clock DLL // ///////////////////////////////////////// // // Last modified: March 23, 2004 // based on: Surin Kittitornkun's mltring.v // by Matt King (matthewking@wisc.edu) ///////////////////////////////////////// `timescale 1 ns / 100 ps /* mltring.v memory and logic test ring: serial port, clk, reset_b, parallel port, bar LED, left SRAM, right SRAM (including RAMDAC index values) and test access through external left and right headers. Also contains sample control and interface logic. */ /* Do not include any other code in this module or modify code except as directed without instructor's permission! Failure to follow this warning in a way that results in damage to the XESS Board or its components may result in lab charges for replacement costs! */ /* To prevent three-state conflict between SRAM and output data on ld and rd I/Os, the following control and data specifications are required. */ /////////////////////////////////////////////////////////////////////////////////// // // left and right memory banks // interface module (must be used by the students) // /////////////////////////////////////////////////////////////////////////////////// module interface (clk, clk_90, dll_reset, // system signals read, write, proc_addr, proc_data_from, // signals from processor ram_addr, ram_data, ceb, web, oeb ); // signals to/from SRAM // inputs from mdlring input clk, clk_90; // DLL reset is active high. // Needs to be distinct from system reset input dll_reset; // connections to student processor module input read, write; input [18:0] proc_addr; input [15:0] proc_data_from; // connections to SRAM output [18:0] ram_addr; inout [15:0] ram_data; output ceb, web, oeb; // control signal reg ceb; // input registers reg [15:0] pdat; reg [18:0] padr; reg read_cycle; reg write_cycle; // address supplied to the SRAM reg [18:0] ram_addr; // oscillators reg osc_clk; reg osc_clk90; reg osc_nclk90; // used to generate SRAM control signals wire write_ok; wire read_ok; reg read_enable; // used to verify oscillators in known state reg read_correct; reg write_correct; // generate from oscillators assign write_ok = (write_correct) ? osc_clk90 ^ osc_nclk90 : ~(osc_clk90 ^ osc_nclk90); assign read_ok = (read_correct) ? ~(osc_clk ^ osc_clk90) : osc_clk ^ osc_clk90; // Assign input data to SRAM databus during a write operation assign ram_data = (read_ok & write_cycle)? pdat: 16'hZZZZ; // Assign SRAM control signals assign web = ~(write_ok & write_cycle); assign oeb = ~(read_ok & read_enable & read_cycle); always @ (posedge dll_reset) begin ceb <= 1'b0; end // verify correct operation of oscilators always @ (negedge clk or posedge dll_reset) begin if(dll_reset == 1'b1) begin read_correct <= 1; write_correct <= 1; end else begin if(read_ok != 1'b1) read_correct <= ~read_correct; if(write_ok != 1'b1) write_correct <= ~write_correct; end end // update address to SRAM always @ (posedge clk_90 or posedge dll_reset) begin if(dll_reset == 1'b1) begin ram_addr <= 0; read_enable <= 0; end else begin ram_addr <= padr; read_enable <= read_cycle; end end // Latch input data and determine operation to be performed // writes take precedence over reads always @ (posedge clk or posedge dll_reset) begin if(dll_reset == 1'b1) begin read_cycle <= 0; write_cycle <= 0; padr <= 0; pdat <= 0; end else begin read_cycle <= read & ~write; write_cycle <= write; padr <= proc_addr; pdat <= proc_data_from; end end // define signals to generate SRAM control signals always @ (posedge clk or posedge dll_reset) begin if(dll_reset == 1'b1) osc_clk <= 1'b0; else osc_clk <= ~osc_clk; end always @ (posedge clk_90 or posedge dll_reset) begin if(dll_reset == 1'b1) osc_clk90 <= 1'b0; else osc_clk90 <= ~osc_clk90; end always @ (negedge clk_90 or posedge dll_reset) begin if(dll_reset == 1'b1) osc_nclk90 <= 1'b0; else osc_nclk90 <= ~osc_nclk90; end endmodule /* Include your additional external ports in the next statement - In the mltring.udf file, be sure to remove the # from the pins and enter the correct signal names for your ports. Otherwise, FPGA damage can occur due to arbitrary pin assignment! */ /////////////////////////////////////////////////////////////////////////////////// // // mdlring (the topmost module to download to FPGA) // /////////////////////////////////////////////////////////////////////////////////// module mdlring (clk, // external clock reset_b, // processor reset dll_reset_b, // DLL reset dll_lock, // signal whether CLKDLL is locked lceb, loeb, lweb, la, ld, // to mem left bank control/data rceb, roeb, rweb, ra, rd, // to mem right bank control/data TxD, RxD // serial interface to hyperterminal // Define your external I/O ports here ); /*The following is the input from the internal/external clock on pin p89: */ input clk; /* The following is the input for reset_b, which is the active low reset attached to sw<1>, the pushbutton on p174. If you want an active high reset, you need to invert reset_b. The lines required for this active high reset are given below and should be removed if not needed. */ input reset_b; wire reset; assign reset = ~reset_b; // DLL signals input dll_reset_b; output dll_lock; wire dll_reset; assign dll_reset = ~dll_reset_b; // Left SRAM and test interface signals: output lceb ; // active low chip enable for left SRAM output loeb ; // active low output enable for the left SRAM output lweb ; // active low write enable for the left SRAM inout[15:0] ld; // left bidirectional data and test output[18:0] la; // left address/test outputs // Right SRAM and test interface signals: output rceb ; // active low chip enable for right SRAM output roeb ; // active low output enable for the right SRAM output rweb ; // active low write enable for the right SRAM inout[15:0] rd; // right bidirectional data and test output[18:0] ra; // right address/test outputs /* The following are the receive and transmit lines respectively for the serial port: */ input RxD ; // serial recieve data output TxD ; // serial transmit data assign TxD = RxD; /////////////////////////////////////////////////////////////////////////////////// // // Add your external input/output declarations here! // /////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////// // // local signal declaration // ///////////////////////////////////////// wire lread, lwrite; // mem left bank signals for students to read/write memory wire [18:0] laddr; wire [15:0] ldata; wire rread, rwrite; // mem right bank signals for students to read/write memory wire [18:0] raddr; wire [15:0] rdata; wire clk_ibufg; // input buffered clk wire clk_1,clk_2; // divided by 1 and 2 clks wire clk_90; // 90 degree out of phase clk for memory interface wire clk_1_design, clk_2_design, // use divided by 1 and 2 clks for your design clk_90_design; //////////////////////////////////////////////////// // // LEFT-bank SRAM Interface // //////////////////////////////////////////////////// wire [15:0] lread_data; assign lread_data = ld; interface leftbank(.clk(clk_1_design), // system signals .clk_90(clk_90_design), .dll_reset(dll_reset), .read(lread), // signals from processor .write(lwrite), .proc_addr(laddr), .proc_data_from(ldata), .ram_addr(la), // signals to/from SRAM .ram_data(ld), .ceb(lceb), .web(lweb), .oeb(loeb) ); //////////////////////////////////////////////////// // // RIGHT-bank SRAM controller and Interface modules // //////////////////////////////////////////////////// wire [15:0] rread_data; assign rread_data = rd; interface rightbank(.clk(clk_1_design), // system signals .clk_90(clk_90_design), .dll_reset(dll_reset), .read(rread), // signals from processor .write(rwrite), .proc_addr(raddr), .proc_data_from(rdata), .ram_addr(ra), // signals to/from SRAM .ram_data(rd), .ceb(rceb), .web(rweb), .oeb(roeb) ); ///////////////////////////////////////// // // DLL clock instantiation // for dividing and generating different phases of master clock // ///////////////////////////////////////// IBUFG CLK_ibufg( // input clock buffer .I (clk), .O (clk_ibufg) ); BUFG CLK_bufg1( // global clock buffer 1 .I (clk_1), .O (clk_1_design) // use this clk_1_design in your design ); BUFG CLK_bufg2( // global clock buffer 2 .I (clk_2), .O (clk_2_design) // use this clk_2_design in your design ); BUFG CLK_bufg3( // global clock buffer 2 .I (clk_90), .O (clk_90_design) // use this clk_2_design in your design ); CLKDLL U1 // clock Delay Lock Loop ( .CLKIN(clk_ibufg), // input buffered clock .CLKFB(clk_1_design), // feedback clock .RST(dll_reset), // individual reset for DLL .CLK2X(), // 2x clock .CLK0(clk_1), // 1x clock .CLK90(clk_90), // 90-degree phase clock .CLK180(), // 180-degree phase clock .CLK270(), // 270-degree phase clock .CLKDV(clk_2), // divided clk by CLKDV_DIVDE factor .LOCKED(dll_lock) // dll_lock=1 if DLL is working properly ); // defparam U1.CLKDV_DIVIDE=2; // uncomment the above line for functional simulation only // CLKDV_DIVIDE's default value is 2. // Other than that, you must specify it in mdlring.ucf. // CLK2x, CLK90, CLK180, CLK270, can also be used for // twice the input clock frequency, 90-degree phase, // 180-degree phase, and 270-degree phase clocks respectively. // Note that for CLK2x to work correctly, the 1x input // clock freq. must be greater than or equal 20 MHz. // end CLKDLL /////////////////////////////////////////////////////////////////////////////////// // // Declare your local signals here! // // Instantiate the top module of your design here! // /////////////////////////////////////////////////////////////////////////////////// endmodule