1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-05-04 07:19:29 +00:00
Files
mist-devel.mist-board/cores/c64/rtl/cartridge.v
2018-09-05 23:27:12 +02:00

567 lines
14 KiB
Verilog

module cartridge
(
input romL, // romL signal in
input romH, // romH signal in
input UMAXromH, // romH VIC II address signal
input IOE, // IOE control signal
input IOF, // IOF control signal
input mem_write, // memory write active
input mem_ce,
output mem_ce_out,
input clk32, // 32mhz clock source
input reset, // reset signal
output reg reset_out, // reset signal
input [15:0] cart_id, // cart ID or cart type
input [7:0] cart_exrom, // CRT file EXROM status
input [7:0] cart_game, // CRT file GAME status
input [15:0] cart_bank_laddr, // bank loading address
input [15:0] cart_bank_size, // length of each bank
input [15:0] cart_bank_num,
input [7:0] cart_bank_type,
input [24:0] cart_bank_raddr, // chip packet address
input cart_bank_wr,
input cart_attached, // FLAG to say cart has been loaded
input cart_loading,
input [15:0] c64_mem_address_in, // address from cpu
input [7:0] c64_data_out, // data from cpu going to sdram
output [24:0] sdram_address_out, // translated address output
output exrom, // exrom line
output game, // game line
output reg IOE_ena, // FLAG to enable IOE address relocation
output reg IOF_ena, // FLAG to enable IOF address relocation
output reg max_ram, // Enable whole C64 RAM in Ultimax mode
input freeze_key,
output reg nmi,
input nmi_ack
);
reg [24:0] addr_out;
assign sdram_address_out = addr_out;
reg [6:0] bank_lo;
reg [6:0] bank_hi;
reg [12:0] mask_lo;
reg [6:0] IOE_bank;
reg [6:0] IOF_bank;
reg IOE_wr_ena;
reg IOF_wr_ena;
reg exrom_overide;
reg game_overide;
assign exrom = ~cart_attached | exrom_overide;
assign game = ~cart_attached | game_overide;
(* ramstyle = "logic" *) reg [6:0] lobanks[0:63];
(* ramstyle = "logic" *) reg [6:0] hibanks[0:63];
reg [7:0] bank_cnt;
always @(posedge clk32) begin
reg old_loading;
old_loading <= cart_loading;
if(~old_loading & cart_loading) bank_cnt <= 0;
if(cart_bank_wr) begin
bank_cnt <= bank_cnt + 1'd1;
if(cart_bank_num<64) begin
if(cart_bank_laddr <= 'h8000) begin
lobanks[cart_bank_num[5:0]] <= cart_bank_raddr[19:13];
if(cart_bank_size > 'h2000) hibanks[cart_bank_num[5:0]] <= cart_bank_raddr[19:13]+1'd1;
end
else hibanks[cart_bank_num[5:0]] <= cart_bank_raddr[19:13];
end
end
end
reg romL_we = 0;
reg romH_we = 0;
reg old_ioe, old_iof;
always @(posedge clk32) begin
old_ioe <= IOE;
old_iof <= IOF;
end
wire stb_ioe = (~old_ioe & IOE);
wire stb_iof = (~old_iof & IOF);
wire ioe_wr = stb_ioe & mem_write;
wire ioe_rd = stb_ioe & ~mem_write;
wire iof_wr = stb_iof & mem_write;
//wire iof_rd = stb_iof & ~mem_write;
reg old_freeze = 0;
wire freeze_req = (~old_freeze & freeze_key);
reg old_nmiack = 0;
wire freeze_ack = (nmi & ~old_nmiack & nmi_ack);
// 0018 - EXROM line status
// 0019 - GAME line status
always @(posedge clk32) begin
reg init_n = 0;
reg allow_freeze = 0;
reg saved_d6 = 0;
reg [15:0] count;
reg count_ena;
reg cart_disable = 0;
old_freeze <= freeze_key;
if(freeze_req & allow_freeze) nmi <= 1;
old_nmiack <= nmi_ack;
if(freeze_ack) nmi <= 0;
if(!reset) begin
cart_disable <= 0;
bank_lo <= 0;
bank_hi <= 0;
IOE_ena <= 0;
IOF_ena <= 0;
IOE_wr_ena <= 0;
IOF_wr_ena <= 0;
romL_we <= 0;
romH_we <= 0;
reset_out <= 0;
init_n <= 0;
allow_freeze <= 1;
nmi <= 0;
saved_d6 <= 0;
mask_lo <= 13'h1FFF;
exrom_overide <= 1;
game_overide <= 1;
max_ram <= 0;
end
else
case(cart_id)
// Generic 8k(exrom=0,game=1), 16k(exrom=0,game=0), ULTIMAX(exrom=1,game=0)
0: begin
exrom_overide <= cart_exrom[0];
game_overide <= cart_game[0];
bank_lo <= lobanks[0];
bank_hi <= hibanks[0];
end
// Action Replay v4+ - (32k 4x8k banks + 8K RAM)
// controlled by DE00
1: begin
if(nmi) allow_freeze <= 0;
if(!init_n || freeze_ack) begin
cart_disable <= 0;
exrom_overide <= 1;
game_overide <= 0;
romL_we <= 0;
bank_lo <= 0;
bank_hi <= 0;
IOF_bank <= 0;
IOF_wr_ena <= 0;
IOF_ena <= 1;
if(~init_n) begin
init_n <= 1;
exrom_overide <= 0;
game_overide <= 1;
end
end
else if(cart_disable) begin
exrom_overide <= 1;
game_overide <= 1;
IOF_ena <= 0;
IOF_wr_ena <= 0;
romL_we <= 0;
allow_freeze <= 1;
end else begin
if(ioe_wr) begin
cart_disable <= c64_data_out[2];
bank_lo <= c64_data_out[4:3];
bank_hi <= c64_data_out[4:3];
IOF_bank <= c64_data_out[4:3];
if(c64_data_out[6] | allow_freeze) begin
allow_freeze <= 1;
game_overide <= ~c64_data_out[0];
exrom_overide <= c64_data_out[1];
IOF_wr_ena <= c64_data_out[5];
romL_we <= c64_data_out[5];
if(c64_data_out[5]) begin
bank_lo <= 0;
IOF_bank<= 0;
end
end
end
end
end
// Final Cart III - (64k 4x16k banks)
// all banks @ $8000-$BFFF - switching by $DFFF
3: begin
if(!init_n) begin
init_n <= 1;
game_overide <= 0;
exrom_overide<= 0;
cart_disable <= 0;
bank_lo <= 0;
bank_hi <= 1;
IOE_ena <= 1;
IOE_bank<= 0;
IOF_ena <= 1;
IOF_bank<= 0;
end
else if(!cart_disable) begin
if(iof_wr && &c64_mem_address_in[7:0]) begin
bank_lo <= {c64_data_out[1:0],1'd0};
bank_hi <= {c64_data_out[1:0],1'd1};
IOE_bank<= {c64_data_out[1:0],1'd0};
IOF_bank<= {c64_data_out[1:0],1'd0};
exrom_overide <= c64_data_out[4];
game_overide <= c64_data_out[5];
saved_d6 <= c64_data_out[6];
if(~freeze_key & saved_d6 & ~c64_data_out[6]) nmi <= 1;
if(c64_data_out[6]) allow_freeze <= 1;
cart_disable <= c64_data_out[7];
end
end
if(freeze_ack) begin
cart_disable <= 0;
game_overide <= 0;
allow_freeze <= 0;
end
end
// Simons Basic - (game=0, exrom=0, 2 banks by 8k)
// Read to IOE switches 8k config
// Write to IOE switches 16k config
4: begin
if(!init_n) begin
init_n <= 1;
exrom_overide <= 0;
game_overide <= 0;
bank_lo <= 0;
bank_hi <= 1;
end
if(ioe_wr) game_overide <= 0;
if(ioe_rd) game_overide <= 1;
end
// Ocean Type 1 - (game=0, exrom=0, 128k,256k or 512k in 8k banks)
// BANK is written to lower 6 bits of $DE00 - bit 8 is always set
// best to mirror banks at $8000 and $A000
5: begin
exrom_overide <= 0;
game_overide <= 0;
if(ioe_wr) begin
bank_lo <= c64_data_out[5:0];
bank_hi <= c64_data_out[5:0];
end
end
// PowerPlay, FunPlay
7: begin
if(~init_n) begin
init_n <= 1;
exrom_overide <= 0;
game_overide <= 1;
end
if(ioe_wr) begin
bank_lo <= {c64_data_out[0],c64_data_out[5:3]};
if({c64_data_out[7:6],c64_data_out[2:1]} == 'b1011) exrom_overide <= 1;
if({c64_data_out[7:6],c64_data_out[2:1]} == 'b0000) exrom_overide <= 0;
end
end
// "Super Games"
8: begin
if(~init_n) begin
init_n <= 1;
exrom_overide <= 0;
game_overide <= 0;
bank_lo <= 0;
bank_hi <= 1;
end
if(~cart_disable & iof_wr) begin
bank_lo <= {c64_data_out[1:0],1'd0};
bank_hi <= {c64_data_out[1:0],1'd1};
game_overide <= c64_data_out[2];
exrom_overide <= c64_data_out[2];
cart_disable <= c64_data_out[3];
end
end
// Epyx Fastload - (game=1, exrom=0, 8k bank)
// any access to romL or $DE00 charges a capacitor
// Once discharged the exrom drops to ON disabling cart
10: begin
if(!init_n) count_ena <= 0;
if(IOE || romL) count_ena <= 1;
if(!init_n || IOE || romL) begin
init_n <= 1;
game_overide <= 1;
exrom_overide <= 0;
count <= 16384;
IOF_ena <= 1;
IOF_bank<= 0;
end
else
if(count_ena) begin
if(count) count <= count - 1'd1;
else exrom_overide <= 1;
end
end
// FINAL CARTRIDGE 1,2
// 16k rom - IOE turns off rom / IOF turns rom on
13: begin
if(!init_n) begin
init_n <= 1;
bank_lo <= 0;
bank_hi <= 1;
game_overide <= 0;
exrom_overide <= 0;
// Last 2 pages visible at IOE / IOF
IOE_bank <= 0;
IOF_bank <= 0;
IOE_ena <= 1;
IOF_ena <= 1;
end
if(freeze_ack) begin
game_overide <= 0;
allow_freeze <= 0;
end
if(IOE) begin
game_overide <= 1;
exrom_overide <= 1;
allow_freeze <= 1;
end
if(IOF) begin
game_overide <= 0;
exrom_overide <= 0;
end
end
// C64GS - (game=1, exrom=0, 64 banks by 8k)
// 8k config
// Reading from IOE ($DE00 $DEFF) switches to bank 0
15: begin
game_overide <= 1;
exrom_overide <= 0;
if(ioe_rd) bank_lo <= 0;
if(ioe_wr) bank_lo <= c64_mem_address_in[5:0];
end
// Dinamic - (game=1, exrom=0, 16 banks by 8k)
17: begin
game_overide <= 1;
exrom_overide <= 0;
if(ioe_rd) bank_lo <= c64_mem_address_in[3:0];
end
// Zaxxon, Super Zaxxon (game=0, exrom=0 - 4Kb + 2x8KB)
18: begin
mask_lo <= 'hFFF;
game_overide <= 0;
exrom_overide <= 0;
if(romL & mem_ce & ~c64_mem_address_in[12]) bank_hi <= 1;
if(romL & mem_ce & c64_mem_address_in[12]) bank_hi <= 2;
end
// Magic Desk - (game=1, exrom=0 = 4/8/16 8k banks)
19: begin
if(!init_n) begin
init_n <= 1;
game_overide <= 1;
exrom_overide <= 0;
bank_lo <= 0;
end
if(ioe_wr) begin
bank_lo <= c64_data_out[3:0];
exrom_overide <= c64_data_out[7];
end
end
// Super Snapshot v5 -(64k rom 8*8k banks/4*16k banks, 32k ram 4*8k banks)
20: begin
if(!init_n || freeze_ack) begin
init_n <= 1;
romL_we <= 1;
bank_lo <= 0;
bank_hi <= 1;
game_overide <= 0;
exrom_overide <= 1;
IOE_bank <= 0;
IOE_ena <= 1;
cart_disable <= 0;
end
else
if(~cart_disable & ioe_wr) begin
game_overide <= c64_data_out[0] | c64_data_out[3];
exrom_overide<= ~c64_data_out[1] | c64_data_out[3];
bank_lo <= {c64_data_out[4], c64_data_out[2], 1'b0};
bank_hi <= {c64_data_out[4], c64_data_out[2], 1'b1};
IOE_bank<= {c64_data_out[4], c64_data_out[2], 1'b0};
cart_disable <= c64_data_out[3];
IOE_ena <= ~c64_data_out[3];
//RAM overlay
if(~c64_data_out[1]) bank_lo <= {c64_data_out[4], c64_data_out[2]};
romL_we <= ~c64_data_out[1];
end
end
// Comal80 - (game=0, exrom=0, 4 banks by 16k)
21: begin
if(!init_n) begin
init_n <= 1;
bank_lo <= 0;
bank_hi <= 1;
game_overide <= 0;
exrom_overide <= 0;
end
if(ioe_wr) begin
case(c64_data_out[7:5])
'b010:
begin
exrom_overide <= 0;
game_overide <= 1;
end
'b111:
begin
exrom_overide <= 1;
game_overide <= 1;
end
default:
begin
exrom_overide <= 0;
game_overide <= 0;
end
endcase
bank_lo <= {c64_data_out[1:0], 1'b0};
bank_hi <= {c64_data_out[1:0], 1'b1};
end
end
// Mikro Assembler - (game=1, exrom=0, 8k)
28: begin
game_overide <= 1;
exrom_overide <= 0;
IOE_bank <= 0;
IOE_ena <= 1;
IOF_bank <= 0;
IOF_ena <= 1;
end
// EASYFLASH - 1mb 128x8k/64x16k, XBank format(33) looks the same
// upd: original Easyflash(32) boots in ultimax mode.
// Only one XBank(33) cart has been found: soulless-xbank. It doesn't boot in ultimax mode.
32,
33: begin
if(!init_n) begin
init_n <= 1;
IOF_bank<= 0;
IOF_ena <= 1;
IOF_wr_ena <= 1;
exrom_overide <= (cart_id==32);
game_overide <= 0;
bank_lo <= lobanks[0];
bank_hi <= hibanks[0];
end
if(ioe_wr) begin
if(c64_mem_address_in[1]) begin
game_overide <= ~c64_data_out[0] & c64_data_out[2]; //assume jumper in boot position bit2=0 -> game=0
exrom_overide <= ~c64_data_out[1];
end
else begin
bank_lo <= lobanks[c64_data_out[5:0]];
bank_hi <= hibanks[c64_data_out[5:0]];
end
end
end
// Kingsoft Business Basic
54: begin
max_ram <= 1;
if(!init_n || ioe_rd) begin
init_n <= 1;
game_overide <= 0;
exrom_overide <= 0;
bank_lo <= 0;
bank_hi <= 1;
end
if(ioe_wr) begin
game_overide <= 0;
exrom_overide <= 1;
bank_lo <= 0;
bank_hi <= 2;
end
end
// RGCD (game=1, exrom=0, 8 banks by 8k)
57: begin
if(!init_n) begin
init_n <= 1;
game_overide <= 1;
exrom_overide <= 0;
bank_lo <= 0;
end
if(~cart_disable & ioe_wr) begin
bank_lo <= c64_data_out[2:0];
if(c64_data_out[3]) begin
cart_disable <= 1;
game_overide <= 1;
exrom_overide <= 1;
end
end
end
endcase
end
// ************************************************************************************************************
// ****** Address handling - Redirection to SDRAM CRT file
// ************************************************************************************************************
wire ioe_ce = (IOE && (mem_write ? IOE_wr_ena : IOE_ena));
wire iof_ce = (IOF && (mem_write ? IOF_wr_ena : IOF_ena));
assign mem_ce_out = mem_ce | ioe_ce | iof_ce;
//RAM banks are remapped to 64K-128K space
always @(*) begin
addr_out = c64_mem_address_in;
if(cart_attached) begin
if(romH & (romH_we | ~mem_write)) addr_out[24:13] = romH_we ? {1'b1, bank_hi[2:0]} : {1'b1, bank_hi};
if(romL & (romL_we | ~mem_write)) begin
addr_out[24:13] = romL_we ? {1'b1, bank_lo[2:0]} : {1'b1, bank_lo};
addr_out[12:0] = c64_mem_address_in[12:0] & mask_lo;
end
if(ioe_ce) addr_out[24:13] = IOE_wr_ena ? {1'b1, IOE_bank[2:0]} : {1'b1, IOE_bank}; // read/write to DExx
if(iof_ce) addr_out[24:13] = IOF_wr_ena ? {1'b1, IOF_bank[2:0]} : {1'b1, IOF_bank}; // read/write to DFxx
if(UMAXromH && !mem_write) addr_out[24:12] = {1'b1, bank_hi, 1'b1}; // ULTIMAX CharROM
end
end
endmodule