// ----------------------------------------------------------------------- // // Copyright 2003-2011 H. Peter Anvin - All Rights Reserved // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom // the Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall // be included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // ----------------------------------------------------------------------- // // de1flash.v // // Top-level module template for the Terasic DE1/Altera Cyclone II // Starter Board virtual JTAG programmer module // module de1flash ( input clock_50, // 50 MHz clock input [1:0] clock_24, // 24 MHz clock (on two pins) input [1:0] clock_27, // 27 MHz clock (on two pins) input ext_clock, // External clock input inout ps2_clk, // PS/2 keyboard clock inout ps2_dat, // PS/2 keyboard data output [9:0] ledr, // Red LEDs output [7:0] ledg, // Green LEDs output [6:0] s7_0, // 7-segment LEDs output [6:0] s7_1, // 7-segment LEDs output [6:0] s7_2, // 7-segment LEDs output [6:0] s7_3, // 7-segment LEDs input [3:0] key_n, // Pushbutton switches input [9:0] sw, // Slide switches output fl_rst_n, // Flash ROM RST# output fl_ce_n, // Flash ROM CE# output fl_oe_n, // Flash ROM OE# output fl_we_n, // Flash ROM WE# output [21:0] fl_a, // Flash ROM address bus inout [7:0] fl_dq, // Flash ROM data bus output [1:0] dram_ba, // SDRAM bank selects output dram_ras_n, // SDRAM RAS# output dram_cas_n, // SDRAM CAS# output dram_cke, // SDRAM clock enable output dram_clk, // SDRAM clock output dram_cs_n, // SDRAM CS# output dram_we_n, // SDRAM WE# output [1:0] dram_dqm, // SDRAM DQM (per byte) output [11:0] dram_a, // SDRAM address bus inout [15:0] dram_dq, // SDRAM data bus output sram_ce_n, // SRAM CE# output sram_oe_n, // SRAM OE# output sram_we_n, // SRAM WE# output [1:0] sram_be_n, // SRAM UB#, LB# output [17:0] sram_a, // SRAM address bus inout [15:0] sram_dq, // SRAM data bus output sd_clk, // SD card clock inout sd_cmd, // SD card DI/MOSI/CMD inout sd_dat0, // SD card SO/MISO/DAT0 inout sd_dat3, // SD card CS#/CD/DAT3 output uart_txd, // RS232 port TxD input uart_rxd, // RS232 port RxD output [3:0] vga_r, // VGA red output [3:0] vga_g, // VGA green output [3:0] vga_b, // VGA blue output vga_hs, // VGA horz sync output vga_vs, // VGA vert sync output aud_xck, // Audio master clock output aud_bclk, // Audio bitclock output aud_dacdat, // Audio DAC data output aud_daclrck, // Audio DAC framing input aud_adcdat, // Audio ADC data output aud_adclrck, // Audio ADC framing inout i2c_scl, // I2C SCK line inout i2c_sda, // I2C SDA line inout [35:0] gpio_0, // GPIO headers inout [35:0] gpio_1 // GPIO headers ); wire fl_reset_n; reg tdo; wire [3:0] ir_in; wire tck, tdi, v_sdr, v_cdr, v_uir, v_udr; reg [71:0] jtag_wr_data; reg [71:0] jtag_rd_data; reg jtag_rd_valid; reg [ 6:0] jtag_data_ctr; wire [71:0] jtag_rd_q; wire [ 7:0] jtag_wr_used; reg [ 7:0] jtag_wr_free; wire jtag_rd_empty; reg jtag_bypass; reg jtag_reset = 1'b0; assign ledg[3:0] = ir_in; assign ledg[7:4] = { v_udr, v_sdr, v_cdr, v_uir }; reg jtag_wr_wrq = 1'b0; // FIFO write strobe reg jtag_rd_rrq = 1'b0; // FIFO read strobe parameter cmd_read_fifo = 4'b0001; parameter cmd_free_space = 4'b0010; parameter cmd_write_fifo = 4'b0011; parameter cmd_check_ready = 4'b0100; parameter cmd_reset = 4'b0101; // Shift registers and TDI input always @(posedge tck) begin jtag_wr_wrq <= 1'b0; jtag_rd_rrq <= 1'b0; jtag_reset <= 1'b0; if (v_udr) begin case (ir_in) cmd_write_fifo: jtag_wr_wrq <= 1'b1; endcase // case(ir_in) end // if (v_udr) else if (v_cdr) begin case (ir_in) cmd_read_fifo: begin jtag_rd_data <= { ~jtag_rd_empty, jtag_rd_q[70:0] }; jtag_rd_valid <= ~jtag_rd_empty; jtag_data_ctr <= 7'd71; end cmd_free_space: begin jtag_wr_free <= ~jtag_wr_used; end endcase // case(ir_in) end else if (v_sdr) begin jtag_bypass <= tdi; case (ir_in) cmd_read_fifo: begin if ( jtag_data_ctr == 7'd2 ) begin jtag_rd_rrq <= jtag_rd_valid; jtag_rd_valid <= 1'b0; end if ( ~|jtag_data_ctr ) begin jtag_rd_data <= { ~jtag_rd_empty, jtag_rd_q[70:0] }; jtag_rd_valid <= ~jtag_rd_empty; jtag_data_ctr <= 7'd71; end else begin jtag_rd_data <= { tdi, jtag_rd_data[71:1] }; jtag_data_ctr <= jtag_data_ctr - 1'b1; end end // case: cmd_read_fifo cmd_free_space: jtag_wr_free <= { tdi, jtag_wr_free[ 7:1] }; cmd_write_fifo: jtag_wr_data <= { tdi, jtag_wr_data[71:1] }; cmd_reset: jtag_reset <= tdi; endcase // case(ir_in) end // if (v_sdr) end reg [2:0] jtag_ready = 3'b000; always @(posedge tck) jtag_ready <= { jtag_ready[1:0], fl_reset_n }; // TDO output MUX always @ (*) begin case (ir_in) cmd_read_fifo: tdo <= jtag_rd_data[0]; cmd_free_space: tdo <= jtag_wr_free[0]; cmd_write_fifo: tdo <= jtag_wr_data[0]; cmd_reset: tdo <= 1'b0; // Always read as zero cmd_check_ready: tdo <= jtag_ready[2]; default: tdo <= jtag_bypass; endcase // case(ir_in) end // always @ (*) vjtag_mega vjtag_mega_1 ( .ir_out ( ), .tdo ( tdo ), .ir_in ( ir_in ), .tck ( tck ), .tdi ( tdi ), .virtual_state_cdr ( v_cdr ), .virtual_state_cir ( ), .virtual_state_e1dr ( v_udr ), .virtual_state_e2dr ( ), .virtual_state_pdr ( ), .virtual_state_sdr ( v_sdr ), .virtual_state_udr ( ), .virtual_state_uir ( v_uir ) ); // ------------------------------------------------------------------ // Flash clock PLL and reset logic // ------------------------------------------------------------------ wire pll_locked; wire fl_clk; pll pll ( .areset ( jtag_reset ), .inclk0 ( clock_50 ), .c0 ( fl_clk ), // 20 MHz .locked ( pll_locked ) ); assign fl_reset_n = pll_locked; // ------------------------------------------------------------------ // Write FIFO (JTAG -> programmer) // ------------------------------------------------------------------ wire [71: 0] prog_wr_q; wire prog_wr_rrq; wire prog_wr_empty; fl_fifo fl_wr_fifo ( .aclr ( ~fl_reset_n ), .wrclk ( tck ), .data ( jtag_wr_data ), .wrreq ( jtag_wr_wrq ), .wrusedw ( jtag_wr_used ), .wrfull ( ), .rdclk ( fl_clk ), .q ( prog_wr_q ), .rdreq ( prog_wr_rrq ), .rdempty ( prog_wr_empty ) ); // ------------------------------------------------------------------ // Read FIFO (programmer -> JTAG) // ------------------------------------------------------------------ wire [71:0] prog_rd_data; wire prog_rd_wrq; wire prog_rd_full; fl_fifo fl_rd_fifo ( .aclr ( ~fl_reset_n ), .wrclk ( fl_clk ), .data ( prog_rd_data ), .wrreq ( prog_rd_wrq ), .wrusedw ( ), .wrfull ( prog_rd_full ), .rdclk ( tck ), .q ( jtag_rd_q ), .rdreq ( jtag_rd_rrq ), .rdempty ( jtag_rd_empty ) ); // ------------------------------------------------------------------ // Flash state machine // This is clocked at 20 MHz (50 ns); one clock cycle for each // rising or falling edge // ------------------------------------------------------------------ reg [63:0] fl_data; // Data shift register reg [31:0] fl_bytectr; // Byte counter reg [ 2:0] fl_rbctr; // Read bytes in shift register reg [ 3:0] fl_rbcmd; // Command code reg [31:0] fl_addr; reg fl_ce_q; reg fl_oe_q; reg fl_we_q; reg [31:0] fl_a_q; reg [ 7:0] fl_d_q; reg fl_d_en; assign fl_rst_n = fl_reset_n; assign fl_ce_n = ~fl_ce_q; assign fl_oe_n = ~fl_oe_q; assign fl_we_n = ~fl_we_q; assign fl_a = fl_a_q[21:0]; assign fl_dq = fl_d_en ? fl_d_q : 8'hzz; reg [4:0] prog_state; parameter pst_idle = 5'h00; parameter pst_delay = 5'h01; parameter pst_status = 5'h02; parameter pst_read0 = 5'h04; parameter pst_read1 = 5'h05; parameter pst_read2 = 5'h06; parameter pst_readpad = 5'h07; parameter pst_write0 = 5'h08; parameter pst_write1 = 5'h09; parameter pst_zchk0 = 5'h0A; parameter pst_zchk1 = 5'h0B; parameter pst_zchk2 = 5'h0C; parameter pst_crc0 = 5'h0D; parameter pst_crc1 = 5'h0E; parameter pst_crc2 = 5'h0F; parameter pst_program0 = 5'h10; parameter pst_program1 = 5'h11; parameter pst_program2 = 5'h12; parameter pst_program3 = 5'h13; parameter pst_program4 = 5'h14; parameter pst_program5 = 5'h15; parameter pst_program6 = 5'h16; parameter pst_program7 = 5'h17; parameter pst_program8 = 5'h18; parameter pst_program9 = 5'h19; parameter pst_program10 = 5'h1A; parameter pst_program11 = 5'h1B; parameter pst_program12 = 5'h1C; parameter pst_program13 = 5'h1D; parameter pst_program14 = 5'h1E; reg rd_ack; reg [7:0] pgm_data; reg [7:0] tst_data; // Debugging... registering these is "free" since there are // registers in the I/O buffers, and deconstrains the design reg [9:0] ledr_q; assign ledr = ledr_q; always @(posedge fl_clk or negedge fl_reset_n) if (~fl_reset_n) begin ledr_q <= ~10'b0; end else begin ledr_q[0] <= prog_rd_full; ledr_q[1] <= fl_ce_q; ledr_q[2] <= fl_oe_q; ledr_q[3] <= fl_we_q; ledr_q[4] <= fl_d_en; ledr_q[9:5] <= prog_state; end reg [6:0] s7_0_q; reg [6:0] s7_1_q; reg [6:0] s7_2_q; reg [6:0] s7_3_q; wire [6:0] s7_0_w; wire [6:0] s7_1_w; wire [6:0] s7_2_w; wire [6:0] s7_3_w; assign s7_0 = s7_0_q; assign s7_1 = s7_1_q; assign s7_2 = s7_2_q; assign s7_3 = s7_3_q; hexled hexled0 ( .value (fl_addr[11: 8]), .s7 (s7_0_w) ); hexled hexled1 ( .value (fl_addr[15:12]), .s7 (s7_1_w) ); hexled hexled2 ( .value (fl_addr[19:16]), .s7 (s7_2_w) ); hexled hexled3 ( .value (fl_addr[23:20]), .s7 (s7_3_w) ); reg [2:0] rd_cnt; always @(posedge fl_clk or negedge fl_reset_n) if (~fl_reset_n) begin s7_0_q <= ~7'b1000000; s7_1_q <= ~7'b1000000; s7_2_q <= ~7'b1000000; s7_3_q <= ~7'b1000000; end else begin s7_0_q <= s7_0_w; s7_1_q <= s7_1_w; s7_2_q <= s7_2_w; s7_3_q <= s7_3_w; end assign prog_wr_rrq = ~prog_wr_empty & (prog_state == pst_idle); assign prog_rd_wrq = rd_ack; assign prog_rd_data = { 1'b1, rd_cnt, fl_rbcmd, fl_data }; always @(negedge fl_reset_n or posedge fl_clk) if (~fl_reset_n) rd_cnt <= 3'b000; else rd_cnt <= rd_cnt + rd_ack; wire bump_addr = (prog_state == pst_read2) | (prog_state == pst_zchk2) | (prog_state == pst_crc2) | (prog_state == pst_write1) | ((prog_state == pst_program3) & ~|(tst_data & ~fl_data[7:0])) | ((prog_state == pst_program14) & (tst_data == pgm_data)); wire [31:0] tst_crc; crc_32_d8 crcgen ( .data ( tst_data ), .in ( fl_data[31:0] ), .out ( tst_crc ) ); reg bump_crc; always @(negedge fl_reset_n or posedge fl_clk) if (~fl_reset_n) begin fl_ce_q <= 1'b0; fl_oe_q <= 1'b0; fl_we_q <= 1'b0; fl_addr <= 32'h0; fl_a_q <= 32'h0; fl_d_q <= 8'h0; fl_d_en <= 1'b0; fl_data <= 64'bx; fl_bytectr <= 32'h0; fl_rbctr <= 3'h0; fl_rbcmd <= 4'bx; prog_state <= pst_idle; rd_ack <= 1'b0; bump_crc <= 1'b0; pgm_data <= 8'hxx; tst_data <= 8'hff; end else begin fl_ce_q <= 1'b0; fl_oe_q <= 1'b0; fl_we_q <= 1'b0; fl_d_en <= 1'b0; rd_ack <= 1'b0; bump_crc <= 1'b0; fl_addr <= fl_addr + bump_addr; case ( prog_state ) pst_idle: begin fl_rbctr <= 3'h0; fl_rbcmd <= prog_wr_q[71:68]; tst_data <= 8'hff; if ( ~prog_wr_empty ) casez ( prog_wr_q[71:68] ) 4'b0010: // Delay command begin fl_bytectr <= prog_wr_q[31:0]; prog_state <= pst_delay; end 4'b0101: // Zero check begin fl_addr <= prog_wr_q[63:32]; fl_bytectr <= prog_wr_q[31:0]; prog_state <= pst_zchk0; end 4'b0110: // Read back address, token begin fl_data <= { fl_addr, prog_wr_q[31:0] }; prog_state <= pst_status; end 4'b0111: // CRC32 begin fl_addr <= prog_wr_q[63:32]; fl_bytectr <= prog_wr_q[31:0]; fl_data[63:32] <= 32'hxxxxxxxx; fl_data[31: 0] <= 32'h00000000; prog_state <= pst_crc0; end 4'b100z: // Write bytes command begin fl_data <= prog_wr_q[63:0]; if ( prog_wr_q[68] ) fl_addr <= prog_wr_q[63:32]; prog_state <= pst_write0; end 4'b1011: // Program bytes command begin fl_bytectr <= { 28'b0, prog_wr_q[67:64] }; fl_data <= prog_wr_q[63:0]; prog_state <= pst_program0; end 4'b1101: // Set address register/read command begin fl_addr <= prog_wr_q[63:32]; fl_bytectr <= prog_wr_q[31:0]; prog_state <= pst_read0; end endcase // case( prog_wr_q[71:69] ) end // case: pst_idle pst_delay: begin if ( |fl_bytectr ) fl_bytectr <= fl_bytectr - 1'b1; else prog_state <= pst_idle; end pst_status: begin if ( ~prog_rd_full ) begin rd_ack <= 1'b1; prog_state <= pst_idle; end end pst_read0: // Read initial state begin fl_a_q <= fl_addr; if ( |fl_bytectr ) begin if ( ~prog_rd_full ) begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; prog_state <= pst_read1; end end else if ( |fl_rbctr ) begin if ( ~prog_rd_full ) prog_state <= pst_readpad; end else prog_state <= pst_idle; end // case: pst_read0 pst_read1: // Read output waveform #1 begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; prog_state <= pst_read2; end pst_read2: begin fl_ce_q <= 1'b1; fl_data <= { fl_dq, fl_data[63:8] }; rd_ack <= &fl_rbctr; fl_bytectr <= fl_bytectr - 1'b1; fl_rbctr <= fl_rbctr + 1'b1; prog_state <= pst_read0; end pst_readpad: begin fl_data <= { 8'hFF, fl_data[63:8] }; rd_ack <= &fl_rbctr; fl_rbctr <= fl_rbctr + 1'b1; prog_state <= pst_read0; end pst_zchk0: // Zero check begin fl_a_q <= fl_addr; if ( (&tst_data) & (|fl_bytectr) ) begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; fl_data[63:32] <= 32'hxxxxxxxx; fl_data[31: 0] <= 32'hxxxxxxxx; prog_state <= pst_zchk1; end else if ( ~prog_rd_full ) begin fl_data[63:32] <= fl_addr; fl_data[31: 8] <= 24'hffffff; fl_data[ 7: 0] <= tst_data; rd_ack <= 1'b1; prog_state <= pst_idle; end // else: !if( |fl_bytectr ) end // case: pst_zchk0 pst_zchk1: begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; prog_state <= pst_zchk2; end pst_zchk2: begin fl_ce_q <= 1'b1; tst_data <= fl_dq; fl_bytectr <= fl_bytectr - 1'b1; prog_state <= pst_zchk0; end pst_crc0: // CRC32 begin fl_a_q <= fl_addr; if ( bump_crc ) fl_data[31: 0] <= tst_crc; if ( |fl_bytectr ) begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; fl_data[63:32] <= 32'hxxxxxxxx; prog_state <= pst_crc1; end else if ( ~prog_rd_full ) begin fl_data[63:32] <= fl_addr; rd_ack <= 1'b1; prog_state <= pst_idle; end // else: !if( |fl_bytectr ) end // case: pst_crc0 pst_crc1: begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; prog_state <= pst_crc2; end pst_crc2: begin fl_ce_q <= 1'b1; tst_data <= fl_dq; fl_bytectr <= fl_bytectr - 1'b1; bump_crc <= 1'b1; prog_state <= pst_crc0; end pst_write0: begin fl_ce_q <= 1'b1; fl_we_q <= 1'b1; fl_d_en <= 1'b1; fl_d_q <= fl_data[7:0]; fl_a_q <= fl_data[63:32]; prog_state <= pst_write1; end pst_write1: begin fl_ce_q <= 1'b1; fl_d_en <= 1'b1; prog_state <= pst_idle; end // Programming algorithm: read individual bytes to avoid // hanging the flash chip due to zero bits pst_program0: begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; fl_a_q <= fl_addr; prog_state <= pst_program1; end pst_program1: begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; prog_state <= pst_program2; end pst_program2: begin fl_ce_q <= 1'b1; tst_data <= fl_dq; prog_state <= pst_program3; fl_bytectr <= fl_bytectr - 1'b1; end pst_program3: begin fl_ce_q <= 1'b1; pgm_data <= tst_data & fl_data[7:0]; fl_data <= { 8'hFF, fl_data[63:8] }; if ( |(tst_data & ~fl_data[7:0]) ) begin fl_we_q <= 1'b1; fl_d_en <= 1'b1; fl_d_q <= 8'hAA; fl_a_q <= 32'hAAAA_AAAA; prog_state <= pst_program4; end else begin if ( |fl_bytectr ) prog_state <= pst_program0; else prog_state <= pst_idle; end end // case: pst_program3 pst_program4: begin fl_ce_q <= 1'b1; fl_d_en <= 1'b1; prog_state <= pst_program5; end pst_program5: begin fl_ce_q <= 1'b1; fl_we_q <= 1'b1; fl_d_en <= 1'b1; fl_d_q <= 8'h55; fl_a_q <= 32'h5555_5555; prog_state <= pst_program6; end pst_program6: begin fl_ce_q <= 1'b1; fl_d_en <= 1'b1; prog_state <= pst_program7; end pst_program7: begin fl_ce_q <= 1'b1; fl_we_q <= 1'b1; fl_d_en <= 1'b1; fl_d_q <= 8'hA0; fl_a_q <= 32'hAAAA_AAAA; prog_state <= pst_program8; end pst_program8: begin fl_ce_q <= 1'b1; fl_d_en <= 1'b1; prog_state <= pst_program9; end pst_program9: begin fl_ce_q <= 1'b1; fl_we_q <= 1'b1; fl_d_en <= 1'b1; fl_d_q <= pgm_data; fl_a_q <= fl_addr; prog_state <= pst_program10; end pst_program10: begin fl_ce_q <= 1'b1; fl_d_en <= 1'b1; prog_state <= pst_program11; end pst_program11: begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; prog_state <= pst_program12; end pst_program12: begin fl_ce_q <= 1'b1; fl_oe_q <= 1'b1; prog_state <= pst_program13; end pst_program13: begin fl_ce_q <= 1'b1; tst_data <= fl_dq; prog_state <= pst_program14; end pst_program14: begin fl_ce_q <= 1'b1; if ( tst_data != pgm_data ) prog_state <= pst_program11; else if ( |fl_bytectr ) prog_state <= pst_program0; else prog_state <= pst_idle; end endcase // case( prog_state ) end // ------------------------------------------------------------------ // Unused hardware ports // ------------------------------------------------------------------ // PS/2 port assign ps2_clk = 1'bz; assign ps2_dat = 1'bz; // SDRAM assign dram_ba = 2'b11; assign dram_ras_n = 1'b1; assign dram_cas_n = 1'b1; assign dram_cke = 1'b1; assign dram_clk = 1'b1; assign dram_cs_n = 1'b1; assign dram_we_n = 1'b1; assign dram_dqm = 2'b11; assign dram_a = ~12'b0; assign dram_dq = 16'hzzzz; // SRAM assign sram_ce_n = 1'b1; assign sram_oe_n = 1'b1; assign sram_we_n = 1'b1; assign sram_be_n = 2'b11; assign sram_a = ~18'b0; assign sram_dq = 16'hzzzz; // SD card assign sd_clk = 1'b1; assign sd_cmd = 1'bz; assign sd_dat0 = 1'bz; assign sd_dat3 = 1'bz; // RS232 assign uart_txd = 1'b1; // Video assign vga_r = 4'b0; assign vga_g = 4'b0; assign vga_b = 4'b0; assign vga_hs = 1'b0; assign vga_vs = 1'b0; // Audio I2S assign aud_xck = 1'b1; assign aud_bclk = 1'b1; assign aud_dacdat = 1'b1; assign aud_daclrck = 1'b1; assign aud_adclrck = 1'b1; // Audio I2C assign i2c_scl = 1'bz; assign i2c_sda = 1'bz; // GPIO assign gpio_0 = 36'hz_zzzz_zzzz; assign gpio_1 = 36'hz_zzzz_zzzz; endmodule // de1flash