3D LUT for color correction. Fix OAM in save state. (#282)

* Move Cart RAM to SDRAM

Used the SDRAM controller from the NES core

* 3D LUT for color correction. Load custom LUT

* Add custom LUTs

* Fix OAM saving to save state
This commit is contained in:
paulb-nl
2026-04-13 09:23:58 +02:00
committed by GitHub
parent 71fcc15472
commit 016f45bc7b
17 changed files with 4769 additions and 423 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.lut binary

BIN
ColorLUT/dark.lut Normal file

Binary file not shown.

BIN
ColorLUT/def_corrected.lut Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -239,6 +239,7 @@ localparam CONF_STR = {
"h1P1FC3,GBP,Load Palette;",
"P1OG,Frame blend,Off,On;",
"d4P1OU,GBC Colors,Corrected,Raw;",
"H9P1FC7,LUT,Load GBC Color LUT;",
"P1O5,Stabilize video(buffer),Off,On;",
"P1-;",
"P1O34,Aspect ratio,Original,Full Screen,[ARC1],[ARC2];",
@@ -350,6 +351,8 @@ wire sys_auto = (status[15:14] == 0);
wire sys_gbc = (status[15:14] == 2);
wire sys_megaduck = (status[15:14] == 3);
wire gbc_raw_colors = status[30];
hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io
(
.clk_sys(clk_sys),
@@ -360,7 +363,7 @@ hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io
.ioctl_wr(ioctl_wr),
.ioctl_addr(ioctl_addr),
.ioctl_dout(ioctl_dout),
.ioctl_wait(ioctl_wait),
.ioctl_wait(ioctl_wait | save_wait),
.ioctl_index(filetype),
.sd_lba('{sd_lba}),
@@ -377,8 +380,8 @@ hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io
.buttons(buttons),
.status(status),
.status_menumask({7'h0,
fastboot_available,
.status_menumask({6'h0,
gbc_raw_colors, fastboot_available,
sys_megaduck, boot_gba_available, sgb_border_en, isGBC,
cart_ready, sav_supported, |tint, gg_available}),
.status_in({status[63:34],ss_slot,status[31:0]}),
@@ -417,6 +420,7 @@ wire cart_wr;
wire cart_oe;
wire [7:0] cart_di, cart_do;
wire nCS; // WRAM or Cart RAM CS
wire sdram_rd;
wire cart_download = ioctl_download && (filetype[5:0] == 6'h01 || filetype == 8'h80);
wire md_download = ioctl_download && (filetype == 8'h81);
@@ -425,6 +429,7 @@ wire sgb_border_download = ioctl_download && (filetype == 2);
wire cgb_boot_download = ioctl_download && (filetype == 4);
wire dmg_boot_download = ioctl_download && (filetype == 5);
wire sgb_boot_download = ioctl_download && (filetype == 6);
wire cgb_lut_download = ioctl_download && (filetype == 7);
wire boot_download = cgb_boot_download | dmg_boot_download | sgb_boot_download;
///////////////////////////// Bootrom added features ///////////////////////////
@@ -461,52 +466,82 @@ end
////////////////////////////////////////////////////////////////////////////////
wire [1:0] sdram_ds = cart_download ? 2'b11 : {mbc_addr[0], ~mbc_addr[0]};
localparam CARTRAM_BANK = 2'b01;
//wire [1:0] sdram_ds = cart_download ? 2'b11 : {mbc_addr[0], ~mbc_addr[0]};
wire [15:0] sdram_do;
wire [15:0] sdram_di = cart_download ? ioctl_dout : 16'd0;
wire [23:0] sdram_addr = cart_download? ioctl_addr[24:1]: {2'b00, mbc_addr[22:1]};
wire sdram_oe = ~cart_download & cart_rd & ~cram_rd;
wire sdram_we = cart_download & dn_write;
wire sdram_refresh_force;
wire sdram_autorefresh = !ff_on;
wire [15:0] sdram_di = cart_download ? ioctl_dout :
savestate_ovr ? Savestate_CRAMWriteData :
cart_di;
assign SDRAM_CKE = 1;
wire [24:0] sdram_addr = cart_download ? ioctl_addr[24:0] :
(savestate_ovr | is_cram_addr) ? { CARTRAM_BANK, 6'd0, cram_addr } :
{2'b00, mbc_addr[22:0]};
sdram sdram (
// interface to the MT48LC16M16 chip
.sd_data ( SDRAM_DQ ),
.sd_addr ( SDRAM_A ),
.sd_dqm ( {SDRAM_DQMH, SDRAM_DQML} ),
.sd_cs ( SDRAM_nCS ),
.sd_ba ( SDRAM_BA ),
.sd_we ( SDRAM_nWE ),
.sd_ras ( SDRAM_nRAS ),
.sd_cas ( SDRAM_nCAS ),
.sd_clk ( SDRAM_CLK ),
wire sdram_oe = ~cart_download & (savestate_ovr ? Savestate_CRAMRdEn : sdram_rd);
wire sdram_we = (cart_download & dn_write) | cram_wr;
wire sdram_pause_refresh;
wire sdram_busy;
// system interface
.clk ( clk_ram ),
.sync ( ce_cpu2x ),
.init ( ~pll_locked ),
wire [15:0] save_dout;
// cpu interface
.din ( sdram_di ),
.addr ( sdram_addr ),
.ds ( sdram_ds ),
.we ( sdram_we ),
.oe ( sdram_oe ),
.autorefresh ( sdram_autorefresh ),
.refresh ( sdram_refresh_force ),
.dout ( sdram_do )
assign Savestate_CRAMReadData = bram_save ? Savestate_CRAM_Q : sdram_do;
sdram sdram
(
.SDRAM_DQ(SDRAM_DQ),
.SDRAM_A(SDRAM_A),
.SDRAM_DQML(SDRAM_DQML),
.SDRAM_DQMH(SDRAM_DQMH),
.SDRAM_BA(SDRAM_BA),
.SDRAM_nCS(SDRAM_nCS),
.SDRAM_nWE(SDRAM_nWE),
.SDRAM_nRAS(SDRAM_nRAS),
.SDRAM_nCAS(SDRAM_nCAS),
.SDRAM_CLK(SDRAM_CLK),
.SDRAM_CKE(SDRAM_CKE),
// system interface
.clk ( clk_ram ),
.init (0), //~clock_locked),
// ROM + Cart RAM
.ch0_addr ( sdram_addr ),
.ch0_wr ( sdram_we ),
.ch0_din ( sdram_di ),
.ch0_rd ( sdram_oe ),
.ch0_dout ( sdram_do ),
.ch0_word ( cart_download | savestate_ovr),
.ch0_busy ( sdram_busy),
// HPS Cart RAM Save/Load
.ch1_addr ( { CARTRAM_BANK, 6'd0, save_addr, 1'b0 } ),
.ch1_wr ( save_wr ),
.ch1_din ( bk_data ),
.ch1_rd ( save_rd ),
.ch1_dout ( save_dout ),
.ch1_word ( 1'b1 ),
.ch1_busy ( save_busy ),
.ch2_addr ( 0 ),
.ch2_wr ( 0 ),
.ch2_din ( 0 ),
.ch2_rd ( 0 ),
.ch2_dout ( ),
.ch2_busy ( ),
.refresh ( sdram_pause_refresh )
);
wire dn_write;
wire cart_ready;
wire cram_rd, cram_wr;
wire [7:0] rom_do = (mbc_addr[0]) ? sdram_do[15:8] : sdram_do[7:0];
wire cram_rd, cram_wr, cram_bram_wr, is_cram_addr;
wire [16:0] cram_addr;
wire [15:0] Savestate_CRAM_Q;
wire [7:0] ram_mask_file, cart_ram_size;
wire isGBC_game, isSGB_game;
wire cart_has_save;
wire cart_has_save, bram_save;
wire [31:0] RTC_timestampOut;
wire [47:0] RTC_savedtimeOut;
wire RTC_inuse;
@@ -552,14 +587,18 @@ cart_top cart (
.dn_write ( dn_write ),
.cart_ready ( cart_ready ),
.is_cram_addr( is_cram_addr),
.cram_rd ( cram_rd ),
.cram_wr ( cram_wr ),
.cram_bram_wr( cram_bram_wr ),
.cram_addr ( cram_addr ),
.cart_download ( cart_download ),
.ram_mask_file ( ram_mask_file ),
.ram_size ( cart_ram_size ),
.has_save ( cart_has_save ),
.bram_save ( bram_save ),
.isGBC_game ( isGBC_game ),
.isSGB_game ( isSGB_game ),
@@ -577,7 +616,7 @@ cart_top cart (
.bk_q ( bk_q ),
.img_size ( img_size ),
.rom_di ( rom_do ),
.rom_di ( sdram_do[7:0] ),
.joystick_analog_0 ( joystick_analog_0 ),
@@ -593,12 +632,12 @@ cart_top cart (
.SaveStateExt_rst ( SaveStateBus_rst ),
.SaveStateExt_Dout( SaveStateBus_Dout ),
.savestate_load ( savestate_load ),
.sleep_savestate ( sleep_savestate ),
.savestate_ovr ( savestate_ovr ),
.Savestate_CRAMAddr ( Savestate_CRAMAddr ),
.Savestate_CRAMRWrEn ( Savestate_CRAMRWrEn ),
.Savestate_CRAMWriteData( Savestate_CRAMWriteData ),
.Savestate_CRAMReadData ( Savestate_CRAMReadData ),
.Savestate_CRAM_Q ( Savestate_CRAM_Q ),
.rumbling (rumbling)
);
@@ -672,6 +711,8 @@ gb gb (
.nCS ( nCS ),
.sdram_rd ( sdram_rd ),
.boot_gba_en ( boot_gba_available && status[37] ),
.fast_boot_en ( fastboot_available && status[42] ),
@@ -719,6 +760,7 @@ gb gb (
.load_state (ss_load),
.savestate_number(ss_slot),
.sleep_savestate (sleep_savestate),
.savestate_ovr (savestate_ovr),
.SaveStateExt_Din (SaveStateBus_Din),
.SaveStateExt_Adr (SaveStateBus_Adr),
@@ -728,6 +770,7 @@ gb gb (
.SaveStateExt_load(savestate_load),
.Savestate_CRAMAddr (Savestate_CRAMAddr),
.Savestate_CRAMRdEn (Savestate_CRAMRdEn),
.Savestate_CRAMRWrEn (Savestate_CRAMRWrEn),
.Savestate_CRAMWriteData(Savestate_CRAMWriteData),
.Savestate_CRAMReadData (Savestate_CRAMReadData),
@@ -740,6 +783,8 @@ gb gb (
.SAVE_out_be(ss_be),
.SAVE_out_done(ss_ack), // should be one cycle high when write is done or read value is valid
.savestate_sdram_busy(sdram_busy),
.rewind_on(status[27]),
.rewind_active(status[27] & joystick_0[10])
);
@@ -775,7 +820,7 @@ lcd lcd
.inv ( status[12] ),
.double_buffer( status[5]),
.frame_blend( status[16] ),
.originalcolors( status[30] ),
.originalcolors( gbc_raw_colors ),
.analog_wide ( status[34] ),
// Palettes
@@ -784,6 +829,11 @@ lcd lcd
.pal3 (palette[79:56]),
.pal4 (palette[55:32]),
.lut_download (cgb_lut_download),
.ioctl_wr (ioctl_wr),
.ioctl_addr (ioctl_addr),
.ioctl_dout (ioctl_dout),
.sgb_border_pix ( sgb_border_pix),
.sgb_pal_en ( sgb_pal_en ),
.sgb_en ( sgb_border_en ),
@@ -901,9 +951,8 @@ wire ce_cpu, ce_cpu_n, ce_cpu2x;
wire cart_act = cart_wr | cart_rd;
wire fastforward = joystick_0[8] && !ioctl_download && !OSD_STATUS;
wire ff_on;
wire sleep_savestate;
wire sleep_savestate, savestate_ovr;
reg paused;
always_ff @(posedge clk_sys) begin
@@ -916,12 +965,13 @@ speedcontrol speedcontrol
.pause (paused),
.speedup (fast_forward),
.cart_act (cart_act),
.save_act (bk_state),
.DMA_on (DMA_on),
.ce (ce_cpu),
.ce_n (ce_cpu_n),
.ce_2x (ce_cpu2x),
.refresh (sdram_refresh_force),
.ff_on (ff_on)
.refresh (sdram_pause_refresh),
.ff_on ()
);
///////////////////////////// Fast Forward Latch /////////////////////////////////
@@ -966,9 +1016,10 @@ wire [63:0] SaveStateBus_Dout;
wire savestate_load;
wire [19:0] Savestate_CRAMAddr;
wire Savestate_CRAMRdEn;
wire Savestate_CRAMRWrEn;
wire [7:0] Savestate_CRAMWriteData;
wire [7:0] Savestate_CRAMReadData;
wire [15:0] Savestate_CRAMWriteData;
wire [15:0] Savestate_CRAMReadData;
wire [63:0] ss_dout, ss_din;
wire [27:2] ss_addr;
@@ -1121,18 +1172,7 @@ assign USER_OUT[0] = (serial_ena & sc_int_clock_out) ? ser_clk_out : 1'b1;
///////////////////////// BRAM SAVE/LOAD /////////////////////////////
wire [16:0] bk_addr = {sd_lba[7:0],sd_buff_addr};
wire bk_wr = (sd_lba[7:0] > ram_mask_file) ? 1'b0 : sd_buff_wr & sd_ack; // only restore data amount of saveram, don't save on RTC data
wire bk_rtc_wr = (sd_lba[7:0] > ram_mask_file) & sd_buff_wr & sd_ack;
wire [15:0] bk_data = sd_buff_dout;
wire [15:0] bk_q;
assign sd_buff_din = (sd_lba[7:0] <= ram_mask_file) ? bk_q : // normal saveram data or RTC data
(sd_buff_addr == 8'd0) ? RTC_timestampOut[15:0] :
(sd_buff_addr == 8'd1) ? RTC_timestampOut[31:16] :
(sd_buff_addr == 8'd2) ? RTC_savedtimeOut[15:0] :
(sd_buff_addr == 8'd3) ? RTC_savedtimeOut[31:16] :
(sd_buff_addr == 8'd4) ? RTC_savedtimeOut[47:32] :
16'hFFFF;
@@ -1156,7 +1196,7 @@ always @(posedge clk_sys) begin
else if (bk_state)
new_load <= 1'b0;
if (cram_wr & ~OSD_STATUS & sav_supported)
if ((cram_wr | cram_bram_wr) & ~OSD_STATUS & sav_supported)
sav_pending <= 1'b1;
else if (bk_state)
sav_pending <= 1'b0;
@@ -1210,6 +1250,48 @@ always @(posedge clk_sys) begin
end
end
wire [15:0] bk_addr = {sd_lba[7:0],sd_buff_addr};
wire bk_addr_end = (sd_lba[7:0] > ram_mask_file);
wire bk_wr = bk_addr_end ? 1'b0 : sd_buff_wr & sd_ack; // only restore data amount of saveram, don't save on RTC data
wire bk_rtc_wr = bk_addr_end & sd_buff_wr & sd_ack;
wire [15:0] bk_data = sd_buff_dout;
wire [15:0] bk_q;
assign sd_buff_din = (sd_lba[7:0] <= ram_mask_file) ? ( bram_save ? bk_q : save_dout ) : // normal saveram data or RTC data
(sd_buff_addr == 8'd0) ? RTC_timestampOut[15:0] :
(sd_buff_addr == 8'd1) ? RTC_timestampOut[31:16] :
(sd_buff_addr == 8'd2) ? RTC_savedtimeOut[15:0] :
(sd_buff_addr == 8'd3) ? RTC_savedtimeOut[31:16] :
(sd_buff_addr == 8'd4) ? RTC_savedtimeOut[47:32] :
16'hFFFF;
wire save_busy;
reg save_rd, save_wr;
reg save_wait;
reg [15:0] save_addr;
always @(posedge clk_sys) begin
if(~save_busy & ~save_rd & ~save_wr) save_wait <= 0;
if(~bk_state) begin
save_addr <= '1;
save_wait <= 0;
end else if(sd_ack & ~save_busy) begin
if( ~bk_loading & ~bk_addr_end & (save_addr != bk_addr) ) begin
save_rd <= 1;
save_addr <= bk_addr;
save_wait <= 1;
end
if( bk_loading & ~bk_addr_end & sd_buff_wr ) begin
save_wr <= 1;
save_addr <= bk_addr;
save_wait <= 1;
end
end
if(~bk_state | save_busy) {save_rd, save_wr} <= 0;
end
endmodule

View File

@@ -100,6 +100,7 @@ entity GBse is
A : out std_logic_vector(15 downto 0);
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0);
phi_early : out std_logic; -- for SDRAM
isGBC : in std_logic; -- Gameboy Color
-- savestates
SaveStateBus_Din : in std_logic_vector(BUS_buswidth-1 downto 0);
@@ -147,6 +148,8 @@ begin
SaveStateBus_Dout <= wired_or;
end process;
phi_early <= not TState(1) and not TState(0);
u0 : T80
generic map
(

View File

@@ -24,14 +24,18 @@ module cart_top (
output reg dn_write,
output cart_ready,
output is_cram_addr,
output cram_rd,
output cram_wr,
output cram_bram_wr,
output [16:0] cram_addr,
input cart_download,
output [7:0] ram_mask_file,
output [7:0] ram_size,
output has_save,
output bram_save,
output isGBC_game,
output isSGB_game,
@@ -65,12 +69,12 @@ module cart_top (
input SaveStateExt_rst,
output [63:0] SaveStateExt_Dout,
input savestate_load,
input sleep_savestate,
input savestate_ovr,
input [19:0] Savestate_CRAMAddr,
input Savestate_CRAMRWrEn,
input [7:0] Savestate_CRAMWriteData,
output [7:0] Savestate_CRAMReadData,
input [15:0] Savestate_CRAMWriteData,
output [15:0] Savestate_CRAM_Q,
output rumbling
);
///////////////////////////////////////////////////
@@ -98,7 +102,7 @@ eReg_SavestateV #(0, 37, 63, 0, 64'h0000000000000000) iREG_SAVESTATE_Ext2 (clk_s
assign SaveStateExt_Dout = SaveStateBus_Dout_or[0] | SaveStateBus_Dout_or[1];
wire [7:0] rom_do;
wire [7:0] cram_do;
wire [7:0] mbc_cram_do;
wire [16:0] mbc_cram_addr;
wire mbc_ram_enable, mbc_battery;
wire mbc_cram_wr;
@@ -174,8 +178,8 @@ mappers mappers (
.nCS ( nCS ),
.cram_rd ( cram_rd ),
.cram_di ( cram_q ),
.cram_do ( cram_do ),
.cram_di ( bram_save ? cram_q : rom_di ),
.cram_do ( mbc_cram_do ),
.cram_addr ( mbc_cram_addr ),
.cram_wr_do ( mbc_cram_wr_do ),
@@ -388,32 +392,30 @@ reg [7:0] cart_do_r;
always @* begin
if (~cart_ready)
cart_do_r = 8'h00;
else if (cram_rd)
cart_do_r = cram_do;
else if (is_cram_addr)
cart_do_r = mbc_cram_do;
else
cart_do_r = rom_do;
end
assign cart_do = cart_do_r;
reg read_low = 0;
always @(posedge clk_sys) begin
read_low <= cram_addr[0];
end
assign Savestate_CRAMReadData = read_low ? cram_q_h : cram_q_l;
wire [7:0] cram_q_h, cram_q_l;
wire [7:0] cram_q = cram_addr[0] ? cram_q_h : cram_q_l;
wire [7:0] cram_q_h;
wire [7:0] cram_q_l;
wire is_cram_addr = ~nCS & ~cart_addr[14];
assign is_cram_addr = ~nCS & ~cart_addr[14];
assign cram_rd = cart_rd & is_cram_addr;
assign cram_wr = sleep_savestate ? Savestate_CRAMRWrEn : mbc_cram_wr || (cart_wr & is_cram_addr & mbc_ram_enable);
assign cram_wr = savestate_ovr ? Savestate_CRAMRWrEn : (cart_wr & is_cram_addr & mbc_ram_enable);
assign cram_bram_wr = savestate_ovr ? (Savestate_CRAMRWrEn & ~|Savestate_CRAMAddr[16:8]) : mbc_cram_wr;
wire [16:0] cram_addr = sleep_savestate ? Savestate_CRAMAddr[16:0] : mbc_cram_addr;
wire [7:0] cram_di = sleep_savestate ? Savestate_CRAMWriteData : mbc_cram_wr ? mbc_cram_wr_do : cart_di;
assign cram_addr = savestate_ovr ? Savestate_CRAMAddr[16:0] : mbc_cram_addr;
wire [7:0] cram_di_l = savestate_ovr ? Savestate_CRAMWriteData[ 7:0] : mbc_cram_wr_do;
wire [7:0] cram_di_h = savestate_ovr ? Savestate_CRAMWriteData[15:8] : mbc_cram_wr_do;
assign Savestate_CRAM_Q = { cram_q_h, cram_q_l };
assign bram_save = mbc7 | tama;
// RAM size
assign ram_mask_file = // 0 - no ram
@@ -426,31 +428,30 @@ assign ram_mask_file = // 0 - no ram
assign has_save = mbc_battery && (|ram_size || mbc2 || mbc7 || tama);
// Up to 8kb * 16banks of Cart Ram (128kb)
dpram #(16) cram_l (
dpram #(7) cram_bram_l (
.clock_a (clk_sys),
.address_a (cram_addr[16:1]),
.wren_a (cram_wr & ~cram_addr[0]),
.data_a (cram_di),
.address_a (cram_addr[7:1]),
.wren_a (cram_bram_wr & (~cram_addr[0] | savestate_ovr)),
.data_a (cram_di_l),
.q_a (cram_q_l),
.clock_b (clk_sys),
.address_b (bk_addr[15:0]),
.wren_b (bk_wr),
.address_b (bk_addr[6:0]),
.wren_b (bk_wr & ~|bk_addr[16:7]),
.data_b (bk_data[7:0]),
.q_b (bk_q[7:0])
);
dpram #(16) cram_h (
dpram #(7) cram_bram_h (
.clock_a (clk_sys),
.address_a (cram_addr[16:1]),
.wren_a (cram_wr & cram_addr[0]),
.data_a (cram_di),
.address_a (cram_addr[7:1]),
.wren_a (cram_bram_wr & (cram_addr[0] | savestate_ovr)),
.data_a (cram_di_h),
.q_a (cram_q_h),
.clock_b (clk_sys),
.address_b (bk_addr[15:0]),
.wren_b (bk_wr),
.address_b (bk_addr[6:0]),
.wren_b (bk_wr & ~|bk_addr[16:7]),
.data_b (bk_data[15:8]),
.q_b (bk_q[15:8])
);

View File

@@ -7,7 +7,8 @@ USE altera_mf.altera_mf_components.all;
ENTITY dpram IS
generic (
addr_width : integer := 8;
data_width : integer := 8
data_width : integer := 8;
mem_init_file : string := " "
);
PORT
(
@@ -50,6 +51,7 @@ BEGIN
power_up_uninitialized => "FALSE",
read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ",
init_file => mem_init_file,
widthad_a => addr_width,
widthad_b => addr_width,
width_a => data_width,

View File

@@ -46,6 +46,8 @@ module gb (
// WRAM or Cart RAM CS
output nCS,
output sdram_rd,
input cgb_boot_download,
input dmg_boot_download,
input sgb_boot_download,
@@ -98,6 +100,7 @@ module gb (
input load_state,
input [1:0] savestate_number,
output sleep_savestate,
output savestate_ovr,
output [63:0] SaveStateExt_Din,
output [9:0] SaveStateExt_Adr,
@@ -107,9 +110,10 @@ module gb (
output SaveStateExt_load,
output [19:0] Savestate_CRAMAddr,
output Savestate_CRAMRdEn,
output Savestate_CRAMRWrEn,
output [7:0] Savestate_CRAMWriteData,
input [7:0] Savestate_CRAMReadData,
output [15:0] Savestate_CRAMWriteData,
input [15:0] Savestate_CRAMReadData,
output [63:0] SAVE_out_Din, // data read from savestate
input [63:0] SAVE_out_Dout, // data written to savestate
@@ -119,6 +123,8 @@ module gb (
output [7:0] SAVE_out_be,
input SAVE_out_done, // should be one cycle high when write is done or read value is valid
input savestate_sdram_busy,
input rewind_on,
input rewind_active
);
@@ -128,9 +134,10 @@ wire [63:0] SaveStateBus_Din;
wire [9:0] SaveStateBus_Adr;
wire SaveStateBus_wren, SaveStateBus_rst;
wire [7:0] Savestate_RAMWriteData;
wire [15:0] Savestate_RAMWriteData;
wire [7:0] Savestate_RAMReadData_WRAM, Savestate_RAMReadData_VRAM, Savestate_RAMReadData_ORAM, Savestate_RAMReadData_ZRAM;
wire [19:0] Savestate_RAMAddr;
wire [4:0] Savestate_RAMRdEn;
wire [4:0] Savestate_RAMRWrEn;
localparam SAVESTATE_MODULES = 8;
@@ -239,6 +246,7 @@ reg vram_bank; //0-1 FF4F - VBK
wire [7:0] hdma_do;
wire hdma_active;
wire hdma_rd_clk;
reg cpu_speed; // - 0 Normal mode (4MHz) - 1 Double Speed Mode (8MHz)
reg prepare_switch; // set to 1 to toggle speed
@@ -297,6 +305,7 @@ wire cpu_rd_n;
wire cpu_iorq_n;
wire cpu_m1_n;
wire cpu_mreq_n;
wire cpu_phi_early;
wire clk = clk_sys & ce;
@@ -307,6 +316,8 @@ wire clk_cpu = clk_sys & ce_cpu;
wire hdma_cpu_stop = (isGBC & hdma_active & cpu_rd_n & cpu_wr_n);
wire cpu_clken = ~hdma_cpu_stop & ce_cpu;
assign sdram_rd = ~cpu_phi_early | hdma_rd_clk; // For SDRAM read & refresh
reg reset_r = 1;
wire reset_ss;
@@ -366,6 +377,7 @@ GBse cpu (
.DI ( genie_ovr ? genie_data : cpu_di),
.DO ( cpu_do ),
.STOP ( cpu_stop ),
.phi_early ( cpu_phi_early ),
.isGBC ( isGBC ),
// savestates
.SaveStateBus_Din (SaveStateBus_Din ),
@@ -733,7 +745,7 @@ video video (
.Savestate_OAMRAMAddr (Savestate_RAMAddr[7:0]),
.Savestate_OAMRAMRWrEn (Savestate_RAMRWrEn[2]),
.Savestate_OAMRAMWriteData (Savestate_RAMWriteData),
.Savestate_OAMRAMWriteData (Savestate_RAMWriteData[7:0]),
.Savestate_OAMRAMReadData (Savestate_RAMReadData_ORAM),
.SaveStateBus_Din (SaveStateBus_Din ),
@@ -770,7 +782,7 @@ dpram #(13) vram0 (
.clock_b (clk_sys),
.address_b (Savestate_RAMAddr[12:0]),
.wren_b (Savestate_RAMRWrEn[1] & !Savestate_RAMAddr[13]),
.data_b (Savestate_RAMWriteData),
.data_b (Savestate_RAMWriteData[7:0]),
.q_b (Savestate_RAMReadData_VRAM0)
);
@@ -785,7 +797,7 @@ dpram #(13) vram1 (
.clock_b (clk_sys),
.address_b (Savestate_RAMAddr[12:0]),
.wren_b (Savestate_RAMRWrEn[1] & Savestate_RAMAddr[13]),
.data_b (Savestate_RAMWriteData),
.data_b (Savestate_RAMWriteData[7:0]),
.q_b (Savestate_RAMReadData_VRAM1)
);
@@ -826,6 +838,7 @@ hdma hdma(
// dma connection
.hdma_rd ( hdma_rd ),
.hdma_active ( hdma_active ),
.hdma_rd_clk ( hdma_rd_clk ),
.hdma_source_addr ( hdma_source_addr ),
.hdma_target_addr ( hdma_target_addr ),
@@ -853,7 +866,7 @@ dpram #(7) zpram (
.clock_b (clk_sys),
.address_b (Savestate_RAMAddr[6:0]),
.wren_b (Savestate_RAMRWrEn[3]),
.data_b (Savestate_RAMWriteData),
.data_b (Savestate_RAMWriteData[7:0]),
.q_b (Savestate_RAMReadData_ZRAM)
);
@@ -888,7 +901,7 @@ dpram #(15) wram (
.clock_b (clk_sys),
.address_b (Savestate_RAMAddr[14:0]),
.wren_b (Savestate_RAMRWrEn[0]),
.data_b (Savestate_RAMWriteData),
.data_b (Savestate_RAMWriteData[7:0]),
.q_b (Savestate_RAMReadData_WRAM)
);
@@ -1024,7 +1037,7 @@ assign ext_bus_a15 = ext_bus_i[15] | sel_boot_rom;
assign ext_bus_addr = ext_bus_i[14:0];
assign ext_bus_rd = hdma_read_ext_bus | dma_read_ext_bus | (sel_ext_bus & ~cpu_rd_n);
assign ext_bus_wr = (sel_ext_bus & ~cpu_wr_n_edge) & ~hdma_read_ext_bus & ~dma_read_ext_bus;
assign ext_bus_wr = (sel_ext_bus & ~cpu_wr_n) & ~hdma_read_ext_bus & ~dma_read_ext_bus;
assign ext_bus_wram_sel = ~nCS & ext_bus_addr[14];
assign ext_bus_cram_sel = ~nCS & ~ext_bus_addr[14];
@@ -1056,6 +1069,7 @@ assign SaveStateExt_rst = SaveStateBus_rst;
assign SaveStateExt_load = savestate_loaded;
assign Savestate_CRAMAddr = Savestate_RAMAddr;
assign Savestate_CRAMRdEn = Savestate_RAMRdEn[4];
assign Savestate_CRAMRWrEn = Savestate_RAMRWrEn[4];
assign Savestate_CRAMWriteData = Savestate_RAMWriteData;
@@ -1064,6 +1078,7 @@ wire [63:0] SaveStateBus_Dout = SaveStateBus_wired_or[0] | SaveStateBus_wired_o
SaveStateExt_Dout;
wire sleep_rewind, sleep_savestates;
wire loading_savestate, saving_savestate;
gb_savestates gb_savestates (
.clk (clk_sys),
@@ -1088,12 +1103,15 @@ gb_savestates gb_savestates (
.BUS_rst (SaveStateBus_rst),
.BUS_Dout (SaveStateBus_Dout),
//.loading_savestate (loading_savestate),
//.saving_savestate (saving_savestate),
.loading_savestate (loading_savestate),
.saving_savestate (saving_savestate),
.sleep_savestate (sleep_savestates),
.clock_ena_in (ce_2x),
.memory_busy (savestate_sdram_busy),
.Save_RAMAddr (Savestate_RAMAddr),
.Save_RAMRdEn (Savestate_RAMRdEn),
.Save_RAMWrEn (Savestate_RAMRWrEn),
.Save_RAMWriteData (Savestate_RAMWriteData),
.Save_RAMReadData_WRAM (Savestate_RAMReadData_WRAM),
@@ -1132,6 +1150,6 @@ gb_statemanager #(58720256, 33554432) gb_statemanager (
);
assign sleep_savestate = sleep_rewind | sleep_savestates;
assign savestate_ovr = loading_savestate | saving_savestate;
endmodule

View File

@@ -33,15 +33,18 @@ entity gb_savestates is
saving_savestate : out std_logic := '0';
sleep_savestate : out std_logic := '0';
clock_ena_in : in std_logic;
memory_busy : in std_logic;
Save_RAMAddr : buffer std_logic_vector(19 downto 0) := (others => '0');
Save_RAMWrEn : out std_logic_vector(4 downto 0) := (others => '0');
Save_RAMWriteData : out std_logic_vector(7 downto 0) := (others => '0');
Save_RAMRdEn : buffer std_logic_vector(4 downto 0) := (others => '0');
Save_RAMWrEn : buffer std_logic_vector(4 downto 0) := (others => '0');
Save_RAMWriteData : out std_logic_vector(15 downto 0) := (others => '0');
Save_RAMReadData_WRAM : in std_logic_vector(7 downto 0);
Save_RAMReadData_VRAM : in std_logic_vector(7 downto 0);
Save_RAMReadData_ORAM : in std_logic_vector(7 downto 0);
Save_RAMReadData_ZRAM : in std_logic_vector(7 downto 0);
Save_RAMReadData_CRAM : in std_logic_vector(7 downto 0);
Save_RAMReadData_CRAM : in std_logic_vector(15 downto 0);
bus_out_Din : out std_logic_vector(63 downto 0) := (others => '0');
bus_out_Dout : in std_logic_vector(63 downto 0);
@@ -90,8 +93,10 @@ architecture arch of gb_savestates is
LOADINTERNALS_READ,
LOADINTERNALS_WRITE,
LOADMEMORY_NEXT,
LOADMEMORY_NEXT_WAIT,
LOADMEMORY_READ,
LOADMEMORY_WRITE
LOADMEMORY_WRITE,
LOAD_FINISH
);
signal state : tstate := IDLE;
@@ -101,11 +106,17 @@ architecture arch of gb_savestates is
signal settle : integer range 0 to SETTLECOUNT := 0;
signal bytecounter : integer range 0 to 7 := 0;
signal Save_RAMReadData : std_logic_vector(7 downto 0);
signal Save_RAMReadDataH : std_logic_vector(7 downto 0);
signal RAMAddrNext : std_logic_vector(19 downto 0) := (others => '0');
signal header_amount : unsigned(31 downto 0) := (others => '0');
signal memory_is_slow : std_logic;
signal memory_is_word : std_logic;
signal memory_ready : std_logic;
begin
savestate_busy <= '0' when state = IDLE else '1';
@@ -114,13 +125,20 @@ begin
Save_RAMReadData_VRAM when savetype_counter = 1 else
Save_RAMReadData_ORAM when savetype_counter = 2 else
Save_RAMReadData_ZRAM when savetype_counter = 3 else
Save_RAMReadData_CRAM;
Save_RAMReadData_CRAM(7 downto 0);
Save_RAMReadDataH <= Save_RAMReadData_CRAM(15 downto 8);
memory_is_slow <= '1' when savetype_counter = 4 else '0';
memory_is_word <= '1' when savetype_counter = 4 else '0';
memory_ready <= '1' when memory_is_slow = '0'
or (memory_busy = '0' and Save_RAMRdEn = "00000" and Save_RAMWrEn = "00000")
else '0';
process (clk)
begin
if rising_edge(clk) then
Save_RAMWrEn <= (others => '0');
bus_out_ena <= '0';
BUS_wren <= '0';
BUS_rst <= '0';
@@ -136,6 +154,11 @@ begin
when x"03" => savetypes(4) <= 32768; -- 32 KByte
when others => savetypes(4) <= 131072; -- 128 KByte
end case;
if (memory_is_slow = '0' or memory_busy = '1') then
Save_RAMRdEn <= (others => '0');
Save_RAMWrEn <= (others => '0');
end if;
case state is
@@ -198,11 +221,16 @@ begin
when SAVEMEMORY_NEXT =>
if (savetype_counter < SAVETYPESCOUNT) then
state <= SAVEMEMORY_FIRST;
if (memory_is_slow = '1') then
state <= SAVEMEMORY_READ;
else
state <= SAVEMEMORY_FIRST;
end if;
bytecounter <= 0;
count <= 8;
maxcount <= savetypes(savetype_counter);
Save_RAMAddr <= (others => '0');
Save_RAMRdEn(savetype_counter) <= '1';
else
state <= SAVESIZEAMOUNT;
bus_out_Adr <= std_logic_vector(to_unsigned(savestate_address, 26));
@@ -215,18 +243,35 @@ begin
when SAVEMEMORY_FIRST =>
state <= SAVEMEMORY_READ;
Save_RAMAddr <= std_logic_vector(unsigned(Save_RAMAddr) + 1);
if (memory_is_word = '1') then
Save_RAMAddr <= std_logic_vector(unsigned(Save_RAMAddr) + 2);
else
Save_RAMAddr <= std_logic_vector(unsigned(Save_RAMAddr) + 1);
end if;
Save_RAMRdEn(savetype_counter) <= '1';
when SAVEMEMORY_READ =>
bus_out_Din(bytecounter * 8 + 7 downto bytecounter * 8) <= Save_RAMReadData;
if (bytecounter < 7) then
bytecounter <= bytecounter + 1;
Save_RAMAddr <= std_logic_vector(unsigned(Save_RAMAddr) + 1);
else
state <= SAVEMEMORY_WRITE;
bus_out_ena <= '1';
if (memory_ready = '1') then
if (memory_is_word = '1') then
bus_out_Din(bytecounter * 8 + 15 downto bytecounter * 8) <= Save_RAMReadDataH & Save_RAMReadData;
else
bus_out_Din(bytecounter * 8 + 7 downto bytecounter * 8) <= Save_RAMReadData;
end if;
if (memory_is_word = '1' and bytecounter < 6) then
bytecounter <= bytecounter + 2;
Save_RAMAddr <= std_logic_vector(unsigned(Save_RAMAddr) + 2);
Save_RAMRdEn(savetype_counter) <= '1';
elsif (memory_is_word = '0' and bytecounter < 7) then
bytecounter <= bytecounter + 1;
Save_RAMAddr <= std_logic_vector(unsigned(Save_RAMAddr) + 1);
Save_RAMRdEn(savetype_counter) <= '1';
else
state <= SAVEMEMORY_WRITE;
bus_out_ena <= '1';
end if;
end if;
when SAVEMEMORY_WRITE =>
if (bus_out_done = '1') then
bus_out_Adr <= std_logic_vector(unsigned(bus_out_Adr) + 2);
@@ -309,10 +354,8 @@ begin
bytecounter <= 0;
bus_out_ena <= '1';
else
state <= IDLE;
state <= LOAD_FINISH;
reset_out <= '1';
loading_savestate <= '0';
sleep_savestate <= '0';
load_done <= '1';
end if;
@@ -322,25 +365,45 @@ begin
end if;
when LOADMEMORY_WRITE =>
RAMAddrNext <= std_logic_vector(unsigned(RAMAddrNext) + 1);
Save_RAMAddr <= RAMAddrNext;
Save_RAMWrEn(savetype_counter) <= '1';
Save_RAMWriteData <= bus_out_Dout(bytecounter * 8 + 7 downto bytecounter * 8);
if (bytecounter < 7) then
bytecounter <= bytecounter + 1;
else
bus_out_Adr <= std_logic_vector(unsigned(bus_out_Adr) + 2);
if (count < maxcount) then
state <= LOADMEMORY_READ;
count <= count + 8;
bytecounter <= 0;
bus_out_ena <= '1';
else
savetype_counter <= savetype_counter + 1;
state <= LOADMEMORY_NEXT;
if (memory_ready = '1') then
if (memory_is_word = '1') then
RAMAddrNext <= std_logic_vector(unsigned(RAMAddrNext) + 2);
else
RAMAddrNext <= std_logic_vector(unsigned(RAMAddrNext) + 1);
end if;
Save_RAMAddr <= RAMAddrNext;
Save_RAMWrEn(savetype_counter) <= '1';
Save_RAMWriteData( 7 downto 0) <= bus_out_Dout(bytecounter * 8 + 7 downto bytecounter * 8);
Save_RAMWriteData(15 downto 8) <= bus_out_Dout(bytecounter * 8 + 15 downto bytecounter * 8 + 8);
if (memory_is_word = '1' and bytecounter < 6) then
bytecounter <= bytecounter + 2;
elsif (memory_is_word = '0' and bytecounter < 7) then
bytecounter <= bytecounter + 1;
else
bus_out_Adr <= std_logic_vector(unsigned(bus_out_Adr) + 2);
if (count < maxcount) then
state <= LOADMEMORY_READ;
count <= count + 8;
bytecounter <= 0;
bus_out_ena <= '1';
else
state <= LOADMEMORY_NEXT_WAIT;
end if;
end if;
end if;
when LOADMEMORY_NEXT_WAIT =>
if (memory_ready = '1') then
savetype_counter <= savetype_counter + 1;
state <= LOADMEMORY_NEXT;
end if;
when LOAD_FINISH =>
state <= IDLE;
loading_savestate <= '0';
sleep_savestate <= '0';
end case;
end if;

View File

@@ -16,6 +16,7 @@ module hdma(
// dma connection
output reg hdma_rd,
output reg hdma_active,
output hdma_rd_clk,
output [15:0] hdma_source_addr,
output [15:0] hdma_target_addr,
@@ -53,6 +54,7 @@ wire [1:0] byte_cycles = speed ? 2'd3 : 2'd1;
reg [1:0] hdma_cnt;
//assign hdma_rd = hdma_active;
assign hdma_rd_clk = hdma_rd & (hdma_cnt != byte_cycles);
assign hdma_source_addr = { hdma_source, byte_cnt };
assign hdma_target_addr = { hdma_target, byte_cnt };

View File

@@ -23,6 +23,11 @@ module lcd
input [23:0] pal3,
input [23:0] pal4,
input lut_download,
input ioctl_wr,
input [15:0] ioctl_addr,
input [15:0] ioctl_dout,
input [15:0] sgb_border_pix,
input sgb_pal_en,
input sgb_en,
@@ -301,38 +306,68 @@ function [7:0] blend;
end
endfunction
reg [3:0] color_lut_sr;
wire [7:0] color_lut_dout;
// Color LUT 16bit to 24bit writes
reg [23:0] color_lut_data;
reg [7:0] color_lut_temp;
reg [1:0] color_cnt;
reg [14:0] color_lut_wr_addr;
reg color_lut_wr, prev_color_lut_wr;
reg prev_lut_download;
always@(posedge clk_sys) begin
prev_lut_download <= lut_download;
wire [9:0] color_lut_addr =
color_lut_sr[0] ? { r5, r5 } : // red only
color_lut_sr[1] ? { b5, g5 } : // mixed blue + green
{ b5, b5 }; // blue only
if (~prev_lut_download & lut_download) begin
color_cnt <= 2'd0;
color_lut_wr_addr <= 15'd0;
end
// Color LUT for mix of 2 colors with 2 stage gamma
dpram_dif #(10,8,10,8,"lcd_color_lut.mif") lcd_color_lut (
.clock (clk_vid),
prev_color_lut_wr <= color_lut_wr;
if (prev_color_lut_wr & ~color_lut_wr) begin
color_lut_wr_addr <= color_lut_wr_addr + 1'b1;
end
.address_a (color_lut_addr),
.q_a (color_lut_dout)
);
reg [7:0] r_lut, g_lut, b_lut;
always@(posedge clk_vid) begin
color_lut_sr <= { color_lut_sr[2:0], (ce_pix | ce_pix_n) };
if (color_lut_sr[1]) begin r_lut <= color_lut_dout; end
if (color_lut_sr[2]) begin g_lut <= color_lut_dout; end
if (color_lut_sr[3]) begin b_lut <= color_lut_dout; end
color_lut_wr <= 0;
if (lut_download & ioctl_wr) begin
color_cnt <= color_cnt + 1'b1;
case (color_cnt)
2'd0: begin
color_lut_data[15:0] <= ioctl_dout[15:0];
end
2'd1: begin
color_lut_data[23:16] <= ioctl_dout[7:0];
color_lut_temp <= ioctl_dout[15:8];
color_lut_wr <= 1'b1;
end
2'd2: begin
color_lut_data[23:0] <= { ioctl_dout[15:0], color_lut_temp };
color_lut_wr <= 1'b1;
color_cnt <= 2'd0;
end
endcase
end
end
wire [23:0] color_lut_dout;
// Color 3D LUT
dpram #(15,24, "lcd_color_lut.mif") lcd_color_lut (
.clock_a (clk_vid),
.address_a ( { r5, g5, b5 } ),
.q_a (color_lut_dout),
.clock_b (clk_sys),
.address_b (color_lut_wr_addr),
.data_b (color_lut_data),
.wren_b (color_lut_wr),
.q_b ()
);
reg [7:0] r_tmp, g_tmp, b_tmp;
always@(*) begin
if (~sgb_pal_en & isGBC & !originalcolors) begin
r_tmp = r_lut;
g_tmp = g_lut;
b_tmp = b_lut;
r_tmp = color_lut_dout[7:0];
g_tmp = color_lut_dout[15:8];
b_tmp = color_lut_dout[23:16];
end else if (sgb_pal_en | (isGBC & originalcolors)) begin
r_tmp = {r5,r5[4:2]};
g_tmp = {g5,g5[4:2]};

File diff suppressed because it is too large Load Diff

View File

@@ -72,6 +72,7 @@ reg reg_start;
reg cram_wr_r;
reg ram_io;
reg prev_cram_rd;
reg prev_cart_wr;
reg [6:0] rtc_seconds;
reg [14:0] rtc_subseconds;
@@ -107,7 +108,8 @@ assign savestate_back[ 34] = reg_start;
assign savestate_back[ 35] = cram_wr_r;
assign savestate_back[ 36] = ram_io;
assign savestate_back[ 37] = prev_cram_rd;
assign savestate_back[63:38] = 0;
assign savestate_back[ 38] = prev_cart_wr;
assign savestate_back[63:39] = 0;
always @(posedge clk_sys) begin
if(savestate_load & enable) begin
@@ -123,6 +125,7 @@ always @(posedge clk_sys) begin
cram_wr_r <= savestate_data[ 35]; //1'd0;
ram_io <= savestate_data[ 36]; //1'd0;
prev_cram_rd <= savestate_data[ 37]; //1'd0;
prev_cart_wr <= savestate_data[ 38]; //1'd0;
end else if(~enable) begin
rom_bank_reg <= 5'd0;
unlocked <= 1'd0;
@@ -136,27 +139,31 @@ always @(posedge clk_sys) begin
cram_wr_r <= 1'd0;
ram_io <= 1'd0;
prev_cram_rd <= 1'd0;
prev_cart_wr <= 1'd0;
end else begin
if (ce_cpu & cart_wr & ~nCS & ~cart_addr[14]) begin // $A000-BFFF
if (cart_addr[0]) begin
reg_index <= cart_di[3:0]; // Register index
if (cart_di[3:0] == 4'hA) begin
unlocked <= 1'b1;
if (ce_cpu) begin
prev_cart_wr <= cart_wr;
if (prev_cart_wr & ~cart_wr & ~nCS & ~cart_addr[14]) begin // $A000-BFFF
if (cart_addr[0]) begin
reg_index <= cart_di[3:0]; // Register index
if (cart_di[3:0] == 4'hA) begin
unlocked <= 1'b1;
end
end else if (unlocked) begin
case (reg_index)
4'd0: rom_bank_reg[3:0] <= cart_di[3:0];
4'd1: rom_bank_reg[4] <= cart_di[0];
4'd4: reg_data_in[3:0] <= cart_di[3:0];
4'd5: reg_data_in[7:4] <= cart_di[3:0];
4'd6: { rtc_sel, ram_read, reg_addr[4] } <= cart_di[3:0];
4'd7: begin
reg_addr[3:0] <= cart_di[3:0];
reg_start <= 1'b1;
end
default ;
endcase
end
end else if (unlocked) begin
case (reg_index)
4'd0: rom_bank_reg[3:0] <= cart_di[3:0];
4'd1: rom_bank_reg[4] <= cart_di[0];
4'd4: reg_data_in[3:0] <= cart_di[3:0];
4'd5: reg_data_in[7:4] <= cart_di[3:0];
4'd6: { rtc_sel, ram_read, reg_addr[4] } <= cart_di[3:0];
4'd7: begin
reg_addr[3:0] <= cart_di[3:0];
reg_start <= 1'b1;
end
default ;
endcase
end
end

View File

@@ -1,9 +1,9 @@
//
// sdram.v
// This version issues refresh only when 8bit channel reads the same 16bit word 2 times
//
// sdram controller implementation for the MiST/MiSTer boards
//
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
// Copyright (c) 2017 Sorgelig
// sdram controller implementation
// Copyright (c) 2018 Sorgelig
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
@@ -19,180 +19,260 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
//
// This SDRAM module provides/writes the data in 8 cycles of clock.
// So, with 64MHz of system clock, it can emulate 8MHz asynchronous DRAM.
//
//
module sdram
(
// interface to the MT48LC16M16 chip
inout reg [15:0] sd_data, // 16 bit bidirectional data bus
output reg [12:0] sd_addr, // 13 bit multiplexed address bus
output [1:0] sd_dqm, // two byte masks
output reg [1:0] sd_ba, // two banks
output sd_cs, // a single chip select
output sd_we, // write enable
output sd_ras, // row address select
output sd_cas, // columns address select
output sd_clk,
inout reg [15:0] SDRAM_DQ, // 16 bit bidirectional data bus
output reg [12:0] SDRAM_A, // 13 bit multiplexed address bus
output reg SDRAM_DQML, // byte mask
output reg SDRAM_DQMH, // byte mask
output reg [1:0] SDRAM_BA, // two banks
output reg SDRAM_nCS, // a single chip select
output reg SDRAM_nWE, // write enable
output reg SDRAM_nRAS, // row address select
output reg SDRAM_nCAS, // columns address select
output SDRAM_CLK,
output SDRAM_CKE,
// cpu/chipset interface
input init, // init signal after FPGA config to initialize RAM
input clk, // sdram is accessed at 64MHz
input sync,
input init, // init signal after FPGA config to initialize RAM
input clk, // sdram is accessed at up to 128MHz
input [15:0] din, // data input from chipset/cpu
output reg [15:0] dout, // data output to chipset/cpu
input [23:0] addr, // 24 bit word address
input [1:0] ds, // upper/lower data strobe
input oe, // cpu/chipset requests read
input we, // cpu/chipset requests write
input autorefresh,// autorefresh when no read or write required
input refresh // force refresh when core is paused or fastforward
input [24:0] ch0_addr,
input ch0_rd,
input ch0_wr,
input ch0_word,
input [15:0] ch0_din,
output reg [15:0] ch0_dout,
output reg ch0_busy,
input [24:0] ch1_addr,
input ch1_rd,
input ch1_wr,
input ch1_word,
input [15:0] ch1_din,
output reg [15:0] ch1_dout,
output reg ch1_busy,
input [24:0] ch2_addr,
input ch2_rd,
input ch2_wr,
input [7:0] ch2_din,
output reg [7:0] ch2_dout,
output reg ch2_busy,
input refresh
);
localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 3 cycles@128MHz
localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8
localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved
localparam CAS_LATENCY = 3'd2; // 2/3 allowed
localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed
localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write
assign SDRAM_nCS = 0;
assign SDRAM_CKE = 1;
assign {SDRAM_DQMH,SDRAM_DQML} = SDRAM_A[12:11];
localparam RASCAS_DELAY = 3'd1; // tRCD=20ns -> 2 cycles@85MHz
localparam BURST_LENGTH = 3'd0; // 0=1, 1=2, 2=4, 3=8, 7=full page
localparam ACCESS_TYPE = 1'd0; // 0=sequential, 1=interleaved
localparam CAS_LATENCY = 3'd2; // 2/3 allowed
localparam OP_MODE = 2'd0; // only 0 (standard operation) allowed
localparam NO_WRITE_BURST = 1'd1; // 0=write burst enabled, 1=only single access write
localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH};
localparam STATE_IDLE = 3'd0; // state to check the requests
localparam STATE_START = STATE_IDLE+1'd1; // state in which a new command is started
localparam STATE_NEXT = STATE_START+1'd1; // state in which a new command is started
localparam STATE_CONT = STATE_START+RASCAS_DELAY;
localparam STATE_READY = STATE_CONT+CAS_LATENCY+2'd2;
localparam STATE_LAST = STATE_READY; // last state in cycle
// ---------------------------------------------------------------------
// ------------------------ cycle state machine ------------------------
// ---------------------------------------------------------------------
reg [2:0] state;
reg [22:0] a;
reg [1:0] bank;
reg [15:0] data;
reg we;
reg ds;
reg ram_req=0;
// The state machine runs at 128Mhz synchronous to the 8 Mhz chipset clock.
// It wraps from T15 to T0 on the rising edge of clk_8
wire [2:0] rd,wr;
localparam STATE_FIRST = 3'd0; // first state in cycle
localparam STATE_CMD_START = 3'd1; // state in which a new command can be started
localparam STATE_CMD_CONT = STATE_CMD_START + RASCAS_DELAY; // command can be continued
localparam STATE_READ = STATE_CMD_CONT + CAS_LATENCY + 4'd1;
localparam STATE_HIGHZ = STATE_READ - 4'd1; // disable output to prevent contention
assign rd = {ch2_rd, ch1_rd, ch0_rd};
assign wr = {ch2_wr, ch1_wr, ch0_wr};
// ---------------------------------------------------------------------
// --------------------------- startup/reset ---------------------------
// ---------------------------------------------------------------------
// wait 1ms (32 8Mhz cycles) after FPGA config is done before going
// into normal operation. Initialize the ram in the last 16 reset cycles (cycles 15-0)
reg [4:0] reset;
// access manager
always @(posedge clk) begin
if(init) reset <= 5'h1f;
else if((stage == STATE_FIRST) && (reset != 0))
reset <= reset - 5'd1;
end
reg old_ref;
reg [2:0] old_rd,old_wr;//,rd,wr;
reg [24:1] last_a[3] = '{'1,'1,'1};
// ---------------------------------------------------------------------
// ------------------ generate ram control signals ---------------------
// ---------------------------------------------------------------------
old_rd <= old_rd & rd;
old_wr <= old_wr & wr;
// all possible commands
localparam CMD_INHIBIT = 4'b1111;
localparam CMD_NOP = 4'b0111;
localparam CMD_ACTIVE = 4'b0011;
localparam CMD_READ = 4'b0101;
localparam CMD_WRITE = 4'b0100;
localparam CMD_BURST_TERMINATE = 4'b0110;
localparam CMD_PRECHARGE = 4'b0010;
localparam CMD_AUTO_REFRESH = 4'b0001;
localparam CMD_LOAD_MODE = 4'b0000;
reg [3:0] sd_cmd; // current command sent to sd ram
// drive control signals according to current command
assign sd_cs = sd_cmd[3];
assign sd_ras = sd_cmd[2];
assign sd_cas = sd_cmd[1];
assign sd_we = sd_cmd[0];
assign sd_dqm = sd_addr[12:11];
reg [1:0] mode;
reg [15:0] din_r;
reg [2:0] stage;
always @(posedge clk) begin
reg [12:0] addr_r;
reg old_sync;
reg old_oe;
if(|stage) stage <= stage + 1'd1;
old_sync <= sync;
old_oe <= oe;
if(~old_sync && sync && autorefresh) stage <= 1; // normal operation with read/write and refresh
if(refresh && stage == STATE_FIRST) stage <= 1; // forced refresh when paused or fastforward
if(~old_oe && oe && ~autorefresh) stage <= 1; // react on request only with fastforward
sd_cmd <= CMD_INHIBIT; // default: idle
sd_data <= 16'hZZZZ;
if(reset != 0) begin
// initialization takes place at the end of the reset phase
if(stage == STATE_CMD_START) begin
if(reset == 13) begin
sd_cmd <= CMD_PRECHARGE;
sd_addr[10] <= 1'b1; // precharge all banks
end
if(reset == 2) begin
sd_cmd <= CMD_LOAD_MODE;
sd_addr <= MODE;
end
if(state == STATE_IDLE && mode == MODE_NORMAL) begin
ram_req <= 0;
we <= 0;
ch0_busy <= 0;
ch1_busy <= 0;
ch2_busy <= 0;
if((~old_rd[0] & rd[0]) | (~old_wr[0] & wr[0])) begin
old_rd[0] <= rd[0];
old_wr[0] <= wr[0];
we <= wr[0];
ds <= ch0_word;
{bank,a} <= ch0_addr;
data <= ch0_word ? ch0_din : {ch0_din[7:0],ch0_din[7:0]};
ram_req <= wr[0] || (last_a[0] != ch0_addr[24:1]);
last_a[0] <= wr[0] ? '1 : ch0_addr[24:1];
ch0_busy <= 1;
state <= STATE_START;
end
mode <= 0;
end else begin
// normal operation
if(stage == STATE_CMD_START) begin
if(we || oe) begin
mode <= {we, oe};
// RAS phase
sd_cmd <= CMD_ACTIVE;
sd_addr <= { 1'b0, addr[19:8] };
sd_ba <= addr[21:20];
din_r <= din;
addr_r <= { we ? ~ds : 2'b00, 2'b10, addr[22], addr[7:0] }; // auto precharge
end
else if (autorefresh || refresh) begin
sd_cmd <= CMD_AUTO_REFRESH;
mode <= 0;
end
else if((~old_rd[1] & rd[1]) | (~old_wr[1] & wr[1])) begin
old_rd[1] <= rd[1];
old_wr[1] <= wr[1];
we <= wr[1];
ds <= ch1_word;
{bank,a} <= ch1_addr;
data <= ch1_word ? ch1_din : {ch1_din[7:0],ch1_din[7:0]};
ram_req <= wr[1] || (last_a[1] != ch1_addr[24:1]);
last_a[1] <= wr[1] ? '1 : ch1_addr[24:1];
ch1_busy <= 1;
state <= STATE_START;
end
// CAS phase
if(stage == STATE_CMD_CONT && mode) begin
sd_cmd <= mode[1] ? CMD_WRITE : CMD_READ;
sd_addr <= addr_r;
if(mode[1]) sd_data <= din_r;
else if((~old_rd[2] & rd[2]) | (~old_wr[2] & wr[2])) begin
old_rd[2] <= rd[2];
old_wr[2] <= wr[2];
we <= wr[2];
ds <= 0;
{bank,a} <= ch2_addr;
data <= {ch2_din,ch2_din};
ram_req <= wr[2] || (last_a[2] != ch2_addr[24:1]);
last_a[2] <= wr[2] ? '1 : ch2_addr[24:1];
ch2_busy <= 1;
state <= STATE_START;
end
if(stage == STATE_HIGHZ) begin
sd_addr[12:11] <= 2'b11; // disable chip output
mode[1] <= 0; // disable data output
end
if(stage == STATE_READ && mode) begin
dout <= sd_data;
else if (refresh) begin
ram_req <= 1'b0;
we <= 1'b0;
state <= STATE_START;
end
end
if (state == STATE_READY) begin
ch0_busy <= 0;
ch1_busy <= 0;
ch2_busy <= 0;
end
if(mode != MODE_NORMAL || state != STATE_IDLE || reset) begin
state <= state + 1'd1;
if(state == STATE_LAST) state <= STATE_IDLE;
end
end
localparam MODE_NORMAL = 2'b00;
localparam MODE_RESET = 2'b01;
localparam MODE_LDM = 2'b10;
localparam MODE_PRE = 2'b11;
// initialization
reg [1:0] mode;
reg [4:0] reset=5'h1f;
always @(posedge clk) begin
reg init_old=0;
init_old <= init;
if(init_old & ~init) reset <= 5'h1f;
else if(state == STATE_LAST) begin
if(reset != 0) begin
reset <= reset - 5'd1;
if(reset == 14) mode <= MODE_PRE;
else if(reset == 3) mode <= MODE_LDM;
else mode <= MODE_RESET;
end
else mode <= MODE_NORMAL;
end
end
localparam CMD_NOP = 3'b111;
localparam CMD_ACTIVE = 3'b011;
localparam CMD_READ = 3'b101;
localparam CMD_WRITE = 3'b100;
localparam CMD_BURST_TERMINATE = 3'b110;
localparam CMD_PRECHARGE = 3'b010;
localparam CMD_AUTO_REFRESH = 3'b001;
localparam CMD_LOAD_MODE = 3'b000;
wire [1:0] dqm = {we & ~ds & ~a[0], we & ~ds & a[0]};
// SDRAM state machines
always @(posedge clk) begin
reg [15:0] last_data[3];
reg [15:0] data_reg;
if(state == STATE_START) SDRAM_BA <= (mode == MODE_NORMAL) ? bank : 2'b00;
SDRAM_DQ <= 'Z;
casex({ram_req,we,mode,state})
{2'b1X, MODE_NORMAL, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_ACTIVE;
{2'b11, MODE_NORMAL, STATE_CONT }: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE, SDRAM_DQ} <= {CMD_WRITE, data};
{2'b10, MODE_NORMAL, STATE_CONT }: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_READ;
{2'b0X, MODE_NORMAL, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_AUTO_REFRESH;
// init
{2'bXX, MODE_LDM, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_LOAD_MODE;
{2'bXX, MODE_PRE, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_PRECHARGE;
default: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_NOP;
endcase
casex({ram_req,mode,state})
{1'b1, MODE_NORMAL, STATE_START}: SDRAM_A <= a[13:1];
{1'b1, MODE_NORMAL, STATE_CONT }: SDRAM_A <= {dqm, 2'b10, a[22:14]};
// init
{1'bX, MODE_LDM, STATE_START}: SDRAM_A <= MODE;
{1'bX, MODE_PRE, STATE_START}: SDRAM_A <= 13'b0010000000000;
default: SDRAM_A <= 13'b0000000000000;
endcase
data_reg <= SDRAM_DQ;
if(state == STATE_READY) begin
if(ch0_busy) begin
if(ram_req) begin
if(we) ch0_dout <= data;
else begin
ch0_dout <= (~ch0_word & a[0]) ? {data_reg[7:0], data_reg[15:8]} : data_reg;
last_data[0] <= data_reg;
end
end
else ch0_dout <= (~ch0_word & a[0]) ? {last_data[0][7:0], last_data[0][15:8]} : last_data[0];
end
if(ch1_busy) begin
if(ram_req) begin
if(we) ch1_dout <= data;
else begin
ch1_dout <= (~ch1_word & a[0]) ? {data_reg[7:0], data_reg[15:8]} : data_reg;
last_data[1] <= data_reg;
end
end
else ch1_dout <= (~ch1_word & a[0]) ? {last_data[1][7:0], last_data[1][15:8]} : last_data[1];
end
if(ch2_busy) begin
if(ram_req) begin
if(we) ch2_dout <= data[7:0];
else begin
ch2_dout <= a[0] ? data_reg[15:8] : data_reg[7:0];
last_data[2] <= data_reg;
end
end
else ch2_dout <= a[0] ? last_data[2][15:8] : last_data[2][7:0];
end
end
end
altddio_out
#(
.extend_oe_disable("OFF"),
@@ -209,7 +289,7 @@ sdramclk_ddr
.datain_h(1'b0),
.datain_l(1'b1),
.outclock(clk),
.dataout(sd_clk),
.dataout(SDRAM_CLK),
.aclr(1'b0),
.aset(1'b0),
.oe(1'b1),

View File

@@ -9,6 +9,7 @@ entity speedcontrol is
pause : in std_logic;
speedup : in std_logic;
cart_act : in std_logic;
save_act : in std_logic;
DMA_on : in std_logic;
ce : out std_logic := '0';
ce_n : out std_logic := '0';
@@ -64,7 +65,7 @@ begin
if (pause = '1' and clkdiv = "111" and cart_act = '0') then
state <= PAUSED;
unpause_cnt <= 0;
elsif (speedup = '1' and pause = '0' and DMA_on = '0' and clkdiv = "000") then
elsif (speedup = '1' and pause = '0' and DMA_on = '0' and save_act = '0' and clkdiv = "000") then
state <= FASTFORWARDSTART;
fastforward_cnt <= 0;
else
@@ -82,7 +83,11 @@ begin
when PAUSED =>
if (unpause_cnt = 0) then
refresh <= '1';
if (refreshcnt > 117) then
refresh <= '1';
elsif (refreshcnt = 0) then
refreshcnt <= 127;
end if;
end if;
if (pause = '0') then
@@ -102,7 +107,7 @@ begin
end if;
when FASTFORWARD =>
if (pause = '1' or speedup = '0' or DMA_on = '1') then
if (pause = '1' or speedup = '0' or DMA_on = '1' or save_act = '1') then
state <= FASTFORWARDEND;
fastforward_cnt <= 0;
if (clkdiv(0) = '1') then
@@ -111,11 +116,12 @@ begin
elsif (cart_act = '1' and cart_act_1 = '0') then
state <= RAMACCESS;
sdram_busy <= 1;
elsif (cart_act = '0' and refreshcnt = 0) then
refreshcnt <= 127;
refresh <= '1';
state <= RAMACCESS;
sdram_busy <= 1;
-- Refresh is already done in current SDRAM controller
--elsif (cart_act = '0' and refreshcnt = 0) then
-- refreshcnt <= 127;
-- refresh <= '1';
-- state <= RAMACCESS;
-- sdram_busy <= 1;
else
clkdiv(0) <= not clkdiv(0);
if (clkdiv(0) = '0') then

View File

@@ -129,7 +129,12 @@ dpram #(7,8) oam_data_h (
.q_b (Savestate_OAMRAMReadDataH)
);
assign Savestate_OAMRAMReadData = Savestate_OAMRAMAddr[0] ? Savestate_OAMRAMReadDataH : Savestate_OAMRAMReadDataL;
reg Savestate_OAMRAMAddr0_d;
always @(posedge clk) begin
Savestate_OAMRAMAddr0_d <= Savestate_OAMRAMAddr[0];
end
assign Savestate_OAMRAMReadData = Savestate_OAMRAMAddr0_d ? Savestate_OAMRAMReadDataH : Savestate_OAMRAMReadDataL;
reg [7:0] sprite_x[0:SPRITES_PER_LINE-1];
reg [3:0] sprite_y[0:SPRITES_PER_LINE-1];