--- /dev/null
+/*
+ TOSHIBA EX-80 Emulator 'eEX-80'
+
+ Author : Takeda.Toshiya
+ Date : 2015.12.10-
+
+ [ virtual machine ]
+*/
+
+#include "ex80bs.h"
+#include "../../emu.h"
+#include "../device.h"
+#include "../event.h"
+
+#include "../i8080.h"
+#include "../i8251.h"
+#include "../i8255.h"
+#include "../io.h"
+#include "../pcm1bit.h"
+
+#ifdef USE_DEBUGGER
+#include "../debugger.h"
+#endif
+
+#include "./cmt.h"
+#include "./display.h"
+#include "./memory.h"
+
+using EX80BS::CMT;
+using EX80BS::DISPLAY;
+using EX80BS::MEMORY;
+
+// ----------------------------------------------------------------------------
+// initialize
+// ----------------------------------------------------------------------------
+
+VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
+{
+ // create devices
+ first_device = last_device = NULL;
+ dummy = new DEVICE(this, emu); // must be 1st device
+ event = new EVENT(this, emu); // must be 2nd device
+
+ sio = new I8251(this, emu);
+ pio = new I8255(this, emu);
+ io = new IO(this, emu);
+ pcm = new PCM1BIT(this, emu);
+#ifdef USE_DEBUGGER
+// pcm->set_context_debugger(new DEBUGGER(this, emu));
+#endif
+ cpu = new I8080(this, emu);
+
+ cmt = new CMT(this, emu);
+ display = new DISPLAY(this, emu);
+ memory = new MEMORY(this, emu);
+ // Set names
+#if defined(_USE_QT)
+ dummy->set_device_name(_T("1st Dummy"));
+
+ pio->set_device_name(_T("i8255(SOUND/KEY/DISPLAY)"));
+ sio->set_device_name(_T("i8251(CMT)"));
+ pcm->set_device_name(_T("SOUND OUT"));
+#endif
+
+ // set contexts
+ event->set_context_cpu(cpu);
+ event->set_context_sound(pcm);
+
+ sio->set_context_out(cmt, SIG_CMT_OUT);
+ pio->set_context_port_c(pcm, SIG_PCM1BIT_SIGNAL, 0x08, 0);
+ pio->set_context_port_c(memory, SIG_KEYBOARD_COLUMN, 0x70, 0);
+ pio->set_context_port_c(display, SIG_DISPLAY_PC, 0x87, 0);
+
+ // Sound:: Force realtime rendering. This is temporally fix. 20161024 K.O
+ //pcm->set_realtime_render(true);
+
+ cmt->set_context_sio(sio);
+ display->set_context_cpu(cpu);
+ display->set_ram_ptr(memory->get_ram());
+ display->set_vram_ptr(memory->get_vram());
+ memory->set_context_cpu(cpu);
+ memory->set_context_pio(pio);
+
+ // cpu bus
+ cpu->set_context_mem(memory);
+ cpu->set_context_io(io);
+ cpu->set_context_intr(memory);
+#ifdef USE_DEBUGGER
+ cpu->set_context_debugger(new DEBUGGER(this, emu));
+#endif
+
+ // io bus
+ io->set_iomap_range_rw(0xdc, 0xdd, sio);
+ io->set_iomap_single_w(0xaf, memory);
+ io->set_iomap_single_r(0xef, memory);
+ io->set_iomap_range_rw(0xf8, 0xfb, pio);
+
+ // initialize all devices
+#if defined(__GIT_REPO_VERSION)
+ set_git_repo_version(__GIT_REPO_VERSION);
+#endif
+ initialize_devices();
+}
+
+VM::~VM()
+{
+ // delete all devices
+ for(DEVICE* device = first_device; device;) {
+ DEVICE *next_device = device->next_device;
+ device->release();
+ delete device;
+ device = next_device;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// drive virtual machine
+// ----------------------------------------------------------------------------
+
+
+void VM::run()
+{
+ __UNLIKELY_IF(event == nullptr) return;
+ event->drive();
+}
+
+// ----------------------------------------------------------------------------
+// debugger
+// ----------------------------------------------------------------------------
+
+#ifdef USE_DEBUGGER
+DEVICE *VM::get_cpu(int index)
+{
+ if(index == 0) {
+ return cpu;
+ }
+ return NULL;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// draw screen
+// ----------------------------------------------------------------------------
+
+void VM::draw_screen()
+{
+ __UNLIKELY_IF(display == nullptr) return;
+ display->draw_screen();
+}
+
+int VM::max_draw_ranges()
+{
+ return (config.monitor_type == 0) ? 9 : 8;
+}
+
+// ----------------------------------------------------------------------------
+// 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)
+{
+ __UNLIKELY_IF(event == nullptr) return nullptr;
+ return event->create_sound(extra_frames);
+}
+
+int VM::get_sound_buffer_ptr()
+{
+ __UNLIKELY_IF(event == nullptr) return 0;
+ 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);
+ }
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// notify key
+// ----------------------------------------------------------------------------
+
+void VM::key_down(int code, bool repeat)
+{
+ if(!repeat) {
+ memory->key_down(code);
+ }
+}
+
+void VM::key_up(int code)
+{
+}
+
+// ----------------------------------------------------------------------------
+// user interface
+// ----------------------------------------------------------------------------
+
+void VM::load_binary(int drv, const _TCHAR* file_path)
+{
+ if(drv == 0) {
+ memory->load_binary(file_path);
+ }
+}
+
+void VM::save_binary(int drv, const _TCHAR* file_path)
+{
+ if(drv == 0) {
+ memory->save_binary(file_path);
+ }
+}
+
+void VM::play_tape(int drv, const _TCHAR* file_path)
+{
+ cmt->play_tape(file_path);
+}
+
+void VM::rec_tape(int drv, const _TCHAR* file_path)
+{
+ cmt->rec_tape(file_path);
+}
+
+void VM::close_tape(int drv)
+{
+ cmt->close_tape();
+}
+
+bool VM::is_tape_inserted(int drv)
+{
+ return cmt->is_tape_inserted();
+}
+
+bool VM::is_frame_skippable()
+{
+ __UNLIKELY_IF(event == nullptr) return false;
+ return event->is_frame_skippable();
+}
+
+double VM::get_current_usec()
+{
+ __UNLIKELY_IF(event == nullptr) return 0.0;
+ return event->get_current_usec();
+}
+
+uint64_t VM::get_current_clock_uint64()
+{
+ __UNLIKELY_IF(event == nullptr) return (uint64_t)0;
+ return event->get_current_clock_uint64();
+}
+
+#define STATE_VERSION 2
+
+bool VM::process_state(FILEIO* state_fio, bool loading)
+{
+ if(!(VM_TEMPLATE::process_state_core(state_fio, loading, STATE_VERSION))) {
+ return false;
+ }
+ // Machine specified.
+ return true;
+}
+
--- /dev/null
+/*
+ TOSHIBA EX-80 Emulator 'eEX-80'
+
+ Author : Takeda.Toshiya
+ Date : 2015.12.10-
+
+ [ virtual machine ]
+*/
+
+#ifndef _EX80_BS_H_
+#define _EX80_BS_H_
+
+#define DEVICE_NAME "TOSHIBA EX-80BS"
+#define CONFIG_NAME "ex80bs"
+
+// device informations for virtual machine
+#define FRAMES_PER_SEC 59.94
+#define LINES_PER_FRAME 525
+#define CPU_CLOCKS 2048000
+#define HAS_I8080
+#define SCREEN_WIDTH 960
+#define SCREEN_HEIGHT 670
+#define MEMORY_ADDR_MAX 0x10000
+#define MEMORY_BANK_SIZE 0x400
+#define IO_ADDR_MAX 0x100
+
+// device informations for win32
+#define ONE_BOARD_MICRO_COMPUTER
+#define MAX_BUTTONS 25
+//#define MAX_DRAW_RANGES 9
+/*
+SW1 ON = STEP / OFF = AUTO
+SW2 ON = CHAR / OFF = BIT
+SW3-1/2 ON ,ON = 8000H-81FFH
+ OFF,ON = 8200H-83FFH
+ ON ,OFF = 8400H-85FFH
+ OFF,OFF = 8600H-87FFH
+*/
+#define USE_BOOT_MODE 3
+#define USE_DIPSWITCH
+#define DIPSWITCH_DEFAULT 0x0e
+#define USE_TAPE 1
+#define TAPE_BINARY_ONLY
+#define USE_BINARY_FILE 1
+#define USE_AUTO_KEY 5
+#define USE_AUTO_KEY_RELEASE 6
+#define USE_AUTO_KEY_NO_CAPS
+#define USE_MONITOR_TYPE 2
+#define USE_SOUND_VOLUME 1
+#define USE_DEBUGGER
+#define USE_STATE
+#define USE_CPU_I8080
+
+#include "../../common.h"
+#include "../../fileio.h"
+#include "../vm_template.h"
+
+#ifdef USE_SOUND_VOLUME
+static const _TCHAR *sound_device_caption[] = {
+ _T("Beep"),
+};
+#endif
+
+#define LED_WIDTH 26
+#define LED_HEIGHT 51
+#define TV_WIDTH (32 * 8 * 2 + 8)
+#define TV_HEIGHT (26 * 8 * 2 + 8)
+
+const struct {
+ int x, y;
+ int width, height;
+ int code;
+} vm_buttons[] = {
+ // virtual key codes 0x80-0x8f and 0x98-0x9f are not used in pc keyboard
+ {763 + 36 * 0, 478 + 34 * 4, 30, 21, 0x80}, // 0
+ {763 + 36 * 1, 478 + 34 * 4, 30, 21, 0x81}, // 1
+ {763 + 36 * 2, 478 + 34 * 4, 30, 21, 0x82}, // 2
+ {763 + 36 * 3, 478 + 34 * 4, 30, 21, 0x83}, // 3
+ {763 + 36 * 0, 478 + 34 * 3, 30, 21, 0x84}, // 4
+ {763 + 36 * 1, 478 + 34 * 3, 30, 21, 0x85}, // 5
+ {763 + 36 * 2, 478 + 34 * 3, 30, 21, 0x86}, // 6
+ {763 + 36 * 3, 478 + 34 * 3, 30, 21, 0x87}, // 7
+ {763 + 36 * 0, 478 + 34 * 2, 30, 21, 0x88}, // 8
+ {763 + 36 * 1, 478 + 34 * 2, 30, 21, 0x89}, // 9
+ {763 + 36 * 2, 478 + 34 * 2, 30, 21, 0x8a}, // A
+ {763 + 36 * 3, 478 + 34 * 2, 30, 21, 0x8b}, // B
+ {763 + 36 * 0, 478 + 34 * 1, 30, 21, 0x8c}, // C
+ {763 + 36 * 1, 478 + 34 * 1, 30, 21, 0x8d}, // D
+ {763 + 36 * 2, 478 + 34 * 1, 30, 21, 0x8e}, // E
+ {763 + 36 * 3, 478 + 34 * 1, 30, 21, 0x8f}, // F
+ {763 + 36 * 0, 478 + 34 * 0, 30, 21, 0x98}, // RET
+ {763 + 36 * 1, 478 + 34 * 0, 30, 21, 0x99}, // RUN
+ {763 + 36 * 2, 478 + 34 * 0, 30, 21, 0x9a}, // SDA
+ {763 + 36 * 3, 478 + 34 * 0, 30, 21, 0x9b}, // LDA
+ {763 + 36 * 4, 478 + 34 * 0, 30, 21, 0x00}, // RST
+ {763 + 36 * 4, 478 + 34 * 1, 30, 21, 0x9c}, // ADR
+ {763 + 36 * 4, 478 + 34 * 2, 30, 21, 0x9d}, // RIC
+ {763 + 36 * 4, 478 + 34 * 3, 30, 21, 0x9e}, // RDC
+ {763 + 36 * 4, 478 + 34 * 4, 30, 21, 0x9f}, // WIC
+};
+const struct {
+ int x, y;
+ int width, height;
+} vm_ranges[] = {
+ {668 + 33 * 0, 295, LED_WIDTH, LED_HEIGHT}, // 7-seg LEDs
+ {668 + 33 * 1, 295, LED_WIDTH, LED_HEIGHT},
+ {668 + 33 * 2, 295, LED_WIDTH, LED_HEIGHT},
+ {668 + 33 * 3, 295, LED_WIDTH, LED_HEIGHT},
+ {828 + 33 * 0, 295, LED_WIDTH, LED_HEIGHT},
+ {828 + 33 * 1, 295, LED_WIDTH, LED_HEIGHT},
+ {828 + 33 * 2, 295, LED_WIDTH, LED_HEIGHT},
+ {828 + 33 * 3, 295, LED_WIDTH, LED_HEIGHT},
+ {8, 8, TV_WIDTH, TV_HEIGHT}, // TV
+};
+
+//class csp_state_utils;
+class EMU;
+class DEVICE;
+class EVENT;
+
+class I8251;
+class I8255;
+class IO;
+class PCM1BIT;
+class I8080;
+
+namespace EX80BS {
+ class CMT;
+ class DISPLAY;
+ class MEMORY;
+}
+
+class VM : public VM_TEMPLATE
+{
+protected:
+ //EMU* emu;
+ //csp_state_utils *state_entry;
+ // devices
+ //EVENT* event;
+
+ I8251* sio;
+ I8255* pio;
+ IO* io;
+ PCM1BIT* pcm;
+ I8080* cpu;
+
+ EX80BS::CMT* cmt;
+ EX80BS::DISPLAY* display;
+ EX80BS::MEMORY* memory;
+
+public:
+ // ----------------------------------------
+ // initialize
+ // ----------------------------------------
+
+ VM(EMU_TEMPLATE* parent_emu);
+ ~VM();
+
+ // ----------------------------------------
+ // for emulation class
+ // ----------------------------------------
+
+ // drive virtual machine
+ //void reset();
+ void run() override;
+ double get_frame_rate() override
+ {
+ return FRAMES_PER_SEC;
+ }
+
+#ifdef USE_DEBUGGER
+ // debugger
+ DEVICE *get_cpu(int index) override;
+#endif
+
+ // draw screen
+ void draw_screen() override;
+ int max_draw_ranges() override;
+
+ // sound generation
+ void initialize_sound(int rate, int samples) override;
+ uint16_t* create_sound(int* extra_frames) override;
+ int get_sound_buffer_ptr() override;
+#ifdef USE_SOUND_VOLUME
+ void set_sound_device_volume(int ch, int decibel_l, int decibel_r) override;
+#endif
+ // notify key
+ void key_down(int code, bool repeat) override;
+ void key_up(int code) override;
+
+ // user interface
+ void load_binary(int drv, const _TCHAR* file_path) override;
+ void save_binary(int drv, const _TCHAR* file_path) override;
+ void play_tape(int drv, const _TCHAR* file_path) override;
+ void rec_tape(int drv, const _TCHAR* file_path) override;
+ void close_tape(int drv) override;
+ bool is_tape_inserted(int drv) override;
+ bool is_frame_skippable() override;
+
+ double get_current_usec() override;
+ uint64_t get_current_clock_uint64() override;
+
+ //void update_config();
+ bool process_state(FILEIO* state_fio, bool loading);
+
+ // ----------------------------------------
+ // for each device
+ // ----------------------------------------
+
+ // devices
+ //DEVICE* get_device(int id);
+ //DEVICE* dummy;
+ //DEVICE* first_device;
+ //DEVICE* last_device;
+};
+
+#endif