// use zlib to decompress gzip file???
#ifdef _WIN32
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
- #define USE_ZLIB
+ #ifndef _ANY2D88
+ #define USE_ZLIB
+ #endif
#endif
#endif
}
}
+ // check two side
+ int valid_side = 0;
+
+ for(int trk = 0; trk < 82; trk++) {
+ for(int side = 0; side < 2; side++) {
+ int trkside = trk * 2 + side;
+ pair_t offset;
+ offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
+
+ if(IS_VALID_TRACK(offset.d)) {
+ valid_side |= (1 << side);
+ }
+ }
+ if(valid_side == 3) break;
+ }
+ // FIXME: unformat disk is recognized as two side
+ two_side = (valid_side != 1);
+
// fix write protect flag
if(buffer[0x1a] != 0) {
buffer[0x1a] = 0x10;
bool write_protected;
bool changed;
uint8_t media_type;
+ bool two_side;
int is_special_disk;
// track
--- /dev/null
+cmake_minimum_required (VERSION 2.6)
+
+message("* vm/fm16beta")
+
+set(VM_FM16BETA_LIB_SRCS
+ cmos.cpp
+ keyboard.cpp
+ main.cpp
+ sub.cpp
+ fm16beta.cpp
+)
+
+if(USE_DEVICES_SHARED_LIB)
+else()
+ set(VM_FM16BETA_LIB_SRCS ${VM_FM16BETA_LIB_SRCS}
+ hd46505.cpp
+ i8237.cpp
+ i8251.cpp
+ i8259.cpp
+ mb8877.cpp
+ mc6809.cpp
+ mc6840.cpp
+ msm58321.cpp
+ pcm1bit.cpp
+
+ disk.cpp
+
+ memory.cpp
+ io.cpp
+ )
+endif()
+add_library(vm_fm16beta
+ ${VM_FM16BETA_LIB_SRCS}
+)
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2017.12.30-
+
+ [ 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::write_io8(uint32_t addr, uint32_t data)
+{
+ if(cmos[addr & 0x7ff] != data) {
+ cmos[addr & 0x7ff] = data;
+ modified = true;
+ }
+}
+
+uint32_t CMOS::read_io8(uint32_t addr)
+{
+ return cmos[addr & 0x7ff];
+}
+
+#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);
+}
+
+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();
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2017.12.30-
+
+ [ cmos ]
+*/
+
+#ifndef _CMOS_H_
+#define _CMOS_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+class CMOS : public DEVICE
+{
+private:
+ uint8_t cmos[0x800];
+ bool modified;
+
+public:
+ CMOS(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
+ {
+ set_device_name(_T("CMOS RAM"));
+ }
+ ~CMOS() {}
+
+ // common functions
+ void initialize();
+ void release();
+ 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);
+};
+
+#endif
+
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2017.12.28-
+
+ [ virtual machine ]
+*/
+
+#include "fm16beta.h"
+#include "../../emu.h"
+#include "../device.h"
+#include "../event.h"
+
+#include "../disk.h"
+#include "../hd46505.h"
+#include "../i8237.h"
+#include "../i8251.h"
+#include "../i8259.h"
+#include "../i286.h"
+#include "../io.h"
+#include "../mb8877.h"
+#include "../mc6809.h"
+#include "../mc6840.h"
+#include "../msm58321.h"
+#include "../noise.h"
+#include "../pcm1bit.h"
+
+#ifdef USE_DEBUGGER
+#include "../debugger.h"
+#endif
+
+#include "cmos.h"
+#include "keyboard.h"
+#include "main.h"
+#include "sub.h"
+
+// ----------------------------------------------------------------------------
+// initialize
+// ----------------------------------------------------------------------------
+
+VM::VM(EMU* parent_emu) : emu(parent_emu)
+{
+ // create devices
+ first_device = last_device = NULL;
+ dummy = new DEVICE(this, emu); // must be 1st device
+ event = new EVENT(this, emu); // must be 2nd device
+
+ crtc = new HD46505(this, emu);
+ cpu = new I286(this, emu);
+ io = new IO(this, emu);
+ dma = new I8237(this, emu);
+ sio = new I8251(this, emu);
+ pic = new I8259(this, emu);
+ fdc_2hd = new MB8877(this, emu);
+ fdc_2hd->set_context_noise_seek(new NOISE(this, emu));
+ fdc_2hd->set_context_noise_head_down(new NOISE(this, emu));
+ fdc_2hd->set_context_noise_head_up(new NOISE(this, emu));
+ fdc_2d = new MB8877(this, emu);
+ fdc_2d->set_context_noise_seek(new NOISE(this, emu));
+ fdc_2d->set_context_noise_head_down(new NOISE(this, emu));
+ fdc_2d->set_context_noise_head_up(new NOISE(this, emu));
+ subcpu = new MC6809(this, emu);
+ ptm = new MC6840(this, emu);
+ rtc = new MSM58321(this, emu);
+ pcm = new PCM1BIT(this, emu);
+
+ cmos = new CMOS(this, emu);
+ keyboard = new KEYBOARD(this, emu);
+ main = new MAIN(this, emu);
+
+
+
+
+
+ sub = new SUB(this, emu);
+
+ // set contexts
+ event->set_context_cpu(cpu, 8000000);
+ event->set_context_cpu(subcpu, 2000000);
+ event->set_context_sound(pcm);
+ event->set_context_sound(fdc_2hd->get_context_noise_seek());
+ event->set_context_sound(fdc_2hd->get_context_noise_head_down());
+ event->set_context_sound(fdc_2hd->get_context_noise_head_up());
+ event->set_context_sound(fdc_2d->get_context_noise_seek());
+ event->set_context_sound(fdc_2d->get_context_noise_head_down());
+ event->set_context_sound(fdc_2d->get_context_noise_head_up());
+
+ keyboard->set_context_main(main);
+#ifdef HAS_I286
+ main->set_context_cpu(cpu);
+#endif
+ main->set_context_dma(dma);
+ main->set_context_fdc_2hd(fdc_2hd);
+ main->set_context_fdc_2d(fdc_2d);
+ main->set_context_pic(pic);
+ main->set_context_pcm(pcm);
+ main->set_context_rtc(rtc);
+ main->set_context_sub(sub);
+ main->set_context_keyboard(keyboard);
+
+ dma->set_context_memory(main);
+ dma->set_context_ch0(fdc_2d);
+ dma->set_context_ch1(fdc_2hd);
+
+ sio->set_context_txrdy(main, SIG_MAIN_IRQ0_TX, 1);
+ sio->set_context_rxrdy(main, SIG_MAIN_IRQ0_RX, 1);
+ sio->set_context_syndet(main, SIG_MAIN_IRQ0_SYN, 1);
+
+ fdc_2hd->set_context_irq(main, SIG_MAIN_IRQ5, 1);
+ fdc_2hd->set_context_drq(main, SIG_MAIN_DRQ_2HD, 1);
+ fdc_2hd->set_context_drq(dma, SIG_I8237_CH1, 1);
+
+ fdc_2d->set_context_irq(main, SIG_MAIN_IRQ4, 1);
+ fdc_2d->set_context_drq(main, SIG_MAIN_DRQ_2D, 1);
+ fdc_2d->set_context_drq(dma, SIG_I8237_CH0, 1);
+
+ ptm->set_context_ch0(pcm, SIG_PCM1BIT_SIGNAL, 1);
+ ptm->set_context_irq(main, SIG_MAIN_IRQ8, 1);
+ ptm->set_internal_clock(19200); // temporary
+ ptm->set_external_clock(0, 19200);
+ ptm->set_external_clock(1, 19200);
+ ptm->set_external_clock(2, 19200);
+
+ rtc->set_context_data(main, SIG_MAIN_RTC_DATA, 0x0f, 0);
+ rtc->set_context_busy(main, SIG_MAIN_RTC_BUSY, 0x80);
+
+ crtc->set_context_disp(sub, SIG_SUB_DISP, 1);
+ crtc->set_context_vsync(sub, SIG_SUB_VSYNC, 1);
+
+ sub->addr_max = 0x10000;
+ sub->bank_size = 0x80;
+ sub->set_context_crtc(crtc);
+ sub->set_chregs_ptr(crtc->get_regs());
+ sub->set_context_pcm(pcm);
+ sub->set_context_main(main);
+ sub->set_context_subcpu(subcpu);
+ sub->set_context_keyboard(keyboard);
+
+ // cpu bus
+ cpu->set_context_mem(main);
+ cpu->set_context_io(io);
+ cpu->set_context_intr(pic);
+#ifdef SINGLE_MODE_DMA
+ cpu->set_context_dma(dma);
+#endif
+ subcpu->set_context_mem(sub);
+#ifdef USE_DEBUGGER
+ cpu->set_context_debugger(new DEBUGGER(this, emu));
+ subcpu->set_context_debugger(new DEBUGGER(this, emu));
+#endif
+
+
+ // i/o bus
+ io->set_iomap_range_rw(0x0000, 0x0001, pic);
+ io->set_iomap_range_rw(0x0010, 0x001f, dma);
+ io->set_iomap_range_w(0x0020, 0x0023, main); // dma bank regs
+#ifdef HAS_I286
+ io->set_iomap_single_rw(0x0060, main); // reset
+#endif
+
+ io->set_iomap_range_rw(0xf000, 0xf7ff, cmos);
+ io->set_iomap_range_rw(0xfc80, 0xfcff, sub); // shared ram
+
+ io->set_iomap_range_r(0xfd00, 0xfd01, keyboard);
+ io->set_iomap_range_rw(0xfd02, 0xfd05, main);
+
+ io->set_iomap_range_rw(0xfd06, 0xfd07, sio);
+
+ io->set_iomap_single_rw(0xfd0f, main);
+
+ io->set_iomap_range_rw(0xfd10, 0xfd11, main);
+
+ io->set_iomap_range_rw(0xfd18, 0xfd1b, fdc_2d);
+ io->set_iomap_range_rw(0xfd1c, 0xfd1f, main);
+
+ io->set_iomap_range_r(0xfd20, 0xfd22, sub); // attention
+
+ io->set_iomap_single_rw(0xfd2c, main);
+
+ io->set_iomap_range_rw(0xfd30, 0xfd33, fdc_2hd);
+ io->set_iomap_range_rw(0xfd34, 0xfd37, main);
+
+ io->set_iomap_range_rw(0xfd38, 0xfd3f, ptm);
+ io->set_iomap_range_rw(0xfd98, 0xfd9f, sub);
+ io->set_iomap_single_w(0xfda0, sub);
+ io->set_iomap_single_r(0xfda0, main);
+
+
+ // initialize all devices
+ for(DEVICE* device = first_device; device; device = device->next_device) {
+ device->initialize();
+ }
+ for(int i = 0; i < 4; i++) {
+ fdc_2hd->set_drive_type(i, DRIVE_TYPE_2HD);
+ fdc_2d->set_drive_type(i, DRIVE_TYPE_2D);
+ }
+ fdc_2hd->get_disk_handler(0)->drive_num = 0;
+ fdc_2hd->get_disk_handler(1)->drive_num = 1;
+ fdc_2d->get_disk_handler(0)->drive_num = 2;
+ fdc_2d->get_disk_handler(1)->drive_num = 3;
+}
+
+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();
+ }
+
+ emu->out_debug_log(_T("----- RESET -----\n"));
+
+}
+
+void VM::run()
+{
+ event->drive();
+}
+
+// ----------------------------------------------------------------------------
+// debugger
+// ----------------------------------------------------------------------------
+
+#ifdef USE_DEBUGGER
+DEVICE *VM::get_cpu(int index)
+{
+ if(index == 0) {
+ return cpu;
+ } else if(index == 1) {
+ return subcpu;
+ }
+ return NULL;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// draw screen
+// ----------------------------------------------------------------------------
+
+void VM::draw_screen()
+{
+ sub->draw_screen();
+}
+
+// ----------------------------------------------------------------------------
+// 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);
+ } else if(ch == 1) {
+ fdc_2hd->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
+ fdc_2hd->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
+ fdc_2hd->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
+ fdc_2d->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
+ fdc_2d->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
+ fdc_2d->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
+ }
+}
+#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)
+{
+ if(drv < 2) {
+ fdc_2hd->open_disk(drv, file_path, bank);
+ } else if(drv < 4) {
+ fdc_2d->open_disk(drv - 2, file_path, bank);
+ }
+}
+
+void VM::close_floppy_disk(int drv)
+{
+ if(drv < 2) {
+ fdc_2hd->close_disk(drv);
+ } else if(drv < 4) {
+ fdc_2d->close_disk(drv - 2);
+ }
+}
+
+bool VM::is_floppy_disk_inserted(int drv)
+{
+ if(drv < 2) {
+ return fdc_2hd->is_disk_inserted(drv);
+ } else if(drv < 4) {
+ return fdc_2d->is_disk_inserted(drv - 2);
+ }
+ return false;
+}
+
+void VM::is_floppy_disk_protected(int drv, bool value)
+{
+ if(drv < 2) {
+ fdc_2hd->is_disk_protected(drv, value);
+ } else if(drv < 4) {
+ fdc_2d->is_disk_protected(drv - 2, value);
+ }
+}
+
+bool VM::is_floppy_disk_protected(int drv)
+{
+ if(drv < 2) {
+ return fdc_2hd->is_disk_protected(drv);
+ } else if(drv < 4) {
+ return fdc_2d->is_disk_protected(drv - 2);
+ }
+ return false;
+}
+
+uint32_t VM::is_floppy_disk_accessed()
+{
+ return (fdc_2hd->read_signal(0) & 3) | ((fdc_2d->read_signal(0) & 3) << 2);
+}
+
+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 1
+
+void VM::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+
+ for(DEVICE* device = first_device; device; device = device->next_device) {
+ const char *name = typeid(*device).name() + 6; // skip "class "
+
+ state_fio->FputInt32(strlen(name));
+ state_fio->Fwrite(name, strlen(name), 1);
+ 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) {
+ const char *name = typeid(*device).name() + 6; // skip "class "
+
+ if(!(state_fio->FgetInt32() == strlen(name) && state_fio->Fcompare(name, strlen(name)))) {
+ return false;
+ }
+ if(!device->load_state(state_fio)) {
+ return false;
+ }
+ }
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2017.12.28-
+
+ [ virtual machine ]
+*/
+
+#ifndef _FM16BETA_H_
+#define _FM16BETA_H_
+
+#if defined(HAS_I286)
+#define DEVICE_NAME "FUJITSU FM16beta (i286)"
+#define CONFIG_NAME "fm16beta_i286"
+#else
+#define DEVICE_NAME "FUJITSU FM16beta (i186)"
+#define CONFIG_NAME "fm16beta_i186"
+#endif
+
+// device informations for virtual machine
+
+// TODO: check refresh rate
+#define FRAMES_PER_SEC 55.38
+#define LINES_PER_FRAME 440
+#define CHARS_PER_LINE 54
+#define HD46505_HORIZ_FREQ (21052600.0 / 864)
+
+#define CPU_CLOCKS 8000000
+#define SCREEN_WIDTH 640
+#define SCREEN_HEIGHT 400
+#define WINDOW_HEIGHT_ASPECT 480
+#define MAX_DRIVE 4
+#define I8259_MAX_CHIPS 2
+#define SINGLE_MODE_DMA
+//#define MB8877_NO_BUSY_AFTER_SEEK
+
+#if defined(HAS_I286)
+#define MEMORY_ADDR_MAX 0x1000000 // 16MB
+#else
+#define MEMORY_ADDR_MAX 0x100000 // 1MB
+#endif
+#define MEMORY_BANK_SIZE 0x4000
+
+#define IO_ADDR_MAX 0x10000
+
+// device informations for win32
+#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_AUTO_KEY_NUMPAD
+#define USE_SCREEN_FILTER
+#define USE_SOUND_VOLUME 2
+#define USE_DEBUGGER
+#define USE_STATE
+
+#include "../../common.h"
+#include "../../fileio.h"
+
+#ifdef USE_SOUND_VOLUME
+static const _TCHAR *sound_device_caption[] = {
+ _T("Beep"), _T("Noise (FDD)"),
+};
+#endif
+
+class EMU;
+class DEVICE;
+class EVENT;
+
+class HD46505;
+class I8237;
+class I8251;
+class I8259;
+class I286;
+class IO;
+class MB8877;
+class MC6809;
+class MC6840;
+class MSM58321;
+class PCM1BIT;
+
+class CMOS;
+class KEYBOARD;
+class MAIN;
+class SUB;
+
+class VM
+{
+protected:
+ EMU* emu;
+
+ // devices
+ EVENT* event;
+
+ HD46505* crtc;
+ I8237* dma;
+ I8251* sio;
+ I8259* pic;
+ I286* cpu;
+ IO* io;
+ MB8877* fdc_2hd;
+ MB8877* fdc_2d;
+ MC6809* subcpu;
+ MC6840* ptm;
+ MSM58321* rtc;
+ PCM1BIT* pcm;
+
+ CMOS* cmos;
+ MAIN* main;
+ KEYBOARD* keyboard;
+ SUB* sub;
+
+public:
+ // ----------------------------------------
+ // initialize
+ // ----------------------------------------
+
+ VM(EMU* parent_emu);
+ ~VM();
+
+ // ----------------------------------------
+ // for emulation class
+ // ----------------------------------------
+
+ // drive virtual machine
+ void reset();
+ void notify_power_off();
+ void run();
+
+#ifdef USE_DEBUGGER
+ // debugger
+ DEVICE *get_cpu(int index);
+#endif
+
+ // draw screen
+ void draw_screen();
+
+ // sound generation
+ void initialize_sound(int rate, int samples);
+ uint16_t* create_sound(int* extra_frames);
+ int get_sound_buffer_ptr();
+#ifdef USE_SOUND_VOLUME
+ void set_sound_device_volume(int ch, int decibel_l, int decibel_r);
+#endif
+
+ // 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);
+ uint32_t is_floppy_disk_accessed();
+ 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 FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2018.01.01 -
+
+ [ keyboard ]
+*/
+
+#include "keyboard.h"
+#include "main.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 = 0;
+}
+
+uint32_t KEYBOARD::read_io8(uint32_t addr)
+{
+ if(addr & 1) {
+ d_main->write_signal(SIG_MAIN_IRQ1, 0, 0);
+ kbstat &= ~1;
+ return kbdata & 0xff;
+ } else {
+ return kbdata >> 8;
+ }
+}
+
+void KEYBOARD::event_frame()
+{
+ if(!(kbstat & 1) && !key_buf->empty()) {
+ d_main->write_signal(SIG_MAIN_IRQ1, 1, 1);
+ kbstat |= 1;
+ kbdata = key_buf->read();
+ }
+}
+
+void KEYBOARD::key_down(int code)
+{
+// if(!table[code]) {
+ table[code] = 1;
+ if(code = key_table[code]) {
+//code=0x20;
+ key_buf->write(code);
+ }
+// }
+}
+
+void KEYBOARD::key_up(int code)
+{
+// if(table[code]) {
+ table[code] = 0;
+ if(code = key_table[code]) {
+//code=0x20;
+ key_buf->write(code| 0x80);
+ }
+// }
+}
+
+#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->FputInt32(kbstat);
+ state_fio->FputInt32(kbdata);
+ 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->FgetInt32();
+ kbdata = state_fio->FgetInt32();
+ state_fio->Fread(table, sizeof(table), 1);
+ return true;
+}
+
+static const int key_code[] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0x008, 0x009, -1, -1, -1, 0x00D, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, 0x10B, -1, 0x01B, 0x10D, 0x10E, -1, -1,
+0x020, 0x112, 0x113, 0x111, 0x115, 0x118, 0x116, 0x119, 0x117, -1, -1, -1, -1, 0x110, 0x114, -1,
+0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, -1, -1, -1, -1, -1, -1,
+-1, 0x061, 0x062, 0x063, 0x064, 0x065, 0x066, 0x067, 0x068, 0x069, 0x06A, 0x06B, 0x06C, 0x06D, 0x06E, 0x06F,
+0x070, 0x071, 0x072, 0x073, 0x074, 0x075, 0x076, 0x077, 0x078, 0x079, 0x07A, -1, -1, -1, -1, -1,
+0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F,
+0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x10B, 0x10C, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x03A, 0x03B, 0x02C, 0x02D, 0x02E, 0x02F,
+0x040, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x05B, 0x05C, 0x05D, 0x05E, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const int key_code_shift[] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0x008, 0x009, -1, -1, -1, 0x00D, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, 0x12B, -1, 0x01B, 0x12D, 0x12E, -1, -1,
+0x020, 0x132, 0x133, 0x131, 0x135, 0x138, 0x136, 0x139, 0x137, -1, -1, -1, -1, 0x130, 0x134, -1,
+-1, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x027, 0x028, 0x029, -1, -1, -1, -1, -1, -1,
+-1, 0x041, 0x042, 0x043, 0x044, 0x045, 0x046, 0x047, 0x048, 0x049, 0x04A, 0x04B, 0x04C, 0x04D, 0x04E, 0x04F,
+0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056, 0x057, 0x058, 0x059, 0x05A, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+0x121, 0x122, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B, 0x12C, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x02B, 0x02A, 0x03C, 0x03D, 0x03E, 0x03F,
+0x060, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x07B, 0x07C, 0x07D, 0x07E, -1,
+-1, -1, 0x05F, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const int key_code_kana[] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0x008, 0x009, -1, -1, -1, 0x00D, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, 0x10B, -1, 0x01B, 0x10D, 0x10E, -1, -1,
+0x020, 0x112, 0x113, 0x111, 0x115, 0x118, 0x116, 0x119, 0x117, -1, -1, -1, -1, 0x110, 0x114, -1,
+0x0DC, 0x0C7, 0x0CC, 0x0B1, 0x0B3, 0x0B4, 0x0B5, 0x0D4, 0x0D5, 0x0D6, -1, -1, -1, -1, -1, -1,
+-1, 0x0C1, 0x0BA, 0x0BF, 0x0BC, 0x0B2, 0x0CA, 0x0B7, 0x0B8, 0x0C6, 0x0C9, 0x0C9, 0x0D8, 0x0D3, 0x0D0, 0x0D7,
+0x0BE, 0x0C0, 0x0BD, 0x0C4, 0x0B6, 0x0C5, 0x0CB, 0x0C3, 0x0BB, 0x0DD, 0x0C2, -1, -1, -1, -1, -1,
+0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F,
+0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x10B, 0x10C, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x0B9, 0x0DA, 0x0C8, 0x0CE, 0x0D9, 0x0D2,
+0x0DE, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x0DF, 0x0B0, 0x0D1, 0x0CD, -1,
+-1, -1, 0x0DB, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const int key_code_kana_shift[] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0x008, 0x009, -1, -1, -1, 0x00D, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, 0x12B, -1, 0x01B, 0x12D, 0x12E, -1, -1,
+0x020, 0x132, 0x133, 0x131, 0x135, 0x138, 0x136, 0x139, 0x137, -1, -1, -1, -1, 0x130, 0x134, -1,
+0x0A6, -1, -1, 0x0A7, 0x0A9, 0x0AA, 0x0AB, 0x0AC, 0x0AD, 0x0AE, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, 0x0A8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x0AF, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+0x121, 0x122, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B, 0x12C, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x0A4, -1, 0x0A1, 0x0A5,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x0A2, -1, 0x0A3, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const int key_code_graph[] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0x008, 0x009, -1, -1, -1, 0x00D, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, 0x10B, -1, 0x01B, 0x10D, 0x10E, -1, -1,
+0x020, 0x112, 0x113, 0x111, 0x115, 0x118, 0x116, 0x119, 0x117, -1, -1, -1, -1, 0x110, 0x114, -1,
+0x0F7, 0x0F9, 0x0FA, 0x0FB, 0x0FC, 0x0F2, 0x0F3, 0x0F4, 0x0F5, 0x0F6, -1, -1, -1, -1, -1, -1,
+-1, 0x095, 0x084, 0x082, 0x0E6, 0x0E4, 0x0E7, 0x09E, 0x09F, 0x0E8, 0x0EA, 0x0EB, 0x08E, 0x086, 0x085, 0x0E9,
+0x08D, 0x0FD, 0x0E5, 0x096, 0x09C, 0x0F0, 0x083, 0x0F8, 0x081, 0x09D, 0x080, -1, -1, -1, -1, -1,
+-1, 0x09A, 0x090, 0x09B, 0x093, 0x080, 0x092, 0x0E1, 0x0E2, 0x0E3, 0x098, 0x099, -1, 0x0EE, -1, 0x091,
+0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x10B, 0x10C, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x094, 0x089, 0x087, 0x08C, 0x088, 0x097,
+0x08A, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x0ED, 0x0F1, 0x0EC, 0x08B, -1,
+-1, -1, 0x0E0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const int key_code_graph_shift[] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0x008, 0x009, -1, -1, -1, 0x00D, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, 0x12B, -1, 0x01B, 0x12D, 0x12E, -1, -1,
+0x020, 0x132, 0x133, 0x131, 0x135, 0x138, 0x136, 0x139, 0x137, -1, -1, -1, -1, 0x130, 0x134, -1,
+0x0F7, 0x0F9, 0x0FA, 0x0FB, 0x0FC, 0x0F2, 0x0F3, 0x0F4, 0x0F5, 0x0F6, -1, -1, -1, -1, -1, -1,
+-1, 0x095, 0x084, 0x082, 0x0E6, 0x0E4, 0x0E7, 0x09E, 0x09F, 0x0E8, 0x0EA, 0x0EB, 0x08E, 0x086, 0x085, 0x0E9,
+0x08D, 0x0FD, 0x0E5, 0x096, 0x09C, 0x0F0, 0x083, 0x0F8, 0x081, 0x09D, 0x080, -1, -1, -1, -1, -1,
+-1, 0x09A, 0x090, 0x09B, 0x093, 0x080, 0x092, 0x0E1, 0x0E2, 0x0E3, 0x098, 0x099, -1, 0x0EE, -1, 0x091,
+0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x10B, 0x10C, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x094, 0x089, 0x087, 0x08C, 0x088, 0x097,
+0x08A, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x0ED, 0x0F1, 0x0EC, 0x08B, -1,
+-1, -1, 0x0E0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const int key_code_ctrl[] = {
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, 0x14B, -1, -1, 0x14D, 0x14E, -1, -1,
+-1, 0x152, 0x153, 0x151, 0x155, 0x158, 0x156, 0x159, 0x157, -1, -1, -1, -1, 0x150, 0x154, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, 0x00A, 0x00B, 0x00C, 0x00D, 0x00E, 0x00F,
+0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, 0x018, 0x109, 0x01A, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+0x141, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, 0x14B, 0x14C, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+0x000, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x01B, 0x01C, 0x01D, 0x01E, -1,
+-1, -1, 0x01F, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const int scan_code[] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0x0F, 0x10, -1, -1, -1, 0x1D, -1, -1,
+0x53, 0x52, 0x56, -1, 0x55, 0x5A, -1, -1, -1, 0x59, -1, 0x01, 0x58, 0x57, -1, -1,
+0x35, 0x49, 0x4C, 0x4A, 0x4E, 0x4F, 0x4D, 0x51, 0x50, -1, -1, -1, -1, 0x48, 0x4B, -1,
+0x0B, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, -1, -1, -1, -1, -1, -1,
+-1, 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, -1, -1, -1, -1, -1,
+0x46, 0x42, 0x43, 0x44, 0x3E, 0x3F, 0x40, 0x3A, 0x3B, 0x3C, 0x36, 0x38, 0x41, 0x39, 0x47, 0x37,
+0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x59, 0x5B, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x28, 0x27, 0x31, 0x0C, 0x32, 0x33,
+0x1B, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x1C, 0x0E, 0x29, 0x0D, -1,
+-1, -1, 0x34, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2018.01.01 -
+
+ [ keyboard ]
+*/
+
+#ifndef _KEYBOARD_H_
+#define _KEYBOARD_H_
+
+#include "../vm.h"
+#include "../../emu.h"
+#include "../device.h"
+
+#define SIG_KEYBOARD_INSLED 0
+
+/*
+ \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_main;
+
+ FIFO *key_buf;
+ int kbstat, kbdata;
+ uint8_t table[256];
+
+public:
+ KEYBOARD(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
+ {
+ set_device_name(_T("Keyboard"));
+ }
+ ~KEYBOARD() {}
+
+ // common functions
+ void initialize();
+ void release();
+ void reset();
+ 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_main(DEVICE* device)
+ {
+ d_main = device;
+ }
+ void key_down(int code);
+ void key_up(int code);
+};
+
+#endif
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2017.12.28-
+
+ [ main system ]
+*/
+
+#include "main.h"
+#include "sub.h"
+#include "keyboard.h"
+#include "../disk.h"
+#include "../i8237.h"
+#include "../i8259.h"
+#include "../mb8877.h"
+#include "../msm58321.h"
+#include "../pcm1bit.h"
+
+void MAIN::initialize()
+{
+ MEMORY::initialize();
+
+ memset(ram, 0x00, sizeof(ram));
+ memset(rom, 0xff, sizeof(rom));
+ direct = 0;
+
+ read_bios(_T("IPL.ROM"), rom, sizeof(rom));
+
+ set_memory_rw(0x00000, 0xfbfff, ram);
+ set_memory_r(0xfc000, 0xfffff, rom);
+
+ // main-sub
+// sub_busy = false;
+
+ // 1mb fdd
+ sidereg_2hd = 0; // side 0
+ drvreg_2hd = 0; // drive #0, motor on
+ drq_2hd = false;
+ d_fdc_2hd->write_signal(SIG_MB8877_MOTOR, 1, 1);
+ d_fdc_2hd->write_signal(SIG_MB8877_DRIVEREG, 0, 3);
+
+ // 320kb fdd
+ sidereg_2d = 0; // side 0
+ drvreg_2d = 0x80; // drive #0, motor on
+ drq_2d = false;
+ d_fdc_2d->write_signal(SIG_MB8877_MOTOR, 1, 1);
+ d_fdc_2d->write_signal(SIG_MB8877_DRIVEREG, 0, 3);
+
+ // rtc
+ rtc_data = 0;
+
+ // irq
+ irq_enb = ext_irq_enb = 0;
+ irq0_tx = irq0_rx = irq0_syn = irq1 = irq2 = irq3 = irq4 = irq5 = irq6 = irq7 = irq8 = irq9 = false;
+ firq0 = firq1 = firq2 = firq3 = false;
+ int0 = int1 = int2 = int3 = int4 = int5 = int6 = int7 = false;
+}
+
+void MAIN::release()
+{
+ MEMORY::release();
+}
+
+void MAIN::reset()
+{
+ MEMORY::reset();
+
+#ifdef HAS_I286
+ d_dma->set_address_mask(0x000fffff);
+ d_cpu->set_address_mask(0x000fffff);
+ rst = 0x00;
+#endif
+
+
+ d_pcm->write_signal(SIG_PCM1BIT_ON, 0, 0);
+}
+
+void MAIN::write_io8(uint32_t addr, uint32_t data)
+{
+ uint8_t change;
+
+ switch(addr) {
+ case 0x0020:
+ d_dma->write_signal(SIG_I8237_BANK0, data, 0xff);
+ break;
+ case 0x0021:
+ d_dma->write_signal(SIG_I8237_BANK1, data, 0xff);
+ break;
+ case 0x0022:
+ d_dma->write_signal(SIG_I8237_BANK2, data, 0xff);
+ break;
+ case 0x0023:
+ d_dma->write_signal(SIG_I8237_BANK3, data, 0xff);
+ break;
+
+
+#ifdef HAS_I286
+ case 0x0060:
+ if((data & 0xc0) == 0x40) {
+ d_cpu->reset();
+ rst |= 0x01;
+ }
+ if(data & 0x01) {
+ d_dma->set_address_mask(0x00ffffff);
+ d_cpu->set_address_mask(0x00ffffff);
+ } else {
+ d_dma->set_address_mask(0x000fffff);
+ d_cpu->set_address_mask(0x000fffff);
+ }
+ break;
+#endif
+ case 0xfd02:
+ change = irq_enb ^ data;
+ irq_enb = data;
+ if(change & 0x01) update_int7(); // Printer
+ if(change & 0x0e) update_int4(); // RS-232C
+ if(change & 0x10) update_int0(); // PTM
+ if(change & 0x20) update_int6(); // 320KB FDD
+ if(change & 0x80) update_int1(); // Keyboard
+ break;
+ case 0xfd03:
+ d_pcm->write_signal(SIG_PCM1BIT_ON, data, 0x80);
+ break;
+
+ case 0xfd04:
+ d_sub->write_signal(SIG_SUB_MAINACK, 1, 1);
+ break;
+
+ case 0xfd05:
+ d_sub->write_signal(SIG_SUB_HALT, data, 0x80);
+ d_sub->write_signal(SIG_SUB_CANCEL, data, 0x40);
+ break;
+
+ case 0xfd0f:
+ change = direct ^ data;
+ direct = data;
+ if(change & 0x80) {
+ if(direct & 0x80) {
+ set_memory_mapped_io_rw(0xc0000, 0xcffff, d_sub);
+ } else {
+ set_memory_rw(0xc0000, 0xcffff, ram + 0xc0000);
+ }
+ }
+ d_keyboard->write_signal(SIG_KEYBOARD_INSLED, data, 0x02);
+ break;
+ case 0xfd10:
+ d_rtc->write_signal(SIG_MSM58321_DATA, data, 0x0f);
+ break;
+ case 0xfd11:
+ 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;
+
+ case 0xfd1c:
+ d_fdc_2d->write_signal(SIG_MB8877_SIDEREG, data, 0x01);
+ sidereg_2d = data;
+ break;
+ case 0xfd1d:
+ d_fdc_2d->write_signal(SIG_MB8877_MOTOR, data, 0x80);
+ d_fdc_2d->write_signal(SIG_MB8877_DRIVEREG, data, 0x03);
+ drvreg_2d = data;
+ break;
+
+
+ case 0xfd2c:
+ change = ext_irq_enb ^ data;
+ ext_irq_enb = data;
+ if(change & 0x08) update_int2(); // 1MB FDD
+ break;
+
+ case 0xfd34:
+ d_fdc_2hd->write_signal(SIG_MB8877_SIDEREG, data, 0x01);
+ sidereg_2hd = data;
+ break;
+ case 0xfd35:
+ d_fdc_2hd->write_signal(SIG_MB8877_MOTOR, ~data, 0x80);
+ d_fdc_2hd->write_signal(SIG_MB8877_DRIVEREG, data, 0x03);
+ drvreg_2hd = data;
+ break;
+
+ }
+}
+
+uint32_t MAIN::read_io8(uint32_t addr)
+{
+ switch(addr) {
+#ifdef HAS_I286
+ case 0x0060:
+ {
+ uint8_t val = rst | (d_cpu->get_shutdown_flag() << 1);
+ rst = 0;
+ d_cpu->set_shutdown_flag(0);
+ return val;
+ }
+#endif
+ case 0xfd03:
+ return (irq8 ? 0x01 : 0) | (irq7 ? 0x02 : 0) | (irq4 ? 0x08 : 0) | (irq3 ? 0x10 : 0) | (irq2 ? 0x20 : 0) | (irq1 ? 0x40 : 0) | (irq0_tx || irq0_rx || irq0_syn ? 0x80 : 0);
+
+
+ case 0xfd04:
+ return (firq0 ? 0x01 : 0) | (firq1 ? 0x02 : 0) | (firq2 ? 0x80 : 0);
+
+ case 0xfd05:
+ return (sub_busy ? 0x80 : 0);
+
+ case 0xfd0f:
+ return direct;
+
+ case 0xfd10:
+ return rtc_data;
+
+ case 0xfd1c:
+ return sidereg_2d;
+ case 0xfd1d:
+ return drvreg_2d;
+ case 0xfd1f:
+ return (irq4 ? 0x40 : 0) | (drq_2d ? 0x80 : 0);
+
+ case 0xfd2c:
+ return (irq6 ? 0x04 : 0) | (irq5 ? 0x40 : 0);
+
+ case 0xfd34:
+ return sidereg_2hd;
+ case 0xfd35:
+ return drvreg_2hd;
+ case 0xfd36:
+ {
+ uint8_t val = 0x40; // DSNS=1
+ if(d_fdc_2hd->read_signal(SIG_MB8877_MOTOR)) {
+ for(int i = 0; i < 4; i++) {
+ if(d_fdc_2hd->is_disk_inserted(i)) {
+ val |= 1 << i;
+ }
+ }
+ }
+ DISK *disk = d_fdc_2hd->get_disk_handler(drvreg_2hd & 3);
+ if(disk->get_rpm() == 300) {
+ val |= 0x20;
+ }
+ if(disk->inserted && disk->two_side) {
+ val |= 0x80;
+ }
+ return val;
+ }
+ case 0xfd37:
+ return (irq5 ? 0x40 : 0) | (drq_2hd ? 0x80 : 0);
+
+// case 0xfda0:
+
+ }
+ return 0xff;
+}
+
+void MAIN::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ if(id == SIG_MAIN_IRQ0_TX) {
+ irq0_tx = ((data & mask) != 0);
+ update_int4();
+ } else if(id == SIG_MAIN_IRQ0_RX) {
+ irq0_rx = ((data & mask) != 0);
+ update_int4();
+ } else if(id == SIG_MAIN_IRQ0_SYN) {
+ irq0_syn = ((data & mask) != 0);
+ update_int4();
+ } else if(id == SIG_MAIN_IRQ1) {
+ if(!(irq_enb & 0x80)) {
+ d_sub->write_signal(SIG_SUB_KEY, data, mask);
+ }
+ irq1 = ((data & mask) != 0);
+ update_int1();
+ } else if(id == SIG_MAIN_IRQ2) {
+ irq2 = ((data & mask) != 0);
+ update_int5();
+ } else if(id == SIG_MAIN_IRQ3) {
+ irq3 = ((data & mask) != 0); // dma
+// update_int*();
+ } else if(id == SIG_MAIN_IRQ4) {
+ irq4 = ((data & mask) != 0);
+ update_int6();
+ } else if(id == SIG_MAIN_IRQ5) {
+ irq5 = ((data & mask) != 0);
+ update_int2();
+ } else if(id == SIG_MAIN_IRQ6) {
+ irq6 = ((data & mask) != 0);
+ update_int2();
+ } else if(id == SIG_MAIN_IRQ7) {
+ irq7 = ((data & mask) != 0);
+ update_int6();
+ } else if(id == SIG_MAIN_IRQ8) {
+ irq8 = ((data & mask) != 0);
+ update_int0();
+ } else if(id == SIG_MAIN_IRQ9) {
+ irq9 = ((data & mask) != 0);
+ update_int5();
+ } else if(id == SIG_MAIN_FIRQ0) {
+ firq0 = ((data & mask) != 0);
+ update_int3();
+ } else if(id == SIG_MAIN_FIRQ1) {
+ firq1 = ((data & mask) != 0);
+ update_int1();
+ } else if(id == SIG_MAIN_FIRQ2) {
+ firq2 = ((data & mask) != 0);
+ update_int3();
+ } else if(id == SIG_MAIN_FIRQ3) {
+ firq3 = ((data & mask) != 0);
+ update_int3();
+ } else if(id == SIG_MAIN_SUB_BUSY) {
+ sub_busy = ((data & mask) != 0);
+
+this->out_debug_log("SUB -> MAIN: SUB BUSY = %d\n", sub_busy);
+
+ } else if(id == SIG_MAIN_DRQ_2HD) {
+ drq_2hd = ((data & mask) != 0);
+ } else if(id == SIG_MAIN_DRQ_2D) {
+ drq_2d = ((data & mask) != 0);
+ } else if(id == SIG_MAIN_RTC_DATA) {
+ rtc_data = (data & mask) | (rtc_data & ~mask);
+ } else if(id == SIG_MAIN_RTC_BUSY) {
+ rtc_data = (data & mask) | (rtc_data & ~mask);
+ }
+}
+
+/*
+IRQ8 -> INT0
+ IRQ8: \83^\83C\83}\81[
+IRQ1 + FIRQ1 -> INT1
+ IRQ1: \83L\81[\83{\81[\83h
+ FIRQ1: BREAK\83L\81[
+IRQ5 + IRQ6 -> INT2
+ IRQ5: IMB\83t\83\8d\83b\83s\83B\83f\83B\83X\83N
+ IRQ6: \83n\81[\83h\83f\83B\83X\83N
+FIRQ0 + FIRQ2 + FIRQ3 -> INT3
+ FIRQ0: SUB\83A\83e\83\93\83V\83\87\83\93
+ FIRQ2: \8ag\92£
+ FIRQ3: \83\86\81[\83U\97p
+IRQ0 -> INT4
+ IRQ0: RS-232C
+IRQ2 + IRQ9 + INTNDP -> INT5
+ IRQ2: \8ag\92£
+ IRQ9: \83\86\81[\83U\97p
+IRQ4 -> INT6
+ IRQ4: 320KB\83t\83\8d\83b\83s\83B\83f\83B\83X\83N
+IRQ7 -> INT7
+ IRQ7: \83v\83\8a\83\93\83^
+*/
+
+void MAIN::update_int0()
+{
+// bool prev = int0;
+ int0 = (irq8 && (irq_enb & 0x10));
+// if(prev != int0) {
+ d_pic->write_signal(SIG_I8259_IR0, int0 ? 1 : 0, 1);
+// }
+}
+
+void MAIN::update_int1()
+{
+// bool prev = int1;
+ int1 = (irq1 && (irq_enb & 0x80)) || firq1;
+// if(prev != int1) {
+ d_pic->write_signal(SIG_I8259_IR1, int1 ? 1 : 0, 1);
+// }
+}
+
+void MAIN::update_int2()
+{
+// bool prev = int2;
+ int2 = (irq5 && (ext_irq_enb & 0x08)) || irq6;
+// if(prev != int2) {
+ d_pic->write_signal(SIG_I8259_IR2, int2 ? 1 : 0, 1);
+// }
+}
+
+void MAIN::update_int3()
+{
+// bool prev = int3;
+ int3 = firq0 || firq2 || firq3;
+// if(prev != int3) {
+ d_pic->write_signal(SIG_I8259_IR3, int3 ? 1 : 0, 1);
+// }
+}
+
+void MAIN::update_int4()
+{
+// bool prev = int4;
+ int4 = (irq0_tx && (irq_enb & 0x02)) || (irq0_rx && (irq_enb & 0x04)) || (irq0_syn && (irq_enb & 0x08));
+// if(prev != int4) {
+ d_pic->write_signal(SIG_I8259_IR4, int4 ? 1 : 0, 1);
+// }
+}
+
+void MAIN::update_int5()
+{
+// bool prev = int5;
+ int5 = irq2 || irq9;
+// if(prev != int5) {
+ d_pic->write_signal(SIG_I8259_IR5, int5 ? 1 : 0, 1);
+// }
+}
+
+void MAIN::update_int6()
+{
+// bool prev = int6;
+ int6 = (irq6 && (irq_enb & 0x20));
+// if(prev != int6) {
+ d_pic->write_signal(SIG_I8259_IR6, int6 ? 1 : 0, 1);
+// }
+}
+
+void MAIN::update_int7()
+{
+// bool prev = int7;
+ int7 = irq7 && (irq_enb & 0x01);
+// if(prev != int7) {
+ d_pic->write_signal(SIG_I8259_IR7, int7 ? 1 : 0, 1);
+// }
+}
+
+#define STATE_VERSION 1
+
+void MAIN::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+}
+
+bool MAIN::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2017.12.28-
+
+ [ main system ]
+*/
+
+#ifndef _MAIN_H_
+#define _MAIN_H_
+
+#include "../memory.h"
+
+#define SIG_MAIN_IRQ0_TX 0 // RS-232C
+#define SIG_MAIN_IRQ0_RX 1 // RS-232C
+#define SIG_MAIN_IRQ0_SYN 2 // RS-232C
+#define SIG_MAIN_IRQ1 3 // Keyboard
+#define SIG_MAIN_IRQ2 4 // Expantion
+#define SIG_MAIN_IRQ3 5 // DMA Controller
+#define SIG_MAIN_IRQ4 6 // 320KB Floppy Disk
+#define SIG_MAIN_IRQ5 7 // 1MB Floppy Disk
+#define SIG_MAIN_IRQ6 8 // Hard Disk
+#define SIG_MAIN_IRQ7 9 // Printer
+#define SIG_MAIN_IRQ8 10 // PTM
+#define SIG_MAIN_IRQ9 11 // User
+#define SIG_MAIN_FIRQ0 12 // Sub system attention
+#define SIG_MAIN_FIRQ1 13 // Break
+#define SIG_MAIN_FIRQ2 14 // Expantion
+#define SIG_MAIN_FIRQ3 15 // User
+
+#define SIG_MAIN_SUB_BUSY 16
+
+#define SIG_MAIN_DRQ_2HD 17
+#define SIG_MAIN_DRQ_2D 18
+
+#define SIG_MAIN_RTC_DATA 19
+#define SIG_MAIN_RTC_BUSY 20
+
+#ifdef HAS_I286
+class I286;
+#endif
+class I8237;
+class MB8877;
+
+class MAIN : public MEMORY
+{
+private:
+#ifdef HAS_I286
+ I286 *d_cpu;
+ uint8_t rst;
+#endif
+ I8237 *d_dma;
+ DEVICE *d_pic;
+ DEVICE *d_pcm;
+ DEVICE *d_keyboard;
+
+ // memory
+ uint8_t ram[0xfc000];
+ uint8_t rom[0x04000];
+ uint8_t direct;
+
+ // main-sub
+ DEVICE *d_sub;
+ bool sub_busy;
+
+ // 1mb fdd
+ MB8877 *d_fdc_2hd;
+ uint8_t sidereg_2hd, drvreg_2hd;
+ bool drq_2hd;
+
+ // 320kb fdd
+ MB8877 *d_fdc_2d;
+ uint8_t sidereg_2d, drvreg_2d;
+ bool drq_2d;
+
+ // rtc
+ DEVICE *d_rtc;
+ uint8_t rtc_data;
+
+ // irq
+ uint8_t irq_enb, ext_irq_enb;
+ bool irq0_tx, irq0_rx, irq0_syn, irq1, irq2, irq3, irq4, irq5, irq6, irq7, irq8, irq9;
+ bool firq0, firq1, firq2, firq3;
+ bool int0, int1, int2, int3, int4, int5, int6, int7;
+
+ void update_int0();
+ void update_int1();
+ void update_int2();
+ void update_int3();
+ void update_int4();
+ void update_int5();
+ void update_int6();
+ void update_int7();
+
+public:
+ MAIN(VM* parent_vm, EMU* parent_emu) : MEMORY(parent_vm, parent_emu)
+ {
+ set_device_name(_T("Main System"));
+ }
+ ~MAIN() {}
+
+ // 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 write_signal(int id, uint32_t data, uint32_t mask);
+ void save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // unique functions
+#ifdef HAS_I286
+ void set_context_cpu(I286* device)
+ {
+ d_cpu = device;
+ }
+#endif
+ void set_context_dma(I8237* device)
+ {
+ d_dma = device;
+ }
+ void set_context_fdc_2hd(MB8877* device)
+ {
+ d_fdc_2hd = device;
+ }
+ void set_context_fdc_2d(MB8877* device)
+ {
+ d_fdc_2d = device;
+ }
+ void set_context_pic(DEVICE* device)
+ {
+ d_pic = device;
+ }
+ void set_context_pcm(DEVICE* device)
+ {
+ d_pcm = device;
+ }
+ void set_context_rtc(DEVICE* device)
+ {
+ d_rtc = device;
+ }
+ void set_context_sub(DEVICE* device)
+ {
+ d_sub = device;
+ }
+ void set_context_keyboard(DEVICE* device)
+ {
+ d_keyboard = device;
+ }
+};
+
+#endif
--- /dev/null
+IRQ8 -> INT0
+ IRQ8: \83^\83C\83}\81[
+IRQ1 + FIRQ1 -> INT1
+ IRQ1: \83L\81[\83{\81[\83h
+ FIRQ1: BREAK\83L\81[
+IRQ5 + IRQ6 -> INT2
+ IRQ5: 1MB\83t\83\8d\83b\83s\83B\83f\83B\83X\83N
+ IRQ6: \83n\81[\83h\83f\83B\83X\83N
+FIRQ0 + FIRQ2 + FIRQ3 -> INT3
+ FIRQ0: SUB\83A\83e\83\93\83V\83\87\83\93
+ FIRQ2: \8ag\92£
+ FIRQ3: \83\86\81[\83U\97p
+IRQ0 -> INT4
+ IRQ0: RS-232C
+IRQ2 + IRQ9 + INTNDP -> INT5
+ IRQ2: \8ag\92£
+ IRQ9: \83\86\81[\83U\97p
+IRQ4 -> INT6
+ IRQ4: 320KB\83t\83\8d\83b\83s\83B\83f\83B\83X\83N
+IRQ7 -> INT7
+ IRQ7: \83v\83\8a\83\93\83^
+
+DMA0 320KB\83t\83\8d\83b\83s\83B\83f\83B\83X\83N
+DMA1 1MB\83t\83\8d\83b\83s\83B\83f\83B\83X\83N
+DMA2 \83n\81[\83h\83f\83B\83X\83N
+DMA3 \83\86\81[\83U
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2017.12.28-
+
+ [ sub system ]
+*/
+
+#include "sub.h"
+#include "main.h"
+#include "../pcm1bit.h"
+
+void SUB::initialize()
+{
+ MEMORY::initialize();
+
+ // init memory
+ memset(wram, 0, sizeof(wram));
+ memset(sram, 0, sizeof(sram));
+ memset(gvram, 0, sizeof(gvram));
+ memset(dummy, 0, sizeof(dummy));
+ memset(cvram, 0, sizeof(cvram));
+ memset(kvram, 0, sizeof(kvram));
+ memset(rom, 0xff, sizeof(rom));
+ memset(ank8, 0xff, sizeof(ank8));
+ memset(ank16, 0xff, sizeof(ank16));
+ memset(kanji16, 0xff, sizeof(kanji16));
+
+ // load rom image
+ FILEIO* fio = new FILEIO();
+ if(fio->Fopen(create_local_path(_T("SUBSYS.ROM")), FILEIO_READ_BINARY) ||
+ fio->Fopen(create_local_path(_T("SUB.ROM")), FILEIO_READ_BINARY)) {
+ fio->Fread(rom, sizeof(rom), 1);
+ fio->Fclose();
+ if(rom[0x4ff2] == 0xff && rom[0x4ff3] == 0xff) { // SWI3
+ rom[0x4ff2] = 0x9f;
+ rom[0x4ff3] = 0x6e;
+ }
+ if(rom[0x4ff4] == 0xff && rom[0x4ff5] == 0xff) { // SWI2
+ rom[0x4ff4] = 0x9f;
+ rom[0x4ff5] = 0x71;
+ }
+ if(rom[0x4ff6] == 0xff && rom[0x4ff7] == 0xff) { // FIRQ
+ rom[0x4ff6] = 0x9f;
+ rom[0x4ff7] = 0x74;
+ }
+ if(rom[0x4ff8] == 0xff && rom[0x4ff9] == 0xff) { // IRQ
+ rom[0x4ff8] = 0x9f;
+ rom[0x4ff9] = 0x77;
+ }
+ if(rom[0x4ffa] == 0xff && rom[0x4ffb] == 0xff) { // SWI
+ rom[0x4ffa] = 0x9f;
+ rom[0x4ffb] = 0x7a;
+ }
+ if(rom[0x4ffc] == 0xff && rom[0x4ffd] == 0xff) { // NMI
+ rom[0x4ffc] = 0x9f;
+ rom[0x4ffd] = 0x7d;
+ }
+ if(rom[0x4ffe] == 0xff && rom[0x4fff] == 0xff) { // RESET
+ for(int i = 0; i < sizeof(rom) - 4; i++) {
+ static const uint8_t boot[4] = {0x86, 0x90, 0x1f, 0x8b};
+ if(memcmp(rom + i, boot, sizeof(boot)) == 0) {
+ i += 0xb000;
+ rom[0x4ffe] = (i >> 8) & 0xff;
+ rom[0x4fff] = (i >> 0) & 0xff;
+ break;
+ }
+ }
+ }
+ }
+ 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();
+ }
+ delete fio;
+
+ set_memory_rw(0x9000, 0x9f7f, wram + 0x1000);
+ set_memory_rw(0x9f80, 0x9fff, sram);
+ set_memory_r (0xb000, 0xffff, rom);
+
+ for(int i = 0; i < 8; i++) {
+ palette_txt[i] = palette_cg[i] = RGB_COLOR(i & 2 ? 255 : 0, i & 4 ? 255 : 0, i & 1 ? 255 : 0);
+ }
+
+
+}
+
+void SUB::release()
+{
+ MEMORY::release();
+}
+
+void SUB::reset()
+{
+ MEMORY::reset();
+
+ // reset crtc
+ blink = 0;
+ outctrl = 0xf;
+
+ d_main->write_signal(SIG_MAIN_SUB_BUSY, 1, 1);
+ mix = 0x00;
+
+ update = dispctrl = pagesel = 0;
+ ankcg = 0;
+ accaddr = dispaddr = 0;
+
+ update_cvram_bank();
+ update_kvram_bank();
+
+ memset(attention, 0, sizeof(attention));
+ mainack = 0x80;
+
+ irq_cancel = irq_vsync = firq_key = firq_pen = false;
+
+ kj_l = kj_h = kj_ofs = kj_row = 0;
+
+ cmdreg = maskreg = compbit = bankdis = 0;
+ memset(compreg, 0xff, sizeof(compreg));
+}
+
+void SUB::write_data8(uint32_t addr, uint32_t data)
+{
+ // sub cpu memory bus
+ write_memory(addr, data);
+#ifdef _IO_DEBUG_LOG
+ if((addr >= 0x9f80 && addr < 0xa000) || (addr >= 0xff80 && addr < 0xffe0)) {
+ this->out_debug_log(_T("SUB %06x\tOUT8\t%04x,%02x\n"), get_cpu_pc(1), addr, data);
+ }
+#endif
+}
+
+uint32_t SUB::read_data8(uint32_t addr)
+{
+ // sub cpu memory bus
+ uint32_t val = read_memory(addr);
+#ifdef _IO_DEBUG_LOG
+ if((addr >= 0x9f80 && addr < 0xa000) || (addr >= 0xff80 && addr < 0xffe0)) {
+ this->out_debug_log(_T("SUB %06x\tIN8\t%04x,%02x\n"), get_cpu_pc(1), addr, val);
+ }
+#endif
+ return val;
+}
+
+void SUB::write_memory_mapped_io8(uint32_t addr, uint32_t data)
+{
+ // main cpu direct access
+ addr &= 0xffff;
+ write_memory(addr, data);
+#ifdef _IO_DEBUG_LOG
+ if((addr >= 0x9f80 && addr < 0xa000) || (addr >= 0xff80 && addr < 0xffe0)) {
+ this->out_debug_log(_T("MAIN %06x\tOUT8\t%04x,%02x\n"), get_cpu_pc(0), addr, data);
+ }
+#endif
+}
+
+uint32_t SUB::read_memory_mapped_io8(uint32_t addr)
+{
+ // main cpu direct access
+ addr &= 0xffff;
+ uint32_t val = read_memory(addr);
+#ifdef _IO_DEBUG_LOG
+ if((addr >= 0x9f80 && addr < 0xa000) || (addr >= 0xff80 && addr < 0xffe0)) {
+ this->out_debug_log(_T("MAIN %06x\tIN8\t%04x,%02x\n"), get_cpu_pc(1), addr, val);
+ }
+#endif
+ return val;
+}
+
+void SUB::write_memory(uint32_t addr, uint32_t data)
+{
+ if(addr < 0x8000) {
+ if(dispctrl & 0x40) {
+ uint32_t bank = (pagesel >> 4) & 1;
+ addr &= 0x7fff;
+ addr |= bank << 15;
+ } else {
+ uint32_t bank = (pagesel >> 3) & 3;
+ addr &= 0x3fff;
+ addr |= bank << 14;
+ }
+ if(update & 1) gvram[addr | 0x00000] = data;
+ if(update & 2) gvram[addr | 0x10000] = data;
+ if(update & 4) gvram[addr | 0x20000] = data;
+ } else if(addr >= 0xff80 && addr < 0xffe0) {
+ uint8_t change;
+
+ switch(addr) {
+ case 0xff80:
+ d_main->write_signal(SIG_MAIN_SUB_BUSY, ~data, 1);
+ mix = data;
+ break;
+ case 0xff81:
+ update = data;
+ break;
+ case 0xff82:
+ dispctrl = data;
+ break;
+ case 0xff83:
+ change = pagesel ^ data;
+ pagesel = data;
+ if(change & 0x20) {
+ update_cvram_bank();
+ }
+ break;
+
+
+
+
+ case 0xff87:
+ d_main->write_signal(SIG_MAIN_FIRQ0, 1, 1);
+ mainack &= ~0x80;
+ break;
+
+ case 0xff88:
+ accaddr = (accaddr & 0x00ff) | (data << 8);
+ break;
+ case 0xff89:
+ accaddr = (accaddr & 0xff00) | (data << 0);
+ break;
+ case 0xff8a:
+ dispaddr = (dispaddr & 0x00ff) | (data << 8);
+ break;
+ case 0xff8b:
+ dispaddr = (dispaddr & 0xff00) | (data << 0);
+ break;
+
+ case 0xff8e:
+ case 0xff8f:
+ d_crtc->write_io8(addr, data);
+ break;
+
+ case 0xff90:
+ case 0xff91:
+ case 0xff92:
+ attention[addr & 3] = 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 0xff98:
+ d_pcm->write_signal(SIG_PCM1BIT_ON, 0, 0);
+ break;
+
+ case 0xff99:
+ change = ankcg ^ data;
+ ankcg = data;
+ if(change & 0x01) {
+ update_kvram_bank();
+ }
+ if(change & 0x80) {
+ update_kvram_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;
+#ifdef _IO_DEBUG_LOG
+ default:
+ this->out_debug_log(_T("UNKNOWN:\t"));
+ break;
+#endif
+ }
+ } else {
+ MEMORY::write_data8(addr, data);
+ }
+}
+
+uint32_t SUB::read_memory(uint32_t addr)
+{
+ if(addr < 0x8000) {
+ if(dispctrl & 0x40) {
+ uint32_t bank = (pagesel >> 4) & 1;
+ addr &= 0x7fff;
+ addr |= bank << 15;
+ } else {
+ uint32_t bank = (pagesel >> 3) & 3;
+ addr &= 0x3fff;
+ addr |= bank << 14;
+ }
+ switch(update & 0xc0) {
+ case 0x00: return gvram[addr | 0x00000];
+ case 0x40: return gvram[addr | 0x10000];
+ case 0x80: return gvram[addr | 0x20000];
+ }
+ return 0xff;
+ } else if(addr >= 0xff80 && addr < 0xffe0) {
+ switch(addr) {
+ case 0xff80:
+ // bit5: Cursor LSB
+ // bit4: Light Pen FIRQ 0:Disabled 1:Enabled
+ // bit3: WIDTH 0:40 1:80
+ // bit2: FLASH 0:OFF 1:ON
+ // bit1: INSLED 0:OFF 1:ON
+ // bit0: SUB BUSY 0:BUSY 1:READY
+ return mix | 0xc0;
+ case 0xff81:
+ // bit7: Read Out Control RC2
+ // bit6: Read Out Control RC1
+ // bit2: RAM Select Bit RAM3
+ // bit1: RAM Select Bit RAM2
+ // bit0: RAM Select Bit RAM1
+ return update | 0x38;
+ case 0xff83:
+ return pagesel | 0xc7;
+
+ case 0xff84:
+ {
+ uint8_t val = (firq_key ? 0x01 : 0) | (firq_pen ? 0x80 : 0);
+ firq_key = firq_pen = false;
+ update_firq();
+ return val;
+ }
+
+ case 0xff85:
+ {
+ uint8_t val = (irq_cancel ? 0x01 : 0) | (irq_vsync ? 0x02 : 0) | 0x7e;
+ irq_cancel = irq_vsync = false;
+ update_irq();
+ return val;
+ }
+
+
+
+ case 0xff86:
+ return (disp ? 0x80 : 0) | (vsync ? 0x04 : 0) | 0x70;
+
+ case 0xff87:
+ d_main->write_signal(SIG_MAIN_FIRQ0, 1, 1);
+ mainack &= ~0x80;
+ break;
+
+ case 0xff8c:
+ case 0xff8d:
+ return d_keyboard->read_io8(addr);
+ case 0xff8e:
+ case 0xff8f:
+ return d_crtc->read_io8(addr);
+ case 0xff90:
+ case 0xff91:
+ case 0xff92:
+ return attention[addr & 3];
+ case 0xff93:
+ return mainack;
+ case 0xff94:
+ return 0x80; // \91æ\93ñ\90\85\8f\80\82 \82è
+ case 0xff96:
+ return kanji16[(kj_ofs | ((kj_row & 0xf) << 1)) & 0x3ffff];
+ case 0xff97:
+ return kanji16[(kj_ofs | ((kj_row++ & 0xf) << 1) | 1) & 0x3ffff];
+ case 0xff98:
+ d_pcm->write_signal(SIG_PCM1BIT_ON, 1, 1);
+ break;
+
+ case 0xff99:
+ return ankcg;
+ case 0xffa0:
+ return cmdreg;
+ case 0xffa1:
+ return imgcol | 0xf0;
+ case 0xffa2:
+ return maskreg;
+ case 0xffa3:
+ return compbit;
+ case 0xffab:
+ return bankdis & 0x0f;
+
+ case 0xffb0:
+ return (lofs >> 8) & 0xff;
+ case 0xffb1:
+ return (lofs >> 0) & 0xff;
+#ifdef _IO_DEBUG_LOG
+ default:
+ this->out_debug_log(_T("UNKNOWN:\t"));
+ break;
+#endif
+ }
+ return 0xff;
+ } else {
+ return MEMORY::read_data8(addr);
+ }
+}
+
+void SUB::write_io8(uint32_t addr, uint32_t data)
+{
+ // main cpu i/o bus
+ switch(addr) {
+ case 0xfd98:
+ case 0xfd99:
+ case 0xfd9a:
+ case 0xfd9b:
+ case 0xfd9c:
+ case 0xfd9d:
+ case 0xfd9e:
+ case 0xfd9f:
+ // digital palette
+ 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);
+ }
+ dpal[addr & 7] = data;
+ break;
+ case 0xfda0:
+ outctrl = data;
+ break;
+ // 0xfc80 - 0xfcff
+ default:
+ sram[addr & 0x7f] = data;
+ break;
+ }
+}
+
+uint32_t SUB::read_io8(uint32_t addr)
+{
+ // main cpu i/o bus
+ switch(addr) {
+ case 0xfd20:
+ case 0xfd21:
+ case 0xfd22:
+ return attention[addr & 3];
+
+ case 0xfd98:
+ case 0xfd99:
+ case 0xfd9a:
+ case 0xfd9b:
+ case 0xfd9c:
+ case 0xfd9d:
+ case 0xfd9e:
+ case 0xfd9f:
+ // digital palette
+ return dpal[addr & 7] | 0xf0;
+ // 0xfc80 - 0xfcff
+ default:
+ return sram[addr & 0x7f];
+ }
+ return 0xff;
+}
+
+void SUB::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ if(id == SIG_SUB_DISP) {
+ disp = ((data & mask) != 0);
+ } else if(id == SIG_SUB_VSYNC) {
+ irq_vsync = vsync = ((data & mask) != 0);
+ update_irq();
+ } else if(id == SIG_SUB_CANCEL) {
+ irq_cancel = ((data & mask) != 0);
+ update_irq();
+this->out_debug_log("MAIN -> SUB: CANCEL = %d\n", irq_cancel);
+
+ } else if(id == SIG_SUB_KEY) {
+ firq_key = ((data & mask) != 0);
+ update_firq();
+ } else if(id == SIG_SUB_HALT) {
+this->out_debug_log("MAIN -> SUB: HALT = %d\n", data & mask ?1 : 0);
+ if(data & mask) {
+ d_main->write_signal(SIG_MAIN_SUB_BUSY, 1, 1);
+ mix &= ~0x01;
+ }
+ d_subcpu->write_signal(SIG_CPU_BUSREQ, data, mask);
+ } else if(id == SIG_SUB_MAINACK) {
+this->out_debug_log("MAIN -> SUB: MAINACK = %d\n", data & mask ? 1 : 0);
+ if(data & mask) {
+ d_main->write_signal(SIG_MAIN_FIRQ0, 0, 0);
+ mainack |= 0x80;
+ }
+ }
+}
+
+void SUB::update_irq()
+{
+ d_subcpu->write_signal(SIG_CPU_IRQ, irq_cancel || (irq_vsync && (ankcg & 0x80)) ? 1 : 0, 1);
+}
+
+void SUB::update_firq()
+{
+ d_subcpu->write_signal(SIG_CPU_FIRQ, firq_key || (firq_pen && (mix & 0x10)) ? 1 : 0, 1);
+}
+
+void SUB::update_cvram_bank()
+{
+ if(pagesel & 0x20) {
+ set_memory_rw(0x8000, 0x8fff, wram);
+ } else {
+ set_memory_rw(0x8000, 0x8fff, cvram);
+ }
+}
+
+void SUB::update_kvram_bank()
+{
+ if(ankcg & 0x01) {
+ set_memory_r(0xa000, 0xa7ff, ank8);
+ set_memory_r(0xa800, 0xafff, ank8);
+ } else {
+ set_memory_rw(0xa000, 0xafff, kvram);
+ }
+}
+
+void SUB::key_down(int code)
+{
+
+}
+
+void SUB::key_up(int code)
+{
+
+}
+
+void SUB::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 < 3; pl++) {
+ uint8_t pbit = 1 << pl;
+ if(!(bankdis & pbit)) {
+ if(col & pbit) {
+ gvram[0x8000 * pl + ofs] |= bit;
+ } else {
+ gvram[0x8000 * pl + ofs] &= ~bit;
+ }
+ }
+ }
+ }
+}
+
+void SUB::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);
+}
+
+void SUB::draw_screen()
+{
+ // render screen
+ memset(screen_txt, 0, sizeof(screen_txt));
+ memset(screen_cg, 0, sizeof(screen_cg));
+
+ if(outctrl & 1) {
+ if(mix & 8) {
+ draw_text80();
+ } else {
+ draw_text40();
+ }
+ } else if(outctrl & 2) {
+ // greem text
+ }
+ if(outctrl & 4) {
+ draw_cg();
+ } else if(outctrl & 8) {
+ // green graphics
+ }
+
+ 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);
+}
+
+void SUB::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 SUB::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);
+ }
+ }
+ }
+ }
+ }
+}
+
+void SUB::draw_cg()
+{
+ if(dispctrl & 0x40) {
+ // 400line
+ int pofs = ((dispctrl >> 3) & 1) * 0x20000;
+ uint8_t* p0 = (dispctrl & 0x01) ? &gvram[pofs | 0x00000] : dummy;
+ uint8_t* p1 = (dispctrl & 0x02) ? &gvram[pofs | 0x08000] : dummy;
+ uint8_t* p2 = (dispctrl & 0x04) ? &gvram[pofs | 0x10000] : 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++];
+ ptr &= 0x7fff;
+ uint8_t* d = &screen_cg[y][x];
+
+ d[0] = ((r & 0x80) >> 7) | ((g & 0x80) >> 6) | ((b & 0x80) >> 5);
+ d[1] = ((r & 0x40) >> 6) | ((g & 0x40) >> 5) | ((b & 0x40) >> 4);
+ d[2] = ((r & 0x20) >> 5) | ((g & 0x20) >> 4) | ((b & 0x20) >> 3);
+ d[3] = ((r & 0x10) >> 4) | ((g & 0x10) >> 3) | ((b & 0x10) >> 2);
+ d[4] = ((r & 0x08) >> 3) | ((g & 0x08) >> 2) | ((b & 0x08) >> 1);
+ d[5] = ((r & 0x04) >> 2) | ((g & 0x04) >> 1) | ((b & 0x04) >> 0);
+ d[6] = ((r & 0x02) >> 1) | ((g & 0x02) >> 0) | ((b & 0x02) << 1);
+ d[7] = ((r & 0x01) >> 0) | ((g & 0x01) << 1) | ((b & 0x01) << 2);
+ }
+ }
+ } else {
+ // 200line
+ int pofs = ((dispctrl >> 3) & 3) * 0x10000;
+ uint8_t* p0 = (dispctrl & 0x01) ? &gvram[pofs | 0x0000] : dummy;
+ uint8_t* p1 = (dispctrl & 0x02) ? &gvram[pofs | 0x4000] : dummy;
+ uint8_t* p2 = (dispctrl & 0x04) ? &gvram[pofs | 0x8000] : 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++];
+ ptr &= 0x3fff;
+ uint8_t* d = &screen_cg[y][x];
+
+ d[0] = ((r & 0x80) >> 7) | ((g & 0x80) >> 6) | ((b & 0x80) >> 5);
+ d[1] = ((r & 0x40) >> 6) | ((g & 0x40) >> 5) | ((b & 0x40) >> 4);
+ d[2] = ((r & 0x20) >> 5) | ((g & 0x20) >> 4) | ((b & 0x20) >> 3);
+ d[3] = ((r & 0x10) >> 4) | ((g & 0x10) >> 3) | ((b & 0x10) >> 2);
+ d[4] = ((r & 0x08) >> 3) | ((g & 0x08) >> 2) | ((b & 0x08) >> 1);
+ d[5] = ((r & 0x04) >> 2) | ((g & 0x04) >> 1) | ((b & 0x04) >> 0);
+ d[6] = ((r & 0x02) >> 1) | ((g & 0x02) >> 0) | ((b & 0x02) << 1);
+ d[7] = ((r & 0x01) >> 0) | ((g & 0x01) << 1) | ((b & 0x01) << 2);
+ }
+ memcpy(screen_cg[y + 1], screen_cg[y], 640);
+ }
+ }
+}
+
+#define STATE_VERSION 1
+
+void SUB::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ MEMORY::save_state(state_fio);
+}
+
+bool SUB::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ if(!MEMORY::load_state(state_fio)) {
+ return false;
+ }
+ return true;
+}
+
--- /dev/null
+/*
+ FUJITSU FM16beta Emulator 'eFM16beta'
+
+ Author : Takeda.Toshiya
+ Date : 2017.12.28-
+
+ [ sub system ]
+*/
+
+#ifndef _SUB_H_
+#define _SUB_H_
+
+#include "../memory.h"
+
+#define SIG_SUB_DISP 0
+#define SIG_SUB_VSYNC 1
+#define SIG_SUB_CANCEL 2
+#define SIG_SUB_KEY 3
+#define SIG_SUB_HALT 4
+#define SIG_SUB_MAINACK 5
+
+class SUB : public MEMORY
+{
+private:
+ DEVICE *d_crtc, *d_pcm, *d_main, *d_subcpu, *d_keyboard;
+
+ uint8_t gvram[0x30000];
+ uint8_t dummy[0x8000]; // dummy plane
+ uint8_t cvram[0x1000];
+ uint8_t kvram[0x1000];
+
+ uint8_t wram[0x1f80];
+ uint8_t sram[0x0080];
+ uint8_t rom[0x5000];
+
+ uint8_t ank8[0x800];
+ uint8_t ank16[0x1000];
+ uint8_t kanji16[0x40000];
+
+ uint8_t mix;
+ uint8_t update, dispctrl, pagesel;
+ uint8_t ankcg;
+ uint16_t accaddr, dispaddr;
+
+ // main-sub
+ uint8_t attention[3];
+ uint8_t mainack;
+
+ // interrupts
+ bool irq_cancel, irq_vsync, firq_key, firq_pen;
+ void update_irq();
+ void update_firq();
+
+ // crtc
+ uint8_t* chreg;
+ bool disp, vsync;
+ int blink;
+
+ // video
+ uint8_t dpal[8];
+ uint8_t outctrl;
+
+ void update_cvram_bank();
+ void update_kvram_bank();
+
+ // 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();
+
+ 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[8];
+ scrntype_t palette_cg[8];
+
+ void draw_text40();
+ void draw_text80();
+ void draw_cg();
+
+ void write_memory(uint32_t addr, uint32_t data);
+ uint32_t read_memory(uint32_t addr);
+
+public:
+ SUB(VM* parent_vm, EMU* parent_emu) : MEMORY(parent_vm, parent_emu)
+ {
+ set_device_name(_T("Sub System"));
+ }
+ ~SUB() {}
+
+ // common functions
+ void initialize();
+ void release();
+ void reset();
+ void write_data8(uint32_t addr, uint32_t data);
+ uint32_t read_data8(uint32_t addr);
+ void write_memory_mapped_io8(uint32_t addr, uint32_t data);
+ uint32_t read_memory_mapped_io8(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 save_state(FILEIO* state_fio);
+ bool load_state(FILEIO* state_fio);
+
+ // unique functions
+ void set_context_crtc(DEVICE* device)
+ {
+ d_crtc = device;
+ }
+ void set_chregs_ptr(uint8_t* ptr)
+ {
+ chreg = ptr;
+ }
+ void set_context_pcm(DEVICE* device)
+ {
+ d_pcm = device;
+ }
+ void set_context_main(DEVICE* device)
+ {
+ d_main = device;
+ }
+ void set_context_subcpu(DEVICE* device)
+ {
+ d_subcpu = device;
+ }
+ void set_context_keyboard(DEVICE* device)
+ {
+ d_keyboard = device;
+ }
+ void key_down(int code);
+ void key_up(int code);
+ void draw_screen();
+};
+
+#endif
// reset logical operation
cmdreg = maskreg = compbit = bankdis = 0;
- memset(compreg, sizeof(compreg), 0xff);
+ memset(compreg, 0xff, sizeof(compreg));
#endif
dma_addr_reg = dma_wrap_reg = 0;
dma_addr_mask = 0x00ffffff;
void I8237::write_signal(int id, uint32_t data, uint32_t mask)
{
if(SIG_I8237_CH0 <= id && id <= SIG_I8237_CH3) {
- uint8_t bit = 1 << (id & 3);
+ int ch = id - SIG_I8237_CH0;
+ uint8_t bit = 1 << ch;
if(data & mask) {
if(!(req & bit)) {
- write_signals(&dma[id & 3].outputs_tc, 0);
+ write_signals(&dma[ch].outputs_tc, 0);
req |= bit;
#ifndef SINGLE_MODE_DMA
do_dma();
}
} else if(SIG_I8237_BANK0 <= id && id <= SIG_I8237_BANK3) {
// external bank registers
- dma[id & 3].bankreg = data & mask;
+ int ch = id - SIG_I8237_BANK0;
+ dma[ch].bankreg = data & mask;
} else if(SIG_I8237_MASK0 <= id && id <= SIG_I8237_MASK3) {
// external bank registers
- dma[id & 3].incmask = data & mask;
+ int ch = id - SIG_I8237_MASK0;
+ dma[ch].incmask = data & mask;
}
}
#endif
}
-#define STATE_VERSION 1
+#define STATE_VERSION 2
void I8237::save_state(FILEIO* state_fio)
{
state_fio->FputUint8(tc);
state_fio->FputUint32(tmp);
state_fio->FputBool(mode_word);
+ state_fio->FputUint32(addr_mask);
}
bool I8237::load_state(FILEIO* state_fio)
tc = state_fio->FgetUint8();
tmp = state_fio->FgetUint32();
mode_word = state_fio->FgetBool();
+ addr_mask = state_fio->FgetUint32();
return true;
}
uint8_t tc;
uint32_t tmp;
bool mode_word;
+ uint32_t addr_mask;
void write_mem(uint32_t addr, uint32_t data);
uint32_t read_mem(uint32_t addr);
initialize_output_signals(&dma[i].outputs_tc);
}
mode_word = false;
+ addr_mask = 0xffffffff;
set_device_name(_T("i8237 DMAC"));
}
~I8237_BASE() {}
}
void set_context_tc1(DEVICE* device, int id, uint32_t mask)
{
- register_output_signal(&dma[0].outputs_tc, device, id, mask);
+ register_output_signal(&dma[1].outputs_tc, device, id, mask);
}
void set_context_tc2(DEVICE* device, int id, uint32_t mask)
{
- register_output_signal(&dma[0].outputs_tc, device, id, mask);
+ register_output_signal(&dma[2].outputs_tc, device, id, mask);
}
void set_context_tc3(DEVICE* device, int id, uint32_t mask)
{
- register_output_signal(&dma[0].outputs_tc, device, id, mask);
+ register_output_signal(&dma[3].outputs_tc, device, id, mask);
}
void set_mode_word(bool val)
{
mode_word = val;
}
+ void set_address_mask(uint32_t val)
+ {
+ addr_mask = val;
+ }
};
class I8237 : public I8237_BASE {
void I8237_BASE::write_mem(uint32_t addr, uint32_t data)
{
if(mode_word) {
- d_mem->write_dma_data16(addr << 1, data);
+ d_mem->write_dma_data16((addr << 1) & addr_mask, data);
} else {
- d_mem->write_dma_data8(addr, data);
+ d_mem->write_dma_data8(addr & addr_mask, data);
}
}
uint32_t I8237_BASE::read_mem(uint32_t addr)
{
if(mode_word) {
- return d_mem->read_dma_data16(addr << 1);
+ return d_mem->read_dma_data16((addr << 1) & addr_mask);
} else {
- return d_mem->read_dma_data8(addr);
+ return d_mem->read_dma_data8(addr & addr_mask);
}
}
#include "io.h"
+#define IO_ADDR_MASK (addr_max - 1)
+
+void IO::initialize()
+{
+ // allocate tables here to support multiple instances with different address range
+ if(wr_table == NULL) {
+ wr_table = (wr_bank_t *)calloc(addr_max, sizeof(wr_bank_t));
+ rd_table = (rd_bank_t *)calloc(addr_max, sizeof(rd_bank_t));
+
+ // vm->dummy must be generated first !
+ for(int i = 0; i < addr_max; i++) {
+ wr_table[i].dev = rd_table[i].dev = vm->dummy;
+ wr_table[i].addr = rd_table[i].addr = i;
+ }
+ }
+}
+
+void IO::release()
+{
+ free(wr_table);
+ free(rd_table);
+}
+
void IO::write_io8(uint32_t addr, uint32_t data)
{
write_port8(addr, data, false);
void IO::set_iomap_single_r(uint32_t addr, DEVICE* device)
{
+ IO::initialize(); // subclass may overload initialize()
+
rd_table[addr & IO_ADDR_MASK].dev = device;
rd_table[addr & IO_ADDR_MASK].addr = addr & IO_ADDR_MASK;
}
void IO::set_iomap_single_w(uint32_t addr, DEVICE* device)
{
+ IO::initialize();
+
wr_table[addr & IO_ADDR_MASK].dev = device;
wr_table[addr & IO_ADDR_MASK].addr = addr & IO_ADDR_MASK;
}
void IO::set_iomap_alias_r(uint32_t addr, DEVICE* device, uint32_t alias)
{
+ IO::initialize();
+
rd_table[addr & IO_ADDR_MASK].dev = device;
rd_table[addr & IO_ADDR_MASK].addr = alias & IO_ADDR_MASK;
}
void IO::set_iomap_alias_w(uint32_t addr, DEVICE* device, uint32_t alias)
{
+ IO::initialize();
+
wr_table[addr & IO_ADDR_MASK].dev = device;
wr_table[addr & IO_ADDR_MASK].addr = alias & IO_ADDR_MASK;
}
void IO::set_iomap_range_r(uint32_t s, uint32_t e, DEVICE* device)
{
+ IO::initialize();
+
for(uint32_t i = s; i <= e; i++) {
rd_table[i & IO_ADDR_MASK].dev = device;
rd_table[i & IO_ADDR_MASK].addr = i & IO_ADDR_MASK;
void IO::set_iomap_range_w(uint32_t s, uint32_t e, DEVICE* device)
{
+ IO::initialize();
+
for(uint32_t i = s; i <= e; i++) {
wr_table[i & IO_ADDR_MASK].dev = device;
wr_table[i & IO_ADDR_MASK].addr = i & IO_ADDR_MASK;
void IO::set_iovalue_single_r(uint32_t addr, uint32_t value)
{
+ IO::initialize();
+
rd_table[addr & IO_ADDR_MASK].value = value;
rd_table[addr & IO_ADDR_MASK].value_registered = true;
}
void IO::set_iovalue_range_r(uint32_t s, uint32_t e, uint32_t value)
{
+ IO::initialize();
+
for(uint32_t i = s; i <= e; i++) {
rd_table[i & IO_ADDR_MASK].value = value;
rd_table[i & IO_ADDR_MASK].value_registered = true;
void IO::set_flipflop_single_rw(uint32_t addr, uint32_t value)
{
+ IO::initialize();
+
wr_table[addr & IO_ADDR_MASK].is_flipflop = true;
rd_table[addr & IO_ADDR_MASK].value = value;
rd_table[addr & IO_ADDR_MASK].value_registered = true;
void IO::set_flipflop_range_rw(uint32_t s, uint32_t e, uint32_t value)
{
+ IO::initialize();
+
for(uint32_t i = s; i <= e; i++) {
wr_table[i & IO_ADDR_MASK].is_flipflop = true;
rd_table[i & IO_ADDR_MASK].value = value;
void IO::set_iowait_single_r(uint32_t addr, int wait)
{
+ IO::initialize();
+
rd_table[addr & IO_ADDR_MASK].wait = wait;
}
void IO::set_iowait_single_w(uint32_t addr, int wait)
{
+ IO::initialize();
+
wr_table[addr & IO_ADDR_MASK].wait = wait;
}
void IO::set_iowait_range_r(uint32_t s, uint32_t e, int wait)
{
+ IO::initialize();
+
for(uint32_t i = s; i <= e; i++) {
rd_table[i & IO_ADDR_MASK].wait = wait;
}
void IO::set_iowait_range_w(uint32_t s, uint32_t e, int wait)
{
+ IO::initialize();
+
for(uint32_t i = s; i <= e; i++) {
wr_table[i & IO_ADDR_MASK].wait = wait;
}
state_fio->FputUint32(STATE_VERSION);
state_fio->FputInt32(this_device_id);
- for(int i = 0; i < IO_ADDR_MAX; i++) {
+ for(int i = 0; i < addr_max; i++) {
state_fio->FputUint32(rd_table[i].value);
}
}
if(state_fio->FgetInt32() != this_device_id) {
return false;
}
- for(int i = 0; i < IO_ADDR_MAX; i++) {
+ for(int i = 0; i < addr_max; i++) {
rd_table[i].value = state_fio->FgetUint32();
}
return true;
#ifndef IO_ADDR_MAX
#define IO_ADDR_MAX 0x100
#endif
-#define IO_ADDR_MASK (IO_ADDR_MAX - 1)
class IO : public DEVICE
{
private:
// i/o map
- struct {
+ typedef struct {
DEVICE* dev;
uint32_t addr;
int wait;
bool is_flipflop;
- } wr_table[IO_ADDR_MAX];
+ } wr_bank_t;
- struct {
+ typedef struct {
DEVICE* dev;
uint32_t addr;
int wait;
bool value_registered;
uint32_t value;
- } rd_table[IO_ADDR_MAX];
+ } rd_bank_t;
+
+ wr_bank_t *wr_table;
+ rd_bank_t *rd_table;
void write_port8(uint32_t addr, uint32_t data, bool is_dma);
uint32_t read_port8(uint32_t addr, bool is_dma);
public:
IO(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
{
- memset(wr_table, 0, sizeof(wr_table));
- memset(rd_table, 0, sizeof(rd_table));
-
- // vm->dummy must be generated first !
- for(int i = 0; i < IO_ADDR_MAX; i++) {
- wr_table[i].dev = rd_table[i].dev = vm->dummy;
- wr_table[i].addr = rd_table[i].addr = i;
- }
#ifdef _IO_DEBUG_LOG
cpu_index = 0;
#endif
+ addr_max = IO_ADDR_MAX;
+
+ wr_table = NULL;
+ rd_table = NULL;
+
set_device_name(_T("Generic I/O Bus"));
}
~IO() {}
// common functions
+ void initialize();
+ void release();
void write_io8(uint32_t addr, uint32_t data);
uint32_t read_io8(uint32_t addr);
void write_io16(uint32_t addr, uint32_t data);
#ifdef _IO_DEBUG_LOG
int cpu_index;
#endif
+ int addr_max;
};
#endif
((m_status_reg & 0x02) && (m_control_reg[1] & 0x40)) ||
((m_status_reg & 0x04) && (m_control_reg[2] & 0x40));
- if (new_state != m_IRQ)
+// if (new_state != m_IRQ)
{
m_IRQ = new_state;
{
int val;
- switch ( offset & 7 )
+ offset &= 7;
+
+ switch ( offset )
{
case PTM_6840_CTRL1:
{
void MC6840::write_io8(uint32_t offset, uint32_t data)
{
- switch ( offset & 7 )
+ offset &= 7;
+
+ switch ( offset )
{
case PTM_6840_CTRL1:
case PTM_6840_CTRL2:
#include "memory.h"
-#define ADDR_MASK (MEMORY_ADDR_MAX - 1)
-#define BANK_MASK (MEMORY_BANK_SIZE - 1)
+#define ADDR_MASK (addr_max - 1)
+#define BANK_MASK (bank_size - 1)
+
+void MEMORY::initialize()
+{
+ // allocate tables here to support multiple instances with different address range
+ if(rd_table == NULL) {
+ int bank_num = addr_max / bank_size;
+
+ rd_dummy = (uint8_t *)malloc(bank_size);
+ wr_dummy = (uint8_t *)malloc(bank_size);
+
+ rd_table = (bank_t *)calloc(bank_num, sizeof(bank_t));
+ wr_table = (bank_t *)calloc(bank_num, sizeof(bank_t));
+
+ for(int i = 0; i < bank_num; i++) {
+ rd_table[i].dev = NULL;
+ rd_table[i].memory = rd_dummy;
+ rd_table[i].wait = 0;
+
+ wr_table[i].dev = NULL;
+ wr_table[i].memory = wr_dummy;
+ rd_table[i].wait = 0;
+ }
+ for(int i = 0;; i++) {
+ if(bank_size == (1 << i)) {
+ addr_shift = i;
+ break;
+ }
+ }
+ memset(rd_dummy, 0xff, bank_size);
+ }
+}
void MEMORY::release()
{
- free(read_table);
- free(write_table);
+ free(rd_table);
+ free(wr_table);
+ free(rd_dummy);
+ free(wr_dummy);
}
uint32_t MEMORY::read_data8(uint32_t addr)
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(read_table[bank].dev != NULL) {
- return read_table[bank].dev->read_memory_mapped_io8(addr);
+ if(rd_table[bank].dev != NULL) {
+ return rd_table[bank].dev->read_memory_mapped_io8(addr);
} else {
- return read_table[bank].memory[addr & BANK_MASK];
+ return rd_table[bank].memory[addr & BANK_MASK];
}
}
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(write_table[bank].dev != NULL) {
- write_table[bank].dev->write_memory_mapped_io8(addr, data);
+ if(wr_table[bank].dev != NULL) {
+ wr_table[bank].dev->write_memory_mapped_io8(addr, data);
} else {
- write_table[bank].memory[addr & BANK_MASK] = data;
+ wr_table[bank].memory[addr & BANK_MASK] = data;
}
}
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(read_table[bank].dev != NULL) {
- return read_table[bank].dev->read_memory_mapped_io16(addr);
+ if(rd_table[bank].dev != NULL) {
+ return rd_table[bank].dev->read_memory_mapped_io16(addr);
} else {
uint32_t val = read_data8(addr);
val |= read_data8(addr + 1) << 8;
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(write_table[bank].dev != NULL) {
- write_table[bank].dev->write_memory_mapped_io16(addr, data);
+ if(wr_table[bank].dev != NULL) {
+ wr_table[bank].dev->write_memory_mapped_io16(addr, data);
} else {
write_data8(addr, data & 0xff);
write_data8(addr + 1, (data >> 8) & 0xff);
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(read_table[bank].dev != NULL) {
- return read_table[bank].dev->read_memory_mapped_io32(addr);
+ if(rd_table[bank].dev != NULL) {
+ return rd_table[bank].dev->read_memory_mapped_io32(addr);
} else {
uint32_t val = read_data16(addr);
val |= read_data16(addr + 2) << 16;
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(write_table[bank].dev != NULL) {
- write_table[bank].dev->write_memory_mapped_io32(addr, data);
+ if(wr_table[bank].dev != NULL) {
+ wr_table[bank].dev->write_memory_mapped_io32(addr, data);
} else {
write_data16(addr, data & 0xffff);
write_data16(addr + 2, (data >> 16) & 0xffff);
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- *wait = read_table[bank].wait;
- if(read_table[bank].dev != NULL) {
- return read_table[bank].dev->read_memory_mapped_io8(addr);
+ *wait = rd_table[bank].wait;
+ if(rd_table[bank].dev != NULL) {
+ return rd_table[bank].dev->read_memory_mapped_io8(addr);
} else {
- return read_table[bank].memory[addr & BANK_MASK];
+ return rd_table[bank].memory[addr & BANK_MASK];
}
}
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- *wait = write_table[bank].wait;
- if(write_table[bank].dev != NULL) {
- write_table[bank].dev->write_memory_mapped_io8(addr, data);
+ *wait = wr_table[bank].wait;
+ if(wr_table[bank].dev != NULL) {
+ wr_table[bank].dev->write_memory_mapped_io8(addr, data);
} else {
- write_table[bank].memory[addr & BANK_MASK] = data;
+ wr_table[bank].memory[addr & BANK_MASK] = data;
}
}
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(read_table[bank].dev != NULL) {
-// return read_table[bank].dev->read_memory_mapped_io8(addr);
+ if(rd_table[bank].dev != NULL) {
+// return rd_table[bank].dev->read_memory_mapped_io8(addr);
return 0xff;
} else {
- return read_table[bank].memory[addr & BANK_MASK];
+ return rd_table[bank].memory[addr & BANK_MASK];
}
}
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(write_table[bank].dev != NULL) {
-// write_table[bank].dev->write_memory_mapped_io8(addr, data);
+ if(wr_table[bank].dev != NULL) {
+// wr_table[bank].dev->write_memory_mapped_io8(addr, data);
} else {
- write_table[bank].memory[addr & BANK_MASK] = data;
+ wr_table[bank].memory[addr & BANK_MASK] = data;
}
}
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(read_table[bank].dev != NULL) {
-// return read_table[bank].dev->read_memory_mapped_io16(addr);
+ if(rd_table[bank].dev != NULL) {
+// return rd_table[bank].dev->read_memory_mapped_io16(addr);
return 0xffff;
} else {
uint32_t val = read_dma_data8(addr);
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(write_table[bank].dev != NULL) {
-// write_table[bank].dev->write_memory_mapped_io16(addr, data);
+ if(wr_table[bank].dev != NULL) {
+// wr_table[bank].dev->write_memory_mapped_io16(addr, data);
} else {
write_dma_data8(addr, data & 0xff);
write_dma_data8(addr + 1, (data >> 8) & 0xff);
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(read_table[bank].dev != NULL) {
-// return read_table[bank].dev->read_memory_mapped_io32(addr);
+ if(rd_table[bank].dev != NULL) {
+// return rd_table[bank].dev->read_memory_mapped_io32(addr);
return 0xffffffff;
} else {
uint32_t val = read_dma_data16(addr);
{
int bank = (addr & ADDR_MASK) >> addr_shift;
- if(write_table[bank].dev != NULL) {
-// write_table[bank].dev->write_memory_mapped_io32(addr, data);
+ if(wr_table[bank].dev != NULL) {
+// wr_table[bank].dev->write_memory_mapped_io32(addr, data);
} else {
write_dma_data16(addr, data & 0xffff);
write_dma_data16(addr + 2, (data >> 16) & 0xffff);
void MEMORY::set_memory_r(uint32_t start, uint32_t end, uint8_t *memory)
{
+ MEMORY::initialize(); // subclass may overload initialize()
+
uint32_t start_bank = start >> addr_shift;
uint32_t end_bank = end >> addr_shift;
for(uint32_t i = start_bank; i <= end_bank; i++) {
- read_table[i].dev = NULL;
- read_table[i].memory = memory + MEMORY_BANK_SIZE * (i - start_bank);
+ rd_table[i].dev = NULL;
+ rd_table[i].memory = memory + bank_size * (i - start_bank);
}
}
void MEMORY::set_memory_w(uint32_t start, uint32_t end, uint8_t *memory)
{
+ MEMORY::initialize();
+
uint32_t start_bank = start >> addr_shift;
uint32_t end_bank = end >> addr_shift;
for(uint32_t i = start_bank; i <= end_bank; i++) {
- write_table[i].dev = NULL;
- write_table[i].memory = memory + MEMORY_BANK_SIZE * (i - start_bank);
+ wr_table[i].dev = NULL;
+ wr_table[i].memory = memory + bank_size * (i - start_bank);
}
}
void MEMORY::set_memory_mapped_io_r(uint32_t start, uint32_t end, DEVICE *device)
{
+ MEMORY::initialize();
+
uint32_t start_bank = start >> addr_shift;
uint32_t end_bank = end >> addr_shift;
for(uint32_t i = start_bank; i <= end_bank; i++) {
- read_table[i].dev = device;
+ rd_table[i].dev = device;
}
}
void MEMORY::set_memory_mapped_io_w(uint32_t start, uint32_t end, DEVICE *device)
{
+ MEMORY::initialize();
+
uint32_t start_bank = start >> addr_shift;
uint32_t end_bank = end >> addr_shift;
for(uint32_t i = start_bank; i <= end_bank; i++) {
- write_table[i].dev = device;
+ wr_table[i].dev = device;
}
}
void MEMORY::set_wait_r(uint32_t start, uint32_t end, int wait)
{
+ MEMORY::initialize();
+
uint32_t start_bank = start >> addr_shift;
uint32_t end_bank = end >> addr_shift;
for(uint32_t i = start_bank; i <= end_bank; i++) {
- read_table[i].wait = wait;
+ rd_table[i].wait = wait;
}
}
void MEMORY::set_wait_w(uint32_t start, uint32_t end, int wait)
{
+ MEMORY::initialize();
+
uint32_t start_bank = start >> addr_shift;
uint32_t end_bank = end >> addr_shift;
for(uint32_t i = start_bank; i <= end_bank; i++) {
- write_table[i].wait = wait;
+ wr_table[i].wait = wait;
}
}
void MEMORY::unset_memory_r(uint32_t start, uint32_t end)
{
+ MEMORY::initialize();
+
uint32_t start_bank = start >> addr_shift;
uint32_t end_bank = end >> addr_shift;
for(uint32_t i = start_bank; i <= end_bank; i++) {
- read_table[i].dev = NULL;
- read_table[i].memory = read_dummy;
+ rd_table[i].dev = NULL;
+ rd_table[i].memory = rd_dummy;
}
}
void MEMORY::unset_memory_w(uint32_t start, uint32_t end)
{
+ MEMORY::initialize();
+
uint32_t start_bank = start >> addr_shift;
uint32_t end_bank = end >> addr_shift;
for(uint32_t i = start_bank; i <= end_bank; i++) {
- write_table[i].dev = NULL;
- write_table[i].memory = write_dummy;
+ wr_table[i].dev = NULL;
+ wr_table[i].memory = wr_dummy;
}
}
int wait;
} bank_t;
- bank_t *read_table;
- bank_t *write_table;
+ bank_t *rd_table;
+ bank_t *wr_table;
int addr_shift;
- uint8_t read_dummy[MEMORY_BANK_SIZE];
- uint8_t write_dummy[MEMORY_BANK_SIZE];
+ uint8_t *rd_dummy;
+ uint8_t *wr_dummy;
public:
MEMORY(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
{
- int bank_num = MEMORY_ADDR_MAX / MEMORY_BANK_SIZE;
-
- read_table = (bank_t *)malloc(sizeof(bank_t) * bank_num);
- write_table = (bank_t *)malloc(sizeof(bank_t) * bank_num);
-
- for(int i = 0; i < bank_num; i++) {
- read_table[i].dev = NULL;
- read_table[i].memory = read_dummy;
- read_table[i].wait = 0;
-
- write_table[i].dev = NULL;
- write_table[i].memory = write_dummy;
- read_table[i].wait = 0;
- }
- for(int i = 0;; i++) {
- if(MEMORY_BANK_SIZE == (1 << i)) {
- addr_shift = i;
- break;
- }
- }
- memset(read_dummy, 0xff, MEMORY_BANK_SIZE);
- set_device_name(_T("GENERIC MEMORY"));
+ addr_max = MEMORY_ADDR_MAX;
+ bank_size = MEMORY_BANK_SIZE;
+
+ rd_table = wr_table = NULL;
+ rd_dummy = wr_dummy = NULL;
+
+ set_device_name(_T("Generic Memory Bus"));
}
~MEMORY() {}
// common functions
+ void initialize();
void release();
uint32_t read_data8(uint32_t addr);
void write_data8(uint32_t addr, uint32_t data);
bool write_bios(const _TCHAR *file_name, uint8_t *buffer, int size);
bool read_image(const _TCHAR *file_path, uint8_t *buffer, int size);
bool write_image(const _TCHAR *file_path, uint8_t *buffer, int size);
+
+ int addr_max;
+ int bank_size;
};
#endif
// dma ch.1: memory refresh
#if defined(SUPPORT_2HD_FDD_IF)
dma->set_context_ch2(fdc_2hd);
+ dma->set_context_tc2(fdc_2hd, SIG_UPD765A_TC, 1);
#endif
#if defined(SUPPORT_2DD_FDD_IF)
dma->set_context_ch3(fdc_2dd);
+ dma->set_context_tc3(fdc_2dd, SIG_UPD765A_TC, 1);
#endif
#if defined(SUPPORT_2HD_2DD_FDD_IF)
#if !defined(SUPPORT_HIRESO)
dma->set_context_ch2(fdc);
dma->set_context_ch3(fdc);
+ dma->set_context_tc2(fdc, SIG_UPD765A_TC, 1);
+ dma->set_context_tc3(fdc, SIG_UPD765A_TC, 1);
#else
dma->set_context_ch1(fdc);
+ dma->set_context_tc1(fdc, SIG_UPD765A_TC, 1);
#endif
#endif
// sio_rs->set_context_rxrdy(pic, SIG_I8259_CHIP0 | SIG_I8259_IR4, 1);
uint8_t UPD765A::get_devstat(int drv)
{
if(drv >= _max_drive) {
- return 0x80 | drv;
+ return ST3_FT | drv;
}
// XM8 version 1.20
if(force_ready && !disk[drv]->inserted) {
return drv;
}
- return 0x28 | drv | (fdc[drv].track ? 0 : 0x10) | ((fdc[drv].track & 1) ? 0x04 : 0) | (disk[drv]->write_protected ? 0x40 : 0);
+ return drv | ((fdc[drv].track & 1) ? ST3_HD : 0) | (disk[drv]->inserted && disk[drv]->two_side ? ST3_TS : 0) | (fdc[drv].track ? 0 : ST3_T0) | (force_ready || disk[drv]->inserted ? ST3_RY : 0) | (disk[drv]->write_protected ? ST3_WP : 0);
}
void UPD765A::cmd_seek()
#endif
continue;
}
+#ifdef _FDC_DEBUG_LOG
+ this->out_debug_log(_T("FDC: SECTOR FOUND (TRK=%d SIDE=%d ID=%2x,%2x,%2x,%2x)\n"), trk, side, id[0], id[1], id[2], id[3]);
+#endif
if(disk[drv]->sector_size.sd == 0) {
continue;
}
#include "fm7/fm7.h"
#endif
+// FUJITSU FM16beta
+#ifdef _FM16BETA
+#include "fm16beta/fm16beta.h"
+#endif
+
// FUJITSU FM16pi
#ifdef _FM16PI
#include "fm16pi/fm16pi.h"