ADAMem DOS and ADAMem SDL v1.81
Visual Studio 2008でADAMem SDLをビルドしてみました。
ADAMem DOS and ADAMem SDL v1.81 - Page 2 - ColecoVision / Adam - AtariAge Forums
AdamemSDL.c
Mouse_Init (); // keyboardmode=(EmuMode)? 1:0; keyboardmode=0;
Z80IO.h
; //#if (__GNUC__ <= 3 && __GNUC__MINOR__ <= 4) \ // || (__GNUC__ >= 2 && __GNUC__MINOR__ >= 7) //#define FASTCALL __attribute__ ((regparm(3))) //#ifdef INLINE_MEM //#define INLINE_MEM_GNU //#endif //#else #define FASTCALL //#endif
SVI-328の拡張スロットにMSXカートリッジをつないでみる
SVI-328の拡張スロットに、MSXカートリッジをつなぐ方法を考えてみました。
以下の回路図から転記してみました。
http://www.hardwarebook.info/Spectravideo_SVI318/328_Expansion_Bus
http://d4.princess.ne.jp/msx/datas/slot.html
SVI-328 MSX PIN 1 +5V PIN45 +5V PIN 2 /CTRL2 NC PIN 3 +12V PIN48 +12V PIN 4 -12V PIN50 -12V PIN 5 /CTRL1 NC PIN 6 /WAIT PIN 7 /WAIT PIN 7 /RST PIN15 /RST PIN 8 CLK PIN42 CLK PIN 9 A15 PIN18 A15 PIN10 A14 PIN25 A14 PIN11 A13 PIN26 A13 PIN12 A12 PIN23 A12 PIN13 A11 PIN19 A11 PIN14 A10 PIN20 A10 PIN15 A9 PIN17 A9 PIN16 A8 PIN24 A8 PIN17 A7 PIN21 A7 PIN18 A6 PIN22 A6 PIN19 A5 PIN31 A5 PIN20 A4 PIN32 A4 PIN21 A3 PIN29 A3 PIN22 A2 PIN32 A2 PIN23 A1 PIN27 A1 PIN24 A0 PIN28 A0 PIN25 /RFSH PIN 6 /RFSH PIN26 /EXCSR NC PIN27 /M1 PIN 9 /M1 PIN28 /EXCSW NC PIN29 /WR PIN13 /WR PIN30 /MREQ PIN12 /MREQ PIN31 /IORQ PIN11 /IORQ PIN32 /RD PIN14 /RD PIN33 D0 PIN34 D0 PIN34 D1 PIN33 D1 PIN35 D2 PIN36 D2 PIN36 D3 PIN35 D3 PIN37 D4 PIN38 D4 PIN38 D5 PIN37 D5 PIN39 D6 PIN40 D6 PIN40 D7 PIN39 D7 PIN41 CSOUND PIN49 CSOUND PIN42 /INT PIN 8 /INT PIN43 /RAMDIS NC PIN44 /ROMDIS NC PIN45 /BK32 NC PIN46 /BK31 NC PIN47 /BK22 NC PIN48 /BK21 NC PIN49 GND PIN41 GND PIN50 GND PIN43 GND
SVI-328でSG-1000を動かす
メモリーマップが同じため比較的かんたんなパッチで動きます。
SG-1000のメモリマップはROMが0000-7FFF、RAMがC000-C3FF SVI-328のメモリマップはROMが0000-7FFF、RAMが8000-FFFF
VDPとジョイパッドのポート番号を修正して行きます。ただしサウンドは音源チップが異なるため鳴りません。
D3 BE→80 D3 BF→81 DB BE→84 DB BF→85
guzzler.sg.pat
* Patch for Guzzler.sg * * Made by バイナリ書き替え君 Version 2.03 * *== TARGET_FILE ================ FILENAME Guzzler.sg * FileSize: 8192 bytes * LastMod : 1996/12/24 23:32:00 *=============================== 00000001: ED 31 00000002: 56 00 00000003: 31 C1 00000004: 00 ED 00000005: C1 56 0000003B: BF 85 00000129: BF 81 0000016C: BF 81 00000170: BF 81 0000017C: BF 81 00000180: BF 81 0000018B: BF 81 0000018E: BF 81 00000191: BE 80 0000019C: BE 80 000001A5: BF 81 000001A8: BF 81 0000169F: 3A 3E 000016A0: 09 0E 000016A1: C0 D3 000016A2: B7 88 000016A3: CA DB 000016A4: 0B 90 000016A5: 17 47 000016A6: 3E DB 000016A7: 07 98 000016A8: D3 F6 000016A9: DE EF 000016AA: DB C3 000016AB: DC 0B 000016AC: B7 17 0000170B: DB 00 0000170C: DC A0
SVI-3x8エミュレータをつくる その4
以下を取り込んでディスクに対応しました。
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; }
SVI-3x8エミュレータをつくる その3
メモリーマップを見直して以下に対応しました。
https://www.msx.org/news/en/nyyrikki-msx-rom-loader-svi
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_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_rw(0x98, memory, 0); // 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) { 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(); drec->close_tape(); emu->unlock_vm(); drec->set_remote(false); } bool VM::is_tape_inserted(int drv) { return drec->is_tape_inserted(); } bool VM::is_tape_playing(int drv) { return drec->is_tape_playing(); } bool VM::is_tape_recording(int drv) { return drec->is_tape_recording(); } int VM::get_tape_position(int drv) { return drec->get_tape_position(); } const _TCHAR* VM::get_tape_message(int drv) { return drec->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); } 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; }
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 // 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; uint8_t strig; public: MEMORY_EX(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) { set_device_name(_T("Memory Bus")); strig=0xff; } ~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) { return strig; } void write_io8(uint32_t addr, uint32_t data) { strig = data; } // unique functions void open_cart(const _TCHAR *file_path); void close_cart(); bool is_cart_inserted() { return inserted; } bool load_cart(const _TCHAR *file_path/*, uint8_t *rom*/); }; #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" #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() { 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; close_cart(); } 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)); return; } void MEMORY_EX::write_data8(uint32_t addr, uint32_t data) { wbank[addr >> 13][addr & 0x1fff] = data; } uint32_t MEMORY_EX::read_data8(uint32_t addr) { 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, rdmy,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); } #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; }
GAMELIB16 その8
ここを見ていてX1でできるなら、メガドライブ・IBM JXでもXEVIOUSっぽいものを動かしたいと思いました。
http://85data.world.coocan.jp/02-info-soft-xevious01.html
以下が生成されたマップチップです。8×8ドットのチップが696個にもなりました。
マップチップを活用するためにBMPTOOLというものを開発してみました。上記サイトの生成されたマップチップを256色BMP形式に保存して試してみます。
http://www.geocities.jp/parallel_computer_inc/bmptool.zip
>bmptool.exe -i mapset.bmp 640 x 72 pixels 256 colors (0-719) mapset.map is created
8x8ドットのチップが720個(0-719)ですね。このmapset.mapを書き換えることでAREA1~16のマップを生成していきます。
>type mapset.map 0000,0001,0002,0003,0004,0005,0006,0007,0008,0009,000a,000b,000c,000d,000e,000f,0010,0011,0012,0013,0014, ... 0050,0051,0052,0053,0054,0055,0056,0057,0058,0059,005a,005b,005c,005d,005e,005f,0060,0061,0062,0063,0064, ... :
たとえばAREA1はこんな感じです。
http://www.geocities.jp/parallel_computer_inc/mapset.zip
>type mapset.map 02a8,028f,02aa,02ae,02b1,028b,02ac,02a8,028f,02aa,02ae,02b1,028b,02ac,02a8,028f,02aa,02ae,02b1,028b,02ac, ... 0292,0293,0290,0291,02a3,02a4,02a5,02a6,029c,029d,029e,029f,02a0,02a1,0294,02a2,0292,0293,0290,0291,02a3, ... :
BMPTOOLを使ってmapset.bmpとmapset.mapからoutput.bmpを生成します。
>bmptool.exe -m mapset.bmp output.bmp is created