以下を取り込んでディスクに対応しました。
http://www.acc.umu.se/~yarin/sviemu/
memory_ex.h
/*
Common Source Code Project
SVI-3x8
Origin : src/vm/msx/memory.h
modified by tanam
Date : 2018.12.09-
[ memory ]
*/
#ifndef _MEMORY_EX_H_
#define _MEMORY_EX_H_
#include "../vm.h"
#include "../../emu.h"
#include "../device.h"
#define SIG_MEMORY_SEL 0
#if defined(FDD_PATCH_SLOT)
class DISK;
#endif
#define MAX_TAPE_LEN 524288
// memory bus
class MEMORY_EX : public DEVICE
{
private:
uint8_t* wbank[8];
uint8_t* rbank[8];
uint8_t wdmy[0x2000];
uint8_t rdmy[0x2000];
uint8_t bio[0x8000]; /* BANK01 */
uint8_t ram[0x8000]; /* BANK02 */
uint8_t rom[0x8000]; /* BANK11 */
uint8_t r12[0x8000]; /* BANK12 */
uint8_t r21[0x8000]; /* BANK21 */
uint8_t r22[0x8000]; /* BANK22 */
uint8_t r31[0x8000]; /* BANK31 */
uint8_t r32[0x8000]; /* BANK32 */
bool inserted;
bool play;
uint8_t strig;
#if defined(FDD_PATCH_SLOT)
DISK* disk[MAX_DRIVE];
DEVICE *d_fdpat;
bool access[MAX_DRIVE];
#endif
int count;
int done;
int tapePos;
int tapeLen;
byte tapedata[MAX_TAPE_LEN];
public:
MEMORY_EX(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
{
set_device_name(_T("Memory Bus"));
}
~MEMORY_EX() {}
// common functions
void initialize();
void reset();
void write_data8(uint32_t addr, uint32_t data);
uint32_t read_data8(uint32_t addr);
uint32_t fetch_op(uint32_t addr, int* wait);
bool process_state(FILEIO* state_fio, bool loading);
void write_signal(int id, uint32_t data, uint32_t mask);
uint32_t read_io8(uint32_t addr);
void write_io8(uint32_t addr, uint32_t data);
// unique functions
void open_cart(const _TCHAR *file_path);
void close_cart();
bool load_cart(const _TCHAR *file_path/*, uint8_t *rom*/);
bool is_cart_inserted()
{
return inserted;
}
bool play_tape(const _TCHAR* file_path);
// bool rec_tape(const _TCHAR* file_path);
void close_tape();
#if defined(FDD_PATCH_SLOT)
void release();
void set_context_fdd_patch(DEVICE *device)
{
d_fdpat = device;
}
void open_disk(int drv, const _TCHAR* file_path, int bank);
void close_disk(int drv);
bool is_disk_inserted(int drv);
void is_disk_protected(int drv, bool value);
bool is_disk_protected(int drv);
#endif
bool is_tape_inserted()
{
return play;
}
const _TCHAR* get_message()
{
if (play) return "Play";
else return "Stop";
}
};
#endif
memory_ex.cpp
/*
Common Source Code Project
SVI-3x8
Origin : src/vm/msx/memory_ex.cpp
modified by tanam
Date : 2018.12.09-
[ memory ]
*/
#include "memory_ex.h"
#if defined(FDD_PATCH_SLOT)
#include "../disk.h"
#define MSX_SECTOR_SIZE 512
char dskPath[64]=""; /* Disk image path */
/** Floppy drive *********/
unsigned char fdc_drive = 0;
unsigned char fdc_head = 0;
unsigned char fdc_density = 0;
unsigned char fdc_status = 0;
unsigned char svi_disk_heads[2];
unsigned char svi_disk_tracks=40;
unsigned char svi_UseDisk = 0;
#ifndef UINT16
#define UINT16 unsigned short int
#endif
#ifndef UINT8
#define UINT8 unsigned char
#endif
#define MAX_DRIVES 2 /* we support 'only' four drives in MESS */
#define WD179X_IRQ_CLR 0
#define WD179X_IRQ_SET 1
#define WD179X_DRQ_CLR 2
#define WD179X_DRQ_SET 3
#define DEN_FM_LO 0 /* this is used by TRS-80 (but not working) */
#define DEN_FM_HI 1
#define DEN_MFM_LO 2 /* and this one is the one that works */
#define DEN_MFM_HI 3 /* There were no HD disks back then ;) */
#define REAL_FDD ((void*)-1)
#define FDC_STEP_RATE 0x03 /* Type I additional flags */
#define FDC_STEP_VERIFY 0x04 /* verify track number */
#define FDC_STEP_HDLOAD 0x08 /* load head */
#define FDC_STEP_UPDATE 0x10 /* update track register */
#define FDC_RESTORE 0x00 /* Type I commands */
#define FDC_SEEK 0x10
#define FDC_STEP 0x20
#define FDC_STEP_IN 0x40
#define FDC_STEP_OUT 0x60
#define FDC_MASK_TYPE_I (FDC_STEP_HDLOAD|FDC_STEP_VERIFY|FDC_STEP_RATE)
/* Type I commands status */
#define STA_1_BUSY 0x01 /* controller is busy */
#define STA_1_IPL 0x02 /* index pulse */
#define STA_1_TRACK0 0x04 /* track 0 detected */
#define STA_1_CRC_ERR 0x08 /* CRC error */
#define STA_1_SEEK_ERR 0x10 /* seek error */
#define STA_1_HD_LOADED 0x20 /* head loaded */
#define STA_1_WRITE_PRO 0x40 /* floppy is write protected */
#define STA_1_NOT_READY 0x80 /* controller not ready */
/* Type II and III additional flags */
#define FDC_DELETED_AM 0x01 /* read/write deleted address mark */
#define FDC_SIDE_CMP_T 0x02 /* side compare track data */
#define FDC_15MS_DELAY 0x04 /* delay 15ms before command */
#define FDC_SIDE_CMP_S 0x08 /* side compare sector data */
#define FDC_MULTI_REC 0x10 /* only for type II commands */
/* Type II commands */
#define FDC_READ_SEC 0x80 /* read sector */
#define FDC_WRITE_SEC 0xA0 /* write sector */
#define FDC_MASK_TYPE_II (FDC_MULTI_REC|FDC_SIDE_CMP_S|FDC_15MS_DELAY|FDC_SIDE_CMP_T|FDC_DELETED_AM)
/* Type II commands status */
#define STA_2_BUSY 0x01
#define STA_2_DRQ 0x02
#define STA_2_LOST_DAT 0x04
#define STA_2_CRC_ERR 0x08
#define STA_2_REC_N_FND 0x10
#define STA_2_REC_TYPE 0x20
#define STA_2_WRITE_PRO 0x40
#define STA_2_NOT_READY 0x80
#define FDC_MASK_TYPE_III (FDC_SIDE_CMP_S|FDC_15MS_DELAY|FDC_SIDE_CMP_T|FDC_DELETED_AM)
/* Type III commands */
#define FDC_READ_DAM 0xc0 /* read data address mark */
#define FDC_READ_TRK 0xe0 /* read track */
#define FDC_WRITE_TRK 0xf0 /* write track (format) */
/* Type IV additional flags */
#define FDC_IM0 0x01 /* interrupt mode 0 */
#define FDC_IM1 0x02 /* interrupt mode 1 */
#define FDC_IM2 0x04 /* interrupt mode 2 */
#define FDC_IM3 0x08 /* interrupt mode 3 */
#define FDC_MASK_TYPE_IV (FDC_IM3|FDC_IM2|FDC_IM1|FDC_IM0)
/* Type IV commands */
#define FDC_FORCE_INT 0xd0 /* force interrupt */
typedef struct {
UINT8 track;
UINT8 sector;
UINT8 status;
} SECMAP;
typedef struct {
void (* callback)(int event); /* callback for IRQ status */
UINT8 unit; /* unit number if image_file == REAL_FDD */
UINT8 tracks; /* maximum # of tracks */
UINT8 heads; /* maximum # of heads */
UINT8 density; /* FM/MFM, single / double density */
UINT16 offset; /* track 0 offset */
UINT8 first_sector_id; /* id of first sector */
UINT8 sec_per_track; /* sectors per track */
UINT16 sector_length; /* sector length (byte) */
UINT8 head; /* current head # */
UINT8 track; /* current track # */
UINT8 track_reg; /* value of track register */
UINT8 direction; /* last step direction */
UINT8 sector; /* current sector # */
UINT8 sector_dam; /* current sector # to fake read DAM command */
UINT8 data; /* value of data register */
UINT8 command; /* last command written */
UINT8 read_cmd; /* last read command issued */
UINT8 write_cmd; /* last write command issued */
UINT8 status; /* status register */
UINT8 status_drq; /* status register data request bit */
UINT8 status_ipl; /* status register toggle index pulse bit */
UINT8 busy_count; /* how long to keep busy bit set */
UINT8 buffer[6144]; /* I/O buffer (holds up to a whole track) */
UINT8 dam_list[256][4]; /* list of data address marks while formatting */
int dam_data[256]; /* offset to data inside buffer while formatting */
int dam_cnt; /* valid number of entries in the dam_list */
UINT8 *fmt_sector_data[256]; /* pointer to data after formatting a track */
int data_offset; /* offset into I/O buffer */
int data_count; /* transfer count from/into I/O buffer */
const char *image_name; /* file name for disc image */
void *image_file; /* file handle for disc image */
int mode; /* open mode == 0 read only, != 0 read/write */
unsigned long image_size; /* size of image file */
UINT16 dir_sector; /* directory track for deleted DAM */
UINT16 dir_length; /* directory length for deleted DAM */
SECMAP *secmap;
} WD179X;
/* structure describing a double density track */
#define TRKSIZE_DD 6144
static UINT8 track_DD[][2] = {
{16, 0x4e}, /* 16 * 4E (track lead in) */
{ 8, 0x00}, /* 8 * 00 (pre DAM) */
{ 3, 0xf5}, /* 3 * F5 (clear CRC) */
{ 1, 0xfe}, /* *** sector *** FE (DAM) */
{ 1, 0x80}, /* 4 bytes track,head,sector,seclen */
{ 1, 0xf7}, /* 1 * F7 (CRC) */
{22, 0x4e}, /* 22 * 4E (sector lead in) */
{12, 0x00}, /* 12 * 00 (pre AM) */
{ 3, 0xf5}, /* 3 * F5 (clear CRC) */
{ 1, 0xfb}, /* 1 * FB (AM) */
{ 1, 0x81}, /* x bytes sector data */
{ 1, 0xf7}, /* 1 * F7 (CRC) */
{16, 0x4e}, /* 16 * 4E (sector lead out) */
{ 8, 0x00}, /* 8 * 00 (post sector) */
{ 0, 0x00}, /* end of data */
};
/* structure describing a single density track */
#define TRKSIZE_SD 3172
static UINT8 track_SD[][2] = {
{16, 0xff}, /* 16 * FF (track lead in) */
{ 8, 0x00}, /* 8 * 00 (pre DAM) */
{ 1, 0xfc}, /* 1 * FC (clear CRC) */
{11, 0xff}, /* *** sector *** 11 * FF */
{ 6, 0x00}, /* 6 * 00 (pre DAM) */
{ 1, 0xfe}, /* 1 * FE (DAM) */
{ 1, 0x80}, /* 4 bytes track,head,sector,seclen */
{ 1, 0xf7}, /* 1 * F7 (CRC) */
{10, 0xff}, /* 10 * FF (sector lead in) */
{ 4, 0x00}, /* 4 * 00 (pre AM) */
{ 1, 0xfb}, /* 1 * FB (AM) */
{ 1, 0x81}, /* x bytes sector data */
{ 1, 0xf7}, /* 1 * F7 (CRC) */
{ 0, 0x00}, /* end of data */
};
WD179X *wd[MAX_DRIVES];
static UINT8 drv = 0;
void wd179x_CloseDiskImage(unsigned char DriveNumber)
{
WD179X *w = wd[DriveNumber];
fclose((FILE *)w->image_file);
w->image_file = NULL;
w->image_name = NULL;
}
void wd179x_InitDiskImage(unsigned char DriveNumber, const char *DriveImageFileName)
{
WD179X *w = wd[DriveNumber];
w->image_name = DriveImageFileName;
// Open file images
w->mode = 1;
// Open Read/Write
w->image_file = fopen(w->image_name, "r+b");
if( !w->image_file )
{
w->mode = 0;
// Open Read Only
w->image_file = fopen(w->image_name,"rb");
}
w->track = 0;
w->head = 0;
w->sector = 0;
}
void wd179x_init(int active)
{
int i;
for (i = 0; i < MAX_DRIVES; i++)
{
wd[i] = (WD179X *)malloc(sizeof(WD179X));
if (!wd[i])
{
while (--i >= 0)
{
free(wd[i]);
wd[i] = 0;
}
return;
}
memset(wd[i], 0, sizeof(WD179X));
wd[i]->unit = 0;
wd[i]->tracks = 40;
wd[i]->heads = 1;
wd[i]->density = DEN_MFM_LO;
wd[i]->offset = 0;
wd[i]->first_sector_id = 0;
wd[i]->sec_per_track = 17;
wd[i]->sector_length = 256;
wd[i]->head = 0;
wd[i]->track = 0;
wd[i]->track_reg = 0;
wd[i]->direction = 1;
wd[i]->sector = 0;
wd[i]->data = 0;
wd[i]->status = (active) ? STA_1_TRACK0 : 0;
wd[i]->status_drq = 0;
wd[i]->status_ipl = 0;
wd[i]->busy_count = 0;
wd[i]->data_offset = 0;
wd[i]->data_count = 0;
wd[i]->image_name = 0;
wd[i]->image_size = 0;
wd[i]->dir_sector = 0;
wd[i]->dir_length = 0;
wd[i]->secmap = 0;
}
}
void wd179x_select_drive(UINT8 drive, UINT8 head, void (*callback) (int))
{
WD179X *w = wd[drive];
if (drive < MAX_DRIVES)
{
drv = drive;
w->head = head;
w->status_ipl = STA_1_IPL;
w->callback = callback;
if (w->image_file)
{
return;
}
}
w->status = STA_1_NOT_READY;
}
void wd179x_stop_drive(void)
{
int i;
for (i = 0; i < MAX_DRIVES; i++)
{
WD179X *w = wd[i];
w->busy_count = 0;
w->status = 0;
w->status_drq = 0;
if (w->callback)
(*w->callback) (WD179X_DRQ_CLR);
w->status_ipl = 0;
}
}
void wd179x_read_sectormap(UINT8 drive, UINT8 * tracks, UINT8 * heads, UINT8 * sec_per_track)
{
WD179X *w = wd[drive];
SECMAP *p;
UINT8 head;
if (!w->secmap)
w->secmap = (SECMAP *)malloc(0x2200);
if (!w->secmap) return;
fseek((FILE *)w->image_file, 0, SEEK_SET);
fread(w->secmap, 1, 0x2200, (FILE *)w->image_file);
w->offset = 0x2200;
w->tracks = 0;
w->heads = 0;
w->sec_per_track = 0;
w->first_sector_id = 0x0ff;
for (p = w->secmap; p->track != 0xff; p++)
{
if (p->track > w->tracks)
w->tracks = p->track;
if (p->sector < w->first_sector_id)
w->first_sector_id = p->sector;
if (p->sector > w->sec_per_track)
w->sec_per_track = p->sector;
head = (p->status >> 4) & 1;
if (head > w->heads)
w->heads = head;
}
*tracks = w->tracks++;
*heads = w->heads++;
*sec_per_track = w->sec_per_track++;
}
void wd179x_set_geometry(UINT8 density, UINT8 drive, UINT8 tracks, UINT8 heads, UINT8 sec_per_track, UINT16 sector_length, UINT16 dir_sector, UINT16 dir_length, UINT8 first_sector_id)
{
WD179X *w = wd[drive];
if (drive >= MAX_DRIVES)
{
return;
}
w->density = density;
w->tracks = tracks;
w->heads = heads;
w->first_sector_id = first_sector_id;
w->sec_per_track = sec_per_track;
w->sector_length = sector_length;
w->dir_sector = dir_sector;
w->dir_length = dir_length;
w->image_size = w->tracks * w->heads * w->sec_per_track * w->sector_length;
/* calculate greatest power of 2 */
if (w->image_file == REAL_FDD)
{
unsigned long N = 0;
unsigned long ShiftCount = 0;
if (N==0)
{
N = (w->sector_length);
while ((N & 0x080000000)==0)
{
N = N<<1;
ShiftCount++;
}
/* get left-shift required to shift 1 to this
power of 2 */
/* N = 0 for 128, N = 1 for 256, N = 2 for 512 ... */
N = (31 - ShiftCount)-7;
}
else
{
N = 1;
}
}
}
/* seek to track/head/sector relative position in image file */
static int seek(WD179X * w, UINT8 t, UINT8 h, UINT8 s)
{
unsigned long offset;
SECMAP *p;
UINT8 head;
if (w->secmap)
{
offset = 0x2200;
for (p = w->secmap; p->track != 0xff; p++)
{
if (p->track == t && p->sector == s)
{
head = (p->status & 0x10) >> 4;
if (head == h)
{
if (fseek((FILE *)w->image_file, offset, SEEK_SET) < 0)
{
return STA_1_SEEK_ERR;
}
return 0;
}
}
//offset += 0x100;
if (p->track==0 && head==0)
offset += 0x80;
else
offset += 0x100;
}
return STA_1_SEEK_ERR;
}
/* allow two additional tracks */
if (t >= w->tracks + 2)
{
return STA_1_SEEK_ERR;
}
if (h >= w->heads)
{
return STA_1_SEEK_ERR;
}
if (s >= (w->first_sector_id + w->sec_per_track))
{
return STA_2_REC_N_FND;
}
if ((t==0) && (h==0))
offset = (s-w->first_sector_id)*128;
else
offset = ((t*w->heads+h)*17+s-w->first_sector_id)*256-2048; // (17*256)-(18*128)=2048
if (offset > w->image_size)
{
return STA_1_SEEK_ERR;
}
if (fseek((FILE *)w->image_file, offset, SEEK_SET) < 0)
{
return STA_1_SEEK_ERR;
}
return 0;
}
/* return STA_2_REC_TYPE depending on relative sector */
static int deleted_dam(WD179X * w)
{
unsigned rel_sector = (w->track * w->heads + w->head) * w->sec_per_track + (w->sector-w->first_sector_id);
SECMAP *p;
UINT8 head;
if (w->secmap)
{
for (p = w->secmap; p->track != 0xff; p++)
{
if (p->track == w->track && p->sector == w->sector)
{
head = (p->status >> 4) & 1;
if (w->head == head)
return p->status & STA_2_REC_TYPE;
}
}
return STA_2_REC_N_FND;
}
if (rel_sector >= w->dir_sector && rel_sector < w->dir_sector + w->dir_length)
{
return STA_2_REC_TYPE;
}
return 0;
}
/* calculate CRC for data address marks or sector data */
static void calc_crc(UINT16 * crc, UINT8 value)
{
UINT8 l, h;
l = value ^ (*crc >> 8);
*crc = (*crc & 0xff) | (l << 8);
l >>= 4;
l ^= (*crc >> 8);
*crc <<= 8;
*crc = (*crc & 0xff00) | l;
l = (l << 4) | (l >> 4);
h = l;
l = (l << 2) | (l >> 6);
l &= 0x1f;
*crc = *crc ^ (l << 8);
l = h & 0xf0;
*crc = *crc ^ (l << 8);
l = (h << 1) | (h >> 7);
l &= 0xe0;
*crc = *crc ^ l;
}
/* read the next data address mark */
static void read_dam(WD179X * w)
{
UINT16 crc = 0xffff;
w->data_offset = 0;
w->data_count = 6;
w->buffer[0] = w->track;
w->buffer[1] = w->head;
w->buffer[2] = w->sector_dam;
w->buffer[3] = w->sector_length >> 8;
calc_crc(&crc, w->buffer[0]);
calc_crc(&crc, w->buffer[1]);
calc_crc(&crc, w->buffer[2]);
calc_crc(&crc, w->buffer[3]);
w->buffer[4] = crc & 255;
w->buffer[5] = crc / 256;
if (++w->sector_dam == w->sec_per_track)
w->sector_dam = w->first_sector_id;
w->status_drq = STA_2_DRQ;
if (w->callback)
(*w->callback) (WD179X_DRQ_SET);
w->status = STA_2_DRQ | STA_2_BUSY;
w->busy_count = 50;
}
/* read a sector */
static void read_sector(WD179X * w)
{
w->data_offset = 0;
w->data_count = w->sector_length;
/* if a track was just formatted */
if (w->dam_cnt)
{
int i;
for (i = 0; i < w->dam_cnt; i++)
{
if (w->track == w->dam_list[i][0] &&
w->head == w->dam_list[i][1] &&
w->sector == w->dam_list[i][2])
{
w->data_offset = w->dam_data[i];
return;
}
}
/* sector not found, now the track buffer is invalid */
w->dam_cnt = 0;
}
/* if this is the real thing */
if (w->image_file == REAL_FDD)
{
int tries = 3;
do {
//w->status = osd_fdc_get_sector(w->track, w->head, w->head, w->sector, w->buffer);
tries--;
} while (tries && (w->status & (STA_2_REC_N_FND | STA_2_CRC_ERR | STA_2_LOST_DAT)));
/* no error bits set ? */
if ((w->status & (STA_2_REC_N_FND | STA_2_CRC_ERR | STA_2_LOST_DAT)) == 0)
{
/* start transferring data to the emulation now */
w->status_drq = STA_2_DRQ;
if (w->callback)
(*w->callback) (WD179X_DRQ_SET);
w->status |= STA_2_DRQ | STA_2_BUSY;
}
return;
}
else
if (fread(w->buffer, 1, w->sector_length, (FILE *)w->image_file) != w->sector_length)
{
w->status = STA_2_LOST_DAT;
return;
}
w->status_drq = STA_2_DRQ;
if (w->callback)
(*w->callback) (WD179X_DRQ_SET);
w->status = STA_2_DRQ | STA_2_BUSY;
w->busy_count = 0;
}
/* read an entire track */
static void read_track(WD179X * w)
{
UINT8 *psrc; /* pointer to track format structure */
UINT8 *pdst; /* pointer to track buffer */
int cnt; /* number of bytes to fill in */
UINT16 crc; /* id or data CRC */
UINT8 d; /* data */
UINT8 t = w->track; /* track of DAM */
UINT8 h = w->head; /* head of DAM */
UINT8 s = w->sector_dam; /* sector of DAM */
UINT16 l = w->sector_length; /* sector length of DAM */
int i;
for (i = 0; i < w->sec_per_track; i++)
{
w->dam_list[i][0] = t;
w->dam_list[i][1] = h;
w->dam_list[i][2] = i;
w->dam_list[i][3] = l >> 8;
}
pdst = w->buffer;
if (w->density)
{
psrc = track_DD[0]; /* double density track format */
cnt = TRKSIZE_DD;
}
else
{
psrc = track_SD[0]; /* single density track format */
cnt = TRKSIZE_SD;
}
while (cnt > 0)
{
if (psrc[0] == 0) /* no more track format info ? */
{
if (w->dam_cnt < w->sec_per_track) /* but more DAM info ? */
{
if (w->density)/* DD track ? */
psrc = track_DD[3];
else
psrc = track_SD[3];
}
}
if (psrc[0] != 0) /* more track format info ? */
{
cnt -= psrc[0]; /* subtract size */
d = psrc[1];
if (d == 0xf5) /* clear CRC ? */
{
crc = 0xffff;
d = 0xa1; /* store A1 */
}
for (i = 0; i < *psrc; i++)
*pdst++ = d; /* fill data */
if (d == 0xf7) /* store CRC ? */
{
pdst--; /* go back one byte */
*pdst++ = crc & 255; /* put CRC low */
*pdst++ = crc / 256; /* put CRC high */
cnt -= 1; /* count one more byte */
}
else if (d == 0xfe)/* address mark ? */
{
crc = 0xffff; /* reset CRC */
}
else if (d == 0x80)/* sector ID ? */
{
pdst--; /* go back one byte */
t = *pdst++ = w->dam_list[w->dam_cnt][0]; /* track number */
h = *pdst++ = w->dam_list[w->dam_cnt][1]; /* head number */
s = *pdst++ = w->dam_list[w->dam_cnt][2]; /* sector number */
l = *pdst++ = w->dam_list[w->dam_cnt][3]; /* sector length code */
w->dam_cnt++;
calc_crc(&crc, t); /* build CRC */
calc_crc(&crc, h); /* build CRC */
calc_crc(&crc, s); /* build CRC */
calc_crc(&crc, l); /* build CRC */
l = (l == 0) ? 128 : l << 8;
}
else if (d == 0xfb)// data address mark ?
{
crc = 0xffff; // reset CRC
}
else if (d == 0x81)// sector DATA ?
{
pdst--; /* go back one byte */
if (seek(w, t, h, s) == 0)
{
if (fread(pdst, 1, l, (FILE *)w->image_file) != l)
{
w->status = STA_2_CRC_ERR;
return;
}
}
else
{
w->status = STA_2_REC_N_FND;
return;
}
for (i = 0; i < l; i++) // build CRC of all data
calc_crc(&crc, *pdst++);
cnt -= l;
}
psrc += 2;
}
else
{
*pdst++ = 0xff; /* fill track */
cnt--; /* until end */
}
}
w->data_offset = 0;
w->data_count = (w->density) ? TRKSIZE_DD : TRKSIZE_SD;
w->status_drq = STA_2_DRQ;
if (w->callback)
(*w->callback) (WD179X_DRQ_SET);
w->status |= STA_2_DRQ | STA_2_BUSY;
w->busy_count = 0;
}
/* write a sector */
static void write_sector(WD179X * w)
{
if (w->image_file == REAL_FDD)
{
return;
}
if (w->mode == 0)
{
w->status = STA_2_WRITE_PRO;
}
else
{
w->status = seek(w, w->track, w->head, w->sector);
if (w->status == 0)
{
if (fwrite(w->buffer, 1, w->data_offset, (FILE *)w->image_file) != w->data_offset)
w->status = STA_2_LOST_DAT;
}
}
}
/* write an entire track by extracting the sectors */
static void write_track(WD179X * w)
{
UINT8 *f;
int cnt;
w->dam_cnt = 0;
if (w->image_file != REAL_FDD && w->mode == 0)
{
w->status = STA_2_WRITE_PRO;
return;
}
memset(w->dam_list, 0xff, sizeof(w->dam_list));
memset(w->dam_data, 0x00, sizeof(w->dam_data));
f = w->buffer;
cnt = (w->density) ? TRKSIZE_DD : TRKSIZE_SD;
do
{
while ((--cnt > 0) && (*f != 0xfe)) /* start of DAM ?? */
f++;
if (cnt > 4)
{
int seclen;
cnt -= 5;
f++; /* skip FE */
w->dam_list[w->dam_cnt][0] = *f++; /* copy track number */
w->dam_list[w->dam_cnt][1] = *f++; /* copy head number */
w->dam_list[w->dam_cnt][2] = *f++; /* copy sector number */
w->dam_list[w->dam_cnt][3] = *f++; /* copy sector length */
/* sector length in bytes */
seclen = 128 << w->dam_list[w->dam_cnt][3];
/* search start of DATA */
while ((--cnt > 0) && (*f != 0xf9) && (*f != 0xfa) && (*f != 0xfb))
f++;
if (cnt > seclen)
{
cnt--;
/* skip data address mark */
f++;
/* set pointer to DATA to later write the sectors contents */
w->dam_data[w->dam_cnt] = (int)(f - w->buffer);
w->dam_cnt++;
f += seclen;
cnt -= seclen;
}
}
} while (cnt > 0);
if (w->image_file == REAL_FDD)
{
w->status = 0;
}
else
{
/* now put all sectors contained in the format buffer */
for (cnt = 0; cnt < w->dam_cnt; cnt++)
{
w->status = seek(w, w->track, w->head, w->dam_list[cnt][2]);
if (w->status == 0)
{
if (fwrite(&w->buffer[w->dam_data[cnt]],1, w->sector_length, (FILE *)w->image_file) != w->sector_length)
{
w->status = STA_2_LOST_DAT;
return;
}
}
}
}
}
/* read the FDC status register. This clears IRQ line too */
UINT8 wd179x_status_r(void)
{
WD179X *w = wd[drv];
int result = w->status;
if (w->callback)
(*w->callback) (WD179X_IRQ_CLR);
if (w->busy_count)
{
if (!--w->busy_count)
w->status &= ~STA_1_BUSY;
}
/* eventually toggle index pulse bit */
w->status ^= w->status_ipl;
/* eventually set data request bit */
w->status |= w->status_drq;
return result;
}
/* read the FDC track register */
UINT8 wd179x_track_r(void)
{
WD179X *w = wd[drv];
return w->track_reg;
}
/* read the FDC sector register */
UINT8 wd179x_sector_r(void)
{
WD179X *w = wd[drv];
return w->sector;
}
/* read the FDC data register */
UINT8 wd179x_data_r(void)
{
WD179X *w = wd[drv];
if (w->data_count > 0)
{
w->status &= ~STA_2_DRQ;
if (--w->data_count <= 0)
{
/* clear busy bit */
w->status &= ~STA_2_BUSY;
/* no more setting of data request bit */
w->status_drq = 0;
if (w->callback)
(*w->callback) (WD179X_DRQ_CLR);
if (w->image_file != REAL_FDD)
{
/* read normal or deleted data address mark ? */
w->status |= deleted_dam(w);
}
/* generate an IRQ */
if (w->callback)
(*w->callback) (WD179X_IRQ_SET);
}
w->data = w->buffer[w->data_offset++];
}
return w->data;
}
/* write the FDC command register */
void wd179x_command_w(UINT8 data)
{
WD179X *w = wd[drv];
if ((data | 1) == 0xff) /* change single/double density ? */
{
/* only supports FM/LO and MFM/LO */
w->density = (data & 1) ? DEN_MFM_LO : DEN_FM_LO;
return;
}
if ((data & ~FDC_MASK_TYPE_IV) == FDC_FORCE_INT)
{
w->data_count = 0;
w->data_offset = 0;
w->status &= ~(STA_2_DRQ | STA_2_BUSY);
w->status_drq = 0;
if (w->callback)
(*w->callback) (WD179X_DRQ_CLR);
w->status_ipl = 0;
if (w->callback)
(*w->callback) (WD179X_IRQ_CLR);
w->busy_count = 0;
return;
}
if (data & 0x80)
{
w->status_ipl = 0;
if ((data & ~FDC_MASK_TYPE_II) == FDC_READ_SEC)
{
w->read_cmd = data;
w->command = data & ~FDC_MASK_TYPE_II;
w->status = seek(w, w->track, w->head, w->sector);
if (w->status == 0)
read_sector(w);
return;
}
if ((data & ~FDC_MASK_TYPE_II) == FDC_WRITE_SEC)
{
w->write_cmd = data;
w->command = data & ~FDC_MASK_TYPE_II;
w->data_offset = 0;
w->data_count = w->sector_length;
w->status_drq = STA_2_DRQ;
if (w->callback)
(*w->callback) (WD179X_DRQ_SET);
w->status = STA_2_DRQ | STA_2_BUSY;
w->busy_count = 0;
return;
}
if ((data & ~FDC_MASK_TYPE_III) == FDC_READ_TRK)
{
w->command = data & ~FDC_MASK_TYPE_III;
w->status = seek(w, w->track, w->head, w->sector);
if (w->status == 0)
read_track(w);
return;
}
if ((data & ~FDC_MASK_TYPE_III) == FDC_WRITE_TRK)
{
w->command = data & ~FDC_MASK_TYPE_III;
w->data_offset = 0;
w->data_count = (w->density) ? TRKSIZE_DD : TRKSIZE_SD;
w->status_drq = STA_2_DRQ;
if (w->callback)
(*w->callback) (WD179X_DRQ_SET);
w->status = STA_2_DRQ | STA_2_BUSY;
w->busy_count = 0;
return;
}
if ((data & ~FDC_MASK_TYPE_III) == FDC_READ_DAM)
{
w->status = seek(w, w->track, w->head, w->sector);
if (w->status == 0)
read_dam(w);
return;
}
return;
}
if ((data & ~FDC_MASK_TYPE_I) == FDC_RESTORE)
{
/* simulate seek time busy signal */
w->busy_count = w->track * ((data & FDC_STEP_RATE) + 1);
/* if it is a real floppy, issue a recal command */
if (w->image_file == REAL_FDD)
{
w->track = 0;//osd_fdc_recal(&w->track);
}
else
{
w->track = 0; /* set track number 0 */
}
w->track_reg = w->track;
}
if ((data & ~FDC_MASK_TYPE_I) == FDC_SEEK)
{
UINT8 newtrack = w->data;
/* if it is a real floppy, issue a seek command */
/* simulate seek time busy signal */
w->busy_count = abs(newtrack - w->track) * ((data & FDC_STEP_RATE) + 1);
if (w->image_file == REAL_FDD)
w->track = newtrack;//osd_fdc_seek(newtrack, &w->track);
else
w->track = newtrack; /* get track number from data register */
w->track_reg = w->track;
}
if ((data & ~(FDC_STEP_UPDATE | FDC_MASK_TYPE_I)) == FDC_STEP)
{
/* if it is a real floppy, issue a step command */
/* simulate seek time busy signal */
w->busy_count = ((data & FDC_STEP_RATE) + 1);
if (w->image_file == REAL_FDD)
w->track += w->direction;//osd_fdc_step(w->direction, &w->track);
else
w->track += w->direction; /* adjust track number */
}
if ((data & ~(FDC_STEP_UPDATE | FDC_MASK_TYPE_I)) == FDC_STEP_IN)
{
w->direction = +1;
/* simulate seek time busy signal */
w->busy_count = ((data & FDC_STEP_RATE) + 1);
/* if it is a real floppy, issue a step command */
if (w->image_file == REAL_FDD)
w->track += w->direction;//osd_fdc_step(w->direction, &w->track);
else
w->track += w->direction; /* adjust track number */
}
if ((data & ~(FDC_STEP_UPDATE | FDC_MASK_TYPE_I)) == FDC_STEP_OUT)
{
w->direction = -1;
/* simulate seek time busy signal */
w->busy_count = ((data & FDC_STEP_RATE) + 1);
/* if it is a real floppy, issue a step command */
if (w->image_file == REAL_FDD)
w->track += w->direction;//osd_fdc_step(w->direction, &w->track);
else
w->track += w->direction; /* adjust track number */
}
if (w->busy_count)
w->status = STA_1_BUSY;
/* toggle index pulse at read */
w->status_ipl = STA_1_IPL;
if (w->track >= w->tracks)
w->status |= STA_1_SEEK_ERR;
if (w->track == 0)
w->status |= STA_1_TRACK0;
if (w->mode == 0)
w->status |= STA_1_WRITE_PRO;
if (data & FDC_STEP_UPDATE)
w->track_reg = w->track;
if (data & FDC_STEP_HDLOAD)
w->status |= STA_1_HD_LOADED;
if (data & FDC_STEP_VERIFY)
if (w->track_reg != w->track)
w->status |= STA_1_SEEK_ERR;
}
/* write the FDC track register */
void wd179x_track_w(UINT8 data)
{
WD179X *w = wd[drv];
w->track = w->track_reg = data;
}
/* write the FDC sector register */
void wd179x_sector_w(UINT8 data)
{
WD179X *w = wd[drv];
w->sector = data;
}
/* write the FDC data register */
void wd179x_data_w(UINT8 data)
{
WD179X *w = wd[drv];
if (w->data_count > 0)
{
w->buffer[w->data_offset++] = data;
if (--w->data_count <= 0)
{
w->status_drq = 0;
if (w->callback)
(*w->callback) (WD179X_DRQ_CLR);
if (w->command == FDC_WRITE_TRK)
write_track(w);
else
write_sector(w);
w->data_offset = 0;
if (w->callback)
(*w->callback) (WD179X_IRQ_SET);
}
}
w->data = data;
}
/*************************************************************/
/* Function: svi_LoadDisk */
/* Purpose: Try to load a disk image */
/*************************************************************/
unsigned char svi_LoadDisk(unsigned char disk, char *filename)
{
unsigned char status = 0;
char s[256];
FILE *f;
int fsize;
if (strstr(filename,".\\")!=filename)
{
strcpy(s,dskPath);
strcat(s,filename);
if (f=fopen(s,"rb"))
{
strcpy(filename,s);
fclose(f);
}
}
if (!(f=fopen(filename,"rb")))
return 0;
fseek(f,0,SEEK_END);
fsize=ftell(f);
switch (fsize)
{
case 346112 : svi_disk_heads[disk] = 2;
status=1;
break;
case 172032 : svi_disk_heads[disk] = 1;
status=1;
break;
}
fclose(f);
return status;
}
/*************************************************************/
/* Function: svi_fdc_callback */
/* Purpose: Callback routine for the FDC. */
/*************************************************************/
void svi_fdc_callback(int param)
{
switch( param )
{
case WD179X_IRQ_CLR:
fdc_status &= ~0x80;
break;
case WD179X_IRQ_SET:
fdc_status |= 0x80;
break;
case WD179X_DRQ_CLR:
fdc_status &= ~0x40;
break;
case WD179X_DRQ_SET:
fdc_status |= 0x40;
break;
}
}
/*************************************************************/
/* Function: svi_fdc_disk_motor */
/* Purpose: Floppy disk and motor select. */
/*************************************************************/
void svi_fdc_disk_motor(unsigned char data)
{
unsigned char seldrive = 255;
if (data == 0)
{
wd179x_stop_drive();
return;
}
if (data & 2)
{
seldrive=1;
}
if (data & 1)
{
seldrive=0;
}
if (seldrive > 3) return;
fdc_drive = seldrive;
wd179x_select_drive(fdc_drive, fdc_head, svi_fdc_callback);
}
/*************************************************************/
/* Function: svi_fdc_density_side */
/* Purpose: Floppy density and head select. */
/*************************************************************/
void svi_fdc_density_side(unsigned char data)
{
unsigned char sectors_track;
unsigned short int sector_size;
if (data & 2)
fdc_head = 1;
else
fdc_head = 0;
if (data & 1)
{
fdc_density = DEN_FM_LO;
sectors_track = 18;
sector_size = 128;
}
else
{
fdc_density = DEN_MFM_LO;
sectors_track = 17;
sector_size = 256;
}
wd179x_set_geometry(fdc_density, fdc_drive, svi_disk_tracks, svi_disk_heads[fdc_drive], sectors_track, sector_size, 0, 0, 1);
}
#endif
#define EVENT_CLOCK 0
#define SET_BANK(s, e, w, r) { \
int sb = (s) >> 13, eb = (e) >> 13; \
for(int i = sb; i <= eb; i++) { \
if((w) == wdmy) { \
wbank[i] = wdmy; \
} else { \
wbank[i] = (w) + 0x2000 * (i - sb); \
} \
if((r) == rdmy) { \
rbank[i] = rdmy; \
} else { \
rbank[i] = (r) + 0x2000 * (i - sb); \
} \
} \
}
bool MEMORY_EX::load_cart(const _TCHAR *file_path)
{
bool result = false;
FILEIO* fio = new FILEIO();
if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
memset(rom, 0xff, sizeof(rom));
fio->Fread(rom, sizeof(rom), 1);
fio->Fread(r12, sizeof(r12), 1);
SET_BANK(0x0000, 0x7fff, wdmy, rom);
SET_BANK(0x8000, 0xffff, ram, ram);
fio->Fclose();
result = true;
}
delete fio;
return result;
}
void MEMORY_EX::open_cart(const _TCHAR *file_path)
{
if(load_cart(file_path)) {
inserted = true;
}
}
void MEMORY_EX::close_cart()
{
SET_BANK(0x0000, 0x7fff, wdmy, bio);
SET_BANK(0x8000, 0xffff, ram, ram);
inserted = false;
}
// memory bus
void MEMORY_EX::initialize()
{
svi_UseDisk = 0;
memset(bio, 0xff, sizeof(bio));
memset(rdmy, 0xff, sizeof(rdmy));
memset(wdmy, 0xff, sizeof(wdmy));
FILEIO* fio = new FILEIO();
if((fio->Fopen(create_local_path(_T("SVI318.ROM")), FILEIO_READ_BINARY)) ||
(fio->Fopen(create_local_path(_T("SVI328.ROM")), FILEIO_READ_BINARY)) ||
(fio->Fopen(create_local_path(_T("SVI328a.ROM")), FILEIO_READ_BINARY))) {
fio->Fread(bio, sizeof(bio), 1);
fio->Fclose();
}
delete fio;
#if defined(FDD_PATCH_SLOT)
wd179x_init(1);
for(int i = 0; i < MAX_DRIVE; i++) {
disk[i] = new DISK(emu);
disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
disk[i]->drive_type = DRIVE_TYPE_2DD;
}
#endif
close_cart();
close_tape();
}
#if defined(FDD_PATCH_SLOT)
void MEMORY_EX::release()
{
for(int i = 0; i < MAX_DRIVE; i++) {
if(disk[i]) {
disk[i]->close();
delete disk[i];
}
}
}
#endif
void MEMORY_EX::reset()
{
if (!inserted) {
memset(rom, 0xff, sizeof(rom));
memset(r12, 0xff, sizeof(r12));
}
memset(ram, 0, sizeof(ram));
memset(r21, 0, sizeof(r21));
memset(r22, 0, sizeof(r22));
memset(r31, 0, sizeof(r31));
memset(r32, 0, sizeof(r32));
memset(tapedata, 0, sizeof(tapedata));
}
void MEMORY_EX::write_data8(uint32_t addr, uint32_t data)
{
wbank[addr >> 13][addr & 0x1fff] = data;
}
uint32_t MEMORY_EX::read_io8(uint32_t addr)
{
unsigned char port = addr;
uint32_t ret=0xff;
switch (port)
{
case 0x30 : if (svi_UseDisk == 1)
ret=wd179x_status_r();
break;
case 0x31 : if (svi_UseDisk == 1)
ret=wd179x_track_r();
break;
case 0x32 : if (svi_UseDisk == 1)
ret=wd179x_sector_r();
break;
case 0x33 : if (svi_UseDisk == 1)
ret=wd179x_data_r();
break;
case 0x34 : if (svi_UseDisk == 1)
ret=fdc_status;
break;
default:
ret=strig;
}
return ret;
}
void MEMORY_EX::write_io8(uint32_t addr, uint32_t data)
{
// Write the value to the appropriate port
unsigned char port = addr;
unsigned char value = data;
switch (port)
{
case 0x30 : if (svi_UseDisk == 1)
{
wd179x_command_w(value);
if ((value & ~FDC_MASK_TYPE_I) == FDC_RESTORE)
fdc_status |= 0x80;
}
break;
case 0x31 : if (svi_UseDisk == 1)
wd179x_track_w(value);
break;
case 0x32 : if (svi_UseDisk == 1)
wd179x_sector_w(value);
break;
case 0x33 : if (svi_UseDisk == 1)
wd179x_data_w(value);
break;
case 0x34 : if (svi_UseDisk == 1)
svi_fdc_disk_motor(value);
break;
case 0x38 : if (svi_UseDisk == 1)
svi_fdc_density_side(value);
break;
default:
strig &= 0xE0;
data &= 0x1F;
strig |= data;
}
}
uint32_t MEMORY_EX::read_data8(uint32_t addr)
{
addr &= 0xffff;
if (!play)
return rbank[addr >> 13][addr & 0x1fff];
if (addr==0x210a) {
count=0;
done=0;
return 0xAF;
}
if (addr==0x210b) {
strig &= 0x7F;
return 0x00;
}
if (addr==0x210c)
return 0xc9;
if (addr==0x21a9)
return 0x3e;
if (addr==0x21aa) {
while ((tapePos<tapeLen)&&(!done))
{
switch (tapedata[tapePos++])
{
case 0x7F : done=count>=10; break;
case 0x55 : count++; break;
default : count=0; break;
}
}
return tapedata[tapePos++];
}
if (addr==0x21ab)
return 0xc9;
return rbank[addr >> 13][addr & 0x1fff];
}
void MEMORY_EX::write_signal(int id, uint32_t data, uint32_t mask) {
if (data & 16) {
if (data & 4) {
SET_BANK(0x8000, 0xffff, ram, ram);
} else {
if (data % 2 == 1) {
SET_BANK(0x8000, 0xffff, r22, r22);
} else {
SET_BANK(0x8000, 0xffff, wdmy,r12);
}
}
} else {
SET_BANK(0x8000, 0xffff, r32, r32);
}
data &= 0x0f;
if (data==3 || data==7) {
SET_BANK(0x0000, 0x7fff, r31, r31);
} else if (data==13) {
SET_BANK(0x0000, 0x7fff, r21, r21);
} else {
if (data % 2 == 1) {
SET_BANK(0x0000, 0x7fff, wdmy,bio);
} else {
SET_BANK(0x0000, 0x7fff, wdmy,rom);
}
}
return;
}
uint32_t MEMORY_EX::fetch_op(uint32_t addr, int* wait)
{
*wait = 1;
return read_data8(addr);
}
bool MEMORY_EX::play_tape(const _TCHAR* file_path)
{
FILEIO* fio = new FILEIO();
if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
fio->Fread(tapedata, sizeof(tapedata), 1);
tapeLen = fio->Ftell();
fio->Fclose();
play = true;
}
delete fio;
strig = 0xBF;
tapePos=0;
return true;
}
void MEMORY_EX::close_tape()
{
memset(tapedata, 0, sizeof(tapedata));
strig = 0xFF;
tapePos=0;
play = false;
}
#if defined(FDD_PATCH_SLOT)
void MEMORY_EX::open_disk(int drv, const _TCHAR* file_path, int bank)
{
if(drv < MAX_DRIVE) {
// disk[drv]->open(file_path, bank);
if (svi_LoadDisk(drv, (char *)file_path) > 0)
{
wd179x_InitDiskImage(drv, file_path);
disk[drv]->inserted = true;
svi_UseDisk = 1;
}
}
}
void MEMORY_EX::close_disk(int drv)
{
if(drv < MAX_DRIVE && disk[drv]->inserted) {
// disk[drv]->close();
wd179x_CloseDiskImage(drv);
disk[drv]->inserted = false;
svi_UseDisk = 0;
}
}
bool MEMORY_EX::is_disk_inserted(int drv)
{
if(drv < MAX_DRIVE) {
return disk[drv]->inserted;
}
return false;
}
void MEMORY_EX::is_disk_protected(int drv, bool value)
{
if(drv < MAX_DRIVE) {
disk[drv]->write_protected = value;
}
}
bool MEMORY_EX::is_disk_protected(int drv)
{
if(drv < MAX_DRIVE) {
return disk[drv]->write_protected;
}
return false;
}
#endif
#define STATE_VERSION 1
bool MEMORY_EX::process_state(FILEIO* state_fio, bool loading)
{
if(!state_fio->StateCheckUint32(STATE_VERSION)) {
return false;
}
if(!state_fio->StateCheckInt32(this_device_id)) {
return false;
}
state_fio->StateValue(inserted);
// post process
if(loading) {
if(inserted) {
SET_BANK(0x0000, 0x7fff, wdmy, rom);
SET_BANK(0x8000, 0xffff, ram, ram);
} else {
SET_BANK(0x0000, 0x7fff, wdmy, bio);
SET_BANK(0x8000, 0xffff, ram, ram);
}
}
return true;
}
msx_ex.h
/*
Common Source Code Project
SVI-3x8
Origin : src/vm/msx/msx.h
modified by tanam
Date : 2018.12.09-
[ virtual machine ]
*/
#ifndef _MSX_EX_H_
#define _MSX_EX_H_
#if defined(_SVI3X8)
#define DEVICE_NAME "SPECTRAVIDEO SVI-3x8"
#define CONFIG_NAME "svi3x8"
#endif
#if defined(_SVI3X8)
#define _MSX1_VARIANTS
#define MAINROM_SLOT 0x00
#define CART1_SLOT 0x01
#define FDD_PATCH_SLOT 0x8B
#endif
// device informations for virtual machine
#define FRAMES_PER_SEC 60
#define LINES_PER_FRAME 262
#define CPU_CLOCKS 3579545
#if defined(_MSX1_VARIANTS)
#define SCREEN_WIDTH 512
#define SCREEN_HEIGHT 384
#define WINDOW_WIDTH_ASPECT 576
#endif
#define TMS9918A_VRAM_SIZE 0x4000
#define TMS9918A_LIMIT_SPRITES
//#if defined(FDD_PATCH_SLOT)
#define MAX_DRIVE 2
//#define SUPPORT_MEDIA_TYPE_1DD
//#define Z80_PSEUDO_BIOS
//#endif
#define HAS_AY_3_8910
// for Flappy Limited '85
#define AY_3_891X_PORT_MODE 0x80
// device informations for win32
#define USE_CART 2
#define USE_TAPE 1
//#if defined(FDD_PATCH_SLOT)
#define USE_FLOPPY_DISK 2
//#endif
#define USE_AUTO_KEY 6
#define USE_AUTO_KEY_RELEASE 10
#define USE_SOUND_VOLUME 7
#define USE_JOYSTICK
#define USE_DEBUGGER
#define USE_STATE
//#define USE_PRINTER
//#define USE_PRINTER_TYPE 4
#include "../../common.h"
#include "../../fileio.h"
#include "../vm_template.h"
#ifdef USE_SOUND_VOLUME
static const _TCHAR *sound_device_caption[] = {
_T("PSG"), _T("Beep"), _T("CMT (Signal)"),
_T("Cart#1"), _T("Cart#2"), _T("MSX-MUSIC"), _T("Noise (CMT)"),
};
#endif
class EMU;
class DEVICE;
class EVENT;
//class DATAREC;
class I8255;
class IO;
class NOT;
class AY_3_891X;
class PCM1BIT;
class TMS9918A;
class Z80;
class JOYSTICK;
class KEYBOARD;
class MEMORY_EX;
class SLOT_MAINROM;
class SLOT_CART;
#if defined(USE_PRINTER)
class PRINTER;
#endif
//#if defined(FDD_PATCH_SLOT)
//class SLOT_FDD_PATCH;
//#endif
class VM : public VM_TEMPLATE
{
protected:
// EMU* emu;
// devices
EVENT* event;
// DATAREC* drec;
I8255* pio;
IO* io;
NOT* not_remote;
AY_3_891X* psg;
PCM1BIT* pcm;
TMS9918A* vdp;
Z80* cpu;
JOYSTICK* joystick;
KEYBOARD* keyboard;
MEMORY_EX* memory;
SLOT_MAINROM *slot_mainrom;
SLOT_CART *slot_cart[1];
//#ifdef USE_PRINTER
// PRINTER* printer;
//#endif
public:
// ----------------------------------------
// initialize
// ----------------------------------------
VM(EMU* parent_emu);
~VM();
// ----------------------------------------
// for emulation class
// ----------------------------------------
// drive virtual machine
void reset();
void run();
double get_frame_rate()
{
return FRAMES_PER_SEC;
}
#ifdef USE_DEBUGGER
// debugger
DEVICE *get_cpu(int index);
#endif
// draw screen
void draw_screen();
// sound generation
void initialize_sound(int rate, int samples);
uint16_t* create_sound(int* extra_frames);
int get_sound_buffer_ptr();
#ifdef USE_SOUND_VOLUME
void set_sound_device_volume(int ch, int decibel_l, int decibel_r);
#endif
// user interface
void open_cart(int drv, const _TCHAR* file_path);
void close_cart(int drv);
bool is_cart_inserted(int drv);
void play_tape(int drv, const _TCHAR* file_path);
void rec_tape(int drv, const _TCHAR* file_path);
void close_tape(int drv);
bool is_tape_inserted(int drv);
bool is_tape_playing(int drv);
bool is_tape_recording(int drv);
int get_tape_position(int drv);
const _TCHAR* get_tape_message(int drv);
void push_play(int drv);
void push_stop(int drv);
void push_fast_forward(int drv);
void push_fast_rewind(int drv);
void push_apss_forward(int drv) {}
void push_apss_rewind(int drv) {}
#if defined(FDD_PATCH_SLOT)
void open_floppy_disk(int drv, const _TCHAR* file_path, int bank);
void close_floppy_disk(int drv);
bool is_floppy_disk_inserted(int drv);
void is_floppy_disk_protected(int drv, bool value);
bool is_floppy_disk_protected(int drv);
uint32_t is_floppy_disk_accessed();
#endif
bool is_frame_skippable();
void update_config();
bool process_state(FILEIO* state_fio, bool loading);
// ----------------------------------------
// for each device
// ----------------------------------------
// devices
DEVICE* get_device(int id);
// DEVICE* dummy;
// DEVICE* first_device;
// DEVICE* last_device;
};
#endif
msx_ex.cpp
/*
Common Source Code Project
SVI-3x8
Origin : src/vm/msx/msx_ex.cpp
modified by tanam
Date : 2018.12.09-
[ virtual machine ]
*/
#include "msx_ex.h"
#include "../../emu.h"
#include "../device.h"
#include "../event.h"
//#include "../datarec.h"
#include "../i8255.h"
#include "../io.h"
#include "../noise.h"
#include "../not.h"
#include "../ay_3_891x.h"
#include "../pcm1bit.h"
#include "../tms9918a.h"
#include "../z80.h"
#ifdef USE_DEBUGGER
#include "../debugger.h"
#endif
#include "joystick.h"
#include "keyboard.h"
#include "memory_ex.h"
#ifdef USE_PRINTER
#include "printer.h"
#include "../prnfile.h"
#endif
// ----------------------------------------------------------------------------
// initialize
// ----------------------------------------------------------------------------
VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
{
// create devices
first_device = last_device = NULL;
dummy = new DEVICE(this, emu); // must be 1st device
event = new EVENT(this, emu); // must be 2nd device
// drec = new DATAREC(this, emu);
// drec->set_context_noise_play(new NOISE(this, emu));
// drec->set_context_noise_stop(new NOISE(this, emu));
// drec->set_context_noise_fast(new NOISE(this, emu));
pio = new I8255(this, emu);
io = new IO(this, emu);
not_remote = new NOT(this, emu);
psg = new AY_3_891X(this, emu);
pcm = new PCM1BIT(this, emu);
vdp = new TMS9918A(this, emu);
cpu = new Z80(this, emu);
joystick = new JOYSTICK(this, emu);
keyboard = new KEYBOARD(this, emu);
memory = new MEMORY_EX(this, emu);
#ifdef USE_PRINTER
printer = new PRINTER(this, emu);
#endif
// set contexts
event->set_context_cpu(cpu);
event->set_context_sound(psg);
event->set_context_sound(pcm);
// event->set_context_sound(drec);
// event->set_context_sound(drec->get_context_noise_play());
// event->set_context_sound(drec->get_context_noise_stop());
// event->set_context_sound(drec->get_context_noise_fast());
// drec->set_context_ear(psg, SIG_AY_3_891X_PORT_A, 0x80);
pio->set_context_port_c(keyboard, SIG_KEYBOARD_COLUMN, 0x0f, 0);
pio->set_context_port_c(not_remote, SIG_NOT_INPUT, 0x10, 0);
// not_remote->set_context_out(drec, SIG_DATAREC_REMOTE, 1);
// pio->set_context_port_c(drec, SIG_DATAREC_MIC, 0x20, 0);
pio->set_context_port_c(pcm, SIG_PCM1BIT_SIGNAL, 0x80, 0);
psg->set_context_port_b(memory, SIG_MEMORY_SEL, 0x0f, 0);
vdp->set_context_irq(cpu, SIG_CPU_IRQ, 1);
joystick->set_context_psg(psg);
joystick->set_context_memory(memory);
keyboard->set_context_pio(pio);
#ifdef USE_PRINTER
if(config.printer_type == 0) {
printer->set_context_prn(new PRNFILE(this, emu));
} else {
printer->set_context_prn(printer);
}
#endif
// cpu bus
cpu->set_context_mem(memory);
cpu->set_context_io(io);
cpu->set_context_intr(dummy);
#ifdef USE_DEBUGGER
cpu->set_context_debugger(new DEBUGGER(this, emu));
#endif
// i/o bus
io->set_iomap_range_rw(0x30, 0x38, memory);
io->set_iomap_range_w(0x80, 0x81, vdp);
io->set_iomap_range_r(0x84, 0x85, vdp);
io->set_iomap_range_w(0x94, 0x97, pio);
io->set_iomap_range_r(0x99, 0x9a, pio);
io->set_iomap_alias_w(0x88, psg, 0); // PSG ch
io->set_iomap_alias_w(0x8c, psg, 1); // PSG data
io->set_iomap_alias_r(0x90, psg, 1); // STICK
io->set_iomap_alias_r(0x98, memory, 1); // STRIG
#ifdef USE_PRINTER
io->set_iomap_range_rw(0x10, 0x11, printer);
#endif
// initialize all devices
for(DEVICE* device = first_device; device; device = device->next_device) {
device->initialize();
}
}
VM::~VM()
{
// delete all devices
for(DEVICE* device = first_device; device;) {
DEVICE *next_device = device->next_device;
device->release();
delete device;
device = next_device;
}
}
DEVICE* VM::get_device(int id)
{
for(DEVICE* device = first_device; device; device = device->next_device) {
if(device->this_device_id == id) {
return device;
}
}
return NULL;
}
// ----------------------------------------------------------------------------
// drive virtual machine
// ----------------------------------------------------------------------------
void VM::reset()
{
// reset all devices
for(DEVICE* device = first_device; device; device = device->next_device) {
device->reset();
}
}
void VM::run()
{
event->drive();
}
// ----------------------------------------------------------------------------
// debugger
// ----------------------------------------------------------------------------
#ifdef USE_DEBUGGER
DEVICE *VM::get_cpu(int index)
{
if(index == 0) {
return cpu;
}
return NULL;
}
#endif
// ----------------------------------------------------------------------------
// draw screen
// ----------------------------------------------------------------------------
void VM::draw_screen()
{
vdp->draw_screen();
}
// ----------------------------------------------------------------------------
// soud manager
// ----------------------------------------------------------------------------
void VM::initialize_sound(int rate, int samples)
{
// init sound manager
event->initialize_sound(rate, samples);
// init sound gen
psg->initialize_sound(rate, 3579545, samples, 0, 0);
pcm->initialize_sound(rate, 8000);
}
uint16_t* VM::create_sound(int* extra_frames)
{
return event->create_sound(extra_frames);
}
int VM::get_sound_buffer_ptr()
{
return event->get_sound_buffer_ptr();
}
#ifdef USE_SOUND_VOLUME
void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
{
if(ch == 0) {
psg->set_volume(1, decibel_l, decibel_r);
} else if(ch == 1) {
pcm->set_volume(0, decibel_l, decibel_r);
// } else if(ch == 2) {
// drec->set_volume(0, decibel_l, decibel_r);
// } else if(ch == 6) {
// drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
// drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
// drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
}
}
#endif
// ----------------------------------------------------------------------------
// user interface
// ----------------------------------------------------------------------------
void VM::open_cart(int drv, const _TCHAR* file_path)
{
if(drv == 0) {
// slot_cart[drv]->open_cart(file_path);
// memory->set_context_slot(MAINROM_SLOT, slot_cart[0]);
memory->open_cart(file_path);
}
reset();
}
void VM::close_cart(int drv)
{
if(drv == 0) {
// slot_cart[drv]->close_cart();
// memory->set_context_slot(MAINROM_SLOT, slot_mainrom);
memory->close_cart();
}
reset();
}
bool VM::is_cart_inserted(int drv)
{
if(drv == 0) {
// return slot_cart[drv]->is_cart_inserted();
return memory->is_cart_inserted();
} else {
return false;
}
}
void VM::play_tape(int drv, const _TCHAR* file_path)
{
memory->play_tape(file_path);
// bool remote = drec->get_remote();
// if(drec->play_tape(file_path) && remote) {
// // if machine already sets remote on, start playing now
// push_play(drv);
// }
}
void VM::rec_tape(int drv, const _TCHAR* file_path)
{
// bool remote = drec->get_remote();
// if(drec->rec_tape(file_path) && remote) {
// // if machine already sets remote on, start recording now
// push_play(drv);
// }
}
void VM::close_tape(int drv)
{
emu->lock_vm();
memory->close_tape();
emu->unlock_vm();
// drec->set_remote(false);
}
bool VM::is_tape_inserted(int drv)
{
return memory->is_tape_inserted();
}
bool VM::is_tape_playing(int drv)
{
return false;
// return drec->is_tape_playing();
}
bool VM::is_tape_recording(int drv)
{
return false;
// return drec->is_tape_recording();
}
int VM::get_tape_position(int drv)
{
return 0;
// return drec->get_tape_position();
}
const _TCHAR* VM::get_tape_message(int drv)
{
return memory->get_message();
}
void VM::push_play(int drv)
{
// drec->set_remote(false);
// drec->set_ff_rew(0);
// drec->set_remote(true);
}
void VM::push_stop(int drv)
{
// drec->set_remote(false);
}
void VM::push_fast_forward(int drv)
{
// drec->set_remote(false);
// drec->set_ff_rew(1);
// drec->set_remote(true);
}
void VM::push_fast_rewind(int drv)
{
// drec->set_remote(false);
// drec->set_ff_rew(-1);
// drec->set_remote(true);
}
#if defined(FDD_PATCH_SLOT)
void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
{
memory->open_disk(drv, file_path, bank);
}
void VM::close_floppy_disk(int drv)
{
memory->close_disk(drv);
}
bool VM::is_floppy_disk_inserted(int drv)
{
return memory->is_disk_inserted(drv);
}
void VM::is_floppy_disk_protected(int drv, bool value)
{
memory->is_disk_protected(drv, value);
}
bool VM::is_floppy_disk_protected(int drv)
{
return memory->is_disk_protected(drv);
}
uint32_t VM::is_floppy_disk_accessed()
{
return memory->read_signal(0);
}
#endif
bool VM::is_frame_skippable()
{
return event->is_frame_skippable();
}
void VM::update_config()
{
for(DEVICE* device = first_device; device; device = device->next_device) {
device->update_config();
}
}
#define STATE_VERSION 5
bool VM::process_state(FILEIO* state_fio, bool loading)
{
if(!state_fio->StateCheckUint32(STATE_VERSION)) {
return false;
}
for(DEVICE* device = first_device; device; device = device->next_device) {
const char *name = typeid(*device).name() + 6; // skip "class "
int len = strlen(name);
if(!state_fio->StateCheckInt32(len)) {
return false;
}
if(!state_fio->StateCheckBuffer(name, len, 1)) {
return false;
}
if(!device->process_state(state_fio, loading)) {
return false;
}
}
return true;
}