├── tile.png ├── tile.raw ├── .gitignore ├── GO-KB-C64-map.png ├── main ├── ui.h ├── component.mk └── main.cpp ├── assets ├── image_keyboard_error.png ├── baseline_keyboard_black_48dp.png └── baseline_error_outline_black_48dp.png ├── components ├── ugui │ ├── ugui_config.h.gch │ ├── component.mk │ ├── .gitignore │ ├── README.md │ ├── ugui_config.h │ └── LICENSE.md ├── odroid │ ├── odroid_audio.h.gch │ ├── odroid_input.h.gch │ ├── odroid_sdcard.h.gch │ ├── odroid_system.h.gch │ ├── odroid_display.h.gch │ ├── odroid_settings.h.gch │ ├── odroid_system.h │ ├── odroid_sdcard.h │ ├── component.mk │ ├── odroid_audio.h │ ├── odroid_settings.h │ ├── odroid_input.h │ ├── odroid_display.h │ ├── odroid_keyboard.h │ ├── odroid_system.c │ ├── odroid_audio.c │ ├── odroid_sdcard.c │ ├── odroid_settings.c │ └── odroid_input.c └── frodo │ ├── SAM.h │ ├── Version.h │ ├── component.mk │ ├── main.h │ ├── REU.h │ ├── 1541fs.h │ ├── 1541t64.h │ ├── Display.h │ ├── ndir.h │ ├── CPU_common.h │ ├── 1541job.h │ ├── SID.h │ ├── 1541d64.h │ ├── sysdeps.h │ ├── IEC.h │ ├── Prefs.h │ ├── CPU_common.cpp │ ├── main.cpp │ ├── SID.cpp │ ├── DigitalRenderer.h │ ├── CIA.h │ ├── ndir.c │ ├── sysconfig.h │ ├── REU.cpp │ ├── CPUC64.h │ ├── C64.h │ ├── CPU1541.h │ ├── VIC.h │ ├── IEC.cpp │ ├── 1541job.cpp │ ├── FixPoint.i │ └── CIA.cpp ├── flashapp.sh ├── pack.sh ├── Makefile ├── partitions.csv └── README.md /tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/tile.png -------------------------------------------------------------------------------- /tile.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/tile.raw -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | sdkconfig.old 3 | .vscode/ 4 | mkfw 5 | Frodo.fw 6 | roms/ 7 | -------------------------------------------------------------------------------- /GO-KB-C64-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/GO-KB-C64-map.png -------------------------------------------------------------------------------- /main/ui.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | const char* ui_choosefile(const char* path, const char* current); 4 | -------------------------------------------------------------------------------- /assets/image_keyboard_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/assets/image_keyboard_error.png -------------------------------------------------------------------------------- /components/ugui/ugui_config.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/components/ugui/ugui_config.h.gch -------------------------------------------------------------------------------- /components/odroid/odroid_audio.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/components/odroid/odroid_audio.h.gch -------------------------------------------------------------------------------- /components/odroid/odroid_input.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/components/odroid/odroid_input.h.gch -------------------------------------------------------------------------------- /components/odroid/odroid_sdcard.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/components/odroid/odroid_sdcard.h.gch -------------------------------------------------------------------------------- /components/odroid/odroid_system.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/components/odroid/odroid_system.h.gch -------------------------------------------------------------------------------- /assets/baseline_keyboard_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/assets/baseline_keyboard_black_48dp.png -------------------------------------------------------------------------------- /components/odroid/odroid_display.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/components/odroid/odroid_display.h.gch -------------------------------------------------------------------------------- /components/odroid/odroid_settings.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/components/odroid/odroid_settings.h.gch -------------------------------------------------------------------------------- /flashapp.sh: -------------------------------------------------------------------------------- 1 | . ${IDF_PATH}/add_path.sh 2 | esptool.py --chip esp32 --port "/dev/ttyUSB0" --baud 921600 write_flash 0x100000 build/frodo-go.bin 3 | -------------------------------------------------------------------------------- /assets/baseline_error_outline_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtherCrashOverride/frodo-go/HEAD/assets/baseline_error_outline_black_48dp.png -------------------------------------------------------------------------------- /pack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm Frodo.fw 3 | TITLE="Frodo ($(date +%Y%m%d))" 4 | ./mkfw "$TITLE" tile.raw 0 16 2097152 frodo build/frodo-go.bin 5 | mv firmware.fw Frodo.fw 6 | 7 | -------------------------------------------------------------------------------- /components/odroid/odroid_system.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void odroid_system_application_set(int slot); 4 | void odroid_system_sleep(); 5 | void odroid_system_init(); 6 | void odroid_system_led_set(int value); 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := frodo-go 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | -------------------------------------------------------------------------------- /components/frodo/SAM.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SAM.h - Simple Assembler and Monitor With Integrated System Explorer 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _SAM_H 8 | #define _SAM_H 9 | 10 | class C64; 11 | 12 | // Exported functions 13 | extern void SAM(C64 *the_c64); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /components/frodo/Version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Version.h - Version information 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _VERSION_H 8 | #define _VERSION_H 9 | 10 | // Version/revision 11 | const int FRODO_VERSION = 4; 12 | const int FRODO_REVISION = 1; 13 | const char VERSION_STRING[] = "Frodo V4.1b"; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | nvs, data, nvs, 0x9000, 0x4000 4 | otadata, data, ota, 0xd000, 0x2000 5 | phy_init, data, phy, 0xf000, 0x1000 6 | factory, app, factory, 0x10000, 0x200000 7 | -------------------------------------------------------------------------------- /components/ugui/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /components/odroid/odroid_sdcard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esp_err.h" 4 | 5 | 6 | esp_err_t odroid_sdcard_open(const char* base_path); 7 | esp_err_t odroid_sdcard_close(); 8 | size_t odroid_sdcard_get_filesize(const char* path); 9 | size_t odroid_sdcard_copy_file_to_memory(const char* path, void* ptr); 10 | char* odroid_sdcard_create_savefile_path(const char* base_path, const char* fileName); 11 | -------------------------------------------------------------------------------- /components/ugui/.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | *.exe 3 | *.bak 4 | *bak 5 | *bck 6 | *~ 7 | 8 | *.pdf 9 | 10 | #kicad temp files 11 | *-cache.lib 12 | *.net 13 | _autosave* 14 | 15 | # gerber files: 16 | *.grb 17 | *.gbr 18 | *.drl 19 | 20 | # platformio temporaries: 21 | .pioenvs 22 | .clang_complete 23 | .gcc-flags.json 24 | 25 | 26 | #Qt 27 | *.user 28 | *.user.* 29 | *.autosave 30 | 31 | .travis.yml 32 | 33 | # build directories 34 | b/ 35 | build/ 36 | 37 | -------------------------------------------------------------------------------- /components/frodo/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Component Makefile 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | 10 | #CFLAGS := 11 | #COMPONENT_DEPENDS := 12 | #COMPONENT_ADD_INCLUDEDIRS := . 13 | #COMPONENT_SRCDIRS := . 14 | -------------------------------------------------------------------------------- /components/odroid/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Component Makefile 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | 10 | #CFLAGS := 11 | #COMPONENT_DEPENDS := 12 | #COMPONENT_ADD_INCLUDEDIRS := . 13 | #COMPONENT_SRCDIRS := . 14 | -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | COMPILEDATE:=\"$(shell date "+%Y%m%d")\" 10 | GITREV:=\"$(shell git rev-parse HEAD | cut -b 1-10)\" 11 | 12 | CPPFLAGS += -DCOMPILEDATE="$(COMPILEDATE)" -DGITREV="$(GITREV)" -------------------------------------------------------------------------------- /components/odroid/odroid_audio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #define ODROID_VOLUME_LEVEL_COUNT (5) 5 | 6 | typedef enum 7 | { 8 | ODROID_VOLUME_LEVEL0 = 0, 9 | ODROID_VOLUME_LEVEL1 = 1, 10 | ODROID_VOLUME_LEVEL2 = 2, 11 | ODROID_VOLUME_LEVEL3 = 3, 12 | ODROID_VOLUME_LEVEL4 = 4, 13 | 14 | _ODROID_VOLUME_FILLER = 0xffffffff 15 | } odroid_volume_level; 16 | 17 | 18 | odroid_volume_level odroid_audio_volume_get(); 19 | void odroid_audio_volume_set(odroid_volume_level value); 20 | void odroid_audio_volume_change(); 21 | void odroid_audio_init(int sample_rate); 22 | void odroid_audio_terminate(); 23 | void odroid_audio_submit(short* stereoAudioBuffer, int frameCount); 24 | void odroid_audio_submit_zero(); 25 | int odroid_audio_sample_rate_get(); 26 | -------------------------------------------------------------------------------- /components/frodo/main.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | /* 3 | * main.h - Main program 4 | * 5 | * Frodo (C) 1994-1997,2002 Christian Bauer 6 | */ 7 | 8 | #ifndef _MAIN_H 9 | #define _MAIN_H 10 | 11 | 12 | class C64; 13 | 14 | // Global variables 15 | //extern char AppDirPath[1024]; // Path of application directory 16 | 17 | 18 | 19 | /* 20 | * X specific stuff 21 | */ 22 | 23 | #if 1 24 | 25 | class Prefs; 26 | 27 | class Frodo { 28 | public: 29 | Frodo(); 30 | void ArgvReceived(int argc, char **argv); 31 | void ReadyToRun(void); 32 | static Prefs *reload_prefs(void); 33 | 34 | C64 *TheC64; 35 | 36 | private: 37 | bool load_rom_files(void); 38 | 39 | static char prefs_path[256]; // Pathname of current preferences file 40 | }; 41 | 42 | #endif 43 | 44 | #endif 45 | #endif -------------------------------------------------------------------------------- /components/frodo/REU.h: -------------------------------------------------------------------------------- 1 | /* 2 | * REU.h - 17xx REU emulation 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _REU_H 8 | #define _REU_H 9 | 10 | 11 | class MOS6510; 12 | class Prefs; 13 | 14 | class REU { 15 | public: 16 | REU(MOS6510 *CPU); 17 | ~REU(); 18 | 19 | void NewPrefs(Prefs *prefs); 20 | void Reset(void); 21 | uint8 ReadRegister(uint16 adr); 22 | void WriteRegister(uint16 adr, uint8 byte); 23 | void FF00Trigger(void); 24 | 25 | private: 26 | void open_close_reu(int old_size, int new_size); 27 | void execute_dma(void); 28 | 29 | MOS6510 *the_cpu; // Pointer to 6510 30 | 31 | uint8 *ex_ram; // REU expansion RAM 32 | 33 | uint32 ram_size; // Size of expansion RAM 34 | uint32 ram_mask; // Expansion RAM address bit mask 35 | 36 | uint8 regs[16]; // REU registers 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /components/odroid/odroid_settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | char* odroid_util_GetFileName(const char* path); 6 | char* odroid_util_GetFileExtenstion(const char* path); 7 | char* odroid_util_GetFileNameWithoutExtension(const char* path); 8 | 9 | 10 | int32_t odroid_settings_VRef_get(); 11 | void odroid_settings_VRef_set(int32_t value); 12 | 13 | int32_t odroid_settings_Volume_get(); 14 | void odroid_settings_Volume_set(int32_t value); 15 | 16 | char* odroid_settings_RomFilePath_get(); 17 | void odroid_settings_RomFilePath_set(char* value); 18 | 19 | int32_t odroid_settings_AppSlot_get(); 20 | void odroid_settings_AppSlot_set(int32_t value); 21 | 22 | int32_t odroid_settings_DataSlot_get(); 23 | void odroid_settings_DataSlot_set(int32_t value); 24 | 25 | int32_t odroid_settings_Backlight_get(); 26 | void odroid_settings_Backlight_set(int32_t value); 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # frodo-go 2 | Commodore 64 emulation for ODROID-GO 3 | 4 | To use, you will need to do the following steps: 5 | 6 | 1) Purchase and receive the ODROID-GO QWERTY Keyboard which is required for this emulator. 7 | 8 | 2) Create the below directory on your SD card. 9 | ``` 10 | /roms/c64/ 11 | ``` 12 | 3) Place the following 4 BIOS files in the /roms/c64/ directory, named exactly as shown. 13 | ``` 14 | 1541.ROM 15 | Basic.ROM 16 | Char.ROM 17 | Kernal.ROM 18 | ``` 19 | 4) Place your .D64 files in the /roms/c64/ directory. Only D64 format is supported at this time. 20 | 21 | # Keyboard Map 22 | Below is the current keyboard mapping graphic for this emulator. 23 | ![QWERTY Map](GO-KB-C64-map.png?raw=true) 24 | 25 | Please note the symbols above the number keys have changed to match the original C64. 26 | 27 | Red means the keys were remapped from what is shown on the actual keyboard. 28 | 29 | Blue means that remapping is only active when Fn-lock is on. 30 | 31 | H = "HOME / CLR" 32 | 33 | RE = "RESTORE" 34 | 35 | RS = "Right Shift" 36 | -------------------------------------------------------------------------------- /components/odroid/odroid_input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | #define ODROID_GAMEPAD_IO_X ADC1_CHANNEL_6 7 | #define ODROID_GAMEPAD_IO_Y ADC1_CHANNEL_7 8 | #define ODROID_GAMEPAD_IO_SELECT GPIO_NUM_27 9 | #define ODROID_GAMEPAD_IO_START GPIO_NUM_39 10 | #define ODROID_GAMEPAD_IO_A GPIO_NUM_32 11 | #define ODROID_GAMEPAD_IO_B GPIO_NUM_33 12 | #define ODROID_GAMEPAD_IO_MENU GPIO_NUM_13 13 | #define ODROID_GAMEPAD_IO_VOLUME GPIO_NUM_0 14 | 15 | 16 | enum 17 | { 18 | ODROID_INPUT_UP = 0, 19 | ODROID_INPUT_RIGHT, 20 | ODROID_INPUT_DOWN, 21 | ODROID_INPUT_LEFT, 22 | ODROID_INPUT_SELECT, 23 | ODROID_INPUT_START, 24 | ODROID_INPUT_A, 25 | ODROID_INPUT_B, 26 | ODROID_INPUT_MENU, 27 | ODROID_INPUT_VOLUME, 28 | 29 | ODROID_INPUT_MAX 30 | }; 31 | 32 | typedef struct 33 | { 34 | uint8_t values[ODROID_INPUT_MAX]; 35 | } odroid_gamepad_state; 36 | 37 | typedef struct 38 | { 39 | int millivolts; 40 | int percentage; 41 | } odroid_battery_state; 42 | 43 | void odroid_input_gamepad_init(); 44 | void odroid_input_gamepad_terminate(); 45 | void odroid_input_gamepad_read(odroid_gamepad_state* out_state); 46 | odroid_gamepad_state odroid_input_read_raw(); 47 | 48 | void odroid_input_battery_level_init(); 49 | void odroid_input_battery_level_read(odroid_battery_state* out_state); 50 | void odroid_input_battery_level_force_voltage(float volts); 51 | void odroid_input_battery_monitor_enabled_set(int value); 52 | -------------------------------------------------------------------------------- /components/frodo/1541fs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 1541fs.h - 1541 emulation in host file system 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _1541FS_H 8 | #define _1541FS_H 9 | 10 | #include "IEC.h" 11 | 12 | 13 | class FSDrive : public Drive { 14 | public: 15 | FSDrive(IEC *iec, char *path); 16 | virtual ~FSDrive(); 17 | virtual uint8 Open(int channel, char *filename); 18 | virtual uint8 Close(int channel); 19 | virtual uint8 Read(int channel, uint8 *byte); 20 | virtual uint8 Write(int channel, uint8 byte, bool eoi); 21 | virtual void Reset(void); 22 | 23 | private: 24 | bool change_dir(char *dirpath); 25 | uint8 open_file(int channel, char *filename); 26 | uint8 open_directory(int channel, char *filename); 27 | void convert_filename(char *srcname, char *destname, int *filemode, int *filetype, bool *wildflag); 28 | void find_first_file(char *name); 29 | void close_all_channels(void); 30 | void execute_command(char *command); 31 | void chdir_cmd(char *dirpath); 32 | uint8 conv_from_64(uint8 c, bool map_slash); 33 | uint8 conv_to_64(uint8 c, bool map_slash); 34 | 35 | char dir_path[256]; // Path to directory 36 | char orig_dir_path[256]; // Original directory path 37 | char dir_title[16]; // Directory title 38 | FILE *file[16]; // File pointers for each of the 16 channels 39 | 40 | char cmd_buffer[44]; // Buffer for incoming command strings 41 | int cmd_len; // Length of received command 42 | 43 | uint8 read_char[16]; // Buffers for one-byte read-ahead 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /components/ugui/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | ## What is µGUI? 3 | µGUI is a free and open source graphic library for embedded systems. It is platform-independent 4 | and can be easily ported to almost any microcontroller system. As long as the display is capable 5 | of showing graphics, µGUI is not restricted to a certain display technology. Therefore, display 6 | technologies such as LCD, TFT, E-Paper, LED or OLED are supported. The whole module 7 | consists of three files: **ugui.c**, **ugui.h** and **ugui_config.h**. 8 | 9 | ## µGUI Features 10 | * µGUI supports any color, grayscale or monochrome display 11 | * µGUI supports any display resolution 12 | * µGUI supports multiple different displays 13 | * µGUI supports any touch screen technology (e.g. AR, PCAP) 14 | * µGUI supports windows and objects (e.g. button, textbox) 15 | * µGUI supports platform-specific hardware acceleration 16 | * 16 different fonts available 17 | * cyrillic fonts supported 18 | * TrueType font converter available ([https://github.com/AriZuu](https://github.com/AriZuu)) 19 | * integrated and free scalable system console 20 | * basic geometric functions (e.g. line, circle, frame etc.) 21 | * can be easily ported to almost any microcontroller system 22 | * no risky dynamic memory allocation required 23 | 24 | ## µGUI Requirements 25 | µGUI is platform-independent, so there is no need to use a certain embedded system. In order to 26 | use µGUI, only two requirements are necessary: 27 | * a C-function which is able to control pixels of the target display. 28 | * integer types for the target platform have to be adjusted in ugui_config.h. 29 | -------------------------------------------------------------------------------- /components/odroid/odroid_display.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum ODROID_SD_ERR { 6 | ODROID_SD_ERR_BADFILE = 0x01, 7 | ODROID_SD_ERR_NOCARD = 0x02 8 | }; 9 | 10 | void ili9341_write_frame_gb(uint16_t* buffer, int scale); 11 | void ili9341_init(); 12 | void ili9341_poweroff(); 13 | void ili9341_prepare(); 14 | void send_reset_drawing(int left, int top, int width, int height); 15 | void send_continue_wait(); 16 | void send_continue_line(uint16_t *line, int width, int lineCount); 17 | 18 | void ili9341_write_frame_sms(uint8_t* buffer, uint16_t color[], uint8_t isGameGear, uint8_t scale); 19 | void ili9341_write_frame_nes(uint8_t* buffer, uint16_t* myPalette, uint8_t scale); 20 | 21 | void backlight_percentage_set(int value); 22 | //void ili9341_write_frame(uint16_t* buffer); 23 | void ili9341_write_frame_rectangle(short left, short top, short width, short height, uint16_t* buffer); 24 | void ili9341_clear(uint16_t color); 25 | void ili9341_write_frame_rectangleLE(short left, short top, short width, short height, uint16_t* buffer); 26 | void display_tasktonotify_set(int value); 27 | 28 | int is_backlight_initialized(); 29 | void odroid_display_show_splash(); 30 | void odroid_display_drain_spi(); 31 | void odroid_display_lock_gb_display(); 32 | void odroid_display_unlock_gb_display(); 33 | void odroid_display_show_sderr(int errNum); 34 | void odroid_display_show_hourglass(); 35 | void odroid_display_lock_nes_display(); 36 | void odroid_display_unlock_nes_display(); 37 | void odroid_display_lock_sms_display(); 38 | void odroid_display_unlock_sms_display(); 39 | 40 | void ili9341_write_frame_lnx(uint16_t* buffer); 41 | void ili9341_write_frame_atari2600(uint8_t* buffer, uint16_t* palette, uint8_t isPal); 42 | void ili9341_write_frame_atari7800(uint8_t* buffer, uint16_t* palette); 43 | 44 | void odroid_display_lock(); 45 | void odroid_display_unlock(); 46 | void ili9341_write_frame_c64(uint8_t* buffer, uint16_t* palette); 47 | -------------------------------------------------------------------------------- /components/ugui/ugui_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __UGUI_CONFIG_H 2 | #define __UGUI_CONFIG_H 3 | 4 | #include "stdint.h" 5 | 6 | /* -------------------------------------------------------------------------------- */ 7 | /* -- CONFIG SECTION -- */ 8 | /* -------------------------------------------------------------------------------- */ 9 | 10 | //#define USE_MULTITASKING 11 | 12 | /* Enable color mode */ 13 | //#define USE_COLOR_RGB888 // RGB = 0xFF,0xFF,0xFF 14 | #define USE_COLOR_RGB565 // RGB = 0bRRRRRGGGGGGBBBBB 15 | 16 | /* Enable needed fonts here */ 17 | #define USE_FONT_4X6 18 | #define USE_FONT_5X8 19 | #define USE_FONT_5X12 20 | #define USE_FONT_6X8 21 | #define USE_FONT_6X10 22 | #define USE_FONT_7X12 23 | #define USE_FONT_8X8 24 | //#define USE_FONT_8X12_CYRILLIC 25 | #define USE_FONT_8X12 26 | #define USE_FONT_8X12 27 | #define USE_FONT_8X14 28 | #define USE_FONT_10X16 29 | #define USE_FONT_12X16 30 | #define USE_FONT_12X20 31 | #define USE_FONT_16X26 32 | #define USE_FONT_22X36 33 | #define USE_FONT_24X40 34 | #define USE_FONT_32X53 35 | 36 | /* Specify platform-dependent integer types here */ 37 | 38 | #define __UG_FONT_DATA const 39 | typedef uint8_t UG_U8; 40 | typedef int8_t UG_S8; 41 | typedef uint16_t UG_U16; 42 | typedef int16_t UG_S16; 43 | typedef uint32_t UG_U32; 44 | typedef int32_t UG_S32; 45 | 46 | 47 | /* Example for dsPIC33 48 | typedef unsigned char UG_U8; 49 | typedef signed char UG_S8; 50 | typedef unsigned int UG_U16; 51 | typedef signed int UG_S16; 52 | typedef unsigned long int UG_U32; 53 | typedef signed long int UG_S32; 54 | */ 55 | 56 | /* -------------------------------------------------------------------------------- */ 57 | /* -------------------------------------------------------------------------------- */ 58 | 59 | 60 | /* Feature enablers */ 61 | #define USE_PRERENDER_EVENT 62 | #define USE_POSTRENDER_EVENT 63 | 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /components/frodo/1541t64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 1541t64.h - 1541 emulation in .t64/LYNX file 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _1541T64_H 8 | #define _1541T64_H 9 | 10 | #include "IEC.h" 11 | 12 | 13 | // Information for file inside a .t64 file 14 | typedef struct { 15 | char name[17]; // File name, PETSCII 16 | uint8 type; // File type 17 | uint8 sa_lo, sa_hi; // Start address 18 | int offset; // Offset of first byte in .t64 file 19 | int length; // Length of file 20 | } FileInfo; 21 | 22 | 23 | class T64Drive : public Drive { 24 | public: 25 | T64Drive(IEC *iec, char *filepath); 26 | virtual ~T64Drive(); 27 | virtual uint8 Open(int channel, char *filename); 28 | virtual uint8 Close(int channel); 29 | virtual uint8 Read(int channel, uint8 *byte); 30 | virtual uint8 Write(int channel, uint8 byte, bool eoi); 31 | virtual void Reset(void); 32 | 33 | private: 34 | void open_close_t64_file(char *t64name); 35 | bool parse_t64_file(void); 36 | bool parse_lynx_file(void); 37 | uint8 open_file(int channel, char *filename); 38 | uint8 open_directory(int channel, char *filename); 39 | void convert_filename(char *srcname, char *destname, int *filemode, int *filetype); 40 | bool find_first_file(char *name, int type, int *num); 41 | void close_all_channels(void); 42 | void execute_command(char *command); 43 | void cht64_cmd(char *t64path); 44 | uint8 conv_from_64(uint8 c, bool map_slash); 45 | 46 | FILE *the_file; // File pointer for .t64 file 47 | bool is_lynx; // Flag: .t64 file is really a LYNX archive 48 | 49 | char orig_t64_name[256]; // Original path of .t64 file 50 | char dir_title[16]; // Directory title 51 | FILE *file[16]; // File pointers for each of the 16 channels (all temporary files) 52 | 53 | int num_files; // Number of files in .t64 file and in file_info array 54 | FileInfo *file_info; // Pointer to array of file information structs for each file 55 | 56 | char cmd_buffer[44]; // Buffer for incoming command strings 57 | int cmd_len; // Length of received command 58 | 59 | uint8 read_char[16]; // Buffers for one-byte read-ahead 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /components/frodo/Display.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Display.h - C64 graphics display, emulator window handling 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _DISPLAY_H 8 | #define _DISPLAY_H 9 | 10 | #ifdef __BEOS__ 11 | #include 12 | #endif 13 | 14 | #ifdef AMIGA 15 | #include 16 | #endif 17 | 18 | #ifdef HAVE_SDL 19 | struct SDL_Surface; 20 | #endif 21 | 22 | #ifdef WIN32 23 | #include 24 | #endif 25 | 26 | #ifdef __riscos__ 27 | #include "ROlib.h" 28 | #endif 29 | 30 | 31 | // Display dimensions 32 | #if defined(SMALL_DISPLAY) 33 | const int DISPLAY_X = 0x168; 34 | const int DISPLAY_Y = 0x110; 35 | #else 36 | const int DISPLAY_X = 0x180; 37 | const int DISPLAY_Y = 0x110; 38 | #endif 39 | 40 | 41 | class C64Window; 42 | class C64Screen; 43 | class C64; 44 | class Prefs; 45 | 46 | // Class for C64 graphics display 47 | class C64Display { 48 | public: 49 | C64Display(C64 *the_c64); 50 | ~C64Display(); 51 | 52 | void Update(void); 53 | void UpdateLEDs(int l0, int l1, int l2, int l3); 54 | void Speedometer(int speed); 55 | uint8 *BitmapBase(void); 56 | int BitmapXMod(void); 57 | #ifdef __riscos__ 58 | void PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick, uint8 *joystick2); 59 | #else 60 | void PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick); 61 | #endif 62 | bool NumLock(void); 63 | void InitColors(uint8 *colors); 64 | void NewPrefs(Prefs *prefs); 65 | 66 | C64 *TheC64; 67 | 68 | 69 | 70 | #if 1 71 | bool quit_requested; 72 | #endif 73 | 74 | private: 75 | int led_state[4]; 76 | int old_led_state[4]; 77 | 78 | 79 | 80 | // #ifdef HAVE_SDL 81 | // char speedometer_string[16]; // Speedometer text 82 | // void draw_string(SDL_Surface *s, int x, int y, const char *str, uint8 front_color, uint8 back_color); 83 | // #endif 84 | 85 | // #ifdef __unix 86 | // void draw_led(int num, int state); // Draw one LED 87 | // static void pulse_handler(...); // LED error blinking 88 | // #endif 89 | 90 | }; 91 | 92 | 93 | // Exported functions 94 | extern long ShowRequester(char *str, char *button1, char *button2 = NULL); 95 | 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /components/frodo/ndir.h: -------------------------------------------------------------------------------- 1 | /* ndir.c - portable directory routines 2 | Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 1, or (at your option) 7 | any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | $Header: /u/src/master/ccvs/windows-NT/ndir.h,v 1.4 1996/01/03 21:15:00 kingdon Exp $ 19 | */ 20 | 21 | /* Everything non trivial in this code is taken from: @(#)msd_dir.c 1.4 22 | 87/11/06. A public domain implementation of BSD directory routines 23 | for MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield), 24 | August 1897 */ 25 | 26 | #include /* ino_t definition */ 27 | 28 | #define rewinddir(dirp) seekdir(dirp, 0L) 29 | 30 | /* 255 is said to be big enough for Windows NT. The more elegant 31 | solution would be declaring d_name as one byte long and allocating 32 | it to the actual size needed. */ 33 | #define MAXNAMLEN 255 34 | 35 | struct direct 36 | { 37 | ino_t d_ino; /* a bit of a farce */ 38 | int d_reclen; /* more farce */ 39 | int d_namlen; /* length of d_name */ 40 | char d_name[MAXNAMLEN + 1]; /* garentee null termination */ 41 | }; 42 | 43 | struct _dircontents 44 | { 45 | char *_d_entry; 46 | struct _dircontents *_d_next; 47 | }; 48 | 49 | typedef struct _dirdesc 50 | { 51 | int dd_id; /* uniquely identify each open directory */ 52 | long dd_loc; /* where we are in directory entry is this */ 53 | struct _dircontents *dd_contents; /* pointer to contents of dir */ 54 | struct _dircontents *dd_cp; /* pointer to current position */ 55 | } DIR; 56 | 57 | extern void seekdir (DIR *, long); 58 | extern long telldir (DIR *); 59 | extern DIR *opendir (const char *); 60 | extern void closedir (DIR *); 61 | extern struct direct *readdir (DIR *); 62 | 63 | /* 64 | * Local Variables: 65 | * mode:C 66 | * ChangeLog:ChangeLog 67 | * compile-command:make 68 | * End: 69 | */ 70 | -------------------------------------------------------------------------------- /components/frodo/CPU_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CPU_common.h - Definitions common to 6502/6510 SC emulation 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _CPU_COMMON_H_ 8 | #define _CPU_COMMON_H_ 9 | 10 | 11 | // States for addressing modes/operations (Frodo SC) 12 | enum { 13 | // Read effective address, no extra cycles 14 | A_ZERO=0x18, 15 | A_ZEROX, A_ZEROX1, 16 | A_ZEROY, A_ZEROY1, 17 | A_ABS, A_ABS1, 18 | A_ABSX, A_ABSX1, A_ABSX2, A_ABSX3, 19 | A_ABSY, A_ABSY1, A_ABSY2, A_ABSY3, 20 | A_INDX, A_INDX1, A_INDX2, A_INDX3, 21 | A_INDY, A_INDY1, A_INDY2, A_INDY3, A_INDY4, 22 | 23 | // Read effective address, extra cycle on page crossing 24 | AE_ABSX, AE_ABSX1, AE_ABSX2, 25 | AE_ABSY, AE_ABSY1, AE_ABSY2, 26 | AE_INDY, AE_INDY1, AE_INDY2, AE_INDY3, 27 | 28 | // Read operand and write it back (for RMW instructions), no extra cycles 29 | M_ZERO, 30 | M_ZEROX, M_ZEROX1, 31 | M_ZEROY, M_ZEROY1, 32 | M_ABS, M_ABS1, 33 | M_ABSX, M_ABSX1, M_ABSX2, M_ABSX3, 34 | M_ABSY, M_ABSY1, M_ABSY2, M_ABSY3, 35 | M_INDX, M_INDX1, M_INDX2, M_INDX3, 36 | M_INDY, M_INDY1, M_INDY2, M_INDY3, M_INDY4, 37 | RMW_DO_IT, RMW_DO_IT1, 38 | 39 | // Operations (_I = Immediate/Indirect, _A = Accumulator) 40 | O_LDA, O_LDA_I, O_LDX, O_LDX_I, O_LDY, O_LDY_I, 41 | O_STA, O_STX, O_STY, 42 | O_TAX, O_TXA, O_TAY, O_TYA, O_TSX, O_TXS, 43 | O_ADC, O_ADC_I, O_SBC, O_SBC_I, 44 | O_INX, O_DEX, O_INY, O_DEY, O_INC, O_DEC, 45 | O_AND, O_AND_I, O_ORA, O_ORA_I, O_EOR, O_EOR_I, 46 | O_CMP, O_CMP_I, O_CPX, O_CPX_I, O_CPY, O_CPY_I, 47 | O_BIT, 48 | O_ASL, O_ASL_A, O_LSR, O_LSR_A, O_ROL, O_ROL_A, O_ROR, O_ROR_A, 49 | O_PHA, O_PHA1, O_PLA, O_PLA1, O_PLA2, 50 | O_PHP, O_PHP1, O_PLP, O_PLP1, O_PLP2, 51 | O_JMP, O_JMP1, O_JMP_I, O_JMP_I1, 52 | O_JSR, O_JSR1, O_JSR2, O_JSR3, O_JSR4, 53 | O_RTS, O_RTS1, O_RTS2, O_RTS3, O_RTS4, 54 | O_RTI, O_RTI1, O_RTI2, O_RTI3, O_RTI4, 55 | O_BRK, O_BRK1, O_BRK2, O_BRK3, O_BRK4, O_BRK5, O_BRK5NMI, 56 | O_BCS, O_BCC, O_BEQ, O_BNE, O_BVS, O_BVC, O_BMI, O_BPL, 57 | O_BRANCH_NP, O_BRANCH_BP, O_BRANCH_BP1, O_BRANCH_FP, O_BRANCH_FP1, 58 | O_SEC, O_CLC, O_SED, O_CLD, O_SEI, O_CLI, O_CLV, 59 | O_NOP, 60 | 61 | O_NOP_I, O_NOP_A, 62 | O_LAX, O_SAX, 63 | O_SLO, O_RLA, O_SRE, O_RRA, O_DCP, O_ISB, 64 | O_ANC_I, O_ASR_I, O_ARR_I, O_ANE_I, O_LXA_I, O_SBX_I, 65 | O_LAS, O_SHS, O_SHY, O_SHX, O_SHA, 66 | O_EXT 67 | }; 68 | 69 | 70 | // Addressing mode for each opcode (first part of execution) (Frodo SC) 71 | extern const uint8 ModeTab[256]; 72 | 73 | // Operation for each opcode (second part of execution) (Frodo SC) 74 | extern const uint8 OpTab[256]; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /components/odroid/odroid_keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | typedef enum { 8 | ODROID_KEY_NONE = 0, 9 | 10 | ODROID_KEY_GRAVE_ACCENT = 1, 11 | ODROID_KEY_1, 12 | ODROID_KEY_2, 13 | ODROID_KEY_3, 14 | ODROID_KEY_4, 15 | ODROID_KEY_5, 16 | ODROID_KEY_6, 17 | ODROID_KEY_7, 18 | 19 | ODROID_KEY_8 = 11, 20 | ODROID_KEY_9, 21 | ODROID_KEY_0, 22 | ODROID_KEY_ESCAPE, 23 | ODROID_KEY_Q, 24 | ODROID_KEY_W, 25 | ODROID_KEY_E, 26 | ODROID_KEY_R, 27 | 28 | ODROID_KEY_T = 21, 29 | ODROID_KEY_Y, 30 | ODROID_KEY_U, 31 | ODROID_KEY_I, 32 | ODROID_KEY_O, 33 | ODROID_KEY_P, 34 | ODROID_KEY_CONTROL, 35 | ODROID_KEY_A, 36 | 37 | ODROID_KEY_S = 31, 38 | ODROID_KEY_D, 39 | ODROID_KEY_F, 40 | ODROID_KEY_G, 41 | ODROID_KEY_H, 42 | ODROID_KEY_J, 43 | ODROID_KEY_K, 44 | ODROID_KEY_L, 45 | 46 | ODROID_KEY_BACKSPACE = 41, 47 | ODROID_KEY_ALTERNATE, 48 | ODROID_KEY_Z, 49 | ODROID_KEY_X, 50 | ODROID_KEY_C, 51 | ODROID_KEY_V, 52 | ODROID_KEY_B, 53 | ODROID_KEY_N, 54 | 55 | ODROID_KEY_M = 51, 56 | ODROID_KEY_BACKSLASH, 57 | ODROID_KEY_ENTER, 58 | ODROID_KEY_SHIFT, 59 | ODROID_KEY_SEMICOLON, 60 | ODROID_KEY_APOSTROPHE, 61 | ODROID_KEY_MINUS, 62 | ODROID_KEY_EQUALS, 63 | 64 | ODROID_KEY_SPACE = 61, 65 | ODROID_KEY_COMMA, 66 | ODROID_KEY_PERIOD, 67 | ODROID_KEY_SLASH, 68 | ODROID_KEY_LEFTBRACKET, 69 | ODROID_KEY_RIGHTBRACKET, 70 | 71 | } odroid_key_t; 72 | 73 | typedef enum 74 | { 75 | ODROID_KEY_RELEASED = 0, 76 | ODROID_KEY_PRESSED 77 | } odroid_keystate_t; 78 | 79 | typedef struct 80 | { 81 | uint8_t rows[8]; 82 | } odroid_keyboardstate_t; 83 | 84 | typedef enum 85 | { 86 | ODROID_KEYBOARD_LED_NONE = 0, 87 | ODROID_KEYBOARD_LED_Fn = (1 << 0), 88 | ODORID_KEYBOARD_LED_Aa = (1 << 1), 89 | ODROID_KEYBOARD_LED_St = (1 << 2) 90 | } odroid_keyboard_led_t; 91 | 92 | typedef struct 93 | { 94 | odroid_keystate_t state; 95 | odroid_key_t key; 96 | } odroid_keyboard_event_t; 97 | 98 | 99 | 100 | 101 | bool odroid_keyboard_init(); 102 | void odroid_keyboard_state_key_set(odroid_keyboardstate_t* state, odroid_key_t key, odroid_keystate_t value); 103 | odroid_keystate_t odroid_keyboard_state_key_get(odroid_keyboardstate_t* state, odroid_key_t key); 104 | odroid_keyboardstate_t odroid_keyboard_state_get(); 105 | odroid_keyboard_led_t odroid_keyboard_leds_get(); 106 | void odroid_keyboard_leds_set(odroid_keyboard_led_t value); 107 | void odroid_keyboard_event_callback_set(void (*callback)(odroid_keystate_t, odroid_key_t)); 108 | -------------------------------------------------------------------------------- /components/ugui/LICENSE.md: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------- */ 2 | /* -- µGUI - Generic GUI module (C)Achim Döbler, 2015 -- */ 3 | /* -------------------------------------------------------------------------------- */ 4 | // µGUI is a generic GUI module for embedded systems. 5 | // This is a free software that is open for education, research and commercial 6 | // developments under license policy of following terms. 7 | // 8 | // Copyright (C) 2015, Achim Döbler, all rights reserved. 9 | // URL: http://www.embeddedlightning.com/ 10 | // 11 | // * The µGUI module is a free software and there is NO WARRANTY. 12 | // * No restriction on use. You can use, modify and redistribute it for 13 | // personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 14 | // * Redistributions of source code must retain the above copyright notice. 15 | // 16 | /* -------------------------------------------------------------------------------- */ 17 | /* -- MY SPECIAL THANKS GO TO -- */ 18 | /* -------------------------------------------------------------------------------- */ 19 | // Andrey Filimonov (-->https://github.com/Sermus) 20 | // for giving valuable suggestions, reporting bugs and adding several new features. 21 | // Andrey also put a lot of work in the implementaion of anti-aliased font support. 22 | // 23 | // Mikhail Podkur (-->https://github.com/MikhailPodkur) 24 | // for adding cyrillic 8x12 font, checkbox feature and RGB565 support. 25 | // 26 | // Gustavo Denardin 27 | // for giving valuable suggestions regarding real-time os support. 28 | // 29 | // Samuel Kleiser 30 | // for reporting bugs and giving examples how to improve µGUI. 31 | /* -------------------------------------------------------------------------------- */ 32 | /* -- REVISION HISTORY -- */ 33 | /* -------------------------------------------------------------------------------- */ 34 | // Dec 20, 2015 V0.31 Checkbox component with all funtions added. 35 | // Cyrillic font 8x12 added. 36 | // RGB565 color schema added. 37 | // Windows components font could be getted from current GUI by default 38 | // Mar 18, 2015 V0.3 Driver support added. 39 | // Window and object support added. 40 | // Touch support added. 41 | // Fixed some minor bugs. 42 | // 43 | // Oct 20, 2014 V0.2 Function UG_DrawRoundFrame() added. 44 | // Function UG_FillRoundFrame() added. 45 | // Function UG_DrawArc() added. 46 | // Fixed some minor bugs. 47 | // 48 | // Oct 11, 2014 V0.1 First release. 49 | /* -------------------------------------------------------------------------------- */ 50 | -------------------------------------------------------------------------------- /components/frodo/1541job.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 1541job.h - Emulation of 1541 GCR disk reading/writing 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _1541JOB_H 8 | #define _1541JOB_H 9 | 10 | 11 | class MOS6502_1541; 12 | class Prefs; 13 | struct Job1541State; 14 | 15 | class Job1541 { 16 | public: 17 | Job1541(uint8 *ram1541); 18 | ~Job1541(); 19 | 20 | void GetState(Job1541State *state); 21 | void SetState(Job1541State *state); 22 | void NewPrefs(Prefs *prefs); 23 | void MoveHeadOut(void); 24 | void MoveHeadIn(void); 25 | bool SyncFound(void); 26 | uint8 ReadGCRByte(void); 27 | uint8 WPState(void); 28 | void WriteSector(void); 29 | void FormatTrack(void); 30 | 31 | private: 32 | void open_d64_file_internal(char *filepath); 33 | void open_d64_file(char *filepath); 34 | void close_d64_file(void); 35 | bool read_sector(int track, int sector, uint8 *buffer); 36 | bool write_sector(int track, int sector, uint8 *buffer); 37 | void format_disk(void); 38 | int secnum_from_ts(int track, int sector); 39 | int offset_from_ts(int track, int sector); 40 | void gcr_conv4(uint8 *from, uint8 *to); 41 | void sector2gcr(int track, int sector); 42 | void disk2gcr(void); 43 | 44 | uint8 *ram; // Pointer to 1541 RAM 45 | FILE *the_file; // File pointer for .d64 file 46 | int image_header; // Length of .d64/.x64 file header 47 | 48 | uint8 id1, id2; // ID of disk 49 | uint8 error_info[683]; // Sector error information (1 byte/sector) 50 | 51 | uint8 *gcr_data; // Pointer to GCR encoded disk data 52 | uint8 *gcr_ptr; // Pointer to GCR data under R/W head 53 | uint8 *gcr_track_start; // Pointer to start of GCR data of current track 54 | uint8 *gcr_track_end; // Pointer to end of GCR data of current track 55 | int current_halftrack; // Current halftrack number (2..70) 56 | 57 | bool write_protected; // Flag: Disk write-protected 58 | bool disk_changed; // Flag: Disk changed (WP sensor strobe control) 59 | }; 60 | 61 | // 1541 GCR state 62 | struct Job1541State { 63 | int current_halftrack; 64 | uint32 gcr_ptr; 65 | bool write_protected; 66 | bool disk_changed; 67 | }; 68 | 69 | 70 | /* 71 | * Check if R/W head is over SYNC 72 | */ 73 | 74 | inline bool Job1541::SyncFound(void) 75 | { 76 | if (*gcr_ptr == 0xff) 77 | return true; 78 | else { 79 | gcr_ptr++; // Rotate disk 80 | if (gcr_ptr == gcr_track_end) 81 | gcr_ptr = gcr_track_start; 82 | return false; 83 | } 84 | } 85 | 86 | 87 | /* 88 | * Read one GCR byte from disk 89 | */ 90 | 91 | inline uint8 Job1541::ReadGCRByte(void) 92 | { 93 | uint8 byte = *gcr_ptr++; // Rotate disk 94 | if (gcr_ptr == gcr_track_end) 95 | gcr_ptr = gcr_track_start; 96 | return byte; 97 | } 98 | 99 | 100 | /* 101 | * Return state of write protect sensor 102 | */ 103 | 104 | inline uint8 Job1541::WPState(void) 105 | { 106 | if (disk_changed) { // Disk change -> WP sensor strobe 107 | disk_changed = false; 108 | return write_protected ? 0x10 : 0; 109 | } else 110 | return write_protected ? 0 : 0x10; 111 | } 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /components/odroid/odroid_system.c: -------------------------------------------------------------------------------- 1 | #include "odroid_system.h" 2 | 3 | #include "freertos/FreeRTOS.h" 4 | #include "esp_system.h" 5 | #include "esp_event.h" 6 | #include "driver/rtc_io.h" 7 | #include "esp_partition.h" 8 | #include "esp_ota_ops.h" 9 | 10 | #include "odroid_input.h" 11 | 12 | static bool system_initialized = false; 13 | 14 | void odroid_system_application_set(int slot) 15 | { 16 | const esp_partition_t* partition = esp_partition_find_first( 17 | ESP_PARTITION_TYPE_APP, 18 | ESP_PARTITION_SUBTYPE_APP_OTA_MIN + slot, 19 | NULL); 20 | if (partition != NULL) 21 | { 22 | esp_err_t err = esp_ota_set_boot_partition(partition); 23 | if (err != ESP_OK) 24 | { 25 | printf("odroid_system_application_set: esp_ota_set_boot_partition failed.\n"); 26 | abort(); 27 | } 28 | } 29 | } 30 | 31 | void odroid_system_sleep() 32 | { 33 | printf("odroid_system_sleep: Entered.\n"); 34 | 35 | // Wait for button release 36 | odroid_gamepad_state joystick; 37 | odroid_input_gamepad_read(&joystick); 38 | 39 | while (joystick.values[ODROID_INPUT_MENU]) 40 | { 41 | vTaskDelay(1); 42 | odroid_input_gamepad_read(&joystick); 43 | } 44 | 45 | //odroid_input_gamepad_terminate(); 46 | 47 | 48 | // Configure button to wake 49 | printf("odroid_system_sleep: Configuring deep sleep.\n"); 50 | #if 1 51 | esp_err_t err = esp_sleep_enable_ext0_wakeup(ODROID_GAMEPAD_IO_MENU, 0); 52 | #else 53 | const int ext_wakeup_pin_1 = ODROID_GAMEPAD_IO_MENU; 54 | const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1; 55 | 56 | esp_err_t err = esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ALL_LOW); 57 | #endif 58 | if (err != ESP_OK) 59 | { 60 | printf("odroid_system_sleep: esp_sleep_enable_ext0_wakeup failed.\n"); 61 | abort(); 62 | } 63 | 64 | err = rtc_gpio_pullup_en(ODROID_GAMEPAD_IO_MENU); 65 | if (err != ESP_OK) 66 | { 67 | printf("odroid_system_sleep: rtc_gpio_pullup_en failed.\n"); 68 | abort(); 69 | } 70 | 71 | 72 | // Isolate GPIO12 pin from external circuits. This is needed for modules 73 | // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER) 74 | // to minimize current consumption. 75 | // rtc_gpio_isolate(GPIO_NUM_12); 76 | // #if 1 77 | // rtc_gpio_isolate(GPIO_NUM_34); 78 | // rtc_gpio_isolate(GPIO_NUM_35); 79 | // rtc_gpio_isolate(GPIO_NUM_0); 80 | // rtc_gpio_isolate(GPIO_NUM_39); 81 | // //rtc_gpio_isolate(GPIO_NUM_14); 82 | // #endif 83 | 84 | // Sleep 85 | //esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); 86 | 87 | vTaskDelay(100); 88 | esp_deep_sleep_start(); 89 | } 90 | 91 | void odroid_system_init() 92 | { 93 | rtc_gpio_deinit(ODROID_GAMEPAD_IO_MENU); 94 | //rtc_gpio_deinit(GPIO_NUM_14); 95 | 96 | // blue led 97 | gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT); 98 | gpio_set_level(GPIO_NUM_2, 0); 99 | 100 | system_initialized = true; 101 | } 102 | 103 | void odroid_system_led_set(int value) 104 | { 105 | if (!system_initialized) 106 | { 107 | printf("odroid_system_init not called before use.\n"); 108 | abort(); 109 | } 110 | 111 | gpio_set_level(GPIO_NUM_2, value); 112 | } 113 | -------------------------------------------------------------------------------- /components/frodo/SID.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SID.h - 6581 emulation 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _SID_H 8 | #define _SID_H 9 | 10 | #include 11 | 12 | 13 | // Define this if you want an emulation of an 8580 14 | // (affects combined waveforms) 15 | #undef EMUL_MOS8580 16 | 17 | 18 | class Prefs; 19 | class C64; 20 | class SIDRenderer; 21 | struct MOS6581State; 22 | 23 | // Class for administrative functions 24 | class MOS6581 { 25 | public: 26 | MOS6581(C64 *c64); 27 | ~MOS6581(); 28 | 29 | void Reset(void); 30 | uint8 ReadRegister(uint16 adr); 31 | void WriteRegister(uint16 adr, uint8 byte); 32 | void NewPrefs(Prefs *prefs); 33 | void PauseSound(void); 34 | void ResumeSound(void); 35 | void GetState(MOS6581State *ss); 36 | void SetState(MOS6581State *ss); 37 | void EmulateLine(void); 38 | 39 | private: 40 | void open_close_renderer(int old_type, int new_type); 41 | 42 | C64 *the_c64; // Pointer to C64 object 43 | SIDRenderer *the_renderer; // Pointer to current renderer 44 | uint8 regs[32]; // Copies of the 25 write-only SID registers 45 | uint8 last_sid_byte; // Last value written to SID 46 | uint8 pad00; 47 | uint8 pad01; 48 | uint8 pad02; 49 | }; 50 | 51 | 52 | // Renderers do the actual audio data processing 53 | class SIDRenderer { 54 | protected: 55 | SIDRenderer(){} 56 | public: 57 | virtual ~SIDRenderer() {} 58 | virtual void Reset(void)=0; 59 | virtual void EmulateLine(void)=0; 60 | virtual void WriteRegister(uint16 adr, uint8 byte)=0; 61 | virtual void NewPrefs(Prefs *prefs)=0; 62 | virtual void Pause(void)=0; 63 | virtual void Resume(void)=0; 64 | }; 65 | 66 | 67 | // SID state 68 | struct MOS6581State { 69 | uint8 freq_lo_1; 70 | uint8 freq_hi_1; 71 | uint8 pw_lo_1; 72 | uint8 pw_hi_1; 73 | uint8 ctrl_1; 74 | uint8 AD_1; 75 | uint8 SR_1; 76 | 77 | uint8 freq_lo_2; 78 | uint8 freq_hi_2; 79 | uint8 pw_lo_2; 80 | uint8 pw_hi_2; 81 | uint8 ctrl_2; 82 | uint8 AD_2; 83 | uint8 SR_2; 84 | 85 | uint8 freq_lo_3; 86 | uint8 freq_hi_3; 87 | uint8 pw_lo_3; 88 | uint8 pw_hi_3; 89 | uint8 ctrl_3; 90 | uint8 AD_3; 91 | uint8 SR_3; 92 | 93 | uint8 fc_lo; 94 | uint8 fc_hi; 95 | uint8 res_filt; 96 | uint8 mode_vol; 97 | 98 | uint8 pot_x; 99 | uint8 pot_y; 100 | uint8 osc_3; 101 | uint8 env_3; 102 | }; 103 | 104 | 105 | /* 106 | * Fill buffer (for Unix sound routines), sample volume (for sampled voice) 107 | */ 108 | 109 | inline void MOS6581::EmulateLine(void) 110 | { 111 | if (the_renderer != NULL) 112 | the_renderer->EmulateLine(); 113 | } 114 | 115 | 116 | /* 117 | * Read from register 118 | */ 119 | 120 | inline uint8 MOS6581::ReadRegister(uint16 adr) 121 | { 122 | // A/D converters 123 | if (adr == 0x19 || adr == 0x1a) { 124 | last_sid_byte = 0; 125 | return 0xff; 126 | } 127 | 128 | // Voice 3 oscillator/EG readout 129 | if (adr == 0x1b || adr == 0x1c) { 130 | last_sid_byte = 0; 131 | return rand(); 132 | } 133 | 134 | // Write-only register: Return last value written to SID 135 | return last_sid_byte; 136 | } 137 | 138 | 139 | /* 140 | * Write to register 141 | */ 142 | 143 | inline void MOS6581::WriteRegister(uint16 adr, uint8 byte) 144 | { 145 | // Keep a local copy of the register values 146 | last_sid_byte = regs[adr] = byte; 147 | 148 | if (the_renderer != NULL) 149 | the_renderer->WriteRegister(adr, byte); 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /components/frodo/1541d64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 1541d64.h - 1541 emulation in .d64 file 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _1541D64_H 8 | #define _1541D64_H 9 | 10 | #include "IEC.h" 11 | 12 | 13 | // BAM structure 14 | typedef struct { 15 | uint8 dir_track; // Track... 16 | uint8 dir_sector; // ...and sector of first directory block 17 | int8 fmt_type; // Format type 18 | int8 pad0; 19 | uint8 bitmap[4*35]; // Sector allocation 20 | uint8 disk_name[18]; // Disk name 21 | uint8 id[2]; // Disk ID 22 | int8 pad1; 23 | uint8 fmt_char[2]; // Format characters 24 | int8 pad2[4]; 25 | int8 pad3[85]; 26 | } BAM; 27 | 28 | // Directory entry structure 29 | typedef struct { 30 | uint8 type; // File type 31 | uint8 track; // Track... 32 | uint8 sector; // ...and sector of first data block 33 | uint8 name[16]; // File name 34 | uint8 side_track; // Track... 35 | uint8 side_sector; // ...and sector of first side sector 36 | uint8 rec_len; // Record length 37 | int8 pad0[4]; 38 | uint8 ovr_track; // Track... 39 | uint8 ovr_sector; // ...and sector on overwrite 40 | uint8 num_blocks_l; // Number of blocks, LSB 41 | uint8 num_blocks_h; // Number of blocks, MSB 42 | int8 pad1[2]; 43 | } DirEntry; 44 | 45 | // Directory block structure 46 | typedef struct { 47 | uint8 padding[2]; // Keep DirEntry word-aligned 48 | uint8 next_track; 49 | uint8 next_sector; 50 | DirEntry entry[8]; 51 | } Directory; 52 | 53 | 54 | class D64Drive : public Drive { 55 | public: 56 | D64Drive(IEC *iec, char *filepath); 57 | virtual ~D64Drive(); 58 | virtual uint8 Open(int channel, char *filename); 59 | virtual uint8 Close(int channel); 60 | virtual uint8 Read(int channel, uint8 *byte); 61 | virtual uint8 Write(int channel, uint8 byte, bool eoi); 62 | virtual void Reset(void); 63 | 64 | private: 65 | void open_close_d64_file(char *d64name); 66 | uint8 open_file(int channel, char *filename); 67 | void convert_filename(char *srcname, char *destname, int *filemode, int *filetype); 68 | bool find_file(char *filename, int *track, int *sector); 69 | uint8 open_file_ts(int channel, int track, int sector); 70 | uint8 open_directory(char *pattern); 71 | uint8 open_direct(int channel, char *filename); 72 | void close_all_channels(); 73 | void execute_command(char *command); 74 | void block_read_cmd(char *command); 75 | void buffer_ptr_cmd(char *command); 76 | bool parse_bcmd(char *cmd, int *arg1, int *arg2, int *arg3, int *arg4); 77 | void chd64_cmd(char *d64name); 78 | int alloc_buffer(int want); 79 | void free_buffer(int buf); 80 | bool read_sector(int track, int sector, uint8 *buffer); 81 | int offset_from_ts(int track, int sector); 82 | uint8 conv_from_64(uint8 c, bool map_slash); 83 | void open_close_d64_file_internal(char *d64name); 84 | 85 | char orig_d64_name[256]; // Original path of .d64 file 86 | 87 | FILE *the_file; // File pointer for .d64 file 88 | 89 | uint8 *ram; // 2KB 1541 RAM 90 | BAM *bam; // Pointer to BAM 91 | Directory dir; // Buffer for directory blocks 92 | 93 | int chan_mode[16]; // Channel mode 94 | int chan_buf_num[16]; // Buffer number of channel (for direct access channels) 95 | uint8 *chan_buf[16]; // Pointer to buffer 96 | uint8 *buf_ptr[16]; // Pointer in buffer 97 | int buf_len[16]; // Remaining bytes in buffer 98 | 99 | bool buf_free[4]; // Buffer 0..3 free? 100 | 101 | char cmd_buffer[44]; // Buffer for incoming command strings 102 | int cmd_len; // Length of received command 103 | 104 | int image_header; // Length of .d64 file header 105 | 106 | uint8 error_info[683]; // Sector error information (1 byte/sector) 107 | }; 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /components/frodo/sysdeps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sysdeps.h - Try to include the right system headers and get other 3 | * system-specific stuff right 4 | * 5 | * Frodo (C) 1994-1997,2002 Christian Bauer 6 | */ 7 | 8 | #include "sysconfig.h" 9 | 10 | extern "C" 11 | { 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #ifndef __PSXOS__ 19 | #include 20 | #include 21 | #endif 22 | 23 | #ifdef HAVE_SYS_TYPES_H 24 | #include 25 | #endif 26 | 27 | #ifdef HAVE_VALUES_H 28 | //#include 29 | #endif 30 | 31 | #ifdef HAVE_STRINGS_H 32 | #include 33 | #endif 34 | #ifdef HAVE_STRING_H 35 | #include 36 | #endif 37 | 38 | #ifdef HAVE_UNISTD_H 39 | #include 40 | #endif 41 | #ifdef HAVE_FCNTL_H 42 | #include 43 | #endif 44 | 45 | #ifdef HAVE_UTIME_H 46 | #include 47 | #endif 48 | 49 | #ifdef HAVE_SYS_PARAM_H 50 | #include 51 | #endif 52 | 53 | #ifdef HAVE_SYS_SELECT_H 54 | #include 55 | #endif 56 | 57 | #ifdef HAVE_SYS_VFS_H 58 | //#include 59 | #endif 60 | 61 | #ifdef HAVE_SYS_STAT_H 62 | #include 63 | #endif 64 | 65 | #ifdef HAVE_SYS_MOUNT_H 66 | //#include 67 | #endif 68 | 69 | #ifdef HAVE_SYS_STATFS_H 70 | //#include 71 | #endif 72 | 73 | #ifdef HAVE_SYS_STATVFS_H 74 | //#include 75 | #endif 76 | 77 | #if TIME_WITH_SYS_TIME 78 | # include 79 | # include 80 | #else 81 | # if HAVE_SYS_TIME_H 82 | # include 83 | # else 84 | #ifndef __PSXOS__ 85 | # include 86 | #endif 87 | # endif 88 | #endif 89 | 90 | #if HAVE_DIRENT_H 91 | # include 92 | #else 93 | # define dirent direct 94 | # if HAVE_SYS_NDIR_H 95 | # include 96 | # endif 97 | # if HAVE_SYS_DIR_H 98 | # include 99 | # endif 100 | # if HAVE_NDIR_H 101 | # include 102 | # endif 103 | #endif 104 | 105 | #ifndef __PSXOS__ 106 | #include 107 | #endif 108 | #include 109 | 110 | #if EEXIST == ENOTEMPTY 111 | #define BROKEN_OS_PROBABLY_AIX 112 | #endif 113 | 114 | #ifdef HAVE_LINUX_JOYSTICK_H 115 | //#include 116 | #endif 117 | 118 | #ifdef __NeXT__ 119 | #define S_IRUSR S_IREAD 120 | #define S_IWUSR S_IWRITE 121 | #define S_IXUSR S_IEXEC 122 | #define S_ISDIR(val) (S_IFDIR & val) 123 | struct utimbuf 124 | { 125 | time_t actime; 126 | time_t modtime; 127 | }; 128 | #endif 129 | 130 | #ifdef __DOS__ 131 | #include 132 | #include 133 | #else 134 | #undef O_BINARY 135 | #define O_BINARY 0 136 | #endif 137 | 138 | #ifdef __mac__ 139 | #define bool Boolean 140 | #endif 141 | 142 | #ifdef __riscos 143 | #define bool int 144 | #endif 145 | 146 | #ifdef WIN32 147 | #include 148 | #include 149 | #if !defined(M_PI) 150 | #define M_PI 3.14159265358979323846 151 | #endif 152 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 153 | #if _MSC_VER < 1100 154 | #define bool char 155 | #endif 156 | #define LITTLE_ENDIAN_UNALIGNED 1 157 | #endif 158 | 159 | /* If char has more then 8 bits, good night. */ 160 | #ifndef __BEOS__ 161 | typedef unsigned char uint8; 162 | typedef signed char int8; 163 | 164 | #if SIZEOF_SHORT == 2 165 | typedef unsigned short uint16; 166 | typedef short int16; 167 | #elif SIZEOF_INT == 2 168 | typedef unsigned int uint16; 169 | typedef int int16; 170 | #else 171 | #error No 2 byte type, you lose. 172 | #endif 173 | 174 | #if SIZEOF_INT == 4 175 | typedef unsigned int uint32; 176 | typedef int int32; 177 | #elif SIZEOF_LONG == 4 178 | typedef unsigned long uint32; 179 | typedef long int32; 180 | #else 181 | #error No 4 byte type, you lose. 182 | #endif 183 | #endif // __BEOS__ 184 | 185 | #define UNUSED(x) (x = x) 186 | } 187 | -------------------------------------------------------------------------------- /components/frodo/IEC.h: -------------------------------------------------------------------------------- 1 | /* 2 | * IEC.h - IEC bus routines, 1541 emulation (DOS level) 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _IEC_H 8 | #define _IEC_H 9 | 10 | 11 | // Maximum length of file names 12 | const int NAMEBUF_LENGTH = 256; 13 | 14 | 15 | // C64 status codes 16 | enum { 17 | ST_OK = 0, // No error 18 | ST_READ_TIMEOUT = 0x02, // Timeout on reading 19 | ST_TIMEOUT = 0x03, // Timeout 20 | ST_EOF = 0x40, // End of file 21 | ST_NOTPRESENT = 0x80 // Device not present 22 | }; 23 | 24 | 25 | // 1541 error codes 26 | enum { 27 | ERR_OK, // 00 OK 28 | ERR_WRITEERROR, // 25 WRITE ERROR 29 | ERR_WRITEPROTECT, // 26 WRITE PROTECT ON 30 | ERR_SYNTAX30, // 30 SYNTAX ERROR (unknown command) 31 | ERR_SYNTAX33, // 33 SYNTAX ERROR (wildcards on writing) 32 | ERR_WRITEFILEOPEN, // 60 WRITE FILE OPEN 33 | ERR_FILENOTOPEN, // 61 FILE NOT OPEN 34 | ERR_FILENOTFOUND, // 62 FILE NOT FOUND 35 | ERR_ILLEGALTS, // 67 ILLEGAL TRACK OR SECTOR 36 | ERR_NOCHANNEL, // 70 NO CHANNEL 37 | ERR_STARTUP, // 73 Power-up message 38 | ERR_NOTREADY // 74 DRIVE NOT READY 39 | }; 40 | 41 | 42 | // IEC command codes 43 | enum { 44 | CMD_DATA = 0x60, // Data transfer 45 | CMD_CLOSE = 0xe0, // Close channel 46 | CMD_OPEN = 0xf0 // Open channel 47 | }; 48 | 49 | 50 | // IEC ATN codes 51 | enum { 52 | ATN_LISTEN = 0x20, 53 | ATN_UNLISTEN = 0x30, 54 | ATN_TALK = 0x40, 55 | ATN_UNTALK = 0x50 56 | }; 57 | 58 | 59 | // Drive LED states 60 | enum { 61 | DRVLED_OFF, // Inactive, LED off 62 | DRVLED_ON, // Active, LED on 63 | DRVLED_ERROR // Error, blink LED 64 | }; 65 | 66 | 67 | class Drive; 68 | class C64Display; 69 | class Prefs; 70 | 71 | // Class for complete IEC bus system with drives 8..11 72 | class IEC { 73 | public: 74 | IEC(C64Display *display); 75 | ~IEC(); 76 | 77 | void Reset(void); 78 | void NewPrefs(Prefs *prefs); 79 | void UpdateLEDs(void); 80 | 81 | uint8 Out(uint8 byte, bool eoi); 82 | uint8 OutATN(uint8 byte); 83 | uint8 OutSec(uint8 byte); 84 | uint8 In(uint8 *byte); 85 | void SetATN(void); 86 | void RelATN(void); 87 | void Turnaround(void); 88 | void Release(void); 89 | 90 | private: 91 | uint8 listen(int device); 92 | uint8 talk(int device); 93 | uint8 unlisten(void); 94 | uint8 untalk(void); 95 | uint8 sec_listen(void); 96 | uint8 sec_talk(void); 97 | uint8 open_out(uint8 byte, bool eoi); 98 | uint8 data_out(uint8 byte, bool eoi); 99 | uint8 data_in(uint8 *byte); 100 | 101 | C64Display *the_display; // Pointer to display object (for drive LEDs) 102 | 103 | char name_buf[NAMEBUF_LENGTH]; // Buffer for file names and command strings 104 | char *name_ptr; // Pointer for reception of file name 105 | int name_len; // Received length of file name 106 | 107 | Drive *drive[4]; // 4 drives (8..11) 108 | 109 | Drive *listener; // Pointer to active listener 110 | Drive *talker; // Pointer to active talker 111 | 112 | bool listener_active; // Listener selected, listener_data is valid 113 | bool talker_active; // Talker selected, talker_data is valid 114 | bool listening; // Last ATN was listen (to decide between sec_listen/sec_talk) 115 | 116 | uint8 received_cmd; // Received command code ($x0) 117 | uint8 sec_addr; // Received secondary address ($0x) 118 | }; 119 | 120 | 121 | // Abstract superclass for individual drives 122 | class Drive { 123 | public: 124 | Drive(IEC *iec); 125 | virtual ~Drive() {} 126 | 127 | virtual uint8 Open(int channel, char *filename)=0; 128 | virtual uint8 Close(int channel)=0; 129 | virtual uint8 Read(int channel, uint8 *byte)=0; 130 | virtual uint8 Write(int channel, uint8 byte, bool eoi)=0; 131 | virtual void Reset(void)=0; 132 | 133 | int LED; // Drive LED state 134 | bool Ready; // Drive is ready for operation 135 | 136 | protected: 137 | void set_error(int error); 138 | 139 | char *error_ptr; // Pointer within error message 140 | int error_len; // Remaining length of error message 141 | 142 | private: 143 | IEC *the_iec; // Pointer to IEC object 144 | }; 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /components/frodo/Prefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Prefs.h - Global preferences 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _PREFS_H 8 | #define _PREFS_H 9 | 10 | 11 | // Drive types 12 | enum { 13 | DRVTYPE_DIR, // 1541 emulation in host file system 14 | DRVTYPE_D64, // 1541 emulation in .d64 file 15 | DRVTYPE_T64 // 1541 emulation in .t64 file 16 | }; 17 | 18 | 19 | // SID types 20 | enum { 21 | SIDTYPE_NONE, // SID emulation off 22 | SIDTYPE_DIGITAL, // Digital SID emulation 23 | SIDTYPE_SIDCARD // SID card 24 | }; 25 | 26 | 27 | // REU sizes 28 | enum { 29 | REU_NONE, // No REU 30 | REU_128K, // 128K 31 | REU_256K, // 256K 32 | REU_512K // 512K 33 | }; 34 | 35 | 36 | // Display types (BeOS) 37 | enum { 38 | DISPTYPE_WINDOW, // BWindow 39 | DISPTYPE_SCREEN // BWindowScreen 40 | }; 41 | 42 | 43 | // Preferences data 44 | class Prefs { 45 | public: 46 | Prefs(); 47 | bool ShowEditor(bool startup, char *prefs_name); 48 | void Check(void); 49 | void Load(char *filename); 50 | bool Save(char *filename); 51 | 52 | bool operator==(const Prefs &rhs) const; 53 | bool operator!=(const Prefs &rhs) const; 54 | 55 | int NormalCycles; // Available CPU cycles in normal raster lines 56 | int BadLineCycles; // Available CPU cycles in Bad Lines 57 | int CIACycles; // CIA timer ticks per raster line 58 | int FloppyCycles; // Available 1541 CPU cycles per line 59 | int SkipFrames; // Draw every n-th frame 60 | 61 | int DriveType[4]; // Type of drive 8..11 62 | 63 | char DrivePath[4][256]; // Path for drive 8..11 64 | 65 | char ViewPort[256]; // Size of the C64 screen to display (Win32) 66 | char DisplayMode[256]; // Video mode to use for full screen (Win32) 67 | 68 | int SIDType; // SID emulation type 69 | int REUSize; // Size of REU 70 | int DisplayType; // Display type (BeOS) 71 | int LatencyMin; // Min msecs ahead of sound buffer (Win32) 72 | int LatencyMax; // Max msecs ahead of sound buffer (Win32) 73 | int LatencyAvg; // Averaging interval in msecs (Win32) 74 | int ScalingNumerator; // Window scaling numerator (Win32) 75 | int ScalingDenominator; // Window scaling denominator (Win32) 76 | 77 | bool SpritesOn; // Sprite display is on 78 | bool SpriteCollisions; // Sprite collision detection is on 79 | bool Joystick1On; // Joystick connected to port 1 of host 80 | bool Joystick2On; // Joystick connected to port 2 of host 81 | bool JoystickSwap; // Swap joysticks 1<->2 82 | bool LimitSpeed; // Limit speed to 100% 83 | bool FastReset; // Skip RAM test on reset 84 | bool CIAIRQHack; // Write to CIA ICR clears IRQ 85 | bool MapSlash; // Map '/' in C64 filenames 86 | bool Emul1541Proc; // Enable processor-level 1541 emulation 87 | bool SIDFilters; // Emulate SID filters 88 | bool DoubleScan; // Double scan lines (BeOS, if DisplayType == DISPTYPE_SCREEN) 89 | bool HideCursor; // Hide mouse cursor when visible (Win32) 90 | bool DirectSound; // Use direct sound (instead of wav) (Win32) 91 | bool ExclusiveSound; // Use exclusive mode with direct sound (Win32) 92 | bool AutoPause; // Auto pause when not foreground app (Win32) 93 | bool PrefsAtStartup; // Show prefs dialog at startup (Win32) 94 | bool SystemMemory; // Put view work surface in system mem (Win32) 95 | bool AlwaysCopy; // Always use a work surface (Win32) 96 | bool SystemKeys; // Enable system keys and menu keys (Win32) 97 | bool ShowLEDs; // Show LEDs (Win32) 98 | 99 | #ifdef __mac__ 100 | void ChangeDisks(void); 101 | #endif 102 | 103 | #ifdef WIN32 104 | private: 105 | static BOOL CALLBACK StandardDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); 106 | static BOOL CALLBACK WIN32DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); 107 | BOOL DialogProc(int page, HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); 108 | void SetupControls(int page); 109 | void SetValues(int page); 110 | void GetValues(int page); 111 | void BrowseForDevice(int id); 112 | 113 | static Prefs *edit_prefs; 114 | static char *edit_prefs_name; 115 | static HWND hDlg; 116 | #endif 117 | }; 118 | 119 | 120 | // These are the active preferences 121 | extern Prefs ThePrefs; 122 | 123 | // Theses are the preferences on disk 124 | extern Prefs ThePrefsOnDisk; 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /main/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | extern "C" 14 | { 15 | #include "../components/odroid/odroid_settings.h" 16 | #include "../components/odroid/odroid_audio.h" 17 | #include "../components/odroid/odroid_input.h" 18 | #include "../components/odroid/odroid_system.h" 19 | #include "../components/odroid/odroid_display.h" 20 | #include "../components/odroid/odroid_sdcard.h" 21 | 22 | #include "../components/ugui/ugui.h" 23 | } 24 | 25 | 26 | // Frodo 27 | #include "../components/frodo/Prefs.h" 28 | #include "../components/frodo/C64.h" 29 | 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #define ESP32_PSRAM (0x3f800000) 36 | const char* SD_BASE_PATH = "/sd"; 37 | 38 | #define AUDIO_SAMPLE_RATE (32000) 39 | 40 | 41 | #define BASIC_ROM_FILE "/sd/roms/c64/Basic.rom" 42 | #define KERNAL_ROM_FILE "/sd/roms/c64/Kernal.rom" 43 | #define CHAR_ROM_FILE "/sd/roms/c64/Char.rom" 44 | #define FLOPPY_ROM_FILE "/sd/roms/c64/1541.rom" 45 | 46 | C64* TheC64; 47 | 48 | bool load_rom_files(void) 49 | { 50 | FILE *file; 51 | 52 | // Load Basic ROM 53 | if ((file = fopen(BASIC_ROM_FILE, "rb")) != NULL) { 54 | if (fread(TheC64->Basic, 1, 0x2000, file) != 0x2000) { 55 | abort(); 56 | //ShowRequester("Can't read 'Basic ROM'.", "Quit"); 57 | return false; 58 | } 59 | fclose(file); 60 | } else { 61 | abort(); 62 | //ShowRequester("Can't find 'Basic ROM'.", "Quit"); 63 | return false; 64 | } 65 | 66 | // Load Kernal ROM 67 | if ((file = fopen(KERNAL_ROM_FILE, "rb")) != NULL) { 68 | if (fread(TheC64->Kernal, 1, 0x2000, file) != 0x2000) { 69 | //ShowRequester("Can't read 'Kernal ROM'.", "Quit"); 70 | return false; 71 | } 72 | fclose(file); 73 | } else { 74 | //ShowRequester("Can't find 'Kernal ROM'.", "Quit"); 75 | return false; 76 | } 77 | 78 | // Load Char ROM 79 | if ((file = fopen(CHAR_ROM_FILE, "rb")) != NULL) { 80 | if (fread(TheC64->Char, 1, 0x1000, file) != 0x1000) { 81 | //ShowRequester("Can't read 'Char ROM'.", "Quit"); 82 | return false; 83 | } 84 | fclose(file); 85 | } else { 86 | //ShowRequester("Can't find 'Char ROM'.", "Quit"); 87 | return false; 88 | } 89 | 90 | // Load 1541 ROM 91 | if ((file = fopen(FLOPPY_ROM_FILE, "rb")) != NULL) { 92 | if (fread(TheC64->ROM1541, 1, 0x4000, file) != 0x4000) { 93 | //ShowRequester("Can't read '1541 ROM'.", "Quit"); 94 | return false; 95 | } 96 | fclose(file); 97 | } else { 98 | //ShowRequester("Can't find '1541 ROM'.", "Quit"); 99 | return false; 100 | } 101 | 102 | return true; 103 | } 104 | 105 | 106 | extern "C" void app_main() 107 | { 108 | printf("frodo-go started (%s|%s).\n", COMPILEDATE, GITREV); 109 | 110 | //printf("HEAP:0x%x (%#08x)\n", esp_get_free_heap_size(), heap_caps_get_free_size(MALLOC_CAP_DMA)); 111 | 112 | 113 | nvs_flash_init(); 114 | 115 | odroid_system_init(); 116 | odroid_input_gamepad_init(); 117 | odroid_input_battery_level_init(); 118 | 119 | ili9341_prepare(); 120 | 121 | ili9341_init(); 122 | ili9341_clear(0x0000); 123 | 124 | //vTaskDelay(500 / portTICK_RATE_MS); 125 | 126 | // Open SD card 127 | esp_err_t r = odroid_sdcard_open(SD_BASE_PATH); 128 | if (r != ESP_OK) 129 | { 130 | odroid_display_show_sderr(ODROID_SD_ERR_NOCARD); 131 | abort(); 132 | } 133 | 134 | 135 | //const char* romfile = ChooseFile(); 136 | //printf("%s: filename='%s'\n", __func__, romfile); 137 | 138 | 139 | ili9341_clear(0x0000); 140 | 141 | odroid_audio_init(AUDIO_SAMPLE_RATE); 142 | 143 | 144 | //ThePrefs.Load(prefs_path); 145 | 146 | ThePrefs.Emul1541Proc = true; 147 | //ThePrefs.DriveType[0] = DRVTYPE_D64; 148 | //strcpy(ThePrefs.DrivePath[0], "."); 149 | 150 | // Create and start C64 151 | TheC64 = new C64; 152 | if (load_rom_files()) 153 | { 154 | TheC64->Run(); 155 | } 156 | 157 | printf("load_rom_files failed.\n"); 158 | 159 | while(1) 160 | { 161 | vTaskDelay(1); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /components/frodo/CPU_common.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CPU_common.cpp - Definitions common to 6502/6510 SC emulation 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #include "sysdeps.h" 8 | 9 | #include "CPU_common.h" 10 | 11 | 12 | // Addressing mode for each opcode (first part of execution) (Frodo SC) 13 | const uint8 ModeTab[256] = { 14 | O_BRK, A_INDX, 1, M_INDX, A_ZERO, A_ZERO, M_ZERO, M_ZERO, // 00 15 | O_PHP, O_ORA_I,O_ASL_A,O_ANC_I,A_ABS, A_ABS, M_ABS, M_ABS, 16 | O_BPL, AE_INDY,1, M_INDY, A_ZEROX,A_ZEROX,M_ZEROX,M_ZEROX,// 10 17 | O_CLC, AE_ABSY,O_NOP, M_ABSY, AE_ABSX,AE_ABSX,M_ABSX, M_ABSX, 18 | O_JSR, A_INDX, 1, M_INDX, A_ZERO, A_ZERO, M_ZERO, M_ZERO, // 20 19 | O_PLP, O_AND_I,O_ROL_A,O_ANC_I,A_ABS, A_ABS, M_ABS, M_ABS, 20 | O_BMI, AE_INDY,1, M_INDY, A_ZEROX,A_ZEROX,M_ZEROX,M_ZEROX,// 30 21 | O_SEC, AE_ABSY,O_NOP, M_ABSY, AE_ABSX,AE_ABSX,M_ABSX, M_ABSX, 22 | O_RTI, A_INDX, 1, M_INDX, A_ZERO, A_ZERO, M_ZERO, M_ZERO, // 40 23 | O_PHA, O_EOR_I,O_LSR_A,O_ASR_I,O_JMP, A_ABS, M_ABS, M_ABS, 24 | O_BVC, AE_INDY,1, M_INDY, A_ZEROX,A_ZEROX,M_ZEROX,M_ZEROX,// 50 25 | O_CLI, AE_ABSY,O_NOP, M_ABSY, AE_ABSX,AE_ABSX,M_ABSX, M_ABSX, 26 | O_RTS, A_INDX, 1, M_INDX, A_ZERO, A_ZERO, M_ZERO, M_ZERO, // 60 27 | O_PLA, O_ADC_I,O_ROR_A,O_ARR_I,A_ABS, A_ABS, M_ABS, M_ABS, 28 | O_BVS, AE_INDY,1, M_INDY, A_ZEROX,A_ZEROX,M_ZEROX,M_ZEROX,// 70 29 | O_SEI, AE_ABSY,O_NOP, M_ABSY, AE_ABSX,AE_ABSX,M_ABSX, M_ABSX, 30 | O_NOP_I,A_INDX, O_NOP_I,A_INDX, A_ZERO, A_ZERO, A_ZERO, A_ZERO, // 80 31 | O_DEY, O_NOP_I,O_TXA, O_ANE_I,A_ABS, A_ABS, A_ABS, A_ABS, 32 | O_BCC, A_INDY, 1, A_INDY, A_ZEROX,A_ZEROX,A_ZEROY,A_ZEROY,// 90 33 | O_TYA, A_ABSY, O_TXS, A_ABSY, A_ABSX, A_ABSX, A_ABSY, A_ABSY, 34 | O_LDY_I,A_INDX, O_LDX_I,A_INDX, A_ZERO, A_ZERO, A_ZERO, A_ZERO, // a0 35 | O_TAY, O_LDA_I,O_TAX, O_LXA_I,A_ABS, A_ABS, A_ABS, A_ABS, 36 | O_BCS, AE_INDY,1, AE_INDY,A_ZEROX,A_ZEROX,A_ZEROY,A_ZEROY,// b0 37 | O_CLV, AE_ABSY,O_TSX, AE_ABSY,AE_ABSX,AE_ABSX,AE_ABSY,AE_ABSY, 38 | O_CPY_I,A_INDX, O_NOP_I,M_INDX, A_ZERO, A_ZERO, M_ZERO, M_ZERO, // c0 39 | O_INY, O_CMP_I,O_DEX, O_SBX_I,A_ABS, A_ABS, M_ABS, M_ABS, 40 | O_BNE, AE_INDY,1, M_INDY, A_ZEROX,A_ZEROX,M_ZEROX,M_ZEROX,// d0 41 | O_CLD, AE_ABSY,O_NOP, M_ABSY, AE_ABSX,AE_ABSX,M_ABSX, M_ABSX, 42 | O_CPX_I,A_INDX, O_NOP_I,M_INDX, A_ZERO, A_ZERO, M_ZERO, M_ZERO, // e0 43 | O_INX, O_SBC_I,O_NOP, O_SBC_I,A_ABS, A_ABS, M_ABS, M_ABS, 44 | O_BEQ, AE_INDY,O_EXT, M_INDY, A_ZEROX,A_ZEROX,M_ZEROX,M_ZEROX,// f0 45 | O_SED, AE_ABSY,O_NOP, M_ABSY, AE_ABSX,AE_ABSX,M_ABSX, M_ABSX 46 | }; 47 | 48 | 49 | // Operation for each opcode (second part of execution) (Frodo SC) 50 | const uint8 OpTab[256] = { 51 | 1, O_ORA, 1, O_SLO, O_NOP_A,O_ORA, O_ASL, O_SLO, // 00 52 | 1, 1, 1, 1, O_NOP_A,O_ORA, O_ASL, O_SLO, 53 | 1, O_ORA, 1, O_SLO, O_NOP_A,O_ORA, O_ASL, O_SLO, // 10 54 | 1, O_ORA, 1, O_SLO, O_NOP_A,O_ORA, O_ASL, O_SLO, 55 | 1, O_AND, 1, O_RLA, O_BIT, O_AND, O_ROL, O_RLA, // 20 56 | 1, 1, 1, 1, O_BIT, O_AND, O_ROL, O_RLA, 57 | 1, O_AND, 1, O_RLA, O_NOP_A,O_AND, O_ROL, O_RLA, // 30 58 | 1, O_AND, 1, O_RLA, O_NOP_A,O_AND, O_ROL, O_RLA, 59 | 1, O_EOR, 1, O_SRE, O_NOP_A,O_EOR, O_LSR, O_SRE, // 40 60 | 1, 1, 1, 1, 1, O_EOR, O_LSR, O_SRE, 61 | 1, O_EOR, 1, O_SRE, O_NOP_A,O_EOR, O_LSR, O_SRE, // 50 62 | 1, O_EOR, 1, O_SRE, O_NOP_A,O_EOR, O_LSR, O_SRE, 63 | 1, O_ADC, 1, O_RRA, O_NOP_A,O_ADC, O_ROR, O_RRA, // 60 64 | 1, 1, 1, 1, O_JMP_I,O_ADC, O_ROR, O_RRA, 65 | 1, O_ADC, 1, O_RRA, O_NOP_A,O_ADC, O_ROR, O_RRA, // 70 66 | 1, O_ADC, 1, O_RRA, O_NOP_A,O_ADC, O_ROR, O_RRA, 67 | 1, O_STA, 1, O_SAX, O_STY, O_STA, O_STX, O_SAX, // 80 68 | 1, 1, 1, 1, O_STY, O_STA, O_STX, O_SAX, 69 | 1, O_STA, 1, O_SHA, O_STY, O_STA, O_STX, O_SAX, // 90 70 | 1, O_STA, 1, O_SHS, O_SHY, O_STA, O_SHX, O_SHA, 71 | 1, O_LDA, 1, O_LAX, O_LDY, O_LDA, O_LDX, O_LAX, // a0 72 | 1, 1, 1, 1, O_LDY, O_LDA, O_LDX, O_LAX, 73 | 1, O_LDA, 1, O_LAX, O_LDY, O_LDA, O_LDX, O_LAX, // b0 74 | 1, O_LDA, 1, O_LAS, O_LDY, O_LDA, O_LDX, O_LAX, 75 | 1, O_CMP, 1, O_DCP, O_CPY, O_CMP, O_DEC, O_DCP, // c0 76 | 1, 1, 1, 1, O_CPY, O_CMP, O_DEC, O_DCP, 77 | 1, O_CMP, 1, O_DCP, O_NOP_A,O_CMP, O_DEC, O_DCP, // d0 78 | 1, O_CMP, 1, O_DCP, O_NOP_A,O_CMP, O_DEC, O_DCP, 79 | 1, O_SBC, 1, O_ISB, O_CPX, O_SBC, O_INC, O_ISB, // e0 80 | 1, 1, 1, 1, O_CPX, O_SBC, O_INC, O_ISB, 81 | 1, O_SBC, 1, O_ISB, O_NOP_A,O_SBC, O_INC, O_ISB, // f0 82 | 1, O_SBC, 1, O_ISB, O_NOP_A,O_SBC, O_INC, O_ISB 83 | }; 84 | -------------------------------------------------------------------------------- /components/frodo/main.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | /* 3 | * main.cpp - Main program 4 | * 5 | * Frodo (C) 1994-1997,2002 Christian Bauer 6 | */ 7 | 8 | #include "sysdeps.h" 9 | 10 | #include "main.h" 11 | #include "C64.h" 12 | #include "Display.h" 13 | #include "Prefs.h" 14 | #include "SAM.h" 15 | 16 | 17 | // Global variables 18 | //char AppDirPath[1024]; // Path of application directory 19 | 20 | 21 | // ROM file names 22 | #ifdef __riscos__ 23 | #define BASIC_ROM_FILE "FrodoRsrc:Basic_ROM" 24 | #define KERNAL_ROM_FILE "FrodoRsrc:Kernal_ROM" 25 | #define CHAR_ROM_FILE "FrodoRsrc:Char_ROM" 26 | #define FLOPPY_ROM_FILE "FrodoRsrc:1541_ROM" 27 | #else 28 | #define BASIC_ROM_FILE "Basic.rom" 29 | #define KERNAL_ROM_FILE "Kernal.rom" 30 | #define CHAR_ROM_FILE "Char.rom" 31 | #define FLOPPY_ROM_FILE "1541.rom" 32 | #endif 33 | 34 | 35 | /* 36 | * Load C64 ROM files 37 | */ 38 | 39 | #ifndef __PSXOS__ 40 | bool Frodo::load_rom_files(void) 41 | { 42 | FILE *file; 43 | 44 | // Load Basic ROM 45 | if ((file = fopen(BASIC_ROM_FILE, "rb")) != NULL) { 46 | if (fread(TheC64->Basic, 1, 0x2000, file) != 0x2000) { 47 | ShowRequester("Can't read 'Basic ROM'.", "Quit"); 48 | return false; 49 | } 50 | fclose(file); 51 | } else { 52 | ShowRequester("Can't find 'Basic ROM'.", "Quit"); 53 | return false; 54 | } 55 | 56 | // Load Kernal ROM 57 | if ((file = fopen(KERNAL_ROM_FILE, "rb")) != NULL) { 58 | if (fread(TheC64->Kernal, 1, 0x2000, file) != 0x2000) { 59 | ShowRequester("Can't read 'Kernal ROM'.", "Quit"); 60 | return false; 61 | } 62 | fclose(file); 63 | } else { 64 | ShowRequester("Can't find 'Kernal ROM'.", "Quit"); 65 | return false; 66 | } 67 | 68 | // Load Char ROM 69 | if ((file = fopen(CHAR_ROM_FILE, "rb")) != NULL) { 70 | if (fread(TheC64->Char, 1, 0x1000, file) != 0x1000) { 71 | ShowRequester("Can't read 'Char ROM'.", "Quit"); 72 | return false; 73 | } 74 | fclose(file); 75 | } else { 76 | ShowRequester("Can't find 'Char ROM'.", "Quit"); 77 | return false; 78 | } 79 | 80 | // Load 1541 ROM 81 | if ((file = fopen(FLOPPY_ROM_FILE, "rb")) != NULL) { 82 | if (fread(TheC64->ROM1541, 1, 0x4000, file) != 0x4000) { 83 | ShowRequester("Can't read '1541 ROM'.", "Quit"); 84 | return false; 85 | } 86 | fclose(file); 87 | } else { 88 | ShowRequester("Can't find '1541 ROM'.", "Quit"); 89 | return false; 90 | } 91 | 92 | return true; 93 | } 94 | #endif 95 | 96 | 97 | /* 98 | * main_x.i - Main program, X specific stuff 99 | * 100 | * Frodo (C) 1994-1997,2002 Christian Bauer 101 | */ 102 | 103 | #include "Version.h" 104 | 105 | 106 | extern int init_graphics(void); 107 | 108 | 109 | // Global variables 110 | char Frodo::prefs_path[256] = ""; 111 | 112 | 113 | /* 114 | * Create application object and start it 115 | */ 116 | 117 | int main(int argc, char **argv) 118 | { 119 | Frodo *the_app; 120 | 121 | timeval tv; 122 | gettimeofday(&tv, NULL); 123 | srand(tv.tv_usec); 124 | 125 | printf("%s by Christian Bauer\n", VERSION_STRING); 126 | if (!init_graphics()) 127 | return 0; 128 | fflush(stdout); 129 | 130 | the_app = new Frodo(); 131 | the_app->ArgvReceived(argc, argv); 132 | the_app->ReadyToRun(); 133 | delete the_app; 134 | 135 | return 0; 136 | } 137 | 138 | 139 | /* 140 | * Constructor: Initialize member variables 141 | */ 142 | 143 | Frodo::Frodo() 144 | { 145 | TheC64 = NULL; 146 | } 147 | 148 | 149 | /* 150 | * Process command line arguments 151 | */ 152 | 153 | void Frodo::ArgvReceived(int argc, char **argv) 154 | { 155 | if (argc == 2) 156 | strncpy(prefs_path, argv[1], 255); 157 | } 158 | 159 | 160 | /* 161 | * Arguments processed, run emulation 162 | */ 163 | 164 | void Frodo::ReadyToRun(void) 165 | { 166 | getcwd(AppDirPath, 256); 167 | 168 | // Load preferences 169 | if (!prefs_path[0]) { 170 | char *home = getenv("HOME"); 171 | if (home != NULL && strlen(home) < 240) { 172 | strncpy(prefs_path, home, 200); 173 | strcat(prefs_path, "/"); 174 | } 175 | strcat(prefs_path, ".frodorc"); 176 | } 177 | ThePrefs.Load(prefs_path); 178 | 179 | // Create and start C64 180 | TheC64 = new C64; 181 | if (load_rom_files()) 182 | TheC64->Run(); 183 | delete TheC64; 184 | } 185 | 186 | 187 | Prefs *Frodo::reload_prefs(void) 188 | { 189 | static Prefs newprefs; 190 | newprefs.Load(prefs_path); 191 | return &newprefs; 192 | } 193 | 194 | 195 | #endif 196 | -------------------------------------------------------------------------------- /components/frodo/SID.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SID.cpp - 6581 emulation 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | * 6 | 7 | * 8 | * Incompatibilities: 9 | * ------------------ 10 | * 11 | * - Lots of empirically determined constants in the filter calculations 12 | * - Voice 3 cannot be muted 13 | */ 14 | 15 | #include "sysdeps.h" 16 | 17 | 18 | #include "SID.h" 19 | #include "Prefs.h" 20 | 21 | #include "DigitalRenderer.h" 22 | 23 | 24 | /* 25 | * Constructor 26 | */ 27 | 28 | MOS6581::MOS6581(C64 *c64) : the_c64(c64) 29 | { 30 | //printf("%s\n", __func__); 31 | 32 | the_renderer = NULL; 33 | for (int i=0; i<32; i++) 34 | regs[i] = 0; 35 | 36 | // Open the renderer 37 | open_close_renderer(SIDTYPE_NONE, ThePrefs.SIDType); 38 | } 39 | 40 | 41 | /* 42 | * Destructor 43 | */ 44 | 45 | MOS6581::~MOS6581() 46 | { 47 | // Close the renderer 48 | open_close_renderer(ThePrefs.SIDType, SIDTYPE_NONE); 49 | } 50 | 51 | 52 | /* 53 | * Reset the SID 54 | */ 55 | 56 | void MOS6581::Reset(void) 57 | { 58 | for (int i=0; i<32; i++) 59 | regs[i] = 0; 60 | last_sid_byte = 0; 61 | 62 | // Reset the renderer 63 | if (the_renderer != NULL) 64 | the_renderer->Reset(); 65 | } 66 | 67 | 68 | /* 69 | * Preferences may have changed 70 | */ 71 | 72 | void MOS6581::NewPrefs(Prefs *prefs) 73 | { 74 | open_close_renderer(ThePrefs.SIDType, prefs->SIDType); 75 | if (the_renderer != NULL) 76 | the_renderer->NewPrefs(prefs); 77 | } 78 | 79 | 80 | /* 81 | * Pause sound output 82 | */ 83 | 84 | void MOS6581::PauseSound(void) 85 | { 86 | if (the_renderer != NULL) 87 | the_renderer->Pause(); 88 | } 89 | 90 | 91 | /* 92 | * Resume sound output 93 | */ 94 | 95 | void MOS6581::ResumeSound(void) 96 | { 97 | if (the_renderer != NULL) 98 | the_renderer->Resume(); 99 | } 100 | 101 | 102 | /* 103 | * Get SID state 104 | */ 105 | 106 | void MOS6581::GetState(MOS6581State *ss) 107 | { 108 | ss->freq_lo_1 = regs[0]; 109 | ss->freq_hi_1 = regs[1]; 110 | ss->pw_lo_1 = regs[2]; 111 | ss->pw_hi_1 = regs[3]; 112 | ss->ctrl_1 = regs[4]; 113 | ss->AD_1 = regs[5]; 114 | ss->SR_1 = regs[6]; 115 | 116 | ss->freq_lo_2 = regs[7]; 117 | ss->freq_hi_2 = regs[8]; 118 | ss->pw_lo_2 = regs[9]; 119 | ss->pw_hi_2 = regs[10]; 120 | ss->ctrl_2 = regs[11]; 121 | ss->AD_2 = regs[12]; 122 | ss->SR_2 = regs[13]; 123 | 124 | ss->freq_lo_3 = regs[14]; 125 | ss->freq_hi_3 = regs[15]; 126 | ss->pw_lo_3 = regs[16]; 127 | ss->pw_hi_3 = regs[17]; 128 | ss->ctrl_3 = regs[18]; 129 | ss->AD_3 = regs[19]; 130 | ss->SR_3 = regs[20]; 131 | 132 | ss->fc_lo = regs[21]; 133 | ss->fc_hi = regs[22]; 134 | ss->res_filt = regs[23]; 135 | ss->mode_vol = regs[24]; 136 | 137 | ss->pot_x = 0xff; 138 | ss->pot_y = 0xff; 139 | ss->osc_3 = 0; 140 | ss->env_3 = 0; 141 | } 142 | 143 | 144 | /* 145 | * Restore SID state 146 | */ 147 | 148 | void MOS6581::SetState(MOS6581State *ss) 149 | { 150 | regs[0] = ss->freq_lo_1; 151 | regs[1] = ss->freq_hi_1; 152 | regs[2] = ss->pw_lo_1; 153 | regs[3] = ss->pw_hi_1; 154 | regs[4] = ss->ctrl_1; 155 | regs[5] = ss->AD_1; 156 | regs[6] = ss->SR_1; 157 | 158 | regs[7] = ss->freq_lo_2; 159 | regs[8] = ss->freq_hi_2; 160 | regs[9] = ss->pw_lo_2; 161 | regs[10] = ss->pw_hi_2; 162 | regs[11] = ss->ctrl_2; 163 | regs[12] = ss->AD_2; 164 | regs[13] = ss->SR_2; 165 | 166 | regs[14] = ss->freq_lo_3; 167 | regs[15] = ss->freq_hi_3; 168 | regs[16] = ss->pw_lo_3; 169 | regs[17] = ss->pw_hi_3; 170 | regs[18] = ss->ctrl_3; 171 | regs[19] = ss->AD_3; 172 | regs[20] = ss->SR_3; 173 | 174 | regs[21] = ss->fc_lo; 175 | regs[22] = ss->fc_hi; 176 | regs[23] = ss->res_filt; 177 | regs[24] = ss->mode_vol; 178 | 179 | // Stuff the new register values into the renderer 180 | if (the_renderer != NULL) 181 | for (int i=0; i<25; i++) 182 | the_renderer->WriteRegister(i, regs[i]); 183 | } 184 | 185 | /* 186 | * Open/close the renderer, according to old and new prefs 187 | */ 188 | 189 | void MOS6581::open_close_renderer(int old_type, int new_type) 190 | { 191 | if (old_type == new_type) 192 | return; 193 | 194 | // Delete the old renderer 195 | if (the_renderer) delete the_renderer; 196 | 197 | // Create new renderer 198 | if (new_type == SIDTYPE_DIGITAL) 199 | the_renderer = new DigitalRenderer(); 200 | else 201 | the_renderer = NULL; 202 | 203 | // Stuff the current register values into the new renderer 204 | if (the_renderer != NULL) 205 | for (int i=0; i<25; i++) 206 | the_renderer->WriteRegister(i, regs[i]); 207 | } 208 | -------------------------------------------------------------------------------- /components/frodo/DigitalRenderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sysdeps.h" 4 | 5 | #include "SID.h" 6 | #include "Prefs.h" 7 | 8 | /** 9 | ** Renderer for digital SID emulation (SIDTYPE_DIGITAL) 10 | **/ 11 | 12 | #if defined(AMIGA) || defined(__riscos__) 13 | const uint32 SAMPLE_FREQ = 22050; // Sample output frequency in Hz 14 | #else 15 | const uint32 SAMPLE_FREQ = 32000; // Sample output frequency in Hz 16 | #endif 17 | const uint32 SID_FREQ = 985248; // SID frequency in Hz 18 | const uint32 CALC_FREQ = 50; // Frequency at which calc_buffer is called in Hz (should be 50Hz) 19 | const uint32 SID_CYCLES = SID_FREQ/SAMPLE_FREQ; // # of SID clocks per sample frame 20 | const int SAMPLE_BUF_SIZE = 0x138*2;// Size of buffer for sampled voice (double buffered) 21 | 22 | // SID waveforms (some of them :-) 23 | enum { 24 | WAVE_NONE, 25 | WAVE_TRI, 26 | WAVE_SAW, 27 | WAVE_TRISAW, 28 | WAVE_RECT, 29 | WAVE_TRIRECT, 30 | WAVE_SAWRECT, 31 | WAVE_TRISAWRECT, 32 | WAVE_NOISE 33 | }; 34 | 35 | // EG states 36 | enum { 37 | EG_IDLE, 38 | EG_ATTACK, 39 | EG_DECAY, 40 | EG_RELEASE 41 | }; 42 | 43 | // Filter types 44 | enum { 45 | FILT_NONE, 46 | FILT_LP, 47 | FILT_BP, 48 | FILT_LPBP, 49 | FILT_HP, 50 | FILT_NOTCH, 51 | FILT_HPBP, 52 | FILT_ALL 53 | }; 54 | 55 | // Structure for one voice 56 | struct DRVoice { 57 | int wave; // Selected waveform 58 | int eg_state; // Current state of EG 59 | DRVoice *mod_by; // Voice that modulates this one 60 | DRVoice *mod_to; // Voice that is modulated by this one 61 | 62 | uint32 count; // Counter for waveform generator, 8.16 fixed 63 | uint32 add; // Added to counter in every frame 64 | 65 | uint16 freq; // SID frequency value 66 | uint16 pw; // SID pulse-width value 67 | 68 | uint32 a_add; // EG parameters 69 | uint32 d_sub; 70 | uint32 s_level; 71 | uint32 r_sub; 72 | uint32 eg_level; // Current EG level, 8.16 fixed 73 | 74 | uint32 noise; // Last noise generator output value 75 | 76 | bool gate; // EG gate bit 77 | bool ring; // Ring modulation bit 78 | bool test; // Test bit 79 | bool filter; // Flag: Voice filtered 80 | 81 | // The following bit is set for the modulating 82 | // voice, not for the modulated one (as the SID bits) 83 | bool sync; // Sync modulation bit 84 | }; 85 | 86 | // Renderer class 87 | class DigitalRenderer : public SIDRenderer { 88 | public: 89 | DigitalRenderer(); 90 | virtual ~DigitalRenderer(); 91 | 92 | virtual void Reset(void); 93 | virtual void EmulateLine(void); 94 | virtual void WriteRegister(uint16 adr, uint8 byte); 95 | virtual void NewPrefs(Prefs *prefs); 96 | virtual void Pause(void); 97 | virtual void Resume(void); 98 | 99 | private: 100 | void init_sound(void); 101 | void calc_filter(void); 102 | 103 | void calc_buffer(int16 *buf, long count); 104 | 105 | bool ready; // Flag: Renderer has initialized and is ready 106 | uint8 volume; // Master volume 107 | bool v3_mute; // Voice 3 muted 108 | uint8 pad00; 109 | 110 | static uint16 TriTable[0x1000*2]; // Tables for certain waveforms 111 | static const uint16 TriSawTable[0x100]; 112 | static const uint16 TriRectTable[0x100]; 113 | static const uint16 SawRectTable[0x100]; 114 | static const uint16 TriSawRectTable[0x100]; 115 | static const uint32 EGTable[16]; // Increment/decrement values for all A/D/R settings 116 | static const uint8 EGDRShift[256]; // For exponential approximation of D/R 117 | static const int16 SampleTab[16]; // Table for sampled voice 118 | 119 | DRVoice voice[3]; // Data for 3 voices 120 | 121 | uint8 f_type; // Filter type 122 | uint8 f_freq; // SID filter frequency (upper 8 bits) 123 | uint8 f_res; // Filter resonance (0..15) 124 | uint8 pad01; 125 | 126 | #ifdef USE_FIXPOINT_MATHS 127 | FixPoint f_ampl; 128 | FixPoint d1, d2, g1, g2; 129 | int32 xn1, xn2, yn1, yn2; // can become very large 130 | FixPoint sidquot; 131 | #ifdef PRECOMPUTE_RESONANCE 132 | FixPoint resonanceLP[256]; 133 | FixPoint resonanceHP[256]; 134 | #endif 135 | #else 136 | float f_ampl; // IIR filter input attenuation 137 | float d1, d2, g1, g2; // IIR filter coefficients 138 | float xn1, xn2, yn1, yn2; // IIR filter previous input/output signal 139 | #ifdef PRECOMPUTE_RESONANCE 140 | float resonanceLP[256]; // shortcut for calc_filter 141 | float resonanceHP[256]; 142 | #endif 143 | #endif 144 | 145 | uint8 sample_buf[SAMPLE_BUF_SIZE]; // Buffer for sampled voice 146 | int sample_in_ptr; // Index in sample_buf for writing 147 | 148 | 149 | 150 | #if 1 151 | int devfd, sndbufsize, buffer_rate; 152 | int16* sound_buffer;//[SAMPLE_FREQ / 25]; 153 | #endif 154 | 155 | }; 156 | -------------------------------------------------------------------------------- /components/frodo/CIA.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CIA.h - 6526 emulation 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _CIA_H 8 | #define _CIA_H 9 | 10 | #include "Prefs.h" 11 | 12 | #pragma GCC diagnostic warning "-Wdelete-non-virtual-dtor" 13 | 14 | class MOS6510; 15 | class MOS6502_1541; 16 | class MOS6569; 17 | struct MOS6526State; 18 | 19 | 20 | class MOS6526 { 21 | public: 22 | MOS6526(MOS6510 *CPU); 23 | //virtual ~MOS6526() {} 24 | 25 | void Reset(void); 26 | void GetState(MOS6526State *cs); 27 | void SetState(MOS6526State *cs); 28 | #ifdef FRODO_SC 29 | void CheckIRQs(void); 30 | void EmulateCycle(void); 31 | #else 32 | void EmulateLine(int cycles); 33 | #endif 34 | void CountTOD(void); 35 | virtual void TriggerInterrupt(int bit)=0; 36 | 37 | protected: 38 | MOS6510 *the_cpu; // Pointer to 6510 39 | 40 | uint8 pra, prb, ddra, ddrb; 41 | 42 | uint16 ta, tb, latcha, latchb; 43 | 44 | uint8 tod_10ths, tod_sec, tod_min, tod_hr; 45 | uint8 alm_10ths, alm_sec, alm_min, alm_hr; 46 | 47 | uint8 sdr, icr, cra, crb; 48 | uint8 int_mask; 49 | 50 | int tod_divider; // TOD frequency divider 51 | 52 | bool tod_halt, // Flag: TOD halted 53 | ta_cnt_phi2, // Flag: Timer A is counting Phi 2 54 | tb_cnt_phi2, // Flag: Timer B is counting Phi 2 55 | tb_cnt_ta; // Flag: Timer B is counting underflows of Timer A 56 | 57 | #ifdef FRODO_SC 58 | bool ta_irq_next_cycle, // Flag: Trigger TA IRQ in next cycle 59 | tb_irq_next_cycle, // Flag: Trigger TB IRQ in next cycle 60 | has_new_cra, // Flag: New value for CRA pending 61 | has_new_crb; // Flag: New value for CRB pending 62 | char ta_state, tb_state; // Timer A/B states 63 | uint8 new_cra, new_crb; // New values for CRA/CRB 64 | #endif 65 | }; 66 | 67 | 68 | class MOS6526_1 : public MOS6526 { 69 | public: 70 | MOS6526_1(MOS6510 *CPU, MOS6569 *VIC); 71 | 72 | void Reset(void); 73 | uint8 ReadRegister(uint16 adr); 74 | void WriteRegister(uint16 adr, uint8 byte); 75 | virtual void TriggerInterrupt(int bit); 76 | 77 | uint8 KeyMatrix[8]; // C64 keyboard matrix, 1 bit/key (0: key down, 1: key up) 78 | uint8 RevMatrix[8]; // Reversed keyboard matrix 79 | 80 | uint8 Joystick1; // Joystick 1 AND value 81 | uint8 Joystick2; // Joystick 2 AND value 82 | 83 | private: 84 | void check_lp(void); 85 | 86 | MOS6569 *the_vic; 87 | 88 | uint8 prev_lp; // Previous state of LP line (bit 4) 89 | }; 90 | 91 | 92 | class MOS6526_2 : public MOS6526{ 93 | public: 94 | MOS6526_2(MOS6510 *CPU, MOS6569 *VIC, MOS6502_1541 *CPU1541); 95 | 96 | void Reset(void); 97 | uint8 ReadRegister(uint16 adr); 98 | void WriteRegister(uint16 adr, uint8 byte); 99 | virtual void TriggerInterrupt(int bit); 100 | 101 | uint8 IECLines; // State of IEC lines (bit 7 - DATA, bit 6 - CLK, bit 4 - ATN) 102 | 103 | private: 104 | MOS6569 *the_vic; 105 | MOS6502_1541 *the_cpu_1541; 106 | }; 107 | 108 | 109 | // CIA state 110 | struct MOS6526State { 111 | uint8 pra; 112 | uint8 ddra; 113 | uint8 prb; 114 | uint8 ddrb; 115 | uint8 ta_lo; 116 | uint8 ta_hi; 117 | uint8 tb_lo; 118 | uint8 tb_hi; 119 | uint8 tod_10ths; 120 | uint8 tod_sec; 121 | uint8 tod_min; 122 | uint8 tod_hr; 123 | uint8 sdr; 124 | uint8 int_data; // Pending interrupts 125 | uint8 cra; 126 | uint8 crb; 127 | // Additional registers 128 | uint16 latcha; // Timer latches 129 | uint16 latchb; 130 | uint8 alm_10ths; // Alarm time 131 | uint8 alm_sec; 132 | uint8 alm_min; 133 | uint8 alm_hr; 134 | uint8 int_mask; // Enabled interrupts 135 | }; 136 | 137 | 138 | /* 139 | * Emulate CIA for one cycle/raster line 140 | */ 141 | 142 | #ifdef FRODO_SC 143 | inline void MOS6526::CheckIRQs(void) 144 | { 145 | // Trigger pending interrupts 146 | if (ta_irq_next_cycle) { 147 | ta_irq_next_cycle = false; 148 | TriggerInterrupt(1); 149 | } 150 | if (tb_irq_next_cycle) { 151 | tb_irq_next_cycle = false; 152 | TriggerInterrupt(2); 153 | } 154 | } 155 | #else 156 | inline void MOS6526::EmulateLine(int cycles) 157 | { 158 | unsigned long tmp; 159 | 160 | // Timer A 161 | if (ta_cnt_phi2) { 162 | ta = tmp = ta - cycles; // Decrement timer 163 | 164 | if (tmp > 0xffff) { // Underflow? 165 | ta = latcha; // Reload timer 166 | 167 | if (cra & 8) { // One-shot? 168 | cra &= 0xfe; 169 | ta_cnt_phi2 = false; 170 | } 171 | TriggerInterrupt(1); 172 | if (tb_cnt_ta) { // Timer B counting underflows of Timer A? 173 | tb = tmp = tb - 1; // tmp = --tb doesn't work 174 | if (tmp > 0xffff) goto tb_underflow; 175 | } 176 | } 177 | } 178 | 179 | // Timer B 180 | if (tb_cnt_phi2) { 181 | tb = tmp = tb - cycles; // Decrement timer 182 | 183 | if (tmp > 0xffff) { // Underflow? 184 | tb_underflow: 185 | tb = latchb; 186 | 187 | if (crb & 8) { // One-shot? 188 | crb &= 0xfe; 189 | tb_cnt_phi2 = false; 190 | tb_cnt_ta = false; 191 | } 192 | TriggerInterrupt(2); 193 | } 194 | } 195 | } 196 | #endif 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /components/frodo/ndir.c: -------------------------------------------------------------------------------- 1 | #if 0 2 | /* msd_dir.c - portable directory routines 3 | Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 1, or (at your option) 8 | any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | 19 | $Header: /u/src/master/ccvs/windows-NT/ndir.c,v 1.3 1995/09/08 00:34:09 jimb Exp $ 20 | */ 21 | 22 | /* Everything non trivial in this code is from: @(#)msd_dir.c 1.4 23 | 87/11/06. A public domain implementation of BSD directory routines 24 | for MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield), 25 | August 1897 */ 26 | 27 | 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | #include "ndir.h" 37 | 38 | static void free_dircontents (struct _dircontents *); 39 | 40 | /* find ALL files! */ 41 | #define ATTRIBUTES (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR) 42 | 43 | 44 | 45 | DIR * 46 | opendir (const char *name) 47 | { 48 | struct _finddata_t find_buf; 49 | DIR *dirp; 50 | struct _dircontents *dp; 51 | char name_buf[_MAX_PATH + 1]; 52 | char *slash = ""; 53 | long hFile; 54 | 55 | if (!name) 56 | name = ""; 57 | else if (*name) 58 | { 59 | const char *s; 60 | int l = strlen (name); 61 | 62 | s = name + l - 1; 63 | if ( !(l == 2 && *s == ':') && *s != '\\' && *s != '/') 64 | slash = "/"; /* save to insert slash between path and "*.*" */ 65 | } 66 | 67 | strcat (strcat (strcpy (name_buf, name), slash), "*.*"); 68 | 69 | dirp = (DIR *) malloc (sizeof (DIR)); 70 | if (dirp == (DIR *)0) 71 | return (DIR *)0; 72 | 73 | dirp->dd_loc = 0; 74 | dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) 0; 75 | 76 | if ((hFile = _findfirst (name_buf, &find_buf)) < 0) 77 | { 78 | free (dirp); 79 | return (DIR *)0; 80 | } 81 | 82 | do 83 | { 84 | dp = (struct _dircontents *) malloc (sizeof (struct _dircontents)); 85 | if (dp == (struct _dircontents *)0) 86 | { 87 | free_dircontents (dirp->dd_contents); 88 | return (DIR *)0; 89 | } 90 | 91 | dp->_d_entry = malloc (strlen (find_buf.name) + 1); 92 | if (dp->_d_entry == (char *)0) 93 | { 94 | free (dp); 95 | free_dircontents (dirp->dd_contents); 96 | return (DIR *)0; 97 | } 98 | 99 | if (dirp->dd_contents) 100 | dirp->dd_cp = dirp->dd_cp->_d_next = dp; 101 | else 102 | dirp->dd_contents = dirp->dd_cp = dp; 103 | 104 | strcpy (dp->_d_entry, find_buf.name); 105 | 106 | dp->_d_next = (struct _dircontents *)0; 107 | 108 | } while (!_findnext (hFile, &find_buf)); 109 | 110 | dirp->dd_cp = dirp->dd_contents; 111 | 112 | _findclose(hFile); 113 | 114 | return dirp; 115 | } 116 | 117 | 118 | void 119 | closedir (DIR *dirp) 120 | { 121 | free_dircontents (dirp->dd_contents); 122 | free ((char *) dirp); 123 | } 124 | 125 | 126 | struct direct * 127 | readdir (DIR *dirp) 128 | { 129 | static struct direct dp; 130 | 131 | if (dirp->dd_cp == (struct _dircontents *)0) 132 | return (struct direct *)0; 133 | dp.d_namlen = dp.d_reclen = 134 | strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry)); 135 | #if 0 /* JB */ 136 | strlwr (dp.d_name); /* JF */ 137 | #endif 138 | dp.d_ino = 0; 139 | dirp->dd_cp = dirp->dd_cp->_d_next; 140 | dirp->dd_loc++; 141 | 142 | return &dp; 143 | } 144 | 145 | 146 | void 147 | seekdir (DIR *dirp, long off) 148 | { 149 | long i = off; 150 | struct _dircontents *dp; 151 | 152 | if (off < 0) 153 | return; 154 | for (dp = dirp->dd_contents; --i >= 0 && dp; dp = dp->_d_next) 155 | ; 156 | dirp->dd_loc = off - (i + 1); 157 | dirp->dd_cp = dp; 158 | } 159 | 160 | 161 | long 162 | telldir (DIR *dirp) 163 | { 164 | return dirp->dd_loc; 165 | } 166 | 167 | 168 | /* Garbage collection */ 169 | 170 | static void 171 | free_dircontents (struct _dircontents *dp) 172 | { 173 | struct _dircontents *odp; 174 | 175 | while (dp) 176 | { 177 | if (dp->_d_entry) 178 | free (dp->_d_entry); 179 | dp = (odp = dp)->_d_next; 180 | free (odp); 181 | } 182 | } 183 | 184 | 185 | #ifdef TEST 186 | 187 | void main (int argc, char *argv[]); 188 | 189 | void 190 | main (int argc, char *argv[]) 191 | { 192 | static DIR *directory; 193 | struct direct *entry = (struct direct *)0; 194 | 195 | char *name = ""; 196 | 197 | if (argc > 1) 198 | name = argv[1]; 199 | 200 | directory = opendir (name); 201 | 202 | if (!directory) 203 | { 204 | fprintf (stderr, "can't open directory `%s'.\n", name); 205 | exit (2); 206 | } 207 | 208 | while (entry = readdir (directory)) 209 | printf ("> %s\n", entry->d_name); 210 | 211 | printf ("done.\n"); 212 | } 213 | 214 | #endif /* TEST */ 215 | 216 | /* 217 | * Local Variables: 218 | * mode:C 219 | * ChangeLog:ChangeLog 220 | * compile-command:make 221 | * End: 222 | */ 223 | #endif -------------------------------------------------------------------------------- /components/frodo/sysconfig.h: -------------------------------------------------------------------------------- 1 | /* sysconfig.h. Generated automatically by configure. */ 2 | /* sysconfig.h.in. Generated from configure.in by autoheader. */ 3 | 4 | /* Define if you have the header file, and it defines `DIR'. */ 5 | #define HAVE_DIRENT_H 1 6 | 7 | /* Define if you have the header file. */ 8 | #define HAVE_FCNTL_H 1 9 | 10 | /* Define if you have the `gettimeofday' function. */ 11 | #define HAVE_GETTIMEOFDAY 1 12 | 13 | /* Define if you have the header file. */ 14 | #define HAVE_INTTYPES_H 1 15 | 16 | /* Define if you have the header file. */ 17 | //#define HAVE_LINUX_JOYSTICK_H 1 18 | 19 | /* Define if you have the header file. */ 20 | #define HAVE_MEMORY_H 1 21 | 22 | /* Define if you have the `mkdir' function. */ 23 | #define HAVE_MKDIR 1 24 | 25 | /* Define if you have the header file. */ 26 | #define HAVE_NCURSES_H 1 27 | 28 | /* Define if you have the header file, and it defines `DIR'. */ 29 | /* #undef HAVE_NDIR_H */ 30 | 31 | /* Define if you have the `rmdir' function. */ 32 | #define HAVE_RMDIR 1 33 | 34 | /* Define if you have the `select' function. */ 35 | #define HAVE_SELECT 1 36 | 37 | /* Define if you have the `sigaction' function. */ 38 | //#define HAVE_SIGACTION 1 39 | 40 | /* Define if you have the `statfs' function. */ 41 | #define HAVE_STATFS 1 42 | 43 | /* Define if you have the header file. */ 44 | #define HAVE_STDINT_H 1 45 | 46 | /* Define if you have the header file. */ 47 | #define HAVE_STDLIB_H 1 48 | 49 | /* Define if you have the `strerror' function. */ 50 | #define HAVE_STRERROR 1 51 | 52 | /* Define if you have the header file. */ 53 | #define HAVE_STRINGS_H 1 54 | 55 | /* Define if you have the header file. */ 56 | #define HAVE_STRING_H 1 57 | 58 | /* Define if you have the `strstr' function. */ 59 | #define HAVE_STRSTR 1 60 | 61 | /* Define if `st_blocks' is member of `struct stat'. */ 62 | #define HAVE_STRUCT_STAT_ST_BLOCKS 1 63 | 64 | /* Define if your `struct stat' has `st_blocks'. Deprecated, use 65 | `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ 66 | #define HAVE_ST_BLOCKS 1 67 | 68 | /* Define if you have the header file, and it defines `DIR'. */ 69 | /* #undef HAVE_SYS_DIR_H */ 70 | 71 | /* Define if you have the header file. */ 72 | #define HAVE_SYS_MOUNT_H 1 73 | 74 | /* Define if you have the header file, and it defines `DIR'. */ 75 | /* #undef HAVE_SYS_NDIR_H */ 76 | 77 | /* Define if you have the header file. */ 78 | #define HAVE_SYS_PARAM_H 1 79 | 80 | /* Define if you have the header file. */ 81 | #define HAVE_SYS_SELECT_H 1 82 | 83 | /* Define if you have the header file. */ 84 | #define HAVE_SYS_STATFS_H 1 85 | 86 | /* Define if you have the header file. */ 87 | #define HAVE_SYS_STATVFS_H 1 88 | 89 | /* Define if you have the header file. */ 90 | #define HAVE_SYS_STAT_H 1 91 | 92 | /* Define if you have the header file. */ 93 | #define HAVE_SYS_TIME_H 1 94 | 95 | /* Define if you have the header file. */ 96 | #define HAVE_SYS_TYPES_H 1 97 | 98 | /* Define if you have the header file. */ 99 | #define HAVE_SYS_VFS_H 1 100 | 101 | /* Define if you have the header file. */ 102 | #define HAVE_UNISTD_H 1 103 | 104 | /* Define if you have the `usleep' function. */ 105 | #define HAVE_USLEEP 1 106 | 107 | /* Define if you have the header file. */ 108 | #define HAVE_UTIME_H 1 109 | 110 | /* Define if `utime(file, NULL)' sets file's timestamp to the present. */ 111 | #define HAVE_UTIME_NULL 1 112 | 113 | /* Define if you have the header file. */ 114 | #define HAVE_VALUES_H 1 115 | 116 | /* Define as the return type of signal handlers (`int' or `void'). */ 117 | #define RETSIGTYPE void 118 | 119 | /* The size of a `char', as computed by sizeof. */ 120 | #define SIZEOF_CHAR 1 121 | 122 | /* The size of a `int', as computed by sizeof. */ 123 | #define SIZEOF_INT 4 124 | 125 | /* The size of a `long', as computed by sizeof. */ 126 | #define SIZEOF_LONG 8 127 | 128 | /* The size of a `long long', as computed by sizeof. */ 129 | #define SIZEOF_LONG_LONG 8 130 | 131 | /* The size of a `short', as computed by sizeof. */ 132 | #define SIZEOF_SHORT 2 133 | 134 | /* Define if you have the ANSI C header files. */ 135 | #define STDC_HEADERS 1 136 | 137 | /* Define if you can safely include both and . */ 138 | #define TIME_WITH_SYS_TIME 1 139 | 140 | /* Define if your declares `struct tm'. */ 141 | /* #undef TM_IN_SYS_TIME */ 142 | 143 | /* Define if the X Window System is missing or not being used. */ 144 | /* #undef X_DISPLAY_MISSING */ 145 | 146 | /* Define if on AIX 3. 147 | System headers sometimes define this. 148 | We just want to avoid a redefinition error message. */ 149 | #ifndef _ALL_SOURCE 150 | /* # undef _ALL_SOURCE */ 151 | #endif 152 | 153 | /* Define if you need to in order for stat and other things to work. */ 154 | /* #undef _POSIX_SOURCE */ 155 | 156 | /* Define to empty if `const' does not conform to ANSI C. */ 157 | /* #undef const */ 158 | 159 | /* Define as `__inline' if that's what the C compiler calls it, or to nothing 160 | if it is not supported. */ 161 | /* #undef inline */ 162 | 163 | /* Define to `int' if does not define. */ 164 | /* #undef mode_t */ 165 | 166 | /* Define to `long' if does not define. */ 167 | /* #undef off_t */ 168 | 169 | /* Define to `int' if does not define. */ 170 | /* #undef pid_t */ 171 | -------------------------------------------------------------------------------- /components/frodo/REU.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * REU.cpp - 17xx REU emulation 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | * 6 | 7 | * 8 | * Incompatibilities: 9 | * ------------------ 10 | * 11 | * - REU interrupts are not emulated 12 | * - Transfer time is not accounted for, all transfers 13 | * are done in 0 cycles 14 | */ 15 | 16 | #include "sysdeps.h" 17 | 18 | #include "REU.h" 19 | #include "CPUC64.h" 20 | #include "Prefs.h" 21 | 22 | 23 | /* 24 | * Constructor 25 | */ 26 | 27 | REU::REU(MOS6510 *CPU) : the_cpu(CPU) 28 | { 29 | int i; 30 | 31 | // Init registers 32 | regs[0] = 0x40; 33 | for (i=1; i<11; i++) 34 | regs[i] = 0; 35 | for (i=11; i<16; i++) 36 | regs[i] = 0xff; 37 | 38 | ex_ram = NULL; 39 | ram_size = ram_mask = 0; 40 | 41 | // Allocate RAM 42 | open_close_reu(REU_NONE, ThePrefs.REUSize); 43 | } 44 | 45 | 46 | /* 47 | * Destructor 48 | */ 49 | 50 | REU::~REU() 51 | { 52 | // Free RAM 53 | open_close_reu(ThePrefs.REUSize, REU_NONE); 54 | } 55 | 56 | 57 | /* 58 | * Prefs may have changed, reallocate expansion RAM 59 | */ 60 | 61 | void REU::NewPrefs(Prefs *prefs) 62 | { 63 | open_close_reu(ThePrefs.REUSize, prefs->REUSize); 64 | } 65 | 66 | 67 | /* 68 | * Allocate/free expansion RAM 69 | */ 70 | 71 | void REU::open_close_reu(int old_size, int new_size) 72 | { 73 | if (old_size == new_size) 74 | return; 75 | 76 | // Free old RAM 77 | if (old_size != REU_NONE) { 78 | delete[] ex_ram; 79 | ex_ram = NULL; 80 | } 81 | 82 | // Allocate new RAM 83 | if (new_size != REU_NONE) { 84 | switch (new_size) { 85 | case REU_128K: 86 | ram_size = 0x20000; 87 | break; 88 | case REU_256K: 89 | ram_size = 0x40000; 90 | break; 91 | case REU_512K: 92 | ram_size = 0x80000; 93 | break; 94 | } 95 | ram_mask = ram_size - 1; 96 | ex_ram = new uint8[ram_size]; 97 | 98 | // Set size bit in status register 99 | if (ram_size > 0x20000) 100 | regs[0] |= 0x10; 101 | else 102 | regs[0] &= 0xef; 103 | } 104 | } 105 | 106 | 107 | /* 108 | * Reset the REU 109 | */ 110 | 111 | void REU::Reset(void) 112 | { 113 | int i; 114 | 115 | for (i=1; i<11; i++) 116 | regs[i] = 0; 117 | for (i=11; i<16; i++) 118 | regs[i] = 0xff; 119 | 120 | if (ram_size > 0x20000) 121 | regs[0] = 0x50; 122 | else 123 | regs[0] = 0x40; 124 | } 125 | 126 | 127 | /* 128 | * Read from REU register 129 | */ 130 | 131 | uint8 REU::ReadRegister(uint16 adr) 132 | { 133 | if (ex_ram == NULL) 134 | return rand(); 135 | 136 | switch (adr) { 137 | case 0:{ 138 | uint8 ret = regs[0]; 139 | regs[0] &= 0x1f; 140 | return ret; 141 | } 142 | case 6: 143 | return regs[6] | 0xf8; 144 | case 9: 145 | return regs[9] | 0x1f; 146 | case 10: 147 | return regs[10] | 0x3f; 148 | default: 149 | return regs[adr]; 150 | } 151 | } 152 | 153 | 154 | /* 155 | * Write to REU register 156 | */ 157 | 158 | void REU::WriteRegister(uint16 adr, uint8 byte) 159 | { 160 | if (ex_ram == NULL) 161 | return; 162 | 163 | switch (adr) { 164 | case 0: // Status register is read-only 165 | case 11: // Unconnected registers 166 | case 12: 167 | case 13: 168 | case 14: 169 | case 15: 170 | break; 171 | case 1: // Command register 172 | regs[1] = byte; 173 | if ((byte & 0x90) == 0x90) 174 | execute_dma(); 175 | break; 176 | default: 177 | regs[adr] = byte; 178 | break; 179 | } 180 | } 181 | 182 | 183 | /* 184 | * CPU triggered REU by writing to $ff00 185 | */ 186 | 187 | void REU::FF00Trigger(void) 188 | { 189 | if (ex_ram == NULL) 190 | return; 191 | 192 | if ((regs[1] & 0x90) == 0x80) 193 | execute_dma(); 194 | } 195 | 196 | 197 | /* 198 | * Execute REU DMA transfer 199 | */ 200 | 201 | void REU::execute_dma(void) 202 | { 203 | // Get C64 and REU transfer base addresses 204 | uint16 c64_adr = regs[2] | (regs[3] << 8); 205 | uint32 reu_adr = regs[4] | (regs[5] << 8) | (regs[6] << 16); 206 | 207 | // Calculate transfer length 208 | int length = regs[7] | (regs[8] << 8); 209 | if (!length) 210 | length = 0x10000; 211 | 212 | // Calculate address increments 213 | uint32 c64_inc = (regs[10] & 0x80) ? 0 : 1; 214 | uint32 reu_inc = (regs[10] & 0x40) ? 0 : 1; 215 | 216 | // Do transfer 217 | switch (regs[1] & 3) { 218 | 219 | case 0: // C64 -> REU 220 | for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc) 221 | ex_ram[reu_adr & ram_mask] = the_cpu->REUReadByte(c64_adr); 222 | break; 223 | 224 | case 1: // C64 <- REU 225 | for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc) 226 | the_cpu->REUWriteByte(c64_adr, ex_ram[reu_adr & ram_mask]); 227 | break; 228 | 229 | case 2: // C64 <-> REU 230 | for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc) { 231 | uint8 tmp = the_cpu->REUReadByte(c64_adr); 232 | the_cpu->REUWriteByte(c64_adr, ex_ram[reu_adr & ram_mask]); 233 | ex_ram[reu_adr & ram_mask] = tmp; 234 | } 235 | break; 236 | 237 | case 3: // Compare 238 | for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc) 239 | if (ex_ram[reu_adr & ram_mask] != the_cpu->REUReadByte(c64_adr)) { 240 | regs[0] |= 0x20; 241 | break; 242 | } 243 | break; 244 | } 245 | 246 | // Update address and length registers if autoload is off 247 | if (!(regs[1] & 0x20)) { 248 | regs[2] = c64_adr; 249 | regs[3] = c64_adr >> 8; 250 | regs[4] = reu_adr; 251 | regs[5] = reu_adr >> 8; 252 | regs[6] = reu_adr >> 16; 253 | regs[7] = length + 1; 254 | regs[8] = (length + 1) >> 8; 255 | } 256 | 257 | // Set complete bit in status register 258 | regs[0] |= 0x40; 259 | 260 | // Clear execute bit in command register 261 | regs[1] &= 0x7f; 262 | } 263 | -------------------------------------------------------------------------------- /components/frodo/CPUC64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CPUC64.h - 6510 (C64) emulation (line based) 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _CPU_C64_H 8 | #define _CPU_C64_H 9 | 10 | #include "C64.h" 11 | 12 | 13 | // Set this to 1 if the 6502 PC should be represented by a real pointer 14 | #ifndef FRODO_SC 15 | #ifndef PC_IS_POINTER 16 | #define PC_IS_POINTER 1 17 | #endif 18 | #endif 19 | 20 | // Set this to 1 for more precise CPU cycle calculation 21 | #ifndef PRECISE_CPU_CYCLES 22 | #define PRECISE_CPU_CYCLES 0 23 | #endif 24 | 25 | // Set this to 1 for instruction-aligned CIA emulation 26 | #ifndef PRECISE_CIA_CYCLES 27 | #define PRECISE_CIA_CYCLES 0 28 | #endif 29 | 30 | 31 | // Interrupt types 32 | enum { 33 | INT_VICIRQ, 34 | INT_CIAIRQ, 35 | INT_NMI 36 | // INT_RESET (private) 37 | }; 38 | 39 | 40 | class MOS6569; 41 | class MOS6581; 42 | class MOS6526_1; 43 | class MOS6526_2; 44 | class REU; 45 | class IEC; 46 | struct MOS6510State; 47 | 48 | 49 | // 6510 emulation (C64) 50 | class MOS6510 { 51 | public: 52 | MOS6510(C64 *c64, uint8 *Ram, uint8 *Basic, uint8 *Kernal, uint8 *Char, uint8 *Color); 53 | 54 | #ifdef FRODO_SC 55 | void EmulateCycle(void); // Emulate one clock cycle 56 | #else 57 | int EmulateLine(int cycles_left); // Emulate until cycles_left underflows 58 | #endif 59 | void Reset(void); 60 | void AsyncReset(void); // Reset the CPU asynchronously 61 | void AsyncNMI(void); // Raise NMI asynchronously (NMI pulse) 62 | void GetState(MOS6510State *s); 63 | void SetState(MOS6510State *s); 64 | uint8 ExtReadByte(uint16 adr); 65 | void ExtWriteByte(uint16 adr, uint8 byte); 66 | uint8 REUReadByte(uint16 adr); 67 | void REUWriteByte(uint16 adr, uint8 byte); 68 | 69 | void TriggerVICIRQ(void); 70 | void ClearVICIRQ(void); 71 | void TriggerCIAIRQ(void); 72 | void ClearCIAIRQ(void); 73 | void TriggerNMI(void); 74 | void ClearNMI(void); 75 | 76 | int ExtConfig; // Memory configuration for ExtRead/WriteByte (0..7) 77 | 78 | MOS6569 *TheVIC; // Pointer to VIC 79 | MOS6581 *TheSID; // Pointer to SID 80 | MOS6526_1 *TheCIA1; // Pointer to CIA 1 81 | MOS6526_2 *TheCIA2; // Pointer to CIA 2 82 | REU *TheREU; // Pointer to REU 83 | IEC *TheIEC; // Pointer to drive array 84 | 85 | #ifdef FRODO_SC 86 | bool BALow; // BA line for Frodo SC 87 | #endif 88 | 89 | private: 90 | uint8 read_byte(uint16 adr); 91 | uint8 read_byte_io(uint16 adr); 92 | uint16 read_word(uint16 adr); 93 | void write_byte(uint16 adr, uint8 byte); 94 | void write_byte_io(uint16 adr, uint8 byte); 95 | 96 | uint8 read_zp(uint16 adr); 97 | uint16 read_zp_word(uint16 adr); 98 | void write_zp(uint16 adr, uint8 byte); 99 | 100 | void new_config(void); 101 | void jump(uint16 adr); 102 | void illegal_op(uint8 op, uint16 at); 103 | void illegal_jump(uint16 at, uint16 to); 104 | 105 | void do_adc(uint8 byte); 106 | void do_sbc(uint8 byte); 107 | 108 | uint8 read_emulator_id(uint16 adr); 109 | 110 | C64 *the_c64; // Pointer to C64 object 111 | 112 | uint8 *ram; // Pointer to main RAM 113 | uint8 *basic_rom, *kernal_rom, *char_rom, *color_ram; // Pointers to ROMs and color RAM 114 | 115 | union { // Pending interrupts 116 | uint8 intr[4]; // Index: See definitions above 117 | unsigned long intr_any; 118 | } interrupt; 119 | bool nmi_state; // State of NMI line 120 | 121 | uint8 n_flag, z_flag; 122 | bool v_flag, d_flag, i_flag, c_flag; 123 | uint8 a, x, y, sp; 124 | 125 | #if PC_IS_POINTER 126 | uint8 *pc, *pc_base; 127 | #else 128 | uint16 pc; 129 | #endif 130 | 131 | #ifdef FRODO_SC 132 | uint32 first_irq_cycle, first_nmi_cycle; 133 | 134 | uint8 state, op; // Current state and opcode 135 | uint16 ar, ar2; // Address registers 136 | uint8 rdbuf; // Data buffer for RMW instructions 137 | uint8 ddr, pr; // Processor port 138 | #else 139 | int borrowed_cycles; // Borrowed cycles from next line 140 | #endif 141 | 142 | bool basic_in, kernal_in, char_in, io_in; 143 | uint8 dfff_byte; 144 | }; 145 | 146 | // 6510 state 147 | struct MOS6510State { 148 | uint8 a, x, y; 149 | uint8 p; // Processor flags 150 | uint8 ddr, pr; // Port 151 | uint16 pc, sp; 152 | uint8 intr[4]; // Interrupt state 153 | bool nmi_state; 154 | uint8 dfff_byte; 155 | bool instruction_complete; 156 | }; 157 | 158 | 159 | // Interrupt functions 160 | #ifdef FRODO_SC 161 | inline void MOS6510::TriggerVICIRQ(void) 162 | { 163 | if (!(interrupt.intr[INT_VICIRQ] || interrupt.intr[INT_CIAIRQ])) 164 | first_irq_cycle = the_c64->CycleCounter; 165 | interrupt.intr[INT_VICIRQ] = true; 166 | } 167 | 168 | inline void MOS6510::TriggerCIAIRQ(void) 169 | { 170 | if (!(interrupt.intr[INT_VICIRQ] || interrupt.intr[INT_CIAIRQ])) 171 | first_irq_cycle = the_c64->CycleCounter; 172 | interrupt.intr[INT_CIAIRQ] = true; 173 | } 174 | 175 | inline void MOS6510::TriggerNMI(void) 176 | { 177 | if (!nmi_state) { 178 | nmi_state = true; 179 | interrupt.intr[INT_NMI] = true; 180 | first_nmi_cycle = the_c64->CycleCounter; 181 | } 182 | } 183 | #else 184 | inline void MOS6510::TriggerVICIRQ(void) 185 | { 186 | interrupt.intr[INT_VICIRQ] = true; 187 | } 188 | 189 | inline void MOS6510::TriggerCIAIRQ(void) 190 | { 191 | interrupt.intr[INT_CIAIRQ] = true; 192 | } 193 | 194 | inline void MOS6510::TriggerNMI(void) 195 | { 196 | if (!nmi_state) { 197 | nmi_state = true; 198 | interrupt.intr[INT_NMI] = true; 199 | } 200 | } 201 | #endif 202 | inline void MOS6510::ClearVICIRQ(void) 203 | { 204 | interrupt.intr[INT_VICIRQ] = false; 205 | } 206 | 207 | inline void MOS6510::ClearCIAIRQ(void) 208 | { 209 | interrupt.intr[INT_CIAIRQ] = false; 210 | } 211 | 212 | inline void MOS6510::ClearNMI(void) 213 | { 214 | nmi_state = false; 215 | } 216 | 217 | #endif 218 | -------------------------------------------------------------------------------- /components/frodo/C64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * C64.h - Put the pieces together 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _C64_H 8 | #define _C64_H 9 | 10 | #include "sysdeps.h" 11 | 12 | #ifdef __BEOS__ 13 | #include 14 | #include 15 | #endif 16 | 17 | #ifdef AMIGA 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | #ifdef __riscos__ 24 | #include "ROlib.h" 25 | #endif 26 | 27 | 28 | // false: Frodo, true: FrodoSC 29 | extern bool IsFrodoSC; 30 | 31 | 32 | class Prefs; 33 | class C64Display; 34 | class MOS6510; 35 | class MOS6569; 36 | class MOS6581; 37 | class MOS6526_1; 38 | class MOS6526_2; 39 | class IEC; 40 | class REU; 41 | class MOS6502_1541; 42 | class Job1541; 43 | class CmdPipe; 44 | 45 | class C64 { 46 | public: 47 | C64(); 48 | ~C64(); 49 | 50 | void Run(void); 51 | void Quit(void); 52 | void Pause(void); 53 | void Resume(void); 54 | void Reset(void); 55 | void NMI(void); 56 | void VBlank(bool draw_frame); 57 | void NewPrefs(Prefs *prefs); 58 | void PatchKernal(bool fast_reset, bool emul_1541_proc); 59 | void SaveRAM(char *filename); 60 | void SaveSnapshot(char *filename); 61 | bool LoadSnapshot(char *filename); 62 | int SaveCPUState(FILE *f); 63 | int Save1541State(FILE *f); 64 | bool Save1541JobState(FILE *f); 65 | bool SaveVICState(FILE *f); 66 | bool SaveSIDState(FILE *f); 67 | bool SaveCIAState(FILE *f); 68 | bool LoadCPUState(FILE *f); 69 | bool Load1541State(FILE *f); 70 | bool Load1541JobState(FILE *f); 71 | bool LoadVICState(FILE *f); 72 | bool LoadSIDState(FILE *f); 73 | bool LoadCIAState(FILE *f); 74 | 75 | uint8 *RAM, *Basic, *Kernal, 76 | *Char, *Color; // C64 77 | uint8 *RAM1541, *ROM1541; // 1541 78 | 79 | C64Display *TheDisplay; 80 | 81 | MOS6510 *TheCPU; // C64 82 | MOS6569 *TheVIC; 83 | MOS6581 *TheSID; 84 | MOS6526_1 *TheCIA1; 85 | MOS6526_2 *TheCIA2; 86 | IEC *TheIEC; 87 | REU *TheREU; 88 | 89 | MOS6502_1541 *TheCPU1541; // 1541 90 | Job1541 *TheJob1541; 91 | 92 | #ifdef FRODO_SC 93 | uint32 CycleCounter; 94 | #endif 95 | 96 | private: 97 | void c64_ctor1(void); 98 | void c64_ctor2(void); 99 | void c64_dtor(void); 100 | void open_close_joysticks(bool oldjoy1, bool oldjoy2, bool newjoy1, bool newjoy2); 101 | uint8 poll_joystick(int port); 102 | void thread_func(void); 103 | 104 | bool thread_running; // Emulation thread is running 105 | bool quit_thyself; // Emulation thread shall quit 106 | bool have_a_break; // Emulation thread shall pause 107 | 108 | int joy_minx, joy_maxx, joy_miny, joy_maxy; // For dynamic joystick calibration 109 | uint8 joykey; // Joystick keyboard emulation mask value 110 | 111 | uint8 orig_kernal_1d84, // Original contents of kernal locations $1d84 and $1d85 112 | orig_kernal_1d85; // (for undoing the Fast Reset patch) 113 | 114 | #ifdef __BEOS__ 115 | public: 116 | void SoundSync(void); 117 | 118 | private: 119 | static long thread_invoc(void *obj); 120 | 121 | BJoystick *joy[2]; // Joystick objects 122 | thread_id the_thread; 123 | sem_id pause_sem; 124 | sem_id sound_sync_sem; 125 | double start_time; 126 | #endif 127 | 128 | #ifdef AMIGA 129 | struct MsgPort *timer_port; // For speed limiter 130 | struct timerequest *timer_io; 131 | struct timeval start_time; 132 | struct MsgPort *game_port; // For joystick 133 | struct IOStdReq *game_io; 134 | struct GamePortTrigger game_trigger; 135 | struct InputEvent game_event; 136 | UBYTE joy_state; // Current state of joystick 137 | bool game_open, port_allocated; // Flags: gameport.device opened, game port allocated 138 | #endif 139 | 140 | #ifdef __unix 141 | int joyfd[2]; // File descriptors for joysticks 142 | double speed_index; 143 | public: 144 | CmdPipe *gui; 145 | #endif 146 | 147 | #ifdef WIN32 148 | private: 149 | void CheckTimerChange(); 150 | void StartTimer(); 151 | void StopTimer(); 152 | static void CALLBACK StaticTimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); 153 | void TimeProc(UINT id); 154 | #ifdef FRODO_SC 155 | void EmulateCyclesWith1541(); 156 | void EmulateCyclesWithout1541(); 157 | #endif 158 | 159 | DWORD ref_time; // when frame count was reset 160 | int skipped_frames; // number of skipped frames 161 | int timer_every; // frequency of timer in frames 162 | HANDLE timer_semaphore; // Timer semaphore for synch 163 | MMRESULT timer_id; // Timer identifier 164 | int frame; // current frame number 165 | uint8 joy_state; // Current state of joystick 166 | bool state_change; 167 | #endif 168 | 169 | #ifdef __riscos__ 170 | public: 171 | void RequestSnapshot(void); 172 | bool LoadOldSnapshot(FILE *f); 173 | void LoadSystemConfig(const char *filename); // loads timing vals and keyboard joys 174 | void SaveSystemConfig(const char *filename); // saves timing vals and keyboard joys 175 | void ReadTimings(int *poll_after, int *speed_after, int *sound_after); 176 | void WriteTimings(int poll_after, int speed_after, int sound_after); 177 | 178 | WIMP *TheWIMP; 179 | int PollAfter; // centiseconds before polling 180 | int SpeedAfter; // centiseconds before updating speedometer 181 | int PollSoundAfter; // *rasterlines* after which DigitalRenderer is polled 182 | int HostVolume; // sound volume of host machine 183 | 184 | private: 185 | bool make_a_snapshot; 186 | 187 | uint8 joykey2; // two keyboard joysticks possible here 188 | 189 | uint8 joystate[2]; // Joystick state 190 | bool Poll; // TRUE if polling should take place 191 | int LastPoll, LastFrame, LastSpeed; // time of last poll / last frame / speedom (cs) 192 | int FramesSince; 193 | int laststate; // last keyboard state (-> scroll lock) 194 | int lastptr; // last mouse pointer shape 195 | bool SingleTasking; 196 | #endif 197 | }; 198 | 199 | 200 | #endif 201 | -------------------------------------------------------------------------------- /components/odroid/odroid_audio.c: -------------------------------------------------------------------------------- 1 | #include "odroid_audio.h" 2 | 3 | #include "odroid_settings.h" 4 | 5 | #include "freertos/FreeRTOS.h" 6 | #include "esp_system.h" 7 | #include "driver/i2s.h" 8 | #include "driver/rtc_io.h" 9 | 10 | 11 | 12 | #define I2S_NUM (I2S_NUM_0) 13 | #define BUILTIN_DAC_ENABLED 1 14 | 15 | static float Volume = 1.0f; 16 | static odroid_volume_level volumeLevel = ODROID_VOLUME_LEVEL3; 17 | static int volumeLevels[] = {0, 125, 250, 500, 1000}; 18 | static int audio_sample_rate; 19 | 20 | 21 | odroid_volume_level odroid_audio_volume_get() 22 | { 23 | return volumeLevel; 24 | } 25 | 26 | void odroid_audio_volume_set(odroid_volume_level value) 27 | { 28 | if (value >= ODROID_VOLUME_LEVEL_COUNT) 29 | { 30 | printf("odroid_audio_volume_set: value out of range (%d)\n", value); 31 | abort(); 32 | } 33 | 34 | volumeLevel = value; 35 | Volume = (float)volumeLevels[value] * 0.001f; 36 | } 37 | 38 | void odroid_audio_volume_change() 39 | { 40 | int level = (volumeLevel + 1) % ODROID_VOLUME_LEVEL_COUNT; 41 | odroid_audio_volume_set(level); 42 | 43 | odroid_settings_Volume_set(level); 44 | } 45 | 46 | void odroid_audio_init(int sample_rate) 47 | { 48 | audio_sample_rate = sample_rate; 49 | 50 | // NOTE: buffer needs to be adjusted per AUDIO_SAMPLE_RATE 51 | # if BUILTIN_DAC_ENABLED 52 | 53 | i2s_config_t i2s_config = { 54 | //.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX 55 | .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, 56 | .sample_rate = audio_sample_rate, 57 | .bits_per_sample = 16, 58 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels 59 | .communication_format = I2S_COMM_FORMAT_I2S_MSB, 60 | //.communication_format = I2S_COMM_FORMAT_PCM, 61 | .dma_buf_count = 4, 62 | //.dma_buf_len = 1472 / 2, // (368samples * 2ch * 2(short)) = 1472 63 | .dma_buf_len = 512, // (416samples * 2ch * 2(short)) = 1664 64 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, //Interrupt level 1 65 | .use_apll = 0 //1 66 | }; 67 | 68 | i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); 69 | 70 | i2s_set_pin(I2S_NUM, NULL); 71 | i2s_set_dac_mode(/*I2S_DAC_CHANNEL_LEFT_EN*/ I2S_DAC_CHANNEL_BOTH_EN); 72 | 73 | #else 74 | 75 | i2s_config_t i2s_config = { 76 | .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX 77 | .sample_rate = audio_sample_rate, 78 | .bits_per_sample = 16, 79 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels 80 | .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB, 81 | .dma_buf_count = 4, 82 | //.dma_buf_len = 1472 / 2, // (368samples * 2ch * 2(short)) = 1472 83 | .dma_buf_len = 512, // (416samples * 2ch * 2(short)) = 1664 84 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, //Interrupt level 1 85 | .use_apll = 1 86 | }; 87 | 88 | i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); 89 | 90 | 91 | i2s_pin_config_t pin_config = { 92 | .bck_io_num = 26, 93 | .ws_io_num = 25, 94 | .data_out_num = 27, 95 | .data_in_num = -1 //Not used 96 | }; 97 | i2s_set_pin(I2S_NUM, &pin_config); 98 | 99 | #endif 100 | 101 | odroid_volume_level level = odroid_settings_Volume_get(); 102 | odroid_audio_volume_set(level); 103 | } 104 | 105 | void odroid_audio_terminate() 106 | { 107 | i2s_zero_dma_buffer(I2S_NUM); 108 | i2s_stop(I2S_NUM); 109 | 110 | i2s_start(I2S_NUM); 111 | 112 | 113 | esp_err_t err = rtc_gpio_init(GPIO_NUM_25); 114 | err = rtc_gpio_init(GPIO_NUM_26); 115 | if (err != ESP_OK) 116 | { 117 | abort(); 118 | } 119 | 120 | err = rtc_gpio_set_direction(GPIO_NUM_25, RTC_GPIO_MODE_OUTPUT_ONLY); 121 | err = rtc_gpio_set_direction(GPIO_NUM_26, RTC_GPIO_MODE_OUTPUT_ONLY); 122 | if (err != ESP_OK) 123 | { 124 | abort(); 125 | } 126 | 127 | err = rtc_gpio_set_level(GPIO_NUM_25, 0); 128 | err = rtc_gpio_set_level(GPIO_NUM_26, 0); 129 | if (err != ESP_OK) 130 | { 131 | abort(); 132 | } 133 | } 134 | 135 | void odroid_audio_submit(short* stereoAudioBuffer, int frameCount) 136 | { 137 | short currentAudioSampleCount = frameCount * 2; 138 | 139 | #if BUILTIN_DAC_ENABLED 140 | // Convert for built in DAC 141 | for (short i = 0; i < currentAudioSampleCount; i += 2) 142 | { 143 | int32_t dac0; 144 | int32_t dac1; 145 | 146 | if (Volume == 0.0f) 147 | { 148 | // Disable amplifier 149 | dac0 = 0; 150 | dac1 = 0; 151 | } 152 | else 153 | { 154 | dac1 = 0x8000; 155 | 156 | // Down mix stero to mono 157 | int32_t sample = stereoAudioBuffer[i]; 158 | sample += stereoAudioBuffer[i + 1]; 159 | sample >>= 1; 160 | 161 | // Apply volume 162 | sample *= Volume; 163 | 164 | // Convert to unsigned 165 | dac0 = sample + 0x8000; 166 | } 167 | 168 | stereoAudioBuffer[i] = (int16_t)dac1; 169 | stereoAudioBuffer[i + 1] = (int16_t)dac0; 170 | } 171 | 172 | #endif 173 | 174 | int len = currentAudioSampleCount * sizeof(int16_t); 175 | int count = i2s_write_bytes(I2S_NUM, (const char *)stereoAudioBuffer, len, portMAX_DELAY); 176 | if (count != len) 177 | { 178 | printf("i2s_write_bytes: count (%d) != len (%d)\n", count, len); 179 | abort(); 180 | } 181 | } 182 | 183 | void odroid_audio_submit_zero() 184 | { 185 | esp_err_t err = i2s_zero_dma_buffer(I2S_NUM); 186 | if (err != ESP_OK) abort(); 187 | } 188 | 189 | int odroid_audio_sample_rate_get() 190 | { 191 | return audio_sample_rate; 192 | } 193 | -------------------------------------------------------------------------------- /components/odroid/odroid_sdcard.c: -------------------------------------------------------------------------------- 1 | #include "odroid_sdcard.h" 2 | 3 | //#include "esp_err.h" 4 | #include "esp_log.h" 5 | #include "esp_vfs_fat.h" 6 | #include "driver/sdmmc_host.h" 7 | #include "driver/sdspi_host.h" 8 | #include "sdmmc_cmd.h" 9 | #include "esp_heap_caps.h" 10 | #include "esp_spiffs.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | 19 | #define SD_PIN_NUM_MISO 19 20 | #define SD_PIN_NUM_MOSI 23 21 | #define SD_PIN_NUM_CLK 18 22 | #define SD_PIN_NUM_CS 22 23 | 24 | 25 | static bool isOpen = false; 26 | 27 | 28 | esp_err_t odroid_sdcard_open(const char* base_path) 29 | { 30 | esp_err_t ret; 31 | 32 | if (isOpen) 33 | { 34 | printf("odroid_sdcard_open: alread open.\n"); 35 | ret = ESP_FAIL; 36 | } 37 | else 38 | { 39 | sdmmc_host_t host = SDSPI_HOST_DEFAULT(); 40 | host.slot = HSPI_HOST; // HSPI_HOST; 41 | //host.max_freq_khz = SDMMC_FREQ_HIGHSPEED; //10000000; 42 | host.max_freq_khz = SDMMC_FREQ_DEFAULT; 43 | 44 | sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT(); 45 | slot_config.gpio_miso = (gpio_num_t)SD_PIN_NUM_MISO; 46 | slot_config.gpio_mosi = (gpio_num_t)SD_PIN_NUM_MOSI; 47 | slot_config.gpio_sck = (gpio_num_t)SD_PIN_NUM_CLK; 48 | slot_config.gpio_cs = (gpio_num_t)SD_PIN_NUM_CS; 49 | //slot_config.dma_channel = 2; 50 | 51 | // Options for mounting the filesystem. 52 | // If format_if_mount_failed is set to true, SD card will be partitioned and 53 | // formatted in case when mounting fails. 54 | esp_vfs_fat_sdmmc_mount_config_t mount_config; 55 | memset(&mount_config, 0, sizeof(mount_config)); 56 | 57 | mount_config.format_if_mount_failed = false; 58 | mount_config.max_files = 5; 59 | 60 | 61 | // Use settings defined above to initialize SD card and mount FAT filesystem. 62 | // Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function. 63 | // Please check its source code and implement error recovery when developing 64 | // production applications. 65 | sdmmc_card_t* card; 66 | ret = esp_vfs_fat_sdmmc_mount(base_path, &host, &slot_config, &mount_config, &card); 67 | 68 | if (ret == ESP_OK) 69 | { 70 | isOpen = true; 71 | } 72 | else 73 | { 74 | printf("odroid_sdcard_open: esp_vfs_fat_sdmmc_mount failed (%d)\n", ret); 75 | } 76 | } 77 | 78 | return ret; 79 | } 80 | 81 | 82 | esp_err_t odroid_sdcard_close() 83 | { 84 | esp_err_t ret; 85 | 86 | if (!isOpen) 87 | { 88 | printf("odroid_sdcard_close: not open.\n"); 89 | ret = ESP_FAIL; 90 | } 91 | else 92 | { 93 | ret = esp_vfs_fat_sdmmc_unmount(); 94 | 95 | if (ret != ESP_OK) 96 | { 97 | printf("odroid_sdcard_close: esp_vfs_fat_sdmmc_unmount failed (%d)\n", ret); 98 | } 99 | 100 | isOpen = false; 101 | } 102 | 103 | return ret; 104 | } 105 | 106 | 107 | size_t odroid_sdcard_get_filesize(const char* path) 108 | { 109 | size_t ret = 0; 110 | 111 | if (!isOpen) 112 | { 113 | printf("odroid_sdcard_get_filesize: not open.\n"); 114 | } 115 | else 116 | { 117 | FILE* f = fopen(path, "rb"); 118 | if (f == NULL) 119 | { 120 | printf("odroid_sdcard_get_filesize: fopen failed.\n"); 121 | } 122 | else 123 | { 124 | // get the file size 125 | fseek(f, 0, SEEK_END); 126 | ret = ftell(f); 127 | fseek(f, 0, SEEK_SET); 128 | } 129 | } 130 | 131 | return ret; 132 | } 133 | 134 | size_t odroid_sdcard_copy_file_to_memory(const char* path, void* ptr) 135 | { 136 | size_t ret = 0; 137 | 138 | if (!isOpen) 139 | { 140 | printf("odroid_sdcard_copy_file_to_memory: not open.\n"); 141 | } 142 | else 143 | { 144 | if (!ptr) 145 | { 146 | printf("odroid_sdcard_copy_file_to_memory: ptr is null.\n"); 147 | } 148 | else 149 | { 150 | FILE* f = fopen(path, "rb"); 151 | if (f == NULL) 152 | { 153 | printf("odroid_sdcard_copy_file_to_memory: fopen failed.\n"); 154 | } 155 | else 156 | { 157 | // copy 158 | const size_t BLOCK_SIZE = 512; 159 | while(true) 160 | { 161 | __asm__("memw"); 162 | size_t count = fread((uint8_t*)ptr + ret, 1, BLOCK_SIZE, f); 163 | __asm__("memw"); 164 | 165 | ret += count; 166 | 167 | if (count < BLOCK_SIZE) break; 168 | } 169 | } 170 | } 171 | } 172 | 173 | return ret; 174 | } 175 | 176 | char* odroid_sdcard_create_savefile_path(const char* base_path, const char* fileName) 177 | { 178 | char* result = NULL; 179 | 180 | if (!base_path) abort(); 181 | if (!fileName) abort(); 182 | 183 | //printf("%s: base_path='%s', fileName='%s'\n", __func__, base_path, fileName); 184 | 185 | // Determine folder 186 | char* extension = fileName + strlen(fileName); // place at NULL terminator 187 | while (extension != fileName) 188 | { 189 | if (*extension == '.') 190 | { 191 | ++extension; 192 | break; 193 | } 194 | --extension; 195 | } 196 | 197 | if (extension == fileName) 198 | { 199 | printf("%s: File extention not found.\n", __func__); 200 | abort(); 201 | } 202 | 203 | //printf("%s: extension='%s'\n", __func__, extension); 204 | 205 | const char* DATA_PATH = "/odroid/data/"; 206 | const char* SAVE_EXTENSION = ".sav"; 207 | 208 | size_t savePathLength = strlen(base_path) + strlen(DATA_PATH) + strlen(extension) + 1 + strlen(fileName) + strlen(SAVE_EXTENSION) + 1; 209 | char* savePath = malloc(savePathLength); 210 | if (savePath) 211 | { 212 | strcpy(savePath, base_path); 213 | strcat(savePath, DATA_PATH); 214 | strcat(savePath, extension); 215 | strcat(savePath, "/"); 216 | strcat(savePath, fileName); 217 | strcat(savePath, SAVE_EXTENSION); 218 | 219 | printf("%s: savefile_path='%s'\n", __func__, savePath); 220 | 221 | result = savePath; 222 | } 223 | 224 | return result; 225 | } 226 | -------------------------------------------------------------------------------- /components/frodo/CPU1541.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CPU1541.h - 6502 (1541) emulation (line based) 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _CPU_1541_H 8 | #define _CPU_1541_H 9 | 10 | #include "CIA.h" 11 | #include "C64.h" 12 | 13 | #pragma GCC diagnostic warning "-Wparentheses" 14 | 15 | // Set this to 1 if the 6502 PC should be represented by a real pointer 16 | #ifndef FRODO_SC 17 | #ifndef PC_IS_POINTER 18 | #define PC_IS_POINTER 1 19 | #endif 20 | #endif 21 | 22 | // Set this to 1 for more precise CPU cycle calculation 23 | #ifndef PRECISE_CPU_CYCLES 24 | #define PRECISE_CPU_CYCLES 0 25 | #endif 26 | 27 | 28 | // Interrupt types 29 | enum { 30 | INT_VIA1IRQ, 31 | INT_VIA2IRQ, 32 | INT_IECIRQ 33 | // INT_RESET (private) 34 | }; 35 | 36 | 37 | class C64; 38 | class Job1541; 39 | class C64Display; 40 | struct MOS6502State; 41 | 42 | 43 | // 6502 emulation (1541) 44 | class MOS6502_1541 { 45 | public: 46 | MOS6502_1541(C64 *c64, Job1541 *job, C64Display *disp, uint8 *Ram, uint8 *Rom); 47 | 48 | #ifdef FRODO_SC 49 | void EmulateCycle(void); // Emulate one clock cycle 50 | #else 51 | int EmulateLine(int cycles_left); // Emulate until cycles_left underflows 52 | #endif 53 | void Reset(void); 54 | void AsyncReset(void); // Reset the CPU asynchronously 55 | void GetState(MOS6502State *s); 56 | void SetState(MOS6502State *s); 57 | uint8 ExtReadByte(uint16 adr); 58 | void ExtWriteByte(uint16 adr, uint8 byte); 59 | void CountVIATimers(int cycles); 60 | void NewATNState(void); 61 | void IECInterrupt(void); 62 | void TriggerJobIRQ(void); 63 | bool InterruptEnabled(void); 64 | 65 | MOS6526_2 *TheCIA2; // Pointer to C64 CIA 2 66 | 67 | uint8 IECLines; // State of IEC lines (bit 7 - DATA, bit 6 - CLK) 68 | bool Idle; // true: 1541 is idle 69 | 70 | private: 71 | uint8 read_byte(uint16 adr); 72 | uint8 read_byte_io(uint16 adr); 73 | uint16 read_word(uint16 adr); 74 | void write_byte(uint16 adr, uint8 byte); 75 | void write_byte_io(uint16 adr, uint8 byte); 76 | 77 | uint8 read_zp(uint16 adr); 78 | uint16 read_zp_word(uint16 adr); 79 | void write_zp(uint16 adr, uint8 byte); 80 | 81 | void jump(uint16 adr); 82 | void illegal_op(uint8 op, uint16 at); 83 | void illegal_jump(uint16 at, uint16 to); 84 | 85 | void do_adc(uint8 byte); 86 | void do_sbc(uint8 byte); 87 | 88 | uint8 *ram; // Pointer to main RAM 89 | uint8 *rom; // Pointer to ROM 90 | C64 *the_c64; // Pointer to C64 object 91 | C64Display *the_display; // Pointer to C64 display object 92 | Job1541 *the_job; // Pointer to 1541 job object 93 | 94 | union { // Pending interrupts 95 | uint8 intr[4]; // Index: See definitions above 96 | unsigned long intr_any; 97 | } interrupt; 98 | 99 | uint8 n_flag, z_flag; 100 | bool v_flag, d_flag, i_flag, c_flag; 101 | uint8 a, x, y, sp; 102 | #if PC_IS_POINTER 103 | uint8 *pc, *pc_base; 104 | #else 105 | uint16 pc; 106 | #endif 107 | 108 | #ifdef FRODO_SC 109 | uint32 first_irq_cycle; 110 | 111 | uint8 state, op; // Current state and opcode 112 | uint16 ar, ar2; // Address registers 113 | uint8 rdbuf; // Data buffer for RMW instructions 114 | uint8 ddr, pr; // Processor port 115 | #else 116 | int borrowed_cycles; // Borrowed cycles from next line 117 | #endif 118 | 119 | uint8 via1_pra; // PRA of VIA 1 120 | uint8 via1_ddra; // DDRA of VIA 1 121 | uint8 via1_prb; // PRB of VIA 1 122 | uint8 via1_ddrb; // DDRB of VIA 1 123 | uint16 via1_t1c; // T1 Counter of VIA 1 124 | uint16 via1_t1l; // T1 Latch of VIA 1 125 | uint16 via1_t2c; // T2 Counter of VIA 1 126 | uint16 via1_t2l; // T2 Latch of VIA 1 127 | uint8 via1_sr; // SR of VIA 1 128 | uint8 via1_acr; // ACR of VIA 1 129 | uint8 via1_pcr; // PCR of VIA 1 130 | uint8 via1_ifr; // IFR of VIA 1 131 | uint8 via1_ier; // IER of VIA 1 132 | 133 | uint8 via2_pra; // PRA of VIA 2 134 | uint8 via2_ddra; // DDRA of VIA 2 135 | uint8 via2_prb; // PRB of VIA 2 136 | uint8 via2_ddrb; // DDRB of VIA 2 137 | uint16 via2_t1c; // T1 Counter of VIA 2 138 | uint16 via2_t1l; // T1 Latch of VIA 2 139 | uint16 via2_t2c; // T2 Counter of VIA 2 140 | uint16 via2_t2l; // T2 Latch of VIA 2 141 | uint8 via2_sr; // SR of VIA 2 142 | uint8 via2_acr; // ACR of VIA 2 143 | uint8 via2_pcr; // PCR of VIA 2 144 | uint8 via2_ifr; // IFR of VIA 2 145 | uint8 via2_ier; // IER of VIA 2 146 | }; 147 | 148 | // 6502 state 149 | struct MOS6502State { 150 | uint8 a, x, y; 151 | uint8 p; // Processor flags 152 | uint16 pc, sp; 153 | 154 | uint8 intr[4]; // Interrupt state 155 | bool instruction_complete; 156 | bool idle; 157 | 158 | uint8 via1_pra; // VIA 1 159 | uint8 via1_ddra; 160 | uint8 via1_prb; 161 | uint8 via1_ddrb; 162 | uint16 via1_t1c; 163 | uint16 via1_t1l; 164 | uint16 via1_t2c; 165 | uint16 via1_t2l; 166 | uint8 via1_sr; 167 | uint8 via1_acr; 168 | uint8 via1_pcr; 169 | uint8 via1_ifr; 170 | uint8 via1_ier; 171 | 172 | uint8 via2_pra; // VIA 2 173 | uint8 via2_ddra; 174 | uint8 via2_prb; 175 | uint8 via2_ddrb; 176 | uint16 via2_t1c; 177 | uint16 via2_t1l; 178 | uint16 via2_t2c; 179 | uint16 via2_t2l; 180 | uint8 via2_sr; 181 | uint8 via2_acr; 182 | uint8 via2_pcr; 183 | uint8 via2_ifr; 184 | uint8 via2_ier; 185 | }; 186 | 187 | 188 | 189 | /* 190 | * Trigger job loop IRQ 191 | */ 192 | 193 | #ifdef FRODO_SC 194 | inline void MOS6502_1541::TriggerJobIRQ(void) 195 | { 196 | if (!(interrupt.intr[INT_VIA2IRQ])) 197 | first_irq_cycle = the_c64->CycleCounter; 198 | interrupt.intr[INT_VIA2IRQ] = true; 199 | Idle = false; 200 | } 201 | #else 202 | inline void MOS6502_1541::TriggerJobIRQ(void) 203 | { 204 | interrupt.intr[INT_VIA2IRQ] = true; 205 | Idle = false; 206 | } 207 | #endif 208 | 209 | 210 | /* 211 | * Count VIA timers 212 | */ 213 | 214 | inline void MOS6502_1541::CountVIATimers(int cycles) 215 | { 216 | unsigned long tmp; 217 | 218 | via1_t1c = tmp = via1_t1c - cycles; 219 | if (tmp > 0xffff) { 220 | if (via1_acr & 0x40) // Reload from latch in free-run mode 221 | via1_t1c = via1_t1l; 222 | via1_ifr |= 0x40; 223 | } 224 | 225 | if (!(via1_acr & 0x20)) { // Only count in one-shot mode 226 | via1_t2c = tmp = via1_t2c - cycles; 227 | if (tmp > 0xffff) 228 | via1_ifr |= 0x20; 229 | } 230 | 231 | via2_t1c = tmp = via2_t1c - cycles; 232 | if (tmp > 0xffff) { 233 | if (via2_acr & 0x40) // Reload from latch in free-run mode 234 | via2_t1c = via2_t1l; 235 | via2_ifr |= 0x40; 236 | if (via2_ier & 0x40) 237 | TriggerJobIRQ(); 238 | } 239 | 240 | if (!(via2_acr & 0x20)) { // Only count in one-shot mode 241 | via2_t2c = tmp = via2_t2c - cycles; 242 | if (tmp > 0xffff) 243 | via2_ifr |= 0x20; 244 | } 245 | } 246 | 247 | 248 | /* 249 | * ATN line probably changed state, recalc IECLines 250 | */ 251 | 252 | inline void MOS6502_1541::NewATNState(void) 253 | { 254 | uint8 byte = ~via1_prb & via1_ddrb; 255 | IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80 // DATA (incl. ATN acknowledge) 256 | | (byte << 3) & 0x40; // CLK 257 | } 258 | 259 | 260 | /* 261 | * Interrupt by negative edge of ATN on IEC bus 262 | */ 263 | 264 | inline void MOS6502_1541::IECInterrupt(void) 265 | { 266 | ram[0x7c] = 1; 267 | 268 | // Wake up 1541 269 | Idle = false; 270 | } 271 | 272 | 273 | /* 274 | * Test if interrupts are enabled (for job loop) 275 | */ 276 | 277 | inline bool MOS6502_1541::InterruptEnabled(void) 278 | { 279 | return !i_flag; 280 | } 281 | 282 | #endif 283 | -------------------------------------------------------------------------------- /components/odroid/odroid_settings.c: -------------------------------------------------------------------------------- 1 | #include "nvs_flash.h" 2 | #include "esp_heap_caps.h" 3 | 4 | #include "string.h" 5 | 6 | #include "odroid_audio.h" 7 | 8 | 9 | static const char* NvsNamespace = "Odroid"; 10 | 11 | static const char* NvsKey_RomFilePath = "RomFilePath"; 12 | static const char* NvsKey_Volume = "Volume"; 13 | static const char* NvsKey_VRef = "VRef"; 14 | static const char* NvsKey_AppSlot = "AppSlot"; 15 | static const char* NvsKey_DataSlot = "DataSlot"; 16 | static const char* NvsKey_Backlight = "Backlight"; 17 | 18 | 19 | 20 | char* odroid_util_GetFileName(const char* path) 21 | { 22 | int length = strlen(path); 23 | int fileNameStart = length; 24 | 25 | if (fileNameStart < 1) abort(); 26 | 27 | while (fileNameStart > 0) 28 | { 29 | if (path[fileNameStart] == '/') 30 | { 31 | ++fileNameStart; 32 | break; 33 | } 34 | 35 | --fileNameStart; 36 | } 37 | 38 | int size = length - fileNameStart + 1; 39 | 40 | char* result = malloc(size); 41 | if (!result) abort(); 42 | 43 | result[size - 1] = 0; 44 | for (int i = 0; i < size - 1; ++i) 45 | { 46 | result[i] = path[fileNameStart + i]; 47 | } 48 | 49 | //printf("GetFileName: result='%s'\n", result); 50 | 51 | return result; 52 | } 53 | 54 | char* odroid_util_GetFileExtenstion(const char* path) 55 | { 56 | // Note: includes '.' 57 | int length = strlen(path); 58 | int extensionStart = length; 59 | 60 | if (extensionStart < 1) abort(); 61 | 62 | while (extensionStart > 0) 63 | { 64 | if (path[extensionStart] == '.') 65 | { 66 | break; 67 | } 68 | 69 | --extensionStart; 70 | } 71 | 72 | int size = length - extensionStart + 1; 73 | 74 | char* result = malloc(size); 75 | if (!result) abort(); 76 | 77 | result[size - 1] = 0; 78 | for (int i = 0; i < size - 1; ++i) 79 | { 80 | result[i] = path[extensionStart + i]; 81 | } 82 | 83 | //printf("GetFileExtenstion: result='%s'\n", result); 84 | 85 | return result; 86 | } 87 | 88 | char* odroid_util_GetFileNameWithoutExtension(const char* path) 89 | { 90 | char* fileName = odroid_util_GetFileName(path); 91 | 92 | int length = strlen(fileName); 93 | int extensionStart = length; 94 | 95 | if (extensionStart < 1) abort(); 96 | 97 | while (extensionStart > 0) 98 | { 99 | if (fileName[extensionStart] == '.') 100 | { 101 | break; 102 | } 103 | 104 | --extensionStart; 105 | } 106 | 107 | int size = extensionStart + 1; 108 | 109 | char* result = malloc(size); 110 | if (!result) abort(); 111 | 112 | result[size - 1] = 0; 113 | for (int i = 0; i < size - 1; ++i) 114 | { 115 | result[i] = fileName[i]; 116 | } 117 | 118 | free(fileName); 119 | 120 | //printf("GetFileNameWithoutExtension: result='%s'\n", result); 121 | 122 | return result; 123 | } 124 | 125 | 126 | int32_t odroid_settings_VRef_get() 127 | { 128 | int32_t result = 1100; 129 | 130 | // Open 131 | nvs_handle my_handle; 132 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 133 | if (err != ESP_OK) abort(); 134 | 135 | 136 | // Read 137 | err = nvs_get_i32(my_handle, NvsKey_VRef, &result); 138 | if (err == ESP_OK) 139 | { 140 | printf("odroid_settings_VRefGet: value=%d\n", result); 141 | } 142 | 143 | 144 | // Close 145 | nvs_close(my_handle); 146 | 147 | return result; 148 | } 149 | void odroid_settings_VRef_set(int32_t value) 150 | { 151 | nvs_handle my_handle; 152 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 153 | if (err != ESP_OK) abort(); 154 | 155 | // Write key 156 | err = nvs_set_i32(my_handle, NvsKey_VRef, value); 157 | if (err != ESP_OK) abort(); 158 | 159 | // Close 160 | nvs_close(my_handle); 161 | } 162 | 163 | 164 | int32_t odroid_settings_Volume_get() 165 | { 166 | int result = ODROID_VOLUME_LEVEL3; 167 | 168 | // Open 169 | nvs_handle my_handle; 170 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 171 | if (err != ESP_OK) abort(); 172 | 173 | // Read 174 | err = nvs_get_i32(my_handle, NvsKey_Volume, &result); 175 | if (err == ESP_OK) 176 | { 177 | printf("odroid_settings_Volume_get: value=%d\n", result); 178 | } 179 | 180 | // Close 181 | nvs_close(my_handle); 182 | 183 | return result; 184 | } 185 | void odroid_settings_Volume_set(int32_t value) 186 | { 187 | // Open 188 | nvs_handle my_handle; 189 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 190 | if (err != ESP_OK) abort(); 191 | 192 | // Read 193 | err = nvs_set_i32(my_handle, NvsKey_Volume, value); 194 | if (err != ESP_OK) abort(); 195 | 196 | // Close 197 | nvs_close(my_handle); 198 | } 199 | 200 | 201 | char* odroid_settings_RomFilePath_get() 202 | { 203 | char* result = NULL; 204 | 205 | // Open 206 | nvs_handle my_handle; 207 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 208 | if (err != ESP_OK) abort(); 209 | 210 | 211 | // Read 212 | size_t required_size; 213 | err = nvs_get_str(my_handle, NvsKey_RomFilePath, NULL, &required_size); 214 | if (err == ESP_OK) 215 | { 216 | char* value = malloc(required_size); 217 | if (!value) abort(); 218 | 219 | err = nvs_get_str(my_handle, NvsKey_RomFilePath, value, &required_size); 220 | if (err != ESP_OK) abort(); 221 | 222 | result = value; 223 | 224 | printf("odroid_settings_RomFilePathGet: value='%s'\n", value); 225 | } 226 | 227 | 228 | // Close 229 | nvs_close(my_handle); 230 | 231 | return result; 232 | } 233 | void odroid_settings_RomFilePath_set(char* value) 234 | { 235 | nvs_handle my_handle; 236 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 237 | if (err != ESP_OK) abort(); 238 | 239 | // Write key 240 | err = nvs_set_str(my_handle, NvsKey_RomFilePath, value); 241 | if (err != ESP_OK) abort(); 242 | 243 | // Close 244 | nvs_close(my_handle); 245 | } 246 | 247 | 248 | int32_t odroid_settings_AppSlot_get() 249 | { 250 | int32_t result = -1; 251 | 252 | // Open 253 | nvs_handle my_handle; 254 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 255 | if (err != ESP_OK) abort(); 256 | 257 | 258 | // Read 259 | err = nvs_get_i32(my_handle, NvsKey_AppSlot, &result); 260 | if (err == ESP_OK) 261 | { 262 | printf("odroid_settings_AppSlot_get: value=%d\n", result); 263 | } 264 | 265 | 266 | // Close 267 | nvs_close(my_handle); 268 | 269 | return result; 270 | } 271 | void odroid_settings_AppSlot_set(int32_t value) 272 | { 273 | nvs_handle my_handle; 274 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 275 | if (err != ESP_OK) abort(); 276 | 277 | // Write key 278 | err = nvs_set_i32(my_handle, NvsKey_AppSlot, value); 279 | if (err != ESP_OK) abort(); 280 | 281 | // Close 282 | nvs_close(my_handle); 283 | } 284 | 285 | 286 | int32_t odroid_settings_DataSlot_get() 287 | { 288 | int32_t result = -1; 289 | 290 | // Open 291 | nvs_handle my_handle; 292 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 293 | if (err != ESP_OK) abort(); 294 | 295 | 296 | // Read 297 | err = nvs_get_i32(my_handle, NvsKey_DataSlot, &result); 298 | if (err == ESP_OK) 299 | { 300 | printf("odroid_settings_DataSlot_get: value=%d\n", result); 301 | } 302 | 303 | 304 | // Close 305 | nvs_close(my_handle); 306 | 307 | return result; 308 | } 309 | void odroid_settings_DataSlot_set(int32_t value) 310 | { 311 | nvs_handle my_handle; 312 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 313 | if (err != ESP_OK) abort(); 314 | 315 | // Write key 316 | err = nvs_set_i32(my_handle, NvsKey_DataSlot, value); 317 | if (err != ESP_OK) abort(); 318 | 319 | // Close 320 | nvs_close(my_handle); 321 | } 322 | 323 | 324 | int32_t odroid_settings_Backlight_get() 325 | { 326 | // TODO: Move to header 327 | int result = 2; 328 | 329 | // Open 330 | nvs_handle my_handle; 331 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 332 | if (err != ESP_OK) abort(); 333 | 334 | // Read 335 | err = nvs_get_i32(my_handle, NvsKey_Backlight, &result); 336 | if (err == ESP_OK) 337 | { 338 | printf("odroid_settings_Backlight_get: value=%d\n", result); 339 | } 340 | 341 | // Close 342 | nvs_close(my_handle); 343 | 344 | return result; 345 | } 346 | void odroid_settings_Backlight_set(int32_t value) 347 | { 348 | // Open 349 | nvs_handle my_handle; 350 | esp_err_t err = nvs_open(NvsNamespace, NVS_READWRITE, &my_handle); 351 | if (err != ESP_OK) abort(); 352 | 353 | // Read 354 | err = nvs_set_i32(my_handle, NvsKey_Backlight, value); 355 | if (err != ESP_OK) abort(); 356 | 357 | // Close 358 | nvs_close(my_handle); 359 | } 360 | -------------------------------------------------------------------------------- /components/frodo/VIC.h: -------------------------------------------------------------------------------- 1 | /* 2 | * VIC.h - 6569R5 emulation (line based) 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | */ 6 | 7 | #ifndef _VIC_H 8 | #define _VIC_H 9 | 10 | 11 | // Define this if you want global variables instead of member variables 12 | //#if defined(__i386) || defined(mc68000) || defined(__MC68K__) 13 | //#define GLOBAL_VARS 14 | //#endif 15 | 16 | // Define this if you have a processor that can do unaligned accesses quickly 17 | //#if defined(__i386) || defined(mc68000) || defined(__MC68K__) 18 | //#define CAN_ACCESS_UNALIGNED 19 | //#endif 20 | 21 | 22 | // Total number of raster lines (PAL) 23 | const unsigned TOTAL_RASTERS = 0x138; 24 | 25 | // Screen refresh frequency (PAL) 26 | const unsigned SCREEN_FREQ = 50; 27 | 28 | 29 | class MOS6510; 30 | class C64Display; 31 | class C64; 32 | struct MOS6569State; 33 | 34 | 35 | class MOS6569 { 36 | public: 37 | MOS6569(C64 *c64, C64Display *disp, MOS6510 *CPU, uint8 *RAM, uint8 *Char, uint8 *Color); 38 | 39 | uint8 ReadRegister(uint16 adr); 40 | void WriteRegister(uint16 adr, uint8 byte); 41 | #ifdef FRODO_SC 42 | bool EmulateCycle(void); 43 | #else 44 | int EmulateLine(void); 45 | #endif 46 | void ChangedVA(uint16 new_va); // CIA VA14/15 has changed 47 | void TriggerLightpen(void); // Trigger lightpen interrupt 48 | void ReInitColors(void); 49 | void GetState(MOS6569State *vd); 50 | void SetState(MOS6569State *vd); 51 | 52 | #ifdef FRODO_SC 53 | uint8 LastVICByte; 54 | #endif 55 | 56 | private: 57 | #ifndef GLOBAL_VARS 58 | void vblank(void); 59 | void raster_irq(void); 60 | 61 | uint16 mx[8]; // VIC registers 62 | uint8 my[8]; 63 | uint8 mx8; 64 | uint8 ctrl1, ctrl2; 65 | uint8 lpx, lpy; 66 | uint8 me, mxe, mye, mdp, mmc; 67 | uint8 vbase; 68 | uint8 irq_flag, irq_mask; 69 | uint8 clx_spr, clx_bgr; 70 | uint8 ec, b0c, b1c, b2c, b3c, mm0, mm1; 71 | uint8 sc[8]; 72 | 73 | uint8 *ram, *char_rom, *color_ram; // Pointers to RAM and ROM 74 | C64 *the_c64; // Pointer to C64 75 | C64Display *the_display; // Pointer to C64Display 76 | MOS6510 *the_cpu; // Pointer to 6510 77 | 78 | uint8 colors[256]; // Indices of the 16 C64 colors (16 times mirrored to avoid "& 0x0f") 79 | 80 | uint8 ec_color, b0c_color, b1c_color, 81 | b2c_color, b3c_color; // Indices for exterior/background colors 82 | uint8 mm0_color, mm1_color; // Indices for MOB multicolors 83 | uint8 spr_color[8]; // Indices for MOB colors 84 | 85 | uint32 ec_color_long; // ec_color expanded to 32 bits 86 | 87 | uint8 matrix_line[40]; // Buffer for video line, read in Bad Lines 88 | uint8 color_line[40]; // Buffer for color line, read in Bad Lines 89 | 90 | #ifdef __POWERPC__ 91 | double chunky_tmp[0x180/8]; // Temporary line buffer for speedup 92 | #endif 93 | uint8 *chunky_line_start; // Pointer to start of current line in bitmap buffer 94 | int xmod; // Number of bytes per row 95 | 96 | uint16 raster_y; // Current raster line 97 | uint16 irq_raster; // Interrupt raster line 98 | uint16 dy_start; // Comparison values for border logic 99 | uint16 dy_stop; 100 | uint16 rc; // Row counter 101 | uint16 vc; // Video counter 102 | uint16 vc_base; // Video counter base 103 | uint16 x_scroll; // X scroll value 104 | uint16 y_scroll; // Y scroll value 105 | uint16 cia_vabase; // CIA VA14/15 video base 106 | 107 | uint16 mc[8]; // Sprite data counters 108 | 109 | int display_idx; // Index of current display mode 110 | int skip_counter; // Counter for frame-skipping 111 | 112 | long pad0; // Keep buffers long-aligned 113 | uint8 spr_coll_buf[0x180]; // Buffer for sprite-sprite collisions and priorities 114 | uint8 fore_mask_buf[0x180/8]; // Foreground mask for sprite-graphics collisions and priorities 115 | #ifndef CAN_ACCESS_UNALIGNED 116 | uint8 text_chunky_buf[40*8]; // Line graphics buffer 117 | #endif 118 | 119 | bool display_state; // true: Display state, false: Idle state 120 | bool border_on; // Flag: Upper/lower border on (Frodo SC: Main border flipflop) 121 | bool frame_skipped; // Flag: Frame is being skipped 122 | uint8 bad_lines_enabled; // Flag: Bad Lines enabled for this frame 123 | bool lp_triggered; // Flag: Lightpen was triggered in this frame 124 | 125 | #ifdef FRODO_SC 126 | uint8 read_byte(uint16 adr); 127 | void matrix_access(void); 128 | void graphics_access(void); 129 | void draw_graphics(void); 130 | void draw_sprites(void); 131 | void draw_background(void); 132 | 133 | int cycle; // Current cycle in line (1..63) 134 | 135 | uint8 *chunky_ptr; // Pointer in chunky bitmap buffer (this is where out output goes) 136 | uint8 *fore_mask_ptr; // Pointer in fore_mask_buf 137 | 138 | uint16 matrix_base; // Video matrix base 139 | uint16 char_base; // Character generator base 140 | uint16 bitmap_base; // Bitmap base 141 | 142 | bool is_bad_line; // Flag: Current line is bad line 143 | bool draw_this_line; // Flag: This line is drawn on the screen 144 | bool ud_border_on; // Flag: Upper/lower border on 145 | bool vblanking; // Flag: VBlank in next cycle 146 | 147 | bool border_on_sample[5]; // Samples of border state at different cycles (1, 17, 18, 56, 57) 148 | uint8 border_color_sample[0x180/8]; // Samples of border color at each "displayed" cycle 149 | 150 | uint8 ref_cnt; // Refresh counter 151 | uint8 spr_exp_y; // 8 sprite y expansion flipflops 152 | uint8 spr_dma_on; // 8 flags: Sprite DMA active 153 | uint8 spr_disp_on; // 8 flags: Sprite display active 154 | uint8 spr_draw; // 8 flags: Draw sprite in this line 155 | uint16 spr_ptr[8]; // Sprite data pointers 156 | uint16 mc_base[8]; // Sprite data counter bases 157 | 158 | uint16 raster_x; // Current raster x position 159 | 160 | int ml_index; // Index in matrix/color_line[] 161 | uint8 gfx_data, char_data, color_data, last_char_data; 162 | uint8 spr_data[8][4]; // Sprite data read 163 | uint8 spr_draw_data[8][4]; // Sprite data for drawing 164 | 165 | uint32 first_ba_cycle; // Cycle when BA first went low 166 | #else 167 | uint8 *get_physical(uint16 adr); 168 | void make_mc_table(void); 169 | void el_std_text(uint8 *p, uint8 *q, uint8 *r); 170 | void el_mc_text(uint8 *p, uint8 *q, uint8 *r); 171 | void el_std_bitmap(uint8 *p, uint8 *q, uint8 *r); 172 | void el_mc_bitmap(uint8 *p, uint8 *q, uint8 *r); 173 | void el_ecm_text(uint8 *p, uint8 *q, uint8 *r); 174 | void el_std_idle(uint8 *p, uint8 *r); 175 | void el_mc_idle(uint8 *p, uint8 *r); 176 | void el_sprites(uint8 *chunky_ptr); 177 | int el_update_mc(int raster); 178 | 179 | uint16 mc_color_lookup[4]; 180 | 181 | bool border_40_col; // Flag: 40 column border 182 | uint8 sprite_on; // 8 flags: Sprite display/DMA active 183 | 184 | uint8 *matrix_base; // Video matrix base 185 | uint8 *char_base; // Character generator base 186 | uint8 *bitmap_base; // Bitmap base 187 | #endif 188 | #endif 189 | }; 190 | 191 | 192 | // VIC state 193 | struct MOS6569State { 194 | uint8 m0x; // Sprite coordinates 195 | uint8 m0y; 196 | uint8 m1x; 197 | uint8 m1y; 198 | uint8 m2x; 199 | uint8 m2y; 200 | uint8 m3x; 201 | uint8 m3y; 202 | uint8 m4x; 203 | uint8 m4y; 204 | uint8 m5x; 205 | uint8 m5y; 206 | uint8 m6x; 207 | uint8 m6y; 208 | uint8 m7x; 209 | uint8 m7y; 210 | uint8 mx8; 211 | 212 | uint8 ctrl1; // Control registers 213 | uint8 raster; 214 | uint8 lpx; 215 | uint8 lpy; 216 | uint8 me; 217 | uint8 ctrl2; 218 | uint8 mye; 219 | uint8 vbase; 220 | uint8 irq_flag; 221 | uint8 irq_mask; 222 | uint8 mdp; 223 | uint8 mmc; 224 | uint8 mxe; 225 | uint8 mm; 226 | uint8 md; 227 | 228 | uint8 ec; // Color registers 229 | uint8 b0c; 230 | uint8 b1c; 231 | uint8 b2c; 232 | uint8 b3c; 233 | uint8 mm0; 234 | uint8 mm1; 235 | uint8 m0c; 236 | uint8 m1c; 237 | uint8 m2c; 238 | uint8 m3c; 239 | uint8 m4c; 240 | uint8 m5c; 241 | uint8 m6c; 242 | uint8 m7c; 243 | // Additional registers 244 | uint8 pad0; 245 | uint16 irq_raster; // IRQ raster line 246 | uint16 vc; // Video counter 247 | uint16 vc_base; // Video counter base 248 | uint8 rc; // Row counter 249 | uint8 spr_dma; // 8 Flags: Sprite DMA active 250 | uint8 spr_disp; // 8 Flags: Sprite display active 251 | uint8 mc[8]; // Sprite data counters 252 | uint8 mc_base[8]; // Sprite data counter bases 253 | bool display_state; // true: Display state, false: Idle state 254 | bool bad_line; // Flag: Bad Line state 255 | bool bad_line_enable; // Flag: Bad Lines enabled for this frame 256 | bool lp_triggered; // Flag: Lightpen was triggered in this frame 257 | bool border_on; // Flag: Upper/lower border on (Frodo SC: Main border flipflop) 258 | 259 | uint16 bank_base; // VIC bank base address 260 | uint16 matrix_base; // Video matrix base 261 | uint16 char_base; // Character generator base 262 | uint16 bitmap_base; // Bitmap base 263 | uint16 sprite_base[8]; // Sprite bases 264 | 265 | // Frodo SC: 266 | int cycle; // Current cycle in line (1..63) 267 | uint16 raster_x; // Current raster x position 268 | int ml_index; // Index in matrix/color_line[] 269 | uint8 ref_cnt; // Refresh counter 270 | uint8 last_vic_byte; // Last byte read by VIC 271 | bool ud_border_on; // Flag: Upper/lower border on 272 | }; 273 | 274 | typedef union { 275 | uint32 b; 276 | struct { 277 | uint8 a,b,c,d; 278 | } a; 279 | 280 | } color_table_t; 281 | 282 | extern const color_table_t TextColorTable[16][16][256][2]; 283 | 284 | #endif 285 | -------------------------------------------------------------------------------- /components/frodo/IEC.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * IEC.cpp - IEC bus routines, 1541 emulation (DOS level) 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | * 6 | 7 | * 8 | * Notes: 9 | * ------ 10 | * 11 | * - There are three kinds of devices on the IEC bus: controllers, 12 | * listeners and talkers. We are always the controller and we 13 | * can additionally be either listener or talker. There can be 14 | * only one listener and one talker active at the same time (the 15 | * real IEC bus allows multiple listeners, but we don't). 16 | * - There is one Drive object for every emulated drive (8..11). 17 | * A pointer to one of them is stored in "listener"/"talker" 18 | * when talk()/listen() is called and is used by the functions 19 | * called afterwards. 20 | * - The Drive objects have four virtual functions so that the 21 | * interface to them is independent of their implementation: 22 | * Open() opens a channel 23 | * Close() closes a channel 24 | * Read() reads from a channel 25 | * Write() writes to a channel 26 | * - The EOI/EOF signal is special on the IEC bus in that it is 27 | * Sent before the last byte, not after it. 28 | */ 29 | 30 | #include "sysdeps.h" 31 | 32 | #include "IEC.h" 33 | #include "1541fs.h" 34 | #include "1541d64.h" 35 | #include "1541t64.h" 36 | #include "Prefs.h" 37 | #include "Display.h" 38 | 39 | 40 | /* 41 | * Constructor: Initialize variables 42 | */ 43 | 44 | IEC::IEC(C64Display *display) : the_display(display) 45 | { 46 | int i; 47 | 48 | // Create drives 8..11 49 | for (i=0; i<4; i++) 50 | drive[i] = NULL; // Important because UpdateLEDs is called from the drive constructors (via set_error) 51 | 52 | if (!ThePrefs.Emul1541Proc) 53 | for (i=0; i<4; i++) { 54 | if (ThePrefs.DriveType[i] == DRVTYPE_DIR) 55 | drive[i] = new FSDrive(this, ThePrefs.DrivePath[i]); 56 | else if (ThePrefs.DriveType[i] == DRVTYPE_D64) 57 | drive[i] = new D64Drive(this, ThePrefs.DrivePath[i]); 58 | else 59 | drive[i] = new T64Drive(this, ThePrefs.DrivePath[i]); 60 | } 61 | 62 | listener_active = talker_active = false; 63 | listening = false; 64 | } 65 | 66 | 67 | /* 68 | * Destructor: Delete drives 69 | */ 70 | 71 | IEC::~IEC() 72 | { 73 | for (int i=0; i<4; i++) 74 | delete drive[i]; 75 | } 76 | 77 | 78 | /* 79 | * Reset all drives 80 | */ 81 | 82 | void IEC::Reset(void) 83 | { 84 | for (int i=0; i<4; i++) 85 | if (drive[i] != NULL && drive[i]->Ready) 86 | drive[i]->Reset(); 87 | 88 | UpdateLEDs(); 89 | } 90 | 91 | 92 | /* 93 | * Preferences have changed, prefs points to new preferences, 94 | * ThePrefs still holds the previous ones. Check if drive settings 95 | * have changed. 96 | */ 97 | 98 | void IEC::NewPrefs(Prefs *prefs) 99 | { 100 | // Delete and recreate all changed drives 101 | for (int i=0; i<4; i++) 102 | if ((ThePrefs.DriveType[i] != prefs->DriveType[i]) || strcmp(ThePrefs.DrivePath[i], prefs->DrivePath[i]) || ThePrefs.Emul1541Proc != prefs->Emul1541Proc) { 103 | delete drive[i]; 104 | drive[i] = NULL; // Important because UpdateLEDs is called from drive constructors (via set_error()) 105 | if (!prefs->Emul1541Proc) { 106 | if (prefs->DriveType[i] == DRVTYPE_DIR) 107 | drive[i] = new FSDrive(this, prefs->DrivePath[i]); 108 | else if (prefs->DriveType[i] == DRVTYPE_D64) 109 | drive[i] = new D64Drive(this, prefs->DrivePath[i]); 110 | else 111 | drive[i] = new T64Drive(this, prefs->DrivePath[i]); 112 | } 113 | } 114 | 115 | UpdateLEDs(); 116 | } 117 | 118 | 119 | /* 120 | * Update drive LED display 121 | */ 122 | 123 | void IEC::UpdateLEDs(void) 124 | { 125 | if (drive[0] != NULL && drive[1] != NULL && drive[2] != NULL && drive[3] != NULL) 126 | the_display->UpdateLEDs(drive[0]->LED, drive[1]->LED, drive[2]->LED, drive[3]->LED); 127 | } 128 | 129 | 130 | /* 131 | * Output one byte 132 | */ 133 | 134 | uint8 IEC::Out(uint8 byte, bool eoi) 135 | { 136 | if (listener_active) { 137 | if (received_cmd == CMD_OPEN) 138 | return open_out(byte, eoi); 139 | if (received_cmd == CMD_DATA) 140 | return data_out(byte, eoi); 141 | return ST_TIMEOUT; 142 | } else 143 | return ST_TIMEOUT; 144 | } 145 | 146 | 147 | /* 148 | * Output one byte with ATN (Talk/Listen/Untalk/Unlisten) 149 | */ 150 | 151 | uint8 IEC::OutATN(uint8 byte) 152 | { 153 | received_cmd = sec_addr = 0; // Command is sent with secondary address 154 | switch (byte & 0xf0) { 155 | case ATN_LISTEN: 156 | listening = true; 157 | return listen(byte & 0x0f); 158 | case ATN_UNLISTEN: 159 | listening = false; 160 | return unlisten(); 161 | case ATN_TALK: 162 | listening = false; 163 | return talk(byte & 0x0f); 164 | case ATN_UNTALK: 165 | listening = false; 166 | return untalk(); 167 | } 168 | return ST_TIMEOUT; 169 | } 170 | 171 | 172 | /* 173 | * Output secondary address 174 | */ 175 | 176 | uint8 IEC::OutSec(uint8 byte) 177 | { 178 | if (listening) { 179 | if (listener_active) { 180 | sec_addr = byte & 0x0f; 181 | received_cmd = byte & 0xf0; 182 | return sec_listen(); 183 | } 184 | } else { 185 | if (talker_active) { 186 | sec_addr = byte & 0x0f; 187 | received_cmd = byte & 0xf0; 188 | return sec_talk(); 189 | } 190 | } 191 | return ST_TIMEOUT; 192 | } 193 | 194 | 195 | /* 196 | * Read one byte 197 | */ 198 | 199 | uint8 IEC::In(uint8 *byte) 200 | { 201 | if (talker_active && (received_cmd == CMD_DATA)) 202 | return data_in(byte); 203 | 204 | *byte = 0; 205 | return ST_TIMEOUT; 206 | } 207 | 208 | 209 | /* 210 | * Assert ATN (for Untalk) 211 | */ 212 | 213 | void IEC::SetATN(void) 214 | { 215 | // Only needed for real IEC 216 | } 217 | 218 | 219 | /* 220 | * Release ATN 221 | */ 222 | 223 | void IEC::RelATN(void) 224 | { 225 | // Only needed for real IEC 226 | } 227 | 228 | 229 | /* 230 | * Talk-attention turn-around 231 | */ 232 | 233 | void IEC::Turnaround(void) 234 | { 235 | // Only needed for real IEC 236 | } 237 | 238 | 239 | /* 240 | * System line release 241 | */ 242 | 243 | void IEC::Release(void) 244 | { 245 | // Only needed for real IEC 246 | } 247 | 248 | 249 | /* 250 | * Listen 251 | */ 252 | 253 | uint8 IEC::listen(int device) 254 | { 255 | if ((device >= 8) && (device <= 11)) { 256 | if ((listener = drive[device-8]) != NULL && listener->Ready) { 257 | listener_active = true; 258 | return ST_OK; 259 | } 260 | } 261 | 262 | listener_active = false; 263 | return ST_NOTPRESENT; 264 | } 265 | 266 | 267 | /* 268 | * Talk 269 | */ 270 | 271 | uint8 IEC::talk(int device) 272 | { 273 | if ((device >= 8) && (device <= 11)) { 274 | if ((talker = drive[device-8]) != NULL && talker->Ready) { 275 | talker_active = true; 276 | return ST_OK; 277 | } 278 | } 279 | 280 | talker_active = false; 281 | return ST_NOTPRESENT; 282 | } 283 | 284 | 285 | /* 286 | * Unlisten 287 | */ 288 | 289 | uint8 IEC::unlisten(void) 290 | { 291 | listener_active = false; 292 | return ST_OK; 293 | } 294 | 295 | 296 | /* 297 | * Untalk 298 | */ 299 | 300 | uint8 IEC::untalk(void) 301 | { 302 | talker_active = false; 303 | return ST_OK; 304 | } 305 | 306 | 307 | /* 308 | * Secondary address after Listen 309 | */ 310 | 311 | uint8 IEC::sec_listen(void) 312 | { 313 | switch (received_cmd) { 314 | 315 | case CMD_OPEN: // Prepare for receiving the file name 316 | name_ptr = name_buf; 317 | name_len = 0; 318 | return ST_OK; 319 | 320 | case CMD_CLOSE: // Close channel 321 | if (listener->LED != DRVLED_ERROR) { 322 | listener->LED = DRVLED_OFF; // Turn off drive LED 323 | UpdateLEDs(); 324 | } 325 | return listener->Close(sec_addr); 326 | } 327 | return ST_OK; 328 | } 329 | 330 | 331 | /* 332 | * Secondary address after Talk 333 | */ 334 | 335 | uint8 IEC::sec_talk(void) 336 | { 337 | return ST_OK; 338 | } 339 | 340 | 341 | /* 342 | * Byte after Open command: Store character in file name, open file on EOI 343 | */ 344 | 345 | uint8 IEC::open_out(uint8 byte, bool eoi) 346 | { 347 | if (name_len < NAMEBUF_LENGTH) { 348 | *name_ptr++ = byte; 349 | name_len++; 350 | } 351 | 352 | if (eoi) { 353 | *name_ptr = 0; // End string 354 | listener->LED = DRVLED_ON; // Turn on drive LED 355 | UpdateLEDs(); 356 | return listener->Open(sec_addr, name_buf); 357 | } 358 | 359 | return ST_OK; 360 | } 361 | 362 | 363 | /* 364 | * Write byte to channel 365 | */ 366 | 367 | uint8 IEC::data_out(uint8 byte, bool eoi) 368 | { 369 | return listener->Write(sec_addr, byte, eoi); 370 | } 371 | 372 | 373 | /* 374 | * Read byte from channel 375 | */ 376 | 377 | uint8 IEC::data_in(uint8 *byte) 378 | { 379 | return talker->Read(sec_addr, byte); 380 | } 381 | 382 | 383 | /* 384 | * Drive constructor 385 | */ 386 | 387 | Drive::Drive(IEC *iec) 388 | { 389 | the_iec = iec; 390 | LED = DRVLED_OFF; 391 | Ready = false; 392 | set_error(ERR_STARTUP); 393 | } 394 | 395 | 396 | /* 397 | * Set error message on drive 398 | */ 399 | 400 | // 1541 error messages 401 | char *Errors_1541[] = { 402 | "00, OK,00,00\r", 403 | "25,WRITE ERROR,00,00\r", 404 | "26,WRITE PROTECT ON,00,00\r", 405 | "30,SYNTAX ERROR,00,00\r", 406 | "33,SYNTAX ERROR,00,00\r", 407 | "60,WRITE FILE OPEN,00,00\r", 408 | "61,FILE NOT OPEN,00,00\r", 409 | "62,FILE NOT FOUND,00,00\r", 410 | "67,ILLEGAL TRACK OR SECTOR,00,00\r", 411 | "70,NO CHANNEL,00,00\r", 412 | "73,CBM DOS V2.6 1541,00,00\r", 413 | "74,DRIVE NOT READY,00,00\r" 414 | }; 415 | 416 | void Drive::set_error(int error) 417 | { 418 | error_ptr = Errors_1541[error]; 419 | error_len = strlen(error_ptr); 420 | 421 | // Set drive condition 422 | if (error != ERR_OK) 423 | if (error == ERR_STARTUP) 424 | LED = DRVLED_OFF; 425 | else 426 | LED = DRVLED_ERROR; 427 | else if (LED == DRVLED_ERROR) 428 | LED = DRVLED_OFF; 429 | the_iec->UpdateLEDs(); 430 | } 431 | -------------------------------------------------------------------------------- /components/frodo/1541job.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 1541job.cpp - Emulation of 1541 GCR disk reading/writing 3 | * 4 | * Frodo (C) 1994-1997,2002 Christian Bauer 5 | * 6 | 7 | * 8 | * Notes: 9 | * ------ 10 | * 11 | * - This is only used for processor-level 1541 emulation. 12 | * It simulates the 1541 disk controller hardware (R/W head, 13 | * GCR reading/writing). 14 | * - The preferences settings for drive 8 are used to 15 | * specify the .d64 file 16 | * 17 | * Incompatibilities: 18 | * ------------------ 19 | * 20 | * - No GCR writing possible (WriteSector is a ROM patch) 21 | * - Programs depending on the exact timing of head movement/disk 22 | * rotation don't work 23 | * - The .d64 error info is unused 24 | */ 25 | 26 | #include "sysdeps.h" 27 | 28 | #include "1541job.h" 29 | #include "CPU1541.h" 30 | #include "Prefs.h" 31 | 32 | #include 33 | 34 | extern "C" 35 | { 36 | #include "../odroid/odroid_display.h" 37 | } 38 | 39 | // Number of tracks/sectors 40 | const int NUM_TRACKS = 35; 41 | const int NUM_SECTORS = 683; 42 | 43 | // Size of GCR encoded data 44 | const int GCR_SECTOR_SIZE = 1+10+9+1+325+8; // SYNC Header Gap SYNC Data Gap (should be 5 SYNC bytes each) 45 | const int GCR_TRACK_SIZE = GCR_SECTOR_SIZE * 21; // Each track in gcr_data has 21 sectors 46 | const int GCR_DISK_SIZE = GCR_TRACK_SIZE * NUM_TRACKS; 47 | 48 | // Job return codes 49 | const int RET_OK = 1; // No error 50 | const int RET_NOT_FOUND = 2; // Block not found 51 | const int RET_NOT_READY = 15; // Drive not ready 52 | 53 | 54 | // Number of sectors of each track 55 | const int num_sectors[36] = { 56 | 0, 57 | 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, 58 | 19,19,19,19,19,19,19, 59 | 18,18,18,18,18,18, 60 | 17,17,17,17,17 61 | }; 62 | 63 | // Sector offset of start of track in .d64 file 64 | const int sector_offset[36] = { 65 | 0, 66 | 0,21,42,63,84,105,126,147,168,189,210,231,252,273,294,315,336, 67 | 357,376,395,414,433,452,471, 68 | 490,508,526,544,562,580, 69 | 598,615,632,649,666 70 | }; 71 | 72 | 73 | /* 74 | * Constructor: Open .d64 file if processor-level 1541 75 | * emulation is enabled 76 | */ 77 | 78 | Job1541::Job1541(uint8 *ram1541) : ram(ram1541) 79 | { 80 | the_file = NULL; 81 | 82 | gcr_data = gcr_ptr = gcr_track_start = (uint8*)heap_caps_malloc(GCR_DISK_SIZE, MALLOC_CAP_SPIRAM); //new uint8[GCR_DISK_SIZE]; 83 | gcr_track_end = gcr_track_start + GCR_TRACK_SIZE; 84 | current_halftrack = 2; 85 | 86 | disk_changed = true; 87 | 88 | if (ThePrefs.Emul1541Proc) 89 | open_d64_file(ThePrefs.DrivePath[0]); 90 | } 91 | 92 | 93 | /* 94 | * Destructor: Close .d64 file 95 | */ 96 | 97 | Job1541::~Job1541() 98 | { 99 | close_d64_file(); 100 | delete[] gcr_data; 101 | } 102 | 103 | 104 | /* 105 | * Preferences may have changed 106 | */ 107 | 108 | void Job1541::NewPrefs(Prefs *prefs) 109 | { 110 | // 1541 emulation turned off? 111 | if (!prefs->Emul1541Proc) 112 | close_d64_file(); 113 | 114 | // 1541 emulation turned on? 115 | else if (!ThePrefs.Emul1541Proc && prefs->Emul1541Proc) 116 | open_d64_file(prefs->DrivePath[0]); 117 | 118 | // .d64 file name changed? 119 | else if (strcmp(ThePrefs.DrivePath[0], prefs->DrivePath[0])) { 120 | close_d64_file(); 121 | open_d64_file(prefs->DrivePath[0]); 122 | disk_changed = true; 123 | } 124 | } 125 | 126 | 127 | /* 128 | * Open .d64 file 129 | */ 130 | 131 | void Job1541::open_d64_file_internal(char *filepath) 132 | { 133 | long size; 134 | uint8 magic[4]; 135 | uint8 bam[256]; 136 | 137 | // Clear GCR buffer 138 | memset(gcr_data, 0x55, GCR_DISK_SIZE); 139 | 140 | // Try opening the file for reading/writing first, then for reading only 141 | write_protected = false; 142 | the_file = fopen(filepath, "rb+"); 143 | if (the_file == NULL) { 144 | write_protected = true; 145 | the_file = fopen(filepath, "rb"); 146 | } 147 | if (the_file != NULL) { 148 | 149 | // Check length 150 | fseek(the_file, 0, SEEK_END); 151 | if ((size = ftell(the_file)) < NUM_SECTORS * 256) { 152 | fclose(the_file); 153 | the_file = NULL; 154 | return; 155 | } 156 | 157 | // x64 image? 158 | fseek(the_file, 0, SEEK_SET); 159 | fread(&magic, 4, 1, the_file); 160 | if (magic[0] == 0x43 && magic[1] == 0x15 && magic[2] == 0x41 && magic[3] == 0x64) 161 | image_header = 64; 162 | else 163 | image_header = 0; 164 | 165 | // Preset error info (all sectors no error) 166 | memset(error_info, 1, NUM_SECTORS); 167 | 168 | // Load sector error info from .d64 file, if present 169 | if (!image_header && size == NUM_SECTORS * 257) { 170 | fseek(the_file, NUM_SECTORS * 256, SEEK_SET); 171 | fread(&error_info, NUM_SECTORS, 1, the_file); 172 | }; 173 | 174 | // Read BAM and get ID 175 | read_sector(18, 0, bam); 176 | id1 = bam[162]; 177 | id2 = bam[163]; 178 | 179 | // Create GCR encoded disk data from image 180 | disk2gcr(); 181 | } 182 | } 183 | 184 | void Job1541::open_d64_file(char *filepath) 185 | { 186 | // Wait for LCD completion 187 | odroid_display_lock(); 188 | odroid_display_unlock(); 189 | 190 | open_d64_file_internal(filepath); 191 | } 192 | 193 | /* 194 | * Close .d64 file 195 | */ 196 | 197 | void Job1541::close_d64_file(void) 198 | { 199 | odroid_display_lock(); 200 | 201 | if (the_file != NULL) { 202 | fclose(the_file); 203 | the_file = NULL; 204 | } 205 | 206 | odroid_display_unlock(); 207 | } 208 | 209 | 210 | /* 211 | * Write sector to disk (1541 ROM patch) 212 | */ 213 | 214 | void Job1541::WriteSector(void) 215 | { 216 | int track = ram[0x18]; 217 | int sector = ram[0x19]; 218 | uint16 buf = ram[0x30] | (ram[0x31] << 8); 219 | 220 | if (buf <= 0x0700) 221 | if (write_sector(track, sector, ram + buf)) 222 | sector2gcr(track, sector); 223 | } 224 | 225 | 226 | /* 227 | * Format one track (1541 ROM patch) 228 | */ 229 | 230 | void Job1541::FormatTrack(void) 231 | { 232 | int track = ram[0x51]; 233 | 234 | // Get new ID 235 | uint8 bufnum = ram[0x3d]; 236 | id1 = ram[0x12 + bufnum]; 237 | id2 = ram[0x13 + bufnum]; 238 | 239 | // Create empty block 240 | uint8 buf[256]; 241 | memset(buf, 1, 256); 242 | buf[0] = 0x4b; 243 | 244 | // Write block to all sectors on track 245 | for(int sector=0; sector GCR 288 | * true: success, false: error 289 | */ 290 | 291 | bool Job1541::write_sector(int track, int sector, uint8 *buffer) 292 | { 293 | int offset; 294 | 295 | // Convert track/sector to byte offset in file 296 | if ((offset = offset_from_ts(track, sector)) < 0) 297 | return false; 298 | 299 | odroid_display_lock(); 300 | 301 | #ifdef AMIGA 302 | if (offset != ftell(the_file)) 303 | fseek(the_file, offset + image_header, SEEK_SET); 304 | #else 305 | fseek(the_file, offset + image_header, SEEK_SET); 306 | #endif 307 | fwrite(buffer, 256, 1, the_file); 308 | 309 | odroid_display_unlock(); 310 | 311 | return true; 312 | } 313 | 314 | 315 | /* 316 | * Convert track/sector to offset 317 | */ 318 | 319 | int Job1541::secnum_from_ts(int track, int sector) 320 | { 321 | return sector_offset[track] + sector; 322 | } 323 | 324 | int Job1541::offset_from_ts(int track, int sector) 325 | { 326 | if ((track < 1) || (track > NUM_TRACKS) || 327 | (sector < 0) || (sector >= num_sectors[track])) 328 | return -1; 329 | 330 | return (sector_offset[track] + sector) << 8; 331 | } 332 | 333 | 334 | /* 335 | * Convert 4 bytes to 5 GCR encoded bytes 336 | */ 337 | 338 | const uint16 gcr_table[16] = { 339 | 0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17, 340 | 0x09, 0x19, 0x1a, 0x1b, 0x0d, 0x1d, 0x1e, 0x15 341 | }; 342 | 343 | void Job1541::gcr_conv4(uint8 *from, uint8 *to) 344 | { 345 | uint16 g; 346 | 347 | g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15]; 348 | *to++ = g >> 2; 349 | *to = (g << 6) & 0xc0; 350 | from++; 351 | 352 | g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15]; 353 | *to++ |= (g >> 4) & 0x3f; 354 | *to = (g << 4) & 0xf0; 355 | from++; 356 | 357 | g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15]; 358 | *to++ |= (g >> 6) & 0x0f; 359 | *to = (g << 2) & 0xfc; 360 | from++; 361 | 362 | g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15]; 363 | *to++ |= (g >> 8) & 0x03; 364 | *to = g; 365 | } 366 | 367 | 368 | /* 369 | * Create GCR encoded disk data from image 370 | */ 371 | 372 | void Job1541::sector2gcr(int track, int sector) 373 | { 374 | uint8 block[256]; 375 | uint8 buf[4]; 376 | uint8 *p = gcr_data + (track-1) * GCR_TRACK_SIZE + sector * GCR_SECTOR_SIZE; 377 | 378 | read_sector(track, sector, block); 379 | 380 | // Create GCR header 381 | *p++ = 0xff; // SYNC 382 | buf[0] = 0x08; // Header mark 383 | buf[1] = sector ^ track ^ id2 ^ id1; // Checksum 384 | buf[2] = sector; 385 | buf[3] = track; 386 | gcr_conv4(buf, p); 387 | buf[0] = id2; 388 | buf[1] = id1; 389 | buf[2] = 0x0f; 390 | buf[3] = 0x0f; 391 | gcr_conv4(buf, p+5); 392 | p += 10; 393 | memset(p, 0x55, 9); // Gap 394 | p += 9; 395 | 396 | // Create GCR data 397 | uint8 sum; 398 | *p++ = 0xff; // SYNC 399 | buf[0] = 0x07; // Data mark 400 | sum = buf[1] = block[0]; 401 | sum ^= buf[2] = block[1]; 402 | sum ^= buf[3] = block[2]; 403 | gcr_conv4(buf, p); 404 | p += 5; 405 | for (int i=3; i<255; i+=4) { 406 | sum ^= buf[0] = block[i]; 407 | sum ^= buf[1] = block[i+1]; 408 | sum ^= buf[2] = block[i+2]; 409 | sum ^= buf[3] = block[i+3]; 410 | gcr_conv4(buf, p); 411 | p += 5; 412 | } 413 | sum ^= buf[0] = block[255]; 414 | buf[1] = sum; // Checksum 415 | buf[2] = 0; 416 | buf[3] = 0; 417 | gcr_conv4(buf, p); 418 | p += 5; 419 | memset(p, 0x55, 8); // Gap 420 | } 421 | 422 | void Job1541::disk2gcr(void) 423 | { 424 | // Convert all tracks and sectors 425 | for (int track=1; track<=NUM_TRACKS; track++) 426 | for(int sector=0; sector> 1) - 1) * GCR_TRACK_SIZE; 444 | gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE; 445 | } 446 | 447 | 448 | /* 449 | * Move R/W head in (higher track numbers) 450 | */ 451 | 452 | void Job1541::MoveHeadIn(void) 453 | { 454 | if (current_halftrack == NUM_TRACKS*2) 455 | return; 456 | current_halftrack++; 457 | #ifndef __riscos__ 458 | printf("Head move %d\n", current_halftrack); 459 | #endif 460 | gcr_ptr = gcr_track_start = gcr_data + ((current_halftrack >> 1) - 1) * GCR_TRACK_SIZE; 461 | gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE; 462 | } 463 | 464 | 465 | /* 466 | * Get state 467 | */ 468 | 469 | void Job1541::GetState(Job1541State *state) 470 | { 471 | state->current_halftrack = current_halftrack; 472 | state->gcr_ptr = gcr_ptr - gcr_data; 473 | state->write_protected = write_protected; 474 | state->disk_changed = disk_changed; 475 | } 476 | 477 | 478 | /* 479 | * Set state 480 | */ 481 | 482 | void Job1541::SetState(Job1541State *state) 483 | { 484 | current_halftrack = state->current_halftrack; 485 | gcr_ptr = gcr_data + state->gcr_ptr; 486 | gcr_track_start = gcr_data + ((current_halftrack >> 1) - 1) * GCR_TRACK_SIZE; 487 | gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE; 488 | write_protected = state->write_protected; 489 | disk_changed = state->disk_changed; 490 | } 491 | -------------------------------------------------------------------------------- /components/frodo/FixPoint.i: -------------------------------------------------------------------------------- 1 | /* 2 | * FixPoint.i 3 | * 4 | * Provides fixpoint arithmetic (for use in SID.cpp) 5 | * You need to define FIXPOINT_PREC (number of fractional bits) and 6 | * ldSINTAB (ld of the size of the sinus table) as well M_PI 7 | * _before_ including this file. 8 | * Requires at least 32bit ints! 9 | * (C) 1997 Andreas Dehmel 10 | */ 11 | 12 | 13 | #define FIXPOINT_BITS 32 14 | // Sign-bit 15 | #define FIXPOINT_SIGN (1<<(FIXPOINT_BITS-1)) 16 | 17 | 18 | /* 19 | * Elementary functions for the FixPoint class 20 | */ 21 | 22 | // Multiplies two fixpoint numbers, result is a fixpoint number. 23 | static inline int fixmult(int x, int y) 24 | { 25 | register unsigned int a,b; 26 | register bool sign; 27 | 28 | sign = (x ^ y) < 0; 29 | if (x < 0) {x = -x;} 30 | if (y < 0) {y = -y;} 31 | // a, b : integer part; x, y : fractional part. All unsigned now (for shift right)!!! 32 | a = (((unsigned int)x) >> FIXPOINT_PREC); x &= ~(a << FIXPOINT_PREC); 33 | b = (((unsigned int)y) >> FIXPOINT_PREC); y &= ~(b << FIXPOINT_PREC); 34 | x = ((a*b) << FIXPOINT_PREC) + (a*y + b*x) + 35 | ((unsigned int)((x*y) + (1 << (FIXPOINT_PREC-1))) >> FIXPOINT_PREC); 36 | #ifdef FIXPOINT_SIGN 37 | if (x < 0) {x ^= FIXPOINT_SIGN;} 38 | #endif 39 | if (sign) {x = -x;} 40 | return(x); 41 | } 42 | 43 | 44 | // Multiplies a fixpoint number with an integer, result is a 32 bit (!) integer in 45 | // contrast to using the standard member-functions which can provide only (32-FIXPOINT_PREC) 46 | // valid bits. 47 | static inline int intmult(int x, int y) // x is fixpoint, y integer 48 | { 49 | register unsigned int i,j; 50 | register bool sign; 51 | 52 | sign = (x ^ y) < 0; 53 | if (x < 0) {x = -x;} 54 | if (y < 0) {y = -y;} 55 | i = (((unsigned int)x) >> 16); x &= ~(i << 16); // split both into 16.16 parts 56 | j = (((unsigned int)y) >> 16); y &= ~(j << 16); 57 | #if FIXPOINT_PREC <= 16 58 | // This '32' is independent of the number of bits used, it's due to the 16 bit shift 59 | i = ((i*j) << (32 - FIXPOINT_PREC)) + ((i*y + j*x) << (16 - FIXPOINT_PREC)) + 60 | ((unsigned int)(x*y + (1 << (FIXPOINT_PREC - 1))) >> FIXPOINT_PREC); 61 | #else 62 | { 63 | register unsigned int h; 64 | 65 | h = (i*y + j*x); 66 | i = ((i*j) << (32 - FIXPOINT_PREC)) + (h >> (FIXPOINT_PREC - 16)); 67 | h &= ((1 << (FIXPOINT_PREC - 16)) - 1); x *= y; 68 | i += (x >> FIXPOINT_PREC); x &= ((1 << FIXPOINT_PREC) - 1); 69 | i += (((h + (x >> 16)) + (1 << (FIXPOINT_PREC - 17))) >> (FIXPOINT_PREC - 16)); 70 | } 71 | #endif 72 | #ifdef FIXPOINT_SIGN 73 | if (i < 0) {i ^= FIXPOINT_SIGN;} 74 | #endif 75 | if (sign) {i = -i;} 76 | return(i); 77 | } 78 | 79 | 80 | // Computes the product of a fixpoint number with itself. 81 | static inline int fixsquare(int x) 82 | { 83 | register unsigned int a; 84 | 85 | if (x < 0) {x = -x;} 86 | a = (((unsigned int)x) >> FIXPOINT_PREC); x &= ~(a << FIXPOINT_PREC); 87 | x = ((a*a) << FIXPOINT_PREC) + ((a*x) << 1) + 88 | ((unsigned int)((x*x) + (1 << (FIXPOINT_PREC-1))) >> FIXPOINT_PREC); 89 | #ifdef FIXPOINT_SIGN 90 | if (x < 0) {x ^= FIXPOINT_SIGN;} 91 | #endif 92 | return(x); 93 | } 94 | 95 | 96 | // Computes the square root of a fixpoint number. 97 | static inline int fixsqrt(int x) 98 | { 99 | register int test, step; 100 | 101 | if (x < 0) return(-1); if (x == 0) return(0); 102 | step = (x <= (1<>1)); 103 | test = 0; 104 | while (step != 0) 105 | { 106 | register int h; 107 | 108 | h = fixsquare(test + step); 109 | if (h <= x) {test += step;} 110 | if (h == x) break; 111 | step >>= 1; 112 | } 113 | return(test); 114 | } 115 | 116 | 117 | // Divides a fixpoint number by another fixpoint number, yielding a fixpoint result. 118 | static inline int fixdiv(int x, int y) 119 | { 120 | register int res, mask; 121 | register bool sign; 122 | 123 | sign = (x ^ y) < 0; 124 | if (x < 0) {x = -x;} 125 | if (y < 0) {y = -y;} 126 | mask = (1< y) {y <<= 1; mask <<= 1;} 128 | while (mask != 0) 129 | { 130 | if (x >= y) {res |= mask; x -= y;} 131 | mask >>= 1; y >>= 1; 132 | } 133 | #ifdef FIXPOINT_SIGN 134 | if (res < 0) {res ^= FIXPOINT_SIGN;} 135 | #endif 136 | if (sign) {res = -res;} 137 | return(res); 138 | } 139 | 140 | 141 | 142 | 143 | 144 | /* 145 | * The C++ Fixpoint class. By no means exhaustive... 146 | * Since it contains only one int data, variables of type FixPoint can be 147 | * passed directly rather than as a reference. 148 | */ 149 | 150 | class FixPoint 151 | { 152 | private: 153 | int x; 154 | 155 | public: 156 | FixPoint(void); 157 | FixPoint(int y); 158 | ~FixPoint(void); 159 | 160 | // conversions 161 | int Value(void); 162 | int round(void); 163 | operator int(void); 164 | 165 | // unary operators 166 | FixPoint sqrt(void); 167 | FixPoint sqr(void); 168 | FixPoint abs(void); 169 | FixPoint operator+(void); 170 | FixPoint operator-(void); 171 | FixPoint operator++(void); 172 | FixPoint operator--(void); 173 | 174 | // binary operators 175 | int imul(int y); 176 | FixPoint operator=(FixPoint y); 177 | FixPoint operator=(int y); 178 | FixPoint operator+(FixPoint y); 179 | FixPoint operator+(int y); 180 | FixPoint operator-(FixPoint y); 181 | FixPoint operator-(int y); 182 | FixPoint operator/(FixPoint y); 183 | FixPoint operator/(int y); 184 | FixPoint operator*(FixPoint y); 185 | FixPoint operator*(int y); 186 | FixPoint operator+=(FixPoint y); 187 | FixPoint operator+=(int y); 188 | FixPoint operator-=(FixPoint y); 189 | FixPoint operator-=(int y); 190 | FixPoint operator*=(FixPoint y); 191 | FixPoint operator*=(int y); 192 | FixPoint operator/=(FixPoint y); 193 | FixPoint operator/=(int y); 194 | FixPoint operator<<(int y); 195 | FixPoint operator>>(int y); 196 | FixPoint operator<<=(int y); 197 | FixPoint operator>>=(int y); 198 | 199 | // conditional operators 200 | bool operator<(FixPoint y); 201 | bool operator<(int y); 202 | bool operator<=(FixPoint y); 203 | bool operator<=(int y); 204 | bool operator>(FixPoint y); 205 | bool operator>(int y); 206 | bool operator>=(FixPoint y); 207 | bool operator>=(int y); 208 | bool operator==(FixPoint y); 209 | bool operator==(int y); 210 | bool operator!=(FixPoint y); 211 | bool operator!=(int y); 212 | }; 213 | 214 | 215 | /* 216 | * int gets treated differently according to the case: 217 | * 218 | * a) Equations (=) or condition checks (==, <, <= ...): raw int (i.e. no conversion) 219 | * b) As an argument for an arithmetic operation: conversion to fixpoint by shifting 220 | * 221 | * Otherwise loading meaningful values into FixPoint variables would be very awkward. 222 | */ 223 | 224 | FixPoint::FixPoint(void) {x = 0;} 225 | 226 | FixPoint::FixPoint(int y) {x = y;} 227 | 228 | FixPoint::~FixPoint(void) {;} 229 | 230 | inline int FixPoint::Value(void) {return(x);} 231 | 232 | inline int FixPoint::round(void) {return((x + (1 << (FIXPOINT_PREC-1))) >> FIXPOINT_PREC);} 233 | 234 | inline FixPoint::operator int(void) {return(x);} 235 | 236 | 237 | // unary operators 238 | inline FixPoint FixPoint::sqrt(void) {return(fixsqrt(x));} 239 | 240 | inline FixPoint FixPoint::sqr(void) {return(fixsquare(x));} 241 | 242 | inline FixPoint FixPoint::abs(void) {return((x < 0) ? -x : x);} 243 | 244 | inline FixPoint FixPoint::operator+(void) {return(x);} 245 | 246 | inline FixPoint FixPoint::operator-(void) {return(-x);} 247 | 248 | inline FixPoint FixPoint::operator++(void) {x += (1 << FIXPOINT_PREC); return x;} 249 | 250 | inline FixPoint FixPoint::operator--(void) {x -= (1 << FIXPOINT_PREC); return x;} 251 | 252 | 253 | // binary operators 254 | inline int FixPoint::imul(int y) {return(intmult(x,y));} 255 | 256 | inline FixPoint FixPoint::operator=(FixPoint y) {x = y.Value(); return x;} 257 | 258 | inline FixPoint FixPoint::operator=(int y) {x = y; return x;} 259 | 260 | inline FixPoint FixPoint::operator+(FixPoint y) {return(x + y.Value());} 261 | 262 | inline FixPoint FixPoint::operator+(int y) {return(x + (y << FIXPOINT_PREC));} 263 | 264 | inline FixPoint FixPoint::operator-(FixPoint y) {return(x - y.Value());} 265 | 266 | inline FixPoint FixPoint::operator-(int y) {return(x - (y << FIXPOINT_PREC));} 267 | 268 | inline FixPoint FixPoint::operator/(FixPoint y) {return(fixdiv(x,y.Value()));} 269 | 270 | inline FixPoint FixPoint::operator/(int y) {return(x/y);} 271 | 272 | inline FixPoint FixPoint::operator*(FixPoint y) {return(fixmult(x,y.Value()));} 273 | 274 | inline FixPoint FixPoint::operator*(int y) {return(x*y);} 275 | 276 | inline FixPoint FixPoint::operator+=(FixPoint y) {x += y.Value(); return x;} 277 | 278 | inline FixPoint FixPoint::operator+=(int y) {x += (y << FIXPOINT_PREC); return x;} 279 | 280 | inline FixPoint FixPoint::operator-=(FixPoint y) {x -= y.Value(); return x;} 281 | 282 | inline FixPoint FixPoint::operator-=(int y) {x -= (y << FIXPOINT_PREC); return x;} 283 | 284 | inline FixPoint FixPoint::operator*=(FixPoint y) {x = fixmult(x,y.Value()); return x;} 285 | 286 | inline FixPoint FixPoint::operator*=(int y) {x *= y; return x;} 287 | 288 | inline FixPoint FixPoint::operator/=(FixPoint y) {x = fixdiv(x,y.Value()); return x;} 289 | 290 | inline FixPoint FixPoint::operator/=(int y) {x /= y; return x;} 291 | 292 | inline FixPoint FixPoint::operator<<(int y) {return(x << y);} 293 | 294 | inline FixPoint FixPoint::operator>>(int y) {return(x >> y);} 295 | 296 | inline FixPoint FixPoint::operator<<=(int y) {x <<= y; return x;} 297 | 298 | inline FixPoint FixPoint::operator>>=(int y) {x >>= y; return x;} 299 | 300 | 301 | // conditional operators 302 | inline bool FixPoint::operator<(FixPoint y) {return(x < y.Value());} 303 | 304 | inline bool FixPoint::operator<(int y) {return(x < y);} 305 | 306 | inline bool FixPoint::operator<=(FixPoint y) {return(x <= y.Value());} 307 | 308 | inline bool FixPoint::operator<=(int y) {return(x <= y);} 309 | 310 | inline bool FixPoint::operator>(FixPoint y) {return(x > y.Value());} 311 | 312 | inline bool FixPoint::operator>(int y) {return(x > y);} 313 | 314 | inline bool FixPoint::operator>=(FixPoint y) {return(x >= y.Value());} 315 | 316 | inline bool FixPoint::operator>=(int y) {return(x >= y);} 317 | 318 | inline bool FixPoint::operator==(FixPoint y) {return(x == y.Value());} 319 | 320 | inline bool FixPoint::operator==(int y) {return(x == y);} 321 | 322 | inline bool FixPoint::operator!=(FixPoint y) {return(x != y.Value());} 323 | 324 | inline bool FixPoint::operator!=(int y) {return(x != y);} 325 | 326 | 327 | 328 | /* 329 | * In case the first argument is an int (i.e. member-operators not applicable): 330 | * Not supported: things like int/FixPoint. The same difference in conversions 331 | * applies as mentioned above. 332 | */ 333 | 334 | 335 | // binary operators 336 | inline FixPoint operator+(int x, FixPoint y) {return((x << FIXPOINT_PREC) + y.Value());} 337 | 338 | inline FixPoint operator-(int x, FixPoint y) {return((x << FIXPOINT_PREC) - y.Value());} 339 | 340 | inline FixPoint operator*(int x, FixPoint y) {return(x*y.Value());} 341 | 342 | 343 | // conditional operators 344 | inline bool operator==(int x, FixPoint y) {return(x == y.Value());} 345 | 346 | inline bool operator!=(int x, FixPoint y) {return(x != y.Value());} 347 | 348 | inline bool operator<(int x, FixPoint y) {return(x < y.Value());} 349 | 350 | inline bool operator<=(int x, FixPoint y) {return(x <= y.Value());} 351 | 352 | inline bool operator>(int x, FixPoint y) {return(x > y.Value());} 353 | 354 | inline bool operator>=(int x, FixPoint y) {return(x >= y.Value());} 355 | 356 | 357 | 358 | /* 359 | * For more convenient creation of constant fixpoint numbers from constant floats. 360 | */ 361 | 362 | #define FixNo(n) (FixPoint)((int)(n*(1<= 3*(1<= 2*(1<= (1<> (FIXPOINT_PREC - ldSINTAB - 1)) & ((1<<(ldSINTAB+2))-1); 391 | FIXPOINT_SIN_COS_GENERIC 392 | } 393 | 394 | 395 | static inline FixPoint fixcos(FixPoint x) 396 | { 397 | int angle = x; 398 | 399 | // cos(x) = sin(x+PI/2) 400 | angle = (angle + (1<<(FIXPOINT_PREC-1)) >> (FIXPOINT_PREC - ldSINTAB - 1)) & ((1<<(ldSINTAB+2))-1); 401 | FIXPOINT_SIN_COS_GENERIC 402 | } 403 | 404 | 405 | 406 | static inline void InitFixSinTab(void) 407 | { 408 | int i; 409 | float step; 410 | 411 | for (i=0, step=0; i<(1<PRB), 19 | * RevMatrix for reversed polling (PRB->PRA). 20 | * 21 | * Incompatibilities: 22 | * ------------------ 23 | * 24 | * - The TOD clock should not be stopped on a read access, but 25 | * latched 26 | * - The SDR interrupt is faked 27 | */ 28 | 29 | #include "sysdeps.h" 30 | 31 | #include "CIA.h" 32 | #include "CPUC64.h" 33 | #include "CPU1541.h" 34 | #include "VIC.h" 35 | #include "Prefs.h" 36 | 37 | 38 | /* 39 | * Constructors 40 | */ 41 | 42 | MOS6526::MOS6526(MOS6510 *CPU) : the_cpu(CPU) {} 43 | MOS6526_1::MOS6526_1(MOS6510 *CPU, MOS6569 *VIC) : MOS6526(CPU), the_vic(VIC) {} 44 | MOS6526_2::MOS6526_2(MOS6510 *CPU, MOS6569 *VIC, MOS6502_1541 *CPU1541) : MOS6526(CPU), the_vic(VIC), the_cpu_1541(CPU1541) {} 45 | 46 | 47 | /* 48 | * Reset the CIA 49 | */ 50 | 51 | void MOS6526::Reset(void) 52 | { 53 | pra = prb = ddra = ddrb = 0; 54 | 55 | ta = tb = 0xffff; 56 | latcha = latchb = 1; 57 | 58 | tod_10ths = tod_sec = tod_min = tod_hr = 0; 59 | alm_10ths = alm_sec = alm_min = alm_hr = 0; 60 | 61 | sdr = icr = cra = crb = int_mask = 0; 62 | 63 | tod_halt = ta_cnt_phi2 = tb_cnt_phi2 = tb_cnt_ta = false; 64 | tod_divider = 0; 65 | } 66 | 67 | void MOS6526_1::Reset(void) 68 | { 69 | MOS6526::Reset(); 70 | 71 | // Clear keyboard matrix and joystick states 72 | for (int i=0; i<8; i++) 73 | KeyMatrix[i] = RevMatrix[i] = 0xff; 74 | 75 | Joystick1 = Joystick2 = 0xff; 76 | prev_lp = 0x10; 77 | } 78 | 79 | void MOS6526_2::Reset(void) 80 | { 81 | MOS6526::Reset(); 82 | 83 | // VA14/15 = 0 84 | the_vic->ChangedVA(0); 85 | 86 | // IEC 87 | IECLines = 0xd0; 88 | } 89 | 90 | 91 | /* 92 | * Get CIA state 93 | */ 94 | 95 | void MOS6526::GetState(MOS6526State *cs) 96 | { 97 | cs->pra = pra; 98 | cs->prb = prb; 99 | cs->ddra = ddra; 100 | cs->ddrb = ddrb; 101 | 102 | cs->ta_lo = ta & 0xff; 103 | cs->ta_hi = ta >> 8; 104 | cs->tb_lo = tb & 0xff; 105 | cs->tb_hi = tb >> 8; 106 | cs->latcha = latcha; 107 | cs->latchb = latchb; 108 | cs->cra = cra; 109 | cs->crb = crb; 110 | 111 | cs->tod_10ths = tod_10ths; 112 | cs->tod_sec = tod_sec; 113 | cs->tod_min = tod_min; 114 | cs->tod_hr = tod_hr; 115 | cs->alm_10ths = alm_10ths; 116 | cs->alm_sec = alm_sec; 117 | cs->alm_min = alm_min; 118 | cs->alm_hr = alm_hr; 119 | 120 | cs->sdr = sdr; 121 | 122 | cs->int_data = icr; 123 | cs->int_mask = int_mask; 124 | } 125 | 126 | 127 | /* 128 | * Restore CIA state 129 | */ 130 | 131 | void MOS6526::SetState(MOS6526State *cs) 132 | { 133 | pra = cs->pra; 134 | prb = cs->prb; 135 | ddra = cs->ddra; 136 | ddrb = cs->ddrb; 137 | 138 | ta = (cs->ta_hi << 8) | cs->ta_lo; 139 | tb = (cs->tb_hi << 8) | cs->tb_lo; 140 | latcha = cs->latcha; 141 | latchb = cs->latchb; 142 | cra = cs->cra; 143 | crb = cs->crb; 144 | 145 | tod_10ths = cs->tod_10ths; 146 | tod_sec = cs->tod_sec; 147 | tod_min = cs->tod_min; 148 | tod_hr = cs->tod_hr; 149 | alm_10ths = cs->alm_10ths; 150 | alm_sec = cs->alm_sec; 151 | alm_min = cs->alm_min; 152 | alm_hr = cs->alm_hr; 153 | 154 | sdr = cs->sdr; 155 | 156 | icr = cs->int_data; 157 | int_mask = cs->int_mask; 158 | 159 | tod_halt = false; 160 | ta_cnt_phi2 = ((cra & 0x21) == 0x01); 161 | tb_cnt_phi2 = ((crb & 0x61) == 0x01); 162 | tb_cnt_ta = ((crb & 0x61) == 0x41); 163 | } 164 | 165 | 166 | /* 167 | * Read from register (CIA 1) 168 | */ 169 | 170 | uint8 MOS6526_1::ReadRegister(uint16 adr) 171 | { 172 | switch (adr) { 173 | case 0x00: { 174 | uint8 ret = pra | ~ddra, tst = (prb | ~ddrb) & Joystick1; 175 | if (!(tst & 0x01)) ret &= RevMatrix[0]; // AND all active columns 176 | if (!(tst & 0x02)) ret &= RevMatrix[1]; 177 | if (!(tst & 0x04)) ret &= RevMatrix[2]; 178 | if (!(tst & 0x08)) ret &= RevMatrix[3]; 179 | if (!(tst & 0x10)) ret &= RevMatrix[4]; 180 | if (!(tst & 0x20)) ret &= RevMatrix[5]; 181 | if (!(tst & 0x40)) ret &= RevMatrix[6]; 182 | if (!(tst & 0x80)) ret &= RevMatrix[7]; 183 | return ret & Joystick2; 184 | } 185 | case 0x01: { 186 | uint8 ret = ~ddrb, tst = (pra | ~ddra) & Joystick2; 187 | if (!(tst & 0x01)) ret &= KeyMatrix[0]; // AND all active rows 188 | if (!(tst & 0x02)) ret &= KeyMatrix[1]; 189 | if (!(tst & 0x04)) ret &= KeyMatrix[2]; 190 | if (!(tst & 0x08)) ret &= KeyMatrix[3]; 191 | if (!(tst & 0x10)) ret &= KeyMatrix[4]; 192 | if (!(tst & 0x20)) ret &= KeyMatrix[5]; 193 | if (!(tst & 0x40)) ret &= KeyMatrix[6]; 194 | if (!(tst & 0x80)) ret &= KeyMatrix[7]; 195 | return (ret | (prb & ddrb)) & Joystick1; 196 | } 197 | case 0x02: return ddra; 198 | case 0x03: return ddrb; 199 | case 0x04: return ta; 200 | case 0x05: return ta >> 8; 201 | case 0x06: return tb; 202 | case 0x07: return tb >> 8; 203 | case 0x08: tod_halt = false; return tod_10ths; 204 | case 0x09: return tod_sec; 205 | case 0x0a: return tod_min; 206 | case 0x0b: tod_halt = true; return tod_hr; 207 | case 0x0c: return sdr; 208 | case 0x0d: { 209 | uint8 ret = icr; // Read and clear ICR 210 | icr = 0; 211 | the_cpu->ClearCIAIRQ(); // Clear IRQ 212 | return ret; 213 | } 214 | case 0x0e: return cra; 215 | case 0x0f: return crb; 216 | } 217 | return 0; // Can't happen 218 | } 219 | 220 | 221 | /* 222 | * Read from register (CIA 2) 223 | */ 224 | 225 | uint8 MOS6526_2::ReadRegister(uint16 adr) 226 | { 227 | switch (adr) { 228 | case 0x00: 229 | return (pra | ~ddra) & 0x3f 230 | | IECLines & the_cpu_1541->IECLines; 231 | case 0x01: return prb | ~ddrb; 232 | case 0x02: return ddra; 233 | case 0x03: return ddrb; 234 | case 0x04: return ta; 235 | case 0x05: return ta >> 8; 236 | case 0x06: return tb; 237 | case 0x07: return tb >> 8; 238 | case 0x08: tod_halt = false; return tod_10ths; 239 | case 0x09: return tod_sec; 240 | case 0x0a: return tod_min; 241 | case 0x0b: tod_halt = true; return tod_hr; 242 | case 0x0c: return sdr; 243 | case 0x0d: { 244 | uint8 ret = icr; // Read and clear ICR 245 | icr = 0; 246 | the_cpu->ClearNMI(); // Clear NMI 247 | return ret; 248 | } 249 | case 0x0e: return cra; 250 | case 0x0f: return crb; 251 | } 252 | return 0; // Can't happen 253 | } 254 | 255 | 256 | /* 257 | * Write to register (CIA 1) 258 | */ 259 | 260 | // Write to port B, check for lightpen interrupt 261 | inline void MOS6526_1::check_lp(void) 262 | { 263 | if ((prb | ~ddrb) & 0x10 != prev_lp) 264 | the_vic->TriggerLightpen(); 265 | prev_lp = (prb | ~ddrb) & 0x10; 266 | } 267 | 268 | void MOS6526_1::WriteRegister(uint16 adr, uint8 byte) 269 | { 270 | switch (adr) { 271 | case 0x0: pra = byte; break; 272 | case 0x1: 273 | prb = byte; 274 | check_lp(); 275 | break; 276 | case 0x2: ddra = byte; break; 277 | case 0x3: 278 | ddrb = byte; 279 | check_lp(); 280 | break; 281 | 282 | case 0x4: latcha = (latcha & 0xff00) | byte; break; 283 | case 0x5: 284 | latcha = (latcha & 0xff) | (byte << 8); 285 | if (!(cra & 1)) // Reload timer if stopped 286 | ta = latcha; 287 | break; 288 | 289 | case 0x6: latchb = (latchb & 0xff00) | byte; break; 290 | case 0x7: 291 | latchb = (latchb & 0xff) | (byte << 8); 292 | if (!(crb & 1)) // Reload timer if stopped 293 | tb = latchb; 294 | break; 295 | 296 | case 0x8: 297 | if (crb & 0x80) 298 | alm_10ths = byte & 0x0f; 299 | else 300 | tod_10ths = byte & 0x0f; 301 | break; 302 | case 0x9: 303 | if (crb & 0x80) 304 | alm_sec = byte & 0x7f; 305 | else 306 | tod_sec = byte & 0x7f; 307 | break; 308 | case 0xa: 309 | if (crb & 0x80) 310 | alm_min = byte & 0x7f; 311 | else 312 | tod_min = byte & 0x7f; 313 | break; 314 | case 0xb: 315 | if (crb & 0x80) 316 | alm_hr = byte & 0x9f; 317 | else 318 | tod_hr = byte & 0x9f; 319 | break; 320 | 321 | case 0xc: 322 | sdr = byte; 323 | TriggerInterrupt(8); // Fake SDR interrupt for programs that need it 324 | break; 325 | 326 | case 0xd: 327 | if (ThePrefs.CIAIRQHack) // Hack for addressing modes that read from the address 328 | icr = 0; 329 | if (byte & 0x80) { 330 | int_mask |= byte & 0x7f; 331 | if (icr & int_mask & 0x1f) { // Trigger IRQ if pending 332 | icr |= 0x80; 333 | the_cpu->TriggerCIAIRQ(); 334 | } 335 | } else 336 | int_mask &= ~byte; 337 | break; 338 | 339 | case 0xe: 340 | cra = byte & 0xef; 341 | if (byte & 0x10) // Force load 342 | ta = latcha; 343 | ta_cnt_phi2 = ((byte & 0x21) == 0x01); 344 | break; 345 | 346 | case 0xf: 347 | crb = byte & 0xef; 348 | if (byte & 0x10) // Force load 349 | tb = latchb; 350 | tb_cnt_phi2 = ((byte & 0x61) == 0x01); 351 | tb_cnt_ta = ((byte & 0x61) == 0x41); 352 | break; 353 | } 354 | } 355 | 356 | 357 | /* 358 | * Write to register (CIA 2) 359 | */ 360 | 361 | void MOS6526_2::WriteRegister(uint16 adr, uint8 byte) 362 | { 363 | switch (adr) { 364 | case 0x0:{ 365 | pra = byte; 366 | byte = ~pra & ddra; 367 | the_vic->ChangedVA(byte & 3); 368 | uint8 old_lines = IECLines; 369 | IECLines = (byte << 2) & 0x80 // DATA 370 | | (byte << 2) & 0x40 // CLK 371 | | (byte << 1) & 0x10; // ATN 372 | if ((IECLines ^ old_lines) & 0x10) { // ATN changed 373 | the_cpu_1541->NewATNState(); 374 | if (old_lines & 0x10) // ATN 1->0 375 | the_cpu_1541->IECInterrupt(); 376 | } 377 | break; 378 | } 379 | case 0x1: prb = byte; break; 380 | 381 | case 0x2: 382 | ddra = byte; 383 | the_vic->ChangedVA(~(pra | ~ddra) & 3); 384 | break; 385 | case 0x3: ddrb = byte; break; 386 | 387 | case 0x4: latcha = (latcha & 0xff00) | byte; break; 388 | case 0x5: 389 | latcha = (latcha & 0xff) | (byte << 8); 390 | if (!(cra & 1)) // Reload timer if stopped 391 | ta = latcha; 392 | break; 393 | 394 | case 0x6: latchb = (latchb & 0xff00) | byte; break; 395 | case 0x7: 396 | latchb = (latchb & 0xff) | (byte << 8); 397 | if (!(crb & 1)) // Reload timer if stopped 398 | tb = latchb; 399 | break; 400 | 401 | case 0x8: 402 | if (crb & 0x80) 403 | alm_10ths = byte & 0x0f; 404 | else 405 | tod_10ths = byte & 0x0f; 406 | break; 407 | case 0x9: 408 | if (crb & 0x80) 409 | alm_sec = byte & 0x7f; 410 | else 411 | tod_sec = byte & 0x7f; 412 | break; 413 | case 0xa: 414 | if (crb & 0x80) 415 | alm_min = byte & 0x7f; 416 | else 417 | tod_min = byte & 0x7f; 418 | break; 419 | case 0xb: 420 | if (crb & 0x80) 421 | alm_hr = byte & 0x9f; 422 | else 423 | tod_hr = byte & 0x9f; 424 | break; 425 | 426 | case 0xc: 427 | sdr = byte; 428 | TriggerInterrupt(8); // Fake SDR interrupt for programs that need it 429 | break; 430 | 431 | case 0xd: 432 | if (ThePrefs.CIAIRQHack) 433 | icr = 0; 434 | if (byte & 0x80) { 435 | int_mask |= byte & 0x7f; 436 | if (icr & int_mask & 0x1f) { // Trigger NMI if pending 437 | icr |= 0x80; 438 | the_cpu->TriggerNMI(); 439 | } 440 | } else 441 | int_mask &= ~byte; 442 | break; 443 | 444 | case 0xe: 445 | cra = byte & 0xef; 446 | if (byte & 0x10) // Force load 447 | ta = latcha; 448 | ta_cnt_phi2 = ((byte & 0x21) == 0x01); 449 | break; 450 | 451 | case 0xf: 452 | crb = byte & 0xef; 453 | if (byte & 0x10) // Force load 454 | tb = latchb; 455 | tb_cnt_phi2 = ((byte & 0x61) == 0x01); 456 | tb_cnt_ta = ((byte & 0x61) == 0x41); 457 | break; 458 | } 459 | } 460 | 461 | 462 | /* 463 | * Count CIA TOD clock (called during VBlank) 464 | */ 465 | 466 | void MOS6526::CountTOD(void) 467 | { 468 | uint8 lo, hi; 469 | 470 | // Decrement frequency divider 471 | if (tod_divider) 472 | tod_divider--; 473 | else { 474 | 475 | // Reload divider according to 50/60 Hz flag 476 | if (cra & 0x80) 477 | tod_divider = 4; 478 | else 479 | tod_divider = 5; 480 | 481 | // 1/10 seconds 482 | tod_10ths++; 483 | if (tod_10ths > 9) { 484 | tod_10ths = 0; 485 | 486 | // Seconds 487 | lo = (tod_sec & 0x0f) + 1; 488 | hi = tod_sec >> 4; 489 | if (lo > 9) { 490 | lo = 0; 491 | hi++; 492 | } 493 | if (hi > 5) { 494 | tod_sec = 0; 495 | 496 | // Minutes 497 | lo = (tod_min & 0x0f) + 1; 498 | hi = tod_min >> 4; 499 | if (lo > 9) { 500 | lo = 0; 501 | hi++; 502 | } 503 | if (hi > 5) { 504 | tod_min = 0; 505 | 506 | // Hours 507 | lo = (tod_hr & 0x0f) + 1; 508 | hi = (tod_hr >> 4) & 1; 509 | tod_hr &= 0x80; // Keep AM/PM flag 510 | if (lo > 9) { 511 | lo = 0; 512 | hi++; 513 | } 514 | tod_hr |= (hi << 4) | lo; 515 | if ((tod_hr & 0x1f) > 0x11) 516 | tod_hr = tod_hr & 0x80 ^ 0x80; 517 | } else 518 | tod_min = (hi << 4) | lo; 519 | } else 520 | tod_sec = (hi << 4) | lo; 521 | } 522 | 523 | // Alarm time reached? Trigger interrupt if enabled 524 | if (tod_10ths == alm_10ths && tod_sec == alm_sec && 525 | tod_min == alm_min && tod_hr == alm_hr) 526 | TriggerInterrupt(4); 527 | } 528 | } 529 | 530 | 531 | /* 532 | * Trigger IRQ (CIA 1) 533 | */ 534 | 535 | void MOS6526_1::TriggerInterrupt(int bit) 536 | { 537 | icr |= bit; 538 | if (int_mask & bit) { 539 | icr |= 0x80; 540 | the_cpu->TriggerCIAIRQ(); 541 | } 542 | } 543 | 544 | 545 | /* 546 | * Trigger NMI (CIA 2) 547 | */ 548 | 549 | void MOS6526_2::TriggerInterrupt(int bit) 550 | { 551 | icr |= bit; 552 | if (int_mask & bit) { 553 | icr |= 0x80; 554 | the_cpu->TriggerNMI(); 555 | } 556 | } 557 | -------------------------------------------------------------------------------- /components/odroid/odroid_input.c: -------------------------------------------------------------------------------- 1 | #include "odroid_input.h" 2 | #include "odroid_settings.h" 3 | #include "odroid_system.h" 4 | //#include "odroid_display.h" 5 | #include "driver/ledc.h" 6 | 7 | #include "driver/i2c.h" 8 | #include "driver/gpio.h" 9 | #include 10 | #include "esp_adc_cal.h" 11 | #include "freertos/FreeRTOS.h" 12 | 13 | #include 14 | 15 | //extern void backlight_percentage_set(int value); 16 | 17 | static volatile bool input_task_is_running = false; 18 | static volatile odroid_gamepad_state gamepad_state; 19 | static odroid_gamepad_state previous_gamepad_state; 20 | static uint8_t debounce[ODROID_INPUT_MAX]; 21 | static volatile bool input_gamepad_initialized = false; 22 | static SemaphoreHandle_t xSemaphore; 23 | 24 | static esp_adc_cal_characteristics_t characteristics; 25 | static bool input_battery_initialized = false; 26 | static float adc_value = 0.0f; 27 | static float forced_adc_value = 0.0f; 28 | static bool battery_monitor_enabled = true; 29 | 30 | #define BACKLIGHT_LEVEL_COUNT (4) 31 | static int BacklightLevels[BACKLIGHT_LEVEL_COUNT] = {10, 33, 66, 100}; 32 | static int BacklightLevel = BACKLIGHT_LEVEL_COUNT - 1; 33 | 34 | int is_backlight_initialized(); 35 | 36 | odroid_gamepad_state odroid_input_read_raw() 37 | { 38 | odroid_gamepad_state state = {0}; 39 | 40 | int joyX = adc1_get_raw(ODROID_GAMEPAD_IO_X); 41 | int joyY = adc1_get_raw(ODROID_GAMEPAD_IO_Y); 42 | 43 | if (joyX > 2048 + 1024) 44 | { 45 | state.values[ODROID_INPUT_LEFT] = 1; 46 | state.values[ODROID_INPUT_RIGHT] = 0; 47 | } 48 | else if (joyX > 1024) 49 | { 50 | state.values[ODROID_INPUT_LEFT] = 0; 51 | state.values[ODROID_INPUT_RIGHT] = 1; 52 | } 53 | else 54 | { 55 | state.values[ODROID_INPUT_LEFT] = 0; 56 | state.values[ODROID_INPUT_RIGHT] = 0; 57 | } 58 | 59 | if (joyY > 2048 + 1024) 60 | { 61 | state.values[ODROID_INPUT_UP] = 1; 62 | state.values[ODROID_INPUT_DOWN] = 0; 63 | } 64 | else if (joyY > 1024) 65 | { 66 | state.values[ODROID_INPUT_UP] = 0; 67 | state.values[ODROID_INPUT_DOWN] = 1; 68 | } 69 | else 70 | { 71 | state.values[ODROID_INPUT_UP] = 0; 72 | state.values[ODROID_INPUT_DOWN] = 0; 73 | } 74 | 75 | state.values[ODROID_INPUT_SELECT] = !(gpio_get_level(ODROID_GAMEPAD_IO_SELECT)); 76 | state.values[ODROID_INPUT_START] = !(gpio_get_level(ODROID_GAMEPAD_IO_START)); 77 | 78 | state.values[ODROID_INPUT_A] = !(gpio_get_level(ODROID_GAMEPAD_IO_A)); 79 | state.values[ODROID_INPUT_B] = !(gpio_get_level(ODROID_GAMEPAD_IO_B)); 80 | 81 | state.values[ODROID_INPUT_MENU] = !(gpio_get_level(ODROID_GAMEPAD_IO_MENU)); 82 | state.values[ODROID_INPUT_VOLUME] = !(gpio_get_level(ODROID_GAMEPAD_IO_VOLUME)); 83 | 84 | return state; 85 | } 86 | 87 | static void odroid_input_task(void *arg) 88 | { 89 | input_task_is_running = true; 90 | 91 | // Initialize state 92 | for(int i = 0; i < ODROID_INPUT_MAX; ++i) 93 | { 94 | debounce[i] = 0xff; 95 | } 96 | 97 | BacklightLevel = odroid_settings_Backlight_get(); 98 | bool changed = false; 99 | 100 | while(input_task_is_running) 101 | { 102 | // Shift current values 103 | for(int i = 0; i < ODROID_INPUT_MAX; ++i) 104 | { 105 | debounce[i] <<= 1; 106 | } 107 | 108 | 109 | // Read hardware 110 | #if 1 111 | 112 | odroid_gamepad_state state = odroid_input_read_raw(); 113 | 114 | #else 115 | odroid_gamepad_state state = {0}; 116 | 117 | int joyX = adc1_get_raw(ODROID_GAMEPAD_IO_X); 118 | int joyY = adc1_get_raw(ODROID_GAMEPAD_IO_Y); 119 | 120 | if (joyX > 2048 + 1024) 121 | { 122 | state.values[ODROID_INPUT_LEFT] = 1; 123 | state.values[ODROID_INPUT_RIGHT] = 0; 124 | } 125 | else if (joyX > 1024) 126 | { 127 | state.values[ODROID_INPUT_LEFT] = 0; 128 | state.values[ODROID_INPUT_RIGHT] = 1; 129 | } 130 | else 131 | { 132 | state.values[ODROID_INPUT_LEFT] = 0; 133 | state.values[ODROID_INPUT_RIGHT] = 0; 134 | } 135 | 136 | if (joyY > 2048 + 1024) 137 | { 138 | state.values[ODROID_INPUT_UP] = 1; 139 | state.values[ODROID_INPUT_DOWN] = 0; 140 | } 141 | else if (joyY > 1024) 142 | { 143 | state.values[ODROID_INPUT_UP] = 0; 144 | state.values[ODROID_INPUT_DOWN] = 1; 145 | } 146 | else 147 | { 148 | state.values[ODROID_INPUT_UP] = 0; 149 | state.values[ODROID_INPUT_DOWN] = 0; 150 | } 151 | 152 | state.values[ODROID_INPUT_SELECT] = !(gpio_get_level(ODROID_GAMEPAD_IO_SELECT)); 153 | state.values[ODROID_INPUT_START] = !(gpio_get_level(ODROID_GAMEPAD_IO_START)); 154 | 155 | state.values[ODROID_INPUT_A] = !(gpio_get_level(ODROID_GAMEPAD_IO_A)); 156 | state.values[ODROID_INPUT_B] = !(gpio_get_level(ODROID_GAMEPAD_IO_B)); 157 | 158 | state.values[ODROID_INPUT_MENU] = !(gpio_get_level(ODROID_GAMEPAD_IO_MENU)); 159 | state.values[ODROID_INPUT_VOLUME] = !(gpio_get_level(ODROID_GAMEPAD_IO_VOLUME)); 160 | #endif 161 | 162 | // Debounce 163 | xSemaphoreTake(xSemaphore, portMAX_DELAY); 164 | 165 | for(int i = 0; i < ODROID_INPUT_MAX; ++i) 166 | { 167 | debounce[i] |= state.values[i] ? 1 : 0; 168 | uint8_t val = debounce[i] & 0x03; //0x0f; 169 | switch (val) { 170 | case 0x00: 171 | gamepad_state.values[i] = 0; 172 | break; 173 | 174 | case 0x03: //0x0f: 175 | gamepad_state.values[i] = 1; 176 | break; 177 | 178 | default: 179 | // ignore 180 | break; 181 | } 182 | 183 | //gamepad_state.values[i] = (debounce[i] == 0xff); 184 | //printf("odroid_input_task: %d=%d (raw=%d)\n", i, gamepad_state.values[i], state.values[i]); 185 | } 186 | 187 | if (gamepad_state.values[ODROID_INPUT_START]) 188 | { 189 | 190 | if (gamepad_state.values[ODROID_INPUT_DOWN] && !previous_gamepad_state.values[ODROID_INPUT_DOWN]) 191 | { 192 | --BacklightLevel; 193 | if (BacklightLevel < 0) BacklightLevel = 0; 194 | 195 | changed = true; 196 | odroid_settings_Backlight_set(BacklightLevel); 197 | } 198 | else if (gamepad_state.values[ODROID_INPUT_UP] && !previous_gamepad_state.values[ODROID_INPUT_UP]) 199 | { 200 | ++BacklightLevel; 201 | if (BacklightLevel >= BACKLIGHT_LEVEL_COUNT) BacklightLevel = BACKLIGHT_LEVEL_COUNT - 1; 202 | 203 | changed = true; 204 | odroid_settings_Backlight_set(BacklightLevel); 205 | } 206 | 207 | 208 | } 209 | 210 | if (is_backlight_initialized()) 211 | { 212 | const int DUTY_MAX = 0x1fff; 213 | int duty = DUTY_MAX * (BacklightLevels[BacklightLevel] * 0.01f); 214 | 215 | uint32_t currentDuty = ledc_get_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); 216 | if (currentDuty != duty) 217 | { 218 | changed = true; 219 | } 220 | 221 | if (changed) 222 | { 223 | //backlight_percentage_set(BacklightLevels[BacklightLevel]); 224 | 225 | #if 0 226 | ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty, 1); 227 | ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_WAIT_DONE /*LEDC_FADE_NO_WAIT*/); 228 | #else 229 | esp_err_t err; 230 | 231 | err = ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty); 232 | if (err != ESP_OK) abort(); 233 | 234 | err = ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); 235 | if (err != ESP_OK) abort(); 236 | #endif 237 | //ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty); 238 | 239 | changed = false; 240 | } 241 | } 242 | 243 | previous_gamepad_state = gamepad_state; 244 | 245 | xSemaphoreGive(xSemaphore); 246 | 247 | 248 | // delay 249 | vTaskDelay(10 / portTICK_PERIOD_MS); 250 | } 251 | 252 | input_gamepad_initialized = false; 253 | 254 | vSemaphoreDelete(xSemaphore); 255 | 256 | // Remove the task from scheduler 257 | vTaskDelete(NULL); 258 | 259 | // Never return 260 | while (1) { vTaskDelay(1);} 261 | } 262 | 263 | void odroid_input_gamepad_init() 264 | { 265 | //printf("portTICK_PERIOD_MS = %d\n", portTICK_PERIOD_MS); 266 | 267 | xSemaphore = xSemaphoreCreateMutex(); 268 | 269 | if(xSemaphore == NULL) 270 | { 271 | printf("xSemaphoreCreateMutex failed.\n"); 272 | abort(); 273 | } 274 | 275 | gpio_set_direction(ODROID_GAMEPAD_IO_SELECT, GPIO_MODE_INPUT); 276 | gpio_set_pull_mode(ODROID_GAMEPAD_IO_SELECT, GPIO_PULLUP_ONLY); 277 | 278 | gpio_set_direction(ODROID_GAMEPAD_IO_START, GPIO_MODE_INPUT); 279 | 280 | gpio_set_direction(ODROID_GAMEPAD_IO_A, GPIO_MODE_INPUT); 281 | gpio_set_pull_mode(ODROID_GAMEPAD_IO_A, GPIO_PULLUP_ONLY); 282 | 283 | gpio_set_direction(ODROID_GAMEPAD_IO_B, GPIO_MODE_INPUT); 284 | gpio_set_pull_mode(ODROID_GAMEPAD_IO_B, GPIO_PULLUP_ONLY); 285 | 286 | adc1_config_width(ADC_WIDTH_12Bit); 287 | adc1_config_channel_atten(ODROID_GAMEPAD_IO_X, ADC_ATTEN_11db); 288 | adc1_config_channel_atten(ODROID_GAMEPAD_IO_Y, ADC_ATTEN_11db); 289 | 290 | gpio_set_direction(ODROID_GAMEPAD_IO_MENU, GPIO_MODE_INPUT); 291 | gpio_set_pull_mode(ODROID_GAMEPAD_IO_MENU, GPIO_PULLUP_ONLY); 292 | 293 | gpio_set_direction(ODROID_GAMEPAD_IO_VOLUME, GPIO_MODE_INPUT); 294 | 295 | input_gamepad_initialized = true; 296 | 297 | // Start background polling 298 | xTaskCreatePinnedToCore(&odroid_input_task, "odroid_input_task", 1024 * 2, NULL, 5, NULL, 1); 299 | 300 | printf("odroid_input_gamepad_init done.\n"); 301 | 302 | } 303 | 304 | void odroid_input_gamepad_terminate() 305 | { 306 | if (!input_gamepad_initialized) abort(); 307 | 308 | input_task_is_running = false; 309 | } 310 | 311 | void odroid_input_gamepad_read(odroid_gamepad_state* out_state) 312 | { 313 | if (!input_gamepad_initialized) abort(); 314 | 315 | xSemaphoreTake(xSemaphore, portMAX_DELAY); 316 | 317 | *out_state = gamepad_state; 318 | 319 | xSemaphoreGive(xSemaphore); 320 | } 321 | 322 | 323 | static void odroid_battery_monitor_task() 324 | { 325 | bool led_state = false; 326 | 327 | while(true) 328 | { 329 | if (battery_monitor_enabled) 330 | { 331 | odroid_battery_state battery; 332 | odroid_input_battery_level_read(&battery); 333 | 334 | if (battery.percentage < 2) 335 | { 336 | led_state = !led_state; 337 | odroid_system_led_set(led_state); 338 | } 339 | else if(led_state) 340 | { 341 | led_state = 0; 342 | odroid_system_led_set(led_state); 343 | } 344 | } 345 | 346 | vTaskDelay(500 / portTICK_PERIOD_MS); 347 | } 348 | } 349 | 350 | 351 | static void print_char_val_type(esp_adc_cal_value_t val_type) 352 | { 353 | if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { 354 | printf("ADC: Characterized using Two Point Value\n"); 355 | } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) { 356 | printf("ADC: Characterized using eFuse Vref\n"); 357 | } else { 358 | printf("ADC: Characterized using Default Vref\n"); 359 | } 360 | } 361 | 362 | #define DEFAULT_VREF 1100 363 | void odroid_input_battery_level_init() 364 | { 365 | adc1_config_width(ADC_WIDTH_12Bit); 366 | adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_11db); 367 | 368 | //int vref_value = odroid_settings_VRef_get(); 369 | //esp_adc_cal_get_characteristics(vref_value, ADC_ATTEN_11db, ADC_WIDTH_12Bit, &characteristics); 370 | 371 | //Characterize ADC 372 | //adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); 373 | esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_11db, ADC_WIDTH_BIT_12, DEFAULT_VREF, &characteristics); 374 | print_char_val_type(val_type); 375 | 376 | input_battery_initialized = true; 377 | xTaskCreatePinnedToCore(&odroid_battery_monitor_task, "battery_monitor", 1024, NULL, 5, NULL, 1); 378 | } 379 | 380 | void odroid_input_battery_level_read(odroid_battery_state* out_state) 381 | { 382 | if (!input_battery_initialized) 383 | { 384 | printf("odroid_input_battery_level_read: not initilized.\n"); 385 | abort(); 386 | } 387 | 388 | 389 | const int sampleCount = 4; 390 | 391 | float adcSample = 0.0f; 392 | for (int i = 0; i < sampleCount; ++i) 393 | { 394 | //adcSample += adc1_to_voltage(ADC1_CHANNEL_0, &characteristics) * 0.001f; 395 | adcSample += esp_adc_cal_raw_to_voltage(adc1_get_raw(ADC1_CHANNEL_0), &characteristics) * 0.001f; 396 | } 397 | adcSample /= sampleCount; 398 | 399 | 400 | if (adc_value == 0.0f) 401 | { 402 | adc_value = adcSample; 403 | } 404 | else 405 | { 406 | adc_value += adcSample; 407 | adc_value /= 2.0f; 408 | } 409 | 410 | 411 | // Vo = (Vs * R2) / (R1 + R2) 412 | // Vs = Vo / R2 * (R1 + R2) 413 | const float R1 = 10000; 414 | const float R2 = 10000; 415 | const float Vo = adc_value; 416 | const float Vs = (forced_adc_value > 0.0f) ? (forced_adc_value) : (Vo / R2 * (R1 + R2)); 417 | 418 | const float FullVoltage = 4.2f; 419 | const float EmptyVoltage = 3.5f; 420 | 421 | out_state->millivolts = (int)(Vs * 1000); 422 | out_state->percentage = (int)((Vs - EmptyVoltage) / (FullVoltage - EmptyVoltage) * 100.0f); 423 | } 424 | 425 | void odroid_input_battery_level_force_voltage(float volts) 426 | { 427 | forced_adc_value = volts; 428 | } 429 | 430 | void odroid_input_battery_monitor_enabled_set(int value) 431 | { 432 | battery_monitor_enabled = value; 433 | } 434 | --------------------------------------------------------------------------------