From 90fcdf6615613fd3c4ef71e33092a74566dedc77 Mon Sep 17 00:00:00 2001 From: ikari Date: Fri, 31 Dec 2010 02:49:04 +0100 Subject: [PATCH] feature reduced FPGA config for uC flash embedding --- verilog/sd2sneslite/address.v | 110 ++++++ verilog/sd2sneslite/avr_cmd.v | 163 +++++++++ verilog/sd2sneslite/clk_test.v | 52 +++ verilog/sd2sneslite/dac_dcm.v | 106 ++++++ verilog/sd2sneslite/dac_test.v | 168 +++++++++ verilog/sd2sneslite/data.v | 78 ++++ verilog/sd2sneslite/dcm.v | 72 ++++ verilog/sd2sneslite/main.ucf | 515 ++++++++++++++++++++++++++ verilog/sd2sneslite/main.v | 519 +++++++++++++++++++++++++++ verilog/sd2sneslite/msu.v | 182 ++++++++++ verilog/sd2sneslite/sd2sneslite.xise | 358 ++++++++++++++++++ verilog/sd2sneslite/sd_dma.v | 132 +++++++ verilog/sd2sneslite/spi.v | 141 ++++++++ 13 files changed, 2596 insertions(+) create mode 100644 verilog/sd2sneslite/address.v create mode 100644 verilog/sd2sneslite/avr_cmd.v create mode 100644 verilog/sd2sneslite/clk_test.v create mode 100644 verilog/sd2sneslite/dac_dcm.v create mode 100644 verilog/sd2sneslite/dac_test.v create mode 100644 verilog/sd2sneslite/data.v create mode 100644 verilog/sd2sneslite/dcm.v create mode 100644 verilog/sd2sneslite/main.ucf create mode 100644 verilog/sd2sneslite/main.v create mode 100644 verilog/sd2sneslite/msu.v create mode 100644 verilog/sd2sneslite/sd2sneslite.xise create mode 100644 verilog/sd2sneslite/sd_dma.v create mode 100644 verilog/sd2sneslite/spi.v diff --git a/verilog/sd2sneslite/address.v b/verilog/sd2sneslite/address.v new file mode 100644 index 0000000..98ced2a --- /dev/null +++ b/verilog/sd2sneslite/address.v @@ -0,0 +1,110 @@ +`timescale 1 ns / 1 ns +////////////////////////////////////////////////////////////////////////////////// +// Company: Rehkopf +// Engineer: Rehkopf +// +// Create Date: 01:13:46 05/09/2009 +// Design Name: +// Module Name: address +// Project Name: +// Target Devices: +// Tool versions: +// Description: Address logic w/ SaveRAM masking +// +// Dependencies: +// +// Revision: +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module address( + input CLK, + input [2:0] MAPPER, // MCU detected mapper + input [23:0] SNES_ADDR, // requested address from SNES + input SNES_CS, // "CART" pin from SNES (active low) + output [22:0] ROM_ADDR, // Address to request from SRAM0 + output ROM_SEL, // enable SRAM0 (active low) + input MCU_OVR, // enable MCU master mode (active low) + input MODE, // MCU(1) or SNES(0) ("bus phase") + output IS_SAVERAM, // address/CS mapped as SRAM? + output IS_ROM, // address mapped as ROM? + input [23:0] MCU_ADDR, // allow address to be set externally + input ADDR_WRITE, + output ROM_ADDR0, + input [23:0] SAVERAM_MASK, + input [23:0] ROM_MASK, + input use_msu, + output msu_enable + ); + +wire [1:0] SRAM_BANK; + +wire [23:0] SRAM_ADDR_FULL; + +/* currently supported mappers: + Index Mapper + 000 HiROM + 001 LoROM + 010 ExHiROM (48-64Mbit) + 110 brainfuck interleaved 96MBit Star Ocean =) + 111 menu (ROM in upper SRAM) +*/ + +/* HiROM: SRAM @ Bank 0x30-0x3f, 0xb0-0xbf + Offset 6000-7fff */ + +assign IS_ROM = ( (MAPPER == 3'b000) ? ((!SNES_ADDR[22] & SNES_ADDR[15]) + |(SNES_ADDR[22])) + : (MAPPER == 3'b001) ? ((!SNES_ADDR[22] & SNES_ADDR[15]) + |(SNES_ADDR[22])) + : (MAPPER == 3'b010) ? ((!SNES_ADDR[22] & SNES_ADDR[15]) + |(SNES_ADDR[22])) + : (MAPPER == 3'b110) ? ((!SNES_ADDR[22] & SNES_ADDR[15]) + |(SNES_ADDR[22])) + : (MAPPER == 3'b111) ? ((!SNES_ADDR[22] & SNES_ADDR[15]) + |(SNES_ADDR[22])) + : 1'b0); + +assign IS_SAVERAM = ((MAPPER == 3'b000 || MAPPER == 3'b010 || MAPPER == 3'b110 || MAPPER == 3'b111) ? (!SNES_ADDR[22] + & SNES_ADDR[21:20] + & &SNES_ADDR[14:13] + & !SNES_ADDR[15] + & SNES_CS + ) +/* LoROM: SRAM @ Bank 0x70-0x7d, 0xf0-0xfd + Offset 0000-7fff TODO: 0000-ffff for + small ROMs */ + :(MAPPER == 3'b001) ? (&SNES_ADDR[22:20] + & (SNES_ADDR[19:16] < 4'b1110) + & !SNES_ADDR[15] + & !SNES_CS) + : 1'b0); + +assign SRAM_ADDR_FULL = (MODE) ? MCU_ADDR + : ((MAPPER == 3'b000) ? + (IS_SAVERAM ? 24'hE00000 + ((SNES_ADDR[14:0] - 15'h6000) & SAVERAM_MASK) + : ({1'b0, SNES_ADDR[22:0]} & ROM_MASK)) + :(MAPPER == 3'b001) ? + (IS_SAVERAM ? 24'hE00000 + (SNES_ADDR[14:0] & SAVERAM_MASK) + : ({2'b00, SNES_ADDR[22:16], SNES_ADDR[14:0]} & ROM_MASK)) + :(MAPPER == 3'b010) ? + (IS_SAVERAM ? 24'hE00000 + ((SNES_ADDR[14:0] - 15'h6000) & SAVERAM_MASK) + : ({1'b0, !SNES_ADDR[23], SNES_ADDR[21:0]} & ROM_MASK)) + :(MAPPER == 3'b110) ? + (IS_SAVERAM ? 24'hE00000 + ((SNES_ADDR[14:0] - 15'h6000) & SAVERAM_MASK) + : (SNES_ADDR[15] ? ({1'b0, SNES_ADDR[23:16], SNES_ADDR[14:0]}) + : ({2'b10, SNES_ADDR[23], SNES_ADDR[21:16], SNES_ADDR[14:0]}))) + :(MAPPER == 3'b111) ? + (IS_SAVERAM ? 24'hFF0000 + ((SNES_ADDR[14:0] - 15'h6000) & SAVERAM_MASK) + : (({1'b0, SNES_ADDR[22:0]} & ROM_MASK) + 24'hE00000)) + : 24'b0); + +assign ROM_ADDR = SRAM_ADDR_FULL[23:1]; + +assign ROM_SEL = 1'b0; // (MODE) ? CS_ARRAY[SRAM_BANK] : IS_SAVERAM ? 4'b1000 : CS_ARRAY[SRAM_BANK]; + +assign ROM_ADDR0 = SRAM_ADDR_FULL[0]; +//488888 +assign msu_enable = (!SNES_ADDR[22] && ((SNES_ADDR[15:0] & 16'hfff8) == 16'h2000)); + +endmodule diff --git a/verilog/sd2sneslite/avr_cmd.v b/verilog/sd2sneslite/avr_cmd.v new file mode 100644 index 0000000..72b46da --- /dev/null +++ b/verilog/sd2sneslite/avr_cmd.v @@ -0,0 +1,163 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 21:57:50 08/25/2009 +// Design Name: +// Module Name: mcu_cmd +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module mcu_cmd( + input clk, + input cmd_ready, + input param_ready, + input [7:0] cmd_data, + input [7:0] param_data, + output [3:0] mcu_mapper, + output [3:0] mcu_sram_size, + output mcu_read, + output mcu_write, + output [7:0] mcu_data_out, + input [7:0] mcu_data_in, + output [7:0] spi_data_out, + input [31:0] spi_byte_cnt, + input [2:0] spi_bit_cnt, + output [23:0] addr_out, + output [3:0] mapper, + input endmessage, + input startmessage, + output [23:0] saveram_mask_out, + output [23:0] rom_mask_out + ); + + +reg [3:0] MAPPER_BUF; +reg [3:0] SRAM_SIZE_BUF; +reg MCU_READ_BUF; +reg MCU_WRITE_BUF; +reg [23:0] ADDR_OUT_BUF; + +reg [7:0] MCU_DATA_OUT_BUF; +reg [7:0] MCU_DATA_IN_BUF; +reg [1:0] mcu_nextaddr_buf; + +wire mcu_nextaddr; + +reg [1:0] SRAM_MASK_IDX; +reg [23:0] SAVERAM_MASK; +reg [23:0] ROM_MASK; + +assign spi_data_out = MCU_DATA_IN_BUF; + +initial begin + ADDR_OUT_BUF = 0; +end + +// command interpretation +always @(posedge clk) begin + if (cmd_ready) begin + case (cmd_data[7:4]) + 4'h3: // select mapper + MAPPER_BUF <= cmd_data[3:0]; + endcase + end else if (param_ready) begin + casex (cmd_data[7:0]) + 8'h0x: + case (spi_byte_cnt) + 32'h2: begin + ADDR_OUT_BUF[23:16] <= param_data; + ADDR_OUT_BUF[15:0] <= 16'b0; + end + 32'h3: + ADDR_OUT_BUF[15:8] <= param_data; + 32'h4: + ADDR_OUT_BUF[7:0] <= param_data; + endcase + 8'h1x: + case (spi_byte_cnt) + 32'h2: + ROM_MASK[23:16] <= param_data; + 32'h3: + ROM_MASK[15:8] <= param_data; + 32'h4: + ROM_MASK[7:0] <= param_data; + endcase + 8'h2x: + case (spi_byte_cnt) + 32'h2: + SAVERAM_MASK[23:16] <= param_data; + 32'h3: + SAVERAM_MASK[15:8] <= param_data; + 32'h4: + SAVERAM_MASK[7:0] <= param_data; + endcase + 8'h9x: + MCU_DATA_OUT_BUF <= param_data; + endcase + end + if (mcu_nextaddr & (cmd_data[7:5] == 3'h4) && (cmd_data[3]) && (spi_byte_cnt > (32'h1+cmd_data[4]))) begin + ADDR_OUT_BUF <= ADDR_OUT_BUF + 1; + end +end + +// value fetch during last SPI bit +always @(posedge clk) begin + if (spi_bit_cnt == 3'h7) + if (cmd_data[7:0] == 8'hF0) + MCU_DATA_IN_BUF <= 8'hA5; + else if (cmd_data[7:0] == 8'hFF) + MCU_DATA_IN_BUF <= param_data; + else if (cmd_data[7:4] == 4'h8) + MCU_DATA_IN_BUF <= mcu_data_in; + else + MCU_DATA_IN_BUF <= cmd_data; +end + +// nextaddr pulse generation +always @(posedge clk) begin + if (spi_bit_cnt == 3'h0) + mcu_nextaddr_buf <= {mcu_nextaddr_buf[0], 1'b1}; + else + mcu_nextaddr_buf <= {mcu_nextaddr_buf[0], 1'b0}; +end + + +// r/w pulse +always @(posedge clk) begin + if ((spi_bit_cnt == 3'h1 || spi_bit_cnt == 3'h2 || spi_bit_cnt == 3'h3) & (cmd_data[7:4] == 4'h9) & (spi_byte_cnt > 32'h1)) + MCU_WRITE_BUF <= 1'b0; + else + MCU_WRITE_BUF <= 1'b1; + +// Read pulse is two spi cycles to ensure that the value +// is ready in the 2nd cycle in MCU master mode + if ((spi_bit_cnt == 3'h5 || spi_bit_cnt == 3'h6 || spi_bit_cnt == 3'h7) & (cmd_data[7:4] == 4'h8) & (spi_byte_cnt > 32'h0)) + MCU_READ_BUF <= 1'b0; + else + MCU_READ_BUF <= 1'b1; +end + +// trigger for nextaddr +assign mcu_nextaddr = mcu_nextaddr_buf == 2'b01; + +assign mcu_read = MCU_READ_BUF; +assign mcu_write = MCU_WRITE_BUF; +assign addr_out = ADDR_OUT_BUF; +assign mcu_data_out = MCU_DATA_OUT_BUF; +assign mcu_mapper = MAPPER_BUF; +assign mcu_sram_size = SRAM_SIZE_BUF; +assign rom_mask_out = ROM_MASK; +assign saveram_mask_out = SAVERAM_MASK; + +endmodule diff --git a/verilog/sd2sneslite/clk_test.v b/verilog/sd2sneslite/clk_test.v new file mode 100644 index 0000000..10b54cf --- /dev/null +++ b/verilog/sd2sneslite/clk_test.v @@ -0,0 +1,52 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 22:40:46 12/20/2010 +// Design Name: +// Module Name: clk_test +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module clk_test( + input clk, + input sysclk, + output [31:0] snes_sysclk_freq + ); + +reg [31:0] snes_sysclk_freq_r; +assign snes_sysclk_freq = snes_sysclk_freq_r; + +reg [31:0] sysclk_counter; +reg [31:0] sysclk_value; + +initial snes_sysclk_freq_r = 32'hFFFFFFFF; +initial sysclk_counter = 0; +initial sysclk_value = 0; + +reg [1:0] sysclk_sreg; +always @(posedge clk) sysclk_sreg <= {sysclk_sreg[0], sysclk}; +wire sysclk_rising = (sysclk_sreg == 2'b01); + +always @(posedge clk) begin + if(sysclk_counter < 90315789) begin + sysclk_counter <= sysclk_counter + 1; + if(sysclk_rising) sysclk_value <= sysclk_value + 1; + end else begin + snes_sysclk_freq_r <= sysclk_value; + sysclk_counter <= 0; + sysclk_value <= 0; + end +end + +endmodule diff --git a/verilog/sd2sneslite/dac_dcm.v b/verilog/sd2sneslite/dac_dcm.v new file mode 100644 index 0000000..3c88ed6 --- /dev/null +++ b/verilog/sd2sneslite/dac_dcm.v @@ -0,0 +1,106 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 11:00:52 12/29/2010 +// Design Name: +// Module Name: dac_dcm +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module dac_dcm( + input CLKIN, + output CLKFX + ); + + // DCM: Digital Clock Manager Circuit + // Spartan-3 + // Xilinx HDL Language Template, version 11.1 + + DCM #( + .SIM_MODE("SAFE"), // Simulation: "SAFE" vs. "FAST", see "Synthesis and Simulation Design Guide" for details + .CLKDV_DIVIDE(2.0), // Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 + // 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 + .CLKFX_DIVIDE(2), // Can be any integer from 1 to 32 + .CLKFX_MULTIPLY(19), // Can be any integer from 2 to 32 + .CLKIN_DIVIDE_BY_2("FALSE"), // TRUE/FALSE to enable CLKIN divide by two feature + .CLKIN_PERIOD(46.560), // Specify period of input clock + .CLKOUT_PHASE_SHIFT("NONE"), // Specify phase shift of NONE, FIXED or VARIABLE + .CLK_FEEDBACK("NONE"), // Specify clock feedback of NONE, 1X or 2X + .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), // SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or + // an integer from 0 to 15 + .DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis + .DLL_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for DLL + .DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE + .FACTORY_JF(16'hFFFF), // FACTORY JF values +// .LOC("DCM_X0Y0"), + .PHASE_SHIFT(0), // Amount of fixed phase shift from -255 to 255 + .STARTUP_WAIT("TRUE") // Delay configuration DONE until DCM LOCK, TRUE/FALSE + ) DCM_inst1 ( + .CLKFX(CLKFX1), // DCM CLK synthesis out (M/D) + .CLKIN(CLKIN), // Clock input (from IBUFG, BUFG or DCM) + .RST(1'b0) // DCM asynchronous reset input + ); + + + DCM #( + .SIM_MODE("SAFE"), // Simulation: "SAFE" vs. "FAST", see "Synthesis and Simulation Design Guide" for details + .CLKDV_DIVIDE(2.0), // Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 + // 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 + .CLKFX_DIVIDE(29), // Can be any integer from 1 to 32 + .CLKFX_MULTIPLY(19), // Can be any integer from 2 to 32 + .CLKIN_DIVIDE_BY_2("FALSE"), // TRUE/FALSE to enable CLKIN divide by two feature + .CLKIN_PERIOD(4.901), // Specify period of input clock + .CLKOUT_PHASE_SHIFT("NONE"), // Specify phase shift of NONE, FIXED or VARIABLE + .CLK_FEEDBACK("NONE"), // Specify clock feedback of NONE, 1X or 2X + .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), // SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or + // an integer from 0 to 15 + .DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis + .DLL_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for DLL + .DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE + .FACTORY_JF(16'hFFFF), // FACTORY JF values +// .LOC("DCM_X0Y0"), + .PHASE_SHIFT(0), // Amount of fixed phase shift from -255 to 255 + .STARTUP_WAIT("TRUE") // Delay configuration DONE until DCM LOCK, TRUE/FALSE + ) DCM_inst2 ( + .CLKFX(CLKFX2), // DCM CLK synthesis out (M/D) + .CLKIN(CLKFX1), // Clock input (from IBUFG, BUFG or DCM) + .RST(1'b0) // DCM asynchronous reset input + ); + + DCM #( + .SIM_MODE("SAFE"), // Simulation: "SAFE" vs. "FAST", see "Synthesis and Simulation Design Guide" for details + .CLKDV_DIVIDE(2.0), // Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 + // 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 + .CLKFX_DIVIDE(31), // Can be any integer from 1 to 32 + .CLKFX_MULTIPLY(21), // Can be any integer from 2 to 32 + .CLKIN_DIVIDE_BY_2("FALSE"), // TRUE/FALSE to enable CLKIN divide by two feature + .CLKIN_PERIOD(7.480), // Specify period of input clock + .CLKOUT_PHASE_SHIFT("NONE"), // Specify phase shift of NONE, FIXED or VARIABLE + .CLK_FEEDBACK("NONE"), // Specify clock feedback of NONE, 1X or 2X + .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), // SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or + // an integer from 0 to 15 + .DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis + .DLL_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for DLL + .DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE + .FACTORY_JF(16'hFFFF), // FACTORY JF values +// .LOC("DCM_X0Y0"), + .PHASE_SHIFT(0), // Amount of fixed phase shift from -255 to 255 + .STARTUP_WAIT("TRUE") // Delay configuration DONE until DCM LOCK, TRUE/FALSE + ) DCM_inst3 ( + .CLKFX(CLKFX), // DCM CLK synthesis out (M/D) + .CLKIN(CLKFX2), // Clock input (from IBUFG, BUFG or DCM) + .RST(1'b0) // DCM asynchronous reset input + ); + +endmodule diff --git a/verilog/sd2sneslite/dac_test.v b/verilog/sd2sneslite/dac_test.v new file mode 100644 index 0000000..982c7a9 --- /dev/null +++ b/verilog/sd2sneslite/dac_test.v @@ -0,0 +1,168 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 19:26:11 07/23/2010 +// Design Name: +// Module Name: dac_test +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module dac_test( + input clkin, + input sysclk, + input we, + input[10:0] pgm_address, + input[7:0] pgm_data, + input[7:0] volume, + input vol_latch, + input play, + input reset, + output sdout, + output lrck, + output mclk, + output DAC_STATUS + ); + +reg[8:0] dac_address_r; +wire[8:0] dac_address = dac_address_r; +reg dac_nextaddr_r; + +wire[31:0] dac_data; +assign DAC_STATUS = dac_address_r[8]; +reg[7:0] vol_reg; +reg[7:0] vol_target_reg; +reg[1:0] vol_latch_reg; +reg vol_valid; +reg[2:0] sysclk_sreg; +wire sysclk_rising = (sysclk_sreg[2:1] == 2'b01); + +reg [25:0] interpol_count; +reg interpol_overflow; + +always @(posedge clkin) begin + sysclk_sreg <= {sysclk_sreg[1:0], sysclk}; +end + +dac_buf snes_dac_buf ( + .clka(clkin), + .wea(~we), // Bus [0 : 0] + .addra(pgm_address), // Bus [10 : 0] + .dina(pgm_data), // Bus [7 : 0] + .clkb(clkin), + .addrb(dac_address), // Bus [9 : 0] + .doutb(dac_data)); // Bus [15 : 0] + +reg [15:0] cnt; +reg [15:0] smpcnt; +reg [15:0] samples; +wire [15:0] sample = {smpcnt[10] ? ~smpcnt[9:0] : smpcnt[9:0], 6'b0}; +wire [15:0] sample2 = {smpcnt[9] ? ~smpcnt[8:0] : smpcnt[8:0], 7'b0}; +reg [15:0] smpshift; +reg [15:0] smpdata; + +assign mclk = cnt[2]; // mclk = clk/8 +assign lrck = cnt[10]; // lrck = mclk/256 +wire sclk = cnt[5]; // sclk = lrck*32 + +reg [2:0] lrck_sreg; +reg [2:0] sclk_sreg; +wire lrck_rising = ({lrck_sreg[2:1]} == 2'b01); +wire lrck_falling = ({lrck_sreg[2:1]} == 2'b10); + +wire sclk_rising = ({sclk_sreg[2:1]} == 2'b01); + +wire vol_latch_rising = (vol_latch_reg[1:0] == 2'b01); +reg sdout_reg; +assign sdout = sdout_reg; + +reg [1:0] reset_sreg; +wire reset_rising = (reset_sreg[1:0] == 2'b01); + +reg play_r; + +initial begin + cnt = 16'hff00; + smpcnt = 16'b0; + lrck_sreg = 2'b11; + sclk_sreg = 1'b0; + dac_address_r = 11'b0; + vol_valid = 1'b0; + vol_latch_reg = 1'b0; + vol_reg = 8'h0; + vol_target_reg = 8'hff; + samples <= 16'h0; +end + +always @(posedge clkin) begin + if(reset_rising) begin + dac_address_r <= 0; + interpol_overflow <= 0; + interpol_count <= 0; + end else if(sysclk_rising) begin + if(interpol_count > 59378938) begin + interpol_count <= interpol_count + 122500 - 59501439; + dac_address_r <= dac_address_r + play_r; + interpol_overflow <= 1; + end else begin + interpol_count <= interpol_count + 122500; + interpol_overflow <= 0; + end + end +end + +always @(posedge clkin) begin + cnt <= cnt + 1; + lrck_sreg <= {lrck_sreg[1:0], lrck}; + sclk_sreg <= {sclk_sreg[1:0], sclk}; + vol_latch_reg <= {vol_latch_reg[0], vol_latch}; + play_r <= play; + reset_sreg <= {reset_sreg[0], reset}; +end + +always @(posedge clkin) begin + if (vol_latch_rising) begin + vol_valid <= 1'b1; + end + else if(vol_valid) begin + vol_target_reg <= volume; + vol_valid <= 1'b0; + end +end + +// ramp volume only every 4 samples +always @(posedge clkin) begin + if (lrck_rising && &samples[1:0]) begin + if(vol_reg > vol_target_reg) + vol_reg <= vol_reg - 1; + else if(vol_reg < vol_target_reg) + vol_reg <= vol_reg + 1; + end +end + +always @(posedge clkin) begin + if (lrck_rising) begin // right channel + smpshift <= (({16'h0, dac_data[31:16]^16'h8000} * vol_reg) >> 8) ^ 16'h8000; + samples <= samples + 1; + end else if (lrck_falling) begin // left channel + smpshift <= (({16'h0, dac_data[15:0]^16'h8000} * vol_reg) >> 8) ^ 16'h8000; + end else begin + if (sclk_rising) begin + smpcnt <= smpcnt + 1; + sdout_reg <= smpshift[15]; + smpshift <= {smpshift[14:0], 1'b0}; + end + end +end + +endmodule diff --git a/verilog/sd2sneslite/data.v b/verilog/sd2sneslite/data.v new file mode 100644 index 0000000..1a18cb2 --- /dev/null +++ b/verilog/sd2sneslite/data.v @@ -0,0 +1,78 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 23:03:06 05/13/2009 +// Design Name: +// Module Name: data +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module data( + input CLK, + input SNES_READ, + input SNES_WRITE, + input MCU_READ, + input MCU_WRITE, + inout [7:0] SNES_DATA, + inout [15:0] ROM_DATA, + input [7:0] MCU_IN_DATA, + output [7:0] MCU_OUT_DATA, + input MODE, + input SNES_DATA_TO_MEM, + input MCU_DATA_TO_MEM, + input ROM_DATA_TO_SNES_MEM, + input ROM_DATA_TO_MCU_MEM, + input MCU_OVR, + input ROM_ADDR0, + output [7:0] MSU_DATA_IN, + input [7:0] MSU_DATA_OUT, + input msu_enable + ); + +reg [7:0] SNES_IN_MEM; +reg [7:0] SNES_OUT_MEM; +reg [7:0] MCU_IN_MEM; +reg [7:0] MCU_OUT_MEM; + +wire [7:0] FROM_ROM_BYTE; + +assign MSU_DATA_IN = SNES_DATA; + +assign SNES_DATA = SNES_READ ? 8'bZ : (!MCU_OVR ? 8'h00 : (msu_enable ? MSU_DATA_OUT : SNES_OUT_MEM)); + +assign FROM_ROM_BYTE = (ROM_ADDR0 ? ROM_DATA[7:0] : ROM_DATA[15:8]); + +assign MCU_OUT_DATA = !MCU_OVR ? (FROM_ROM_BYTE) + : (MCU_OUT_MEM); + +assign ROM_DATA[7:0] = ROM_ADDR0 ? (!MCU_OVR ? (!MCU_WRITE ? MCU_IN_DATA : 8'bZ) + : (MODE ? (!MCU_WRITE ? MCU_IN_MEM : 8'bZ) + : (!SNES_WRITE ? SNES_IN_MEM : 8'bZ))) + : 8'bZ; +assign ROM_DATA[15:8] = ROM_ADDR0 ? 8'bZ : (!MCU_OVR ? (!MCU_WRITE ? MCU_IN_DATA : 8'bZ) + : (MODE ? (!MCU_WRITE ? MCU_IN_MEM : 8'bZ) + : (!SNES_WRITE ? SNES_IN_MEM : 8'bZ))); + +always @(posedge CLK) begin + if(SNES_DATA_TO_MEM) + SNES_IN_MEM <= SNES_DATA; + if(MCU_DATA_TO_MEM) + MCU_IN_MEM <= MCU_IN_DATA; + if(ROM_DATA_TO_SNES_MEM) + SNES_OUT_MEM <= FROM_ROM_BYTE; + if(ROM_DATA_TO_MCU_MEM) + MCU_OUT_MEM <= FROM_ROM_BYTE; +end + +endmodule diff --git a/verilog/sd2sneslite/dcm.v b/verilog/sd2sneslite/dcm.v new file mode 100644 index 0000000..6399370 --- /dev/null +++ b/verilog/sd2sneslite/dcm.v @@ -0,0 +1,72 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 13:06:52 06/28/2009 +// Design Name: +// Module Name: dcm +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module my_dcm ( + input CLKIN, + output CLKFX, + output LOCKED, + input RST, + output[7:0] STATUS + ); + + // DCM: Digital Clock Manager Circuit + // Spartan-3 + // Xilinx HDL Language Template, version 11.1 + + DCM #( + .SIM_MODE("SAFE"), // Simulation: "SAFE" vs. "FAST", see "Synthesis and Simulation Design Guide" for details + .CLKDV_DIVIDE(2.0), // Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 + // 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 + .CLKFX_DIVIDE(1), // Can be any integer from 1 to 32 + .CLKFX_MULTIPLY(4), // Can be any integer from 2 to 32 + .CLKIN_DIVIDE_BY_2("FALSE"), // TRUE/FALSE to enable CLKIN divide by two feature + .CLKIN_PERIOD(44.289), // Specify period of input clock + .CLKOUT_PHASE_SHIFT("NONE"), // Specify phase shift of NONE, FIXED or VARIABLE + .CLK_FEEDBACK("NONE"), // Specify clock feedback of NONE, 1X or 2X + .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), // SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or + // an integer from 0 to 15 + .DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis + .DLL_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for DLL + .DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE + .FACTORY_JF(16'hFFFF), // FACTORY JF values +// .LOC("DCM_X0Y0"), + .PHASE_SHIFT(0), // Amount of fixed phase shift from -255 to 255 + .STARTUP_WAIT("TRUE") // Delay configuration DONE until DCM LOCK, TRUE/FALSE + ) DCM_inst ( + .CLK0(CLK0), // 0 degree DCM CLK output + .CLK180(CLK180), // 180 degree DCM CLK output + .CLK270(CLK270), // 270 degree DCM CLK output + .CLK2X(CLK2X), // 2X DCM CLK output + .CLK2X180(CLK2X180), // 2X, 180 degree DCM CLK out + .CLK90(CLK90), // 90 degree DCM CLK output + .CLKDV(CLKDV), // Divided DCM CLK out (CLKDV_DIVIDE) + .CLKFX(CLKFX), // DCM CLK synthesis out (M/D) + .CLKFX180(CLKFX180), // 180 degree CLK synthesis out + .LOCKED(LOCKED), // DCM LOCK status output + .PSDONE(PSDONE), // Dynamic phase adjust done output + .STATUS(STATUS), // 8-bit DCM status bits output + .CLKFB(CLKFB), // DCM clock feedback + .CLKIN(CLKIN), // Clock input (from IBUFG, BUFG or DCM) + .PSCLK(PSCLK), // Dynamic phase adjust clock input + .PSEN(PSEN), // Dynamic phase adjust enable input + .PSINCDEC(PSINCDEC), // Dynamic phase adjust increment/decrement + .RST(RST) // DCM asynchronous reset input + ); +endmodule diff --git a/verilog/sd2sneslite/main.ucf b/verilog/sd2sneslite/main.ucf new file mode 100644 index 0000000..0afd06b --- /dev/null +++ b/verilog/sd2sneslite/main.ucf @@ -0,0 +1,515 @@ +NET "CLKIN" TNM_NET = "CLKIN"; +TIMESPEC TS_CLKIN = PERIOD "CLKIN" 22.579 MHz HIGH 50 %; +NET "SNES_CS" IOSTANDARD = LVCMOS33; +NET "SNES_READ" IOSTANDARD = LVCMOS33; +NET "SNES_WRITE" IOSTANDARD = LVCMOS33; +NET "SNES_CPU_CLK" IOSTANDARD = LVCMOS33; +NET "SNES_REFRESH" IOSTANDARD = LVCMOS33; + +NET "CLKIN" IOSTANDARD = LVCMOS33; +//NET "CLKIN" PULLUP; +NET "SPI_SS" PULLUP; +//NET "DCM_RST" LOC = P46; +//NET "DCM_RST" IOSTANDARD = LVCMOS33; +NET "SNES_DATABUS_DIR" IOSTANDARD = LVCMOS33; +NET "SNES_DATABUS_OE" IOSTANDARD = LVCMOS33; +NET "SNES_IRQ" IOSTANDARD = LVCMOS33; + +NET "ROM_CE" LOC = P172; +NET "ROM_CE" IOSTANDARD = LVCMOS33; +NET "ROM_CE" DRIVE = 8; + +NET "SNES_ADDR[0]" LOC = P119; +NET "SNES_ADDR[10]" LOC = P146; +NET "SNES_ADDR[11]" LOC = P148; +NET "SNES_ADDR[12]" LOC = P147; +NET "SNES_ADDR[13]" LOC = P144; +NET "SNES_ADDR[14]" LOC = P141; +NET "SNES_ADDR[15]" LOC = P139; +NET "SNES_ADDR[16]" LOC = P137; +NET "SNES_ADDR[17]" LOC = P133; +NET "SNES_ADDR[18]" LOC = P131; +NET "SNES_ADDR[19]" LOC = P128; +NET "SNES_ADDR[1]" LOC = P122; +NET "SNES_ADDR[20]" LOC = P125; +NET "SNES_ADDR[21]" LOC = P123; +NET "SNES_ADDR[22]" LOC = P120; +NET "SNES_ADDR[23]" LOC = P117; +NET "SNES_ADDR[2]" LOC = P124; +NET "SNES_ADDR[3]" LOC = P126; +NET "SNES_ADDR[4]" LOC = P130; +NET "SNES_ADDR[5]" LOC = P132; +NET "SNES_ADDR[6]" LOC = P135; +NET "SNES_ADDR[7]" LOC = P138; +NET "SNES_ADDR[8]" LOC = P140; +NET "SNES_ADDR[9]" LOC = P143; +NET "SNES_DATA[0]" LOC = P107; +NET "SNES_DATA[1]" LOC = P102; +NET "SNES_DATA[2]" LOC = P100; +NET "SNES_DATA[3]" LOC = P96; +NET "SNES_DATA[4]" LOC = P108; +NET "SNES_DATA[5]" LOC = P106; +NET "SNES_DATA[6]" LOC = P101; +NET "SNES_DATA[7]" LOC = P97; + + +NET "CLKIN" LOC = P80; +// NET "RST" LOC = P113; +NET "MCU_OVR" LOC = P92; + + +NET "MCU_OVR" IOSTANDARD = LVCMOS33; +NET "MCU_OVR" DRIVE = 8; + + +NET "ROM_ADDR[0]" LOC = P166; + + +NET "ROM_ADDR[0]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[0]" DRIVE = 8; + + +NET "ROM_ADDR[10]" LOC = P197; + + +NET "ROM_ADDR[10]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[10]" DRIVE = 8; + + +NET "ROM_ADDR[11]" LOC = P196; + + +NET "ROM_ADDR[11]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[11]" DRIVE = 8; + + +NET "ROM_ADDR[12]" LOC = P2; + + +NET "ROM_ADDR[12]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[12]" DRIVE = 8; + + +NET "ROM_ADDR[13]" LOC = P194; + + +NET "ROM_ADDR[13]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[13]" DRIVE = 8; + + +NET "ROM_ADDR[14]" LOC = P200; + + +NET "ROM_ADDR[14]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[14]" DRIVE = 8; + + +NET "ROM_ADDR[15]" LOC = P184; + + +NET "ROM_ADDR[15]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[15]" DRIVE = 8; + + +NET "ROM_ADDR[16]" LOC = P199; + + +NET "ROM_ADDR[16]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[16]" DRIVE = 8; + + +NET "ROM_ADDR[17]" LOC = P11; + + +NET "ROM_ADDR[17]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[17]" DRIVE = 8; + + +NET "ROM_ADDR[18]" LOC = P3; + + +NET "ROM_ADDR[18]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[18]" DRIVE = 8; + + +NET "ROM_ADDR[19]" LOC = P4; + + +NET "ROM_ADDR[19]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[19]" DRIVE = 8; + + +NET "ROM_ADDR[1]" LOC = P168; + + +NET "ROM_ADDR[1]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[1]" DRIVE = 8; + + +NET "ROM_ADDR[20]" LOC = P191; + + +NET "ROM_ADDR[20]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[20]" DRIVE = 8; + + +NET "ROM_ADDR[21]" LOC = P203; + + +NET "ROM_ADDR[21]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[21]" DRIVE = 8; + + +NET "ROM_ADDR[22]" LOC = P198; + + +NET "ROM_ADDR[22]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[22]" DRIVE = 8; + + +NET "ROM_ADDR[2]" LOC = P171; + + +NET "ROM_ADDR[2]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[2]" DRIVE = 8; + + +NET "ROM_ADDR[3]" LOC = P165; + + +NET "ROM_ADDR[3]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[3]" DRIVE = 8; + + +NET "ROM_ADDR[4]" LOC = P169; + + +NET "ROM_ADDR[4]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[4]" DRIVE = 8; + + +NET "ROM_ADDR[5]" LOC = P18; + + +NET "ROM_ADDR[5]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[5]" DRIVE = 8; + + +NET "ROM_ADDR[6]" LOC = P175; + + +NET "ROM_ADDR[6]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[6]" DRIVE = 8; + + +NET "ROM_ADDR[7]" LOC = P167; + + +NET "ROM_ADDR[7]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[7]" DRIVE = 8; + + +NET "ROM_ADDR[8]" LOC = P205; + + +NET "ROM_ADDR[8]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[8]" DRIVE = 8; + + +NET "ROM_ADDR[9]" LOC = P204; + + +NET "ROM_ADDR[9]" IOSTANDARD = LVCMOS33; +NET "ROM_ADDR[9]" DRIVE = 8; + + +NET "ROM_BHE" LOC = P161; + + +NET "ROM_BHE" IOSTANDARD = LVCMOS33; +NET "ROM_BHE" DRIVE = 8; + + +NET "ROM_BLE" LOC = P156; + + +NET "ROM_BLE" IOSTANDARD = LVCMOS33; +NET "ROM_BLE" DRIVE = 8; + +NET "IRQ_DIR" LOC = P113; +NET "IRQ_DIR" IOSTANDARD = LVCMOS33; +NET "IRQ_DIR" DRIVE = 8; + + +NET "ROM_DATA[0]" LOC = P176; + + +NET "ROM_DATA[0]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[0]" DRIVE = 8; + + +NET "ROM_DATA[10]" LOC = P15; + + +NET "ROM_DATA[10]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[10]" DRIVE = 8; + + +NET "ROM_DATA[11]" LOC = P12; + + +NET "ROM_DATA[11]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[11]" DRIVE = 8; + + +NET "ROM_DATA[12]" LOC = P10; + + +NET "ROM_DATA[12]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[12]" DRIVE = 8; + + +NET "ROM_DATA[13]" LOC = P7; + + +NET "ROM_DATA[13]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[13]" DRIVE = 8; + + +NET "ROM_DATA[14]" LOC = P9; + + +NET "ROM_DATA[14]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[14]" DRIVE = 8; + + +NET "ROM_DATA[15]" LOC = P5; + + +NET "ROM_DATA[15]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[15]" DRIVE = 8; + + +NET "ROM_DATA[1]" LOC = P178; + + +NET "ROM_DATA[1]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[1]" DRIVE = 8; + + +NET "ROM_DATA[2]" LOC = P181; + + +NET "ROM_DATA[2]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[2]" DRIVE = 8; + + +NET "ROM_DATA[3]" LOC = P182; + + +NET "ROM_DATA[3]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[3]" DRIVE = 8; + + +NET "ROM_DATA[4]" LOC = P183; + + +NET "ROM_DATA[4]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[4]" DRIVE = 8; + + +NET "ROM_DATA[5]" LOC = P187; + + +NET "ROM_DATA[5]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[5]" DRIVE = 8; + + +NET "ROM_DATA[6]" LOC = P185; + + +NET "ROM_DATA[6]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[6]" DRIVE = 8; + + +NET "ROM_DATA[7]" LOC = P189; + + +NET "ROM_DATA[7]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[7]" DRIVE = 8; + + +NET "ROM_DATA[8]" LOC = P16; + + +NET "ROM_DATA[8]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[8]" DRIVE = 8; + + +NET "ROM_DATA[9]" LOC = P13; + + +NET "ROM_DATA[9]" IOSTANDARD = LVCMOS33; +NET "ROM_DATA[9]" DRIVE = 8; + + +NET "ROM_OE" LOC = P162; + + +NET "ROM_OE" IOSTANDARD = LVCMOS33; +NET "ROM_OE" DRIVE = 8; + + +NET "ROM_WE" LOC = P190; + + +NET "ROM_WE" IOSTANDARD = LVCMOS33; +NET "ROM_WE" DRIVE = 8; +NET "SNES_ADDR[0]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[0]" DRIVE = 8; +NET "SNES_ADDR[10]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[10]" DRIVE = 8; +NET "SNES_ADDR[11]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[11]" DRIVE = 8; +NET "SNES_ADDR[12]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[12]" DRIVE = 8; +NET "SNES_ADDR[13]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[13]" DRIVE = 8; +NET "SNES_ADDR[14]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[14]" DRIVE = 8; +NET "SNES_ADDR[15]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[15]" DRIVE = 8; +NET "SNES_ADDR[16]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[16]" DRIVE = 8; +NET "SNES_ADDR[17]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[17]" DRIVE = 8; +NET "SNES_ADDR[18]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[18]" DRIVE = 8; +NET "SNES_ADDR[19]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[19]" DRIVE = 8; +NET "SNES_ADDR[1]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[1]" DRIVE = 8; +NET "SNES_ADDR[20]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[20]" DRIVE = 8; +NET "SNES_ADDR[21]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[21]" DRIVE = 8; +NET "SNES_ADDR[22]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[22]" DRIVE = 8; +NET "SNES_ADDR[23]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[23]" DRIVE = 8; +NET "SNES_ADDR[2]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[2]" DRIVE = 8; +NET "SNES_ADDR[3]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[3]" DRIVE = 8; +NET "SNES_ADDR[4]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[4]" DRIVE = 8; +NET "SNES_ADDR[5]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[5]" DRIVE = 8; +NET "SNES_ADDR[6]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[6]" DRIVE = 8; +NET "SNES_ADDR[7]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[7]" DRIVE = 8; +NET "SNES_ADDR[8]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[8]" DRIVE = 8; +NET "SNES_ADDR[9]" IOSTANDARD = LVCMOS33; +NET "SNES_ADDR[9]" DRIVE = 8; + + +NET "SNES_CPU_CLK" LOC = P94; +NET "SNES_CS" LOC = P116; +NET "SNES_DATABUS_DIR" LOC = P111; +NET "SNES_DATABUS_OE" LOC = P109; + + +NET "SNES_DATA[0]" IOSTANDARD = LVCMOS33; +NET "SNES_DATA[0]" DRIVE = 8; +NET "SNES_DATA[1]" IOSTANDARD = LVCMOS33; +NET "SNES_DATA[1]" DRIVE = 8; +NET "SNES_DATA[2]" IOSTANDARD = LVCMOS33; +NET "SNES_DATA[2]" DRIVE = 8; +NET "SNES_DATA[3]" IOSTANDARD = LVCMOS33; +NET "SNES_DATA[3]" DRIVE = 8; +NET "SNES_DATA[4]" IOSTANDARD = LVCMOS33; +NET "SNES_DATA[4]" DRIVE = 8; +NET "SNES_DATA[5]" IOSTANDARD = LVCMOS33; +NET "SNES_DATA[5]" DRIVE = 8; +NET "SNES_DATA[6]" IOSTANDARD = LVCMOS33; +NET "SNES_DATA[6]" DRIVE = 8; +NET "SNES_DATA[7]" IOSTANDARD = LVCMOS33; +NET "SNES_DATA[7]" DRIVE = 8; + + +NET "SNES_IRQ" LOC = P114; +NET "SNES_READ" LOC = P115; +NET "SNES_REFRESH" LOC = P155; +NET "SNES_WRITE" LOC = P95; + +NET "SPI_MISO" LOC = P72; + + +NET "SPI_MISO" IOSTANDARD = LVCMOS33; +NET "SPI_MISO" DRIVE = 8; + + +NET "SPI_MOSI" LOC = P74; + + +NET "SPI_MOSI" IOSTANDARD = LVCMOS33; +NET "SPI_MOSI" DRIVE = 8; + + +NET "SPI_SCK" LOC = P71; + + +NET "SPI_SCK" IOSTANDARD = LVCMOS33; +NET "SPI_SCK" DRIVE = 8; +NET "SPI_SCK" PULLUP; + + +NET "SPI_SS" LOC = P68; + + +NET "SPI_SS" IOSTANDARD = LVCMOS33; +NET "SPI_SS" DRIVE = 8; + + +NET "DAC_LRCK" LOC = P77; + + +NET "DAC_LRCK" IOSTANDARD = LVCMOS33; +NET "DAC_LRCK" DRIVE = 8; + + +NET "DAC_MCLK" LOC = P76; + + +NET "DAC_MCLK" IOSTANDARD = LVCMOS33; +NET "DAC_MCLK" DRIVE = 8; + + +NET "DAC_SDOUT" LOC = P78; + + +NET "DAC_SDOUT" IOSTANDARD = LVCMOS33; +NET "DAC_SDOUT" DRIVE = 8; + +# PlanAhead Generated physical constraints + +NET "SD_CLK" LOC = P64; +NET "SD_CMD" LOC = P67; +NET "SD_DAT[0]" LOC = P65; +NET "SD_DAT[1]" LOC = P79; +NET "SD_DAT[2]" LOC = P62; +NET "SD_DAT[3]" LOC = P63; + +# PlanAhead Generated IO constraints + +NET "SD_CLK" IOSTANDARD = LVCMOS33; +NET "SD_CMD" IOSTANDARD = LVCMOS33; +NET "SD_DAT[0]" IOSTANDARD = LVCMOS33; +NET "SD_DAT[1]" IOSTANDARD = LVCMOS33; +NET "SD_DAT[2]" IOSTANDARD = LVCMOS33; +NET "SD_DAT[3]" IOSTANDARD = LVCMOS33; + +NET "SNES_SYSCLK" LOC = P180; +NET "SNES_SYSCLK" IOSTANDARD = LVCMOS33; \ No newline at end of file diff --git a/verilog/sd2sneslite/main.v b/verilog/sd2sneslite/main.v new file mode 100644 index 0000000..36ffe7f --- /dev/null +++ b/verilog/sd2sneslite/main.v @@ -0,0 +1,519 @@ +`timescale 1 ns / 1 ns +////////////////////////////////////////////////////////////////////////////////// +// Company: Rehkopf +// Engineer: Rehkopf +// +// Create Date: 01:13:46 05/09/2009 +// Design Name: +// Module Name: main +// Project Name: +// Target Devices: +// Tool versions: +// Description: Master Control FSM +// +// Dependencies: address +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module main( + /* input clock */ + input CLKIN, + + /* SNES signals */ + input [23:0] SNES_ADDR, + input SNES_READ, + input SNES_WRITE, + input SNES_CS, + inout [7:0] SNES_DATA, + input SNES_CPU_CLK, + input SNES_REFRESH, + inout SNES_IRQ, + output SNES_DATABUS_OE, + output SNES_DATABUS_DIR, + output IRQ_DIR, + input SNES_SYSCLK, + + /* SRAM signals */ + inout [15:0] ROM_DATA, + output [22:0] ROM_ADDR, + output ROM_CE, + output ROM_OE, + output ROM_WE, + output ROM_BHE, + output ROM_BLE, + + /* MCU signals */ + input SPI_MOSI, + inout SPI_MISO, + input SPI_SS, + inout SPI_SCK, + input MCU_OVR, + + output DAC_MCLK, + output DAC_LRCK, + output DAC_SDOUT, + + /* SD signals */ + input [3:0] SD_DAT, + inout SD_CMD, + inout SD_CLK + + /* debug */ + //output DCM_IN_STOPPED, + //output DCM_FX_STOPPED + //input DCM_RST + ); + +assign DAC_MCLK = 1'b0; +assign DAC_LRCK = 1'b0; +assign DAC_SDOUT = 1'b0; + +wire [7:0] spi_cmd_data; +wire [7:0] spi_param_data; +wire [7:0] spi_input_data; +wire [31:0] spi_byte_cnt; +wire [2:0] spi_bit_cnt; +wire [23:0] MCU_ADDR; +wire [7:0] mcu_data_in; +wire [7:0] mcu_data_out; +wire [7:0] MCU_IN_DATA; +wire [7:0] MCU_OUT_DATA; +wire [3:0] MAPPER; +wire [23:0] SAVERAM_MASK; +wire [23:0] ROM_MASK; +wire [7:0] SD_DMA_SRAM_DATA; +wire [1:0] SD_DMA_TGT; +wire [10:0] SD_DMA_PARTIAL_START; +wire [10:0] SD_DMA_PARTIAL_END; + +wire [10:0] dac_addr; +//wire [7:0] dac_volume; +wire [7:0] msu_volumerq_out; +wire [6:0] msu_status_out; +wire [31:0] msu_addressrq_out; +wire [15:0] msu_trackrq_out; +wire [13:0] msu_write_addr; +wire [13:0] msu_ptr_addr; +wire [7:0] MSU_SNES_DATA_IN; +wire [7:0] MSU_SNES_DATA_OUT; +wire [5:0] msu_status_reset_bits; +wire [5:0] msu_status_set_bits; + + +spi snes_spi(.clk(CLK2), + .MOSI(SPI_MOSI), + .MISO(SPI_MISO), + .SSEL(SPI_SS), + .SCK(SPI_SCK), + .cmd_ready(spi_cmd_ready), + .param_ready(spi_param_ready), + .cmd_data(spi_cmd_data), + .param_data(spi_param_data), + .endmessage(spi_endmessage), + .startmessage(spi_startmessage), + .input_data(spi_input_data), + .byte_cnt(spi_byte_cnt), + .bit_cnt(spi_bit_cnt) +); + + +mcu_cmd snes_mcu_cmd( + .clk(CLK2), + .cmd_ready(spi_cmd_ready), + .param_ready(spi_param_ready), + .cmd_data(spi_cmd_data), + .param_data(spi_param_data), + .mcu_mapper(MAPPER), + .mcu_sram_size(SRAM_SIZE), + .mcu_read(MCU_READ), + .mcu_write(MCU_WRITE), + .mcu_data_in(MCU_OUT_DATA), + .mcu_data_out(MCU_IN_DATA), + .spi_byte_cnt(spi_byte_cnt), + .spi_bit_cnt(spi_bit_cnt), + .spi_data_out(spi_input_data), + .addr_out(MCU_ADDR), + .endmessage(spi_endmessage), + .startmessage(spi_startmessage), + .saveram_mask_out(SAVERAM_MASK), + .rom_mask_out(ROM_MASK) +); + +// dcm1: dfs 4x +my_dcm snes_dcm(.CLKIN(CLKIN), + .CLKFX(CLK2), + .LOCKED(DCM_LOCKED), + .RST(DCM_RST), + .STATUS(DCM_STATUS) + ); + +assign DCM_RST=0; + +/* +dcm_srl16 snes_dcm_resetter(.CLK(CLKIN), + .Q(DCM_RST) + ); +*/ +//wire DCM_FX_STOPPED = DCM_STATUS[2]; +//always @(posedge CLKIN) begin +// if(DCM_FX_STOPPED) +// DCM_RSTr <= 1'b1; +// else +// DCM_RSTr <= 1'b0; +//end + +/*reg DO_DCM_RESET, DCM_RESETTING; +reg DCM_RSTr; +assign DCM_RST = DCM_RSTr; +reg [2:0] DCM_RESET_CNT; +initial DO_DCM_RESET = 1'b0; +initial DCM_RESETTING = 1'b0; + +always @(posedge CLKIN) begin + if(!DCM_LOCKED && !DCM_RESETTING) begin + DCM_RSTr <= 1'b1; + DO_DCM_RESET <= 1'b1; + DCM_RESET_CNT <= 3'b0; + end else if (DO_DCM_RESET) begin + DCM_RSTr <= 1'b0; + DCM_RESET_CNT <= DCM_RESET_CNT + 1; + end +end + +always @(posedge CLKIN) begin + if (DO_DCM_RESET) + DCM_RESETTING <= 1'b1; + else if (DCM_RESET_CNT == 3'b110) + DCM_RESETTING <= 1'b0; +end +*/ +wire SNES_RW; +reg [1:0] SNES_READr; +reg [1:0] SNES_WRITEr; +reg [1:0] SNES_CSr; +reg [5:0] SNES_CPU_CLKr; +reg [5:0] SNES_RWr; +reg [23:0] SNES_ADDRr; +reg [23:0] SNES_ADDR_PREVr; +reg [3:0] SNES_ADDRCHGr; + +wire SNES_READs = (SNES_READr == 2'b11); +wire SNES_WRITEs = (SNES_WRITEr == 2'b11); +wire SNES_CSs = (SNES_CSr == 2'b11); +wire SNES_CPU_CLKs = SNES_CPU_CLK; // (SNES_CPU_CLKr == 2'b11); +wire SNES_RW_start = (SNES_RWr == 6'b111110); // falling edge marks beginning of cycle +wire SNES_cycle_start = (SNES_CPU_CLKr == 6'b000001); +wire SNES_ADDRCHG = (SNES_ADDRr != SNES_ADDR_PREVr); +wire SNES_addr_start = (SNES_ADDRCHGr[0] == 1'b1); + +assign SNES_RW = (SNES_READ & SNES_WRITE); + +always @(posedge CLK2) begin + SNES_READr <= {SNES_READr[0], SNES_READ}; + SNES_WRITEr <= {SNES_WRITEr[0], SNES_WRITE}; + SNES_CSr <= {SNES_CSr[0], SNES_CS}; + SNES_CPU_CLKr <= {SNES_CPU_CLKr[4:0], SNES_CPU_CLK}; + SNES_RWr <= {SNES_RWr[4:0], SNES_RW}; +end + +reg ADDR_WRITE; + +//reg [23:0] SNES_ADDRr; +//wire [23:0] SNES_ADDRw = SNES_ADDR; + +wire ROM_SEL; + +address snes_addr( + .CLK(CLK2), + .MAPPER(MAPPER), + .SNES_ADDR(SNES_ADDR), // requested address from SNES + .SNES_CS(SNES_CS), // "CART" pin from SNES (active low) + .ROM_ADDR(ROM_ADDR), // Address to request from SRAM (active low) + .ROM_SEL(ROM_SEL), // which SRAM unit to access + .MCU_OVR(MCU_OVR), // enable MCU mode (active low) + .MODE(MODE), // MCU(1) or SNES(0) ("bus phase") + .IS_SAVERAM(IS_SAVERAM), + .IS_ROM(IS_ROM), + .MCU_ADDR(MCU_ADDR), + .ROM_ADDR0(ROM_ADDR0), + .SAVERAM_MASK(SAVERAM_MASK), + .ROM_MASK(ROM_MASK) + ); + +wire SNES_READ_CYCLEw; +wire SNES_WRITE_CYCLEw; +wire MCU_READ_CYCLEw; +wire MCU_WRITE_CYCLEw; + +data snes_data(.CLK(CLK2), + .SNES_READ(SNES_READ), + .SNES_WRITE(SNES_WRITE), + .MCU_READ(MCU_READ), + .MCU_WRITE(MCU_WRITE), + .SNES_DATA(SNES_DATA), + .ROM_DATA(ROM_DATA), + .MODE(MODE), + .SNES_DATA_TO_MEM(SNES_DATA_TO_MEM), + .MCU_DATA_TO_MEM(MCU_DATA_TO_MEM), + .ROM_DATA_TO_SNES_MEM(ROM_DATA_TO_SNES_MEM), + .ROM_DATA_TO_MCU_MEM(ROM_DATA_TO_MCU_MEM), + .MCU_OVR(MCU_OVR), + .MCU_IN_DATA(MCU_IN_DATA), + .MCU_OUT_DATA(MCU_OUT_DATA), + .ROM_ADDR0(ROM_ADDR0), + .MSU_DATA_IN(MSU_SNES_DATA_IN), + .MSU_DATA_OUT(MSU_SNES_DATA_OUT), + .msu_enable(msu_enable) + ); + +parameter MODE_SNES = 1'b0; +parameter MODE_MCU = 1'b1; + +parameter STATE_0 = 14'b00000000000001; +parameter STATE_1 = 14'b00000000000010; +parameter STATE_2 = 14'b00000000000100; +parameter STATE_3 = 14'b00000000001000; +parameter STATE_4 = 14'b00000000010000; +parameter STATE_5 = 14'b00000000100000; +parameter STATE_6 = 14'b00000001000000; +parameter STATE_7 = 14'b00000010000000; +parameter STATE_8 = 14'b00000100000000; +parameter STATE_9 = 14'b00001000000000; +parameter STATE_10 = 14'b00010000000000; +parameter STATE_11 = 14'b00100000000000; +parameter STATE_12 = 14'b01000000000000; +parameter STATE_IDLE = 14'b10000000000000; + +reg [13:0] STATE; +reg [3:0] STATEIDX; + +reg [1:0] CYCLE_RESET; +reg ROM_WE_MASK; +reg ROM_OE_MASK; + +reg [13:0] ROM_WE_ARRAY [3:0]; +reg [13:0] ROM_OE_ARRAY [3:0]; + +reg [13:0] SNES_DATA_TO_MEM_ARRAY[1:0]; +reg [13:0] MCU_DATA_TO_MEM_ARRAY[1:0]; +reg [13:0] ROM_DATA_TO_SNES_MEM_ARRAY[1:0]; +reg [13:0] ROM_DATA_TO_MCU_MEM_ARRAY[1:0]; + +reg [13:0] MODE_ARRAY; + +reg SNES_READ_CYCLE; +reg SNES_WRITE_CYCLE; +reg MCU_READ_CYCLE; +reg MCU_WRITE_CYCLE; +reg MCU_SPI_WRITEONCE; +reg MCU_SPI_READONCE; +reg MCU_SPI_WRITE; +reg MCU_SPI_READ; +reg MCU_SPI_ADDR_INCREMENT; +reg [7:0] MCU_DATA_IN; +reg [3:0] MAPPER_BUF; + +reg SNES_DATABUS_OE_BUF; +reg SNES_DATABUS_DIR_BUF; + +assign MODE = !MCU_OVR ? MODE_MCU : MODE_ARRAY[STATEIDX]; + +initial begin + CYCLE_RESET = 2'b0; + + STATE = STATE_IDLE; + STATEIDX = 13; + ROM_WE_MASK = 1'b1; + ROM_OE_MASK = 1'b1; + SNES_READ_CYCLE = 1'b1; + SNES_WRITE_CYCLE = 1'b1; + MCU_READ_CYCLE = 1'b1; + MCU_WRITE_CYCLE = 1'b1; + MODE_ARRAY = 14'b0_000000_1111111; + + ROM_WE_ARRAY[2'b00] = 14'b1_000000_0000000; + ROM_WE_ARRAY[2'b01] = 14'b1_000000_1111111; + ROM_WE_ARRAY[2'b10] = 14'b1_111111_0000000; + ROM_WE_ARRAY[2'b11] = 14'b1_111111_1111111; + + ROM_OE_ARRAY[2'b00] = 14'b1_111111_1111111; + ROM_OE_ARRAY[2'b01] = 14'b1_111111_0000000; + ROM_OE_ARRAY[2'b10] = 14'b0_000000_1111111; + ROM_OE_ARRAY[2'b11] = 14'b0_000000_0000000; + + SNES_DATA_TO_MEM_ARRAY[1'b0] = 14'b0_000100_0000000; // SNES write + /* 13'b0001000000000 */ + SNES_DATA_TO_MEM_ARRAY[1'b1] = 14'b0_000000_0000000; // SNES read + + MCU_DATA_TO_MEM_ARRAY[1'b0] = 14'b1_111111_1111111; // MCU write +// MCU_DATA_TO_MEM_ARRAY[1'b0] = 13'b0000000001000; // MCU write + + MCU_DATA_TO_MEM_ARRAY[1'b1] = 14'b0_000000_0000000; // MCU read + + ROM_DATA_TO_SNES_MEM_ARRAY[1'b0] = 14'b0_000000_0000000; // SNES write + ROM_DATA_TO_SNES_MEM_ARRAY[1'b1] = 14'b0_000010_0000000; // SNES read + /* 13'b0000100000000; */ + + ROM_DATA_TO_MCU_MEM_ARRAY[1'b0] = 14'b0_000000_0000000; // MCU write + ROM_DATA_TO_MCU_MEM_ARRAY[1'b1] = 14'b0_000000_0000001; // MCU read +// SRAM_DATA_TO_MCU_MEM_ARRAY[1'b1] = 13'b0000000000001; // MCU read + +end + +// falling edge of SNES /RD or /WR marks the beginning of a new cycle +// SNES READ or WRITE always starts @posedge CLK !! +// CPU cycle can be 6, 8 or 12 CLKIN cycles so we must satisfy +// the minimum of 6 SNES cycles to get everything done. +// we have 24 internal cycles to work with. (CLKIN * 4) + +always @(posedge CLK2) begin + CYCLE_RESET <= {CYCLE_RESET[0], SNES_cycle_start}; +end + +always @(posedge CLK2) begin + MCU_READ_CYCLE <= MCU_READ; + MCU_WRITE_CYCLE <= MCU_WRITE; + if (SNES_cycle_start) begin + SNES_READ_CYCLE <= SNES_READ; + SNES_WRITE_CYCLE <= SNES_WRITE; + STATE <= STATE_0; + STATEIDX <= 12; + end else begin + case (STATE) + STATE_0: begin + STATE <= STATE_1; STATEIDX <= 11; + end + STATE_1: begin + STATE <= STATE_2; STATEIDX <= 10; + end + STATE_2: begin + STATE <= STATE_3; STATEIDX <= 9; + end + STATE_3: begin + STATE <= STATE_4; STATEIDX <= 8; + end + STATE_4: begin + STATE <= STATE_5; STATEIDX <= 7; + end + STATE_5: begin + STATE <= STATE_6; STATEIDX <= 6; + end + STATE_6: begin + STATE <= STATE_7; STATEIDX <= 5; + end + STATE_7: begin + STATE <= STATE_8; STATEIDX <= 4; + end + STATE_8: begin + STATE <= STATE_9; STATEIDX <= 3; + end + STATE_9: begin + STATE <= STATE_10; STATEIDX <= 2; + end + STATE_10: begin + STATE <= STATE_11; STATEIDX <= 1; + end + STATE_11: begin + STATE <= STATE_12; STATEIDX <= 0; + end + STATE_12: begin + STATE <= STATE_IDLE; STATEIDX <= 13; + end + STATE_IDLE: begin + STATE <= STATE_IDLE; STATEIDX <= 13; + end + default: begin + STATE <= STATE_IDLE; STATEIDX <= 13; + end + endcase + end +end +/* +always @(posedge CLK2) begin + + case (STATE) + STATE_9: begin + STATEIDX <= 9; + end + + STATE_0: begin + STATEIDX <= 8; + end + + STATE_1: begin + STATEIDX <= 7; + end + + STATE_2: begin + STATEIDX <= 6; + end + + STATE_3: begin + STATEIDX <= 5; + end + + STATE_4: begin + STATEIDX <= 4; + end + + STATE_5: begin + STATEIDX <= 3; + end + + STATE_6: begin + STATEIDX <= 2; + end + + STATE_7: begin + STATEIDX <= 1; + end + + STATE_8: begin + STATEIDX <= 0; + end + default: + STATEIDX <= 9; + endcase +end +*/ +// When in MCU mode, enable SRAM_WE according to MCU programming +// else enable SRAM_WE according to state&cycle +assign ROM_WE = !MCU_OVR ? MCU_WRITE + : ((!IS_SAVERAM & !MODE) | ROM_WE_ARRAY[{SNES_WRITE_CYCLE, MCU_WRITE_CYCLE}][STATEIDX]); + +// When in MCU mode, enable SRAM_OE whenever not writing +// else enable SRAM_OE according to state&cycle +assign ROM_OE = !MCU_OVR ? MCU_READ + : ROM_OE_ARRAY[{SNES_WRITE_CYCLE, MCU_WRITE_CYCLE}][STATEIDX]; + +assign ROM_CE = 1'b0; // !MCU_OVR ? (MCU_READ & MCU_WRITE) : ROM_SEL; + +assign ROM_BHE = !ROM_WE ? ROM_ADDR0 : 1'b0; +assign ROM_BLE = !ROM_WE ? !ROM_ADDR0 : 1'b0; + +//assign SRAM_BHE = SRAM_ADDR0; +//assign SRAM_BLE = ~SRAM_ADDR0; + +// dumb version +//assign SRAM_OE = !MCU_ENA ? MCU_READ : SNES_READs; +//assign SRAM_WE = !MCU_ENA ? MCU_WRITE : 1'b1; + +//assign SNES_DATABUS_OE = (!IS_SAVERAM & SNES_CS) | (SNES_READ & SNES_WRITE); +assign SNES_DATABUS_OE = msu_enable ? 1'b0 : ((IS_ROM & SNES_CS) | (!IS_ROM & !IS_SAVERAM) | (SNES_READ & SNES_WRITE)); +assign SNES_DATABUS_DIR = !SNES_READ ? 1'b1 : 1'b0; + +assign SNES_DATA_TO_MEM = SNES_DATA_TO_MEM_ARRAY[SNES_WRITE_CYCLE][STATEIDX]; +assign MCU_DATA_TO_MEM = MCU_DATA_TO_MEM_ARRAY[MCU_WRITE_CYCLE][STATEIDX]; + +assign ROM_DATA_TO_SNES_MEM = ROM_DATA_TO_SNES_MEM_ARRAY[SNES_WRITE_CYCLE][STATEIDX]; +assign ROM_DATA_TO_MCU_MEM = ROM_DATA_TO_MCU_MEM_ARRAY[MCU_WRITE_CYCLE][STATEIDX]; + +assign SNES_READ_CYCLEw = SNES_READ_CYCLE; +assign SNES_WRITE_CYCLEw = SNES_WRITE_CYCLE; +assign IRQ_DIR = 1'b0; +assign SNES_IRQ = 1'bZ; + +endmodule diff --git a/verilog/sd2sneslite/msu.v b/verilog/sd2sneslite/msu.v new file mode 100644 index 0000000..cbaeef9 --- /dev/null +++ b/verilog/sd2sneslite/msu.v @@ -0,0 +1,182 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 14:55:04 12/14/2010 +// Design Name: +// Module Name: msu +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module msu( + input clkin, + input enable, + input [13:0] pgm_address, + input [7:0] pgm_data, + input pgm_we, + input [2:0] reg_addr, + input [7:0] reg_data_in, + output [7:0] reg_data_out, + input reg_oe, + input reg_we, + output [6:0] status_out, + output [7:0] volume_out, + output volume_latch_out, + output [31:0] addr_out, + output [15:0] track_out, + input [5:0] status_reset_bits, + input [5:0] status_set_bits, + input status_reset_we, + input [13:0] msu_address_ext, + input msu_address_ext_write + ); + +reg [1:0] status_reset_we_r; +always @(posedge clkin) status_reset_we_r = {status_reset_we_r[0], status_reset_we}; +wire status_reset_en = (status_reset_we_r == 2'b01); + +reg [13:0] msu_address_r; +wire [13:0] msu_address = msu_address_r; + +wire [7:0] msu_data; +reg [7:0] msu_data_r; + +reg [1:0] msu_address_ext_write_sreg; +always @(posedge clkin) msu_address_ext_write_sreg <= {msu_address_ext_write_sreg[0], msu_address_ext_write}; +wire msu_address_ext_write_rising = (msu_address_ext_write_sreg[1:0] == 2'b01); + +reg [5:0] reg_oe_sreg; +always @(posedge clkin) reg_oe_sreg <= {reg_oe_sreg[4:0], reg_oe}; +wire reg_oe_falling = (reg_oe_sreg[5:0] == 6'b100000); +wire reg_oe_rising = (reg_oe_sreg[5:0] == 6'b000001); + +reg [1:0] reg_we_sreg; +always @(posedge clkin) reg_we_sreg <= {reg_we_sreg[0], reg_we}; +wire reg_we_rising = (reg_we_sreg[1:0] == 2'b01); + +reg [31:0] addr_out_r; +assign addr_out = addr_out_r; + +reg [15:0] track_out_r; +assign track_out = track_out_r; + +reg [7:0] volume_r; +assign volume_out = volume_r; + +reg volume_start_r; +assign volume_latch_out = volume_start_r; + +reg audio_start_r; +reg audio_busy_r; +reg data_start_r; +reg data_busy_r; +reg ctrl_start_r; +reg [1:0] audio_ctrl_r; +reg [1:0] audio_status_r; + +initial begin + audio_busy_r <= 1'b1; + data_busy_r <= 1'b1; +end + +assign status_out = {msu_address_r[13], + audio_start_r, data_start_r, volume_start_r, audio_ctrl_r, ctrl_start_r}; + +initial msu_address_r = 14'h1234; + +msu_databuf snes_msu_databuf ( + .clka(clkin), + .wea(~pgm_we), // Bus [0 : 0] + .addra(pgm_address), // Bus [13 : 0] + .dina(pgm_data), // Bus [7 : 0] + .clkb(clkin), + .addrb(msu_address), // Bus [13 : 0] + .doutb(msu_data)); // Bus [7 : 0] + +reg [7:0] msu_regs [7:0]; + +reg [7:0] data_out_r; +reg [7:0] data_in_r; +assign reg_data_out = data_out_r; +always @(posedge clkin) data_in_r <= reg_data_in; + +always @(posedge clkin) begin + case(reg_addr) + 3'h0: data_out_r <= {data_busy_r, audio_busy_r, audio_status_r, 4'b0001}; + 3'h1: data_out_r <= msu_data_r; + 3'h2: data_out_r <= 8'h53; + 3'h3: data_out_r <= 8'h2d; + 3'h4: data_out_r <= 8'h4d; + 3'h5: data_out_r <= 8'h53; + 3'h6: data_out_r <= 8'h55; + 3'h7: data_out_r <= 8'h31; + endcase +end + +always @(posedge clkin) begin + if(reg_we_rising && enable) begin + case(reg_addr) + 3'h0: addr_out_r[7:0] <= reg_data_in; + 3'h1: addr_out_r[15:8] <= reg_data_in; + 3'h2: addr_out_r[23:16] <= reg_data_in; + 3'h3: begin + addr_out_r[31:24] <= reg_data_in; + data_start_r <= 1'b1; + data_busy_r <= 1'b1; + end + 3'h4: begin + track_out_r[7:0] <= reg_data_in; + end + 3'h5: begin + track_out_r[15:8] <= reg_data_in; + audio_start_r <= 1'b1; + audio_busy_r <= 1'b1; + end + 3'h6: begin + volume_r <= reg_data_in; + volume_start_r <= 1'b1; + end + 3'h7: begin + if(!audio_busy_r) begin + audio_ctrl_r <= reg_data_in[1:0]; + ctrl_start_r <= 1'b1; + end + end + endcase + end else if (status_reset_en) begin + audio_busy_r <= (audio_busy_r | status_set_bits[5]) & ~status_reset_bits[5]; + if(status_reset_bits[5]) audio_start_r <= 1'b0; + + data_busy_r <= (data_busy_r | status_set_bits[4]) & ~status_reset_bits[4]; + if(status_reset_bits[4]) data_start_r <= 1'b0; + +// volume_start_r <= (volume_start_r | status_set_bits[3]) & ~status_reset_bits[3]; + + audio_status_r <= (audio_status_r | status_set_bits[2:1]) & ~status_reset_bits[2:1]; + + ctrl_start_r <= (ctrl_start_r | status_set_bits[0]) & ~status_reset_bits[0]; + end else begin + volume_start_r <= 1'b0; + end +end + +always @(posedge clkin) begin + if(msu_address_ext_write_rising) + msu_address_r <= msu_address_ext; + else if(enable && reg_addr == 3'h1 && reg_oe_falling) begin + msu_address_r <= msu_address_r + 1; + msu_data_r <= msu_data; + end +end + +endmodule diff --git a/verilog/sd2sneslite/sd2sneslite.xise b/verilog/sd2sneslite/sd2sneslite.xise new file mode 100644 index 0000000..8572964 --- /dev/null +++ b/verilog/sd2sneslite/sd2sneslite.xise @@ -0,0 +1,358 @@ + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/verilog/sd2sneslite/sd_dma.v b/verilog/sd2sneslite/sd_dma.v new file mode 100644 index 0000000..1a0b3d0 --- /dev/null +++ b/verilog/sd2sneslite/sd_dma.v @@ -0,0 +1,132 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 19:19:08 12/01/2010 +// Design Name: +// Module Name: sd_dma +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module sd_dma( + input [3:0] SD_DAT, + inout SD_CLK, + input CLK, + input SD_DMA_EN, + input SD_DMA_TGT, + output SD_DMA_STATUS, + output SD_DMA_SRAM_WE, + output SD_DMA_NEXTADDR, + output [7:0] SD_DMA_SRAM_DATA, + input SD_DMA_PARTIAL, + input [10:0] SD_DMA_PARTIAL_START, + input [10:0] SD_DMA_PARTIAL_END + ); + +reg [10:0] SD_DMA_STARTr; +reg [10:0] SD_DMA_ENDr; +reg SD_DMA_PARTIALr; +always @(posedge CLK) SD_DMA_PARTIALr <= SD_DMA_PARTIAL; + +reg SD_DMA_DONEr; +reg[2:0] SD_DMA_DONEr2; +initial begin + SD_DMA_DONEr2 = 3'b000; + SD_DMA_DONEr = 1'b0; +end +always @(posedge CLK) SD_DMA_DONEr2 <= {SD_DMA_DONEr2[1:0], SD_DMA_DONEr}; +wire SD_DMA_DONE_rising = (SD_DMA_DONEr2[1:0] == 2'b01); + +reg [2:0] SD_DMA_ENr; +initial SD_DMA_ENr = 3'b000; +always @(posedge CLK) SD_DMA_ENr <= {SD_DMA_ENr[1:0], SD_DMA_EN}; +wire SD_DMA_EN_rising = (SD_DMA_ENr [1:0] == 2'b01); + +reg SD_DMA_STATUSr; +assign SD_DMA_STATUS = SD_DMA_STATUSr; + +// we need 1042 cycles (startbit + 1024 nibbles + 16 crc + stopbit) +reg [10:0] cyclecnt; +initial cyclecnt = 11'd0; + +reg SD_DMA_SRAM_WEr; +assign SD_DMA_SRAM_WE = (cyclecnt < 1025 && SD_DMA_STATUSr) ? SD_DMA_SRAM_WEr : 1'b1; + +reg SD_DMA_NEXTADDRr; +assign SD_DMA_NEXTADDR = (cyclecnt < 1025 && SD_DMA_STATUSr) ? SD_DMA_NEXTADDRr : 1'b0; + +reg[7:0] SD_DMA_SRAM_DATAr; +assign SD_DMA_SRAM_DATA = SD_DMA_SRAM_DATAr; + +// we have 4 internal cycles per SD clock +reg [12:0] clkcnt; +initial clkcnt = 13'd0; +reg SD_CLKr; +always @(posedge CLK) SD_CLKr <= clkcnt[1]; +assign SD_CLK = SD_DMA_STATUSr ? SD_CLKr : 1'bZ; + +always @(posedge CLK) begin + if(SD_DMA_EN_rising) begin + SD_DMA_STATUSr <= 1'b1; + SD_DMA_STARTr <= (SD_DMA_PARTIALr ? SD_DMA_PARTIAL_START : 11'h0); + SD_DMA_ENDr <= (SD_DMA_PARTIALr ? SD_DMA_PARTIAL_END : 11'd1024); + end + else if (SD_DMA_DONE_rising) SD_DMA_STATUSr <= 1'b0; +end + +always @(posedge CLK) begin + if(cyclecnt == 1042) SD_DMA_DONEr <= 1; + else SD_DMA_DONEr <= 0; +end + +always @(posedge CLK) begin + if(SD_DMA_EN_rising || !SD_DMA_STATUSr) begin + clkcnt <= 0; + end else begin + if(SD_DMA_STATUSr) begin + clkcnt <= clkcnt + 1; + end + end +end + +always @(posedge CLK) begin + if(SD_DMA_EN_rising || !SD_DMA_STATUSr) cyclecnt <= 0; + else if(clkcnt[1:0] == 2'b11) cyclecnt <= cyclecnt + 1; +end + +// we have 8 clk cycles to complete one RAM write +// (4 clk cycles per SD_CLK; 2 SD_CLK cycles per byte) +always @(posedge CLK) begin + if(SD_DMA_STATUSr) begin + case(clkcnt[2:0]) + 3'h0: begin + SD_DMA_SRAM_WEr <= 1'b1; + SD_DMA_SRAM_DATAr[7:4] <= SD_DAT; + if(cyclecnt>SD_DMA_STARTr && cyclecnt <= SD_DMA_ENDr) SD_DMA_NEXTADDRr <= 1'b1; + end + 3'h1: + SD_DMA_NEXTADDRr <= 1'b0; +// 3'h2: + 3'h3: + if(cyclecnt>=SD_DMA_STARTr && cyclecnt < SD_DMA_ENDr) SD_DMA_SRAM_WEr <= 1'b0; + 3'h4: + SD_DMA_SRAM_DATAr[3:0] <= SD_DAT; +// 3'h5: +// 3'h6: +// 3'h7: + endcase + end +end + +endmodule + diff --git a/verilog/sd2sneslite/spi.v b/verilog/sd2sneslite/spi.v new file mode 100644 index 0000000..ce9a0c3 --- /dev/null +++ b/verilog/sd2sneslite/spi.v @@ -0,0 +1,141 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 21:16:09 07/10/2009 +// Design Name: +// Module Name: spi +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// + +////////////////////////////////////////////////////////////////////////////////// +module spi(input clk, + input SCK, + input MOSI, + inout MISO, + input SSEL, + output cmd_ready, + output param_ready, + output [7:0] cmd_data, + output [7:0] param_data, + output endmessage, + output startmessage, + input [7:0] input_data, + output [31:0] byte_cnt, + output [2:0] bit_cnt + +// SD "DMA" extension + /*input sd_dma_sck, + input sd_dma_ovr*/); + +reg [7:0] cmd_data_r; +reg [7:0] param_data_r; + +// sync SCK to the FPGA clock using a 3-bits shift register +reg [2:0] SCKr; +always @(posedge clk) SCKr <= {SCKr[1:0], SCK}; + +wire SCK_risingedge = (SCKr[1:0]==2'b01); // now we can detect SCK rising edges +wire SCK_fallingedge = (SCKr[1:0]==2'b10); // and falling edges + +// same thing for SSEL +reg [2:0] SSELr; always @(posedge clk) SSELr <= {SSELr[1:0], SSEL}; +wire SSEL_active = ~SSELr[1]; // SSEL is active low +wire SSEL_startmessage = (SSELr[1:0]==2'b10); // message starts at falling edge +wire SSEL_endmessage = (SSELr[1:0]==2'b01); // message stops at rising edge +assign endmessage = SSEL_endmessage; +assign startmessage = SSEL_startmessage; + +// and for MOSI +reg [1:0] MOSIr; always @(posedge clk) MOSIr <= {MOSIr[0], MOSI}; +wire MOSI_data = MOSIr[0]; + +// bit count for one SPI byte + byte count for the message +reg [2:0] bitcnt; +reg [31:0] byte_cnt_r; + +reg byte_received; // high when a byte has been received +reg [7:0] byte_data_received; + +assign bit_cnt = bitcnt; + +always @(posedge clk) +begin + if(~SSEL_active) begin + bitcnt <= 3'b000; + end + else if(SCK_risingedge) begin + bitcnt <= bitcnt + 3'b001; + // shift received data into the register + byte_data_received <= {byte_data_received[6:0], MOSI_data}; + end +end + +always @(posedge clk) byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111); + +always @(posedge clk) begin + if(~SSEL_active) + byte_cnt_r <= 16'h0000; + else if(byte_received) begin + byte_cnt_r <= byte_cnt_r + 16'h0001; + end +end + +reg [7:0] byte_data_sent; + +always @(posedge clk) begin + if(SSEL_active) begin + if(SSEL_startmessage) + byte_data_sent <= 8'h5A; // dummy byte + else + if(SCK_fallingedge) begin + if(bitcnt==3'b000) + byte_data_sent <= input_data; // after that, we send whatever we get + else + byte_data_sent <= {byte_data_sent[6:0], 1'b0}; + end + end +end + +assign MISO = SSEL_active ? byte_data_sent[7] : 1'bZ; // send MSB first + +reg cmd_ready_r; +reg param_ready_r; +reg cmd_ready_r2; +reg param_ready_r2; +assign cmd_ready = cmd_ready_r; +assign param_ready = param_ready_r; +assign cmd_data = cmd_data_r; +assign param_data = param_data_r; +assign byte_cnt = byte_cnt_r; + +always @(posedge clk) cmd_ready_r2 = byte_received && byte_cnt_r == 32'h0; +always @(posedge clk) param_ready_r2 = byte_received && byte_cnt_r > 32'h0; + +// fill registers +always @(posedge clk) begin + if (SSEL_startmessage) + cmd_data_r <= 8'h00; + else if(cmd_ready_r2) + cmd_data_r <= byte_data_received; + else if(param_ready_r2) + param_data_r <= byte_data_received; +end + +// delay ready signals by one clock (why did I do this again...) +always @(posedge clk) begin + cmd_ready_r <= cmd_ready_r2; + param_ready_r <= param_ready_r2; +end + +endmodule