--- /dev/null
+cmake_minimum_required (VERSION 2.6)
+
+message("* vm/fm-towns")
+
+add_library(vm_fmtowns
+ bios.cpp
+ cmos.cpp
+ floppy.cpp
+ keyboard.cpp
+ memory.cpp
+ scsi.cpp
+ timer.cpp
+ fmr50.cpp
+)
\ No newline at end of file
--- /dev/null
+/*
+ FUJITSU FMR-30 Emulator 'eFMR-30'
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.10.06 -
+
+ [ bios ]
+*/
+
+#include "bios.h"
+#include "../disk.h"
+
+// regs
+#define AX regs[0]
+#define CX regs[1]
+#define DX regs[2]
+#define BX regs[3]
+#define SP regs[4]
+#define BP regs[5]
+#define SI regs[6]
+#define DI regs[7]
+
+#define AL regs8[0]
+#define AH regs8[1]
+#define CL regs8[2]
+#define CH regs8[3]
+#define DL regs8[4]
+#define DH regs8[5]
+#define BL regs8[6]
+#define BH regs8[7]
+#define SPL regs8[8]
+#define SPH regs8[9]
+#define BPL regs8[10]
+#define BPH regs8[11]
+#define SIL regs8[12]
+#define SIH regs8[13]
+#define DIL regs8[14]
+#define DIH regs8[15]
+
+// sregs
+#define ES sregs[0]
+#define CS sregs[1]
+#define SS sregs[2]
+#define DS sregs[3]
+
+// error
+#define ERR_FDD_NOTREADY 1
+#define ERR_FDD_PROTECTED 2
+#define ERR_FDD_DELETED 4
+#define ERR_FDD_NOTFOUND 8
+#define ERR_FDD_CRCERROR 0x10
+#define ERR_SCSI_NOTREADY 1
+#define ERR_SCSI_PARAMERROR 2
+#define ERR_SCSI_NOTCONNECTED 4
+
+#if defined(_FMR30)
+// FMR-30
+#define CMOS_SIZE 0x2000
+#define VRAM_SIZE 0x20000
+#define IPL_SIZE 0x10000
+#define IPL_ID '2'
+#elif defined(_FMR50)
+// FMR-50
+#define CMOS_SIZE 0x800
+#define VRAM_SIZE 0x40000
+#define IPL_SIZE 0x4000
+#define IPL_ID '1'
+#elif defined(_FMR60)
+// FMR-60
+#define CMOS_SIZE 0x800
+#define VRAM_SIZE 0x80000
+#define IPL_SIZE 0x4000
+#define IPL_ID '1'
+#endif
+
+#define BLOCK_SIZE 512
+
+static const int iotable[][2] = {
+#ifdef _FMR30
+ {0x0100, 0x19}, // pic
+ {0x0101, 0x40},
+ {0x0101, 0x80},
+ {0x0101, 0x01},
+ {0x0101, 0xff},
+ {0x0108, 0x19},
+ {0x010a, 0x48},
+ {0x010a, 0x07},
+ {0x010a, 0x01},
+ {0x010a, 0xff},
+ {0x0042, 0x00}, // timer
+ {0x0133, 0x30},
+ {0x0130, 0xa0},
+ {0x0130, 0x86},
+ {0x000b, 0x02}, // sio
+ {0x0009, 0x00},
+ {0x0009, 0x50},
+ {0x0009, 0x7f},
+ {0x0009, 0x15},
+ {0x0013, 0x02},
+ {0x001d, 0x02}, // memory
+ {0x001e, 0x00},
+ {0x0040, 0x9f}, // psg
+ {0x0040, 0xbf},
+ {0x0040, 0xdf},
+ {0x0040, 0xff},
+ {0x0300, 0x01}, // lcdc
+ {0x0302, 0x50},
+ {0x0300, 0x09},
+ {0x0302, 0x0f},
+ {0x0300, 0x0a},
+ {0x0302, 0x20},
+ {0x0300, 0x0b},
+ {0x0302, 0x0d},
+ {0x0300, 0x0c},
+ {0x0302, 0x00},
+ {0x0300, 0x0d},
+ {0x0302, 0x00},
+ {0x0300, 0x0e},
+ {0x0302, 0x00},
+ {0x0300, 0x0f},
+ {0x0302, 0x00},
+ {0x0300, 0x11},
+ {0x0302, 0xc7},
+ {0x0300, 0x1d},
+ {0x0302, 0x00},
+ {0x0308, 0x63},
+ {0x0309, 0x00},
+ {0x030a, 0x00},
+#else
+ {0x0060, 0x00}, // timer
+ {0x0604, 0x00}, // keyboard
+ {0x0000, 0x19}, // pic
+ {0x0002, 0x40},
+ {0x0002, 0x80},
+ {0x0002, 0x0d},
+ {0x0002, 0xfe},
+ {0x0010, 0x19},
+ {0x0012, 0x48},
+ {0x0012, 0x87},
+ {0x0012, 0x09},
+ {0x0012, 0xff},
+ {0x0000, 0x20},
+ {0x0046, 0x36}, // pit
+ {0x0040, 0x00},
+ {0x0040, 0x78},
+ {0x0404, 0x00}, // memory
+ {0x0500, 0x00}, // crtc
+ {0x0502, 0x35},
+ {0x0500, 0x01},
+ {0x0502, 0x28},
+ {0x0500, 0x02},
+ {0x0502, 0x2c},
+ {0x0500, 0x03},
+ {0x0502, 0x04},
+ {0x0500, 0x04},
+ {0x0502, 0x1a},
+ {0x0500, 0x05},
+ {0x0502, 0x08},
+ {0x0500, 0x06},
+ {0x0502, 0x19},
+ {0x0500, 0x07},
+ {0x0502, 0x19},
+ {0x0500, 0x08},
+ {0x0502, 0x00},
+ {0x0500, 0x09},
+ {0x0502, 0x0f},
+ {0x0500, 0x0a},
+ {0x0502, 0x20},
+ {0x0500, 0x0b},
+ {0x0502, 0x1e},
+ {0x0500, 0x0c},
+ {0x0502, 0x00},
+ {0x0500, 0x0d},
+ {0x0502, 0x00},
+ {0x0500, 0x0e},
+ {0x0502, 0x00},
+ {0x0500, 0x0f},
+ {0x0502, 0x00},
+ {0x0500, 0x10},
+ {0x0502, 0x00},
+ {0x0500, 0x11},
+ {0x0502, 0x00},
+ {0x0500, 0x1e},
+ {0x0502, 0x00},
+ {0x0500, 0x1f},
+ {0x0502, 0x00},
+ {0xfd98, 0x00}, // palette
+ {0xfd99, 0x01},
+ {0xfd9a, 0x02},
+ {0xfd9b, 0x03},
+ {0xfd9c, 0x04},
+ {0xfd9d, 0x05},
+ {0xfd9e, 0x06},
+ {0xfd9f, 0x07},
+ {0xfda0, 0x0f}, // video
+#endif
+ {-1, -1}
+};
+
+// cmos: $000-
+static const uint8_t cmos_t[] = {
+#ifdef _FMR30
+ 0x01,0xff,0x42,0x4f,0x4f,0x54,0xa8,0x00,0x40,0x00,0x01,0xfe,0x53,0x45,0x54,0x55,
+ 0xe8,0x00,0x00,0x01,0x01,0xfd,0x4c,0x4f,0x47,0x20,0xe8,0x01,0x10,0x03,0x01,0xfc,
+ 0x4f,0x41,0x53,0x59,0xf8,0x04,0x20,0x00,0x01,0xfb,0x44,0x45,0x42,0x20,0x18,0x05,
+ 0x00,0x01,0x01,0xfa,0x44,0x45,0x53,0x4b,0x18,0x06,0x32,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x4a,0x06,0x7b,0x19,0x97,0x62,0x79,0x41
+#else
+ 0x01,0xff,0x42,0x4f,0x4f,0x54,0xa8,0x00,0x40,0x00,0x01,0xfe,0x53,0x45,0x54,0x55,
+ 0xe8,0x00,0x00,0x01,0x01,0xfd,0x4c,0x4f,0x47,0x20,0xe8,0x01,0x10,0x03,0x01,0xfc,
+ 0x4f,0x41,0x53,0x59,0xf8,0x04,0x20,0x00,0x01,0xfb,0x58,0x45,0x4e,0x49,0x18,0x05,
+ 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+// 0x28,0x05,0x99,0x02,0xe1,0xe1,0x79,0x41
+ 0x28,0x05,0x99,0x02,0x00,0x00,0x79,0x41
+#endif
+};
+// FMR-30: cmos $1fd0-
+// FMR-50: cmos $7d0-
+static const uint8_t cmos_b[] = {
+#ifdef _FMR30
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+#else
+ 0x00,0x00,0x01,0x02,0x03,0x04,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+#endif
+};
+
+// boot message
+static const uint8_t msg_c[] = {
+ 0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,
+ 0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,
+ 0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,
+ 0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07
+};
+
+// '\83V\83X\83e\83\80\82ð\83Z\83b\83g\82µ\82Ä\82\82¾\82³\82¢'
+static const uint8_t msg_k[] = {
+ 0x25,0x37,0x00,0x00,0x25,0x39,0x00,0x00,0x25,0x46,0x00,0x00,0x25,0x60,0x00,0x00,
+ 0x24,0x72,0x00,0x00,0x25,0x3b,0x00,0x00,0x25,0x43,0x00,0x00,0x25,0x48,0x00,0x00,
+ 0x24,0x37,0x00,0x00,0x24,0x46,0x00,0x00,0x24,0x2f,0x00,0x00,0x24,0x40,0x00,0x00,
+ 0x24,0x35,0x00,0x00,0x24,0x24,0x00,0x00,0x21,0x21,0x00,0x00
+};
+
+void BIOS::initialize()
+{
+ // to increment timeout counter
+ register_frame_event(this);
+
+ // check scsi drives
+ FILEIO* fio = new FILEIO();
+ for(int i = 0; i < MAX_SCSI; i++) {
+ if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), i), FILEIO_READ_WRITE_BINARY)) {
+ uint32_t file_size = fio->FileLength();
+ if(file_size == 0) {
+ // from ../scsi_hdd.cpp
+ #define SCSI_BUFFER_SIZE 0x10000
+ uint32_t remain = (file_size = 0x2800000); // 40MB
+ void *tmp = calloc(1, SCSI_BUFFER_SIZE);
+ while(remain > 0) {
+ uint32_t length = min(remain, (uint32_t)SCSI_BUFFER_SIZE);
+ fio->Fwrite(tmp, length, 1);
+ remain -= length;
+ }
+ free(tmp);
+ #undef SCSI_BUFFER_SIZE
+ }
+ scsi_blocks[i] = file_size / BLOCK_SIZE;
+ fio->Fclose();
+ } else {
+ scsi_blocks[i] = 0;
+ }
+ }
+ delete fio;
+}
+
+void BIOS::reset()
+{
+ for(int i = 0; i < MAX_DRIVE; i++) {
+ access_fdd[i] = false;
+ }
+ access_scsi = false;
+ secnum = 1;
+ timeout = 0;
+}
+
+void BIOS::event_frame()
+{
+ timeout++;
+}
+
+bool BIOS::bios_call_i86(uint32_t PC, uint16_t regs[], uint16_t sregs[], int32_t* ZeroFlag, int32_t* CarryFlag)
+{
+ uint8_t *regs8 = (uint8_t *)regs;
+ int drv = AL & 0xf;
+ uint8_t buffer[BLOCK_SIZE * 4];
+
+ if(PC == 0xfffc4) {
+ // disk bios
+#ifdef _DEBUG_LOG
+ this->out_debug_log(_T("%6x\tDISK BIOS: AH=%2x,AL=%2x,CX=%4x,DX=%4x,BX=%4x,DS=%2x,DI=%2x\n"), get_cpu_pc(0), AH,AL,CX,DX,BX,DS,DI);
+#endif
+ if(AH == 2) {
+ // drive status
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTREADY;
+ *CarryFlag = 1;
+ return true;
+ }
+ AH = 0;
+ DL = 4;
+ if(disk[drv]->write_protected) {
+ DL |= 2;
+ }
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ if((AL & 0xf0) == 0xb0) {
+ // scsi
+ if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_NOTCONNECTED;
+ *CarryFlag = 1;
+ return true;
+ }
+ AH = 0;
+ AL = (BLOCK_SIZE == 128) ? 0 : (BLOCK_SIZE == 256) ? 1 : (BLOCK_SIZE == 512) ? 2 : 3;
+ BX = scsi_blocks[drv] >> 16;
+ DX = scsi_blocks[drv] & 0xffff;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 2;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 3 || AH == 4) {
+ // restore/seek
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTREADY;
+ *CarryFlag = 1;
+ return true;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ if((AL & 0xf0) == 0xb0) {
+ // scsi
+ if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_NOTCONNECTED;
+ *CarryFlag = 1;
+ return true;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 2;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 5) {
+ // read sectors
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTREADY;
+ *CarryFlag = 1;
+ return true;
+ }
+ // get initial c/h/r
+ int ofs = DS * 16 + DI;
+ int trk = CX;
+ int hed = DH & 1;
+ int sct = DL;
+ while(BX > 0) {
+ // search sector
+ disk[drv]->get_track(trk, hed);
+ access_fdd[drv] = true;
+ secnum = sct;
+ if(!disk[drv]->get_sector(trk, hed, sct - 1)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTFOUND;
+ *CarryFlag = 1;
+ return true;
+ }
+ // check id crc error
+ if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTFOUND | ERR_FDD_CRCERROR;
+ *CarryFlag = 1;
+ return true;
+ }
+ // check deleted mark
+ if(disk[drv]->deleted) {
+ AH = 0x80;
+ CX = ERR_FDD_DELETED;
+ *CarryFlag = 1;
+ return true;
+ }
+ // data transfer
+ for(int i = 0; i < disk[drv]->sector_size.sd; i++) {
+ d_mem->write_data8(ofs++, disk[drv]->sector[i]);
+ }
+ BX--;
+ // check data crc error
+ if(disk[drv]->data_crc_error && !disk[drv]->ignore_crc()) {
+ AH = 0x80;
+ CX = ERR_FDD_CRCERROR;
+ *CarryFlag = 1;
+ return true;
+ }
+ // update c/h/r
+ if(++sct > disk[drv]->sector_num.sd) {
+ sct = 1;
+ if(++hed > 1) {
+ hed = 0;
+ ++trk;
+ }
+ }
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ if((AL & 0xf0) == 0xb0) {
+ // scsi
+ if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_NOTCONNECTED;
+ *CarryFlag = 1;
+ return true;
+ }
+ FILEIO* fio = new FILEIO();
+ if(!fio->Fopen(create_local_path(_T("SCSI%d.DAT"), drv), FILEIO_READ_BINARY)) {
+ AH = 0x80;
+ CX = ERR_SCSI_NOTREADY;
+ *CarryFlag = 1;
+ delete fio;
+ return true;
+ }
+ // get params
+ int ofs = DS * 16 + DI;
+ int block = (CL << 16) | DX;
+ fio->Fseek(block * BLOCK_SIZE, FILEIO_SEEK_SET);
+ while(BX > 0) {
+ // check block
+ access_scsi = true;
+ if(!(block++ < scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_PARAMERROR;
+ *CarryFlag = 1;
+ fio->Fclose();
+ delete fio;
+ return true;
+ }
+ // data transfer
+ fio->Fread(buffer, BLOCK_SIZE, 1);
+ for(int i = 0; i < BLOCK_SIZE; i++) {
+ d_mem->write_data8(ofs++, buffer[i]);
+ }
+ BX--;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ fio->Fclose();
+ delete fio;
+ return true;
+ }
+ AH = 2;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 6) {
+ // write sectors
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTREADY;
+ *CarryFlag = 1;
+ return true;
+ }
+ if(disk[drv]->write_protected) {
+ AH = 0x80;
+ CX = ERR_FDD_PROTECTED;
+ *CarryFlag = 1;
+ return true;
+ }
+ // get initial c/h/r
+ int ofs = DS * 16 + DI;
+ int trk = CX;
+ int hed = DH & 1;
+ int sct = DL;
+ while(BX > 0) {
+ // search sector
+ disk[drv]->get_track(trk, hed);
+ access_fdd[drv] = true;
+ secnum = sct;
+ if(!disk[drv]->get_sector(trk, hed, sct - 1)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTFOUND;
+ *CarryFlag = 1;
+ return true;
+ }
+ // check id crc error
+ if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTFOUND | ERR_FDD_CRCERROR;
+ *CarryFlag = 1;
+ return true;
+ }
+ // data transfer
+ for(int i = 0; i < disk[drv]->sector_size.sd; i++) {
+ disk[drv]->sector[i] = d_mem->read_data8(ofs++);
+ }
+ BX--;
+ // clear deleted mark and data crc error
+ disk[drv]->set_deleted(false);
+ disk[drv]->set_data_crc_error(false);
+ // update c/h/r
+ if(++sct > disk[drv]->sector_num.sd) {
+ sct = 1;
+ if(++hed > 1) {
+ hed = 0;
+ ++trk;
+ }
+ }
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ if((AL & 0xf0) == 0xb0) {
+ // scsi
+ if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_NOTCONNECTED;
+ *CarryFlag = 1;
+ return true;
+ }
+ FILEIO* fio = new FILEIO();
+ if(!fio->Fopen(create_local_path(_T("SCSI%d.DAT"), drv), FILEIO_READ_WRITE_BINARY)) {
+ AH = 0x80;
+ CX = ERR_SCSI_NOTREADY;
+ *CarryFlag = 1;
+ delete fio;
+ return true;
+ }
+ // get params
+ int ofs = DS * 16 + DI;
+ int block = (CL << 16) | DX;
+ fio->Fseek(block * BLOCK_SIZE, FILEIO_SEEK_SET);
+ while(BX > 0) {
+ // check block
+ access_scsi = true;
+ if(!(block++ < scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_PARAMERROR;
+ *CarryFlag = 1;
+ fio->Fclose();
+ delete fio;
+ return true;
+ }
+ // data transfer
+ for(int i = 0; i < BLOCK_SIZE; i++) {
+ buffer[i] = d_mem->read_data8(ofs++);
+ }
+ fio->Fwrite(buffer, BLOCK_SIZE, 1);
+ BX--;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ fio->Fclose();
+ delete fio;
+ return true;
+ }
+ AH = 2;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 7) {
+ // verify sectors
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTREADY;
+ *CarryFlag = 1;
+ return true;
+ }
+ // get initial c/h/r
+ int trk = CX;
+ int hed = DH & 1;
+ int sct = DL;
+ while(BX > 0) {
+ // search sector
+ disk[drv]->get_track(trk, hed);
+ access_fdd[drv] = true;
+ secnum = sct;
+ if(!disk[drv]->get_sector(trk, hed, sct - 1)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTFOUND;
+ *CarryFlag = 1;
+ return true;
+ }
+ // check id crc error
+ if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTFOUND | ERR_FDD_CRCERROR;
+ *CarryFlag = 1;
+ return true;
+ }
+ // FIXME: verify
+ BX--;
+ // check data crc error
+ if(disk[drv]->data_crc_error && !disk[drv]->ignore_crc()) {
+ AH = 0x80;
+ CX = ERR_FDD_CRCERROR;
+ *CarryFlag = 1;
+ return true;
+ }
+ // update c/h/r
+ if(++sct > disk[drv]->sector_num.sd) {
+ sct = 1;
+ if(++hed > 1) {
+ hed = 0;
+ ++trk;
+ }
+ }
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ if((AL & 0xf0) == 0xb0) {
+ // scsi
+ if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_NOTCONNECTED;
+ *CarryFlag = 1;
+ return true;
+ }
+ // get params
+ int block = (CL << 16) | DX;
+ while(BX > 0) {
+ // check block
+ access_scsi = true;
+ if(!(block++ < scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_PARAMERROR;
+ *CarryFlag = 1;
+ return true;
+ }
+ BX--;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 2;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 8) {
+ // reset hard drive controller
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ } else if(AH == 9) {
+ // read id
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTREADY;
+ *CarryFlag = 1;
+ return true;
+ }
+ // get initial c/h
+ int ofs = DS * 16 + DI;
+ int trk = CX;
+ int hed = DH & 1;
+ // search sector
+ disk[drv]->get_track(trk, hed);
+ access_fdd[drv] = true;
+ if(++secnum > disk[drv]->sector_num.sd) {
+ secnum = 1;
+ }
+ if(!disk[drv]->get_sector(trk, hed, secnum - 1)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTFOUND;
+ *CarryFlag = 1;
+ return true;
+ }
+ // data transfer
+ for(int i = 0; i < 6; i++) {
+ d_mem->write_data8(ofs++, disk[drv]->id[i]);
+ }
+ // check id crc error
+ if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
+ AH = 0x80;
+ CX = ERR_FDD_CRCERROR;
+ *CarryFlag = 1;
+ return true;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 2;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 0xa) {
+ // format track
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
+ AH = 0x80;
+ CX = ERR_FDD_NOTREADY;
+ *CarryFlag = 1;
+ return true;
+ }
+ // get initial c/h
+ int ofs = DS * 16 + DI;
+ int trk = CX;
+ int hed = DH & 1;
+ // format track
+ disk[drv]->format_track(trk, hed);
+ access_fdd[drv] = true;
+ bool id_written = false;
+ bool sector_found = false;
+ int sector_length, sector_index;
+ for(int index = 0; index < disk[drv]->get_track_size(); index++) {
+ uint8_t datareg = d_mem->read_data8(ofs++);
+ if(datareg == 0xf5) {
+ // write a1h in missing clock
+ } else if(datareg == 0xf6) {
+ // write c2h in missing clock
+ } else if(datareg == 0xf7) {
+ // write crc
+ if(!id_written) {
+ // insert new sector with data crc error
+write_id:
+ id_written = true;
+ sector_found = false;
+ uint8_t c = disk[drv]->track[index - 4];
+ uint8_t h = disk[drv]->track[index - 3];
+ uint8_t r = disk[drv]->track[index - 2];
+ uint8_t n = disk[drv]->track[index - 1];
+ sector_length = 0x80 << (n & 3);
+ sector_index = 0;
+ disk[drv]->insert_sector(c, h, r, n, false, true, 0xe5, sector_length);
+ } else if(sector_found) {
+ // clear data crc error if all sector data are written
+ disk[drv]->set_data_crc_error(false);
+ id_written = false;
+ } else {
+ // data mark of current sector is not written
+ disk[drv]->set_data_mark_missing();
+ goto write_id;
+ }
+ } else if(id_written) {
+ if(sector_found) {
+ // sector data
+ if(sector_index < sector_length) {
+ disk[drv]->sector[sector_index] = datareg;
+ }
+ sector_index++;
+ } else if(datareg == 0xf8 || datareg == 0xfb) {
+ // data mark
+ disk[drv]->set_deleted(datareg == 0xf8);
+ sector_found = true;
+ }
+ }
+ disk[drv]->track[index] = datareg;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 2;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 0xd) {
+ // read error
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ } else if(AH == 0xe) {
+ // disk change ???
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
+ AH = 0;
+ CX = 0;
+ DL = 1;
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 0;
+ CX = 0;
+ DL = disk[drv]->changed ? 1 : 0;
+ disk[drv]->changed = false;
+ *CarryFlag = 0;
+ return true;
+ }
+ if((AL & 0xf0) == 0xb0) {
+ // scsi
+ if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
+ AH = 3; // ???
+ CX = 0;
+ *CarryFlag = 1;
+ return true;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 2;
+ CX = 0;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 0xfa) {
+ // unknown
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ AH = 1;
+ CX = 0;
+ *CarryFlag = 1;
+ return true;
+ }
+ if((AL & 0xf0) == 0xb0) {
+ // scsi
+ if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
+ AH = 0x80;
+ CX = ERR_SCSI_NOTCONNECTED;
+ *CarryFlag = 1;
+ return true;
+ }
+ AH = 0;
+ CX = 0;
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 2;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 0xfd) {
+ // unknown
+ if((AL & 0xf0) == 0x20) {
+ // floppy
+ AH = 1;
+ CX = 0;
+ *CarryFlag = 1;
+ return true;
+ }
+ if((AL & 0xf0) == 0xb0) {
+ // scsi
+ if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
+ AH = 0;
+ CX = 0x200; // ???
+ *CarryFlag = 0;
+ return true;
+ }
+ AH = 2;
+ CX = 0;
+ *CarryFlag = 1;
+ return true;
+ }
+ AH = 2;
+ CX = 0;
+ *CarryFlag = 1;
+ return true;
+ } else if(AH == 0x80) {
+ // pseudo bios: init i/o
+ for(int i = 0;; i++) {
+ if(iotable[i][0] < 0) {
+ break;
+ }
+ d_io->write_io8(iotable[i][0], iotable[i][1]);
+ }
+ // init cmos
+ memset(cmos, 0, CMOS_SIZE);
+ memcpy(cmos, cmos_t, sizeof(cmos_t));
+ memcpy(cmos + CMOS_SIZE - sizeof(cmos_b), cmos_b, sizeof(cmos_b));
+ // init int vector
+ for(int i = 0, ofs = 0; i < 256; i++) {
+ // int vector = ffff:0008
+ d_mem->write_data16(ofs + 0, 0x0008);
+ d_mem->write_data16(ofs + 2, 0xffff);
+ ofs += 4;
+ }
+ // init screen
+ memset(vram, 0, VRAM_SIZE);
+#ifdef _FMR60
+ memset(cvram, 0, 0x2000);
+ memset(avram, 0, 0x2000);
+#else
+ memset(cvram, 0, 0x1000);
+ memset(kvram, 0, 0x1000);
+ memcpy(cvram + 0xf00, msg_c, sizeof(msg_c));
+ memcpy(kvram + 0xf00, msg_k, sizeof(msg_k));
+#endif
+ *CarryFlag = 0;
+ return true;
+ } else if(AH == 0x81) {
+ // pseudo bios: boot from fdd #0
+ *ZeroFlag = (timeout > (int)(FRAMES_PER_SEC * 4));
+ if(!disk[0]->inserted) {
+ *CarryFlag = 1;
+ return true;
+ }
+ // load ipl
+ disk[0]->get_track(0, 0);
+ access_fdd[0] = true;
+ if(!disk[0]->get_sector(0, 0, 0)) {
+ *CarryFlag = 1;
+ return true;
+ }
+ for(int i = 0; i < disk[0]->sector_size.sd; i++) {
+ buffer[i] = disk[0]->sector[i];
+ }
+ // check ipl
+ if(!(buffer[0] == 'I' && buffer[1] == 'P' && buffer[2] == 'L' && buffer[3] == IPL_ID)) {
+ *CarryFlag = 1;
+ return true;
+ }
+ // data transfer
+ for(int i = 0; i < disk[0]->sector_size.sd; i++) {
+ d_mem->write_data8(0xb0000 + i, buffer[i]);
+ }
+ // clear screen
+#ifdef _FMR60
+ memset(cvram, 0, 0x2000);
+ memset(avram, 0, 0x2000);
+#else
+ memset(cvram, 0, 0x1000);
+ memset(kvram, 0, 0x1000);
+#endif
+ // set result
+ AX = 0xff;
+ CX = 0;
+ BX = 2;
+ *ZeroFlag = 1;
+ *CarryFlag = 0;
+ return true;
+ } else if(AH == 0x82) {
+ // pseudo bios: boot from scsi-hdd #0
+ timeout = 0;
+ if(!scsi_blocks[0]) {
+ *CarryFlag = 1;
+ return true;
+ }
+ FILEIO* fio = new FILEIO();
+ if(!fio->Fopen(create_local_path(_T("SCSI%d.DAT"), drv), FILEIO_READ_BINARY)) {
+ *CarryFlag = 1;
+ delete fio;
+ return true;
+ }
+ // load ipl
+ access_scsi = true;
+ fio->Fread(buffer, BLOCK_SIZE * 4, 1);
+ fio->Fclose();
+ delete fio;
+ // check ipl
+ if(!(buffer[0] == 'I' && buffer[1] == 'P' && buffer[2] == 'L' && buffer[3] == IPL_ID)) {
+ *CarryFlag = 1;
+ return true;
+ }
+ // data transfer
+ for(int i = 0; i < BLOCK_SIZE * 4; i++) {
+ d_mem->write_data8(0xb0000 + i, buffer[i]);
+ }
+ // clear screen
+#ifdef _FMR60
+ memset(cvram, 0, 0x2000);
+ memset(avram, 0, 0x2000);
+#else
+ memset(cvram, 0, 0x1000);
+ memset(kvram, 0, 0x1000);
+#endif
+ // set result
+ AX = 0xffff;
+ CX = 0;
+ BX = 1;
+ *ZeroFlag = 1;
+ *CarryFlag = 0;
+ return true;
+ }
+ } else if(PC == 0xfffc9) {
+ // cmos
+#ifdef _DEBUG_LOG
+ this->out_debug_log(_T("%6x\tCMOS BIOS: AH=%2x,AL=%2x,CX=%4x,DX=%4x,BX=%4x,DS=%2x,DI=%2x\n"), get_cpu_pc(0), AH,AL,CX,DX,BX,DS,DI);
+#endif
+ if(AH == 0) {
+ // init cmos
+ memcpy(cmos, cmos_t, sizeof(cmos_t));
+ memcpy(cmos + CMOS_SIZE - sizeof(cmos_b), cmos_b, sizeof(cmos_b));
+ } else if(AH == 5) {
+ // get $a2
+ BX = cmos[0xa2] | (cmos[0xa3] << 8);
+ } else if(AH == 10) {
+ // memory to cmos
+ int block = AL * 10;
+ int len = cmos[block + 6] | (cmos[block + 7] << 8);
+ int dst = cmos[block + 8] | (cmos[block + 9] << 8);
+ int src = DS * 16 + DI;
+ for(int i = 0; i < len; i++) {
+ cmos[dst++] = d_mem->read_data8(src++);
+ }
+ } else if(AH == 11) {
+ // cmos to memory
+ int block = AL * 10;
+ int len = cmos[block + 6] | (cmos[block + 7] << 8);
+ int src = cmos[block + 8] | (cmos[block + 9] << 8);
+ int dst = DS * 16 + DI;
+ for(int i = 0; i < len; i++) {
+ d_mem->write_data8(dst++, cmos[src++]);
+ }
+ } else if(AH == 20) {
+ // check block header
+ BX = 0;
+ }
+ AH = 0;
+ *CarryFlag = 0;
+ return true;
+ } else if(PC == 0xfffd3) {
+ // wait
+#ifdef _DEBUG_LOG
+ this->out_debug_log(_T("%6x\tWAIT BIOS: AH=%2x,AL=%2x,CX=%4x,DX=%4x,BX=%4x,DS=%2x,DI=%2x\n"), get_cpu_pc(0), AH,AL,CX,DX,BX,DS,DI);
+#endif
+ *CarryFlag = 0;
+ return true;
+ }
+ return false;
+}
+
+bool BIOS::bios_int_i86(int intnum, uint16_t regs[], uint16_t sregs[], int32_t* ZeroFlag, int32_t* CarryFlag)
+{
+ uint8_t *regs8 = (uint8_t *)regs;
+
+ if(intnum == 0x93) {
+ // disk bios
+ return bios_call_i86(0xfffc4, regs, sregs, ZeroFlag, CarryFlag);
+ }
+ return false;
+}
+
+uint32_t BIOS::read_signal(int ch)
+{
+ // get access status
+ uint32_t stat = 0;
+ for(int i = 0; i < MAX_DRIVE; i++) {
+ if(access_fdd[i]) {
+ stat |= 1 << i;
+ }
+ access_fdd[i] = false;
+ }
+ if(access_scsi) {
+ stat |= 0x10;
+ }
+ access_scsi = false;
+ return stat;
+}
+
+#define STATE_VERSION 3
+
+void BIOS::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ for(int i = 0; i < MAX_DRIVE; i++) {
+ disk[i]->save_state(state_fio);
+ }
+ state_fio->FputInt32(secnum);
+ state_fio->FputInt32(timeout);
+}
+
+bool BIOS::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ for(int i = 0; i < MAX_DRIVE; i++) {
+ if(!disk[i]->load_state(state_fio)) {
+ return false;
+ }
+ }
+ secnum = state_fio->FgetInt32();
+ timeout = state_fio->FgetInt32();
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FMR-30 Emulator 'eFMR-30'
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.10.06 -
+
+ [ bios ]
+*/
+
+#ifndef _BIOS_H_
+#define _BIOS_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+class DISK;
+
+class BIOS : public DEVICE
+{
+private:
+ DEVICE *d_mem, *d_io;
+ DISK *disk[MAX_DRIVE];
+
+ // pseudo bios
+ uint8_t *cmos, *vram, *cvram;
+#ifdef _FMR60
+ uint8_t *avram;
+#else
+ uint8_t *kvram;
+#endif
+ int secnum, timeout;
+
+ // disk bios
+ bool access_fdd[MAX_DRIVE], access_scsi;
+ int scsi_blocks[MAX_SCSI];
+
+public:
+ BIOS(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {
+ set_device_name(_T("PSEUDO BIOS"));
+ }
+ ~BIOS() {}
+
+ // common functions
+ void initialize();
+ void reset();
+ void event_frame();
+ bool bios_call_i86(uint32_t PC, uint16_t regs[], uint16_t sregs[], int32_t* ZeroFlag, int32_t* CarryFlag);
+ bool bios_int_i86(int intnum, uint16_t regs[], uint16_t sregs[], int32_t* ZeroFlag, int32_t* CarryFlag);
+ uint32_t read_signal(int ch);
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // unique functions
+ void set_context_mem(DEVICE* device)
+ {
+ d_mem = device;
+ }
+ void set_context_io(DEVICE* device)
+ {
+ d_io = device;
+ }
+ void set_disk_handler(int drv, DISK* dsk)
+ {
+ disk[drv] = dsk;
+ }
+ void set_cmos_ptr(uint8_t* ptr)
+ {
+ cmos = ptr;
+ }
+ void set_vram_ptr(uint8_t* ptr)
+ {
+ vram = ptr;
+ }
+ void set_cvram_ptr(uint8_t* ptr)
+ {
+ cvram = ptr;
+ }
+#ifdef _FMR60
+ void set_avram_ptr(uint8_t* ptr)
+ {
+ avram = ptr;
+ }
+#else
+ void set_kvram_ptr(uint8_t* ptr)
+ {
+ kvram = ptr;
+ }
+#endif
+};
+
+#endif
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.05.01 -
+
+ [ cmos ]
+*/
+
+#include "cmos.h"
+
+void CMOS::initialize()
+{
+ // load cmos image
+ memset(cmos, 0, sizeof(cmos));
+ modified = false;
+
+ FILEIO* fio = new FILEIO();
+ if(fio->Fopen(create_local_path(_T("CMOS.BIN")), FILEIO_READ_BINARY)) {
+ fio->Fread(cmos, sizeof(cmos), 1);
+ fio->Fclose();
+ }
+ delete fio;
+}
+
+void CMOS::release()
+{
+ if(modified) {
+ FILEIO* fio = new FILEIO();
+ if(fio->Fopen(create_local_path(_T("CMOS.BIN")), FILEIO_WRITE_BINARY)) {
+ fio->Fwrite(cmos, sizeof(cmos), 1);
+ fio->Fclose();
+ }
+ delete fio;
+ }
+}
+
+void CMOS::reset()
+{
+ bank = 0;
+}
+
+void CMOS::write_io8(uint32_t addr, uint32_t data)
+{
+ switch(addr) {
+ case 0x90:
+ bank = data & 3;
+ break;
+ default:
+ if(!(addr & 1)) {
+ if(cmos[bank][(addr >> 1) & 0x7ff] != data) {
+ cmos[bank][(addr >> 1) & 0x7ff] = data;
+ modified = true;
+ }
+ }
+ break;
+ }
+}
+
+uint32_t CMOS::read_io8(uint32_t addr)
+{
+ if(!(addr & 1)) {
+ return cmos[bank][(addr >> 1) & 0x7ff];
+ }
+ return 0xff;
+}
+
+#define STATE_VERSION 1
+
+void CMOS::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ state_fio->Fwrite(cmos, sizeof(cmos), 1);
+ state_fio->FputBool(modified);
+ state_fio->FputUint8(bank);
+}
+
+bool CMOS::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ state_fio->Fread(cmos, sizeof(cmos), 1);
+ modified = state_fio->FgetBool();
+ bank = state_fio->FgetUint8();
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.05.01 -
+
+ [ cmos ]
+*/
+
+#ifndef _CMOS_H_
+#define _CMOS_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+class CMOS : public DEVICE
+{
+private:
+#ifdef _FMRCARD
+ uint8_t cmos[4][0x800];
+#else
+ uint8_t cmos[1][0x800];
+#endif
+ bool modified;
+ uint8_t bank;
+
+public:
+ CMOS(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {}
+ ~CMOS() {}
+
+ // common functions
+ void initialize();
+ void release();
+ void reset();
+ void write_io8(uint32_t addr, uint32_t data);
+ uint32_t read_io8(uint32_t addr);
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // unique function
+ uint8_t* get_cmos()
+ {
+ return cmos[0];
+ }
+};
+
+#endif
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.04.30 -
+
+ [ floppy ]
+*/
+
+#include "floppy.h"
+#include "../i8259.h"
+#include "../mb8877.h"
+
+void FLOPPY::initialize()
+{
+ drvreg = drvsel = 0;
+ irq = irqmsk = false;
+ changed[0] = changed[1] = changed[2] = changed[3] = false;
+}
+
+void FLOPPY::write_io8(uint32_t addr, uint32_t data)
+{
+ int nextdrv = drvsel;
+
+ switch(addr & 0xffff) {
+ case 0x208:
+ // drive control register
+ irqmsk = ((data & 1) != 0);
+ update_intr();
+ d_fdc->write_signal(SIG_MB8877_MOTOR, data, 0x10);
+ d_fdc->write_signal(SIG_MB8877_SIDEREG, data, 4);
+ break;
+ case 0x20c:
+ // drive select register
+ if(data & 1) {
+ nextdrv = 0;
+ } else if(data & 2) {
+ nextdrv = 1;
+ } else if(data & 4) {
+ nextdrv = 2;
+ } else if(data & 8) {
+ nextdrv = 3;
+ }
+ if(drvsel != nextdrv) {
+ d_fdc->write_signal(SIG_MB8877_DRIVEREG, drvsel = nextdrv, 3);
+ }
+ drvreg = data;
+ break;
+ }
+}
+
+uint32_t FLOPPY::read_io8(uint32_t addr)
+{
+ switch(addr & 0xffff) {
+ case 0x208:
+ if(changed[drvsel]) {
+ changed[drvsel] = false;
+ return d_fdc->fdc_status() | 0xe1; // fdd*2
+ }
+// return d_fdc->fdc_status() | 0x60; // fdd*1
+ return d_fdc->fdc_status() | 0xe0; // fdd*2
+ case 0x20c:
+ return drvreg;
+ }
+ return 0xff;
+}
+
+void FLOPPY::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ if(id == SIG_FLOPPY_IRQ) {
+ irq = ((data & mask) != 0);
+ update_intr();
+ }
+}
+
+void FLOPPY::update_intr()
+{
+ d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR6, irq && irqmsk ? 1 : 0, 1);
+}
+
+#define STATE_VERSION 1
+
+void FLOPPY::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ state_fio->FputInt32(drvreg);
+ state_fio->FputInt32(drvsel);
+ state_fio->FputBool(irq);
+ state_fio->FputBool(irqmsk);
+ state_fio->Fwrite(changed, sizeof(changed), 1);
+}
+
+bool FLOPPY::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ drvreg = state_fio->FgetInt32();
+ drvsel = state_fio->FgetInt32();
+ irq = state_fio->FgetBool();
+ irqmsk = state_fio->FgetBool();
+ state_fio->Fread(changed, sizeof(changed), 1);
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.04.30 -
+
+ [ floppy ]
+*/
+
+#ifndef _FLOPPY_H_
+#define _FLOPPY_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+#define SIG_FLOPPY_IRQ 0
+
+class MB8877;
+
+class FLOPPY : public DEVICE
+{
+private:
+ MB8877 *d_fdc;
+ DEVICE *d_pic;
+
+ int drvreg, drvsel;
+ bool irq, irqmsk, changed[4];
+ void update_intr();
+
+public:
+ FLOPPY(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {}
+ ~FLOPPY() {}
+
+ // common functions
+ void initialize();
+ void write_io8(uint32_t addr, uint32_t data);
+ uint32_t read_io8(uint32_t addr);
+ void write_signal(int id, uint32_t data, uint32_t mask);
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // unique functions
+ void set_context_fdc(MB8877* device)
+ {
+ d_fdc = device;
+ }
+ void set_context_pic(DEVICE* device)
+ {
+ d_pic = device;
+ }
+ void change_disk(int drv)
+ {
+ changed[drv] = true;
+ }
+};
+
+#endif
+
--- /dev/null
+/*
+ FUJITSU FM-Towns Emulator 'eFMR-60'
+
+ Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
+ Date : 216.12.28 -
+
+ [ virtual machine ]
+ History:
+ 2016-12-28 Copy from eFMR-50.
+*/
+
+#include "fmtowns.h"
+#include "../../emu.h"
+#include "../device.h"
+#include "../event.h"
+
+#include "towns_crtc.h"
+//#include "../hd46505.h"
+#include "../i8251.h"
+#include "../i8253.h"
+#include "../i8259.h"
+
+#include "../i386.h"
+
+#include "../io.h"
+#include "../mb8877.h"
+#include "../msm58321.h"
+#include "../pcm1bit.h"
+#include "../scsi_hdd.h"
+#include "../scsi_host.h"
+#include "../upd71071.h"
+
+// Electric Volume
+//#include "mb87078.h"
+//YM-2612 "OPN2"
+//#include "../ym2612.h"
+//RF5C68 PCM
+//#include "rp5c68.h"
+//AD7820 ADC
+//#include "ad7820.h"
+// 80387?
+
+#ifdef USE_DEBUGGER
+#include "../debugger.h"
+#endif
+
+#include "bios.h"
+#include "cmos.h"
+#include "floppy.h"
+#include "keyboard.h"
+#include "memory.h"
+#include "scsi.h"
+//#include "serial.h"
+#include "timer.h"
+
+// ----------------------------------------------------------------------------
+// initialize
+// ----------------------------------------------------------------------------
+
+VM::VM(EMU* parent_emu) : emu(parent_emu)
+{
+/*
+ Machine ID & CPU ID
+
+ FMR-50FD/HD/LT 0xF8
+ FMR-50FX/HX 0xE0
+ FMR-50SFX/SHX 0xE8
+ FMR-50LT 0xF8
+ FMR-50NBX 0x28
+ FMR-50NB 0x60
+ FMR-50NE/T 0x08
+ FMR-CARD 0x70
+
+ 80286 0x00
+ 80386 0x01
+ 80386SX 0x03
+ 80486 0x02
+*/
+ static const int cpu_clock[] = {
+#if defined(HAS_I386)
+ 16000000, 20000000
+#elif defined(HAS_I486)
+ 20000000, 25000000
+#endif
+ };
+
+#if defined(_FMR60) && (defined(HAS_I386) || defined(HAS_I486) || defined(HAS_PENTIUM))
+ uint8_t machine_id = 0xf0; // FMR-70/80
+#else
+ uint8_t machine_id = 0xf8; // FMR-50/60
+#endif
+
+ FILEIO* fio = new FILEIO();
+ if(fio->Fopen(create_local_path(_T("MACHINE.ID")), FILEIO_READ_BINARY)) {
+ machine_id = fio->Fgetc();
+ fio->Fclose();
+ }
+ delete fio;
+
+ machine_id &= ~7;
+#if defined(HAS_I286)
+ machine_id |= 0; // 286
+#elif defined(HAS_I386)
+// machine_id |= 1; // 386DX
+ machine_id |= 3; // 386SX
+#elif defined(HAS_I486)
+ machine_id |= 2; // 486SX/DX
+#endif
+
+ // 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
+#if defined(_USE_QT)
+ dummy->set_device_name(_T("1st Dummy"));
+ event->set_device_name(_T("EVENT"));
+#endif
+
+ cpu = new I386(this, emu);
+#if defined(_USE_QT)
+ #if defined(HAS_I386)
+ cpu->set_device_name(_T("CPU(i386)"));
+ #elif defined(HAS_I486)
+ cpu->set_device_name(_T("CPU(i486)"));
+ #elif defined(HAS_PENTIUM)
+ cpu->set_device_name(_T("CPU(Pentium)"));
+ #endif
+#endif
+
+ crtc = new TOWNS_CRTC(this, emu);
+
+#if defined(_USE_QT)
+ crtc->set_device_name(_T("TOWNS CRTC"));
+#endif
+
+ sio = new I8251(this, emu);
+ pit0 = new I8253(this, emu);
+ pit1 = new I8253(this, emu);
+ pic = new I8259(this, emu);
+ io = new IO(this, emu);
+ fdc = new MB8877(this, emu);
+ rtc = new MSM58321(this, emu);
+ pcm = new PCM1BIT(this, emu);
+#if defined(_USE_QT)
+ sio->set_device_name(_T("i8251 SIO"));
+ pit0->set_device_name(_T("i8253 PIT #0"));
+ pit1->set_device_name(_T("i8253 PIT #1"));
+ pic->set_device_name(_T("i8259 PIC"));
+ rtc->set_device_name(_T("MSM58321 RTC"));
+ pcm->set_device_name(_T("PCM SOUND"));
+#endif
+
+ scsi_host = new SCSI_HOST(this, emu);
+#if defined(_USE_QT)
+ scsi_host->set_device_name(_T("SCSI HOST"));
+#endif
+ for(int i = 0; i < 7; i++) {
+ if(FILEIO::IsFileExisting(create_local_path(_T("SCSI%d.DAT"), i))) {
+ SCSI_HDD* scsi_hdd = new SCSI_HDD(this, emu);
+#if defined(_USE_QT)
+ char d_name[64] = {0};
+ snprintf(d_name, 64, "SCSI DISK #%d", i + 1);
+ scsi_hdd->set_device_name(d_name);
+#endif
+ scsi_hdd->scsi_id = i;
+ scsi_hdd->set_context_interface(scsi_host);
+ scsi_host->set_context_target(scsi_hdd);
+ }
+ }
+ dma = new UPD71071(this, emu);
+#if defined(_USE_QT)
+ dma->set_device_name(_T("uPD71071 DMAC"));
+#endif
+ if(FILEIO::IsFileExisting(create_local_path(_T("IPL.ROM")))) {
+ bios = NULL;
+ } else {
+ bios = new BIOS(this, emu);
+#if defined(_USE_QT)
+ bios->set_device_name(_T("PSEUDO BIOS"));
+#endif
+ }
+ cmos = new CMOS(this, emu);
+ floppy = new FLOPPY(this, emu);
+ keyboard = new KEYBOARD(this, emu);
+ memory = new MEMORY(this, emu);
+ scsi = new SCSI(this, emu);
+// serial = new SERIAL(this, emu);
+ timer = new TIMER(this, emu);
+#if defined(_USE_QT)
+ cmos->set_device_name(_T("CMOS RAM"));
+ floppy->set_device_name(_T("FLOPPY I/F"));
+ keyboard->set_device_name(_T("KEYBOARD"));
+ memory->set_device_name(_T("MEMORY"));
+ scsi->set_device_name(_T("SCSI I/F"));
+ //serial->set_device_name(_T("SERIAL I/F"));
+ timer->set_device_name(_T("TIMER I/F"));
+#endif
+
+ // set contexts
+ event->set_context_cpu(cpu, cpu_clock[config.cpu_type & 1]);
+ event->set_context_sound(pcm);
+#if defined(USE_SOUND_FILES)
+ if(fdc->load_sound_data(MB8877_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
+ event->set_context_sound(fdc);
+ }
+#endif
+
+/* pic 0 timer
+ 1 keyboard
+ 2 rs-232c
+ 3 ex rs-232c
+ 4 (option)
+ 5 (option)
+ 6 floppy drive or dma ???
+ 7 (slave)
+ 8 scsi
+ 9 (option)
+ 10 (option)
+ 11 (option)
+ 12 printer
+ 13 (option)
+ 14 (option)
+ 15 (reserve)
+
+ dma 0 floppy drive
+ 1 hard drive
+ 2 (option)
+ 3 (reserve)
+*/
+ crtc->set_context_disp(memory, SIG_MEMORY_DISP, 1);
+ crtc->set_context_vsync(memory, SIG_MEMORY_VSYNC, 1);
+#ifdef _FMR60
+ acrtc->set_vram_ptr((uint16_t*)memory->get_vram(), 0x80000);
+#endif
+ pit0->set_context_ch0(timer, SIG_TIMER_CH0, 1);
+ pit0->set_context_ch1(timer, SIG_TIMER_CH1, 1);
+ pit0->set_context_ch2(pcm, SIG_PCM1BIT_SIGNAL, 1);
+ pit0->set_constant_clock(0, 307200);
+ pit0->set_constant_clock(1, 307200);
+ pit0->set_constant_clock(2, 307200);
+ pit1->set_constant_clock(1, 1228800);
+ pic->set_context_cpu(cpu);
+ fdc->set_context_drq(dma, SIG_UPD71071_CH0, 1);
+ fdc->set_context_irq(floppy, SIG_FLOPPY_IRQ, 1);
+ rtc->set_context_data(timer, SIG_TIMER_RTC, 0x0f, 0);
+ rtc->set_context_busy(timer, SIG_TIMER_RTC, 0x80);
+ scsi_host->set_context_irq(scsi, SIG_SCSI_IRQ, 1);
+ scsi_host->set_context_drq(scsi, SIG_SCSI_DRQ, 1);
+ dma->set_context_memory(memory);
+ dma->set_context_ch0(fdc);
+ dma->set_context_ch1(scsi_host);
+
+ floppy->set_context_fdc(fdc);
+ floppy->set_context_pic(pic);
+ keyboard->set_context_pic(pic);
+ memory->set_context_cpu(cpu);
+ memory->set_machine_id(machine_id);
+ memory->set_context_crtc(crtc);
+ memory->set_chregs_ptr(crtc->get_regs());
+ scsi->set_context_dma(dma);
+ scsi->set_context_pic(pic);
+ scsi->set_context_host(scsi_host);
+ timer->set_context_pcm(pcm);
+ timer->set_context_pic(pic);
+ timer->set_context_rtc(rtc);
+
+ // cpu bus
+ cpu->set_context_mem(memory);
+ cpu->set_context_io(io);
+ cpu->set_context_intr(pic);
+ if(bios) {
+ bios->set_context_mem(memory);
+ bios->set_context_io(io);
+ bios->set_cmos_ptr(cmos->get_cmos());
+ bios->set_vram_ptr(memory->get_vram());
+ bios->set_cvram_ptr(memory->get_cvram());
+#ifdef _FMR60
+ bios->set_avram_ptr(memory->get_avram());
+#else
+ bios->set_kvram_ptr(memory->get_kvram());
+#endif
+ cpu->set_context_bios(bios);
+ }
+#ifdef SINGLE_MODE_DMA
+ cpu->set_context_dma(dma);
+#endif
+#ifdef USE_DEBUGGER
+ cpu->set_context_debugger(new DEBUGGER(this, emu));
+#endif
+
+ // i/o bus
+ io->set_iomap_alias_rw(0x00, pic, I8259_ADDR_CHIP0 | 0);
+ io->set_iomap_alias_rw(0x02, pic, I8259_ADDR_CHIP0 | 1);
+ io->set_iomap_alias_rw(0x10, pic, I8259_ADDR_CHIP1 | 0);
+ io->set_iomap_alias_rw(0x12, pic, I8259_ADDR_CHIP1 | 1);
+ io->set_iomap_single_rw(0x20, memory); // reset
+ io->set_iomap_single_r(0x21, memory); // cpu misc
+ io->set_iomap_single_w(0x22, memory); // dma
+ io->set_iomap_single_rw(0x24, memory); // dma
+ io->set_iomap_single_r(0x26, timer);
+ io->set_iomap_single_r(0x27, timer);
+ io->set_iomap_single_r(0x30, memory); // cpu id
+ io->set_iomap_alias_rw(0x40, pit0, 0);
+ io->set_iomap_alias_rw(0x42, pit0, 1);
+ io->set_iomap_alias_rw(0x44, pit0, 2);
+ io->set_iomap_alias_rw(0x46, pit0, 3);
+ io->set_iomap_alias_rw(0x50, pit1, 0);
+ io->set_iomap_alias_rw(0x52, pit1, 1);
+ io->set_iomap_alias_rw(0x54, pit1, 2);
+ io->set_iomap_alias_rw(0x56, pit1, 3);
+ io->set_iomap_single_rw(0x60, timer);
+ io->set_iomap_single_rw(0x70, timer);
+ io->set_iomap_single_w(0x80, timer);
+#ifdef _FMRCARD
+ io->set_iomap_single_w(0x90, cmos);
+#endif
+ io->set_iomap_range_rw(0xa0, 0xaf, dma);
+ io->set_iomap_alias_rw(0x200, fdc, 0);
+ io->set_iomap_alias_rw(0x202, fdc, 1);
+ io->set_iomap_alias_rw(0x204, fdc, 2);
+ io->set_iomap_alias_rw(0x206, fdc, 3);
+ io->set_iomap_single_rw(0x208, floppy);
+ io->set_iomap_single_rw(0x20c, floppy);
+ io->set_iomap_single_rw(0x400, memory); // crtc
+ io->set_iomap_single_rw(0x402, memory); // crtc
+ io->set_iomap_single_rw(0x404, memory); // crtc
+ io->set_iomap_single_w(0x408, memory); // crtc
+ io->set_iomap_single_rw(0x40a, memory); // crtc
+ io->set_iomap_single_rw(0x40c, memory); // crtc
+ io->set_iomap_single_rw(0x40e, memory); // crtc
+ io->set_iomap_alias_rw(0x500, crtc, 0);
+ io->set_iomap_alias_rw(0x502, crtc, 1);
+#ifdef _FMR60
+ io->set_iomap_range_rw(0x520, 0x523, acrtc);
+#endif
+ io->set_iomap_single_rw(0x600, keyboard);
+ io->set_iomap_single_rw(0x602, keyboard);
+ io->set_iomap_single_rw(0x604, keyboard);
+ io->set_iomap_alias_rw(0xa00, sio, 0);
+ io->set_iomap_alias_rw(0xa02, sio, 1);
+// io->set_iomap_single_r(0xa04, serial);
+// io->set_iomap_single_r(0xa06, serial);
+// io->set_iomap_single_w(0xa08, serial);
+ io->set_iomap_single_rw(0xc30, scsi);
+ io->set_iomap_single_rw(0xc32, scsi);
+ io->set_iomap_range_rw(0x3000, 0x3fff, cmos);
+ io->set_iomap_range_rw(0xfd98, 0xfd9f, memory); // crtc
+ io->set_iomap_single_rw(0xfda0, memory); // crtc
+
+ // initialize all devices
+ for(DEVICE* device = first_device; device; device = device->next_device) {
+ device->initialize();
+ }
+ if(bios) {
+ for(int i = 0; i < MAX_DRIVE; i++) {
+ bios->set_disk_handler(i, fdc->get_disk_handler(i));
+ }
+ }
+}
+
+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();
+ }
+ // temporary fix...
+ 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()
+{
+ memory->draw_screen();
+}
+
+uint32_t VM::get_access_lamp_status()
+{
+ uint32_t status_fdd = fdc->read_signal(0);
+ uint32_t status_hdd = scsi_host->read_signal(0);
+ if(bios) {
+ uint32_t status = bios->read_signal(0);
+ status_fdd |= status & 0x0f;
+ status_hdd |= status >> 4;
+ }
+ return (status_hdd) ? 4 : (status_fdd & (1 | 4)) ? 1 : (status_fdd & (2 | 8)) ? 2 : 0;
+}
+
+// ----------------------------------------------------------------------------
+// soud manager
+// ----------------------------------------------------------------------------
+
+void VM::initialize_sound(int rate, int samples)
+{
+ // init sound manager
+ event->initialize_sound(rate, samples);
+
+ // init sound gen
+ 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) {
+ pcm->set_volume(0, decibel_l, decibel_r);
+ }
+#if defined(USE_SOUND_FILES)
+ else if(ch == 1) {
+ fdc->set_volume(0, decibel_l, decibel_r);
+ }
+#endif
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// notify key
+// ----------------------------------------------------------------------------
+
+void VM::key_down(int code, bool repeat)
+{
+ keyboard->key_down(code);
+}
+
+void VM::key_up(int code)
+{
+ keyboard->key_up(code);
+}
+
+// ----------------------------------------------------------------------------
+// user interface
+// ----------------------------------------------------------------------------
+
+void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
+{
+ fdc->open_disk(drv, file_path, bank);
+ floppy->change_disk(drv);
+}
+
+void VM::close_floppy_disk(int drv)
+{
+ fdc->close_disk(drv);
+}
+
+bool VM::is_floppy_disk_inserted(int drv)
+{
+ return fdc->is_disk_inserted(drv);
+}
+
+void VM::is_floppy_disk_protected(int drv, bool value)
+{
+ fdc->is_disk_protected(drv, value);
+}
+
+bool VM::is_floppy_disk_protected(int drv)
+{
+ return fdc->is_disk_protected(drv);
+}
+
+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 3
+
+void VM::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+
+ for(DEVICE* device = first_device; device; device = device->next_device) {
+ device->save_state(state_fio);
+ }
+}
+
+bool VM::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ for(DEVICE* device = first_device; device; device = device->next_device) {
+ if(!device->load_state(state_fio)) {
+ return false;
+ }
+ }
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.04.28 -
+
+ [ virtual machine ]
+*/
+
+#ifndef _FMR50_H_
+#define _FMR50_H_
+
+#if defined(_FMR50)
+#if defined(HAS_I286)
+#define DEVICE_NAME "FUJITSU FMR-50 (i286)"
+#define CONFIG_NAME "fmr50_i286"
+#elif defined(HAS_I386)
+#define DEVICE_NAME "FUJITSU FMR-50 (i386)"
+#define CONFIG_NAME "fmr50_i386"
+#elif defined(HAS_I486)
+#define DEVICE_NAME "FUJITSU FMR-50 (i486)"
+#define CONFIG_NAME "fmr50_i486"
+#elif defined(HAS_PENTIUM)
+#define DEVICE_NAME "FUJITSU FMR-250"
+#define CONFIG_NAME "fmr250"
+#endif
+#elif defined(_FMR60)
+#if defined(HAS_I286)
+#define DEVICE_NAME "FUJITSU FMR-60"
+#define CONFIG_NAME "fmr60"
+#elif defined(HAS_I386)
+#define DEVICE_NAME "FUJITSU FMR-70"
+#define CONFIG_NAME "fmr70"
+#elif defined(HAS_I486)
+#define DEVICE_NAME "FUJITSU FMR-80"
+#define CONFIG_NAME "fmr80"
+#elif defined(HAS_PENTIUM)
+#define DEVICE_NAME "FUJITSU FMR-280"
+#define CONFIG_NAME "fmr280"
+#endif
+#endif
+
+// device informations for virtual machine
+#define FRAMES_PER_SEC 55.4
+#if defined(_FMR60)
+#define LINES_PER_FRAME 784
+#define CHARS_PER_LINE 98
+#else
+#define LINES_PER_FRAME 440
+#define CHARS_PER_LINE 54
+#endif
+//#define CPU_CLOCKS 12000000
+#define CPU_CLOCKS 8000000
+#if defined(_FMR60)
+#define SCREEN_WIDTH 1120
+#define SCREEN_HEIGHT 750
+#define WINDOW_HEIGHT_ASPECT 840
+#else
+#define SCREEN_WIDTH 640
+#define SCREEN_HEIGHT 400
+#define WINDOW_HEIGHT_ASPECT 480
+#endif
+#define MAX_DRIVE 4
+#define MAX_SCSI 8
+#define MAX_MEMCARD 2
+#if defined(HAS_I286)
+#define I86_PSEUDO_BIOS
+#else
+#define I386_PSEUDO_BIOS
+#endif
+#define I8259_MAX_CHIPS 2
+#define SINGLE_MODE_DMA
+#define MB8877_NO_BUSY_AFTER_SEEK
+#define IO_ADDR_MAX 0x10000
+#define SCSI_HOST_AUTO_ACK
+
+// device informations for win32
+#define USE_CPU_TYPE 2
+#define USE_FD1
+#define USE_FD2
+#define USE_FD3
+#define USE_FD4
+#define NOTIFY_KEY_DOWN
+#define USE_SHIFT_NUMPAD_KEY
+#define USE_ALT_F10_KEY
+#define USE_AUTO_KEY 5
+#define USE_AUTO_KEY_RELEASE 6
+#define USE_CRT_FILTER
+#define USE_ACCESS_LAMP
+#define USE_SOUND_FILES 1
+#define USE_SOUND_FILES_FDD
+#if defined(USE_SOUND_FILES)
+#define USE_SOUND_VOLUME 2
+#else
+#define USE_SOUND_VOLUME 1
+#endif
+#define USE_DEBUGGER
+#define USE_STATE
+
+#include "../../common.h"
+#include "../../fileio.h"
+
+#ifdef USE_SOUND_VOLUME
+static const _TCHAR *sound_device_caption[] = {
+ _T("Beep"),
+#if defined(USE_SOUND_FILES)
+ _T("FDD SEEK"),
+#endif
+};
+#endif
+
+class EMU;
+class DEVICE;
+class EVENT;
+
+class HD46505;
+#ifdef _FMR60
+class HD63484;
+#endif
+class I8251;
+class I8253;
+class I8259;
+#if defined(HAS_I286)
+class I286;
+#else
+class I386;
+#endif
+class IO;
+class MB8877;
+class MSM58321;
+class PCM1BIT;
+class SCSI_HOST;
+class UPD71071;
+
+class BIOS;
+class CMOS;
+class FLOPPY;
+class KEYBOARD;
+class MEMORY;
+//class SERIAL;
+class SCSI;
+class TIMER;
+
+class VM
+{
+protected:
+ EMU* emu;
+
+ // devices
+ EVENT* event;
+
+ HD46505* crtc;
+#if defined(_FMR60)
+ HD63484* acrtc;
+#endif
+ I8251* sio;
+ I8253* pit0;
+ I8253* pit1;
+ I8259* pic;
+#if defined(HAS_I286)
+ I286* cpu;
+#else
+ I386* cpu;
+#endif
+ IO* io;
+ MB8877* fdc;
+ MSM58321* rtc;
+ PCM1BIT* pcm;
+ SCSI_HOST* scsi_host;
+ UPD71071* dma;
+
+ BIOS* bios;
+ CMOS* cmos;
+ FLOPPY* floppy;
+ KEYBOARD* keyboard;
+ MEMORY* memory;
+ SCSI* scsi;
+// SERIAL* serial;
+ TIMER* timer;
+
+public:
+ // ----------------------------------------
+ // initialize
+ // ----------------------------------------
+
+ VM(EMU* parent_emu);
+ ~VM();
+
+ // ----------------------------------------
+ // for emulation class
+ // ----------------------------------------
+
+ // drive virtual machine
+ void reset();
+ void run();
+
+#ifdef USE_DEBUGGER
+ // debugger
+ DEVICE *get_cpu(int index);
+#endif
+
+ // draw screen
+ void draw_screen();
+ uint32_t get_access_lamp_status();
+
+ // 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
+
+ // notify key
+ void key_down(int code, bool repeat);
+ void key_up(int code);
+
+ // user interface
+ 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);
+ bool is_frame_skippable();
+
+ void update_config();
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // ----------------------------------------
+ // for each device
+ // ----------------------------------------
+
+ // devices
+ DEVICE* get_device(int id);
+ DEVICE* dummy;
+ DEVICE* first_device;
+ DEVICE* last_device;
+};
+
+#endif
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.05.01 -
+
+ [ keyboard ]
+*/
+
+#include "keyboard.h"
+#include "../i8259.h"
+#include "../../fifo.h"
+
+void KEYBOARD::initialize()
+{
+ key_buf = new FIFO(64);
+ register_frame_event(this);
+}
+
+void KEYBOARD::release()
+{
+ key_buf->release();
+ delete key_buf;
+}
+
+void KEYBOARD::reset()
+{
+ memset(table, 0, sizeof(table));
+ key_buf->clear();
+ kbstat = kbdata = kbint = kbmsk = 0;
+}
+
+void KEYBOARD::write_io8(uint32_t addr, uint32_t data)
+{
+ switch(addr) {
+ case 0x600:
+ // data
+// kbstat |= 2;
+ break;
+ case 0x602:
+ // command
+ break;
+ case 0x604:
+ kbmsk = data;
+ break;
+ }
+}
+
+uint32_t KEYBOARD::read_io8(uint32_t addr)
+{
+ switch(addr) {
+ case 0x600:
+ kbint &= ~1;
+ d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR1, 0, 0);
+ kbstat &= ~1;
+ return kbdata;
+ case 0x602:
+ return kbstat;
+ case 0x604:
+ return kbint | 0xfc;
+ }
+ return 0;
+}
+
+void KEYBOARD::event_frame()
+{
+ if(!(kbstat & 1) && !key_buf->empty()) {
+ kbstat |= 1;
+ kbdata = key_buf->read();
+ }
+ if((kbstat & 1) && (kbmsk & 1) && !(kbint & 1)) {
+ kbint |= 1;
+ d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR1, 1, 1);
+ }
+// kbstat &= ~2;
+}
+
+void KEYBOARD::key_down(int code)
+{
+// if(!table[code]) {
+ table[code] = 1;
+ if(code = key_table[code]) {
+ // $11:CTRL, $10:SHIFT
+ key_buf->write(0xa0 | (table[0x11] ? 8 : 0) | (table[0x10] ? 4 : 0));
+ key_buf->write(code);
+ }
+// }
+}
+
+void KEYBOARD::key_up(int code)
+{
+// if(table[code]) {
+ table[code] = 0;
+ if(code = key_table[code]) {
+ key_buf->write(0xb0);
+ key_buf->write(code);
+ }
+// }
+}
+
+#define STATE_VERSION 1
+
+void KEYBOARD::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ key_buf->save_state((void *)state_fio);
+ state_fio->FputUint8(kbstat);
+ state_fio->FputUint8(kbdata);
+ state_fio->FputUint8(kbint);
+ state_fio->FputUint8(kbmsk);
+ state_fio->Fwrite(table, sizeof(table), 1);
+}
+
+bool KEYBOARD::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ if(!key_buf->load_state((void *)state_fio)) {
+ return false;
+ }
+ kbstat = state_fio->FgetUint8();
+ kbdata = state_fio->FgetUint8();
+ kbint = state_fio->FgetUint8();
+ kbmsk = state_fio->FgetUint8();
+ state_fio->Fread(table, sizeof(table), 1);
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.05.01 -
+
+ [ keyboard ]
+*/
+
+#ifndef _KEYBOARD_H_
+#define _KEYBOARD_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+/*
+ \82Ð\82ç\82ª\82È/\83\8d\81[\83}\8e\9a \82Ð\82ç\82ª\82È
+ \94¼\8ap/\91S\8ap \94¼\8ap/\91S\8ap
+ \95Ï\8a· \95Ï\8a·
+ \96³\95Ï\8a· \96³\95Ï\8a·
+ \82©\82È/\8a¿\8e\9a
+ \83J\83^\83J\83i
+ \91O\8ds PgUp
+ \8e\9f\8ds PgDn
+ \8eÀ\8ds F12
+ \8eæ\8fÁ F11
+ COPY
+*/
+
+static const int key_table[256] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x10,0x00,0x00,0x00,0x1D,0x00,0x00,
+ 0x53,0x52,0x00,0x7C,0x55,0x52,0x00,0x00,0x00,0x71,0x00,0x01,0x58,0x57,0x00,0x00,
+ 0x35,0x6E,0x70,0x00,0x4E,0x4F,0x4D,0x51,0x50,0x00,0x00,0x00,0x00,0x48,0x4B,0x00,
+ 0x0B,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x1E,0x2E,0x2C,0x20,0x13,0x21,0x22,0x23,0x18,0x24,0x25,0x26,0x30,0x2F,0x19,
+ 0x1A,0x11,0x14,0x1F,0x15,0x17,0x2D,0x12,0x2B,0x16,0x2A,0x00,0x00,0x00,0x00,0x00,
+ 0x46,0x42,0x43,0x44,0x3E,0x3F,0x40,0x3A,0x3B,0x3C,0x36,0x38,0x00,0x39,0x47,0x37,
+ 0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x72,0x73,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x7D,0x6B,0x6C,0x6D,0x57,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x27,0x31,0x0C,0x32,0x33,
+ 0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x0E,0x29,0x0D,0x00,
+ 0x00,0x00,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+class FIFO;
+
+class KEYBOARD : public DEVICE
+{
+private:
+ DEVICE* d_pic;
+
+ FIFO *key_buf;
+ uint8_t kbstat, kbdata, kbint, kbmsk;
+ uint8_t table[256];
+
+public:
+ KEYBOARD(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {}
+ ~KEYBOARD() {}
+
+ // common functions
+ void initialize();
+ void release();
+ void reset();
+ void write_io8(uint32_t addr, uint32_t data);
+ uint32_t read_io8(uint32_t addr);
+ void event_frame();
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // unique functions
+ void set_context_pic(DEVICE* device)
+ {
+ d_pic = device;
+ }
+ void key_down(int code);
+ void key_up(int code);
+};
+
+#endif
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.04.29 -
+
+ [ memory and crtc ]
+*/
+
+#include "memory.h"
+#if defined(HAS_I286)
+#include "../i286.h"
+#else
+#include "../i386.h"
+#endif
+
+static const uint8_t bios1[] = {
+ 0xFA, // cli
+ 0xDB,0xE3, // fninit
+ 0xB8,0xA0,0xF7, // mov ax,F7A0
+ 0x8E,0xD0, // mov ss,ax
+ 0xBC,0x7E,0x05, // mov sp,057E
+ // init i/o
+ 0xB4,0x80, // mov ah,80
+ 0x9A,0x14,0x00,0xFB,0xFF, // call far FFFB:0014
+ // boot from fdd
+ 0xB4,0x81, // mov ah,81
+ 0x9A,0x14,0x00,0xFB,0xFF, // call far FFFB:0014
+ 0x73,0x0B, // jnb $+11
+ 0x74,0xF5, // jz $-11
+ // boot from scsi-hdd
+ 0xB4,0x82, // mov ah,82
+ 0x9A,0x14,0x00,0xFB,0xFF, // call far FFFB:0014
+ 0x72,0xEC, // jb $-20
+ // goto ipl
+ 0x9A,0x04,0x00,0x00,0xB0, // call far B000:0004
+ 0xEB,0xE7 // jmp $-25
+};
+
+static const uint8_t bios2[] = {
+ 0xEA,0x00,0x00,0x00,0xFC, // jmp FC00:0000
+ 0x00,0x00,0x00,
+ 0xcf // iret
+};
+
+#define SET_BANK(s, e, w, r) { \
+ int sb = (s) >> 11, eb = (e) >> 11; \
+ for(int i = sb; i <= eb; i++) { \
+ if((w) == wdmy) { \
+ wbank[i] = wdmy; \
+ } else { \
+ wbank[i] = (w) + 0x800 * (i - sb); \
+ } \
+ if((r) == rdmy) { \
+ rbank[i] = rdmy; \
+ } else { \
+ rbank[i] = (r) + 0x800 * (i - sb); \
+ } \
+ } \
+}
+
+void MEMORY::initialize()
+{
+ // init memory
+ memset(ram, 0, sizeof(ram));
+ memset(vram, 0, sizeof(vram));
+ memset(cvram, 0, sizeof(cvram));
+#ifdef _FMR60
+ memset(avram, 0, sizeof(avram));
+#else
+ memset(kvram, 0, sizeof(kvram));
+ memset(dummy, 0, sizeof(dummy));
+#endif
+ memset(ipl, 0xff, sizeof(ipl));
+#ifdef _FMR60
+ memset(ank24, 0xff, sizeof(ank24));
+ memset(kanji24, 0xff, sizeof(kanji24));
+#else
+ memset(ank8, 0xff, sizeof(ank8));
+ memset(ank16, 0xff, sizeof(ank16));
+ memset(kanji16, 0xff, sizeof(kanji16));
+#endif
+ memset(rdmy, 0xff, sizeof(rdmy));
+
+ // load rom image
+ FILEIO* fio = new FILEIO();
+ if(fio->Fopen(create_local_path(_T("IPL.ROM")), FILEIO_READ_BINARY)) {
+ fio->Fread(ipl, sizeof(ipl), 1);
+ fio->Fclose();
+ } else {
+ // load pseudo ipl
+ memcpy(ipl + 0x0000, bios1, sizeof(bios1));
+ memcpy(ipl + 0x3ff0, bios2, sizeof(bios2));
+ }
+#ifdef _FMR60
+ if(fio->Fopen(create_local_path(_T("ANK24.ROM")), FILEIO_READ_BINARY)) {
+ fio->Fread(ank24, sizeof(ank24), 1);
+ fio->Fclose();
+ }
+ if(fio->Fopen(create_local_path(_T("KANJI24.ROM")), FILEIO_READ_BINARY)) {
+ fio->Fread(kanji24, sizeof(kanji24), 1);
+ fio->Fclose();
+ }
+#else
+ if(fio->Fopen(create_local_path(_T("ANK8.ROM")), FILEIO_READ_BINARY)) {
+ fio->Fread(ank8, sizeof(ank8), 1);
+ fio->Fclose();
+ }
+ if(fio->Fopen(create_local_path(_T("ANK16.ROM")), FILEIO_READ_BINARY)) {
+ fio->Fread(ank16, sizeof(ank16), 1);
+ fio->Fclose();
+ }
+ if(fio->Fopen(create_local_path(_T("KANJI16.ROM")), FILEIO_READ_BINARY)) {
+ fio->Fread(kanji16, sizeof(kanji16), 1);
+ fio->Fclose();
+ }
+#endif
+ delete fio;
+
+ // set memory
+ SET_BANK(0x000000, 0xffffff, wdmy, rdmy);
+ SET_BANK(0x000000, sizeof(ram) - 1, ram, ram);
+#ifdef _FMR60
+ SET_BANK(0xff8000, 0xff9fff, cvram, cvram);
+ SET_BANK(0xffa000, 0xffbfff, avram, avram);
+#endif
+ SET_BANK(0xffc000, 0xffffff, wdmy, ipl);
+
+ // set palette
+ for(int i = 0; i < 8; i++) {
+ dpal[i] = i;
+ apal[i][0] = (i & 1) ? 0xf0 : 0;
+ apal[i][1] = (i & 2) ? 0xf0 : 0;
+ apal[i][2] = (i & 4) ? 0xf0 : 0;
+ }
+ for(int i = 0; i < 16; i++) {
+ if(i & 8) {
+ palette_cg[i] = RGB_COLOR(i & 2 ? 255 : 0, i & 4 ? 255 : 0, i & 1 ? 255 : 0);
+ } else {
+ palette_cg[i] = RGB_COLOR(i & 2 ? 127 : 0, i & 4 ? 127 : 0, i & 1 ? 127 : 0);
+ }
+ palette_txt[i] = palette_cg[i];
+ }
+ palette_txt[0] = RGB_COLOR(63, 63, 63);
+ apalsel = 0;
+
+ // register event
+ register_frame_event(this);
+}
+
+void MEMORY::reset()
+{
+ // reset memory
+ protect = rst = 0;
+ mainmem = rplane = wplane = 0;
+#ifndef _FMR60
+ pagesel = ankcg = 0;
+#endif
+ update_bank();
+
+ // reset crtc
+ blink = 0;
+ apalsel = 0;
+ outctrl = 0xf;
+#ifndef _FMR60
+ dispctrl = 0x47;
+ mix = 8;
+ accaddr = dispaddr = 0;
+ kj_l = kj_h = kj_ofs = kj_row = 0;
+
+ // reset logical operation
+ cmdreg = maskreg = compbit = bankdis = 0;
+ memset(compreg, sizeof(compreg), 0xff);
+#endif
+ dma_addr_reg = dma_wrap_reg = 0;
+ dma_addr_mask = 0x00ffffff;
+ d_cpu->set_address_mask(0x00ffffff);
+}
+
+void MEMORY::write_data8(uint32_t addr, uint32_t data)
+{
+ if(addr & 0xff000000) {
+ // > 16MB
+ return;
+ }
+ if(!mainmem) {
+#ifdef _FMR60
+ if(0xc0000 <= addr && addr < 0xe0000) {
+ addr &= 0x1ffff;
+ for(int pl = 0; pl < 4; pl++) {
+ if(wplane & (1 << pl)) {
+ vram[addr + 0x20000 * pl] = data;
+ }
+ }
+ }
+#else
+ if(0xc0000 <= addr && addr < 0xc8000) {
+ // vram
+ uint32_t page;
+ if(dispctrl & 0x40) {
+ // 400 line
+ addr = ((pagesel & 0x10) << 13) | (addr & 0x7fff);
+ page = 0x8000;
+ } else {
+ // 200 line
+ addr = ((pagesel & 0x18) << 13) | (addr & 0x3fff);
+ page = 0x4000;
+ }
+ if(cmdreg & 0x80) {
+ // logical operations
+ if((cmdreg & 7) == 7) {
+ // compare
+ compbit = 0;
+ for(uint8_t bit = 1; bit <= 0x80; bit <<= 1) {
+ uint8_t val = 0;
+ for(int pl = 0; pl < 4; pl++) {
+ if(vram[addr + page * pl] & bit) {
+ val |= 1 << pl;
+ }
+ }
+ for(int i = 0; i < 8; i++) {
+ if((compreg[i] & 0x80) && (compreg[i] & 0xf) == val) {
+ compbit |= bit;
+ }
+ }
+ }
+ } else {
+ uint8_t mask = maskreg | ~data, val[4];
+ for(int pl = 0; pl < 4; pl++) {
+ val[pl] = (imgcol & (1 << pl)) ? 0xff : 0;
+ }
+ switch(cmdreg & 7) {
+ case 2: // or
+ for(int pl = 0; pl < 4; pl++) {
+ val[pl] |= vram[addr + page * pl];
+ }
+ break;
+ case 3: // and
+ for(int pl = 0; pl < 4; pl++) {
+ val[pl] &= vram[addr + page * pl];
+ }
+ break;
+ case 4: // xor
+ for(int pl = 0; pl < 4; pl++) {
+ val[pl] ^= vram[addr + page * pl];
+ }
+ break;
+ case 5: // not
+ for(int pl = 0; pl < 4; pl++) {
+ val[pl] = ~vram[addr + page * pl];
+ }
+ break;
+ case 6: // tile
+ for(int pl = 0; pl < 4; pl++) {
+ val[pl] = tilereg[pl];
+ }
+ break;
+ }
+ for(int pl = 0; pl < 4; pl++) {
+ if(!(bankdis & (1 << pl))) {
+ vram[addr + page * pl] &= mask;
+ vram[addr + page * pl] |= val[pl] & ~mask;
+ }
+ }
+ }
+ } else {
+ for(int pl = 0; pl < 4; pl++) {
+ if(wplane & (1 << pl)) {
+ vram[addr + page * pl] = data;
+ }
+ }
+ }
+ return;
+ } else if(0xcff80 <= addr && addr < 0xcffe0) {
+#ifdef _DEBUG_LOG
+// this->out_debug_log(_T("MW\t%4x, %2x\n"), addr, data);
+#endif
+ // memory mapped i/o
+ switch(addr & 0xffff) {
+ case 0xff80:
+ // mix register
+ mix = data;
+ break;
+ case 0xff81:
+ // update register
+ wplane = data & 7;
+ rplane = (data >> 6) & 3;
+ update_bank();
+ break;
+ case 0xff82:
+ // display ctrl register
+ dispctrl = data;
+ update_bank();
+ break;
+ case 0xff83:
+ // page select register
+ pagesel = data;
+ update_bank();
+ break;
+ case 0xff88:
+ // access start register
+ accaddr = (accaddr & 0xff) | ((data & 0x7f) << 8);
+ break;
+ case 0xff89:
+ // access start register
+ accaddr = (accaddr & 0xff00) | (data & 0xfe);
+ break;
+ case 0xff8a:
+ // display start register
+ dispaddr = (dispaddr & 0xff) | ((data & 0x7f) << 8);
+ break;
+ case 0xff8b:
+ // display start register
+ dispaddr = (dispaddr & 0xff00) | (data & 0xfe);
+ break;
+ case 0xff8e:
+ // crtc addr register
+ d_crtc->write_io8(0, data);
+ break;
+ case 0xff8f:
+ // crtc data register
+ d_crtc->write_io8(1, data);
+ break;
+ case 0xff94:
+ kj_h = data & 0x7f;
+ break;
+ case 0xff95:
+ kj_l = data & 0x7f;
+ kj_row = 0;
+ if(kj_h < 0x30) {
+ kj_ofs = (((kj_l - 0x00) & 0x1f) << 5) | (((kj_l - 0x20) & 0x20) << 9) | (((kj_l - 0x20) & 0x40) << 7) | (((kj_h - 0x00) & 0x07) << 10);
+ } else if(kj_h < 0x70) {
+ kj_ofs = (((kj_l - 0x00) & 0x1f) << 5) + (((kj_l - 0x20) & 0x60) << 9) + (((kj_h - 0x00) & 0x0f) << 10) + (((kj_h - 0x30) & 0x70) * 0xc00) + 0x08000;
+ } else {
+ kj_ofs = (((kj_l - 0x00) & 0x1f) << 5) | (((kj_l - 0x20) & 0x20) << 9) | (((kj_l - 0x20) & 0x40) << 7) | (((kj_h - 0x00) & 0x07) << 10) | 0x38000;
+ }
+ break;
+ case 0xff96:
+ kanji16[(kj_ofs | ((kj_row & 0xf) << 1)) & 0x3ffff] = data;
+ break;
+ case 0xff97:
+ kanji16[(kj_ofs | ((kj_row++ & 0xf) << 1) | 1) & 0x3ffff] = data;
+ break;
+ case 0xff99:
+ ankcg = data;
+ update_bank();
+ break;
+ case 0xffa0:
+ cmdreg = data;
+ break;
+ case 0xffa1:
+ imgcol = data;
+ break;
+ case 0xffa2:
+ maskreg = data;
+ break;
+ case 0xffa3:
+ case 0xffa4:
+ case 0xffa5:
+ case 0xffa6:
+ case 0xffa7:
+ case 0xffa8:
+ case 0xffa9:
+ case 0xffaa:
+ compreg[addr & 7] = data;
+ break;
+ case 0xffab:
+ bankdis = data;
+ break;
+ case 0xffac:
+ case 0xffad:
+ case 0xffae:
+ case 0xffaf:
+ tilereg[addr & 3] = data;
+ break;
+ case 0xffb0:
+ lofs = (lofs & 0xff) | (data << 8);
+ break;
+ case 0xffb1:
+ lofs = (lofs & 0xff00) | data;
+ break;
+ case 0xffb2:
+ lsty = (lsty & 0xff) | (data << 8);
+ break;
+ case 0xffb3:
+ lsty = (lsty & 0xff00) | data;
+ break;
+ case 0xffb4:
+ lsx = (lsx & 0xff) | (data << 8);
+ break;
+ case 0xffb5:
+ lsx = (lsx & 0xff00) | data;
+ break;
+ case 0xffb6:
+ lsy = (lsy & 0xff) | (data << 8);
+ break;
+ case 0xffb7:
+ lsy = (lsy & 0xff00) | data;
+ break;
+ case 0xffb8:
+ lex = (lex & 0xff) | (data << 8);
+ break;
+ case 0xffb9:
+ lex = (lex & 0xff00) | data;
+ break;
+ case 0xffba:
+ ley = (ley & 0xff) | (data << 8);
+ break;
+ case 0xffbb:
+ ley = (ley & 0xff00) | data;
+ // start drawing line
+ line();
+ break;
+ }
+ return;
+ }
+#endif
+ }
+ if((addr & ~3) == 8 && (protect & 0x80)) {
+ return;
+ }
+ wbank[addr >> 11][addr & 0x7ff] = data;
+}
+
+uint32_t MEMORY::read_data8(uint32_t addr)
+{
+ if(addr & 0xff000000) {
+ // > 16MB
+ if(addr >= 0xffffc000) {
+ return ipl[addr & 0x3fff];
+ }
+ return 0xff;
+ }
+#ifndef _FMR60
+ if(!mainmem) {
+ if(0xcff80 <= addr && addr < 0xcffe0) {
+#ifdef _DEBUG_LOG
+// this->out_debug_log(_T("MR\t%4x\n"), addr);
+#endif
+ // memory mapped i/o
+ switch(addr & 0xffff) {
+ case 0xff80:
+ // mix register
+ return mix;
+ case 0xff81:
+ // update register
+ return wplane | (rplane << 6);
+ case 0xff83:
+ // page select register
+ return pagesel;
+ case 0xff86:
+ // status register
+ return (disp ? 0x80 : 0) | (vsync ? 4 : 0) | 0x10;
+ case 0xff8e:
+ // crtc addr register
+ return d_crtc->read_io8(0);
+ case 0xff8f:
+ // crtc data register
+ return d_crtc->read_io8(1);
+ case 0xff94:
+ return 0x80; // ???
+ case 0xff96:
+ return kanji16[(kj_ofs | ((kj_row & 0xf) << 1)) & 0x3ffff];
+ case 0xff97:
+ return kanji16[(kj_ofs | ((kj_row++ & 0xf) << 1) | 1) & 0x3ffff];
+ case 0xffa0:
+ return cmdreg;
+ case 0xffa1:
+ return imgcol | 0xf0;
+ case 0xffa2:
+ return maskreg;
+ case 0xffa3:
+ return compbit;
+ case 0xffab:
+ return bankdis & 0xf;
+ }
+ return 0xff;
+ }
+ }
+#endif
+ return rbank[addr >> 11][addr & 0x7ff];
+}
+
+void MEMORY::write_dma_data8(uint32_t addr, uint32_t data)
+{
+ write_data8(addr & dma_addr_mask, data);
+}
+
+uint32_t MEMORY::read_dma_data8(uint32_t addr)
+{
+ return read_data8(addr & dma_addr_mask);
+}
+
+void MEMORY::write_io8(uint32_t addr, uint32_t data)
+{
+ switch(addr & 0xffff) {
+ case 0x20:
+ // protect and reset
+ protect = data;
+ update_bank();
+ if(data & 0x40) {
+ // power off
+ emu->power_off();
+ }
+ if(data & 1) {
+ // software reset
+ rst |= 1;
+ d_cpu->reset();
+ }
+ // protect mode
+#if defined(HAS_I286)
+ if(data & 0x20) {
+ d_cpu->set_address_mask(0x00ffffff);
+ } else {
+ d_cpu->set_address_mask(0x000fffff);
+ }
+#else
+ switch(data & 0x30) {
+ case 0x00: // 20bit
+ d_cpu->set_address_mask(0x000fffff);
+ break;
+ case 0x20: // 24bit
+ d_cpu->set_address_mask(0x00ffffff);
+ break;
+ default: // 32bit
+ d_cpu->set_address_mask(0xffffffff);
+ break;
+ }
+#endif
+ update_dma_addr_mask();
+ break;
+ case 0x22:
+ dma_addr_reg = data;
+ update_dma_addr_mask();
+ break;
+ case 0x24:
+ dma_wrap_reg = data;
+ update_dma_addr_mask();
+ break;
+ case 0x400:
+ // video output control
+ break;
+ case 0x402:
+ // update register
+ wplane = data & 0xf;
+ break;
+ case 0x404:
+ // read out register
+ mainmem = data & 0x80;
+ rplane = data & 3;
+ update_bank();
+ break;
+ case 0x408:
+ // palette code register
+ apalsel = data & 0xf;
+ break;
+ case 0x40a:
+ // blue level register
+ apal[apalsel][0] = data & 0xf0;
+ palette_cg[apalsel] = RGB_COLOR(apal[apalsel][1], apal[apalsel][2], apal[apalsel][0]);
+ break;
+ case 0x40c:
+ // red level register
+ apal[apalsel][1] = data & 0xf0;
+ palette_cg[apalsel] = RGB_COLOR(apal[apalsel][1], apal[apalsel][2], apal[apalsel][0]);
+ break;
+ case 0x40e:
+ // green level register
+ apal[apalsel][2] = data & 0xf0;
+ palette_cg[apalsel] = RGB_COLOR(apal[apalsel][1], apal[apalsel][2], apal[apalsel][0]);
+ break;
+ case 0xfd98:
+ case 0xfd99:
+ case 0xfd9a:
+ case 0xfd9b:
+ case 0xfd9c:
+ case 0xfd9d:
+ case 0xfd9e:
+ case 0xfd9f:
+ // digital palette
+ dpal[addr & 7] = data;
+ if(data & 8) {
+ palette_cg[addr & 7] = RGB_COLOR(data & 2 ? 255 : 0, data & 4 ? 255 : 0, data & 1 ? 255 : 0);
+ } else {
+ palette_cg[addr & 7] = RGB_COLOR(data & 2 ? 127 : 0, data & 4 ? 127 : 0, data & 1 ? 127 : 0);
+ }
+ break;
+ case 0xfda0:
+ // video output control
+ outctrl = data;
+ break;
+ }
+}
+
+uint32_t MEMORY::read_io8(uint32_t addr)
+{
+ uint32_t val = 0xff;
+
+ switch(addr & 0xffff) {
+ case 0x20:
+ // reset cause register
+ val = rst | (d_cpu->get_shutdown_flag() << 1);
+ rst = 0;
+ d_cpu->set_shutdown_flag(0);
+ return val | 0x7c;
+ case 0x21:
+// return 0x1f;
+ return 0xdf;
+ case 0x24:
+ return dma_wrap_reg;
+ case 0x30:
+ // machine & cpu id
+ return machine_id;
+ case 0x400:
+ // system status register
+#ifdef _FMR60
+ return 0xff;
+#else
+ return 0xfe;
+// return 0xf6;
+#endif
+ case 0x402:
+ // update register
+ return wplane | 0xf0;
+ case 0x404:
+ // read out register
+ return mainmem | rplane | 0x7c;
+ case 0x40a:
+ // blue level register
+ return apal[apalsel][0];
+ case 0x40c:
+ // red level register
+ return apal[apalsel][1];
+ case 0x40e:
+ // green level register
+ return apal[apalsel][2];
+ case 0xfd98:
+ case 0xfd99:
+ case 0xfd9a:
+ case 0xfd9b:
+ case 0xfd9c:
+ case 0xfd9d:
+ case 0xfd9e:
+ case 0xfd9f:
+ // digital palette
+ return dpal[addr & 7] | 0xf0;
+ case 0xfda0:
+ // status register
+ return (disp ? 2 : 0) | (vsync ? 1 : 0) | 0xfc;
+ }
+ return 0xff;
+}
+
+void MEMORY::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ if(id == SIG_MEMORY_DISP) {
+ disp = ((data & mask) != 0);
+ } else if(id == SIG_MEMORY_VSYNC) {
+ vsync = ((data & mask) != 0);
+ }
+}
+
+void MEMORY::event_frame()
+{
+ blink++;
+}
+
+void MEMORY::update_bank()
+{
+ if(!mainmem) {
+#ifdef _FMR60
+ int ofs = rplane * 0x20000;
+ SET_BANK(0xc0000, 0xdffff, vram + ofs, vram + ofs);
+ SET_BANK(0xe0000, 0xeffff, wdmy, rdmy);
+#else
+ if(dispctrl & 0x40) {
+ // 400 line
+ int ofs = (rplane | ((pagesel >> 2) & 4)) * 0x8000;
+ SET_BANK(0xc0000, 0xc7fff, vram + ofs, vram + ofs);
+ } else {
+ // 200 line
+ int ofs = (rplane | ((pagesel >> 1) & 0xc)) * 0x4000;
+ SET_BANK(0xc0000, 0xc3fff, vram + ofs, vram + ofs);
+ SET_BANK(0xc4000, 0xc7fff, vram + ofs, vram + ofs);
+ }
+ SET_BANK(0xc8000, 0xc8fff, cvram, cvram);
+ SET_BANK(0xc9000, 0xc9fff, wdmy, rdmy);
+ if(ankcg & 1) {
+ SET_BANK(0xca000, 0xca7ff, wdmy, ank8);
+ SET_BANK(0xca800, 0xcafff, wdmy, rdmy);
+ SET_BANK(0xcb000, 0xcbfff, wdmy, ank16);
+ } else {
+ SET_BANK(0xca000, 0xcafff, kvram, kvram);
+ SET_BANK(0xcb000, 0xcbfff, wdmy, rdmy);
+ }
+ SET_BANK(0xcc000, 0xeffff, wdmy, rdmy);
+#endif
+ } else {
+ SET_BANK(0xc0000, 0xeffff, ram + 0xc0000, ram + 0xc0000);
+ }
+ if(!(protect & 0x20)) {
+#ifdef _FMR60
+ SET_BANK(0xf8000, 0xf9fff, cvram, cvram);
+ SET_BANK(0xfa000, 0xfbfff, avram, avram);
+#else
+ SET_BANK(0xf8000, 0xfbfff, wdmy, rdmy);
+#endif
+ SET_BANK(0xfc000, 0xfffff, wdmy, ipl);
+ } else {
+ SET_BANK(0xf8000, 0xfffff, ram + 0xf8000, ram + 0xf8000);
+ }
+}
+
+void MEMORY::update_dma_addr_mask()
+{
+ switch(dma_addr_reg & 3) {
+ case 0:
+ dma_addr_mask = d_cpu->get_address_mask();
+ break;
+ case 1:
+ if(!(dma_wrap_reg & 1) && d_cpu->get_address_mask() == 0x000fffff) {
+ dma_addr_mask = 0x000fffff;
+ } else {
+ dma_addr_mask = 0x00ffffff;
+ }
+ break;
+ default:
+ if(!(dma_wrap_reg & 1) && d_cpu->get_address_mask() == 0x000fffff) {
+ dma_addr_mask = 0x000fffff;
+ } else {
+ dma_addr_mask = 0xffffffff;
+ }
+ break;
+ }
+}
+
+#ifndef _FMR60
+void MEMORY::point(int x, int y, int col)
+{
+ if(x < 640 && y < 400) {
+ int ofs = ((lofs & 0x3fff) + (x >> 3) + y * 80) & 0x7fff;
+ uint8_t bit = 0x80 >> (x & 7);
+ for(int pl = 0; pl < 4; pl++) {
+ uint8_t pbit = 1 << pl;
+ if(!(bankdis & pbit)) {
+ if(col & pbit) {
+ vram[0x8000 * pl + ofs] |= bit;
+ } else {
+ vram[0x8000 * pl + ofs] &= ~bit;
+ }
+ }
+ }
+ }
+}
+
+void MEMORY::line()
+{
+ int nx = lsx, ny = lsy;
+ int dx = abs(lex - lsx) * 2;
+ int dy = abs(ley - lsy) * 2;
+ int sx = (lex < lsx) ? -1 : 1;
+ int sy = (ley < lsy) ? -1 : 1;
+ int c = 0;
+
+ point(lsx, lsy, (lsty & (0x8000 >> (c++ & 15))) ? imgcol : 0);
+ if(dx > dy) {
+ int frac = dy - dx / 2;
+ while(nx != lex) {
+ if(frac >= 0) {
+ ny += sy;
+ frac -= dx;
+ }
+ nx += sx;
+ frac += dy;
+ point(nx, ny, (lsty & (0x8000 >> (c++ & 15))) ? imgcol : 0);
+ }
+ } else {
+ int frac = dx - dy / 2;
+ while(ny != ley) {
+ if(frac >= 0) {
+ nx += sx;
+ frac -= dy;
+ }
+ ny += sy;
+ frac += dx;
+ point(nx, ny, (lsty & (0x8000 >> (c++ & 15))) ? imgcol : 0);
+ }
+ }
+// point(lex, ley, (lsty & (0x8000 >> (c++ & 15))) ? imgcol : 0);
+}
+#endif
+
+void MEMORY::draw_screen()
+{
+ // render screen
+ memset(screen_txt, 0, sizeof(screen_txt));
+ memset(screen_cg, 0, sizeof(screen_cg));
+ if(outctrl & 1) {
+#ifdef _FMR60
+ draw_text();
+#else
+ if(mix & 8) {
+ draw_text80();
+ } else {
+ draw_text40();
+ }
+#endif
+ }
+ if(outctrl & 4) {
+ draw_cg();
+ }
+
+ for(int y = 0; y < SCREEN_HEIGHT; y++) {
+ scrntype_t* dest = emu->get_screen_buffer(y);
+ uint8_t* txt = screen_txt[y];
+ uint8_t* cg = screen_cg[y];
+
+ for(int x = 0; x < SCREEN_WIDTH; x++) {
+ dest[x] = txt[x] ? palette_txt[txt[x] & 15] : palette_cg[cg[x]];
+ }
+ }
+ emu->screen_skip_line(false);
+}
+
+#ifdef _FMR60
+void MEMORY::draw_text()
+{
+ int src = ((chreg[12] << 9) | (chreg[13] << 1)) & 0x1fff;
+ int caddr = ((chreg[8] & 0xc0) == 0xc0) ? -1 : (((chreg[14] << 9) | (chreg[15] << 1)) & 0x1fff);
+ int ymax = (chreg[6] > 0) ? chreg[6] : 25;
+ int yofs = 750 / ymax;
+
+ for(int y = 0; y < 25; y++) {
+ for(int x = 0; x < 80; x++) {
+ bool cursor = ((src >> 1) == caddr);
+ int cx = x;
+ uint8_t codel = cvram[src];
+ uint8_t attrl = avram[src];
+ src = (src + 1) & 0x1ffff;
+ uint8_t codeh = cvram[src];
+ uint8_t attrh = avram[src];
+ src = (src + 1) & 0x1ffff;
+ uint8_t col = (attrl & 15) | 16;
+ bool blnk = (attrh & 0x40) || ((blink & 32) && (attrh & 0x10));
+ bool rev = ((attrh & 8) != 0);
+ uint8_t xor_mask = (rev != blnk) ? 0xff : 0;
+
+ if(codeh & 0x80) {
+ // kanji
+ int ofs = (codel | ((codeh & 0x7f) << 8)) * 72;
+ for(int l = 3; l < 27 && l < yofs; l++) {
+ uint8_t pat0 = kanji24[ofs++] ^ xor_mask;
+ uint8_t pat1 = kanji24[ofs++] ^ xor_mask;
+ uint8_t pat2 = kanji24[ofs++] ^ xor_mask;
+ int yy = y * yofs + l;
+ if(yy >= 750) {
+ break;
+ }
+ uint8_t* d = &screen_txt[yy][x * 14];
+
+ d[ 2] = (pat0 & 0x80) ? col : 0;
+ d[ 3] = (pat0 & 0x40) ? col : 0;
+ d[ 4] = (pat0 & 0x20) ? col : 0;
+ d[ 5] = (pat0 & 0x10) ? col : 0;
+ d[ 6] = (pat0 & 0x08) ? col : 0;
+ d[ 7] = (pat0 & 0x04) ? col : 0;
+ d[ 8] = (pat0 & 0x02) ? col : 0;
+ d[ 9] = (pat0 & 0x01) ? col : 0;
+ d[10] = (pat1 & 0x80) ? col : 0;
+ d[11] = (pat1 & 0x40) ? col : 0;
+ d[12] = (pat1 & 0x20) ? col : 0;
+ d[13] = (pat1 & 0x10) ? col : 0;
+ d[14] = (pat1 & 0x08) ? col : 0;
+ d[15] = (pat1 & 0x04) ? col : 0;
+ d[16] = (pat1 & 0x02) ? col : 0;
+ d[17] = (pat1 & 0x01) ? col : 0;
+ d[18] = (pat2 & 0x80) ? col : 0;
+ d[19] = (pat2 & 0x40) ? col : 0;
+ d[20] = (pat2 & 0x20) ? col : 0;
+ d[21] = (pat2 & 0x10) ? col : 0;
+ d[22] = (pat2 & 0x08) ? col : 0;
+ d[23] = (pat2 & 0x04) ? col : 0;
+ d[24] = (pat2 & 0x02) ? col : 0;
+ d[25] = (pat2 & 0x01) ? col : 0;
+ }
+ src = (src + 2) & 0x1fff;
+ x++;
+ } else if(codeh) {
+ } else {
+ // ank
+ int ofs = codel * 48;
+ for(int l = 3; l < 27 && l < yofs; l++) {
+ uint8_t pat0 = ank24[ofs++] ^ xor_mask;
+ uint8_t pat1 = ank24[ofs++] ^ xor_mask;
+ int yy = y * yofs + l;
+ if(yy >= 750) {
+ break;
+ }
+ uint8_t* d = &screen_txt[yy][x * 14];
+
+ d[ 0] = (pat0 & 0x80) ? col : 0;
+ d[ 1] = (pat0 & 0x40) ? col : 0;
+ d[ 2] = (pat0 & 0x20) ? col : 0;
+ d[ 3] = (pat0 & 0x10) ? col : 0;
+ d[ 4] = (pat0 & 0x08) ? col : 0;
+ d[ 5] = (pat0 & 0x04) ? col : 0;
+ d[ 6] = (pat0 & 0x02) ? col : 0;
+ d[ 7] = (pat0 & 0x01) ? col : 0;
+ d[ 8] = (pat1 & 0x80) ? col : 0;
+ d[ 9] = (pat1 & 0x40) ? col : 0;
+ d[10] = (pat1 & 0x20) ? col : 0;
+ d[11] = (pat1 & 0x10) ? col : 0;
+ d[12] = (pat1 & 0x08) ? col : 0;
+ d[13] = (pat1 & 0x04) ? col : 0;
+ }
+ }
+/*
+ if(cursor) {
+ int bp = chreg[10] & 0x60;
+ if(bp == 0 || (bp == 0x40 && (blink & 8)) || (bp == 0x60 && (blink & 0x10))) {
+ int st = chreg[10] & 15;
+ int ed = chreg[11] & 15;
+ for(int i = st; i < ed && i < yofs; i++) {
+ memset(&screen_txt[y * yofs + i][cx << 3], 7, 8);
+ }
+ }
+ }
+*/
+ }
+ }
+}
+#else
+void MEMORY::draw_text40()
+{
+ int src = ((chreg[12] << 9) | (chreg[13] << 1)) & 0xfff;
+ int caddr = ((chreg[8] & 0xc0) == 0xc0) ? -1 : (((chreg[14] << 9) | (chreg[15] << 1) | (mix & 0x20 ? 1 : 0)) & 0x7ff);
+ int ymax = (chreg[6] > 0) ? chreg[6] : 25;
+ int yofs = 400 / ymax;
+
+ for(int y = 0; y < ymax; y++) {
+ for(int x = 0; x < 40; x++) {
+ bool cursor = ((src >> 1) == caddr);
+ int cx = x;
+ uint8_t code = cvram[src];
+ uint8_t h = kvram[src] & 0x7f;
+ src = (src + 1) & 0xfff;
+ uint8_t attr = cvram[src];
+ uint8_t l = kvram[src] & 0x7f;
+ src = (src + 1) & 0xfff;
+ uint8_t col = ((attr & 0x20) >> 2) | (attr & 7) | 16;
+ bool blnk = (blink & 32) && (attr & 0x10);
+ bool rev = ((attr & 8) != 0);
+ uint8_t xor_mask = (rev != blnk) ? 0xff : 0;
+
+ if(attr & 0x40) {
+ // kanji
+ int ofs;
+ if(h < 0x30) {
+ ofs = (((l - 0x00) & 0x1f) << 5) | (((l - 0x20) & 0x20) << 9) | (((l - 0x20) & 0x40) << 7) | (((h - 0x00) & 0x07) << 10);
+ } else if(h < 0x70) {
+ ofs = (((l - 0x00) & 0x1f) << 5) + (((l - 0x20) & 0x60) << 9) + (((h - 0x00) & 0x0f) << 10) + (((h - 0x30) & 0x70) * 0xc00) + 0x08000;
+ } else {
+ ofs = (((l - 0x00) & 0x1f) << 5) | (((l - 0x20) & 0x20) << 9) | (((l - 0x20) & 0x40) << 7) | (((h - 0x00) & 0x07) << 10) | 0x38000;
+ }
+
+ for(int l = 0; l < 16 && l < yofs; l++) {
+ uint8_t pat0 = kanji16[ofs + (l << 1) + 0] ^ xor_mask;
+ uint8_t pat1 = kanji16[ofs + (l << 1) + 1] ^ xor_mask;
+ int yy = y * yofs + l;
+ if(yy >= 400) {
+ break;
+ }
+ uint8_t* d = &screen_txt[yy][x << 4];
+
+ d[ 0] = d[ 1] = (pat0 & 0x80) ? col : 0;
+ d[ 2] = d[ 3] = (pat0 & 0x40) ? col : 0;
+ d[ 4] = d[ 5] = (pat0 & 0x20) ? col : 0;
+ d[ 6] = d[ 7] = (pat0 & 0x10) ? col : 0;
+ d[ 8] = d[ 9] = (pat0 & 0x08) ? col : 0;
+ d[10] = d[11] = (pat0 & 0x04) ? col : 0;
+ d[12] = d[13] = (pat0 & 0x02) ? col : 0;
+ d[14] = d[15] = (pat0 & 0x01) ? col : 0;
+ d[16] = d[17] = (pat1 & 0x80) ? col : 0;
+ d[18] = d[19] = (pat1 & 0x40) ? col : 0;
+ d[20] = d[21] = (pat1 & 0x20) ? col : 0;
+ d[22] = d[23] = (pat1 & 0x10) ? col : 0;
+ d[24] = d[25] = (pat1 & 0x08) ? col : 0;
+ d[26] = d[27] = (pat1 & 0x04) ? col : 0;
+ d[28] = d[29] = (pat1 & 0x02) ? col : 0;
+ d[30] = d[31] = (pat1 & 0x01) ? col : 0;
+ }
+ src = (src + 2) & 0xfff;
+ x++;
+ } else {
+ for(int l = 0; l < 16 && l < yofs; l++) {
+ uint8_t pat = ank16[(code << 4) + l] ^ xor_mask;
+ int yy = y * yofs + l;
+ if(yy >= 400) {
+ break;
+ }
+ uint8_t* d = &screen_txt[yy][x << 4];
+
+ d[ 0] = d[ 1] = (pat & 0x80) ? col : 0;
+ d[ 2] = d[ 3] = (pat & 0x40) ? col : 0;
+ d[ 4] = d[ 5] = (pat & 0x20) ? col : 0;
+ d[ 6] = d[ 7] = (pat & 0x10) ? col : 0;
+ d[ 8] = d[ 9] = (pat & 0x08) ? col : 0;
+ d[10] = d[11] = (pat & 0x04) ? col : 0;
+ d[12] = d[13] = (pat & 0x02) ? col : 0;
+ d[14] = d[15] = (pat & 0x01) ? col : 0;
+ }
+ }
+ if(cursor) {
+ int bp = chreg[10] & 0x60;
+ if(bp == 0 || (bp == 0x40 && (blink & 8)) || (bp == 0x60 && (blink & 0x10))) {
+ int st = chreg[10] & 15;
+ int ed = chreg[11] & 15;
+ for(int i = st; i < ed && i < yofs; i++) {
+ memset(&screen_txt[y * yofs + i][cx << 3], 7, 8);
+ }
+ }
+ }
+ }
+ }
+}
+
+void MEMORY::draw_text80()
+{
+ int src = ((chreg[12] << 9) | (chreg[13] << 1)) & 0xfff;
+ int caddr = ((chreg[8] & 0xc0) == 0xc0) ? -1 : (((chreg[14] << 9) | (chreg[15] << 1) | (mix & 0x20 ? 1 : 0)) & 0x7ff);
+ int ymax = (chreg[6] > 0) ? chreg[6] : 25;
+ int yofs = 400 / ymax;
+
+ for(int y = 0; y < 25; y++) {
+ for(int x = 0; x < 80; x++) {
+ bool cursor = ((src >> 1) == caddr);
+ int cx = x;
+ uint8_t code = cvram[src];
+ uint8_t h = kvram[src] & 0x7f;
+ src = (src + 1) & 0xfff;
+ uint8_t attr = cvram[src];
+ uint8_t l = kvram[src] & 0x7f;
+ src = (src + 1) & 0xfff;
+ uint8_t col = ((attr & 0x20) >> 2) | (attr & 7) | 16;
+ bool blnk = (blink & 32) && (attr & 0x10);
+ bool rev = ((attr & 8) != 0);
+ uint8_t xor_mask = (rev != blnk) ? 0xff : 0;
+
+ if(attr & 0x40) {
+ // kanji
+ int ofs;
+ if(h < 0x30) {
+ ofs = (((l - 0x00) & 0x1f) << 5) | (((l - 0x20) & 0x20) << 9) | (((l - 0x20) & 0x40) << 7) | (((h - 0x00) & 0x07) << 10);
+ } else if(h < 0x70) {
+ ofs = (((l - 0x00) & 0x1f) << 5) + (((l - 0x20) & 0x60) << 9) + (((h - 0x00) & 0x0f) << 10) + (((h - 0x30) & 0x70) * 0xc00) + 0x08000;
+ } else {
+ ofs = (((l - 0x00) & 0x1f) << 5) | (((l - 0x20) & 0x20) << 9) | (((l - 0x20) & 0x40) << 7) | (((h - 0x00) & 0x07) << 10) | 0x38000;
+ }
+
+ for(int l = 0; l < 16 && l < yofs; l++) {
+ uint8_t pat0 = kanji16[ofs + (l << 1) + 0] ^ xor_mask;
+ uint8_t pat1 = kanji16[ofs + (l << 1) + 1] ^ xor_mask;
+ int yy = y * yofs + l;
+ if(yy >= 400) {
+ break;
+ }
+ uint8_t* d = &screen_txt[yy][x << 3];
+
+ d[ 0] = (pat0 & 0x80) ? col : 0;
+ d[ 1] = (pat0 & 0x40) ? col : 0;
+ d[ 2] = (pat0 & 0x20) ? col : 0;
+ d[ 3] = (pat0 & 0x10) ? col : 0;
+ d[ 4] = (pat0 & 0x08) ? col : 0;
+ d[ 5] = (pat0 & 0x04) ? col : 0;
+ d[ 6] = (pat0 & 0x02) ? col : 0;
+ d[ 7] = (pat0 & 0x01) ? col : 0;
+ d[ 8] = (pat1 & 0x80) ? col : 0;
+ d[ 9] = (pat1 & 0x40) ? col : 0;
+ d[10] = (pat1 & 0x20) ? col : 0;
+ d[11] = (pat1 & 0x10) ? col : 0;
+ d[12] = (pat1 & 0x08) ? col : 0;
+ d[13] = (pat1 & 0x04) ? col : 0;
+ d[14] = (pat1 & 0x02) ? col : 0;
+ d[15] = (pat1 & 0x01) ? col : 0;
+ }
+ src = (src + 2) & 0xfff;
+ x++;
+ } else {
+ for(int l = 0; l < 16 && l < yofs; l++) {
+ uint8_t pat = ank16[(code << 4) + l] ^ xor_mask;
+ int yy = y * yofs + l;
+ if(yy >= 400) {
+ break;
+ }
+ uint8_t* d = &screen_txt[yy][x << 3];
+
+ d[0] = (pat & 0x80) ? col : 0;
+ d[1] = (pat & 0x40) ? col : 0;
+ d[2] = (pat & 0x20) ? col : 0;
+ d[3] = (pat & 0x10) ? col : 0;
+ d[4] = (pat & 0x08) ? col : 0;
+ d[5] = (pat & 0x04) ? col : 0;
+ d[6] = (pat & 0x02) ? col : 0;
+ d[7] = (pat & 0x01) ? col : 0;
+ }
+ }
+ if(cursor) {
+ int bp = chreg[10] & 0x60;
+ if(bp == 0 || (bp == 0x40 && (blink & 8)) || (bp == 0x60 && (blink & 0x10))) {
+ int st = chreg[10] & 15;
+ int ed = chreg[11] & 15;
+ for(int i = st; i < ed && i < yofs; i++) {
+ memset(&screen_txt[y * yofs + i][cx << 3], 7, 8);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+void MEMORY::draw_cg()
+{
+#ifdef _FMR60
+ uint8_t* p0 = &vram[0x00000];
+ uint8_t* p1 = &vram[0x20000];
+ uint8_t* p2 = &vram[0x40000];
+ uint8_t* p3 = &vram[0x60000];
+ int ptr = 0;
+
+ for(int y = 0; y < 750; y++) {
+ for(int x = 0; x < 1120; x += 8) {
+ uint8_t r = p0[ptr];
+ uint8_t g = p1[ptr];
+ uint8_t b = p2[ptr];
+ uint8_t i = p3[ptr++];
+ ptr &= 0x1ffff;
+ uint8_t* d = &screen_cg[y][x];
+
+ d[0] = ((r & 0x80) >> 7) | ((g & 0x80) >> 6) | ((b & 0x80) >> 5) | ((i & 0x80) >> 4);
+ d[1] = ((r & 0x40) >> 6) | ((g & 0x40) >> 5) | ((b & 0x40) >> 4) | ((i & 0x40) >> 3);
+ d[2] = ((r & 0x20) >> 5) | ((g & 0x20) >> 4) | ((b & 0x20) >> 3) | ((i & 0x20) >> 2);
+ d[3] = ((r & 0x10) >> 4) | ((g & 0x10) >> 3) | ((b & 0x10) >> 2) | ((i & 0x10) >> 1);
+ d[4] = ((r & 0x08) >> 3) | ((g & 0x08) >> 2) | ((b & 0x08) >> 1) | ((i & 0x08) >> 0);
+ d[5] = ((r & 0x04) >> 2) | ((g & 0x04) >> 1) | ((b & 0x04) >> 0) | ((i & 0x04) << 1);
+ d[6] = ((r & 0x02) >> 1) | ((g & 0x02) >> 0) | ((b & 0x02) << 1) | ((i & 0x02) << 2);
+ d[7] = ((r & 0x01) >> 0) | ((g & 0x01) << 1) | ((b & 0x01) << 2) | ((i & 0x01) << 3);
+ }
+ }
+#else
+ if(dispctrl & 0x40) {
+ // 400line
+ int pofs = ((dispctrl >> 3) & 1) * 0x20000;
+ uint8_t* p0 = (dispctrl & 0x01) ? &vram[pofs | 0x00000] : dummy;
+ uint8_t* p1 = (dispctrl & 0x02) ? &vram[pofs | 0x08000] : dummy;
+ uint8_t* p2 = (dispctrl & 0x04) ? &vram[pofs | 0x10000] : dummy;
+ uint8_t* p3 = (dispctrl & 0x20) ? &vram[pofs | 0x18000] : dummy; // ???
+ int ptr = dispaddr & 0x7ffe;
+
+ for(int y = 0; y < 400; y++) {
+ for(int x = 0; x < 640; x += 8) {
+ uint8_t r = p0[ptr];
+ uint8_t g = p1[ptr];
+ uint8_t b = p2[ptr];
+ uint8_t i = p3[ptr++];
+ ptr &= 0x7fff;
+ uint8_t* d = &screen_cg[y][x];
+
+ d[0] = ((r & 0x80) >> 7) | ((g & 0x80) >> 6) | ((b & 0x80) >> 5) | ((i & 0x80) >> 4);
+ d[1] = ((r & 0x40) >> 6) | ((g & 0x40) >> 5) | ((b & 0x40) >> 4) | ((i & 0x40) >> 3);
+ d[2] = ((r & 0x20) >> 5) | ((g & 0x20) >> 4) | ((b & 0x20) >> 3) | ((i & 0x20) >> 2);
+ d[3] = ((r & 0x10) >> 4) | ((g & 0x10) >> 3) | ((b & 0x10) >> 2) | ((i & 0x10) >> 1);
+ d[4] = ((r & 0x08) >> 3) | ((g & 0x08) >> 2) | ((b & 0x08) >> 1) | ((i & 0x08) >> 0);
+ d[5] = ((r & 0x04) >> 2) | ((g & 0x04) >> 1) | ((b & 0x04) >> 0) | ((i & 0x04) << 1);
+ d[6] = ((r & 0x02) >> 1) | ((g & 0x02) >> 0) | ((b & 0x02) << 1) | ((i & 0x02) << 2);
+ d[7] = ((r & 0x01) >> 0) | ((g & 0x01) << 1) | ((b & 0x01) << 2) | ((i & 0x01) << 3);
+ }
+ }
+ } else {
+ // 200line
+ int pofs = ((dispctrl >> 3) & 3) * 0x10000;
+ uint8_t* p0 = (dispctrl & 0x01) ? &vram[pofs | 0x0000] : dummy;
+ uint8_t* p1 = (dispctrl & 0x02) ? &vram[pofs | 0x4000] : dummy;
+ uint8_t* p2 = (dispctrl & 0x04) ? &vram[pofs | 0x8000] : dummy;
+ uint8_t* p3 = (dispctrl & 0x20) ? &vram[pofs | 0xc000] : dummy; // ???
+ int ptr = dispaddr & 0x3ffe;
+
+ for(int y = 0; y < 400; y += 2) {
+ for(int x = 0; x < 640; x += 8) {
+ uint8_t r = p0[ptr];
+ uint8_t g = p1[ptr];
+ uint8_t b = p2[ptr];
+ uint8_t i = p3[ptr++];
+ ptr &= 0x3fff;
+ uint8_t* d = &screen_cg[y][x];
+
+ d[0] = ((r & 0x80) >> 7) | ((g & 0x80) >> 6) | ((b & 0x80) >> 5) | ((i & 0x80) >> 4);
+ d[1] = ((r & 0x40) >> 6) | ((g & 0x40) >> 5) | ((b & 0x40) >> 4) | ((i & 0x40) >> 3);
+ d[2] = ((r & 0x20) >> 5) | ((g & 0x20) >> 4) | ((b & 0x20) >> 3) | ((i & 0x20) >> 2);
+ d[3] = ((r & 0x10) >> 4) | ((g & 0x10) >> 3) | ((b & 0x10) >> 2) | ((i & 0x10) >> 1);
+ d[4] = ((r & 0x08) >> 3) | ((g & 0x08) >> 2) | ((b & 0x08) >> 1) | ((i & 0x08) >> 0);
+ d[5] = ((r & 0x04) >> 2) | ((g & 0x04) >> 1) | ((b & 0x04) >> 0) | ((i & 0x04) << 1);
+ d[6] = ((r & 0x02) >> 1) | ((g & 0x02) >> 0) | ((b & 0x02) << 1) | ((i & 0x02) << 2);
+ d[7] = ((r & 0x01) >> 0) | ((g & 0x01) << 1) | ((b & 0x01) << 2) | ((i & 0x01) << 3);
+ }
+ memcpy(screen_cg[y + 1], screen_cg[y], 640);
+ }
+ }
+#endif
+}
+
+#define STATE_VERSION 1
+
+void MEMORY::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ state_fio->Fwrite(ram, sizeof(ram), 1);
+ state_fio->Fwrite(vram, sizeof(vram), 1);
+ state_fio->Fwrite(cvram, sizeof(cvram), 1);
+#ifdef _FMR60
+ state_fio->Fwrite(avram, sizeof(avram), 1);
+#else
+ state_fio->Fwrite(kvram, sizeof(kvram), 1);
+#endif
+ state_fio->FputUint8(machine_id);
+ state_fio->FputUint8(protect);
+ state_fio->FputUint8(rst);
+ state_fio->FputUint8(mainmem);
+ state_fio->FputUint8(rplane);
+ state_fio->FputUint8(wplane);
+ state_fio->FputUint8(dma_addr_reg);
+ state_fio->FputUint8(dma_wrap_reg);
+ state_fio->FputUint32(dma_addr_mask);
+ state_fio->FputBool(disp);
+ state_fio->FputBool(vsync);
+ state_fio->FputInt32(blink);
+ state_fio->Fwrite(apal, sizeof(apal), 1);
+ state_fio->FputUint8(apalsel);
+ state_fio->Fwrite(dpal, sizeof(dpal), 1);
+ state_fio->FputUint8(outctrl);
+#ifndef _FMR60
+ state_fio->FputUint8(pagesel);
+ state_fio->FputUint8(ankcg);
+ state_fio->FputUint8(dispctrl);
+ state_fio->FputUint8(mix);
+ state_fio->FputUint16(accaddr);
+ state_fio->FputUint16(dispaddr);
+ state_fio->FputInt32(kj_h);
+ state_fio->FputInt32(kj_l);
+ state_fio->FputInt32(kj_ofs);
+ state_fio->FputInt32(kj_row);
+ state_fio->FputUint8(cmdreg);
+ state_fio->FputUint8(imgcol);
+ state_fio->FputUint8(maskreg);
+ state_fio->Fwrite(compreg, sizeof(compreg), 1);
+ state_fio->FputUint8(compbit);
+ state_fio->FputUint8(bankdis);
+ state_fio->Fwrite(tilereg, sizeof(tilereg), 1);
+ state_fio->FputUint16(lofs);
+ state_fio->FputUint16(lsty);
+ state_fio->FputUint16(lsx);
+ state_fio->FputUint16(lsy);
+ state_fio->FputUint16(lex);
+ state_fio->FputUint16(ley);
+#endif
+ state_fio->Fwrite(palette_cg, sizeof(palette_cg), 1);
+}
+
+bool MEMORY::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ state_fio->Fread(ram, sizeof(ram), 1);
+ state_fio->Fread(vram, sizeof(vram), 1);
+ state_fio->Fread(cvram, sizeof(cvram), 1);
+#ifdef _FMR60
+ state_fio->Fread(avram, sizeof(avram), 1);
+#else
+ state_fio->Fread(kvram, sizeof(kvram), 1);
+#endif
+ machine_id = state_fio->FgetUint8();
+ protect = state_fio->FgetUint8();
+ rst = state_fio->FgetUint8();
+ mainmem = state_fio->FgetUint8();
+ rplane = state_fio->FgetUint8();
+ wplane = state_fio->FgetUint8();
+ dma_addr_reg = state_fio->FgetUint8();
+ dma_wrap_reg = state_fio->FgetUint8();
+ dma_addr_mask = state_fio->FgetUint32();
+ disp = state_fio->FgetBool();
+ vsync = state_fio->FgetBool();
+ blink = state_fio->FgetInt32();
+ state_fio->Fread(apal, sizeof(apal), 1);
+ apalsel = state_fio->FgetUint8();
+ state_fio->Fread(dpal, sizeof(dpal), 1);
+ outctrl = state_fio->FgetUint8();
+#ifndef _FMR60
+ pagesel = state_fio->FgetUint8();
+ ankcg = state_fio->FgetUint8();
+ dispctrl = state_fio->FgetUint8();
+ mix = state_fio->FgetUint8();
+ accaddr = state_fio->FgetUint16();
+ dispaddr = state_fio->FgetUint16();
+ kj_h = state_fio->FgetInt32();
+ kj_l = state_fio->FgetInt32();
+ kj_ofs = state_fio->FgetInt32();
+ kj_row = state_fio->FgetInt32();
+ cmdreg = state_fio->FgetUint8();
+ imgcol = state_fio->FgetUint8();
+ maskreg = state_fio->FgetUint8();
+ state_fio->Fread(compreg, sizeof(compreg), 1);
+ compbit = state_fio->FgetUint8();
+ bankdis = state_fio->FgetUint8();
+ state_fio->Fread(tilereg, sizeof(tilereg), 1);
+ lofs = state_fio->FgetUint16();
+ lsty = state_fio->FgetUint16();
+ lsx = state_fio->FgetUint16();
+ lsy = state_fio->FgetUint16();
+ lex = state_fio->FgetUint16();
+ ley = state_fio->FgetUint16();
+#endif
+ state_fio->Fread(palette_cg, sizeof(palette_cg), 1);
+
+ // post process
+ update_bank();
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.04.29 -
+
+ [ memory ]
+*/
+
+#ifndef _MEMORY_H_
+#define _MEMORY_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+#define SIG_MEMORY_DISP 0
+#define SIG_MEMORY_VSYNC 1
+
+#if defined(HAS_I286)
+class I286;
+#else
+class I386;
+#endif
+
+class MEMORY : public DEVICE
+{
+private:
+#if defined(HAS_I286)
+ I286 *d_cpu;
+#else
+ I386 *d_cpu;
+#endif
+ DEVICE *d_crtc;
+
+ uint8_t* rbank[8192]; // 16MB / 2KB
+ uint8_t* wbank[8192];
+ uint8_t wdmy[0x800];
+ uint8_t rdmy[0x800];
+
+ uint8_t ram[0x400000]; // RAM 1+3MB
+#ifdef _FMR60
+ uint8_t vram[0x80000]; // VRAM 512KB
+ uint8_t cvram[0x2000];
+ uint8_t avram[0x2000];
+#else
+ uint8_t vram[0x40000]; // VRAM 256KB
+ uint8_t cvram[0x1000];
+ uint8_t kvram[0x1000];
+ uint8_t dummy[0x8000]; // dummy plane
+#endif
+ uint8_t ipl[0x4000]; // IPL 16KB
+#ifdef _FMR60
+ uint8_t ank24[0x3000]; // ANK(14x24)
+ uint8_t kanji24[0x240000]; // KANJI(24x24)
+#else
+ uint8_t ank8[0x800]; // ANK(8x8) 2KB
+ uint8_t ank16[0x1000]; // ANK(8x16) 4KB
+ uint8_t kanji16[0x40000]; // KANJI(16x16) 256KB
+#endif
+ uint8_t machine_id; // MACHINE ID
+
+ // memory
+ uint8_t protect, rst;
+ uint8_t mainmem, rplane, wplane;
+ uint8_t dma_addr_reg, dma_wrap_reg;
+ uint32_t dma_addr_mask;
+
+ // crtc
+ uint8_t* chreg;
+ bool disp, vsync;
+ int blink;
+
+ // video
+ uint8_t apal[16][3], apalsel, dpal[8];
+ uint8_t outctrl;
+
+#ifndef _FMR60
+ // 16bit card
+ uint8_t pagesel, ankcg;
+ uint8_t dispctrl;
+ uint8_t mix;
+ uint16_t accaddr, dispaddr;
+
+ // kanji
+ int kj_h, kj_l, kj_ofs, kj_row;
+
+ // logical operation
+ uint8_t cmdreg, imgcol, maskreg, compreg[8], compbit, bankdis, tilereg[3];
+ uint16_t lofs, lsty, lsx, lsy, lex, ley;
+ void point(int x, int y, int col);
+ void line();
+#endif
+
+ uint8_t screen_txt[SCREEN_HEIGHT][SCREEN_WIDTH + 14];
+ uint8_t screen_cg[SCREEN_HEIGHT][SCREEN_WIDTH];
+// uint8_t screen_txt[400][648];
+// uint8_t screen_cg[400][640];
+ scrntype_t palette_txt[16];
+ scrntype_t palette_cg[16];
+
+ void update_bank();
+ void update_dma_addr_mask();
+#ifdef _FMR60
+ void draw_text();
+#else
+ void draw_text40();
+ void draw_text80();
+#endif
+ void draw_cg();
+
+public:
+ MEMORY(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {
+ set_device_name(_T("MEMORY"));
+ }
+ ~MEMORY() {}
+
+ // common functions
+ void initialize();
+ void reset();
+ void write_data8(uint32_t addr, uint32_t data);
+ uint32_t read_data8(uint32_t addr);
+ void write_dma_data8(uint32_t addr, uint32_t data);
+ uint32_t read_dma_data8(uint32_t addr);
+ void write_io8(uint32_t addr, uint32_t data);
+ uint32_t read_io8(uint32_t addr);
+ void write_signal(int id, uint32_t data, uint32_t mask);
+ void event_frame();
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // unique functions
+#if defined(HAS_I286)
+ void set_context_cpu(I286* device)
+#else
+ void set_context_cpu(I386* device)
+#endif
+ {
+ d_cpu = device;
+ }
+ void set_machine_id(uint8_t id)
+ {
+ machine_id = id;
+ }
+ void set_context_crtc(DEVICE* device)
+ {
+ d_crtc = device;
+ }
+ void set_chregs_ptr(uint8_t* ptr)
+ {
+ chreg = ptr;
+ }
+ uint8_t* get_vram()
+ {
+ return vram;
+ }
+ uint8_t* get_cvram()
+ {
+ return cvram;
+ }
+#ifdef _FMR60
+ uint8_t* get_avram()
+ {
+ return avram;
+ }
+#else
+ uint8_t* get_kvram()
+ {
+ return kvram;
+ }
+#endif
+ void draw_screen();
+};
+
+#endif
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2016.03.03-
+
+ [ scsi ]
+*/
+
+#include "scsi.h"
+#include "../i8259.h"
+#include "../scsi_host.h"
+#include "../upd71071.h"
+
+// control register
+#define CTRL_WEN 0x80
+#define CTRL_IMSK 0x40
+#define CTRL_ATN 0x10
+#define CTRL_SEL 0x04
+#define CTRL_DMAE 0x02
+#define CTRL_RST 0x01
+
+#define STATUS_REQ 0x80
+#define STATUS_IO 0x40
+#define STATUS_MSG 0x20
+#define STATUS_CD 0x10
+#define STATUS_BSY 0x08
+#define STATUS_INT 0x02
+#define STATUS_PERR 0x01
+
+void SCSI::reset()
+{
+ ctrl_reg = CTRL_IMSK;
+ irq_status = false;
+}
+
+void SCSI::write_io8(uint32_t addr, uint32_t data)
+{
+ switch(addr & 0xffff) {
+ case 0xc30:
+ // data register
+ #ifdef _SCSI_DEBUG_LOG
+ this->out_debug_log(_T("[SCSI] out %04X %02X\n"), addr, data);
+ #endif
+ if(ctrl_reg & CTRL_WEN) {
+ d_host->write_dma_io8(addr, data);
+ }
+ break;
+
+ case 0xc32:
+ // control register
+ #ifdef _SCSI_DEBUG_LOG
+ this->out_debug_log(_T("[SCSI] out %04X %02X\n"), addr, data);
+ #endif
+ ctrl_reg = data;
+ if(ctrl_reg & CTRL_WEN) {
+ d_host->write_signal(SIG_SCSI_RST, data, CTRL_RST);
+ d_host->write_signal(SIG_SCSI_SEL, data, CTRL_SEL);
+ d_host->write_signal(SIG_SCSI_ATN, data, CTRL_ATN);
+ }
+ break;
+ }
+}
+
+uint32_t SCSI::read_io8(uint32_t addr)
+{
+ uint32_t value = 0;
+
+ switch(addr & 0xffff) {
+ case 0xc30:
+ // data register
+ if(ctrl_reg & CTRL_WEN) {
+ value = d_host->read_dma_io8(addr);
+ }
+ #ifdef _SCSI_DEBUG_LOG
+ this->out_debug_log(_T("[SCSI] in %04X %02X\n"), addr, value);
+ #endif
+ return value;
+
+ case 0xc32:
+ // status register
+ value = (d_host->read_signal(SIG_SCSI_REQ) ? STATUS_REQ : 0) |
+ (d_host->read_signal(SIG_SCSI_IO ) ? STATUS_IO : 0) |
+ (d_host->read_signal(SIG_SCSI_MSG) ? STATUS_MSG : 0) |
+ (d_host->read_signal(SIG_SCSI_CD ) ? STATUS_CD : 0) |
+ (d_host->read_signal(SIG_SCSI_BSY) ? STATUS_BSY : 0) |
+ (irq_status ? STATUS_INT : 0);
+ #ifdef _SCSI_DEBUG_LOG
+ this->out_debug_log(_T("[SCSI] in %04X %02X\n"), addr, value);
+ #endif
+ return value;
+ }
+ return 0xff;
+}
+
+void SCSI::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ switch(id) {
+ case SIG_SCSI_IRQ:
+ if(ctrl_reg & CTRL_IMSK) {
+ d_pic->write_signal(SIG_I8259_CHIP1 | SIG_I8259_IR0, data, mask);
+ }
+ irq_status = ((data & mask) != 0);
+ break;
+
+ case SIG_SCSI_DRQ:
+ if(ctrl_reg & CTRL_DMAE) {
+ d_dma->write_signal(SIG_UPD71071_CH1, data, mask);
+ }
+ break;
+ }
+}
+
+#define STATE_VERSION 1
+
+void SCSI::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ state_fio->FputUint8(ctrl_reg);
+ state_fio->FputBool(irq_status);
+}
+
+bool SCSI::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ ctrl_reg = state_fio->FgetUint8();
+ irq_status = state_fio->FgetBool();
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2016.03.03-
+
+ [ scsi ]
+*/
+
+#ifndef _SCSI_H_
+#define _SCSI_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+#define SIG_SCSI_IRQ 0
+#define SIG_SCSI_DRQ 1
+
+class SCSI : public DEVICE
+{
+private:
+ DEVICE *d_dma, *d_pic, *d_host;
+
+ uint8_t ctrl_reg;
+ bool irq_status;
+
+public:
+ SCSI(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {
+ set_device_name(_T("FMR50 SCSI"));
+ }
+ ~SCSI() {}
+
+ // common functions
+ void reset();
+ void write_io8(uint32_t addr, uint32_t data);
+ uint32_t read_io8(uint32_t addr);
+ void write_signal(int id, uint32_t data, uint32_t mask);
+
+ // unique functions
+ void set_context_dma(DEVICE* device)
+ {
+ d_dma = device;
+ }
+ void set_context_pic(DEVICE* device)
+ {
+ d_pic = device;
+ }
+ void set_context_host(DEVICE* device)
+ {
+ d_host = device;
+ }
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+};
+
+#endif
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.04.30 -
+
+ [ timer ]
+*/
+
+#include "timer.h"
+#include "../i8259.h"
+#include "../msm58321.h"
+#include "../pcm1bit.h"
+
+void TIMER::initialize()
+{
+ free_run_counter = 0;
+ intr_reg = rtc_data = 0;
+ tmout0 = tmout1 = false;
+}
+
+void TIMER::write_io8(uint32_t addr, uint32_t data)
+{
+ switch(addr) {
+ case 0x60:
+ if(data & 0x80) {
+ tmout0 = false;
+ }
+ intr_reg = data;
+ update_intr();
+ d_pcm->write_signal(SIG_PCM1BIT_ON, data, 4);
+ break;
+ case 0x70:
+ d_rtc->write_signal(SIG_MSM58321_DATA, data, 0x0f);
+ break;
+ case 0x80:
+ d_rtc->write_signal(SIG_MSM58321_CS, data, 0x80);
+ d_rtc->write_signal(SIG_MSM58321_READ, data, 0x04);
+ d_rtc->write_signal(SIG_MSM58321_WRITE, data, 0x02);
+ d_rtc->write_signal(SIG_MSM58321_ADDR_WRITE, data, 0x01);
+ break;
+ }
+}
+
+uint32_t TIMER::read_io8(uint32_t addr)
+{
+ switch(addr) {
+ case 0x26:
+ free_run_counter = (uint16_t)get_passed_usec(0);
+ return free_run_counter & 0xff;
+ case 0x27:
+ return free_run_counter >> 8;
+ case 0x60:
+ return (tmout0 ? 1 : 0) | (tmout1 ? 2 : 0) | ((intr_reg & 7) << 2) | 0xe0;
+ case 0x70:
+ return rtc_data;
+ }
+ return 0xff;
+}
+
+void TIMER::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ if(id == SIG_TIMER_CH0) {
+ if(data & mask) {
+ tmout0 = true;
+ }
+ update_intr();
+ } else if(id == SIG_TIMER_CH1) {
+ tmout1 = ((data & mask) != 0);
+ update_intr();
+ } else if(id == SIG_TIMER_RTC) {
+ rtc_data = (data & mask) | (rtc_data & ~mask);
+ }
+}
+
+void TIMER::update_intr()
+{
+ if((tmout0 && (intr_reg & 1)) || (tmout1 && (intr_reg & 2))) {
+ d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR0, 1, 1);
+ } else {
+ d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR0, 0, 1);
+ }
+}
+
+#define STATE_VERSION 1
+
+void TIMER::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ state_fio->FputUint16(free_run_counter);
+ state_fio->FputUint8(intr_reg);
+ state_fio->FputUint8(rtc_data);
+ state_fio->FputBool(tmout0);
+ state_fio->FputBool(tmout1);
+}
+
+bool TIMER::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ free_run_counter = state_fio->FgetUint16();
+ intr_reg = state_fio->FgetUint8();
+ rtc_data = state_fio->FgetUint8();
+ tmout0 = state_fio->FgetBool();
+ tmout1 = state_fio->FgetBool();
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FMR-50 Emulator 'eFMR-50'
+ FUJITSU FMR-60 Emulator 'eFMR-60'
+
+ Author : Takeda.Toshiya
+ Date : 2008.04.30 -
+
+ [ timer ]
+*/
+
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+#define SIG_TIMER_CH0 0
+#define SIG_TIMER_CH1 1
+#define SIG_TIMER_RTC 2
+
+class TIMER : public DEVICE
+{
+private:
+ DEVICE *d_pcm, *d_pic, *d_rtc;
+
+ uint16_t free_run_counter;
+ uint8_t intr_reg, rtc_data;
+ bool tmout0, tmout1;
+ void update_intr();
+
+public:
+ TIMER(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {}
+ ~TIMER() {}
+
+ // common functions
+ void initialize();
+ void write_io8(uint32_t addr, uint32_t data);
+ uint32_t read_io8(uint32_t addr);
+ void write_signal(int id, uint32_t data, uint32_t mask);
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // unique functions
+ void set_context_pcm(DEVICE* device)
+ {
+ d_pcm = device;
+ }
+ void set_context_pic(DEVICE* device)
+ {
+ d_pic = device;
+ }
+ void set_context_rtc(DEVICE* device)
+ {
+ d_rtc = device;
+ }
+};
+
+#endif
+
--- /dev/null
+/*
+ Skelton for retropc emulator
+
+ Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
+ Date : 2016.12.28 -
+
+ [ FM-Towns CRTC ]
+ History: 2016.12.28 Initial from HD46505 .
+*/
+
+#include "towns_crtc.h"
+
+#define EVENT_DISPLAY 0
+#define EVENT_HSYNC_S 1
+#define EVENT_HSYNC_E 2
+
+void TOWNS_CRTC::initialize()
+{
+ memset(regs, 0, sizeof(regs));
+ memset(regs_written, 0, sizeof(regs_written));
+
+ // register events
+ register_frame_event(this);
+ register_vline_event(this);
+}
+
+void TOWNS_CRTC::reset()
+{
+ // initialize
+ display = false;
+ vblank = vsync = hsync = true;
+
+// memset(regs, 0, sizeof(regs));
+ ch = 0;
+
+ // initial settings for 1st frame
+#ifdef CHARS_PER_LINE
+ hz_total = (CHARS_PER_LINE > 54) ? CHARS_PER_LINE : 54;
+#else
+ hz_total = 54;
+#endif
+ hz_disp = (hz_total > 80) ? 80 : 40;
+ hs_start = hz_disp + 4;
+ hs_end = hs_start + 4;
+
+ vt_total = LINES_PER_FRAME;
+ vt_disp = (SCREEN_HEIGHT > LINES_PER_FRAME) ? (SCREEN_HEIGHT >> 1) : SCREEN_HEIGHT;
+ vs_start = vt_disp + 16;
+ vs_end = vs_start + 16;
+
+ timing_changed = false;
+ disp_end_clock = 0;
+
+#if defined(TOWNS_CRTC_CHAR_CLOCK)
+ char_clock = 0;
+ next_char_clock = TOWNS_CRTC_CHAR_CLOCK;
+#elif defined(TOWNS_CRTC_HORIZ_FREQ)
+ horiz_freq = 0;
+ next_horiz_freq = TOWNS_CRTC_HORIZ_FREQ;
+#endif
+}
+
+void TOWNS_CRTC::write_io8(uint32_t addr, uint32_t data)
+{
+ if(addr & 1) {
+ if(ch < 32) {
+ if(ch < 16 && regs[ch] != data) {
+ timing_changed = true;
+ }
+ regs[ch] = data;
+ regs_written[ch] = true;
+ }
+ } else {
+ ch = data;
+ }
+}
+
+uint32_t TOWNS_CRTC::read_io8(uint32_t addr)
+{
+ if(addr & 1) {
+ return (12 <= ch && ch < 18) ? regs[ch] : 0xff;
+ } else {
+ return ch;
+ }
+}
+
+void TOWNS_CRTC::event_pre_frame()
+{
+ if(timing_changed) {
+ if(regs_written[0] && regs_written[1] && regs_written[2] && regs_written[3] && regs_written[4] && regs_written[5] && regs_written[6] && regs_written[7] && regs_written[9]) {
+ int ch_height = (regs[9] & 0x1f) + 1;
+
+ hz_total = regs[0] + 1;
+ hz_disp = regs[1];
+ hs_start = regs[2];
+ hs_end = hs_start + (regs[3] & 0x0f);
+
+ int new_vt_total = ((regs[4] & 0x7f) + 1) * ch_height + (regs[5] & 0x1f);
+ vt_disp = (regs[6] & 0x7f) * ch_height;
+ vs_start = ((regs[7] & 0x7f) + 1) * ch_height;
+ vs_end = vs_start + ((regs[3] & 0xf0) ? (regs[3] >> 4) : 16);
+
+ if(vt_total != new_vt_total) {
+ vt_total = new_vt_total;
+ set_lines_per_frame(vt_total);
+ }
+ timing_changed = false;
+ disp_end_clock = 0;
+#if defined(TOWNS_CRTC_CHAR_CLOCK)
+ char_clock = 0;
+#elif defined(TOWNS_CRTC_HORIZ_FREQ)
+ horiz_freq = 0;
+#endif
+ }
+ }
+#if defined(TOWNS_CRTC_CHAR_CLOCK)
+ if(char_clock != next_char_clock) {
+ char_clock = next_char_clock;
+ frames_per_sec = char_clock / (double)vt_total / (double)hz_total;
+ if(regs[8] & 1) {
+ frames_per_sec *= 2; // interlace mode
+ }
+ set_frames_per_sec(frames_per_sec);
+ }
+#elif defined(TOWNS_CRTC_HORIZ_FREQ)
+ if(horiz_freq != next_horiz_freq) {
+ horiz_freq = next_horiz_freq;
+ frames_per_sec = horiz_freq / (double)vt_total;
+ if(regs[8] & 1) {
+ frames_per_sec *= 2; // interlace mode
+ }
+ set_frames_per_sec(frames_per_sec);
+ }
+#endif
+}
+
+void TOWNS_CRTC::update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame)
+{
+ cpu_clocks = new_clocks;
+#if !defined(TOWNS_CRTC_CHAR_CLOCK) && !defined(TOWNS_CRTC_HORIZ_FREQ)
+ frames_per_sec = new_frames_per_sec;
+#endif
+
+ // update event clocks
+ disp_end_clock = 0;
+}
+
+void TOWNS_CRTC::event_frame()
+{
+ // update envet clocks after update_timing() is called
+ if(disp_end_clock == 0 && vt_total != 0) {
+ disp_end_clock = (int)((double)cpu_clocks * (double)hz_disp / frames_per_sec / (double)vt_total / (double)hz_total);
+ hs_start_clock = (int)((double)cpu_clocks * (double)hs_start / frames_per_sec / (double)vt_total / (double)hz_total);
+ hs_end_clock = (int)((double)cpu_clocks * (double)hs_end / frames_per_sec / (double)vt_total / (double)hz_total);
+ }
+}
+
+void TOWNS_CRTC::event_vline(int v, int clock)
+{
+ // if vt_disp == 0, raise vblank for one line
+ bool new_vblank = ((v < vt_disp) || (v == 0 && vt_disp == 0));
+
+ // display
+ if(outputs_disp.count) {
+ set_display(new_vblank);
+ if(new_vblank && hz_disp < hz_total) {
+ register_event_by_clock(this, EVENT_DISPLAY, disp_end_clock, false, NULL);
+ }
+ }
+
+ // vblank
+ set_vblank(new_vblank); // active low
+
+ // vsync
+ set_vsync(vs_start <= v && v < vs_end);
+
+ // hsync
+ if(outputs_hsync.count && hs_start < hs_end && hs_end < hz_total) {
+ set_hsync(false);
+ register_event_by_clock(this, EVENT_HSYNC_S, hs_start_clock, false, NULL);
+ register_event_by_clock(this, EVENT_HSYNC_E, hs_end_clock, false, NULL);
+ }
+}
+
+void TOWNS_CRTC::event_callback(int event_id, int err)
+{
+ if(event_id == EVENT_DISPLAY) {
+ set_display(false);
+ } else if(event_id == EVENT_HSYNC_S) {
+ set_hsync(true);
+ } else if(event_id == EVENT_HSYNC_E) {
+ set_hsync(false);
+ }
+}
+
+void TOWNS_CRTC::set_display(bool val)
+{
+ if(display != val) {
+ write_signals(&outputs_disp, val ? 0xffffffff : 0);
+ display = val;
+ }
+}
+
+void TOWNS_CRTC::set_vblank(bool val)
+{
+ if(vblank != val) {
+ write_signals(&outputs_vblank, val ? 0xffffffff : 0);
+ vblank = val;
+ }
+}
+
+#define STATE_VERSION 1
+
+void TOWNS_CRTC::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+ state_fio->Fwrite(regs, sizeof(regs), 1);
+ state_fio->Fwrite(regs_written, sizeof(regs_written), 1);
+ state_fio->FputInt32(ch);
+ state_fio->FputBool(timing_changed);
+ state_fio->FputInt32(cpu_clocks);
+#if defined(TOWNS_CRTC_CHAR_CLOCK)
+ state_fio->FputDouble(char_clock);
+ state_fio->FputDouble(next_char_clock);
+#elif defined(TOWNS_CRTC_HORIZ_FREQ)
+ state_fio->FputDouble(horiz_freq);
+ state_fio->FputDouble(next_horiz_freq);
+#endif
+ state_fio->FputDouble(frames_per_sec);
+ state_fio->FputInt32(hz_total);
+ state_fio->FputInt32(hz_disp);
+ state_fio->FputInt32(hs_start);
+ state_fio->FputInt32(hs_end);
+ state_fio->FputInt32(vt_total);
+ state_fio->FputInt32(vt_disp);
+ state_fio->FputInt32(vs_start);
+ state_fio->FputInt32(vs_end);
+ state_fio->FputInt32(disp_end_clock);
+ state_fio->FputInt32(hs_start_clock);
+ state_fio->FputInt32(hs_end_clock);
+ state_fio->FputBool(display);
+ state_fio->FputBool(vblank);
+ state_fio->FputBool(vsync);
+ state_fio->FputBool(hsync);
+}
+
+bool TOWNS_CRTC::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ state_fio->Fread(regs, sizeof(regs), 1);
+ state_fio->Fread(regs_written, sizeof(regs_written), 1);
+ ch = state_fio->FgetInt32();
+ timing_changed = state_fio->FgetBool();
+ cpu_clocks = state_fio->FgetInt32();
+#if defined(TOWNS_CRTC_CHAR_CLOCK)
+ char_clock = state_fio->FgetDouble();
+ next_char_clock = state_fio->FgetDouble();
+#elif defined(TOWNS_CRTC_HORIZ_FREQ)
+ horiz_freq = state_fio->FgetDouble();
+ next_horiz_freq = state_fio->FgetDouble();
+#endif
+ frames_per_sec = state_fio->FgetDouble();
+ hz_total = state_fio->FgetInt32();
+ hz_disp = state_fio->FgetInt32();
+ hs_start = state_fio->FgetInt32();
+ hs_end = state_fio->FgetInt32();
+ vt_total = state_fio->FgetInt32();
+ vt_disp = state_fio->FgetInt32();
+ vs_start = state_fio->FgetInt32();
+ vs_end = state_fio->FgetInt32();
+ disp_end_clock = state_fio->FgetInt32();
+ hs_start_clock = state_fio->FgetInt32();
+ hs_end_clock = state_fio->FgetInt32();
+ display = state_fio->FgetBool();
+ vblank = state_fio->FgetBool();
+ vsync = state_fio->FgetBool();
+ hsync = state_fio->FgetBool();
+
+ return true;
+}
--- /dev/null
+/*
+ Skelton for retropc emulator
+
+ Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
+ Date : 2016.12.28 -
+
+ [ FM-Towns CRTC ]
+ History: 2016.12.28 Initial from HD46505 .
+*/
+
+#ifndef _TOWNS_CRTC_H_
+#define _TOWNS_CRTC_H_
+
+#include "../vm.h"
+#include "../emu.h"
+#include "device.h"
+
+class TOWNS_CRTC : public DEVICE
+{
+private:
+ // output signals
+ outputs_t outputs_disp;
+ outputs_t outputs_vblank;
+ outputs_t outputs_vsync;
+ outputs_t outputs_hsync;
+
+ uint8_t regs[32];
+ bool regs_written[32];
+ int ch;
+ bool timing_changed;
+
+ int cpu_clocks;
+#if defined(TOWNS_CRTC_CHAR_CLOCK)
+ double char_clock, next_char_clock;
+#elif defined(TOWNS_CRTC_HORIZ_FREQ)
+ double horiz_freq, next_horiz_freq;
+#endif
+ double frames_per_sec;
+
+ int hz_total, hz_disp;
+ int hs_start, hs_end;
+
+ int vt_total, vt_disp;
+ int vs_start, vs_end;
+
+ int disp_end_clock;
+ int hs_start_clock, hs_end_clock;
+
+ bool display, vblank, vsync, hsync;
+
+ void set_display(bool val);
+ void set_vblank(bool val);
+ void set_vsync(bool val);
+ void set_hsync(bool val);
+
+public:
+ TOWNS_CRTC(VM *parent_vm, EMU *parent_emu) : DEVICE(parent_vm, parent_emu)
+ {
+ initialize_output_signals(&outputs_disp);
+ initialize_output_signals(&outputs_vblank);
+ initialize_output_signals(&outputs_vsync);
+ initialize_output_signals(&outputs_hsync);
+ set_device_name(_T("FM-Towns CRTC"));
+ }
+ ~TOWNS_CRTC() {}
+
+ void initialize();
+ void reset();
+ void write_io8(uint32_t addr, uint32_t data);
+ uint32_t read_io8(uint32_t addr);
+ void event_pre_frame();
+ void event_frame();
+ void event_vline(int v, int clock);
+ void event_callback(int event_id, int err);
+ void update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame);
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+ // unique function
+ void set_context_disp(DEVICE* device, int id, uint32_t mask)
+ {
+ register_output_signal(&outputs_disp, device, id, mask);
+ }
+ void set_context_vblank(DEVICE* device, int id, uint32_t mask)
+ {
+ register_output_signal(&outputs_vblank, device, id, mask);
+ }
+ void set_context_vsync(DEVICE* device, int id, uint32_t mask)
+ {
+ register_output_signal(&outputs_vsync, device, id, mask);
+ }
+ void set_context_hsync(DEVICE* device, int id, uint32_t mask)
+ {
+ register_output_signal(&outputs_hsync, device, id, mask);
+ }
+#if defined(TOWNS_CRTC_CHAR_CLOCK)
+ void set_char_clock(double clock)
+ {
+ next_char_clock = clock;
+ }
+#elif defined(TOWNS_CRTC_HORIZ_FREQ)
+ void set_horiz_freq(double freq)
+ {
+ next_horiz_freq = freq;
+ }
+#endif
+ uint8_t* get_regs()
+ {
+ return regs;
+ }
+
+};
+
+#endif
+
--- /dev/null
+/*
+ Skelton for retropc emulator
+
+ Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
+ Date : 2016.12.28 -
+
+ [ FM-Towns VRAM ]
+ History: 2016.12.28 Initial.
+*/
+
+#ifndef _TOWNS_VRAM_H_
+#define _TOWNS_VRAM_H_
+
+#include "../vm.h"
+#include "../emu.h"
+#include "device.h"
+
+// Older Towns.
+#define TOWNS_VRAM_ADDR_MASK 0x7ffff
+// VRAM DIRECT ACCESS: For Sprite. You should access with 16bit
+// You can write raw data, drawing with colorkey is automatically.
+#define SIG_TOWNS_TRANSFER_SPRITE_DATA 0x100000
+#define SIG_TOWNS_SET_SPRITE_BANK 0x140000
+#define SIG_TOWNS_CLEAR_SPRITE_BUFFER 0x140001
+// Do render with any mode. You should set vline to arg.
+#define SIG_TOWNS_RENDER_RASTER 0x01
+#define SIG_TOWNS_RENDER_FULL 0x02
+#define SIG_TOWNS_VRAM_VSTART 0x03
+#define SIG_TOWNS_VRAM_VBLANK 0x04
+#define SIG_TOWNS_VRAM_VSYNC 0x05
+#define SIG_TOWNS_VRAM_HSYNC 0x06
+#define SIG_TOWNS_VRAM_SET_VLINE 0x07
+#define SIG_TOWNS_RENDER_FLAG 0x08
+
+class TOWNS_VRAM : public DEVICE
+{
+protected:
+ scrntype_t *render_buffer;
+ uint32_t page_modes[4];
+ uint32_t masks;
+ uint8_t vram[0x80000]; // Related by machine.
+public:
+ TOWNS_VRAM(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
+ {
+ memset(vram, 0x00, sizeof(vram));
+ render_buffer = NULL;
+ page_modes[0] = page_modes[1] = page_modes[2] = page_modes[3] = 0;
+ masks = 0;
+ }
+ ~TOWNS_VRAM() {}
+
+ uint32_t read_data8(uint32_t addr)
+ {
+ if(addr < 0x80000000) {
+ // Plane Access
+ uint32_t data32;
+ uint8_t data8;
+ uint32_t n_plane = (addr & 0x18000) / 0x8000;
+ uint32_t n_addr = addr & 0x7fff;
+ uint32_t x_addr = n_addr << 2;
+ uint32_t *p;
+ if(plane_page1) x_addr += 0x20000;
+ p = (uint32_t *)(&(vram[x_addr]));
+ data32 = *p;
+ data32 >>= (3 - n_plane);
+ data8 =
+ ((data32 & 0x10000000) ? 0x80 : 0) |
+ ((data32 & 0x01000000) ? 0x40 : 0) |
+ ((data32 & 0x00100000) ? 0x20 : 0) |
+ ((data32 & 0x00010000) ? 0x10 : 0) |
+ ((data32 & 0x00001000) ? 0x08 : 0) |
+ ((data32 & 0x00000100) ? 0x04 : 0) |
+ ((data32 & 0x00000010) ? 0x02 : 0) |
+ ((data32 & 0x00000001) ? 0x01 : 0);
+ return (uint32_t) data8;
+ } else {
+ return vram[addr & TOWNS_VRAM_ADDR_MASK];
+ }
+ };
+
+ uint32_t read_data16(uint32_t addr)
+ {
+ pair_t n;
+ n.d = 0;
+ if(addr < 0x80000000) {
+ addr = addr & 0x1fffe;
+ n.b.h = read_data8(addr + 1);
+ n.b.l = read_data8(addr);
+ } else {
+ addr = addr & (TOWNS_VRAM_ADDR_MASK & 0xfffffffe);
+ n.b.h = vram[addr + 1];
+ n.b.l = vram[addr];
+ }
+ return n.d;
+ }
+
+ uint32_t read_data32(uint32_t addr)
+ {
+ if(addr < 0x80000000) {
+ addr = addr & 0x1fffc;
+ n.b.h3 = read_data8(addr + 3);
+ n.b.h2 = read_data8(addr + 2);
+ n.b.h = read_data8(addr + 1);
+ n.b.l = read_data8(addr);
+ } else {
+ addr = addr & (TOWNS_VRAM_ADDR_MASK & 0xfffffffc);
+ n.b.h3 = vram[addr + 3];
+ n.b.h2 = vram[addr + 2];
+ n.b.h = vram[addr + 1];
+ n.b.l = vram[addr];
+ }
+ return n.d;
+ }
+
+ void write_data8(uint32_t addr, uint32_t data)
+ {
+ if(addr < 0x80000000) {
+ // Plane Access
+ pair_t data_p;
+ uint32_t n_plane = (addr & 0x18000) / 0x8000;
+ uint32_t n_addr = addr & 0x7fff;
+ uint32_t x_addr = n_addr << 2;
+
+ pair_t *p;
+ if(plane_page1) x_addr += 0x20000;
+ p = (pair_t *)(&(vram[x_addr]));
+ data_p.d = *p;
+ // ToDo
+ } else {
+ // ToDo: Scroll
+ uint32_t mask2 = (masks >> ((3 - (addr & 3)) * 8)) & 0xff;
+ uint32_t d_s = vram[addr & TOWNS_VRAM_ADDR_MASK] & ~mask2;
+ uint32_t d_d = data & mask2;
+ vram[addr & TOWNS_VRAM_ADDR_MASK] = d_s | d_d;
+ }
+ }
+
+ void write_data16(uint32_t addr, uint32_t data)
+ {
+ if(addr < 0x80000000) {
+ // Plane Access
+ pair_t data_p;
+ uint32_t n_plane = (addr & 0x18000) / 0x8000;
+ uint32_t n_addr = addr & 0x7fff;
+ uint32_t x_addr = n_addr << 2;
+
+ pair_t *p;
+ if(plane_page1) x_addr += 0x20000;
+ p = (pair_t *)(&(vram[x_addr]));
+ data_p.d = *p;
+ // ToDo
+ } else {
+ pair_t n;
+ uint16_t *p;
+ n.d = 0;
+ p = (uint16_t *)(&(vram[addr & TOWNS_VRAM_ADDR_MASK & 0xfffffffe]));
+ n.sw.l = *p;
+ uint32_t mask2 = (masks >> ((2 - (addr & 2)) * 16)) & 0xffff;
+ uint32_t d_s = n.d & ~mask2;
+ uint32_t d_d = data & mask2;
+ // ToDo: Scroll
+ n.d = d_s | d_d;
+ *p = n.sw.l;
+ }
+ }
+
+ void write_data32(uint32_t addr, uint32_t data)
+ {
+ if(addr < 0x80000000) {
+ // Plane Access
+ pair_t data_p;
+ uint32_t n_plane = (addr & 0x18000) / 0x8000;
+ uint32_t n_addr = addr & 0x7fff;
+ uint32_t x_addr = n_addr << 2;
+
+ pair_t *p;
+ if(plane_page1) x_addr += 0x20000;
+ p = (pair_t *)(&(vram[x_addr]));
+ data_p.d = *p;
+ // ToDo
+ } else {
+ uint32_t n;
+ uint32_t *p;
+
+ p = (uint32_t *)(&(vram[addr & TOWNS_VRAM_ADDR_MASK & 0xfffffffc]));
+ n = *p;
+ uint32_t mask2 = masks;
+ uint32_t d_s = n & ~mask2;
+ uint32_t d_d = data & mask2;
+ // ToDo: Scroll
+ *p = d_s | d_d;
+ }
+ }
+
+ uint32_t read_io8(uint32_t addr);
+ void write_io8(uint32_t addr, uint32_t data);
+ void draw_screen();
+ void write_signal(int id, uint32_t data, uint32_t mask); // Do render
+
+ void set_context_renderbuffer(scrntype_t *p){
+ render_buffer = p;
+ };
+};
+
+#endif