Skip to content

Commit

Permalink
[FDS] Fixed support for "Kosodate Gokko" (#396).
Browse files Browse the repository at this point in the history
- Added a menu item to create empty floppy images.
- Added a visual indicator that shows when the FDS drive motor is active and whether it is reading or writing to disk:
  * green: reading data from disk
  * red: writing data to disk
  * yellow: disk head moving
  * off: drive motor off
  • Loading branch information
punesemu committed May 6, 2024
1 parent 6d40da4 commit 21b0258
Show file tree
Hide file tree
Showing 17 changed files with 268 additions and 113 deletions.
37 changes: 16 additions & 21 deletions src/core/cpu_inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,6 @@ INLINE static BYTE fds_rd_mem(BYTE nidx, WORD address, BYTE made_tick) {
// bit 1 (trasfer flag)
nes[nidx].c.cpu.openbus |= fds.drive.transfer_flag;
// bit 2 e 3 non settati
// TODO : bit 4 (CRC control : 0 passato, 1 errore)
nes[nidx].c.cpu.openbus |= (fds.drive.crc ? 0x10 : 0x00);
// bit 5 non settato
// bit 6 (end of head)
Expand All @@ -725,9 +724,12 @@ INLINE static BYTE fds_rd_mem(BYTE nidx, WORD address, BYTE made_tick) {
fds.drive.transfer_flag = FALSE;
nes[nidx].c.irq.high &= ~FDS_DISK_IRQ;
#if !defined (RELEASE)
//printf("0x%04X 0x%02X [0x%04X] 0x%04X %d %d\n", address, nes[nidx].c.cpu.openbus,
// fds.info.sides[fds.drive.side_inserted].data[fds.drive.disk_position], nes[nidx].c.cpu.opcode_PC,
// fds.drive.disk_position, nes[nidx].c.irq.high);
//printf("0x%04X 0x%02X [0x%04X] 0x%04X %d %d\n",
// address, nes[nidx].c.cpu.openbus,
// fds.info.sides[fds.drive.side_inserted].data[fds.drive.disk_position],
// nes[nidx].c.cpu.opcode_PC,
// fds.drive.disk_position,
// nes[nidx].c.irq.high);
#endif
return (TRUE);
}
Expand All @@ -749,12 +751,13 @@ INLINE static BYTE fds_rd_mem(BYTE nidx, WORD address, BYTE made_tick) {
nes[nidx].c.cpu.openbus |= fds.info.write_protected;

#if !defined (RELEASE)
//printf("%5d - %3d - %3d : 0x%04X 0x%02X %d %d %d %d\n",
//printf("%5d - %3d - %3d : 0x%04X 0x%02X %d %d %d %d %d\n",
// nes[nidx].p.ppu.frames,
// nes[nidx].p.ppu.frame_y,
// nes[nidx].p.ppu.frame_x,
// address, nes[nidx].c.cpu.openbus, fds.drive.disk_ejected, fds.drive.scan,
// fds.drive.delay_insert, fds.drive.disk_position);
// address, nes[nidx].c.cpu.openbus,
// fds.drive.end_of_head, fds.drive.transfer_reset,
// fds.drive.motor_started, fds.drive.io_mode, fds.drive.disk_position);
#endif
if (fds_auto_insert_enabled() && !fds.auto_insert.r4032.disabled && !fds.auto_insert.delay.dummy) {
if (!fds.auto_insert.r4032.frames) {
Expand All @@ -767,10 +770,10 @@ INLINE static BYTE fds_rd_mem(BYTE nidx, WORD address, BYTE made_tick) {
if (diff < 70) {
if (!fds.drive.scan && (++fds.auto_insert.r4032.checks > FDS_AUTOINSERT_R4032_MAX_CHECKS)) {
// - 19 Neunzehn (1988)(Soft Pro)(J).fds (il controllo del r4032 e' mooooolto lento)
// - Dandy (19xx)(Pony Canyon)(J).fds
// - Zelda no Densetsu - The Hyrule Fantasy (1986)(Nintendo)(J).fds
// - Ao no Senritsu (1987)(Gakken)(J).fds
// - Bishojou SF Alien Battle (19xx)(Hacker International)(J)(Unl)[b].fds
// - Dandy (19xx)(Pony Canyon)(J).fds
// - Zelda no Densetsu - The Hyrule Fantasy (1986)(Nintendo)(J).fds
fds_disk_op(FDS_DISK_EJECT, 0, TRUE);
gui_update_fds_menu();
fds.auto_insert.delay.dummy = fds.info.cycles_dummy_delay;
Expand Down Expand Up @@ -1950,7 +1953,7 @@ INLINE static BYTE fds_wr_mem(BYTE nidx, WORD address, BYTE value) {
// |+- Enable disk I/O registers
// +-- Enable sound I/O registers
#if !defined (RELEASE)
//printf("0x%04X 0x%02X %d %d\n", address, value, fds.drive.disk_ejected, fds.drive.delay);
//printf("0x%04X 0x%02X %d %d\n", address, value, fds.drive.disk_ejected, fds.drive.io_mode);
#endif
fds.drive.enabled_dsk_reg = value & 0x01;
fds.drive.enabled_snd_reg = value & 0x02;
Expand Down Expand Up @@ -2001,18 +2004,14 @@ INLINE static BYTE fds_wr_mem(BYTE nidx, WORD address, BYTE value) {
// nes[nidx].p.ppu.frames,
// nes[nidx].p.ppu.frame_y,
// nes[nidx].p.ppu.frame_x,
// address, value, fds.drive.motor_on, fds.drive.scan,
// address, value,
// fds.drive.motor_started,
// fds.drive.scan,
// fds.drive.delay_insert, fds.drive.disk_position);
#endif
if (fds.drive.enabled_dsk_reg) {
fds.drive.motor_on = value & 0x01;
if (!fds.drive.transfer_reset && (value & 0x02)) {
fds.drive.motor_started = TRUE;
}
fds.drive.transfer_reset = value & 0x02;
if (!fds.drive.transfer_reset || !fds.drive.motor_on) {
fds.drive.motor_started = FALSE;
}
fds.drive.io_mode = value & 0x04;
fds.drive.mirroring = value & 0x08;
if (fds.drive.mirroring) {
Expand All @@ -2033,11 +2032,7 @@ INLINE static BYTE fds_wr_mem(BYTE nidx, WORD address, BYTE value) {
fds.drive.mark_finded = FALSE;
}
fds.drive.irq_disk_enabled = value & 0x80;

// "Akuu Senki Raijin (Japan) (Disk Writer)" (sporcare lo screen).
fds.drive.delay_8bit = fds.info.cycles_8bit_delay;
}
fds.drive.transfer_flag = FALSE;
nes[nidx].c.irq.high &= ~FDS_DISK_IRQ;
return (TRUE);
}
Expand Down
19 changes: 13 additions & 6 deletions src/core/fds.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ void fds_init(void) {
fds.side.change.new_side = 0xFF;

fds.drive.disk_ejected = TRUE;
fds.drive.motor_on = TRUE;
fds.drive.enabled_dsk_reg = 0x01;
fds.drive.enabled_snd_reg = 0x02;
}
Expand Down Expand Up @@ -329,7 +328,7 @@ BYTE fds_load_bios(void) {

return (EXIT_OK);
}
BYTE fds_create_empty_disk(BYTE format, BYTE type, BYTE double_side, uTCHAR *file) {
BYTE fds_create_empty_disk(uTCHAR *file, BYTE format, BYTE type, BYTE double_side) {
BYTE total_sides = double_side ? 2 : 1, *mfds = NULL;
size_t size = (type == FDS_TYPE_FDS ? 16 : 0) + (fds_disk_side_size(format) * total_sides);
FILE *fp = NULL;
Expand Down Expand Up @@ -561,7 +560,11 @@ void fds_disk_op(WORD type, BYTE side_to_insert, BYTE quiet) {
case FDS_DISK_EJECT:
fds.drive.disk_ejected = TRUE;
fds.drive.scan = FALSE;
fds.drive.end_of_head = 0x40;
fds.drive.motor_on = 0x01;
fds.drive.transfer_reset = 0x02;
fds.drive.motor_started = FALSE;
fds.drive.delay_8bit = 0;
fds.auto_insert.r4032.frames = 0;
fds.auto_insert.r4032.checks = 0;
if (!quiet) {
Expand All @@ -580,8 +583,12 @@ void fds_disk_op(WORD type, BYTE side_to_insert, BYTE quiet) {
fds.drive.mark_finded = FALSE;
fds.drive.disk_ejected = FALSE;
fds.drive.scan = FALSE;
fds.drive.end_of_head = 0x40;
fds.drive.motor_on = 0x01;
fds.drive.transfer_reset = 0x02;
fds.drive.motor_started = FALSE;
fds.drive.delay_insert = 32768;
fds.drive.delay_8bit = 0;
fds.drive.delay_insert = FDS_DELAY_INSERT;
fds.auto_insert.r4032.frames = 0;
fds.auto_insert.r4032.checks = 0;
if (!quiet) {
Expand Down Expand Up @@ -792,7 +799,7 @@ BYTE fds_to_image(_fds_info *finfo) {

fib.blength = finfo->protection.magic_card_trainer
? 0x200
: finfo->protection.kgk ? 0x500 : finfo->protection.quick_hunter ? 0x3000 : 0;
: finfo->protection.kgk ? 0x2500 : finfo->protection.quick_hunter ? 0x3000 : 0;
// indico l'inizio del blocco
fds_image_memset(&dst[size], FDS_DISK_BLOCK_MARK, 1);
size += 1;
Expand Down Expand Up @@ -1109,7 +1116,7 @@ void fds_image_sinfo(BYTE side, _fds_sinfo *sinfo) {
memset(sinfo, 0x00, sizeof(_fds_sinfo));

for (position = 0; position < fds_disk_side_size(fds.info.format);) {
BYTE block = src[position], stop = FALSE;;
BYTE block = src[position], stop = FALSE;
uint32_t blength = 1;

switch (block) {
Expand Down Expand Up @@ -1414,7 +1421,7 @@ BYTE fds_create_ips(const BYTE *d1, const size_t size1, const BYTE *d2, const si
fwrite("PATCH", 5, 1, fp);
fsize += 5;

while ((i < size1) || (i < size2)) {
while ((i < size1) && (i < size2)) {
size_t length = 0;
BYTE rle = TRUE;

Expand Down
5 changes: 3 additions & 2 deletions src/core/fds.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ enum fds_misc {
FDS_DISK_BLOCK_MARK = 0x80,
FDS_AUTOINSERT_R4032_MAX_CHECKS = 7,
FDS_MIN_LAG_FRAMES = 20,
FDS_DELAY_INSERT = 90000,
FDS_IMAGE_SIDE_SIZE = 75500,
DISK_FDS_SIDE_SIZE = 65500,
DISK_QD_SIDE_SIZE = 65536
DISK_QD_SIDE_SIZE = 65536,
};

// https://www.chrismcovell.com/fds-lister.html
Expand Down Expand Up @@ -234,7 +235,7 @@ EXTERNC void fds_init(void);
EXTERNC void fds_quit(void);
EXTERNC BYTE fds_load_rom(BYTE format);
EXTERNC BYTE fds_load_bios(void);
EXTERNC BYTE fds_create_empty_disk(BYTE format, BYTE type, BYTE double_side, uTCHAR *file);
EXTERNC BYTE fds_create_empty_disk(uTCHAR *file, BYTE format, BYTE type, BYTE double_side);
EXTERNC BYTE fds_change_disk(uTCHAR *file);
EXTERNC void fds_info(void);
EXTERNC void fds_info_side(BYTE side);
Expand Down
2 changes: 1 addition & 1 deletion src/core/mappers/mapper_091.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void extcl_cpu_wr_mem_091(BYTE nidx, WORD address, BYTE value) {
m091.chr[address & 0x03] = value;
chr_fix_091();
}
return;;
return;
case 0x7000:
switch (address & 0x0003) {
case 0:
Expand Down
133 changes: 77 additions & 56 deletions src/core/mappers/mapper_FDS.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ void map_init_FDS(void) {
fds.auto_insert.in_game = FALSE;

fds.drive.mirroring = 0x08;
fds.drive.transfer_reset = 0x02;
fds.drive.io_mode = 0x04;
fds.drive.drive_ready = 0x40;

Expand Down Expand Up @@ -250,97 +249,119 @@ void extcl_cpu_every_cycle_FDS(BYTE nidx) {
return;
}

if (fds.drive.delay_insert) {
fds.drive.delay_insert--;
return;
if (!fds.drive.motor_on) {
fds.drive.transfer_reset = 0x02;
}

if (!fds.drive.motor_on && !fds.drive.motor_started) {
if (fds.drive.delay_insert) {
--fds.drive.delay_insert;
if (fds.drive.transfer_reset) {
fds.drive.motor_started = FALSE;
}
if (fds.drive.delay_insert) {
return;
}
fds.drive.disk_position = 0;
fds.drive.mark_finded = FALSE;
return;
fds.drive.end_of_head = FALSE;
fds.drive.data_available = FALSE;
fds.drive.delay_8bit = fds.info.cycles_8bit_delay;
}

if (!fds.drive.motor_started && !fds.drive.transfer_reset && fds.drive.drive_ready) {
// "Akuu Senki Raijin (Japan) (Disk Writer)" (sporcare lo screen).
fds.drive.delay_8bit = fds.info.cycles_8bit_delay;
fds.drive.motor_started = TRUE;
}

// se c'e' un delay aspetto
if ((fds.drive.delay_8bit > 0) && --fds.drive.delay_8bit) {
if (fds.drive.delay_8bit && --fds.drive.delay_8bit) {
return;
}

fds.drive.scan = !fds.drive.transfer_reset;
fds.drive.scan = FALSE;
fds.info.last_operation = FDS_OP_NONE;
fds.drive.data_available = FALSE;

if (fds.drive.scan) {
BYTE data = 0, transfer = FALSE;
if (fds.drive.motor_started) {
fds.drive.scan = !fds.drive.transfer_reset;

data = fds.side.info->data[fds.drive.disk_position];
if (fds.drive.scan) {
BYTE data = 0, transfer = FALSE;

if (fds.drive.io_mode) {
// read
if (fds.drive.drive_ready) {
if (fds.drive.mark_finded) {
transfer = TRUE;
fds.drive.crc = fds_crc_byte(fds.drive.crc, data);
} else if (data == FDS_DISK_BLOCK_MARK) {
fds.drive.mark_finded = TRUE;
fds.drive.crc = 0;
fds.drive.crc = fds_crc_byte(fds.drive.crc, data);
data = fds.side.info->data[fds.drive.disk_position];

if (fds.drive.io_mode) {
// read
if (fds.drive.drive_ready) {
if (fds.drive.mark_finded) {
transfer = TRUE;
fds.drive.crc = fds_crc_byte(fds.drive.crc, data);
} else if (data == FDS_DISK_BLOCK_MARK) {
fds.drive.mark_finded = TRUE;
fds.drive.crc = 0;
fds.drive.crc = fds_crc_byte(fds.drive.crc, data);
}
}
}
} else {
if (!fds.drive.drive_ready) {
data = FDS_DISK_GAP;
fds.drive.crc = 0;
} else {
if (fds.drive.crc_control) {
data = fds.drive.crc >> 0;
fds.drive.crc >>= 8;
// write
if (!fds.drive.drive_ready) {
data = FDS_DISK_GAP;
fds.drive.crc = 0;
} else {
data = fds.drive.data_io;
fds.drive.crc = fds_crc_byte(fds.drive.crc, data);
if (fds.drive.crc_control) {
data = fds.drive.crc >> 0;
fds.drive.crc >>= 8;
} else {
data = fds.drive.data_io;
fds.drive.crc = fds_crc_byte(fds.drive.crc, data);
fds.drive.data_io = FDS_DISK_GAP;
}
}
transfer = TRUE;
}
transfer = TRUE;
}

fds.auto_insert.r4032.frames = 0;
fds.auto_insert.r4032.checks = 0;
fds.auto_insert.r4032.frames = 0;
fds.auto_insert.r4032.checks = 0;

if (transfer) {
fds.drive.data_available = 0x80;

if (fds.drive.irq_disk_enabled) {
if (transfer) {
fds.drive.data_available = 0x80;
fds.drive.transfer_flag = 0x02;
nes[nidx].c.irq.high |= FDS_DISK_IRQ;
}
if (fds.drive.io_mode) {
fds.drive.data_io = data;
fds.info.last_operation = FDS_OP_READ;
} else {
fds.side.info->data[fds.drive.disk_position] = data;
fds.info.writings_occurred = TRUE;
fds.info.last_operation = FDS_OP_WRITE;

if (fds.drive.irq_disk_enabled) {
nes[nidx].c.irq.high |= FDS_DISK_IRQ;
}
if (fds.drive.io_mode) {
fds.drive.data_io = data;
fds.info.last_operation = FDS_OP_READ;
} else {
fds.side.info->data[fds.drive.disk_position] = data;
fds.info.writings_occurred = TRUE;
fds.info.last_operation = FDS_OP_WRITE;
}
}
}
}
if (fds.drive.scan || fds.drive.motor_started) {
if (++fds.drive.disk_position >= fds.info.sides[fds.drive.side_inserted].size) {
fds.drive.delay_insert = FDS_DELAY_INSERT;
// Kosodate Gokko non risconosce il fine disco senza questo
if (!fds.drive.transfer_reset && fds.drive.transfer_flag && fds.drive.irq_disk_enabled) {
nes[nidx].c.irq.high |= FDS_DISK_IRQ;
}
// signal "disk is full" if end track was reached during writing
if (!fds.drive.io_mode) {
fds.drive.transfer_reset = 0x02;
}
fds.drive.end_of_head = 0x40;
fds.drive.disk_position = 0;
fds.drive.transfer_reset = FALSE;
// Bishoujo Alien Battle (Japan) (Unl).fds non esegue la routine a 0xE188
// Bishoujo Alien Battle (Japan) (Unl).fds non esegue la routine a 0xE188
fds.auto_insert.in_game = TRUE;
if (fds.drive.motor_started) {
fds.drive.motor_on = FALSE;
fds.drive.motor_started = FALSE;
if (fds_auto_insert_enabled() && !fds.auto_insert.end_of_head.disabled && !fds.auto_insert.delay.dummy) {
fds_disk_op(FDS_DISK_EJECT, 0, TRUE);
gui_update_fds_menu();
fds.auto_insert.delay.dummy = fds.info.cycles_dummy_delay;
}
}
} else {
fds.drive.end_of_head = FALSE;
// il delay per riuscire a leggere i prossimi 8 bit
fds.drive.delay_8bit = fds.info.cycles_8bit_delay;
}
Expand Down
Binary file added src/gui/designer/icons/disk_empty.svgz
Binary file not shown.
Loading

0 comments on commit 21b0258

Please sign in to comment.