From 975b7886644aa4cfd2e626afe6474e51201d8526 Mon Sep 17 00:00:00 2001 From: sorgelig Date: Sun, 7 Oct 2018 16:31:31 +0800 Subject: [PATCH] Merge Sharp MZ code. --- menu.cpp | 42 +- sharpmz.cpp | 3134 +++++++++++++++++++++++++++++++++++++++++++++++++++ sharpmz.h | 469 ++++++++ user_io.cpp | 45 +- user_io.h | 2 + 5 files changed, 3690 insertions(+), 2 deletions(-) create mode 100644 sharpmz.cpp create mode 100644 sharpmz.h diff --git a/menu.cpp b/menu.cpp index 76d6679..5ff6b1e 100644 --- a/menu.cpp +++ b/menu.cpp @@ -48,6 +48,7 @@ along with this program. If not, see . #include "debug.h" #include "minimig_boot.h" #include "archie.h" +#include "sharpmz.h" #include "fpga_io.h" #include #include "cfg.h" @@ -656,6 +657,7 @@ void HandleUI(void) case CORE_TYPE_MIST: case CORE_TYPE_MINIMIG2: case CORE_TYPE_8BIT: + case CORE_TYPE_SHARPMZ: case CORE_TYPE_ARCHIE: break; @@ -807,6 +809,13 @@ void HandleUI(void) } + // SHARPMZ Series Menu - This has been located within the sharpmz.cpp code base in order to keep updates to common code + // base to a minimum and shrink its size. The UI is called with the basic state data and it handles everything internally, + // only updating values in this function as necessary. + // + if (user_io_core_type() == CORE_TYPE_SHARPMZ) + sharpmz_ui(MENU_NONE1, MENU_NONE2, MENU_8BIT_SYSTEM1, MENU_FILE_SELECT1, &parentstate, &menustate, &menusub, &menusub_last, &menumask, SelectedPath, &helptext, helptext_custom, &fs_ExtLen, &fs_Options, &fs_MenuSelect, &fs_MenuCancel, fs_pFileExt, menu, select, up, down, left, right, plus, minus); + // Switch to current menu screen switch (menustate) { @@ -1306,7 +1315,19 @@ void HandleUI(void) break; case MENU_8BIT_SYSTEM2: - if (menu) menustate = MENU_NONE1; + if (menu) + { + switch (user_io_core_type()) + { + case CORE_TYPE_SHARPMZ: + menusub = menusub_last; + menustate = sharpmz_default_ui_state(); + break; + default: + menustate = MENU_NONE1; + break; + }; + } if (select) { @@ -1359,6 +1380,11 @@ void HandleUI(void) menustate = MENU_RESET1; menusub = 1; } + else if (user_io_core_type() == CORE_TYPE_SHARPMZ) + { + menustate = sharpmz_reset_config(1); + menusub = 0; + } break; case 5: // Save settings @@ -1370,6 +1396,10 @@ void HandleUI(void) archie_save_config(); menustate = MENU_ARCHIE_MAIN1; } + else if (user_io_core_type() == CORE_TYPE_SHARPMZ) + { + menustate = sharpmz_save_config(); + } else { char *filename = user_io_create_config_name(); @@ -1417,6 +1447,10 @@ void HandleUI(void) menusub = 0; menustate = MENU_8BIT_MAIN1; break; + case CORE_TYPE_SHARPMZ: + menusub = menusub_last; + menustate = sharpmz_default_ui_state(); + break; } } @@ -2412,6 +2446,7 @@ void HandleUI(void) case MENU_RESET2: m = 0; if (user_io_core_type() == CORE_TYPE_MINIMIG2) m = 1; + if (user_io_core_type() == CORE_TYPE_SHARPMZ) m = 2; if (select && menusub == 0) { @@ -2420,6 +2455,11 @@ void HandleUI(void) menustate = MENU_NONE1; MinimigReset(); } + else if(m == 2) + { + menustate = MENU_8BIT_SYSTEM1; + sharpmz_reset_config(1); + } else { char *filename = user_io_create_config_name(); diff --git a/sharpmz.cpp b/sharpmz.cpp new file mode 100644 index 0000000..6930b31 --- /dev/null +++ b/sharpmz.cpp @@ -0,0 +1,3134 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Name: sharpmz.cpp +// Created: July 2018 +// Author(s): Philip Smart +// Description: Sharp MZ series MiSTer Menu Add-On. +// This module is an extension to the MiSTer control program. It adds extensions to +// the menu system and additional I/O control specific to the Sharp MZ series +// emulation. +// +// Credits: +// Copyright: (c) 2018 Philip Smart +// +// History: July 2018 - Initial module written. +// Sept 2018 - Synchronised with main MiSTer codebase. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "stdio.h" +#include "string.h" +#include "malloc.h" +#include +#include +#include "hardware.h" +#include "fpga_io.h" +#include "sharpmz.h" +#include "osd.h" +#include "menu.h" +#include "debug.h" +#include "user_io.h" + +#define sharpmz_debugf(a, ...) +//#define sharpmz_debugf(a, ...) printf("\033[1;31mSHARPMZ: " a "\033[0m\n", ##__VA_ARGS__) +#define sharpmz__x_debugf(a, ...) +//#define sharpmz_x_debugf(a, ...) printf("\033[1;32mSHARPMZ: " a "\033[0m\n", ##__VA_ARGS__) + +static sharpmz_config_t config; +static uint8_t sector_buffer[1024]; +static sharpmz_tape_header_t tapeHeader; +static tape_queue_t tapeQueue; + +// Method to open a file for writing. +// +int sharpmz_file_write(fileTYPE *file, const char *fileName) +{ + int ret; + char fullPath[1024]; + struct stat64 st; + + sprintf(fullPath, "%s/%s/%s", getRootDir(), SHARPMZ_CORE_NAME, fileName); + + file->mode = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRWXU | S_IRWXG | S_IRWXO; + file->type = 0; + + file->fd = open(fullPath, file->mode); + if (file->fd <= 0) + { + sharpmz_debugf("sharpmz_file_write (open) - File:%s, error: %d.\n", fullPath, file->fd); + file->fd = -1; + return 0; + } + + ret = fstat64(file->fd, &st); + if (ret < 0) + { + sharpmz_debugf("sharpmz_file_write (stat) - File:%s, error: %d.\n", fullPath, ret); + FileClose(file); + return 0; + } + + file->size = st.st_size; + file->offset = 0; + + // Success. + return 1; +} + +// Method to load a rom into the emulator. +// +void sharpmz_set_rom(romData_t &image) +{ + if(image.romEnabled) + { + sharpmz_debugf("Rom enabled: sharpmz_set_rom(%04x, %04x, %s)\n", image.loadAddr, image.loadSize, image.romFileName); + sharpmz_send_file(image, 0); + } else + { + sharpmz_debugf("Rom not enabled: sharpmz_set_rom(%04x, %04x, %s)\n", image.loadAddr, image.loadSize, image.romFileName); + } +} + +// Save current configuration to SD Card. +// +int sharpmz_save_config(void) +{ + FileSaveConfig(SHARPMZ_CONFIG_FILENAME, &config, sizeof(config)); + + // For calls from the UI, return a state to progress on to. + // + return(MENU_SHARPMZ_MAIN1); +} + +// Method to reset the emulator. +// +void sharpmz_reset(unsigned long preResetSleep, unsigned long postResetSleep) +{ + // Set the reset bit. + // + config.system_ctrl |= 1; + user_io_8bit_set_status(config.system_ctrl, (1)); + + // Sleep and hold device in reset for given period. + // + if(preResetSleep > 0) + usleep(preResetSleep); + + // Remove reset. + // + config.system_ctrl &= ~(1); + user_io_8bit_set_status(config.system_ctrl, (1)); + + // Sleep and hold device in reset for given period. + // + if(postResetSleep > 0) + usleep(postResetSleep); +} + +// Reset the configuration to inbuilt defaults. +// +int sharpmz_reset_config(short setStatus) +{ + char i; + char buf[1024]; + + // Setup config defaults. + // + config.system_ctrl = 0; + for(i=0; i < MAX_REGISTERS; i++) + { + config.system_reg[i] = 0x00; // sharpmz_read_config_register(i); + } + for(i=0; i < MAX_MZMACHINES; i++) + { + sprintf(buf, "%s_mrom.ROM", MZMACHINES[i]); + strcpy(config.romMonitor[i][MONITOR].romFileName, buf); + config.romMonitor[i][MONITOR].romEnabled = 0; + config.romMonitor[i][MONITOR].loadAddr = MZLOADADDR[MROM_IDX][i]; + config.romMonitor[i][MONITOR].loadSize = MZLOADSIZE[MROM_IDX][i]; + sprintf(buf, "%s_80c_mrom.ROM", MZMACHINES[i]); + strcpy(config.romMonitor[i][MONITOR_80C].romFileName, buf); + config.romMonitor[i][MONITOR_80C].romEnabled = 0; + config.romMonitor[i][MONITOR_80C].loadAddr = MZLOADADDR[MROM_80C_IDX][i]; + config.romMonitor[i][MONITOR_80C].loadSize = MZLOADSIZE[MROM_80C_IDX][i]; + sprintf(buf, "%s_cgrom.ROM", MZMACHINES[i]); + strcpy(config.romCG[i].romFileName, buf); + config.romCG[i].romEnabled = 0; + config.romCG[i].loadAddr = MZLOADADDR[CGROM_IDX][i]; + config.romCG[i].loadSize = MZLOADSIZE[CGROM_IDX][i]; + sprintf(buf, "%s_keymap.ROM", MZMACHINES[i]); + strcpy(config.romKeyMap[i].romFileName, buf); + config.romKeyMap[i].romEnabled = 0; + config.romKeyMap[i].loadAddr = MZLOADADDR[KEYMAP_IDX][i]; + config.romKeyMap[i].loadSize = MZLOADSIZE[KEYMAP_IDX][i]; + sprintf(buf, "%s_user.ROM", MZMACHINES[i]); + strcpy(config.romUser[i].romFileName, buf); + config.romUser[i].romEnabled = 0; + config.romUser[i].loadAddr = MZLOADADDR[USERROM_IDX][i]; + config.romUser[i].loadSize = MZLOADSIZE[USERROM_IDX][i]; + sprintf(buf, "%s_fdc.ROM", MZMACHINES[i]); + strcpy(config.romFDC[i].romFileName, buf); + config.romFDC[i].romEnabled = 0; + config.romFDC[i].loadAddr = MZLOADADDR[FDCROM_IDX][i]; + config.romFDC[i].loadSize = MZLOADSIZE[FDCROM_IDX][i]; + } + + // Set the status values. + // + if(setStatus) + { + user_io_8bit_set_status(config.system_ctrl, 0xffffffff); + + // Set the registers. + // + for(int i=0; i < MAX_REGISTERS; i++) + { + sharpmz_set_config_register(i, config.system_reg[i]); + } + } + + // For calls from the UI, return a state to progress on to. + // + return(MENU_SHARPMZ_MAIN1); +} + +// Load the configuration from the HPS. +// +int sharpmz_reload_config(short setStatus) +{ + short success = 0; + + // Try to load config from the filesystem. + // + int size = FileLoadConfig(SHARPMZ_CONFIG_FILENAME, 0, 0); + if (size > 0 && size == sizeof(sharpmz_config_t)) + { + FileLoadConfig(SHARPMZ_CONFIG_FILENAME, &config, sizeof(sharpmz_config_t)); + success = 1; + sharpmz_debugf("Config loaded successfully."); + } + else + { + sharpmz_debugf("No %s config found, creating using defaults", SHARPMZ_CONFIG_FILENAME); + sharpmz_reset_config(0); + sharpmz_save_config(); + } + + // Set the status values and control registers as requested.. + // + if(setStatus && success) + { + user_io_8bit_set_status(config.system_ctrl, 0xffffffff); + + // Set the registers. + // + for(int i=0; i < MAX_REGISTERS; i++) + { + sharpmz_set_config_register(i, config.system_reg[i]); + } + } + + // Let caller know if we succeeded to load config. + // + return(success); +} + +// Initialisation of the machine, upload roms etc. +// +void sharpmz_init(void) +{ + char i; + + sharpmz_debugf("Sharp MZ Series Initialisation"); + + // Necessary sleep to allow the reset to complete and the registers to become available. + // + usleep(50000); + + // Try and load the SD config. + // + if(sharpmz_reload_config(0) == 0) + { + // Set configuration to default in case we cannot load the file based configuration. + // + sharpmz_reset_config(0); + } + + // Setup the status values based on the config. + // + user_io_8bit_set_status(config.system_ctrl, 0xffffffff); + + // Set the control registers according to config. + // + for(int i=0; i < MAX_REGISTERS; i++) + { + sharpmz_set_config_register(i, config.system_reg[i]); + } + + // Upload defined rom files. + // + for(i=0; i < MAX_MZMACHINES; i++) + { + // Load given machine rom images at defined addresses. + // + sharpmz_set_rom(config.romMonitor[i][0]); + sharpmz_set_rom(config.romMonitor[i][1]); + sharpmz_set_rom(config.romCG[i]); + sharpmz_set_rom(config.romKeyMap[i]); + } + + // Debug, show registers. + for(i=0; i < MAX_REGISTERS; i++) + { + sharpmz_debugf("Register (%02x) = %02x", i, sharpmz_read_config_register(i)); + } + + // Initialise tape queue. + // + tapeQueue.top=tapeQueue.bottom = NULL; + tapeQueue.elements = 0; + + sharpmz_debugf("Initialisation complete."); +} + +// Poll handler, perform any periodic tasks via this hook. +// +void sharpmz_poll(void) +{ + // Locals. + static unsigned long time = GetTimer(0); + unsigned long timeElapsed; + char *fileName; + + // Get elapsed time since last poll. + // + timeElapsed = GetTimer(0) - time; + + // Every 2 seconds (READY signal takes 1 second to become active after previous load) to see if the tape buffer is empty. + // + if(timeElapsed > 2000) + { + // Check to see if the Tape READY signal is inactive, if it is and we have items in the queue, load up the next + // tape file and send it. + // + if( !((sharpmz_read_config_register(REGISTER_CMT)) & 0x01) ) + { + // Check the tape queue, if items available, pop oldest and upload. + // + if(tapeQueue.elements > 0) + { + fileName = sharpmz_pop_filename(); + if(fileName != 0) + { + sharpmz_debugf("Loading tape: %s\n", fileName); + sharpmz_load_tape_to_ram(fileName, 1); + } + } + } + + // Check to see if the RECORD_READY flag is set. + if( !((sharpmz_read_config_register(REGISTER_CMT)) & 0x04) ) + { + // Ok, so now see if the auto save feature is enabled. + // + if(config.autoSave) + { + // Save the CMT cache ram to file. The action of reading will reset the READY flag. + // + sharpmz_save_tape_from_cmt((const char *)0); + } + } + + // Reset the timer. + time = GetTimer(0); + } +} + +// Method to push a tape filename onto the queue. +// +void sharpmz_push_filename(char *fileName) +{ + // Locals. + tape_queue_node_t *ptr=(tape_queue_node_t *)malloc(sizeof(tape_queue_node_t)); + + // Copy filename into queue. + strcpy(ptr->fileName, fileName); + + // Tag onto end of queue. + ptr->next=NULL; + if (tapeQueue.top == NULL && tapeQueue.bottom == NULL) + { + tapeQueue.top=tapeQueue.bottom = ptr; + } + else + { + tapeQueue.top->next = ptr; + tapeQueue.top = ptr; + } + tapeQueue.elements++; +} + +// Method to read the oldest tape filename entered and return it. +// +char *sharpmz_pop_filename(void) +{ + // Locals. + tape_queue_node_t *ptr; + static char fileName[MAX_FILENAME_SIZE]; + + // Queue empty, just return. + if(tapeQueue.bottom == NULL) + { + return 0; + } + + // Get item in a FIFO order. + ptr=tapeQueue.bottom; + if(tapeQueue.top == tapeQueue.bottom) + { + tapeQueue.top = NULL; + } + tapeQueue.bottom = tapeQueue.bottom->next; + + // Store in static buffer and free node. + strcpy(fileName, ptr->fileName); + tapeQueue.elements--; + free(ptr); + + // Return filename. + return(fileName); +} + +// Method to iterate through the list of filenames. +// +char *sharpmz_get_next_filename(char reset) +{ + static tape_queue_node_t *ptr = NULL; + + // Queue empty, just return. + if(tapeQueue.bottom == NULL) + { + return 0; + } + + // Reset is active, start at beginning of list. + // + if(reset || ptr == NULL) + { + ptr = tapeQueue.bottom; + } else + { + // At end of list, stop. + if(ptr != NULL) + { + ptr = ptr->next; + } + } + + // Return filename if available. + // + return(ptr == NULL ? 0 : index(ptr->fileName, '/')+1); +} + +// Method to clear the queued tape list. +// +void sharpmz_clear_filelist(void) +{ + // Locals. + tape_queue_node_t *ptr; + + // Queue empty, just return. + if(tapeQueue.bottom == NULL) + { + return; + } + + // Go from bottom to top, freeing the bottom item in each iteration. + for(ptr=tapeQueue.bottom; ptr != NULL; ptr=tapeQueue.bottom) + { + tapeQueue.bottom = ptr->next; + free(ptr); + } + tapeQueue.top = NULL; + tapeQueue.elements = 0; +} + +// Return fast tape status bits. Bit 0,1 of system_reg, 0 = Off, 1 = 2x, 2 = 4x, 3 = 16x +// +int sharpmz_get_fasttape(void) +{ + return (config.system_reg[REGISTER_CMT] & 0x00000007); +} + +// Get the group to which the current machine belongs: +// 0 - MZ80K/C/A type +// 1 - MZ700 type +// 2 - MZ80B/2000 type +// +short sharpmz_get_machine_group(void) +{ + short machineModel = config.system_reg[REGISTER_MODEL] & 0x07; + short machineGroup = 0; + + // Set value according to machine model. + // + switch(machineModel) + { + // These machines currently underdevelopment, so fall through to MZ80K + case MZ80B_IDX: // MZ80B + case MZ2000_IDX: // MZ2000 + machineGroup = 2; + + case MZ80K_IDX: // MZ80K + case MZ80C_IDX: // MZ80C + case MZ1200_IDX: // MZ1200 + case MZ80A_IDX: // MZ80A + machineGroup = 0; + break; + + case MZ700_IDX: // MZ700 + case MZ800_IDX: // MZ800 + machineGroup = 1; + break; + + default: + machineGroup = 0; + break; + } + + return(machineGroup); +} + +// Return string showing Fast Tape mode. +// +const char *sharpmz_get_fasttape_string(void) +{ + short fastTape = (config.system_reg[REGISTER_CMT]) & 0x00000007; + + return(SHARPMZ_FAST_TAPE[ (sharpmz_get_machine_group() * 8) + fastTape ]); +} + +// Set fast tape status bits to given value. +// +void sharpmz_set_fasttape(short mode, short setStatus) +{ + short machineGroup = sharpmz_get_machine_group(); + + // Clear out current setting. + config.system_reg[REGISTER_CMT] &= ~0x07; + + if((machineGroup == 0 && mode > 5) || (machineGroup == 1 && mode > 5) || (machineGroup == 2 && mode > 4)) mode = 0; + config.system_reg[REGISTER_CMT] |= (mode & 0x07); + + if(setStatus) + sharpmz_set_config_register(REGISTER_CMT, config.system_reg[REGISTER_CMT]); +} + +// Return tape buttons status bits. Bit 2, 3 of system_reg, 0 = Off, 1 = Play, 2 = Record, 3 = Auto. +// +int sharpmz_get_tape_buttons(void) +{ + return ((config.system_reg[REGISTER_CMT] >> 3) & 0x00000003 ); +} + +// Return string showing tape buttons setting. +// +const char *sharpmz_get_tape_buttons_string(void) +{ + short tapeSW = (config.system_reg[REGISTER_CMT] >> 3) & 0x00000003; + + return(SHARPMZ_TAPE_BUTTONS[ tapeSW ]); +} + +// Set tape buttons status bits to given value. +// +void sharpmz_set_tape_buttons(short mode, short setStatus) +{ + config.system_reg[REGISTER_CMT] &= ~(3 << 3); + config.system_reg[REGISTER_CMT] |= (mode & 0x03) << 3; + + if(setStatus) + sharpmz_set_config_register(REGISTER_CMT, config.system_reg[REGISTER_CMT]); +} + +// Method to return the next memory bank name string in a loop sequence. +// +short sharpmz_get_next_memory_bank(void) +{ + static short memoryBank = SHARPMZ_MEMBANK_SYSROM; + + if(memoryBank == 1) memoryBank = SHARPMZ_MEMBANK_SYSRAM; // SYSROM spans 2 physical banks. + if(memoryBank >= SHARPMZ_MEMBANK_MAXBANKS) memoryBank = SHARPMZ_MEMBANK_SYSROM; // Loop round when we get to the end. + return (memoryBank++); +} + +// Return string showing memory bank name. +// +const char *sharpmz_get_memory_bank_string(short memoryBank) +{ + return(SHARPMZ_MEMORY_BANK[ memoryBank ]); +} + +// Return string showing memory bank dump file name. +// +const char *sharpmz_get_memory_bank_file(short memoryBank) +{ + return(SHARPMZ_MEMORY_BANK_FILE[ memoryBank ]); +} + +// Return display type status bits. Bit 0, 1, 2 of system_reg. +// +int sharpmz_get_display_type(void) +{ + return (config.system_reg[REGISTER_DISPLAY] & 0x00000007 ); +} + +// Return string showing Display Type. +// +const char *sharpmz_get_display_type_string(void) +{ + short displayType = (config.system_reg[REGISTER_DISPLAY]) & 0x00000007; + + return(SHARPMZ_DISPLAY_TYPE[ displayType ]); +} + +// Set display type status bits to given value. +// +void sharpmz_set_display_type(short displayType, short setStatus) +{ + // Sanity check. + if(displayType > 3) displayType = 0; + //if(displayType == 1) displayType = 3; // Skip unassigned hardware. + //if(displayType == 2) displayType = 3; + + config.system_reg[REGISTER_DISPLAY] &= ~(0x07); + config.system_reg[REGISTER_DISPLAY] |= (displayType & 0x07); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DISPLAY, config.system_reg[REGISTER_DISPLAY]); +} + +// Return aspect ratio status bits. Bit 1 of systemctrl, 0 = Off, 1 = On +// +int sharpmz_get_aspect_ratio(void) +{ + return ((config.system_ctrl & 0x00000002) != 0); +} + +// Return string showing Aspect Ratio. +// +const char *sharpmz_get_aspect_ratio_string(void) +{ + short aspectRatio = (config.system_ctrl & 0x00000002); + + return(SHARPMZ_ASPECT_RATIO[ aspectRatio ]); +} + +// Set aspect ratio status bit to given value. +// +void sharpmz_set_aspect_ratio(short on, short setStatus) +{ + config.system_ctrl &= ~(1 << 1); + config.system_ctrl |= (on == 1 ? 1 << 1 : 0); + + if(setStatus) + user_io_8bit_set_status(config.system_ctrl, (1 << 1)); +} + +// Return Scan doubler fx status bits. Bits 2,3,4 of systemctrl. +// +int sharpmz_get_scandoubler_fx(void) +{ + return ((config.system_ctrl >> 2) & 0x00000007 ); +} + +// Return string showing Scandoubler Fx mode. +// +const char *sharpmz_get_scandoubler_fx_string(void) +{ + short scandoublerFx = ((config.system_ctrl >> 2) & 0x00000007 ); + + return(SHARPMZ_SCANDOUBLER_FX[ scandoublerFx ]); +} + +// Set scan doubler status bits to given value. +// +void sharpmz_set_scandoubler_fx(short doubler, short setStatus) +{ + // Sanity check. + if(doubler > 4) doubler = 0; + + config.system_ctrl &= ~(0x07 << 2); + config.system_ctrl |= (doubler & 0x07) << 2; + + if(setStatus) + user_io_8bit_set_status(config.system_ctrl, (0x07 << 2)); +} + +// Return VRAM wait state mode status bit. Bit 6 of system_reg, 0 = Off, 1 = On +// +int sharpmz_get_vram_wait_mode(void) +{ + return ((config.system_reg[REGISTER_DISPLAY] >> 6) & 0x00000001 ); +} + +// Return string showing VRAM wait state mode. +// +const char *sharpmz_get_vram_wait_mode_string(void) +{ + short vramWaitMode = ((config.system_reg[REGISTER_DISPLAY] >> 6) & 0x00000001 ); + + return(SHARPMZ_VRAMWAIT_MODE[ vramWaitMode ]); +} + +// Set VRAM wait state mode status bit to given value. +// +void sharpmz_set_vram_wait_mode(short on, short setStatus) +{ + config.system_reg[REGISTER_DISPLAY] &= ~(1 << 6); + config.system_reg[REGISTER_DISPLAY] |= (on == 1 ? 1 << 6 : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DISPLAY, config.system_reg[REGISTER_DISPLAY]); +} + +// Return VRAM Output Disable bit. Bit 4 of system_reg, 0 = Output Enabled, 1 = Output Disabled +// +int sharpmz_get_vram_disable_mode(void) +{ + return ((config.system_reg[REGISTER_DISPLAY] >> 4) & 0x00000001 ); +} + +// Return string showing VRAM Output Disable mode. +// +const char *sharpmz_get_vram_disable_mode_string(void) +{ + short vramDisableMode = ((config.system_reg[REGISTER_DISPLAY] >> 4) & 0x00000001 ); + + return(SHARPMZ_VRAMDISABLE_MODE[ vramDisableMode ]); +} + +// Set VRAM Output Disable mode bit to given value. +// +void sharpmz_set_vram_disable_mode(short on, short setStatus) +{ + config.system_reg[REGISTER_DISPLAY] &= ~(1 << 4); + config.system_reg[REGISTER_DISPLAY] |= (on == 1 ? 1 << 4 : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DISPLAY, config.system_reg[REGISTER_DISPLAY]); +} + +// Return GRAM Output Disable bit. Bit 5 of system_reg, 0 = Output Enabled, 1 = Output Disabled +// +int sharpmz_get_gram_disable_mode(void) +{ + return ((config.system_reg[REGISTER_DISPLAY] >> 5) & 0x00000001 ); +} + +// Return string showing GRAM Output Disable mode. +// +const char *sharpmz_get_gram_disable_mode_string(void) +{ + short gramDisableMode = ((config.system_reg[REGISTER_DISPLAY] >> 5) & 0x00000001 ); + + return(SHARPMZ_GRAMDISABLE_MODE[ gramDisableMode ]); +} + +// Set GRAM Output Disable mode bit to given value. +// +void sharpmz_set_gram_disable_mode(short on, short setStatus) +{ + config.system_reg[REGISTER_DISPLAY] &= ~(1 << 5); + config.system_reg[REGISTER_DISPLAY] |= (on == 1 ? 1 << 5 : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DISPLAY, config.system_reg[REGISTER_DISPLAY]); +} + +// Return PCG mode status bit. Bit 7 of system_reg, 0 = Off, 1 = On +// +int sharpmz_get_pcg_mode(void) +{ + return ((config.system_reg[REGISTER_DISPLAY] >> 7) & 0x00000001 ); +} + +// Return string showing PCG mode. +// +const char *sharpmz_get_pcg_mode_string(void) +{ + short pcgMode = ((config.system_reg[REGISTER_DISPLAY] >> 7) & 0x00000001 ); + + return(SHARPMZ_PCG_MODE[ pcgMode ]); +} + +// Set PCG mode status bit to given value. +// +void sharpmz_set_pcg_mode(short on, short setStatus) +{ + config.system_reg[REGISTER_DISPLAY] &= ~(1 << 7); + config.system_reg[REGISTER_DISPLAY] |= (on == 1 ? 1 << 7 : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DISPLAY, config.system_reg[REGISTER_DISPLAY]); +} + +// Return machine model status bits. Bits 0,1,2 of system_reg. +// +int sharpmz_get_machine_model(void) +{ + return (config.system_reg[REGISTER_MODEL] & 0x07); +} + +// Return string showing Machine model. +// +const char *sharpmz_get_machine_model_string(short machineModel ) +{ + return(SHARPMZ_MACHINE_MODEL[ machineModel & 0x07 ]); +} + +// Return string showing Machine model. +// +const char *sharpmz_get_machine_model_string(void) +{ + short machineModel = (config.system_reg[REGISTER_MODEL]) & 0x07; + + return(SHARPMZ_MACHINE_MODEL[ machineModel ]); +} + +// Method to return the next machine model index in a loop sequence. +// +short sharpmz_get_next_machine_model(void) +{ + static short machineModel = (config.system_reg[REGISTER_MODEL]) & 0x07; + + // Certain models not yet active. + if(machineModel == MZ800_IDX || machineModel == MZ80B_IDX || machineModel == MZ2000_IDX) machineModel = MZ80K_IDX; + return (machineModel++); +} + +// Set machine model status bits to given value. +// +void sharpmz_set_machine_model(short machineModel, short setStatus) +{ + // Sanity. + // + machineModel &= 0x07; + + // When setting the model, default other settings to sensible values. + // + switch(machineModel) + { + // These machines currently underdevelopment, so fall through to MZ80K + case MZ800_IDX: // MZ800 + case MZ80B_IDX: // MZ80B + case MZ2000_IDX: // MZ2000 + machineModel = 0; + + case MZ80K_IDX: // MZ80K + case MZ80C_IDX: // MZ80C + case MZ1200_IDX: // MZ1200 + case MZ80A_IDX: // MZ80A + //sharpmz_set_fasttape(0x00, 1); // No. + sharpmz_set_display_type(0x00, 0); // Normal display + //sharpmz_set_pcg_mode(0x00, 1); // ROM + //sharpmz_set_scandoubler_fx(0x00, 1);// None. + sharpmz_set_cpu_speed(0x00, 1); // 2MHz MZ80C, 3.5MHz MZ700 + break; + + case MZ700_IDX: // MZ700 + //sharpmz_set_fasttape(0x00, 1); // No. + sharpmz_set_display_type(0x02, 0); // Colour display + //sharpmz_set_pcg_mode(0x00, 1); // ROM sharpmz_set_scandoubler_fx(0x00, 0);// None. + //sharpmz_set_scandoubler_fx(0x00, 1);// None. + sharpmz_set_cpu_speed(0x00, 0); // 2MHz MZ80C, 3.5MHz MZ700 + break; + } + + // Set the machine model. + config.system_reg[REGISTER_MODEL] &= ~(0x07); + config.system_reg[REGISTER_MODEL] |= (machineModel); + + if(setStatus) + sharpmz_set_config_register(REGISTER_MODEL, config.system_reg[REGISTER_MODEL]); +} + +// Return string showing CPU speed for display. +// +const char *sharpmz_get_cpu_speed_string(void) +{ + short cpuSet = (config.system_reg[REGISTER_CPU]) & 0x00000007; + + return(SHARPMZ_CPU_SPEED[ (sharpmz_get_machine_group() * 8) + cpuSet ]); +} + +// Return cpu speed status bits. Bits 0, 1 of system_reg. +// +int sharpmz_get_cpu_speed(void) +{ + return ((config.system_reg[REGISTER_CPU]) & 0x00000007); +} + +// Set cpu speed status bits to given value. +// +void sharpmz_set_cpu_speed(short cpuSpeed, short setStatus) +{ + short machineGroup = sharpmz_get_machine_group(); + + // Clear current setting. + config.system_reg[REGISTER_CPU] &= ~(0x07); + + if((machineGroup == 0 && cpuSpeed > 5) || (machineGroup == 1 && cpuSpeed > 5) || (machineGroup == 2 && cpuSpeed > 4)) cpuSpeed = 0; + config.system_reg[REGISTER_CPU] |= (cpuSpeed & 0x07); + + if(setStatus) + sharpmz_set_config_register(REGISTER_CPU, config.system_reg[REGISTER_CPU]); +} + +// Return audio source status bit. Bit 0 of system_reg, 0 = sound, 1 = tape +// +int sharpmz_get_audio_source(void) +{ + return ((config.system_reg[REGISTER_AUDIO]) & 0x00000001); +} + +// Return string showing Audio source. +// +const char *sharpmz_get_audio_source_string(void) +{ + short audioSource = ((config.system_reg[REGISTER_AUDIO]) & 0x00000001); + + return(SHARPMZ_AUDIO_SOURCE[ audioSource ]); +} + +// Set audio source status bit to given value. +// +void sharpmz_set_audio_source(short on, short setStatus) +{ + config.system_reg[REGISTER_AUDIO] &= ~(1); + config.system_reg[REGISTER_AUDIO] |= (on == 1 ? 1 : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_AUDIO, config.system_reg[REGISTER_AUDIO]); +} + +// Return audio volume setting. The value is inverse, ie. it is an attenuation, 15 is highest, 0 is off. +// +int sharpmz_get_audio_volume(void) +{ + return ((config.volume) & 0x0f); +} + +// Return string showing Audio volume setting - this is inversed. +// +const char *sharpmz_get_audio_volume_string(void) +{ + return(SHARPMZ_AUDIO_VOLUME[ config.volume & 0x0f ]); +} + +// Set audio volume level. 15 = high attenuation, 0 = no attenuation. +// +void sharpmz_set_audio_volume(short volume, short setStatus) +{ + config.volume &= 0x10; + config.volume |= volume & 0x0f; + + if(setStatus) + spi_uio_cmd8(UIO_AUDVOL, config.volume); +} + +// Return audio mute setting. +// +int sharpmz_get_audio_mute(void) +{ + return ((config.volume & 0x10) >> 4); +} + +// Return string showing Audio mute setting. +// +const char *sharpmz_get_audio_mute_string(void) +{ + return(SHARPMZ_AUDIO_MUTE[ (config.volume & 0x10) >> 4 ]); +} + +// Set audio mute level. +// +void sharpmz_set_audio_mute(short mute, short setStatus) +{ + config.volume &= 0x0f; + config.volume |= mute << 4; + + if(setStatus) + spi_uio_cmd8(UIO_AUDVOL, config.volume); +} + +// Return debug enable status bit. Bit 7 of system_reg, 0 = Off, 1 = On +// +int sharpmz_get_debug_enable(void) +{ + return ((config.system_reg[REGISTER_DEBUG] >> 7) & 0x00000001); +} + +// Return string showing Debug Enable mode. +// +const char *sharpmz_get_debug_enable_string(void) +{ + short debugEnable = ((config.system_reg[REGISTER_DEBUG] >> 7) & 0x00000001); + + return(SHARPMZ_DEBUG_ENABLE[ debugEnable ]); +} + +// Set debug enable status bit to given value. +// +void sharpmz_set_debug_enable(short on, short setStatus) +{ + config.system_reg[REGISTER_DEBUG] &= ~(1 << 7); + config.system_reg[REGISTER_DEBUG] |= (on == 1 ? 1 << 7 : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DEBUG, config.system_reg[REGISTER_DEBUG]); +} + +// Return debug leds status bit. Bit 6 of system_reg, 0 = Off, 1 = On +// +int sharpmz_get_debug_leds(void) +{ + return ((config.system_reg[REGISTER_DEBUG] >> 6) & 0x00000001); +} + +// Return string showing Debug Leds. +// +const char *sharpmz_get_debug_leds_string(void) +{ + short debugLeds = ((config.system_reg[REGISTER_DEBUG] >> 6) & 0x00000001); + + return(SHARPMZ_DEBUG_LEDS[ debugLeds ]); +} + +// Set debug leds status bit to given value. +// +void sharpmz_set_debug_leds(short on, short setStatus) +{ + config.system_reg[REGISTER_DEBUG] &= ~(1 << 6); + config.system_reg[REGISTER_DEBUG] |= (on == 1 ? 1 << 6 : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DEBUG, config.system_reg[REGISTER_DEBUG]); +} + +// Method to return the next debug bank index in a loop sequence. +// +short sharpmz_get_next_debug_leds_bank(void) +{ + static short debugLedsBank = (config.system_reg[REGISTER_DEBUG] & 0x00000007); + + // Certain models not yet active. + if(strcmp(SHARPMZ_DEBUG_LEDS_BANK[ debugLedsBank ], "") == 0) debugLedsBank = 0; + + return (debugLedsBank++); +} + +// Return string showing debug led bank. +// +const char *sharpmz_get_debug_leds_bank_string(void) +{ + short debugLedsBank = (config.system_reg[REGISTER_DEBUG] & 0x00000007); + + return(SHARPMZ_DEBUG_LEDS_BANK[ debugLedsBank ]); +} + +// Set debug LEDS bank index. +// +void sharpmz_set_debug_leds_bank(short debugLedsBank, short setStatus) +{ + // Sanity check. + if(debugLedsBank > 7) debugLedsBank = 0; + + config.system_reg[REGISTER_DEBUG] &= ~(0x07); + config.system_reg[REGISTER_DEBUG] |= (debugLedsBank & 0x07); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DEBUG, config.system_reg[REGISTER_DEBUG]); +} + +// Method to return the next debug sub-bank index in a loop sequence. +// +short sharpmz_get_next_debug_leds_subbank(unsigned char reset) +{ + static short debugLedsSubBank = ((config.system_reg[REGISTER_DEBUG] >> 3) & 0x00000007); + short debugLedsBank = (config.system_reg[REGISTER_DEBUG] & 0x00000007); + + // Limit choice according to number of subbanks and subbanks setup. + if(reset || debugLedsSubBank > 7) debugLedsSubBank = 0; + if(strcmp(SHARPMZ_DEBUG_LEDS_SUBBANK[ (debugLedsBank * 8) + debugLedsSubBank ], "") == 0) debugLedsSubBank = 0; + return (debugLedsSubBank++); +} + +// Return string showing debug led sub-bank. +// +const char *sharpmz_get_debug_leds_subbank_string(void) +{ + short debugLedsBank = (config.system_reg[REGISTER_DEBUG] & 0x00000007); + short debugLedsSubBank = ((config.system_reg[REGISTER_DEBUG] >> 3) & 0x00000007); + + return(SHARPMZ_DEBUG_LEDS_SUBBANK[ (debugLedsBank * 8) + debugLedsSubBank ]); +} + +// Set debug LEDS sub-bank index. +// +void sharpmz_set_debug_leds_subbank(short debugLedsSubBank, short setStatus) +{ + // Sanity check. + if(debugLedsSubBank > 7) debugLedsSubBank = 0; + + config.system_reg[REGISTER_DEBUG] &= ~(0x07 << 3); + config.system_reg[REGISTER_DEBUG] |= ((debugLedsSubBank & 0x07) << 3); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DEBUG, config.system_reg[REGISTER_DEBUG]); +} + +// Method to return the next debug cpu frequency index in a loop sequence. +// +short sharpmz_get_next_debug_cpufreq(void) +{ + static short debugCPUFrequency = ((config.system_reg[REGISTER_DEBUG2] >> 4) & 0x0000000f); + + // Sanity check. + if(debugCPUFrequency > 15) debugCPUFrequency = 0; + + return (debugCPUFrequency++); +} + +// Return string showing debug cpu frequency. +// +const char *sharpmz_get_debug_cpufreq_string(void) +{ + short debugCPUFrequency = ((config.system_reg[REGISTER_DEBUG2] >> 4) & 0x0000000f); + + return(SHARPMZ_DEBUG_CPUFREQ[ debugCPUFrequency ]); +} + +// Set debug cpu frequency index. +// +void sharpmz_set_debug_cpufreq(short debugCPUFrequency, short setStatus) +{ + // Sanity check. + if(debugCPUFrequency > 15) debugCPUFrequency = 0; + + config.system_reg[REGISTER_DEBUG2] &= ~(0x0f << 4); + config.system_reg[REGISTER_DEBUG2] |= ((debugCPUFrequency & 0x0f) << 4); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DEBUG2, config.system_reg[REGISTER_DEBUG2]); +} + +// Method to return the next debug sample frequency index in a loop sequence. +// +short sharpmz_get_next_debug_leds_smpfreq(void) +{ + static short debugLedsSampleFrequency = (config.system_reg[REGISTER_DEBUG2] & 0x0000000f); + + // Sanity check. + if(debugLedsSampleFrequency > 15) debugLedsSampleFrequency = 0; + + return (debugLedsSampleFrequency++); +} + +// Return string showing debug led sample frequency. +// +const char *sharpmz_get_debug_leds_smpfreq_string(void) +{ + short debugLedsSampleFrequency = (config.system_reg[REGISTER_DEBUG2] & 0x0000000f); + + return(SHARPMZ_DEBUG_LEDS_SMPFREQ[ debugLedsSampleFrequency ]); +} + +// Set debug LEDS sample frequency index. +// +void sharpmz_set_debug_leds_smpfreq(short debugLedsSampleFrequency, short setStatus) +{ + // Sanity check. + if(debugLedsSampleFrequency > 15) debugLedsSampleFrequency = 0; + + config.system_reg[REGISTER_DEBUG2] &= ~(0x0f); + config.system_reg[REGISTER_DEBUG2] |= (debugLedsSampleFrequency & 0x0f); + + if(setStatus) + sharpmz_set_config_register(REGISTER_DEBUG2, config.system_reg[REGISTER_DEBUG2]); +} + +// Return string showing auto save enabled mode. +// +const char *sharpmz_get_auto_save_enabled_string(void) +{ + return(SHARPMZ_AUTO_SAVE_ENABLED[ config.autoSave ]); +} + +// Method to return the enabled state of auto save. +// +unsigned char sharpmz_get_auto_save_enabled(void) +{ + return(config.autoSave); +} + +// Method to set the auto save flag to determine if automatic saving of incoming tape data is enabled. +// +void sharpmz_set_auto_save_enabled(unsigned char on) +{ + config.autoSave = on; +} + +// Method to return the enabled state of a user rom for given machine. +// +short sharpmz_get_user_rom_enabled(short machineModel) +{ + return ((config.system_reg[REGISTER_USERROM] >> machineModel) & 0x00000001); +} + +// Return string showing user rom enabled status. +// +const char *sharpmz_get_user_rom_enabled_string(short machineModel) +{ + short userRomEnabled = ((config.system_reg[REGISTER_USERROM] >> machineModel) & 0x00000001); + + return(SHARPMZ_USERROM_ENABLED[ userRomEnabled ]); +} + +// Method to set the enabled state of a user rom for a given machine. +// +void sharpmz_set_user_rom_enabled(short machineModel, short on, short setStatus) +{ + config.system_reg[REGISTER_USERROM] &= ~(1 << machineModel); + config.system_reg[REGISTER_USERROM] |= (on == 1 ? 1 << machineModel : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_USERROM, config.system_reg[REGISTER_USERROM]); +} + +// Method to return the enabled state of a fdc rom for given machine. +// +short sharpmz_get_fdc_rom_enabled(short machineModel) +{ + return ((config.system_reg[REGISTER_FDCROM] >> machineModel) & 0x00000001); +} + +// Return string showing fdc rom enabled status. +// +const char *sharpmz_get_fdc_rom_enabled_string(short machineModel) +{ + short fdcRomEnabled = ((config.system_reg[REGISTER_FDCROM] >> machineModel) & 0x00000001); + + return(SHARPMZ_FDCROM_ENABLED[ fdcRomEnabled ]); +} + +// Method to set the enabled state of a fdc rom for a given machine. +// +void sharpmz_set_fdc_rom_enabled(short machineModel, short on, short setStatus) +{ + config.system_reg[REGISTER_FDCROM] &= ~(1 << machineModel); + config.system_reg[REGISTER_FDCROM] |= (on == 1 ? 1 << machineModel : 0); + + if(setStatus) + sharpmz_set_config_register(REGISTER_FDCROM, config.system_reg[REGISTER_FDCROM]); +} + +// Method to return the enabled state of a rom for loading. +// +short sharpmz_get_custom_rom_enabled(short machineModel, short romType) +{ + short romEnabled; + + machineModel &= 0x07; + romType &= 0x07; + switch(romType) + { + case MROM_IDX: + romEnabled = config.romMonitor[machineModel][MONITOR].romEnabled; + break; + + case MROM_80C_IDX: + romEnabled = config.romMonitor[machineModel][MONITOR_80C].romEnabled; + break; + + case CGROM_IDX: + romEnabled = config.romCG[machineModel].romEnabled; + break; + + case KEYMAP_IDX: + romEnabled = config.romKeyMap[machineModel].romEnabled; + break; + + case USERROM_IDX: + romEnabled = config.romUser[machineModel].romEnabled; + break; + + case FDCROM_IDX: + romEnabled = config.romFDC[machineModel].romEnabled; + break; + + default: + sharpmz_debugf("Unknown get enabled romType: %d\n", romType); + break; + } + return(romEnabled); +} + +// Return string showing rom enabled mode. +// +const char *sharpmz_get_custom_rom_enabled_string(short romEnabled) +{ + return(SHARPMZ_ROM_ENABLED[ romEnabled ]); +} + +// Method to set the enabled state of a rom for loading. +// +void sharpmz_set_custom_rom_enabled(short machineModel, short romType, short on) +{ + machineModel &= 0x07; + romType &= 0x07; + switch(romType) + { + case MROM_IDX: + config.romMonitor[machineModel][MONITOR].romEnabled = (on == 1); + break; + + case MROM_80C_IDX: + config.romMonitor[machineModel][MONITOR_80C].romEnabled = (on == 1); + break; + + case CGROM_IDX: + config.romCG[machineModel].romEnabled = (on == 1); + break; + + case KEYMAP_IDX: + config.romKeyMap[machineModel].romEnabled = (on == 1); + break; + + case USERROM_IDX: + config.romUser[machineModel].romEnabled = (on == 1); + break; + + case FDCROM_IDX: + config.romFDC[machineModel].romEnabled = (on == 1); + break; + + default: + sharpmz_debugf("Unknown set enabled romType: %d\n", romType); + break; + } +} + +// Method to return the filename of a rom. +// +char *sharpmz_get_rom_file(short machineModel, short romType) +{ + machineModel &= 0x07; + romType &= 0x07; + switch(romType) + { + case MROM_IDX: + return(config.romMonitor[machineModel][MONITOR].romFileName); + + case MROM_80C_IDX: + return(config.romMonitor[machineModel][MONITOR_80C].romFileName); + + case CGROM_IDX: + return(config.romCG[machineModel].romFileName); + + case KEYMAP_IDX: + return(config.romKeyMap[machineModel].romFileName); + + case USERROM_IDX: + return(config.romUser[machineModel].romFileName); + + case FDCROM_IDX: + return(config.romFDC[machineModel].romFileName); + + default: + sharpmz_debugf("Unknown get filename romType: %d\n", romType); + break; + } + return(NULL); +} + +// Method to set the filename of a rom. +// +void sharpmz_set_rom_file(short machineModel, short romType, char *filename) +{ + machineModel &= 0x07; + romType &= 0x03; + switch(romType) + { + case MROM_IDX: + strcpy(config.romMonitor[machineModel][MONITOR].romFileName, filename); + sharpmz_debugf("Copy MROM:%s, %s\n", filename,config.romMonitor[machineModel][MONITOR].romFileName ); + break; + + case MROM_80C_IDX: + strcpy(config.romMonitor[machineModel][MONITOR_80C].romFileName, filename); + sharpmz_debugf("Copy MROM (80x25):%s, %s\n", filename,config.romMonitor[machineModel][MONITOR_80C].romFileName ); + break; + + case CGROM_IDX: + strcpy(config.romCG[machineModel].romFileName, filename); + sharpmz_debugf("Copy CGROM:%s, %s\n", filename,config.romCG[machineModel].romFileName ); + break; + + case KEYMAP_IDX: + strcpy(config.romKeyMap[machineModel].romFileName, filename); + sharpmz_debugf("Copy KEYROM:%s, %s\n", filename,config.romKeyMap[machineModel].romFileName ); + break; + + case USERROM_IDX: + strcpy(config.romUser[machineModel].romFileName, filename); + sharpmz_debugf("Copy USERROM:%s, %s\n", filename,config.romUser[machineModel].romFileName ); + break; + + case FDCROM_IDX: + strcpy(config.romFDC[machineModel].romFileName, filename); + sharpmz_debugf("Copy FDCROM:%s, %s\n", filename,config.romFDC[machineModel].romFileName ); + break; + + default: + sharpmz_debugf("Unknown set filename romType: %d, filename:%s\n", romType, filename); + break; + } +} + +// Return string showing last Tape type read. +// +const char *sharpmz_get_tape_type_string(void) +{ + return(SHARPMZ_TAPE_TYPE[ tapeHeader.dataType ]); +} + +// Method to get the header of the last tape loaded. +// +sharpmz_tape_header_t *sharpmz_get_tape_header(void) +{ + return(&tapeHeader); +} + +// Local version of File Read so that we can read exact number of bytes required +// and return parameter specifies number of bytes actually read. +// +int sharpmz_file_read(fileTYPE *file, void *pBuffer, int nSize) +{ + if (!FileSeek(file, file->offset, SEEK_SET)) + { + sharpmz_debugf("file_read error(seek).\n"); + return 0; + } + + int ret = read(file->fd, pBuffer, nSize); + if (ret < 0) + { + sharpmz_debugf("file_read error(%d).\n", ret); + return 0; + } + + return ret; +} + +// Method to program a config register in the emulator. +// +void sharpmz_set_config_register(short addr, unsigned char value) +{ + EnableFpga(); + spi8(SHARPMZ_CONFIG_TX); + spi8(addr); // Address of register to change. + spi8(value); // Value to set in the register. + sharpmz_debugf("Register Set(%02x) -> %02x\n", addr, value); + DisableFpga(); + + for(int i=0; i < MAX_REGISTERS; i++) + { + sharpmz_debugf("%02x => %02x, ", i, sharpmz_read_config_register(i)); + } + sharpmz_debugf("\n"); + //sharpmz_read_config_register(addr); +} + +// Method to read a config register in the emulator. +// +unsigned char sharpmz_read_config_register(short addr) +{ + unsigned char value; + + EnableFpga(); + spi8(SHARPMZ_CONFIG_RX); + spi8(addr); // Address of register to change. + spi8(0x00); + value = spi_b(0x00); // Padding to give a cycle to allow data to be read. + //sharpmz_debugf("Register Read(%02x)=%02x\n", addr, value); + DisableFpga(); + + // Return the value stored in the config register. + return(value); +} + +// Method to send a file to the emulator. +// +void sharpmz_send_file(romData_t &image, char *dirPrefix) +{ + char sendFile[1024]; + unsigned int actualReadSize; + unsigned long time = GetTimer(0); + unsigned short i; + fileTYPE file = { 0 }; + + // If a prefix is given (ie. core directory), prepend it before use. + // + if(dirPrefix) + { + strcpy(sendFile, dirPrefix); + strcat(sendFile, "/"); + strcat(sendFile, image.romFileName); + } else + { + strcpy(sendFile, SHARPMZ_CORE_NAME); + strcat(sendFile, "/"); + strcat(sendFile, image.romFileName); + } + + sharpmz_debugf("Sending file:%s", sendFile); + + // Try and open the given file, exit on failure. + if (!FileOpen(&file, sendFile)) return; + + // Prepare transmission of new file. + EnableFpga(); + spi8(SHARPMZ_FILE_ADDR_TX); + spi8(0x00); + spi8(image.loadAddr >> 16); // Indicate we are uploading rom images into the correct ROM section of the memory. + spi8((image.loadAddr >> 8) & 0xff); // MSB of the rom image. + spi8(image.loadAddr&0xff); // LSB of the rom image. + sharpmz_debugf("Load Address:%04x, %04x, %04x\n", image.loadAddr, image.loadAddr >> 8, image.loadSize); + + // Limit size to that governed in the config. If the rom is larger than the defined size, waste additional data, + // if less then finish early. Prevents large images from corrupting other machine roms. + // + sharpmz_debugf("["); + for (i = 0; i < image.loadSize; i += actualReadSize) + { + if (!(i & 127)) sharpmz_debugf("*"); + + // Work out size of data block to read. + int readSize = (image.loadSize - i >= 512 ? 512 : image.loadSize - i); + + // Perform the read. + DISKLED_ON; + actualReadSize = sharpmz_file_read(&file, sector_buffer, readSize); + DISKLED_OFF; + + // If we encountered an error, then bad file or eof, so exit. + // + if(actualReadSize != 0) + { + spi_write(sector_buffer, actualReadSize, 0); + + // Still bytes to send, then read next sector. + if (actualReadSize == 512) FileNextSector(&file); + } else + { + // End of file, short file, so just move onto end. + actualReadSize = image.loadSize -i; + } + } + DisableFpga(); + sharpmz_debugf("]\n"); + + // Tidy up. + FileClose(&file); + + // For debug, display time it took to upload. + time = GetTimer(0) - time; + sharpmz_debugf("Uploaded in %lu ms", time >> 20); + + // signal end of transmission + EnableFpga(); + spi8(SHARPMZ_FILE_TX); + spi8(SHARPMZ_EOF); + DisableFpga(); +} + +// Method to read the emulator memory. Either a specific bank is given or all banks via the parameter bank. +// +short sharpmz_read_ram(const char *memDumpFile, short bank) +{ + unsigned int actualWriteSize; + fileTYPE file = { 0 }; + + // Open the memory image debug file for writing. + if (!sharpmz_file_write(&file, memDumpFile)) + { + sharpmz_debugf("Failed to open ram dump file:%s\n", memDumpFile); + return(3); + } + + // Depending on the bank, or all banks, loop until request is complete. + // + for(unsigned int mb=(bank == SHARPMZ_MEMBANK_ALL ? 0 : bank); mb <= (bank == SHARPMZ_MEMBANK_ALL ? SHARPMZ_MEMBANK_MAXBANKS-1 : bank); mb++) + { + // Skip bank 1, as SYSROM spans two physical banks 0 and 1. + if(mb == 1) mb = SHARPMZ_MEMBANK_SYSRAM; + + EnableFpga(); // Setup the load address. + spi8(SHARPMZ_FILE_ADDR_RX); + spi8(0x00); + spi8(mb); // Memory bank to read. + spi8(0x00); // A15-A8 + spi8(0x00); // A7-A0 + //spi8(0x00); // Setup to read addr first byte. + + // The bank size is stored in the config. + // + sharpmz_debugf("["); + for (unsigned long j = 0; j < MZBANKSIZE[mb] or actualWriteSize == 0; j += actualWriteSize) + { + if (!(j & 127)) sharpmz_debugf("*"); + + spi_read(sector_buffer, 512, 0); + + DISKLED_ON; + actualWriteSize=FileWriteAdv(&file, sector_buffer, 512); + DISKLED_OFF; + } + sharpmz_debugf("]\n"); + + // Indicate end of upload. + spi8(SHARPMZ_EOF); + DisableFpga(); + } + + // Close file to complete dump. + FileClose(&file); + + // Success. + // + return(0); +} + +// Method to read the header of a tape. +// Useful for decision making prior to load. +// +short sharpmz_read_tape_header(const char *tapeFile) +{ + unsigned int actualReadSize; + + //sharpmz_debugf("Sending tape file:%s to emulator ram", tapeFile); + + // Handle for the MZF file to be processed. + // + fileTYPE file = { 0 }; + + // Try and open the tape file, exit if it cannot be opened. + // + if (!FileOpen(&file, tapeFile)) return(1); + + // Read in the tape header, this indicates crucial data such as data type, size, exec address, load address etc. + // + actualReadSize = sharpmz_file_read(&file, &tapeHeader, 128); + if(actualReadSize != 128) + { + sharpmz_debugf("Only read:%d bytes of header, aborting.\n", actualReadSize); + return(1); + } + + // Some sanity checks. + // + if(tapeHeader.dataType == 0 || tapeHeader.dataType > 5) return(4); + + // Success. + return(0); +} + +// Method to load a tape (MZF) file directly into RAM. +// This involves reading the tape header, extracting the size and destination and loading +// the header and program into emulator ram. +// +short sharpmz_load_tape_to_ram(const char *tapeFile, unsigned char dstCMT) +{ + unsigned int actualReadSize; + unsigned long time = GetTimer(0); + char fileName[17]; + + //sharpmz_debugf("Sending tape file:%s to emulator ram", tapeFile); + + // Handle for the MZF file to be processed. + // + fileTYPE file = { 0 }; + + // Try and open the tape file, exit if it cannot be opened. + // + if (!FileOpen(&file, tapeFile)) return(1); + + // Read in the tape header, this indicates crucial data such as data type, size, exec address, load address etc. + // + actualReadSize = sharpmz_file_read(&file, &tapeHeader, 128); + if(actualReadSize != 128) + { + sharpmz_debugf("Only read:%d bytes of header, aborting.\n", actualReadSize); + return(2); + } + + // Some sanity checks. + // + if(tapeHeader.dataType == 0 || tapeHeader.dataType > 5) return(4); + for(int i=0; i < 17; i++) + { + fileName[i] = tapeHeader.fileName[i] == 0x0d ? 0x00 : tapeHeader.fileName[i]; + } + + // Debug output to indicate the file loaded and information about the tape image. + // + switch(tapeHeader.dataType) + { + case 0x01: + sharpmz_debugf("Binary File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s, StackLow=%04x, StackHigh=%04x)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName, MZ_TAPE_HEADER_STACK_ADDR & 0xff, (MZ_TAPE_HEADER_STACK_ADDR >> 8) & 0xff); + break; + + case 0x02: + sharpmz_debugf("MZ-80 Basic Program(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + break; + + case 0x03: + sharpmz_debugf("MZ-80 Data File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + break; + + case 0x04: + sharpmz_debugf("MZ-700 Data File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + break; + + case 0x05: + sharpmz_debugf("MZ-700 Basic Program(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + break; + + default: + sharpmz_debugf("Unknown tape type(Type=%02x, Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.dataType, tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + break; + } + + // Check the data type, only load machine code. + // + if(dstCMT == 0 && tapeHeader.dataType != SHARPMZ_CMT_MC) + return(3); + + // Reset Emulator if loading direct to RAM. This clears out memory, resets monitor and places it in a known state. + // + if(dstCMT == 0) + sharpmz_reset(10, 50000); + + // Load the data from tape to RAM. + // + EnableFpga(); // Start the transmission session, clear address and set ioctl_download. + spi8(SHARPMZ_FILE_ADDR_TX); + spi8(0x00); + if(dstCMT == 0) // Load to emulators RAM + { + spi8(SHARPMZ_MEMBANK_SYSRAM); + spi8((tapeHeader.loadAddress >> 8)&0xff); + spi8(tapeHeader.loadAddress & 0xff); // Location set inside tape header structure. + } else + { + spi8(SHARPMZ_MEMBANK_CMT_DATA); + spi8(0x00); + spi8(0x00); + } + + sharpmz_debugf("["); + for (unsigned short i = 0; i < tapeHeader.fileSize; i += actualReadSize) + { + if (!(i & 127)) sharpmz_debugf("*"); + + DISKLED_ON; + actualReadSize = sharpmz_file_read(&file, sector_buffer, 512); + DISKLED_OFF; + + // First sector contains the header which has already been written, so just write the remainder. + // + if(i == 0) + { + actualReadSize -= MZ_TAPE_HEADER_SIZE; + memmove(sector_buffer, sector_buffer+MZ_TAPE_HEADER_SIZE, actualReadSize); + } + //sharpmz_debugf("Bytes to read, actual:%d, index:%d, sizeHeader:%d", actualReadSize, i, tapeHeader.fileSize); + if(actualReadSize > 0) + { + // Write the sector (or part) to the fpga memory. + spi_write(sector_buffer, actualReadSize, 0); + + // Move onto next sector of file. + FileNextSector(&file); + } + } + sharpmz_debugf("]\n"); + DisableFpga(); + + // signal end of transmission + EnableFpga(); + spi8(SHARPMZ_FILE_TX); + spi8(SHARPMZ_EOF); + DisableFpga(); + + // Now load header - this is done last because the emulator monitor wipes the stack area on reset. + // + EnableFpga(); // Start the transmission session, clear address and set ioctl_download. + spi8(SHARPMZ_FILE_ADDR_TX); + spi8(0x00); // Tape header position address: Bit 24 + if(dstCMT == 0) // Load to emulators RAM + { + spi8(SHARPMZ_MEMBANK_SYSRAM); // Bits 23:16 + spi8((MZ_TAPE_HEADER_STACK_ADDR >> 8) & 0xff); // Bits 15:8 + spi8(MZ_TAPE_HEADER_STACK_ADDR & 0xff); // Bits 7:0 + } else + { + spi8(SHARPMZ_MEMBANK_CMT_HDR); // Bits 23:16 + spi8(0x00); // Bits 15:8 + spi8(0x00); // Bits 7:0 + } + // + spi_write((unsigned char *)&tapeHeader, MZ_TAPE_HEADER_SIZE, 0); + // + DisableFpga(); + EnableFpga(); // Finally indicate end of transmission. + spi8(SHARPMZ_FILE_TX); + spi8(SHARPMZ_EOF); + DisableFpga(); + + time = GetTimer(0) - time; + sharpmz_debugf("Uploaded in %lu ms", time >> 20); + + // Debug, show registers. + for(unsigned int i=0; i < MAX_REGISTERS; i++) + { + sharpmz_debugf("Register (%02x) = %02x", i, sharpmz_read_config_register(i)); + } + + // Tidy up. + FileClose(&file); + + // Dump out the memory if needed (generally for debug purposes). + if(dstCMT == 0) // Load to emulators RAM + { + sharpmz_read_ram((const char *)"memory.dump", SHARPMZ_MEMBANK_SYSRAM); + } else + { + sharpmz_read_ram((const char *)"cmt_header.dump", SHARPMZ_MEMBANK_CMT_HDR); + sharpmz_read_ram((const char *)"cmt_data.dump", SHARPMZ_MEMBANK_CMT_DATA); + } + + // Remove the LF from the header filename, not needed. + // + for(int i=0; i < 17; i++) + { + if(tapeHeader.fileName[i] == 0x0d) tapeHeader.fileName[i] = 0x00; + } + + // Debug, show registers. + for(unsigned int i=0; i < MAX_REGISTERS; i++) + { + sharpmz_debugf("Register (%02x) = %02x", i, sharpmz_read_config_register(i)); + } + + // Success. + // + return(0); +} + +// Method to save the contents of the CMT buffer onto a disk based MZF file. +// The method reads the header, writes it and then reads the data (upto size specified in header) and write it. +// +short sharpmz_save_tape_from_cmt(const char *tapeFile) +{ + short dataSize = 0; + unsigned short actualWriteSize; + unsigned short writeSize; + char fileName[17]; + + // Handle for the MZF file to be written. + // + fileTYPE file = { 0 }; + + // Read the header, then data, but limit data size to the 'file size' stored in the header. + // + for(unsigned int mb=SHARPMZ_MEMBANK_CMT_HDR; mb <= SHARPMZ_MEMBANK_CMT_DATA; mb++) + { + EnableFpga(); // Setup the load address. + spi8(SHARPMZ_FILE_ADDR_RX); + spi8(0x00); + spi8(mb); // Memory bank to read. + spi8(0x00); // A15-A8 + spi8(0x00); // A7-A0 + spi8(0x00); // Setup to read addr first byte. + + // The bank size is stored in the config. + // + if(mb == SHARPMZ_MEMBANK_CMT_HDR) + { + dataSize = MZ_TAPE_HEADER_SIZE; + } else + { + dataSize = tapeHeader.fileSize; + } + sharpmz_debugf("mb=%d, tapesize=%04x\n", mb, tapeHeader.fileSize); + for (; dataSize > 0; dataSize -= actualWriteSize) + { + sharpmz_debugf("mb=%d, dataSize=%04x, writeSize=%04x\n", mb, dataSize, writeSize); + if(mb == SHARPMZ_MEMBANK_CMT_HDR) + { + writeSize = MZ_TAPE_HEADER_SIZE; + } else + { + writeSize = dataSize > 512 ? 512 : dataSize; + } + spi_read(sector_buffer, writeSize, 0); + if(mb == SHARPMZ_MEMBANK_CMT_HDR) + { + memcpy(&tapeHeader, §or_buffer, MZ_TAPE_HEADER_SIZE); + + // Now open the file for writing. If no name provided, use the one stored in the header. + // + if(tapeFile == 0) + { + for(int i=0; i < 17; i++) + { + fileName[i] = tapeHeader.fileName[i] == 0x0d ? 0x00 : fileName[i]; + } + } else + { + memcpy(fileName, tapeHeader.fileName, 17); + } + + // Open the memory image debug file for writing. + if (!sharpmz_file_write(&file, fileName)) + { + sharpmz_debugf("Failed to open tape file:%s\n", fileName); + return(3); + } + } + DISKLED_ON; + actualWriteSize=FileWriteAdv(&file, sector_buffer, writeSize); + DISKLED_OFF; + } + + // Indicate end of upload. + spi8(SHARPMZ_EOF); + DisableFpga(); + } + + // Close file to complete dump. + FileClose(&file); + + return(0); +} + +// Function from menu.cpp located here due to its static definition. Unneeded parts stripped out but otherwise it performs same +// actions. +// +void sharpmz_select_file(const char* pFileExt, unsigned char Options, char *fs_pFileExt, char chdir, char *SelectedPath) +{ + sharpmz_debugf("pFileExt = %s\n", pFileExt); + + if (strncasecmp(SHARPMZ_CORE_NAME, SelectedPath, strlen(SHARPMZ_CORE_NAME))) strcpy(SelectedPath, SHARPMZ_CORE_NAME); + + ScanDirectory(SelectedPath, SCANF_INIT, pFileExt, Options); + if (!flist_nDirEntries()) + { + SelectedPath[0] = 0; + ScanDirectory(SelectedPath, SCANF_INIT, pFileExt, Options); + } + + AdjustDirectory(SelectedPath); + strcpy(fs_pFileExt, pFileExt); +} + +// Method to return the default UI state. +// +int sharpmz_default_ui_state(void) +{ + return(MENU_SHARPMZ_MAIN1); +} + +// User interface for the SharpMZ Series emulator. This functionality has been located here to minimise changes on common +// code base and to limit common code case size. +// The same general programming structure is maintained to enable easier changes. +// +int sharpmz_ui(int idleState, int idle2State, int systemState, int selectFile, + unsigned char *parentstate, unsigned char *menustate, unsigned char *menusub, unsigned char *menusub_last, + unsigned int *menumask, char *selectedPath, const char **helptext, char *helptext_custom, + unsigned char *fs_ExtLen, unsigned char *fs_Options, unsigned char *fs_MenuSelect, unsigned char *fs_MenuCancel, + char *fs_pFileExt, + unsigned char menu, unsigned char select, unsigned char up, unsigned char down, + unsigned char left, unsigned char right, unsigned char plus, unsigned char minus) +{ + // Locals - original variables are generally all lower case, variables specific to this method are capitalised on change of word. + // + static short romType; + static short machineModel = sharpmz_get_next_machine_model(); + static short debugCPUFrequency = sharpmz_get_next_debug_cpufreq(); + static short debugLedsBank = sharpmz_get_next_debug_leds_bank(); + static short debugLedsSampleFrequency = sharpmz_get_next_debug_leds_smpfreq(); + static short memoryBank = sharpmz_get_next_memory_bank(); + static short fileDumped = 0; + static short scrollPos = 0; + static short volumeDir = 0; + int menuItem; + int subItem; + short romEnabled; + short itemCount; + char sBuf[40]; + char *fileName; + + + // Idle2 state (MENU_NONE2) is our main hook, when the HandleUI state machine reaches this state, if the menu key is pressed, + // we takeover control in this method. + // + if(*menustate == idle2State && menu) + { + OsdSetSize(16); + *menusub = 0; + OsdClear(); + OsdEnable(DISABLE_KEYBOARD); + *menustate = MENU_SHARPMZ_MAIN1; + } + + // The menustate originates in the HandleUI method, if a value is not recognised in the main switch statement in HandleUI then + // it is ignored. This method utilises this fact and operates on a set of states outside those used in HandleUI. + // + switch(*menustate) + { + /******************************************************************/ + /* SharpMZ core menu */ + /******************************************************************/ + + case MENU_SHARPMZ_MAIN1: + + menuItem = 0; + subItem = 0; + *menumask = 0; + + OsdSetTitle(user_io_get_core_name(), 0); + + OsdWrite(menuItem++, " Main Menu", 0, 0); + OsdWrite(menuItem++, "", 0, 0); + + OsdWrite(menuItem++, " Tape Storage \x16", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + // Not yet implemented. + //OsdWrite(menuItem++, " Floppy Storage \x16", *menusub == subItem++, 0); + //*menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, " Machine \x16", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, " Display \x16", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, " Debug \x16", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, " System \x16", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + for (; menuItem < 10; menuItem++) + { + OsdWrite(menuItem, "", 0, 0); + } + + OsdWrite(menuItem++, " Reset", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + OsdWrite(menuItem++, " Reload config", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + OsdWrite(menuItem++, " Save config", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + OsdWrite(menuItem++, " Reset config", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + for (; menuItem < 15; menuItem++) + { + OsdWrite(menuItem, "", 0, 0); + } + + OsdWrite(menuItem++, "", 0, 0); + OsdWrite(menuItem, " exit", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + // Set menu states, parent is the root menu, next is the processing menu 2. + // + *parentstate = MENU_SHARPMZ_MAIN1; + *menustate = MENU_SHARPMZ_MAIN2; + + // set helptext with core display on top of basic info + sprintf(helptext_custom, " "); + strcat(helptext_custom, OsdCoreName()); + strcat(helptext_custom, " "); + strcat(helptext_custom, SHARPMZ_HELPTEXT[0]); + *helptext = helptext_custom; + break; + + case MENU_SHARPMZ_MAIN2: + // menu key closes menu + if (menu) + *menustate = idleState; + + if (select || right) + { + switch (*menusub) + { + case 0: // Tape Storage + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + *menusub_last = *menusub; + *menusub = 0; + if(right) select = true; + break; + + //case 1: // Floppy Storage + // *menustate = MENU_SHARPMZ_FLOPPY_STORAGE1; + // *menusub_last = *menusub; + // *menusub = 0; + // if(right) select = true; + // break; + + case 1: // Machine + *menustate = MENU_SHARPMZ_MACHINE1; + *menusub_last = *menusub; + *menusub = 0; + if(right) select = true; + break; + + case 2: // Display + *menustate = MENU_SHARPMZ_DISPLAY1; + *menusub_last = *menusub; + *menusub = 0; + if(right) select = true; + break; + + case 3: // Debug + *menustate = MENU_SHARPMZ_DEBUG1; + *menusub_last = *menusub; + *menusub = 0; + if(right) select = true; + break; + + case 4: // System + *menustate = systemState; + *menusub_last = *menusub; + *menusub = 0; + if(right) select = true; + break; + + case 5: // Reset Machine + if(select) + { + sharpmz_init(); + *menustate = idleState; + } + break; + + case 6: // Reload Settings + if(select) + { + sharpmz_reload_config(1); + *menustate = MENU_SHARPMZ_MAIN1; + } + break; + + case 7: // Save Settings + if(select) + { + sharpmz_save_config(); + *menustate = MENU_SHARPMZ_MAIN1; + } + break; + + case 8: // Reset Settings + if(select) + { + sharpmz_reset_config(1); + *menustate = MENU_SHARPMZ_MAIN1; + } + break; + + case 9: // Exit + *menustate = idleState; + if(right) select = true; + break; + } + } + break; + + case MENU_SHARPMZ_TAPE_STORAGE1: + menuItem = 0; + subItem = 0; + *menumask = 0; + + OsdSetTitle("Tape Storage", OSD_ARROW_LEFT); + + OsdWrite(menuItem++, "", 0, 0); + + OsdWrite(menuItem++, " Load direct to RAM: *.MZF", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, " Queue Tape: *.MZF", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, " Clear Queue ", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + // List out the current tape queue. + itemCount = 0; + while((fileName = sharpmz_get_next_filename(0)) != 0) + { + sprintf(sBuf, " %d> %s", itemCount++, fileName); + OsdWrite(menuItem++, sBuf, 0, 0); + } + + OsdWrite(menuItem++, "", 0, 0); + + OsdWrite(menuItem++, " Save Tape: *.MZF", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Auto Save Tape: "); + strcat(sBuf, sharpmz_get_auto_save_enabled_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, "", 0, 0); + + strcpy(sBuf, " Tape Buttons: "); + strcat(sBuf, sharpmz_get_tape_buttons_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Fast Tape Load: "); + strcat(sBuf, sharpmz_get_fasttape_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + for (; menuItem < 15; menuItem++) + { + OsdWrite(menuItem, "", 0, 0); + } + + OsdWrite(menuItem, " exit", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + *parentstate = *menustate; + *menustate = MENU_SHARPMZ_TAPE_STORAGE2; + break; + + + case MENU_SHARPMZ_TAPE_STORAGE2: + if (menu) { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + if (select) + { + *menusub_last = *menusub; + switch(*menusub) + { + // Load direct to RAM? This involves parsing the MZF header, copying the header (128 bytes) to 0x10F0 in the Z80 memory range + // then loading the remainder into the location specified (position 20) of size (position 18). + // + // Load from Tape? This involves sending the whole file to the emulator CMT buffer, it then plays the file into the + // emulator as pseudo PWM tape. + // + case 0: + case 1: + *fs_Options = SCANO_DIR; + sharpmz_select_file("MZFmzfMZTmzt", *fs_Options, fs_pFileExt, 1, selectedPath); + //sharpmz_select_file("MZFmzf", *fs_Options, fs_pFileExt, 1, selectedPath); + *fs_ExtLen = strlen(fs_pFileExt); + *fs_MenuSelect = (*menusub == 0 ? MENU_SHARPMZ_TAPE_STORAGE_LOAD_TAPE_TO_RAM : MENU_SHARPMZ_TAPE_STORAGE_QUEUE_TAPE_TO_CMT); + *fs_MenuCancel = MENU_SHARPMZ_MAIN1; + *menustate = selectFile; + break; + + case 2: + sharpmz_clear_filelist(); + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + break; + + case 3: + *menustate = MENU_SHARPMZ_TAPE_STORAGE_SAVE_TAPE_FROM_CMT; + break; + + case 4: + sharpmz_set_auto_save_enabled(sharpmz_get_auto_save_enabled() == 0 ? 1 : 0); + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + break; + + case 5: + sharpmz_set_tape_buttons(sharpmz_get_tape_buttons()+1, 1); + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + break; + + case 6: + sharpmz_set_fasttape(sharpmz_get_fasttape()+1, 1); + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + break; + + case 7: + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + break; + } + } + if (left) + { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + break; + + case MENU_SHARPMZ_TAPE_STORAGE_LOAD_TAPE_TO_RAM: + sharpmz_debugf("File selected to send to RAM: %s, for menu option:%04x\n", selectedPath, *menumask); + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + if(selectedPath) + { + int fail=sharpmz_load_tape_to_ram(selectedPath, 0); + sharpmz_tape_header_t *tapeHeader = sharpmz_get_tape_header(); + + if(!fail) + OsdSetTitle("Tape Details", OSD_ARROW_LEFT); + else + OsdSetTitle(" Tape Error", OSD_ARROW_LEFT); + + *menumask = 0x01; // Exit. + *parentstate = *menustate; + menuItem = 0; + + if(!fail) + OsdWrite(menuItem++, " Tape Details", 0, 0); + else + OsdWrite(menuItem++, " Tape Error", 0, 0); + OsdWrite(menuItem++, "", 0, 0); + sprintf(sBuf, " File Size: %04x", tapeHeader->fileSize); + OsdWrite(menuItem++, sBuf, 0, 0); + strcpy(sBuf, " File Type: "); + strcat(sBuf, sharpmz_get_tape_type_string()); + OsdWrite(menuItem++, sBuf, 0, 0); + strcpy(sBuf, " File Name: "); + strcat(sBuf, tapeHeader->fileName); + OsdWrite(menuItem++, sBuf, 0, 0); + sprintf(sBuf, " Load Addr: %04x", tapeHeader->loadAddress); + OsdWrite(menuItem++, sBuf, 0, 0); + sprintf(sBuf, " Exec Addr: %04x", tapeHeader->execAddress); + OsdWrite(menuItem++, sBuf, 0, 0); + OsdWrite(menuItem++, "", 0, 0); + + if(!fail) + OsdWrite(menuItem++, "", 0, 0); + else + { + switch(fail) + { + case 1: + strcpy(sBuf, " Unable to open file!"); + break; + case 2: + strcpy(sBuf, " Unable to read header!"); + break; + case 3: + strcpy(sBuf, " Not a m/code Program!"); + break; + case 4: + strcpy(sBuf, " Not a valid tape!"); + break; + } + OsdWrite(menuItem++, sBuf, 0, 0); + } + for (; menuItem < OsdGetSize()-1; menuItem++) OsdWrite(menuItem, "", 0, 0); + OsdWrite(menuItem, " exit", true, 0); + *menustate = MENU_SHARPMZ_TAPE_STORAGE_LOAD_TAPE_TO_RAM2; + } + break; + + case MENU_SHARPMZ_TAPE_STORAGE_LOAD_TAPE_TO_RAM2: + if (menu || select || left || up) + { + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + *menusub = *menusub_last; + } + break; + + case MENU_SHARPMZ_TAPE_STORAGE_QUEUE_TAPE_TO_CMT: + sharpmz_debugf("File added to Queue: %s, for menu option:%04x\n", selectedPath, *menumask); + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + if(selectedPath) + { + // Read in the header of the queued tape file. + // + int fail=sharpmz_read_tape_header(selectedPath); + sharpmz_tape_header_t *tapeHeader = sharpmz_get_tape_header(); + + // Limit number of items in queue, makes no sense to have too many and we run out of display space. + // + if(tapeQueue.elements < 5 && !fail) + { + sharpmz_push_filename(selectedPath); + OsdSetTitle("Tape Queued", OSD_ARROW_LEFT); + } else + { + OsdSetTitle("Queue Error", OSD_ARROW_LEFT); + } + + *menumask = 0x01; // Exit. + *parentstate = *menustate; + menuItem = 0; + + if(!fail) + { + OsdWrite(menuItem++, " Tape Details", 0, 0); + OsdWrite(menuItem++, "", 0, 0); + sprintf(sBuf, " File Size: %04x", tapeHeader->fileSize); + OsdWrite(menuItem++, sBuf, 0, 0); + strcpy(sBuf, " File Type: "); + strcat(sBuf, sharpmz_get_tape_type_string()); + OsdWrite(menuItem++, sBuf, 0, 0); + strcpy(sBuf, " File Name: "); + strcat(sBuf, tapeHeader->fileName); + OsdWrite(menuItem++, sBuf, 0, 0); + sprintf(sBuf, " Load Addr: %04x", tapeHeader->loadAddress); + OsdWrite(menuItem++, sBuf, 0, 0); + sprintf(sBuf, " Exec Addr: %04x", tapeHeader->execAddress); + OsdWrite(menuItem++, sBuf, 0, 0); + OsdWrite(menuItem++, "", 0, 0); + OsdWrite(menuItem++, "", 0, 0); + } else + { + OsdWrite(menuItem++, " Queue Error", 0, 0); + OsdWrite(menuItem++, "", 0, 0); + + if(!fail) + strcpy(sBuf, " Queue limit reached!"); + else + { + switch(fail) + { + case 1: + strcpy(sBuf, " Unable to open file!"); + break; + case 2: + strcpy(sBuf, " Unable to read header!"); + break; + case 3: + strcpy(sBuf, " Not a m/code Program!"); + break; + case 4: + strcpy(sBuf, " Not a valid tape!"); + break; + } + } + + OsdWrite(menuItem++, sBuf, 0, 0); + } + for (; menuItem < OsdGetSize()-1; menuItem++) OsdWrite(menuItem, "", 0, 0); + OsdWrite(menuItem, " exit", true, 0); + *menustate = MENU_SHARPMZ_TAPE_STORAGE_QUEUE_TAPE_TO_CMT2; + } + break; + + case MENU_SHARPMZ_TAPE_STORAGE_QUEUE_TAPE_TO_CMT2: + if (menu || select || left || up) + { + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + *menusub = *menusub_last; + } + break; + + case MENU_SHARPMZ_TAPE_STORAGE_SAVE_TAPE_FROM_CMT: + sharpmz_save_tape_from_cmt((const char *)0); + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + break; + + case MENU_SHARPMZ_TAPE_STORAGE_SAVE_TAPE_FROM_CMT2: + *menustate = MENU_SHARPMZ_TAPE_STORAGE1; + break; + + // Floppy Storage + case MENU_SHARPMZ_FLOPPY_STORAGE1: + menuItem = 0; + subItem = 0; + *menumask = 0; + + OsdSetTitle("Floppy Storage", OSD_ARROW_LEFT); + + OsdWrite(menuItem++, "", 0, 0); + + for (; menuItem < 15; menuItem++) + { + OsdWrite(menuItem, "", 0, 0); + } + + OsdWrite(menuItem, " exit", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + *parentstate = *menustate; + *menustate = MENU_SHARPMZ_FLOPPY_STORAGE2; + break; + + case MENU_SHARPMZ_FLOPPY_STORAGE2: + if (menu) { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + if (select) + { + *menusub_last = *menusub; + switch(*menusub) + { + case 0: + break; + + case 1: + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + break; + } + } + if (left) + { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + break; + + // Machine configuration. + case MENU_SHARPMZ_MACHINE1: + menuItem = 0; + subItem = 0; + *menumask = 0; + + OsdSetTitle("Machine", OSD_ARROW_LEFT); + + OsdWrite(menuItem++, "", 0, 0); + + strcpy(sBuf, " Machine Model: "); + strcat(sBuf, sharpmz_get_machine_model_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " CPU Speed: "); + strcat(sBuf, sharpmz_get_cpu_speed_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, "", 0, 0); + + strcpy(sBuf, " Audio Source: "); + strcat(sBuf, sharpmz_get_audio_source_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Audio Volume: "); + strcat(sBuf, sharpmz_get_audio_volume_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Audio Mute: "); + strcat(sBuf, sharpmz_get_audio_mute_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, "", 0, 0); + OsdWrite(menuItem++, " Rom Management \x16", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + for (; menuItem < 15; menuItem++) + { + OsdWrite(menuItem, "", 0, 0); + } + + OsdWrite(menuItem, " exit", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + *parentstate = *menustate; + *menustate = MENU_SHARPMZ_MACHINE2; + break; + + + case MENU_SHARPMZ_MACHINE2: + if (menu) { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + if (select) + { + switch(*menusub) + { + case 0: // Machine Model + //sharpmz_set_machine_model(sharpmz_get_machine_model() + 1, 1); + sharpmz_set_machine_model(sharpmz_get_machine_model() + 1, 1); + *menustate = MENU_SHARPMZ_MACHINE1; + break; + + case 1: // CPU Speed + sharpmz_set_cpu_speed((sharpmz_get_cpu_speed() + 1) & 0x07, 1); + *menustate = MENU_SHARPMZ_MACHINE1; + break; + + case 2: // Audio Source + sharpmz_set_audio_source(sharpmz_get_audio_source() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_MACHINE1; + break; + + case 3: // Audio Volume + sharpmz_set_audio_volume((sharpmz_get_audio_volume() + (volumeDir ? -1 : +1)) & 0x0f, 1); + if(sharpmz_get_audio_volume() == 15) volumeDir = 1; + if(sharpmz_get_audio_volume() == 0) volumeDir = 0; + *menustate = MENU_SHARPMZ_MACHINE1; + break; + + case 4: // Audio Mute + sharpmz_set_audio_mute(sharpmz_get_audio_mute() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_MACHINE1; + break; + + case 5: // Roms + *menustate = MENU_SHARPMZ_ROMS1; + *menusub_last = *menusub; + *menusub = 0; + if(right) select = true; + break; + + case 6: // Exit + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = 1; //*menusub_last; + break; + } + } + if (left) + { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = 1; //*menusub_last; + } + break; + + case MENU_SHARPMZ_ROMS1: + + if(*menusub == 0) + { + scrollPos = 0; + } + if(down && *menusub > 9 && scrollPos < 3) { scrollPos++; (*menusub)--; } + if(up && *menusub < 10 && scrollPos > 0) { scrollPos--; (*menusub)++; } + + menuItem = 0; + subItem = 0; + *menumask = 0; + + OsdSetTitle("Rom Management", OSD_ARROW_LEFT); + + OsdWrite(menuItem++, "", 0, 0); + + if(scrollPos == 0) + { + strcpy(sBuf, " Machine Model: "); + strcat(sBuf, sharpmz_get_machine_model_string(machineModel)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + + if(scrollPos <= 1) + { + strcpy(sBuf, " User ROM: "); + strcat(sBuf, sharpmz_get_user_rom_enabled_string(machineModel)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + + if(scrollPos <= 2) + { + strcpy(sBuf, " Floppy Disk ROM: "); + strcat(sBuf, sharpmz_get_fdc_rom_enabled_string(machineModel)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + OsdWrite(menuItem++, "", 0, 0); + } + + OsdWrite(menuItem++, " Enable Custom Rom: ", 0, 0); + romEnabled = sharpmz_get_custom_rom_enabled(machineModel, MROM_IDX); + strcpy(sBuf, " Monitor (40x25) "); + strcat(sBuf, sharpmz_get_custom_rom_enabled_string(romEnabled)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + if(romEnabled) + { + strcpy(sBuf, " \x16 "); + strcat(sBuf, sharpmz_get_rom_file(machineModel, MROM_IDX)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + + romEnabled = sharpmz_get_custom_rom_enabled(machineModel, MROM_80C_IDX); + strcpy(sBuf, " Monitor (80x25) "); + strcat(sBuf, sharpmz_get_custom_rom_enabled_string(romEnabled)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + if(romEnabled) + { + strcpy(sBuf, " \x16 "); + strcat(sBuf, sharpmz_get_rom_file(machineModel, MROM_80C_IDX)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + + romEnabled = sharpmz_get_custom_rom_enabled(machineModel, CGROM_IDX); + strcpy(sBuf, " Char Generator "); + strcat(sBuf, sharpmz_get_custom_rom_enabled_string(romEnabled)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + if(romEnabled) + { + strcpy(sBuf, " \x16 "); + strcat(sBuf, sharpmz_get_rom_file(machineModel, CGROM_IDX)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + + romEnabled = sharpmz_get_custom_rom_enabled(machineModel, KEYMAP_IDX); + strcpy(sBuf, " Key Mapping "); + strcat(sBuf, sharpmz_get_custom_rom_enabled_string(romEnabled)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + if(romEnabled) + { + strcpy(sBuf, " \x16 "); + strcat(sBuf, sharpmz_get_rom_file(machineModel, KEYMAP_IDX)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + + romEnabled = sharpmz_get_custom_rom_enabled(machineModel, USERROM_IDX); + strcpy(sBuf, " User ROM "); + strcat(sBuf, sharpmz_get_custom_rom_enabled_string(romEnabled)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + if(romEnabled) + { + strcpy(sBuf, " \x16 "); + strcat(sBuf, sharpmz_get_rom_file(machineModel, USERROM_IDX)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + + romEnabled = sharpmz_get_custom_rom_enabled(machineModel, FDCROM_IDX); + strcpy(sBuf, " Floppy Disk "); + strcat(sBuf, sharpmz_get_custom_rom_enabled_string(romEnabled)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + if(romEnabled) + { + strcpy(sBuf, " \x16 "); + strcat(sBuf, sharpmz_get_rom_file(machineModel, FDCROM_IDX)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + + for (; menuItem < 15; menuItem++) + { + OsdWrite(menuItem, "", 0, 0); + } + OsdWrite(menuItem, " exit", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + *parentstate = *menustate; + *menustate = MENU_SHARPMZ_ROMS2; + break; + + + case MENU_SHARPMZ_ROMS2: + if (menu) { + *menustate = MENU_SHARPMZ_MACHINE1; + *menusub = *menusub_last; + } + if (select) + { + int selectItem = *menusub + scrollPos; + + if(selectItem > 3) selectItem += sharpmz_get_custom_rom_enabled(machineModel, MROM_IDX) ? 0 : 1; + if(selectItem > 5) selectItem += sharpmz_get_custom_rom_enabled(machineModel, MROM_80C_IDX) ? 0 : 1; + if(selectItem > 7) selectItem += sharpmz_get_custom_rom_enabled(machineModel, CGROM_IDX) ? 0 : 1; + if(selectItem > 9) selectItem += sharpmz_get_custom_rom_enabled(machineModel, KEYMAP_IDX) ? 0 : 1; + if(selectItem > 11) selectItem += sharpmz_get_custom_rom_enabled(machineModel, USERROM_IDX) ? 0 : 1; + if(selectItem > 13) selectItem += sharpmz_get_custom_rom_enabled(machineModel, FDCROM_IDX) ? 0 : 1; + + switch(selectItem) + { + case 0: + machineModel = sharpmz_get_next_machine_model(); + *menustate = MENU_SHARPMZ_ROMS1; + break; + + case 1: + sharpmz_set_user_rom_enabled(machineModel, sharpmz_get_user_rom_enabled(machineModel) ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_ROMS1; + break; + + case 2: + sharpmz_set_fdc_rom_enabled(machineModel, sharpmz_get_fdc_rom_enabled(machineModel) ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_ROMS1; + break; + + case 3: + case 5: + case 7: + case 9: + case 11: + case 13: + switch(selectItem) + { + case 3: + romType = MROM_IDX; + break; + + case 5: + romType = MROM_80C_IDX; + break; + + case 7: + romType = CGROM_IDX; + break; + + case 9: + romType = KEYMAP_IDX; + break; + + case 11: + romType = USERROM_IDX; + break; + + default: + romType = FDCROM_IDX; + break; + } + sharpmz_set_custom_rom_enabled(machineModel, romType, sharpmz_get_custom_rom_enabled(machineModel, romType) == 0); + *menustate = MENU_SHARPMZ_ROMS1; + break; + + case 4: + case 6: + case 8: + case 10: + case 12: + case 14: + *fs_Options = SCANO_DIR; + sharpmz_select_file("ROMBINrombin", *fs_Options, fs_pFileExt, 1, selectedPath); + *fs_ExtLen = strlen(fs_pFileExt); + *fs_MenuSelect = MENU_SHARPMZ_ROM_FILE_SELECTED; + *fs_MenuCancel = MENU_SHARPMZ_ROMS1; + *menustate = selectFile; + break; + + case 15: + *menustate = MENU_SHARPMZ_MACHINE1; + *menusub = *menusub_last; + break; + } + } + if (left) + { + *menustate = MENU_SHARPMZ_MACHINE1; + *menusub = *menusub_last; + } + break; + + case MENU_SHARPMZ_ROM_FILE_SELECTED: + if(!strncasecmp(selectedPath, SHARPMZ_CORE_NAME, 7)) strcpy(selectedPath, (char *) & selectedPath[8]); + sharpmz_debugf("File selected: %s, model:%d, for option:%04x\n", selectedPath, machineModel, romType); + sharpmz_set_rom_file(machineModel, romType, selectedPath); + *menustate = MENU_SHARPMZ_ROMS1; + break; + + // DISPLAY Menu + case MENU_SHARPMZ_DISPLAY1: + menuItem = 0; + subItem = 0; + *menumask = 0; + + OsdSetTitle("Display", OSD_ARROW_LEFT); + + OsdWrite(menuItem++, "", 0, 0); + + strcpy(sBuf, " Display Type: "); + strcat(sBuf, sharpmz_get_display_type_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Video: "); + strcat(sBuf, sharpmz_get_vram_disable_mode_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Graphics: "); + strcat(sBuf, sharpmz_get_gram_disable_mode_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " VRAM CPU Wait: "); + strcat(sBuf, sharpmz_get_vram_wait_mode_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " PCG Mode: "); + strcat(sBuf, sharpmz_get_pcg_mode_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Aspect Ratio: "); + strcat(sBuf, sharpmz_get_aspect_ratio_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Scandoubler: "); + strcat(sBuf, sharpmz_get_scandoubler_fx_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + for (; menuItem < 15; menuItem++) + { + OsdWrite(menuItem, "", 0, 0); + } + + OsdWrite(menuItem, " exit", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + *parentstate = *menustate; + *menustate = MENU_SHARPMZ_DISPLAY2; + break; + + case MENU_SHARPMZ_DISPLAY2: + if (menu) { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + if (select) + { + switch(*menusub) + { + case 0: + sharpmz_set_display_type((sharpmz_get_display_type() + 1) & 0x07, 1); + *menustate = MENU_SHARPMZ_DISPLAY1; + break; + + case 1: + sharpmz_set_vram_disable_mode(sharpmz_get_vram_disable_mode() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_DISPLAY1; + break; + + case 2: + sharpmz_set_gram_disable_mode(sharpmz_get_gram_disable_mode() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_DISPLAY1; + break; + + case 3: + sharpmz_set_vram_wait_mode(sharpmz_get_vram_wait_mode() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_DISPLAY1; + break; + + case 4: + sharpmz_set_pcg_mode(sharpmz_get_pcg_mode() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_DISPLAY1; + break; + + case 5: + sharpmz_set_aspect_ratio(sharpmz_get_aspect_ratio() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_DISPLAY1; + break; + + case 6: + sharpmz_set_scandoubler_fx((sharpmz_get_scandoubler_fx() + 1) & 0x07, 1); + *menustate = MENU_SHARPMZ_DISPLAY1; + break; + + case 7: + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + break; + } + } + if (left) + { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + break; + + // Debug options. + case MENU_SHARPMZ_DEBUG1: + menuItem = 0; + subItem = 0; + *menumask = 0; + + OsdSetTitle("Debug", OSD_ARROW_LEFT); + + OsdWrite(menuItem++, "", 0, 0); + + strcpy(sBuf, " Select Memory Bank: "); + strcat(sBuf, sharpmz_get_memory_bank_string(memoryBank)); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + if(fileDumped == 1) + { + strcpy(sBuf, " File "); + strcat(sBuf, sharpmz_get_memory_bank_file(memoryBank)); + strcat(sBuf, " written!"); + fileDumped = 0; + } else + { + strcpy(sBuf, " Dump To \x16 "); + strcat(sBuf, sharpmz_get_memory_bank_file(memoryBank)); + } + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + OsdWrite(menuItem++, "", 0, 0); + strcpy(sBuf, " Debug Mode: "); + strcat(sBuf, sharpmz_get_debug_enable_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + // Display the debug menu only when enabled. + // + if(sharpmz_get_debug_enable()) + { + strcpy(sBuf, " CPU Frequency: "); + strcat(sBuf, sharpmz_get_debug_cpufreq_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Debug LEDS: "); + strcat(sBuf, sharpmz_get_debug_leds_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + // Display the LED menu only when enabled. + // + if(sharpmz_get_debug_leds()) + { + strcpy(sBuf, " Sample Freq: "); + strcat(sBuf, sharpmz_get_debug_leds_smpfreq_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Signal Block: "); + strcat(sBuf, sharpmz_get_debug_leds_bank_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + strcpy(sBuf, " Bank: "); + strcat(sBuf, sharpmz_get_debug_leds_subbank_string()); + OsdWrite(menuItem++, sBuf, *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + } + } + + for (; menuItem < 15; menuItem++) + { + OsdWrite(menuItem, "", 0, 0); + } + + OsdWrite(menuItem, " exit", *menusub == subItem++, 0); + *menumask = (*menumask << 1) | 1; + + *parentstate = *menustate; + *menustate = MENU_SHARPMZ_DEBUG2; + break; + + case MENU_SHARPMZ_DEBUG2: + if (menu) { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + if (select) + { + *menusub_last = *menusub; + switch(*menusub) + { + case 0: // Select Memory Bank to be dumped. + memoryBank = sharpmz_get_next_memory_bank(); + *menustate = MENU_SHARPMZ_DEBUG1; + break; + + case 1: // Dump selected Memory Bank + sharpmz_read_ram(sharpmz_get_memory_bank_file(memoryBank), memoryBank); + fileDumped = 1; + *menustate = MENU_SHARPMZ_DEBUG1; + break; + + case 2: // Debug Enable + sharpmz_set_debug_enable(sharpmz_get_debug_enable() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_DEBUG1; + break; + + case 3: // CPU Frequency + debugCPUFrequency = sharpmz_get_next_debug_cpufreq(); + sharpmz_set_debug_cpufreq(debugCPUFrequency, 1); + *menustate = MENU_SHARPMZ_DEBUG1; + break; + + case 4: // Debug LEDS + sharpmz_set_debug_leds(sharpmz_get_debug_leds() ? 0 : 1, 1); + *menustate = MENU_SHARPMZ_DEBUG1; + break; + + case 5: // Sample Frequency + debugLedsSampleFrequency = sharpmz_get_next_debug_leds_smpfreq(); + sharpmz_set_debug_leds_smpfreq(debugLedsSampleFrequency, 1); + *menustate = MENU_SHARPMZ_DEBUG1; + break; + + case 6: // Signal Block + debugLedsBank = sharpmz_get_next_debug_leds_bank(); + sharpmz_set_debug_leds_bank(debugLedsBank, 1); + sharpmz_set_debug_leds_subbank(0, 1); // Always switch to auto if bank changed. + sharpmz_get_next_debug_leds_subbank(1); // And reset the next loop. + *menustate = MENU_SHARPMZ_DEBUG1; + break; + + case 7: // Signal Bank + sharpmz_set_debug_leds_subbank(sharpmz_get_next_debug_leds_subbank(0), 1); + *menustate = MENU_SHARPMZ_DEBUG1; + break; + + case 8: // Exit + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + break; + } + } + if (left) + { + *menustate = MENU_SHARPMZ_MAIN1; + *menusub = *menusub_last; + } + break; + + default: + break; + } +} diff --git a/sharpmz.h b/sharpmz.h new file mode 100644 index 0000000..21dfa66 --- /dev/null +++ b/sharpmz.h @@ -0,0 +1,469 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Name: sharpmz.h +// Created: July 2018 +// Author(s): Philip Smart +// Description: Sharp MZ series MiSTer Menu Add-On. +// This module is an extension to the MiSTer control program. It adds extensions to +// the menu system and additional I/O control specific to the Sharp MZ series +// emulation. +// +// Credits: +// Copyright: (c) 2018 Philip Smart +// +// History: July 2018 - Initial module written. +// Sept 2018 - Synchronised with main MiSTer codebase. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////////////////// +#ifndef SHARPMZ_H +#define SHARPMZ_H + +#include "file_io.h" + +// Defaults. +// +#define MZ_TAPE_HEADER_STACK_ADDR 0x10f0 +#define MZ_TAPE_HEADER_SIZE 128 +#define MEMORY_DUMP_FILE "cmp/lastload" +#define MAX_FILENAME_SIZE 1024 + +// HPS commands to fpga block. +// +#define SHARPMZ_EOF 0x00 +#define SHARPMZ_SOF 0x01 +#define SHARPMZ_FILE_TX 0x53 +#define SHARPMZ_FILE_TX_DAT 0x54 +#define SHARPMZ_FILE_INDEX 0x55 +#define SHARPMZ_FILE_INFO 0x56 +#define SHARPMZ_FILE_ADDR 0x57 +#define SHARPMZ_FILE_ADDR_TX 0x58 +#define SHARPMZ_FILE_ADDR_RX 0x59 +#define SHARPMZ_CONFIG_RX 0x5A +#define SHARPMZ_CONFIG_TX 0x5B + +// Memory blocks within the Emulator. +// +#define SHARPMZ_MEMBANK_ALL 0xff +#define SHARPMZ_MEMBANK_SYSROM 0x00 +#define SHARPMZ_MEMBANK_SYSRAM 0x02 +#define SHARPMZ_MEMBANK_KEYMAP 0x03 +#define SHARPMZ_MEMBANK_VRAM 0x04 +#define SHARPMZ_MEMBANK_CMT_HDR 0x05 +#define SHARPMZ_MEMBANK_CMT_DATA 0x06 +#define SHARPMZ_MEMBANK_CGROM 0x07 +#define SHARPMZ_MEMBANK_CGRAM 0x08 +#define SHARPMZ_MEMBANK_MAXBANKS 9 + +// Name of the configuration file. +// +#define SHARPMZ_CONFIG_FILENAME "SHARPMZ.CFG" + +// Name of the core. +// +#define SHARPMZ_CORE_NAME "SharpMZ" + +// Maximum number of machines currently supported by the emulation. +// +#define MAX_MZMACHINES 8 + +// Maximum number of sub-roms per machine. +// +#define MAX_MROMOPTIONS 2 + +// Numeric index of each machine. +// +#define MZ80K_IDX 0 // 000 +#define MZ80C_IDX 1 // 001 +#define MZ1200_IDX 2 // 010 +#define MZ80A_IDX 3 // 011 +#define MZ700_IDX 4 // 100 +#define MZ800_IDX 5 // 101 +#define MZ80B_IDX 6 // 110 +#define MZ2000_IDX 7 // 111 + +// Maximum number of images which can be loaded. +// +#define MAX_IMAGE_TYPES 6 + +// Numeric index of each main rom image category. +// +#define MROM_IDX 0 +#define MROM_80C_IDX 1 +#define CGROM_IDX 2 +#define KEYMAP_IDX 3 +#define USERROM_IDX 4 +#define FDCROM_IDX 5 + +// Numeric index of monitor rom subtypes. +// +#define MONITOR 0 +#define MONITOR_80C 1 + +// Numeric index of Option rom subtypes. +// +#define USERROM 0 +#define FDCROM 1 + +// Tape(CMT) Data types. +// +#define SHARPMZ_CMT_MC 1 // machine code program. +#define SHARPMZ_CMT_BASIC 2 // MZ-80 Basic program. +#define SHARPMZ_CMT_DATA 3 // MZ-80 data file. +#define SHARPMZ_CMT_700DATA 4 // MZ-700 data file. +#define SHARPMZ_CMT_700BASIC 5 // MZ700 Basic program. + +// Numeric id of system registers. +// +#define REGISTER_MODEL 0 +#define REGISTER_DISPLAY 1 +#define REGISTER_CPU 2 +#define REGISTER_AUDIO 3 +#define REGISTER_CMT 4 +#define REGISTER_CMT2 5 +#define REGISTER_USERROM 6 +#define REGISTER_FDCROM 7 +#define REGISTER_8 8 +#define REGISTER_9 9 +#define REGISTER_10 10 +#define REGISTER_11 11 +#define REGISTER_12 12 +#define REGISTER_13 13 +#define REGISTER_DEBUG 14 +#define REGISTER_DEBUG2 15 +#define MAX_REGISTERS 16 + +// Numeric id of bit for a given CMT register flag. +// +#define CMT_PLAY_READY 0 // Tape play back buffer, 0 = empty, 1 = full. +#define CMT_PLAYING 1 // Tape playback, 0 = stopped, 1 = in progress. +#define CMT_RECORD_READY 2 // Tape record buffer full. +#define CMT_RECORDING 3 // Tape recording, 0 = stopped, 1 = in progress. +#define CMT_ACTIVE 4 // Tape transfer in progress, 0 = no activity, 1 = activity. +#define CMT_SENSE 5 // Tape state Sense out. +#define CMT_WRITEBIT 6 // Write bit to MZ. +#define CMT_READBIT 7 // Receive bit from MZ. +#define CMT_MOTOR 8 // Motor on/off. + +// Names of the supported machines. +// +static const char *MZMACHINES[MAX_MZMACHINES] = { "MZ80K", "MZ80C", "MZ1200", "MZ80A", "MZ700", "MZ800", "MZ80B", "MZ2000" }; + +// Default load addresses of roms. +// +static const unsigned int MZLOADADDR[MAX_IMAGE_TYPES][MAX_MZMACHINES] = + { + { 0x00000, 0x03800, 0x07000, 0x0A800, 0x0E000, 0x11800, 0x15000, 0x17800 }, // MROM + { 0x01000, 0x04800, 0x08000, 0x0B800, 0x0F000, 0x12800, 0x15800, 0x18000 }, // MROM 80C + { 0x70000, 0x71000, 0x72000, 0x73000, 0x74000, 0x75000, 0x76000, 0x77000 }, // CGROM + { 0x30000, 0x30100, 0x30200, 0x30300, 0x30400, 0x30500, 0x30600, 0x30700 }, // KEYMAP + { 0x02000, 0x05800, 0x09000, 0x0C800, 0x10000, 0x13800, 0x16000, 0x18800 }, // USERROM + { 0x02800, 0x06000, 0x09800, 0x0D000, 0x10800, 0x14000, 0x16800, 0x19000 } // FDCROM + }; + +// Default size of roms. +// +static const unsigned int MZLOADSIZE[MAX_IMAGE_TYPES][MAX_MZMACHINES] = + { + { 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800 }, // MROM + { 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800 }, // MROM 80C + { 0x0800, 0x0800, 0x0800, 0x0800, 0x1000, 0x0800, 0x0800, 0x0800 }, // CGROM + { 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100 }, // KEYMAP + { 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800 }, // USERROM + { 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000 } // FDCROM + }; + +static const unsigned int MZBANKSIZE[SHARPMZ_MEMBANK_MAXBANKS] = { 0x20000, 0x0000, 0x10000, 0x00800, 0x04000, 0x00080, 0x10000, 0x08000, 0x08000 }; + +#if !defined(MENU_H) && !defined(USER_IO_H) +// Lookup tables for menu entries. +// +const char *SHARPMZ_FAST_TAPE[] = { "Off", "2x", "4x", "8x", "16x", "32x", "Off", "Off", + "Off", "2x", "4x", "8x", "16x", "32x", "Off", "Off", + "Off", "2x", "4x", "8x", "16x", "Off", "Off", "Off" + }; +const char *SHARPMZ_CPU_SPEED[] = { "2MHz", "4MHz", "8MHz", "16MHz", "32MHz", "64MHz", "2MHz", "2MHz", + "3.5MHz", "7MHz", "14MHz", "28MHz", "56MHz", "112MHz", "3.5MHz", "3.5MHz", + "4MHz", "8MHz", "16MHz", "32MHz", "64MHz", "4MHz", "4MHz", "4MHz" + }; +const char *SHARPMZ_TAPE_BUTTONS[] = { "Off", "Play", "Record", "Auto" }; +const char *SHARPMZ_AUDIO_SOURCE[] = { "Sound", "Tape" }; +const char *SHARPMZ_AUDIO_VOLUME[] = { "Max", "14", "13", "12", "11", "10", "9", "8", "7", "6", "5", "4", "3", "2", "1", "Min" }; +const char *SHARPMZ_AUDIO_MUTE[] = { "Off", "Mute" }; +const char *SHARPMZ_USERROM_ENABLED[] = { "Disabled", "Enabled" }; +const char *SHARPMZ_FDCROM_ENABLED[] = { "Disabled", "Enabled" }; +const char *SHARPMZ_ROM_ENABLED[] = { "Disabled", "Enabled" }; +const char *SHARPMZ_AUTO_SAVE_ENABLED[] = { "No", "Yes" }; +const char *SHARPMZ_DISPLAY_TYPE[] = { "Mono 40x25", "Mono 80x25 ", "Colour 40x25", "Colour 80x25", "tbd3", "tbd4", "tbd5", "tbd6" }; +const char *SHARPMZ_ASPECT_RATIO[] = { "4:3", "16:9" }; +const char *SHARPMZ_SCANDOUBLER_FX[] = { "None", "HQ2x", "CRT 25%", "CRT 50%", "CRT 75%", "tbd1", "tbd2", "tbd3" }; +const char *SHARPMZ_VRAMWAIT_MODE[] = { "Off", "On" }; +const char *SHARPMZ_VRAMDISABLE_MODE[] = { "Enabled", "Disabled" }; +const char *SHARPMZ_GRAMDISABLE_MODE[] = { "Enabled", "Disabled" }; +const char *SHARPMZ_PCG_MODE[] = { "ROM", "RAM" }; +const char *SHARPMZ_MACHINE_MODEL[] = { "MZ80K", "MZ80C", "MZ1200", "MZ80A", "MZ700", "MZ800", "MZ80B", "MZ2000" }; +const char *SHARPMZ_DEBUG_ENABLE[] = { "Off", "On" }; +const char *SHARPMZ_DEBUG_LEDS[] = { "Off", "On" }; +const char *SHARPMZ_DEBUG_LEDS_BANK[] = { "T80", "I/O", "IOCTL", "Config", "MZ80C I", "MZ80C II", "MZ80B I", "MZ80B II" }; +const char *SHARPMZ_DEBUG_LEDS_SUBBANK[] = { "Auto", "A7-0", "A15-8", "DI", "Signals", "", "", "", + "Auto", "Video", "PS2Key", "Signals", "", "", "", "", + "Auto", "A23-16", "A15-8", "A7-0", "Signals", "", "", "", + "Auto", "Config 1", "Config 2", "Config 3", "Config 4", "Config 5", "", "", + "Auto", "CS 1", "CS 2", "CS 3", "INT/RE", "Clk", "", "", + "Auto", "CMT 1", "CMT 2", "CMT 3", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + }; +const char *SHARPMZ_DEBUG_CPUFREQ[] = { "CPU/CMT", "1MHz", "100KHz", "10KHz", "5KHz", "1KHz", "500Hz", "100Hz", "50Hz", "10Hz", "5Hz", "2Hz", "1Hz", "0.5Hz", "0.2Hz", "0.1Hz" }; +const char *SHARPMZ_DEBUG_LEDS_SMPFREQ[] = { "CPU/CMT", "1MHz", "100KHz", "10KHz", "5KHz", "1KHz", "500Hz", "100Hz", "50Hz", "10Hz", "5Hz", "2Hz", "1Hz", "0.5Hz", "0.2Hz", "0.1Hz" }; +const char *SHARPMZ_MEMORY_BANK[] = { "SysROM", "SysRAM", "KeyMap", "VRAM", "CMTHDR", "CMTDATA", "CGROM", "CGRAM", "All" }; +const char *SHARPMZ_MEMORY_BANK_FILE[] = { "sysrom.dump", "sysram.dump", "keymap.dump", "vram.dump", "cmt_hdr.dump", "cmt_data.dump", "cgrom.dump", "cgram.dump", "all_memory.dump" }; +const char *SHARPMZ_TAPE_TYPE[] = { "N/A", "M/code", "MZ80 Basic", "MZ80 Data", "MZ700 Data", "MZ700 Basic", "N/A" }; +const char *SHARPMZ_HELPTEXT[] = { "Welcome to the Sharp MZ Series! Use the cursor keys to navigate the menus. Use space bar or enter to select an item. Press Esc or F12 to exit the menus. ", + 0 + }; +#else +// External definitions. +extern const char *SHARPMZ_FAST_TAPE[]; +extern const char *SHARPMZ_TAPE_BUTTONS[]; +extern const char *SHARPMZ_AUDIO_SOURCE[]; +extern const char *SHARPMZ_AUDIO_VOLUME[]; +extern const char *SHARPMZ_AUDIO_MUTE[]; +extern const char *SHARPMZ_USERROM_ENABLED[]; +extern const char *SHARPMZ_FDCROM_ENABLED[]; +extern const char *SHARPMZ_ROM_ENABLED[]; +extern const char *SHARPMZ_AUTO_SAVE_ENABLED[]; +extern const char *SHARPMZ_DISPLAY_TYPE[]; +extern const char *SHARPMZ_ASPECT_RATIO[]; +extern const char *SHARPMZ_SCANDOUBLER_FX[]; +extern const char *SHARPMZ_VRAMWAIT_MODE[]; +extern const char *SHARPMZ_VRAMDISABLE_MODE[]; +extern const char *SHARPMZ_GRAMDISABLE_MODE[]; +extern const char *SHARPMZ_PCG_MODE[]; +extern const char *SHARPMZ_MACHINE_MODEL[]; +extern const char *SHARPMZ_CPU_SPEED[]; +extern const char *SHARPMZ_DEBUG_ENABLE[]; +extern const char *SHARPMZ_DEBUG_LEDS[]; +extern const char *SHARPMZ_DEBUG_LEDS_BANK[]; +extern const char *SHARPMZ_DEBUG_CPUFREQ[]; +extern const char *SHARPMZ_DEBUG_LEDS_SMPFREQ[]; +extern const char *SHARPMZ_TAPE_TYPE[]; +extern const char *SHARPMZ_MEMORY_BANK[]; +extern const char *SHARPMZ_MEMORY_BANK_FILE[]; +extern const char *SHARPMZ_HELPTEXT[]; +#endif + +// Structure to store the name, load address and the size of a given rom. +// +typedef struct +{ + char romFileName[MAX_FILENAME_SIZE]; + short romEnabled; + unsigned int loadAddr; + unsigned int loadSize; +} romData_t; + +// Structure to store the configuration data of the emulator. +// +typedef struct +{ + unsigned long system_ctrl; // Original MiSTer system control register. + unsigned char system_reg[MAX_REGISTERS]; // Emulator control register bank. + unsigned char autoSave; // Automatically save tape file if RECORD_READY becomes active. Use filename in header. + unsigned char volume; // Volume setting, using the MiSTer DAC level control. BIt 0-3 = Attenuation, bit 4 = Mute. + romData_t romMonitor[MAX_MZMACHINES][MAX_MROMOPTIONS]; // Details of rom monitor images to upload. + romData_t romCG[MAX_MZMACHINES]; // Details of rom character generator images to upload. + romData_t romKeyMap[MAX_MZMACHINES]; // Details of rom Key mapping images to upload. + romData_t romUser[MAX_MZMACHINES]; // Details of User ROM images to upload. + romData_t romFDC[MAX_MZMACHINES]; // Details of FDC ROM images to upload. +} sharpmz_config_t; + +// Structures to store the tape file queue. +// +typedef struct tape_queue_node tape_queue_node_t; +struct tape_queue_node +{ + char fileName[MAX_FILENAME_SIZE]; + tape_queue_node_t *next; +}; +// +typedef struct +{ + struct tape_queue_node *top; + struct tape_queue_node *bottom; + unsigned short elements; +} tape_queue_t; + +// MZ Series Tape header structure - 128 bytes. +// +typedef struct +{ + unsigned char dataType; // 01 = machine code program. + // 02 MZ-80 Basic program. + // 03 MZ-80 data file. + // 04 MZ-700 data file. + // 05 MZ-700 Basic program. + char fileName[17]; // File name. + unsigned short fileSize; // Size of data partition. + unsigned short loadAddress; // Load address of the program/data. + unsigned short execAddress; // Execution address of program. + unsigned char comment[104]; // Free text or code area. +} sharpmz_tape_header_t; + +// UI state machine states, extension set to the main menu.cpp MENU enum. Values are set above the original enum so that they +// are detected and handle within this sharpmz code base. +// +enum SHARPMZ_MENU +{ + // Sharp MZ menu entries + MENU_SHARPMZ_MAIN1 = 0xa0, + MENU_SHARPMZ_MAIN2 = 0xa1, + MENU_SHARPMZ_TAPE_STORAGE1 = 0xa2, + MENU_SHARPMZ_TAPE_STORAGE2 = 0xa3, + MENU_SHARPMZ_TAPE_STORAGE_LOAD_TAPE_TO_RAM = 0xa4, + MENU_SHARPMZ_TAPE_STORAGE_LOAD_TAPE_TO_RAM2 = 0xa5, + MENU_SHARPMZ_TAPE_STORAGE_QUEUE_TAPE_TO_CMT = 0xa6, + MENU_SHARPMZ_TAPE_STORAGE_QUEUE_TAPE_TO_CMT2 = 0xa7, + MENU_SHARPMZ_TAPE_STORAGE_SAVE_TAPE_FROM_CMT = 0xa8, + MENU_SHARPMZ_TAPE_STORAGE_SAVE_TAPE_FROM_CMT2 = 0xa9, + MENU_SHARPMZ_FLOPPY_STORAGE1 = 0xaa, + MENU_SHARPMZ_FLOPPY_STORAGE2 = 0xab, + MENU_SHARPMZ_DISPLAY1 = 0xb0, + MENU_SHARPMZ_DISPLAY2 = 0xb1, + MENU_SHARPMZ_MACHINE1 = 0xb2, + MENU_SHARPMZ_MACHINE2 = 0xb3, + MENU_SHARPMZ_ROMS1 = 0xb4, + MENU_SHARPMZ_ROMS2 = 0xb5, + MENU_SHARPMZ_ROM_FILE_SELECTED = 0xb6, + MENU_SHARPMZ_DEBUG1 = 0xb7, + MENU_SHARPMZ_DEBUG2 = 0xb8 +}; + +// Prototypes. +// +void sharpmz_reset(unsigned long, unsigned long); +short sharpmz_read_ram(char *, short); +void sharpmz_init(void); +void sharpmz_poll(void); +short sharpmz_read_ram(char *, short); +const char *sharpmz_get_rom_name(void); +void sharpmz_set_config_register(short addr, unsigned char value); +unsigned char sharpmz_read_config_register(short addr); +void sharpmz_send_file(romData_t &, char *); +void sharpmz_set_rom(romData_t *); +int sharpmz_FileRead(fileTYPE *file, void *pBuffer, int nSize); +short sharpmz_get_machine_group(void); +unsigned char sharpmz_get_auto_save_enabled(void); +int sharpmz_get_fasttape(void); +int sharpmz_get_display_type(void); +int sharpmz_get_aspect_ratio(void); +int sharpmz_get_scandoubler_fx(void); +int sharpmz_get_vram_wait_mode(void); +int sharpmz_get_vram_disable_mode(void); +int sharpmz_get_gram_disable_mode(void); +int sharpmz_get_pcg_mode(void); +int sharpmz_get_machine_model(void); +int sharpmz_get_cpu_speed(void); +int sharpmz_get_audio_source(void); +int sharpmz_get_audio_volume(void); +int sharpmz_get_audio_mute(void); +int sharpmz_get_debug_enable(void); +int sharpmz_get_debug_leds(void); +int sharpmz_get_tape_buttons(void); +short sharpmz_get_next_memory_bank(void); +short sharpmz_get_next_debug_leds_bank(void); +short sharpmz_get_next_debug_leds_subbank(unsigned char); +short sharpmz_get_next_debug_cpufreq(void); +short sharpmz_get_next_debug_leds_smpfreq(void); +void sharpmz_set_auto_save_enabled(unsigned char); +void sharpmz_set_fasttape(short, short); +void sharpmz_set_display_type(short, short); +void sharpmz_set_aspect_ratio(short, short); +void sharpmz_set_scandoubler_fx(short, short); +void sharpmz_set_vram_wait_mode(short, short); +void sharpmz_set_vram_disable_mode(short, short); +void sharpmz_set_gram_disable_mode(short, short); +void sharpmz_set_pcg_mode(short, short); +void sharpmz_set_machine_model(short, short); +void sharpmz_set_cpu_speed(short, short); +void sharpmz_set_audio_source(short, short); +void sharpmz_set_audio_volume(short, short); +void sharpmz_set_audio_mute(short, short); +void sharpmz_set_debug_enable(short, short); +void sharpmz_set_debug_leds(short, short); +void sharpmz_set_debug_leds_bank(short, short); +void sharpmz_set_debug_leds_subbank(short, short); +void sharpmz_set_debug_cpufreq(short, short); +void sharpmz_set_debug_leds_smpfreq(short, short); +void sharpmz_set_tape_buttons(short, short); +int sharpmz_save_config(void); +int sharpmz_reset_config(short); +int sharpmz_reload_config(short); +short sharpmz_get_next_machine_model(void); +short sharpmz_get_user_rom_enabled(short); +void sharpmz_set_user_rom_enabled(short, short, short); +short sharpmz_get_fdc_rom_enabled(short); +void sharpmz_set_fdc_rom_enabled(short, short, short); +short sharpmz_get_custom_rom_enabled(short, short); +void sharpmz_set_custom_rom_enabled(short, short, short); +char *sharpmz_get_rom_file(short, short); +void sharpmz_set_rom_file(short, short, char *); +short sharpmz_read_tape_header(const char *); +short sharpmz_load_tape_to_ram(const char *, unsigned char); +short sharpmz_save_tape_from_cmt(const char *); +sharpmz_tape_header_t *sharpmz_get_tape_header(void); +const char *sharpmz_get_auto_save_enabled_string(void); +const char *sharpmz_get_fasttape_string(void); +const char *sharpmz_get_display_type_string(void); +const char *sharpmz_get_aspect_ratio_string(void); +const char *sharpmz_get_scandoubler_fx_string(void); +const char *sharpmz_get_vram_wait_mode_string(void); +const char *sharpmz_get_vram_disable_mode_string(void); +const char *sharpmz_get_gram_disable_mode_string(void); +const char *sharpmz_get_pcg_mode_string(void); +const char *sharpmz_get_machine_model_string(void); +const char *sharpmz_get_cpu_speed_string(void); +const char *sharpmz_get_audio_source_string(void); +const char *sharpmz_get_audio_volume_string(void); +const char *sharpmz_get_audio_mute_string(void); +const char *sharpmz_get_debug_enable_string(void); +const char *sharpmz_get_debug_leds_string(void); +const char *sharpmz_get_debug_leds_bank_string(void); +const char *sharpmz_get_debug_leds_subbank_string(void); +const char *sharpmz_get_debug_cpufreq_string(void); +const char *sharpmz_get_debug_leds_smpfreq_string(void); +const char *sharpmz_get_machine_model_string(short machineModel); +const char *sharpmz_get_machine_model_string(void); +const char *sharpmz_get_user_rom_enabled_string(short); +const char *sharpmz_get_fdc_rom_enabled_string(short); +const char *sharpmz_get_custom_rom_enabled_string(short romEnabled); +const char *sharpmz_get_tape_type_string(void); +const char *sharpmz_get_tape_buttons_string(void); +const char *sharpmz_get_memory_bank_string(short); +const char *sharpmz_get_memory_bank_file(short); +void sharpmz_push_filename(char *); +char *sharpmz_pop_filename(void); +char *sharpmz_get_next_filename(char); +void sharpmz_clear_filelist(void); +void sharpmz_select_file(const char*, unsigned char, char *, char, char *); +int sharpmz_default_ui_state(void); +int sharpmz_ui(int, int, int, int, + unsigned char *, unsigned char *, unsigned char *, unsigned char *, + unsigned int *, char *, const char **, char *, + unsigned char *, unsigned char *, unsigned char *, unsigned char *, + char *, + unsigned char, unsigned char, unsigned char, unsigned char, + unsigned char, unsigned char, unsigned char, unsigned char); +#endif // SHARPMZ_H diff --git a/user_io.cpp b/user_io.cpp index c689545..84593fd 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -12,6 +12,7 @@ #include "osd.h" #include "user_io.h" #include "archie.h" +#include "sharpmz.h" #include "debug.h" #include "st_ikbd.h" #include "spi.h" @@ -96,6 +97,11 @@ char is_archie() return(core_type == CORE_TYPE_ARCHIE); } +char is_sharpmz() +{ + return(core_type == CORE_TYPE_SHARPMZ); +} + char* user_io_create_config_name() { static char str[40]; @@ -129,6 +135,9 @@ const char *user_io_get_core_name_ex() case CORE_TYPE_ARCHIE: return "ARCHIE"; + case CORE_TYPE_SHARPMZ: + return "SHARPMZ"; + case CORE_TYPE_8BIT: return core_name; } @@ -412,7 +421,8 @@ void user_io_init(const char *path) (core_type != CORE_TYPE_MINIMIG2) && (core_type != CORE_TYPE_MIST) && (core_type != CORE_TYPE_ARCHIE) && - (core_type != CORE_TYPE_8BIT)) + (core_type != CORE_TYPE_8BIT) && + (core_type != CORE_TYPE_SHARPMZ)) { core_type = CORE_TYPE_UNKNOWN; fio_size = 0; @@ -468,6 +478,13 @@ void user_io_init(const char *path) parse_config(); break; + case CORE_TYPE_SHARPMZ: + puts("Identified Sharp MZ Series core"); + sharpmz_init(); + user_io_read_core_name(); + parse_config(); + break; + case CORE_TYPE_8BIT: // try to load config name = user_io_create_config_name(); @@ -1423,6 +1440,7 @@ void user_io_poll() if ((core_type != CORE_TYPE_MINIMIG2) && (core_type != CORE_TYPE_MIST) && (core_type != CORE_TYPE_ARCHIE) && + (core_type != CORE_TYPE_SHARPMZ) && (core_type != CORE_TYPE_8BIT)) { return; // no user io for the installed core @@ -1786,6 +1804,7 @@ void user_io_poll() } if (core_type == CORE_TYPE_ARCHIE) archie_poll(); + if (core_type == CORE_TYPE_SHARPMZ) sharpmz_poll(); static uint8_t leds = 0; if(use_ps2ctl && core_type != CORE_TYPE_MINIMIG2) @@ -2162,6 +2181,29 @@ static void send_keycode(unsigned short key, int press) if (!press) code |= 0x8000; archie_kbd(code); } + + if (core_type == CORE_TYPE_SHARPMZ) + { + uint32_t code = get_ps2_code(key); + if (code == NONE) return; + + { + if (press > 1 && !use_ps2ctl) return; + + spi_uio_cmd_cont(UIO_KEYBOARD); + + // prepend extended code flag if required + if (code & EXT) spi8(0xe0); + + // prepend break code if required + if (!press) spi8(0xf0); + + // send code itself + spi8(code & 0xff); + + DisableIO(); + } + } } void user_io_mouse(unsigned char b, int16_t x, int16_t y) @@ -2305,6 +2347,7 @@ void user_io_kbd(uint16_t key, int press) if ((core_type == CORE_TYPE_MINIMIG2) || (core_type == CORE_TYPE_MIST) || (core_type == CORE_TYPE_ARCHIE) || + (core_type == CORE_TYPE_SHARPMZ) || (core_type == CORE_TYPE_8BIT)) { if (key) diff --git a/user_io.h b/user_io.h index 8ed6433..12ed9d6 100644 --- a/user_io.h +++ b/user_io.h @@ -130,6 +130,7 @@ #define CORE_TYPE_8BIT 0xa4 // atari 800/c64 like core #define CORE_TYPE_MINIMIG2 0xa5 // new Minimig with AGA #define CORE_TYPE_ARCHIE 0xa6 // Acorn Archimedes +#define CORE_TYPE_SHARPMZ 0xa7 // Sharp MZ Series #define UART_FLG_PPP 0x0001 #define UART_FLG_TERM 0x0002 @@ -176,6 +177,7 @@ void user_io_init(const char *path); unsigned char user_io_core_type(); char is_minimig(); char is_archie(); +char is_sharpmz(); void user_io_poll(); char user_io_menu_button(); char user_io_button_dip_switch1();