├── include ├── user_config.h ├── pin_mux_register.h └── dmastuff.h ├── .gitignore ├── images ├── espple.jpg ├── espple_screen.jpg └── signal_spectrum.jpg ├── image.elf-0x00000.bin ├── image.elf-0x40000.bin ├── software ├── life-0x2000.bin ├── basic-0xE000.bin └── apple30th-0x0280.bin ├── LICENSE ├── user ├── woz_monitor.h ├── user_main.c ├── slc_register.h ├── generate_video.c ├── signetics_video_rom.h └── fake6502.c ├── Makefile ├── README.md └── eagle.app.v6.ld /include/user_config.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | image.elf 2 | image.lst 3 | image.map 4 | -------------------------------------------------------------------------------- /images/espple.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrvach/espple/HEAD/images/espple.jpg -------------------------------------------------------------------------------- /image.elf-0x00000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrvach/espple/HEAD/image.elf-0x00000.bin -------------------------------------------------------------------------------- /image.elf-0x40000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrvach/espple/HEAD/image.elf-0x40000.bin -------------------------------------------------------------------------------- /images/espple_screen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrvach/espple/HEAD/images/espple_screen.jpg -------------------------------------------------------------------------------- /software/life-0x2000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrvach/espple/HEAD/software/life-0x2000.bin -------------------------------------------------------------------------------- /images/signal_spectrum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrvach/espple/HEAD/images/signal_spectrum.jpg -------------------------------------------------------------------------------- /software/basic-0xE000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrvach/espple/HEAD/software/basic-0xE000.bin -------------------------------------------------------------------------------- /software/apple30th-0x0280.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrvach/espple/HEAD/software/apple30th-0x0280.bin -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 CNLohr 4 | 2017 Hrvoje Cavrak 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /user/woz_monitor.h: -------------------------------------------------------------------------------- 1 | uint8_t woz_monitor[] = { 2 | 0xD8, 0x58, 0xA0, 0x7F, 0x8C, 0x12, 0xD0, 0xA9, 3 | 0xA7, 0x8D, 0x11, 0xD0, 0x8D, 0x13, 0xD0, 0xC9, 4 | 0xDF, 0xF0, 0x13, 0xC9, 0x9B, 0xF0, 0x03, 0xC8, 5 | 0x10, 0x0F, 0xA9, 0xDC, 0x20, 0xEF, 0xFF, 0xA9, 6 | 0x8D, 0x20, 0xEF, 0xFF, 0xA0, 0x01, 0x88, 0x30, 7 | 0xF6, 0xAD, 0x11, 0xD0, 0x10, 0xFB, 0xAD, 0x10, 8 | 0xD0, 0x99, 0x00, 0x02, 0x20, 0xEF, 0xFF, 0xC9, 9 | 0x8D, 0xD0, 0xD4, 0xA0, 0xFF, 0xA9, 0x00, 0xAA, 10 | 0x0A, 0x85, 0x2B, 0xC8, 0xB9, 0x00, 0x02, 0xC9, 11 | 0x8D, 0xF0, 0xD4, 0xC9, 0xAE, 0x90, 0xF4, 0xF0, 12 | 0xF0, 0xC9, 0xBA, 0xF0, 0xEB, 0xC9, 0xD2, 0xF0, 13 | 0x3B, 0x86, 0x28, 0x86, 0x29, 0x84, 0x2A, 0xB9, 14 | 0x00, 0x02, 0x49, 0xB0, 0xC9, 0x0A, 0x90, 0x06, 15 | 0x69, 0x88, 0xC9, 0xFA, 0x90, 0x11, 0x0A, 0x0A, 16 | 0x0A, 0x0A, 0xA2, 0x04, 0x0A, 0x26, 0x28, 0x26, 17 | 0x29, 0xCA, 0xD0, 0xF8, 0xC8, 0xD0, 0xE0, 0xC4, 18 | 0x2A, 0xF0, 0x97, 0x24, 0x2B, 0x50, 0x10, 0xA5, 19 | 0x28, 0x81, 0x26, 0xE6, 0x26, 0xD0, 0xB5, 0xE6, 20 | 0x27, 0x4C, 0x44, 0xFF, 0x6C, 0x24, 0x00, 0x30, 21 | 0x2B, 0xA2, 0x02, 0xB5, 0x27, 0x95, 0x25, 0x95, 22 | 0x23, 0xCA, 0xD0, 0xF7, 0xD0, 0x14, 0xA9, 0x8D, 23 | 0x20, 0xEF, 0xFF, 0xA5, 0x25, 0x20, 0xDC, 0xFF, 24 | 0xA5, 0x24, 0x20, 0xDC, 0xFF, 0xA9, 0xBA, 0x20, 25 | 0xEF, 0xFF, 0xA9, 0xA0, 0x20, 0xEF, 0xFF, 0xA1, 26 | 0x24, 0x20, 0xDC, 0xFF, 0x86, 0x2B, 0xA5, 0x24, 27 | 0xC5, 0x28, 0xA5, 0x25, 0xE5, 0x29, 0xB0, 0xC1, 28 | 0xE6, 0x24, 0xD0, 0x02, 0xE6, 0x25, 0xA5, 0x24, 29 | 0x29, 0x07, 0x10, 0xC8, 0x48, 0x4A, 0x4A, 0x4A, 30 | 0x4A, 0x20, 0xE5, 0xFF, 0x68, 0x29, 0x0F, 0x09, 31 | 0xB0, 0xC9, 0xBA, 0x90, 0x02, 0x69, 0x06, 0x2C, 32 | 0x12, 0xD0, 0x30, 0xFB, 0x8D, 0x12, 0xD0, 0x60, 33 | 0x00, 0x00, 0x00, 0x0F, 0x00, 0xFF, 0x00, 0x00 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ---------- CONFIG SECTION ---------- # 2 | 3 | PORT:=/dev/ttyUSB0 4 | BITRATE:=115200 5 | MODE:=dio 6 | 7 | GCC_FOLDER:=/opt/esp8266/esp-open-sdk/xtensa-lx106-elf 8 | ESPTOOL_PY:=/usr/share/esptool/esptool.py 9 | SDK:=/opt/esp8266/esp_iot_sdk_v1.3.0/ 10 | 11 | # ------------------------------------ # 12 | 13 | FW_FILE_1:=image.elf-0x00000.bin 14 | FW_FILE_2:=image.elf-0x40000.bin 15 | TARGET_OUT:=image.elf 16 | all : $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2) 17 | 18 | SRCS:=user/fake6502.c user/generate_video.c user/user_main.c 19 | 20 | XTLIB:=$(SDK)/lib 21 | XTGCCLIB:=$(GCC_FOLDER)/lib/gcc/xtensa-lx106-elf/4.8.5/libgcc.a 22 | FOLDERPREFIX:=$(GCC_FOLDER)/bin 23 | CC:=$(FOLDERPREFIX)/$(PREFIX)gcc 24 | PREFIX:=$(FOLDERPREFIX)/xtensa-lx106-elf- 25 | 26 | CFLAGS:=-mlongcalls -I$(SDK)/include -Iinclude -O3 -I$(SDK)/include/ -DICACHE_FLASH 27 | LDFLAGS_CORE:=-nostdlib -Wl,--start-group -lmain -lnet80211 -lcrypto -lssl -lwpa -llwip -lpp -lphy -Wl,--end-group -lgcc -T$(SDK)/ld/eagle.app.v6.ld 28 | 29 | LINKFLAGS:= $(LDFLAGS_CORE) -B$(XTLIB) 30 | 31 | $(TARGET_OUT) : $(SRCS) 32 | $(PREFIX)gcc $(CFLAGS) $^ $(LINKFLAGS) -o $@ 33 | 34 | $(FW_FILE_1): $(TARGET_OUT) 35 | PATH=$(FOLDERPREFIX):$$PATH;$(ESPTOOL_PY) elf2image --flash_mode $(MODE) $(TARGET_OUT) 36 | 37 | $(FW_FILE_2): $(TARGET_OUT) 38 | PATH=$(FOLDERPREFIX):$$PATH;$(ESPTOOL_PY) elf2image --flash_mode $(MODE) $(TARGET_OUT) 39 | 40 | flash : 41 | $(ESPTOOL_PY) -b $(BITRATE) --port $(PORT) write_flash --flash_mode $(MODE) 0x00000 image.elf-0x00000.bin 0x40000 image.elf-0x40000.bin 42 | 43 | credentials : 44 | python -c "open('wifi_credentials.bin', 'wb').write(''.join(i.ljust(32, '\0') for i in ['$(ssid)','$(password)']))" 45 | $(ESPTOOL_PY) --port $(PORT) write_flash 0x3c000 wifi_credentials.bin 46 | rm wifi_credentials.bin 47 | 48 | clean : 49 | rm -rf user/*.o driver/*.o $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2) 50 | -------------------------------------------------------------------------------- /include/pin_mux_register.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Espressif System 2010 - 2012 3 | * 4 | */ 5 | 6 | #ifndef _PIN_MUX_H_ 7 | #define _PIN_MUX_H_ 8 | 9 | #define PERIPHS_IO_MUX 0x60000800 10 | 11 | #define PERIPHS_IO_MUX_FUNC 0x13 12 | #define PERIPHS_IO_MUX_FUNC_S 4 13 | #define PERIPHS_IO_MUX_PULLUP BIT7 14 | #define PERIPHS_IO_MUX_PULLDWN BIT6 15 | #define PERIPHS_IO_MUX_SLEEP_PULLUP BIT3 16 | #define PERIPHS_IO_MUX_SLEEP_PULLDWN BIT2 17 | #define PERIPHS_IO_MUX_SLEEP_OE BIT1 18 | #define PERIPHS_IO_MUX_OE BIT0 19 | 20 | #define PERIPHS_IO_MUX_CONF_U (PERIPHS_IO_MUX + 0x00) 21 | #define SPI0_CLK_EQU_SYS_CLK BIT8 22 | #define SPI1_CLK_EQU_SYS_CLK BIT9 23 | 24 | #define PERIPHS_IO_MUX_MTDI_U (PERIPHS_IO_MUX + 0x04) 25 | #define FUNC_MTDI 0 26 | #define FUNC_I2SI_DATA 1 27 | #define FUNC_HSPIQ_MISO 2 28 | #define FUNC_GPIO12 3 29 | #define FUNC_UART0_DTR 4 30 | 31 | #define PERIPHS_IO_MUX_MTCK_U (PERIPHS_IO_MUX + 0x08) 32 | #define FUNC_MTCK 0 33 | #define FUNC_I2SI_BCK 1 34 | #define FUNC_HSPID_MOSI 2 35 | #define FUNC_GPIO13 3 36 | #define FUNC_UART0_CTS 4 37 | 38 | #define PERIPHS_IO_MUX_MTMS_U (PERIPHS_IO_MUX + 0x0C) 39 | #define FUNC_MTMS 0 40 | #define FUNC_I2SI_WS 1 41 | #define FUNC_HSPI_CLK 2 42 | #define FUNC_GPIO14 3 43 | #define FUNC_UART0_DSR 4 44 | 45 | #define PERIPHS_IO_MUX_MTDO_U (PERIPHS_IO_MUX + 0x10) 46 | #define FUNC_MTDO 0 47 | #define FUNC_I2SO_BCK 1 48 | #define FUNC_HSPI_CS0 2 49 | #define FUNC_GPIO15 3 50 | #define FUNC_U0RTS 4 51 | #define FUNC_UART0_RTS 4 52 | 53 | #define PERIPHS_IO_MUX_U0RXD_U (PERIPHS_IO_MUX + 0x14) 54 | #define FUNC_U0RXD 0 55 | #define FUNC_I2SO_DATA 1 56 | #define FUNC_GPIO3 3 57 | #define FUNC_CLK_XTAL_BK 4 58 | 59 | #define PERIPHS_IO_MUX_U0TXD_U (PERIPHS_IO_MUX + 0x18) 60 | #define FUNC_U0TXD 0 61 | #define FUNC_SPICS1 1 62 | #define FUNC_GPIO1 3 63 | #define FUNC_CLK_RTC_BK 4 64 | 65 | #define PERIPHS_IO_MUX_SD_CLK_U (PERIPHS_IO_MUX + 0x1c) 66 | #define FUNC_SDCLK 0 67 | #define FUNC_SPICLK 1 68 | #define FUNC_GPIO6 3 69 | #define UART1_CTS 4 70 | 71 | #define PERIPHS_IO_MUX_SD_DATA0_U (PERIPHS_IO_MUX + 0x20) 72 | #define FUNC_SDDATA0 0 73 | #define FUNC_SPIQ_MISO 1 74 | #define FUNC_GPIO7 3 75 | #define FUNC_U1TXD 4 76 | #define FUNC_UART1_TXD 4 77 | 78 | #define PERIPHS_IO_MUX_SD_DATA1_U (PERIPHS_IO_MUX + 0x24) 79 | #define FUNC_SDDATA1 0 80 | #define FUNC_SPID_MOSI 1 81 | #define FUNC_GPIO8 3 82 | #define FUNC_U1RXD 4 83 | #define FUNC_UART1_RXD 4 84 | 85 | #define PERIPHS_IO_MUX_SD_DATA2_U (PERIPHS_IO_MUX + 0x28) 86 | #define FUNC_SDDATA2 0 87 | #define FUNC_SPIHD 1 88 | #define FUNC_GPIO9 3 89 | #define UFNC_HSPIHD 4 90 | 91 | #define PERIPHS_IO_MUX_SD_DATA3_U (PERIPHS_IO_MUX + 0x2c) 92 | #define FUNC_SDDATA3 0 93 | #define FUNC_SPIWP 1 94 | #define FUNC_GPIO10 3 95 | #define FUNC_HSPIWP 4 96 | 97 | #define PERIPHS_IO_MUX_SD_CMD_U (PERIPHS_IO_MUX + 0x30) 98 | #define FUNC_SDCMD 0 99 | #define FUNC_SPICS0 1 100 | #define FUNC_GPIO11 3 101 | #define U1RTS 4 102 | #define UART1_RTS 4 103 | 104 | #define PERIPHS_IO_MUX_GPIO0_U (PERIPHS_IO_MUX + 0x34) 105 | #define FUNC_GPIO0 0 106 | #define FUNC_SPICS2 1 107 | #define FUNC_CLK_OUT 4 108 | 109 | #define PERIPHS_IO_MUX_GPIO2_U (PERIPHS_IO_MUX + 0x38) 110 | #define FUNC_GPIO2 0 111 | #define FUNC_I2SO_WS 1 112 | #define FUNC_U1TXD_BK 2 113 | #define FUNC_UART1_TXD_BK 2 114 | #define FUNC_U0TXD_BK 4 115 | #define FUNC_UART0_TXD_BK 4 116 | 117 | #define PERIPHS_IO_MUX_GPIO4_U (PERIPHS_IO_MUX + 0x3C) 118 | #define FUNC_GPIO4 0 119 | #define FUNC_CLK_XTAL 1 120 | 121 | #define PERIPHS_IO_MUX_GPIO5_U (PERIPHS_IO_MUX + 0x40) 122 | #define FUNC_GPIO5 0 123 | #define FUNC_CLK_RTC 1 124 | 125 | #define PIN_PULLUP_DIS(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP) 126 | #define PIN_PULLUP_EN(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP) 127 | 128 | //XXX THIS LOOKS WRONG. 129 | 130 | #undef PIN_FUNC_SELECT 131 | 132 | #define PIN_FUNC_SELECT(PIN_NAME, FUNC) do { \ 133 | CLEAR_PERI_REG_MASK(PIN_NAME, (PERIPHS_IO_MUX_FUNC<' prompt. 76 | 77 | ### Rebooting 78 | 79 | Press **Ctrl + C** when connected through telnet to trigger emulator reboot. Neither wi-fi or telnet connection will be dropped. 80 | 81 | ## Demo 82 | 83 | [![Espple video demonstration](https://img.youtube.com/vi/rCqbB1UmW8o/0.jpg)](https://www.youtube.com/watch?v=rCqbB1UmW8o) 84 | 85 | Click on the image to see a video of Espple running. 86 | 87 | ## Help 88 | 89 | ##### Q. Backspace doesn't work - it shows _ 90 | 91 | A. This is by design, Apple 1 output works more like a teletype, there is no going back so this is the "rub out" symbol which tells the computer to disregard the previous symbol. 92 | 93 | ##### Q. I've flashed your bin files and now I'm in a reboot loop 94 | 95 | A. My board is an ESP-12E, and requires DIO flash mode to be set (2 pins used for address and data) as opposed to QIO mode (4 pins used) some other variants use. Try flashing with DIO and see if that helps. 96 | 97 | ##### Q. Wifi doesn't connect 98 | 99 | A. Make sure you've set the credentials like instructed. Try moving the ESP board closer to the access point and configure it to use one of the lower frequency channels (1-6). You can monitor progress using a serial connection (115200, 8N1). 100 | 101 | ##### Q. Why can't I simply use the serial as a keyboard input? This wi-fi thing seems overengineered. 102 | 103 | A. Because the UART0 RX line is already being used as an I2S output, and UART1 exposes TX pin only to the board. 104 | 105 | On the plus side, it's totally wireless. 106 | 107 | ##### Q. Program doesn't start after TFTP upload 108 | 109 | A. A packet was probably lost, try again and make sure you have a good wi-fi reception. 110 | 111 | ##### Q. I'd like to use NTSC 112 | 113 | A. Few people asked about the possibility of generating NTSC signal so I've updated the source to support both. Edit generate\_video.c and change #define PAL to #define NTSC. 114 | 115 | ##### Q. I can't find a signal on the TV 116 | 117 | A. Your RF input connector and the whole signal path is shielded inside the TV so there should be some sort of antenna plugged in. If you don't have an indoor antenna, a piece of wire will do just fine. Make sure you don't short the tip and ring of your input connector because you won't receive anything. In your TV menu choose analogue TV, choose PAL standard and select channel 4. The esp board emits at 60 MHz which is slightly lower than channel 4 frequency, so you might have to fine tune a bit. Most modern TVs should be able to automatically scan and find the channel for you. 118 | 119 | ## Missing features 120 | 121 | The emulator should accomodate for the terminal output delay. It should be possible to upload the original tape audio waveform over tftp and use the original Apple Cassette Interface to read it. 122 | 123 | ## License 124 | 125 | This software is licensed under the MIT license. 126 | 127 | ## Credits 128 | 129 | Video generation is derived from the much more impressive [channel3](https://github.com/cnlohr/channel3) project by [Charles Lohr](https://github.com/cnlohr). 130 | 131 | CPU core is made using the fake6502 project by Mike Chambers. 132 | 133 | Apple 1 was famously made by [Stephen Wozniak](https://en.wikipedia.org/wiki/Steve_Wozniak), one of the greatest engineers of our time. 134 | -------------------------------------------------------------------------------- /eagle.app.v6.ld: -------------------------------------------------------------------------------- 1 | /* This linker script generated from xt-genldscripts.tpp for LSP . */ 2 | /* Linker Script for ld -N */ 3 | MEMORY 4 | { 5 | dport0_0_seg : org = 0x3FF00000, len = 0x10 6 | dram0_0_seg : org = 0x3FFE8000, len = 0x14000 7 | iram1_0_seg : org = 0x40100000, len = 0x8000 8 | irom0_0_seg : org = 0x40210000, len = 0x5C000 9 | } 10 | 11 | PHDRS 12 | { 13 | dport0_0_phdr PT_LOAD; 14 | dram0_0_phdr PT_LOAD; 15 | dram0_0_bss_phdr PT_LOAD; 16 | iram1_0_phdr PT_LOAD; 17 | irom0_0_phdr PT_LOAD; 18 | } 19 | 20 | 21 | /* Default entry point: */ 22 | ENTRY(call_user_start) 23 | EXTERN(_DebugExceptionVector) 24 | EXTERN(_DoubleExceptionVector) 25 | EXTERN(_KernelExceptionVector) 26 | EXTERN(_NMIExceptionVector) 27 | EXTERN(_UserExceptionVector) 28 | PROVIDE(_memmap_vecbase_reset = 0x40000000); 29 | /* Various memory-map dependent cache attribute settings: */ 30 | _memmap_cacheattr_wb_base = 0x00000110; 31 | _memmap_cacheattr_wt_base = 0x00000110; 32 | _memmap_cacheattr_bp_base = 0x00000220; 33 | _memmap_cacheattr_unused_mask = 0xFFFFF00F; 34 | _memmap_cacheattr_wb_trapnull = 0x2222211F; 35 | _memmap_cacheattr_wba_trapnull = 0x2222211F; 36 | _memmap_cacheattr_wbna_trapnull = 0x2222211F; 37 | _memmap_cacheattr_wt_trapnull = 0x2222211F; 38 | _memmap_cacheattr_bp_trapnull = 0x2222222F; 39 | _memmap_cacheattr_wb_strict = 0xFFFFF11F; 40 | _memmap_cacheattr_wt_strict = 0xFFFFF11F; 41 | _memmap_cacheattr_bp_strict = 0xFFFFF22F; 42 | _memmap_cacheattr_wb_allvalid = 0x22222112; 43 | _memmap_cacheattr_wt_allvalid = 0x22222112; 44 | _memmap_cacheattr_bp_allvalid = 0x22222222; 45 | PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); 46 | 47 | SECTIONS 48 | { 49 | 50 | .dport0.rodata : ALIGN(4) 51 | { 52 | _dport0_rodata_start = ABSOLUTE(.); 53 | *(.dport0.rodata) 54 | *(.dport.rodata) 55 | _dport0_rodata_end = ABSOLUTE(.); 56 | } >dport0_0_seg :dport0_0_phdr 57 | 58 | .dport0.literal : ALIGN(4) 59 | { 60 | _dport0_literal_start = ABSOLUTE(.); 61 | *(.dport0.literal) 62 | *(.dport.literal) 63 | _dport0_literal_end = ABSOLUTE(.); 64 | } >dport0_0_seg :dport0_0_phdr 65 | 66 | .dport0.data : ALIGN(4) 67 | { 68 | _dport0_data_start = ABSOLUTE(.); 69 | *(.dport0.data) 70 | *(.dport.data) 71 | _dport0_data_end = ABSOLUTE(.); 72 | } >dport0_0_seg :dport0_0_phdr 73 | 74 | .data : ALIGN(4) 75 | { 76 | _data_start = ABSOLUTE(.); 77 | *(.data) 78 | *(.data.*) 79 | *(.gnu.linkonce.d.*) 80 | *(.data1) 81 | *(.sdata) 82 | *(.sdata.*) 83 | *(.gnu.linkonce.s.*) 84 | *(.sdata2) 85 | *(.sdata2.*) 86 | *(.gnu.linkonce.s2.*) 87 | *(.jcr) 88 | _data_end = ABSOLUTE(.); 89 | } >dram0_0_seg :dram0_0_phdr 90 | 91 | .rodata : ALIGN(4) 92 | { 93 | _rodata_start = ABSOLUTE(.); 94 | *(.sdk.version) 95 | *(.rodata) 96 | *(.rodata.*) 97 | *(.gnu.linkonce.r.*) 98 | *(.rodata1) 99 | __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); 100 | *(.xt_except_table) 101 | *(.gcc_except_table) 102 | *(.gnu.linkonce.e.*) 103 | *(.gnu.version_r) 104 | *(.eh_frame) 105 | /* C++ constructor and destructor tables, properly ordered: */ 106 | KEEP (*crtbegin.o(.ctors)) 107 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 108 | KEEP (*(SORT(.ctors.*))) 109 | KEEP (*(.ctors)) 110 | KEEP (*crtbegin.o(.dtors)) 111 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 112 | KEEP (*(SORT(.dtors.*))) 113 | KEEP (*(.dtors)) 114 | /* C++ exception handlers table: */ 115 | __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); 116 | *(.xt_except_desc) 117 | *(.gnu.linkonce.h.*) 118 | __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); 119 | *(.xt_except_desc_end) 120 | *(.dynamic) 121 | *(.gnu.version_d) 122 | . = ALIGN(4); /* this table MUST be 4-byte aligned */ 123 | _bss_table_start = ABSOLUTE(.); 124 | LONG(_bss_start) 125 | LONG(_bss_end) 126 | _bss_table_end = ABSOLUTE(.); 127 | _rodata_end = ABSOLUTE(.); 128 | } >dram0_0_seg :dram0_0_phdr 129 | 130 | .bss ALIGN(8) (NOLOAD) : ALIGN(4) 131 | { 132 | . = ALIGN (8); 133 | _bss_start = ABSOLUTE(.); 134 | *(.dynsbss) 135 | *(.sbss) 136 | *(.sbss.*) 137 | *(.gnu.linkonce.sb.*) 138 | *(.scommon) 139 | *(.sbss2) 140 | *(.sbss2.*) 141 | *(.gnu.linkonce.sb2.*) 142 | *(.dynbss) 143 | *(.bss) 144 | *(.bss.*) 145 | *(.gnu.linkonce.b.*) 146 | *(COMMON) 147 | . = ALIGN (8); 148 | _bss_end = ABSOLUTE(.); 149 | _heap_start = ABSOLUTE(.); 150 | /* _stack_sentry = ALIGN(0x8); */ 151 | } >dram0_0_seg :dram0_0_bss_phdr 152 | /* __stack = 0x3ffc8000; */ 153 | 154 | .irom0.text : ALIGN(4) 155 | { 156 | _irom0_text_start = ABSOLUTE(.); 157 | 158 | *libat.a:(.literal.* .text.*) 159 | *libcrypto.a:(.literal.* .text.*) 160 | *libespnow.a:(.literal.* .text.*) 161 | *libjson.a:(.literal.* .text.*) 162 | *liblwip.a:(.literal.* .text.*) 163 | *libmesh.a:(.literal.* .text.*) 164 | *libnet80211.a:(.literal.* .text.*) 165 | *libsmartconfig.a:(.literal.* .text.*) 166 | *libssl.a:(.literal.* .text.*) 167 | *libupgrade.a:(.literal.* .text.*) 168 | *libwpa.a:(.literal.* .text.*) 169 | *libwpa2.a:(.literal.* .text.*) 170 | *libwps.a:(.literal.* .text.*) 171 | 172 | *libmbedtls.a:(.literal.* .text.*) 173 | 174 | *libm.a:(.literal .text .literal.* .text.*) 175 | 176 | *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) 177 | _irom0_text_end = ABSOLUTE(.); 178 | } >irom0_0_seg :irom0_0_phdr 179 | 180 | .text : ALIGN(4) 181 | { 182 | _stext = .; 183 | _text_start = ABSOLUTE(.); 184 | *(.UserEnter.text) 185 | . = ALIGN(16); 186 | *(.DebugExceptionVector.text) 187 | . = ALIGN(16); 188 | *(.NMIExceptionVector.text) 189 | . = ALIGN(16); 190 | *(.KernelExceptionVector.text) 191 | LONG(0) 192 | LONG(0) 193 | LONG(0) 194 | LONG(0) 195 | . = ALIGN(16); 196 | *(.UserExceptionVector.text) 197 | LONG(0) 198 | LONG(0) 199 | LONG(0) 200 | LONG(0) 201 | . = ALIGN(16); 202 | *(.DoubleExceptionVector.text) 203 | LONG(0) 204 | LONG(0) 205 | LONG(0) 206 | LONG(0) 207 | . = ALIGN (16); 208 | *(.entry.text) 209 | *(.init.literal) 210 | *(.init) 211 | *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) 212 | *(.fini.literal) 213 | *(.fini) 214 | *(.gnu.version) 215 | _text_end = ABSOLUTE(.); 216 | _etext = .; 217 | } >iram1_0_seg :iram1_0_phdr 218 | 219 | .lit4 : ALIGN(4) 220 | { 221 | _lit4_start = ABSOLUTE(.); 222 | *(*.lit4) 223 | *(.lit4.*) 224 | *(.gnu.linkonce.lit4.*) 225 | _lit4_end = ABSOLUTE(.); 226 | } >iram1_0_seg :iram1_0_phdr 227 | } 228 | 229 | /* get ROM code address */ 230 | INCLUDE "../ld/eagle.rom.addr.v6.ld" 231 | -------------------------------------------------------------------------------- /user/user_main.c: -------------------------------------------------------------------------------- 1 | #include "c_types.h" 2 | #include "mem.h" 3 | #include "user_interface.h" 4 | #include "ets_sys.h" 5 | #include "osapi.h" 6 | #include "espconn.h" 7 | #include "woz_monitor.h" 8 | #include "spi_flash.h" 9 | #include 10 | 11 | #define RAM_SIZE 0x5000 12 | #define INSTRUCTIONS_CHUNK 10000 13 | 14 | #define TERM_WIDTH 40 15 | #define TERM_HEIGHT 24 16 | 17 | #define SPACE 0x20 18 | 19 | 20 | static volatile os_timer_t emulator_callback_timer, cursor_timer; 21 | 22 | uint8_t computer_ram[RAM_SIZE], 23 | terminal_ram[TERM_WIDTH * TERM_HEIGHT]; 24 | 25 | uint16_t load_target_start; 26 | 27 | uint32_t current_start, 28 | current_end, 29 | loop_counter = 0; 30 | 31 | /* Current terminal row and column */ 32 | uint8_t term_x = 0, 33 | term_y = 0, 34 | cursor_visible = 0, 35 | cursor_disabled = 0; 36 | 37 | struct pia6821 { 38 | uint8_t keyboard_register; 39 | uint8_t keyboard_control; 40 | uint8_t display_register; 41 | uint8_t display_control; 42 | 43 | } pia = {0}; 44 | 45 | 46 | /* ---------- Function definitions ------------ */ 47 | 48 | void ICACHE_FLASH_ATTR reset_emulator() { 49 | term_x = 0; 50 | term_y = 0; 51 | 52 | ets_memset( computer_ram, 0xff, sizeof(computer_ram) ); 53 | ets_memset( terminal_ram, 0b100000, sizeof(terminal_ram) ); 54 | reset6502(); 55 | } 56 | 57 | uint8_t read6502(uint16_t address) { 58 | /* Address in RAM */ 59 | if (address < RAM_SIZE) 60 | return computer_ram[address]; 61 | 62 | /* 4kB of RAM (0x4000-0x5000) is logically mapped to memory bank 0xE000, needed for BASIC. */ 63 | else if ((address & 0xF000) == 0xE000) 64 | return computer_ram[address - 0xA000]; 65 | 66 | /* PIA peripheral interface */ 67 | else if ((address & 0xFFF0) == 0xD010) { 68 | /* Set keyboard control register to 0 if key was read */ 69 | if (address == 0xD010) { 70 | pia.keyboard_control = 0x00; 71 | } 72 | 73 | return *(&pia.keyboard_register + address - 0xD010); 74 | } 75 | 76 | /* Address belongs to Woz Monitor ROM (0xFF00 - 0xFFFF) */ 77 | else if ((address & 0xFF00) == 0xFF00) 78 | return woz_monitor[address - 0xFF00]; 79 | 80 | /* Default value */ 81 | return 0xff; 82 | } 83 | 84 | 85 | void ICACHE_FLASH_ATTR toggle_cursor() { 86 | uint8_t i; 87 | 88 | cursor_visible ^= 1; 89 | terminal_ram[term_y * TERM_WIDTH + term_x] = cursor_visible | cursor_disabled ? 0x20 : 0x00; 90 | } 91 | 92 | 93 | void ICACHE_FLASH_ATTR terminal_write(uint8_t value) { 94 | /* When changing the terminal_ram, disable cursor first */ 95 | cursor_disabled = 1; 96 | 97 | /* Commit change */ 98 | toggle_cursor(); 99 | 100 | /* End of line reached or return pressed */ 101 | if(term_x > 39 || value == 0x0D) { 102 | term_x = 0; 103 | 104 | if(term_y >= 23) { 105 | /* Scroll 1 line up (copy 23 text lines only, blank the last one) */ 106 | ets_memcpy(terminal_ram, &terminal_ram[TERM_WIDTH], TERM_WIDTH * (TERM_HEIGHT - 1)); 107 | ets_memset(terminal_ram + TERM_WIDTH * (TERM_HEIGHT - 1), SPACE, TERM_WIDTH); 108 | 109 | } 110 | else 111 | term_y++; 112 | 113 | } 114 | 115 | /* Only printable characters go to terminal RAM. Other characters don't move the cursor either. */ 116 | if (value >= 0x20 && value <= 0x7E) { 117 | terminal_ram[term_y * TERM_WIDTH + term_x] = value & 0x3F; 118 | term_x++; 119 | } 120 | 121 | /* Enable cursor again */ 122 | cursor_disabled = 0; 123 | } 124 | 125 | 126 | void write6502(uint16_t address, uint8_t value) 127 | { 128 | if(address < RAM_SIZE) { 129 | computer_ram[address] = value; 130 | } 131 | 132 | /* Address belongs to a 4kB bank mapped at (0xE000 - 0xF000), translate it to real RAM 0x4000-0x5000 133 | * this is needed to run Apple BASIC */ 134 | else if((address & 0xF000) == 0xE000) { 135 | computer_ram[address - 0xA000] = value; 136 | } 137 | 138 | /* Write to PIA chip. */ 139 | else if (address == 0xD010) { 140 | pia.keyboard_register = value; 141 | 142 | /* If a key was pressed, write to keyboard control register as well */ 143 | pia.keyboard_control = 0xFF; 144 | } 145 | else if (address == 0xD012) { 146 | terminal_write(value ^ 0x80); 147 | } 148 | } 149 | 150 | 151 | static void ICACHE_FLASH_ATTR emulator_task(os_event_t *events) 152 | { 153 | current_start = system_get_time(); 154 | exec6502(INSTRUCTIONS_CHUNK); 155 | current_end = system_get_time(); 156 | } 157 | 158 | 159 | static void ICACHE_FLASH_ATTR dataRecvCallback(void *arg, char *pusrdata, unsigned short lenght){ 160 | 161 | char input_character = *pusrdata; 162 | 163 | /* Convert lowercase to uppercase */ 164 | if (input_character > 0x60 && input_character < 0x7B) 165 | input_character ^= 0x20; 166 | 167 | /* Convert LF to CR */ 168 | else if (input_character == 0x0A) 169 | input_character = 0x0D; 170 | 171 | /* Convert backspace to "rub out" */ 172 | else if (input_character == 0x7F) 173 | input_character = '_'; 174 | 175 | /* Enable CPU reset from telnet (Ctrl + C) */ 176 | else if (input_character == 0x03) { 177 | reset_emulator(); 178 | return; 179 | } 180 | 181 | write6502(0xd010, input_character | 0x80); 182 | } 183 | 184 | 185 | static void ICACHE_FLASH_ATTR connectionCallback(void *arg){ 186 | struct espconn *telnet_server = arg; 187 | 188 | /* Welcome message and force character mode on client */ 189 | char *welcome_message = "Welcome to Espple!\n\xff\xfd\x22\xff\xfb\x01"; 190 | 191 | espconn_regist_recvcb(telnet_server, dataRecvCallback); 192 | espconn_send(telnet_server, welcome_message, strlen(welcome_message)); 193 | } 194 | 195 | 196 | void tftp_server_recv(void *arg, char *pdata, unsigned short len) 197 | { 198 | struct espconn* udp_server_local = arg; 199 | uint8_t ack[] = {0x00, 0x04, 0x00, 0x00}; 200 | 201 | if (len < 4) 202 | return; 203 | 204 | /* Write request, this is the first package */ 205 | if (pdata[1] == 0x02) { 206 | load_target_start = (computer_ram[0x27] << 8) + computer_ram[0x26]; 207 | if (load_target_start >= 0xE000) 208 | load_target_start -= 0xA000; 209 | } 210 | 211 | /* Data packet */ 212 | else if(pdata[1] == 0x03) { 213 | /* Copy sequence number into ACK packet and send it */ 214 | ets_memcpy(&ack[2], &pdata[2], 2); 215 | 216 | ets_memcpy(&computer_ram[load_target_start], pdata + 4, len - 4); 217 | load_target_start += (len - 4); 218 | 219 | } 220 | 221 | espconn_send(udp_server_local, ack, 4); 222 | } 223 | 224 | 225 | void ICACHE_FLASH_ATTR user_init(void) 226 | { 227 | uint16_t ui_address; 228 | struct ip_info ip_address; 229 | 230 | char ssid[32] = "SSID"; 231 | char password[32] = "PASSWORD"; 232 | 233 | uart_div_modify(0, UART_CLK_FREQ / 115200); 234 | 235 | uint32 credentials[16] = {0}; 236 | 237 | spi_flash_read(0x3c000, (uint32 *)&credentials[0], 16 * sizeof(uint32)); 238 | 239 | struct station_config stationConf; 240 | 241 | ets_strcpy(&stationConf.ssid, &credentials[0]); 242 | ets_strcpy(&stationConf.password, &credentials[8]); 243 | 244 | current_start = system_get_time(); 245 | 246 | reset_emulator(); 247 | testi2s_init(); 248 | 249 | system_update_cpu_freq( SYS_CPU_160MHZ ); 250 | 251 | /* Create a 10ms timer to call back the emulator task function periodically */ 252 | os_timer_setfn(&emulator_callback_timer, (os_timer_func_t *) emulator_task, NULL); 253 | os_timer_arm(&emulator_callback_timer, 10, 1); 254 | 255 | /* Toggle cursor every 300 ms */ 256 | os_timer_setfn(&cursor_timer, (os_timer_func_t *) toggle_cursor, NULL); 257 | os_timer_arm(&cursor_timer, 300, 1); 258 | 259 | /* Initialize wifi connection */ 260 | wifi_set_opmode( STATION_MODE ); 261 | 262 | wifi_station_set_config(&stationConf); 263 | wifi_set_phy_mode(PHY_MODE_11B); 264 | wifi_station_set_auto_connect(1); 265 | wifi_station_connect(); 266 | 267 | 268 | /* TFTP server */ 269 | struct espconn *tftp_server = (struct espconn *)os_zalloc(sizeof(struct espconn)); 270 | ets_memset( tftp_server, 0, sizeof( struct espconn ) ); 271 | tftp_server->type = ESPCONN_UDP; 272 | tftp_server->proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp)); 273 | tftp_server->proto.udp->local_port = 69; 274 | 275 | espconn_regist_recvcb(tftp_server, tftp_server_recv); 276 | espconn_create(tftp_server); 277 | 278 | 279 | /* Telnet server */ 280 | struct espconn *telnet_server = (struct espconn *)os_zalloc(sizeof(struct espconn)); 281 | ets_memset(telnet_server, 0, sizeof(struct espconn)); 282 | 283 | espconn_create(telnet_server); 284 | telnet_server->type = ESPCONN_TCP; 285 | telnet_server->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); 286 | telnet_server->proto.tcp->local_port = 23; 287 | espconn_regist_connectcb(telnet_server, connectionCallback); 288 | 289 | espconn_accept(telnet_server); 290 | espconn_regist_time(telnet_server, 3600, 0); 291 | } 292 | -------------------------------------------------------------------------------- /user/slc_register.h: -------------------------------------------------------------------------------- 1 | //Generated at 2012-10-23 19:55:03 2 | /* 3 | * Copyright (c) 2010 - 2011 Espressif System 4 | * 5 | */ 6 | 7 | #ifndef SLC_REGISTER_H_ 8 | #define SLC_REGISTER_H_ 9 | 10 | #define REG_SLC_BASE 0x60000B00 11 | //version value:32'h091700 12 | 13 | #define SLC_CONF0 (REG_SLC_BASE + 0x0) 14 | #ifndef ESP_MAC_5 15 | #define SLC_MODE 0x00000003 16 | #define SLC_MODE_S 12 17 | #endif 18 | #define SLC_DATA_BURST_EN (BIT(9)) 19 | #define SLC_DSCR_BURST_EN (BIT(8)) 20 | #define SLC_RX_NO_RESTART_CLR (BIT(7)) 21 | #define SLC_RX_AUTO_WRBACK (BIT(6)) 22 | #define SLC_RX_LOOP_TEST (BIT(5)) 23 | #define SLC_TX_LOOP_TEST (BIT(4)) 24 | #define SLC_AHBM_RST (BIT(3)) 25 | #define SLC_AHBM_FIFO_RST (BIT(2)) 26 | #define SLC_RXLINK_RST (BIT(1)) 27 | #define SLC_TXLINK_RST (BIT(0)) 28 | 29 | #define SLC_INT_RAW (REG_SLC_BASE + 0x4) 30 | #define SLC_TX_DSCR_EMPTY_INT_RAW (BIT(21)) 31 | #define SLC_RX_DSCR_ERR_INT_RAW (BIT(20)) 32 | #define SLC_TX_DSCR_ERR_INT_RAW (BIT(19)) 33 | #define SLC_TOHOST_INT_RAW (BIT(18)) 34 | #define SLC_RX_EOF_INT_RAW (BIT(17)) 35 | #define SLC_RX_DONE_INT_RAW (BIT(16)) 36 | #define SLC_TX_EOF_INT_RAW (BIT(15)) 37 | #define SLC_TX_DONE_INT_RAW (BIT(14)) 38 | #define SLC_TOKEN1_1TO0_INT_RAW (BIT(13)) 39 | #define SLC_TOKEN0_1TO0_INT_RAW (BIT(12)) 40 | #define SLC_TX_OVF_INT_RAW (BIT(11)) 41 | #define SLC_RX_UDF_INT_RAW (BIT(10)) 42 | #define SLC_TX_START_INT_RAW (BIT(9)) 43 | #define SLC_RX_START_INT_RAW (BIT(8)) 44 | #define SLC_FRHOST_BIT7_INT_RAW (BIT(7)) 45 | #define SLC_FRHOST_BIT6_INT_RAW (BIT(6)) 46 | #define SLC_FRHOST_BIT5_INT_RAW (BIT(5)) 47 | #define SLC_FRHOST_BIT4_INT_RAW (BIT(4)) 48 | #define SLC_FRHOST_BIT3_INT_RAW (BIT(3)) 49 | #define SLC_FRHOST_BIT2_INT_RAW (BIT(2)) 50 | #define SLC_FRHOST_BIT1_INT_RAW (BIT(1)) 51 | #define SLC_FRHOST_BIT0_INT_RAW (BIT(0)) 52 | 53 | #define SLC_INT_STATUS (REG_SLC_BASE + 0x8) 54 | #define SLC_TX_DSCR_EMPTY_INT_ST (BIT(21)) 55 | #define SLC_RX_DSCR_ERR_INT_ST (BIT(20)) 56 | #define SLC_TX_DSCR_ERR_INT_ST (BIT(19)) 57 | #define SLC_TOHOST_INT_ST (BIT(18)) 58 | #define SLC_RX_EOF_INT_ST (BIT(17)) 59 | #define SLC_RX_DONE_INT_ST (BIT(16)) 60 | #define SLC_TX_EOF_INT_ST (BIT(15)) 61 | #define SLC_TX_DONE_INT_ST (BIT(14)) 62 | #define SLC_TOKEN1_1TO0_INT_ST (BIT(13)) 63 | #define SLC_TOKEN0_1TO0_INT_ST (BIT(12)) 64 | #define SLC_TX_OVF_INT_ST (BIT(11)) 65 | #define SLC_RX_UDF_INT_ST (BIT(10)) 66 | #define SLC_TX_START_INT_ST (BIT(9)) 67 | #define SLC_RX_START_INT_ST (BIT(8)) 68 | #define SLC_FRHOST_BIT7_INT_ST (BIT(7)) 69 | #define SLC_FRHOST_BIT6_INT_ST (BIT(6)) 70 | #define SLC_FRHOST_BIT5_INT_ST (BIT(5)) 71 | #define SLC_FRHOST_BIT4_INT_ST (BIT(4)) 72 | #define SLC_FRHOST_BIT3_INT_ST (BIT(3)) 73 | #define SLC_FRHOST_BIT2_INT_ST (BIT(2)) 74 | #define SLC_FRHOST_BIT1_INT_ST (BIT(1)) 75 | #define SLC_FRHOST_BIT0_INT_ST (BIT(0)) 76 | 77 | #define SLC_INT_ENA (REG_SLC_BASE + 0xC) 78 | #define SLC_TX_DSCR_EMPTY_INT_ENA (BIT(21)) 79 | #define SLC_RX_DSCR_ERR_INT_ENA (BIT(20)) 80 | #define SLC_TX_DSCR_ERR_INT_ENA (BIT(19)) 81 | #define SLC_TOHOST_INT_ENA (BIT(18)) 82 | #define SLC_RX_EOF_INT_ENA (BIT(17)) 83 | #define SLC_RX_DONE_INT_ENA (BIT(16)) 84 | #define SLC_TX_EOF_INT_ENA (BIT(15)) 85 | #define SLC_TX_DONE_INT_ENA (BIT(14)) 86 | #define SLC_TOKEN1_1TO0_INT_ENA (BIT(13)) 87 | #define SLC_TOKEN0_1TO0_INT_ENA (BIT(12)) 88 | #define SLC_TX_OVF_INT_ENA (BIT(11)) 89 | #define SLC_RX_UDF_INT_ENA (BIT(10)) 90 | #define SLC_TX_START_INT_ENA (BIT(9)) 91 | #define SLC_RX_START_INT_ENA (BIT(8)) 92 | #define SLC_FRHOST_BIT7_INT_ENA (BIT(7)) 93 | #define SLC_FRHOST_BIT6_INT_ENA (BIT(6)) 94 | #define SLC_FRHOST_BIT5_INT_ENA (BIT(5)) 95 | #define SLC_FRHOST_BIT4_INT_ENA (BIT(4)) 96 | #define SLC_FRHOST_BIT3_INT_ENA (BIT(3)) 97 | #define SLC_FRHOST_BIT2_INT_ENA (BIT(2)) 98 | #define SLC_FRHOST_BIT1_INT_ENA (BIT(1)) 99 | #define SLC_FRHOST_BIT0_INT_ENA (BIT(0)) 100 | 101 | #define SLC_FRHOST_BIT_INT_ENA_ALL 0xff 102 | 103 | #define SLC_INT_CLR (REG_SLC_BASE + 0x10) 104 | #define SLC_TX_DSCR_EMPTY_INT_CLR (BIT(21)) 105 | #define SLC_RX_DSCR_ERR_INT_CLR (BIT(20)) 106 | #define SLC_TX_DSCR_ERR_INT_CLR (BIT(19)) 107 | #define SLC_TOHOST_INT_CLR (BIT(18)) 108 | #define SLC_RX_EOF_INT_CLR (BIT(17)) 109 | #define SLC_RX_DONE_INT_CLR (BIT(16)) 110 | #define SLC_TX_EOF_INT_CLR (BIT(15)) 111 | #define SLC_TX_DONE_INT_CLR (BIT(14)) 112 | #define SLC_TOKEN1_1TO0_INT_CLR (BIT(13)) 113 | #define SLC_TOKEN0_1TO0_INT_CLR (BIT(12)) 114 | #define SLC_TX_OVF_INT_CLR (BIT(11)) 115 | #define SLC_RX_UDF_INT_CLR (BIT(10)) 116 | #define SLC_TX_START_INT_CLR (BIT(9)) 117 | #define SLC_RX_START_INT_CLR (BIT(8)) 118 | #define SLC_FRHOST_BIT7_INT_CLR (BIT(7)) 119 | #define SLC_FRHOST_BIT6_INT_CLR (BIT(6)) 120 | #define SLC_FRHOST_BIT5_INT_CLR (BIT(5)) 121 | #define SLC_FRHOST_BIT4_INT_CLR (BIT(4)) 122 | #define SLC_FRHOST_BIT3_INT_CLR (BIT(3)) 123 | #define SLC_FRHOST_BIT2_INT_CLR (BIT(2)) 124 | #define SLC_FRHOST_BIT1_INT_CLR (BIT(1)) 125 | #define SLC_FRHOST_BIT0_INT_CLR (BIT(0)) 126 | 127 | #define SLC_RX_STATUS (REG_SLC_BASE + 0x14) 128 | #define SLC_RX_EMPTY (BIT(1)) 129 | #define SLC_RX_FULL (BIT(0)) 130 | 131 | #define SLC_RX_FIFO_PUSH (REG_SLC_BASE + 0x18) 132 | #define SLC_RXFIFO_PUSH (BIT(16)) 133 | #define SLC_RXFIFO_WDATA 0x000001FF 134 | #define SLC_RXFIFO_WDATA_S 0 135 | 136 | #define SLC_TX_STATUS (REG_SLC_BASE + 0x1C) 137 | #define SLC_TX_EMPTY (BIT(1)) 138 | #define SLC_TX_FULL (BIT(0)) 139 | 140 | #define SLC_TX_FIFO_POP (REG_SLC_BASE + 0x20) 141 | #define SLC_TXFIFO_POP (BIT(16)) 142 | #define SLC_TXFIFO_RDATA 0x000007FF 143 | #define SLC_TXFIFO_RDATA_S 0 144 | 145 | #define SLC_RX_LINK (REG_SLC_BASE + 0x24) 146 | #define SLC_RXLINK_PARK (BIT(31)) 147 | #define SLC_RXLINK_RESTART (BIT(30)) 148 | #define SLC_RXLINK_START (BIT(29)) 149 | #define SLC_RXLINK_STOP (BIT(28)) 150 | #define SLC_RXLINK_DESCADDR_MASK 0x000FFFFF 151 | #define SLC_RXLINK_ADDR_S 0 152 | 153 | #define SLC_TX_LINK (REG_SLC_BASE + 0x28) 154 | #define SLC_TXLINK_PARK (BIT(31)) 155 | #define SLC_TXLINK_RESTART (BIT(30)) 156 | #define SLC_TXLINK_START (BIT(29)) 157 | #define SLC_TXLINK_STOP (BIT(28)) 158 | #define SLC_TXLINK_DESCADDR_MASK 0x000FFFFF 159 | #define SLC_TXLINK_ADDR_S 0 160 | 161 | #define SLC_INTVEC_TOHOST (REG_SLC_BASE + 0x2C) 162 | #define SLC_TOHOST_INTVEC 0x000000FF 163 | #define SLC_TOHOST_INTVEC_S 0 164 | 165 | #define SLC_TOKEN0 (REG_SLC_BASE + 0x30) 166 | #define SLC_TOKEN0_MASK 0x00000FFF 167 | #define SLC_TOKEN0_S 16 168 | #define SLC_TOKEN0_LOCAL_INC_MORE (BIT(14)) 169 | #define SLC_TOKEN0_LOCAL_INC (BIT(13)) 170 | #define SLC_TOKEN0_LOCAL_WR (BIT(12)) 171 | #define SLC_TOKEN0_LOCAL_WDATA_MASK 0x00000FFF 172 | #define SLC_TOKEN0_LOCAL_WDATA_S 0 173 | 174 | #define SLC_TOKEN1 (REG_SLC_BASE + 0x34) 175 | #define SLC_TOKEN1_MASK 0x00000FFF 176 | #define SLC_TOKEN1_S 16 177 | #define SLC_TOKEN1_LOCAL_INC_MORE (BIT(14)) 178 | #define SLC_TOKEN1_LOCAL_INC (BIT(13)) 179 | #define SLC_TOKEN1_LOCAL_WR (BIT(12)) 180 | #define SLC_TOKEN1_LOCAL_WDATA 0x00000FFF 181 | #define SLC_TOKEN1_LOCAL_WDATA_S 0 182 | 183 | #define SLC_CONF1 (REG_SLC_BASE + 0x38) 184 | #define SLC_STATE0 (REG_SLC_BASE + 0x3C) 185 | #define SLC_STATE1 (REG_SLC_BASE + 0x40) 186 | 187 | #define SLC_BRIDGE_CONF (REG_SLC_BASE + 0x44) 188 | #ifndef ESP_MAC_5 189 | #define SLC_TX_PUSH_IDLE_NUM 0x0000FFFF 190 | #define SLC_TX_PUSH_IDLE_NUM_S 16 191 | #define SLC_TX_DUMMY_MODE (BIT(12)) 192 | #endif 193 | #define SLC_FIFO_MAP_ENA 0x0000000F 194 | #define SLC_FIFO_MAP_ENA_S 8 195 | #define SLC_TXEOF_ENA 0x0000003F 196 | #define SLC_TXEOF_ENA_S 0 197 | 198 | #define SLC_RX_EOF_DES_ADDR (REG_SLC_BASE + 0x48) 199 | #define SLC_TX_EOF_DES_ADDR (REG_SLC_BASE + 0x4C) 200 | #define SLC_FROM_HOST_LAST_DESC SLC_TX_EOF_DES_ADDR 201 | #define SLC_TO_HOST_LAST_DESC SLC_RX_EOF_DES_ADDR 202 | 203 | #define SLC_RX_EOF_BFR_DES_ADDR (REG_SLC_BASE + 0x50) 204 | #define SLC_AHB_TEST (REG_SLC_BASE + 0x54) 205 | #define SLC_AHB_TESTADDR 0x00000003 206 | #define SLC_AHB_TESTADDR_S 4 207 | #define SLC_AHB_TESTMODE 0x00000007 208 | #define SLC_AHB_TESTMODE_S 0 209 | 210 | #define SLC_SDIO_ST (REG_SLC_BASE + 0x58) 211 | #define SLC_BUS_ST 0x00000007 212 | #define SLC_BUS_ST_S 12 213 | #define SLC_SDIO_WAKEUP (BIT(8)) 214 | #define SLC_FUNC_ST 0x0000000F 215 | #define SLC_FUNC_ST_S 4 216 | #define SLC_CMD_ST 0x00000007 217 | #define SLC_CMD_ST_S 0 218 | 219 | #define SLC_RX_DSCR_CONF (REG_SLC_BASE + 0x5C) 220 | #ifdef ESP_MAC_5 221 | #define SLC_INFOR_NO_REPLACE (BIT(9)) 222 | #define SLC_TOKEN_NO_REPLACE (BIT(8)) 223 | #define SLC_POP_IDLE_CNT 0x000000FF 224 | #else 225 | #define SLC_RX_FILL_EN (BIT(20)) 226 | #define SLC_RX_EOF_MODE (BIT(19)) 227 | #define SLC_RX_FILL_MODE (BIT(18)) 228 | #define SLC_INFOR_NO_REPLACE (BIT(17)) 229 | #define SLC_TOKEN_NO_REPLACE (BIT(16)) 230 | #define SLC_POP_IDLE_CNT 0x0000FFFF 231 | #endif 232 | #define SLC_POP_IDLE_CNT_S 0 233 | 234 | #define SLC_TXLINK_DSCR (REG_SLC_BASE + 0x60) 235 | #define SLC_TXLINK_DSCR_BF0 (REG_SLC_BASE + 0x64) 236 | #define SLC_TXLINK_DSCR_BF1 (REG_SLC_BASE + 0x68) 237 | #define SLC_RXLINK_DSCR (REG_SLC_BASE + 0x6C) 238 | #define SLC_RXLINK_DSCR_BF0 (REG_SLC_BASE + 0x70) 239 | #define SLC_RXLINK_DSCR_BF1 (REG_SLC_BASE + 0x74) 240 | #define SLC_DATE (REG_SLC_BASE + 0x78) 241 | #define SLC_ID (REG_SLC_BASE + 0x7C) 242 | 243 | #define SLC_HOST_CONF_W0 (REG_SLC_BASE + 0x80 + 0x14) 244 | #define SLC_HOST_CONF_W1 (REG_SLC_BASE + 0x80 + 0x18) 245 | #define SLC_HOST_CONF_W2 (REG_SLC_BASE + 0x80 + 0x20) 246 | #define SLC_HOST_CONF_W3 (REG_SLC_BASE + 0x80 + 0x24) 247 | #define SLC_HOST_CONF_W4 (REG_SLC_BASE + 0x80 + 0x28) 248 | 249 | #define SLC_HOST_INTR_ST (REG_SLC_BASE + 0x80 + 0x1c) 250 | #define SLC_HOST_INTR_CLR (REG_SLC_BASE + 0x80 + 0x30) 251 | #define SLC_HOST_INTR_SOF_BIT (BIT(12)) 252 | 253 | #define SLC_HOST_INTR_ENA (REG_SLC_BASE + 0x80 + 0x34) 254 | #define SLC_RX_NEW_PACKET_INT_ENA (BIT23) 255 | #define SLC_HOST_TOHOST_BIT0_INT_ENA (BIT0) 256 | #define SLC_HOST_CONF_W5 (REG_SLC_BASE + 0x80 + 0x3C) 257 | #define SLC_HOST_INTR_RAW (REG_SLC_BASE + 0x80 + 0x8) 258 | #define SLC_HOST_INTR_ENA_BIT (BIT(23)) 259 | //[15:12]: 0x3ff9xxxx -- 0b01 from_host 260 | // 0x3ffaxxxx -- 0b10 general 261 | // 0x3ffbxxxx -- 0b11 to_host 262 | #define SLC_DATA_ADDR_CLEAR_MASK (~(0xf<<12)) 263 | #define SLC_FROM_HOST_ADDR_MASK (0x1<<12) 264 | #define SLC_TO_HOST_ADDR_MASK (0x3<<12) 265 | 266 | #define SLC_SET_FROM_HOST_ADDR_MASK(v) do { \ 267 | (v) &= SLC_DATA_ADDR_CLEAR_MASK; \ 268 | (v) |= SLC_FROM_HOST_ADDR_MASK; \ 269 | } while(0); 270 | 271 | #define SLC_SET_TO_HOST_ADDR_MASK(v) do { \ 272 | (v) &= SLC_DATA_ADDR_CLEAR_MASK; \ 273 | (v) |= SLC_TO_HOST_ADDR_MASK; \ 274 | } while(0); 275 | 276 | 277 | #define SLC_TX_DESC_DEBUG_REG 0x3ff0002c //[15:0] set to 0xcccc 278 | 279 | 280 | #endif // SLC_REGISTER_H_INCLUDED 281 | 282 | -------------------------------------------------------------------------------- /user/generate_video.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2013-2015 Espressif Systems 3 | * 2015 <>< Charles Lohr 4 | * 2017 Hrvoje Cavrak 5 | */ 6 | 7 | #include "slc_register.h" 8 | #include 9 | #include "user_interface.h" 10 | #include "pin_mux_register.h" 11 | #include "signetics_video_rom.h" 12 | #include 13 | 14 | /* Change this to #define NTSC if you like */ 15 | #define PAL 16 | 17 | #ifdef PAL 18 | #define LINE_BUFFER_LENGTH 160 19 | #define VIDEO_LINES 625 20 | #define LINETYPES 6 21 | 22 | /* PAL signals */ 23 | #define SHORT_SYNC_INTERVAL 5 24 | #define LONG_SYNC_INTERVAL 75 25 | #define NORMAL_SYNC_INTERVAL 10 26 | #define LINE_SIGNAL_INTERVAL 150 27 | 28 | #define PIXEL_LINE_RESET_EVEN 55 29 | #define PIXEL_LINE_RESET_ODD 367 30 | 31 | #else 32 | 33 | #define LINE_BUFFER_LENGTH 159 34 | #define VIDEO_LINES 525 35 | #define LINETYPES 6 36 | 37 | /* NTSC signals */ 38 | #define SHORT_SYNC_INTERVAL 6 39 | #define LONG_SYNC_INTERVAL 73 40 | #define SERRATION_PULSE_INT 67 41 | #define NORMAL_SYNC_INTERVAL 12 42 | #define LINE_SIGNAL_INTERVAL 147 43 | 44 | #define PIXEL_LINE_RESET_EVEN 38 45 | #define PIXEL_LINE_RESET_ODD 299 46 | #endif 47 | 48 | 49 | #define SYNC_LEVEL 0x99999999 50 | #define WHITE_LEVEL 0xffffffff 51 | #define BLACK_LEVEL 0xbbbbbbbb 52 | 53 | #define WS_I2S_BCK 1 54 | #define WS_I2S_DIV 2 55 | 56 | extern uint8_t terminal_ram[40 * 24]; 57 | 58 | uint32_t i2s_dma_buffer[LINE_BUFFER_LENGTH*LINETYPES]; 59 | static struct sdio_queue i2sBufDesc[VIDEO_LINES]; 60 | 61 | int current_pixel_line; 62 | 63 | LOCAL void slc_isr(void) { 64 | struct sdio_queue *finishedDesc; 65 | uint32 slc_intr_status; 66 | uint8_t x; 67 | 68 | //Grab int status 69 | slc_intr_status = READ_PERI_REG(SLC_INT_STATUS); 70 | 71 | //clear all intr flags 72 | WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff); 73 | 74 | if (slc_intr_status & SLC_RX_EOF_INT_ST) { 75 | //The DMA subsystem is done with this block: Push it on the queue so it can be re-used. 76 | finishedDesc=(struct sdio_queue*)READ_PERI_REG(SLC_RX_EOF_DES_ADDR); 77 | 78 | struct sdio_queue * next = (struct sdio_queue *)finishedDesc->next_link_ptr; 79 | uint32_t * buffer_pointer = (uint32_t*)next->buf_ptr; 80 | 81 | if( next->unused > 1) 82 | { 83 | current_pixel_line = 0; 84 | } 85 | 86 | else if( next->unused ) 87 | { 88 | uint8_t pixel_column = 30; 89 | 90 | /* Determines which terminal line we are currently rendering, 192 pixel lines >> 3 = 24 text lines. Each is 40 bytes long. */ 91 | uint8_t *terminal_line = &terminal_ram[40 * (current_pixel_line >> 3)]; 92 | 93 | /* 8 banks (one for each char line) of 192 bytes contain character definitions. Each character is pre-encoded to optimize performance. */ 94 | uint32_t *character_row = &Signetics_2513_Modulated_Video_ROM[(current_pixel_line & 0b111) * 192]; 95 | 96 | /* For each character in the line */ 97 | for( x = 0; x < 40; x++ ) 98 | { 99 | 100 | /* Get pre-encoded character definition from array */ 101 | uint32_t *character = &character_row[3*(terminal_line[x] & 0x3F)]; 102 | 103 | /* Use loop unrolling to improve performance */ 104 | buffer_pointer[pixel_column++] = *character++; 105 | buffer_pointer[pixel_column++] = *character++; 106 | buffer_pointer[pixel_column++] = *character++; 107 | } 108 | 109 | current_pixel_line++; 110 | } 111 | } 112 | } 113 | 114 | #define SHORT_SYNC 0 115 | #define LONG_SYNC 1 116 | #define BLACK_SIGNAL 2 117 | #define SHORT_TO_LONG 3 118 | #define LONG_TO_SHORT 4 119 | #define LINE_SIGNAL 5 120 | 121 | //Initialize I2S subsystem for DMA circular buffer use 122 | void ICACHE_FLASH_ATTR testi2s_init() { 123 | int x, y; 124 | 125 | uint32_t * line = i2s_dma_buffer; 126 | 127 | 128 | #ifdef PAL 129 | /* PAL timings and definitions */ 130 | uint8_t single_line_timings[20] = { 131 | SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL, SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL, 132 | LONG_SYNC_INTERVAL, SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL, SHORT_SYNC_INTERVAL, 133 | NORMAL_SYNC_INTERVAL, LINE_SIGNAL_INTERVAL, 134 | SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL, SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL, 135 | LONG_SYNC_INTERVAL, SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL, SHORT_SYNC_INTERVAL, 136 | NORMAL_SYNC_INTERVAL, LINE_SIGNAL_INTERVAL 137 | }; 138 | 139 | /* Reference: http://martin.hinner.info/vga/pal_tv_diagram_interlace.jpg */ 140 | 141 | uint16_t video_lines[42] = { 142 | 3, LONG_SYNC, 0, 143 | 4, LONG_TO_SHORT, 0, 144 | 6, SHORT_SYNC, 0, 145 | 146 | 57, BLACK_SIGNAL, 0, 147 | 250, LINE_SIGNAL, 1, 148 | 311, BLACK_SIGNAL, 0, 149 | 150 | 313, SHORT_SYNC, 0, 151 | 314, SHORT_TO_LONG, 0, 152 | 316, LONG_SYNC, 0, 153 | 318, SHORT_SYNC, 0, 154 | 155 | 370, BLACK_SIGNAL, 0, 156 | 562, LINE_SIGNAL, 1, 157 | 623, BLACK_SIGNAL, 0, 158 | 159 | 626, SHORT_SYNC, 0, 160 | }; 161 | 162 | 163 | #else 164 | /* NTSC timings and definitions */ 165 | uint8_t single_line_timings[20] = { 166 | SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL, SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL + 1, 167 | SERRATION_PULSE_INT, NORMAL_SYNC_INTERVAL, SERRATION_PULSE_INT, NORMAL_SYNC_INTERVAL + 1, 168 | NORMAL_SYNC_INTERVAL, LINE_SIGNAL_INTERVAL, 169 | SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL, SERRATION_PULSE_INT, NORMAL_SYNC_INTERVAL + 1, 170 | SERRATION_PULSE_INT, NORMAL_SYNC_INTERVAL, SHORT_SYNC_INTERVAL, LONG_SYNC_INTERVAL + 1, 171 | NORMAL_SYNC_INTERVAL, LINE_SIGNAL_INTERVAL, 172 | }; 173 | 174 | /* Reference: http://www.avrfreaks.net/sites/default/files/ntsctime.pdf */ 175 | uint16_t video_lines[48] = { 176 | /* Even Field */ 177 | 178 | 3, SHORT_SYNC, 0, 179 | 6, LONG_SYNC, 0, 180 | 9, SHORT_SYNC, 0, 181 | 182 | 40, BLACK_SIGNAL, 0, 183 | 233, LINE_SIGNAL, 1, 184 | 263, BLACK_SIGNAL, 0, 185 | 186 | /* Odd Field */ 187 | 188 | 265, SHORT_SYNC, 0, 189 | 266, SHORT_TO_LONG, 0, 190 | 268, LONG_SYNC, 0, 191 | 269, LONG_TO_SHORT, 0, 192 | 271, SHORT_SYNC, 0, 193 | 194 | 302, BLACK_SIGNAL, 0, 195 | 495, LINE_SIGNAL, 1, 196 | 525, BLACK_SIGNAL, 0, 197 | }; 198 | 199 | #endif 200 | 201 | uint32_t single_line_levels[20] = { 202 | SYNC_LEVEL, BLACK_LEVEL, SYNC_LEVEL, BLACK_LEVEL, 203 | SYNC_LEVEL, BLACK_LEVEL, SYNC_LEVEL, BLACK_LEVEL, 204 | SYNC_LEVEL, BLACK_LEVEL, 205 | SYNC_LEVEL, BLACK_LEVEL, SYNC_LEVEL, BLACK_LEVEL, 206 | SYNC_LEVEL, BLACK_LEVEL, SYNC_LEVEL, BLACK_LEVEL, 207 | SYNC_LEVEL, BLACK_LEVEL, 208 | }; 209 | 210 | uint8_t i, signal; 211 | 212 | for (signal = 0; signal < 20; signal++) 213 | for (i=0; i < single_line_timings[signal]; i++, *line++ = single_line_levels[signal]) ; 214 | 215 | 216 | uint16_t *video_line = video_lines; 217 | 218 | //Initialize DMA buffer descriptors in such a way that they will form a circular 219 | //buffer. 220 | for (x=0; x 102 | #include 103 | 104 | //6502 defines 105 | // #define UNDOCUMENTED //when this is defined, undocumented opcodes are handled. 106 | //otherwise, they're simply treated as NOPs. 107 | 108 | // #define NES_CPU //when this is defined, the binary-coded decimal (BCD) 109 | //status flag is not honored by ADC and SBC. the 2A03 110 | //CPU in the Nintendo Entertainment System does not 111 | //support BCD operation. 112 | 113 | #define FLAG_CARRY 0x01 114 | #define FLAG_ZERO 0x02 115 | #define FLAG_INTERRUPT 0x04 116 | #define FLAG_DECIMAL 0x08 117 | #define FLAG_BREAK 0x10 118 | #define FLAG_CONSTANT 0x20 119 | #define FLAG_OVERFLOW 0x40 120 | #define FLAG_SIGN 0x80 121 | 122 | #define BASE_STACK 0x100 123 | 124 | #define saveaccum(n) a = (uint8_t)((n) & 0x00FF) 125 | 126 | 127 | //flag modifier macros 128 | #define setcarry() status |= FLAG_CARRY 129 | #define clearcarry() status &= (~FLAG_CARRY) 130 | #define setzero() status |= FLAG_ZERO 131 | #define clearzero() status &= (~FLAG_ZERO) 132 | #define setinterrupt() status |= FLAG_INTERRUPT 133 | #define clearinterrupt() status &= (~FLAG_INTERRUPT) 134 | #define setdecimal() status |= FLAG_DECIMAL 135 | #define cleardecimal() status &= (~FLAG_DECIMAL) 136 | #define setoverflow() status |= FLAG_OVERFLOW 137 | #define clearoverflow() status &= (~FLAG_OVERFLOW) 138 | #define setsign() status |= FLAG_SIGN 139 | #define clearsign() status &= (~FLAG_SIGN) 140 | 141 | 142 | //flag calculation macros 143 | #define zerocalc(n) {\ 144 | if ((n) & 0x00FF) clearzero();\ 145 | else setzero();\ 146 | } 147 | 148 | #define signcalc(n) {\ 149 | if ((n) & 0x0080) setsign();\ 150 | else clearsign();\ 151 | } 152 | 153 | #define carrycalc(n) {\ 154 | if ((n) & 0xFF00) setcarry();\ 155 | else clearcarry();\ 156 | } 157 | 158 | #define overflowcalc(n, m, o) { /* n = result, m = accumulator, o = memory */ \ 159 | if (((n) ^ (uint16_t)(m)) & ((n) ^ (o)) & 0x0080) setoverflow();\ 160 | else clearoverflow();\ 161 | } 162 | 163 | 164 | //6502 CPU registers 165 | uint16_t pc; 166 | uint8_t sp, a, x, y, status; 167 | 168 | 169 | //helper variables 170 | uint32_t clockticks6502 = 0, clockgoal6502 = 0; 171 | uint16_t oldpc, ea, reladdr, value, result; 172 | uint8_t opcode, oldstatus; 173 | 174 | //externally supplied functions 175 | extern uint8_t read6502(uint16_t address); 176 | extern void write6502(uint16_t address, uint8_t value); 177 | 178 | //a few general functions used by various other functions 179 | void push16(uint16_t pushval) { 180 | write6502(BASE_STACK + sp, (pushval >> 8) & 0xFF); 181 | write6502(BASE_STACK + ((sp - 1) & 0xFF), pushval & 0xFF); 182 | sp -= 2; 183 | } 184 | 185 | void push8(uint8_t pushval) { 186 | write6502(BASE_STACK + sp--, pushval); 187 | } 188 | 189 | uint16_t pull16() { 190 | uint16_t temp16; 191 | temp16 = read6502(BASE_STACK + ((sp + 1) & 0xFF)) | ((uint16_t)read6502(BASE_STACK + ((sp + 2) & 0xFF)) << 8); 192 | sp += 2; 193 | return(temp16); 194 | } 195 | 196 | uint8_t pull8() { 197 | return (read6502(BASE_STACK + ++sp)); 198 | } 199 | 200 | void reset6502() { 201 | // pc = ((uint16_t)read6502(0xfffc) | ((uint16_t)read6502(0xfffd) << 8)); 202 | pc = 0xff00; 203 | 204 | a = 0; 205 | x = 0; 206 | y = 0; 207 | sp = 0xFF; 208 | status |= FLAG_CONSTANT | FLAG_BREAK; 209 | } 210 | 211 | 212 | static void (*addrtable[256])(); 213 | static void (*optable[256])(); 214 | uint8_t penaltyop, penaltyaddr; 215 | 216 | //addressing mode functions, calculates effective addresses 217 | static void imp() { //implied 218 | } 219 | 220 | static void acc() { //accumulator 221 | } 222 | 223 | static void imm() { //immediate 224 | ea = pc++; 225 | } 226 | 227 | static void zp() { //zero-page 228 | ea = (uint16_t)read6502((uint16_t)pc++); 229 | } 230 | 231 | static void zpx() { //zero-page,X 232 | ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)x) & 0xFF; //zero-page wraparound 233 | } 234 | 235 | static void zpy() { //zero-page,Y 236 | ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)y) & 0xFF; //zero-page wraparound 237 | } 238 | 239 | static void rel() { //relative for branch ops (8-bit immediate value, sign-extended) 240 | reladdr = (uint16_t)read6502(pc++); 241 | if (reladdr & 0x80) reladdr |= 0xFF00; 242 | } 243 | 244 | static void abso() { //absolute 245 | ea = (uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8); 246 | pc += 2; 247 | } 248 | 249 | static void absx() { //absolute,X 250 | uint16_t startpage; 251 | ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8)); 252 | startpage = ea & 0xFF00; 253 | ea += (uint16_t)x; 254 | 255 | if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes 256 | penaltyaddr = 1; 257 | } 258 | 259 | pc += 2; 260 | } 261 | 262 | static void absy() { //absolute,Y 263 | uint16_t startpage; 264 | ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8)); 265 | startpage = ea & 0xFF00; 266 | ea += (uint16_t)y; 267 | 268 | if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes 269 | penaltyaddr = 1; 270 | } 271 | 272 | pc += 2; 273 | } 274 | 275 | static void ind() { //indirect 276 | uint16_t eahelp, eahelp2; 277 | eahelp = (uint16_t)read6502(pc) | (uint16_t)((uint16_t)read6502(pc+1) << 8); 278 | eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //replicate 6502 page-boundary wraparound bug 279 | ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8); 280 | pc += 2; 281 | } 282 | 283 | static void indx() { // (indirect,X) 284 | uint16_t eahelp; 285 | eahelp = (uint16_t)(((uint16_t)read6502(pc++) + (uint16_t)x) & 0xFF); //zero-page wraparound for table pointer 286 | ea = (uint16_t)read6502(eahelp & 0x00FF) | ((uint16_t)read6502((eahelp+1) & 0x00FF) << 8); 287 | } 288 | 289 | static void indy() { // (indirect),Y 290 | uint16_t eahelp, eahelp2, startpage; 291 | eahelp = (uint16_t)read6502(pc++); 292 | eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //zero-page wraparound 293 | ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8); 294 | startpage = ea & 0xFF00; 295 | ea += (uint16_t)y; 296 | 297 | if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes 298 | penaltyaddr = 1; 299 | } 300 | } 301 | 302 | static uint16_t getvalue() { 303 | if (addrtable[opcode] == acc) return((uint16_t)a); 304 | else return((uint16_t)read6502(ea)); 305 | } 306 | 307 | static uint16_t getvalue16() { 308 | return((uint16_t)read6502(ea) | ((uint16_t)read6502(ea+1) << 8)); 309 | } 310 | 311 | static void putvalue(uint16_t saveval) { 312 | if (addrtable[opcode] == acc) a = (uint8_t)(saveval & 0x00FF); 313 | else write6502(ea, (saveval & 0x00FF)); 314 | } 315 | 316 | 317 | //instruction handler functions 318 | static void adc() { 319 | penaltyop = 1; 320 | value = getvalue(); 321 | result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY); 322 | 323 | carrycalc(result); 324 | zerocalc(result); 325 | overflowcalc(result, a, value); 326 | signcalc(result); 327 | 328 | #ifndef NES_CPU 329 | if (status & FLAG_DECIMAL) { 330 | clearcarry(); 331 | 332 | if ((a & 0x0F) > 0x09) { 333 | a += 0x06; 334 | } 335 | if ((a & 0xF0) > 0x90) { 336 | a += 0x60; 337 | setcarry(); 338 | } 339 | 340 | clockticks6502++; 341 | } 342 | #endif 343 | 344 | saveaccum(result); 345 | } 346 | 347 | static void and() { 348 | penaltyop = 1; 349 | value = getvalue(); 350 | result = (uint16_t)a & value; 351 | 352 | zerocalc(result); 353 | signcalc(result); 354 | 355 | saveaccum(result); 356 | } 357 | 358 | static void asl() { 359 | value = getvalue(); 360 | result = value << 1; 361 | 362 | carrycalc(result); 363 | zerocalc(result); 364 | signcalc(result); 365 | 366 | putvalue(result); 367 | } 368 | 369 | static void bcc() { 370 | if ((status & FLAG_CARRY) == 0) { 371 | oldpc = pc; 372 | pc += reladdr; 373 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 374 | else clockticks6502++; 375 | } 376 | } 377 | 378 | static void bcs() { 379 | if ((status & FLAG_CARRY) == FLAG_CARRY) { 380 | oldpc = pc; 381 | pc += reladdr; 382 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 383 | else clockticks6502++; 384 | } 385 | } 386 | 387 | static void beq() { 388 | if ((status & FLAG_ZERO) == FLAG_ZERO) { 389 | oldpc = pc; 390 | pc += reladdr; 391 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 392 | else clockticks6502++; 393 | } 394 | } 395 | 396 | static void bit() { 397 | value = getvalue(); 398 | result = (uint16_t)a & value; 399 | 400 | zerocalc(result); 401 | status = (status & 0x3F) | (uint8_t)(value & 0xC0); 402 | } 403 | 404 | static void bmi() { 405 | if ((status & FLAG_SIGN) == FLAG_SIGN) { 406 | oldpc = pc; 407 | pc += reladdr; 408 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 409 | else clockticks6502++; 410 | } 411 | } 412 | 413 | static void bne() { 414 | if ((status & FLAG_ZERO) == 0) { 415 | oldpc = pc; 416 | pc += reladdr; 417 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 418 | else clockticks6502++; 419 | } 420 | } 421 | 422 | static void bpl() { 423 | if ((status & FLAG_SIGN) == 0) { 424 | oldpc = pc; 425 | pc += reladdr; 426 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 427 | else clockticks6502++; 428 | } 429 | } 430 | 431 | static void brk() { 432 | pc++; 433 | push16(pc); //push next instruction address onto stack 434 | push8(status | FLAG_BREAK); //push CPU status to stack 435 | setinterrupt(); //set interrupt flag 436 | pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8); 437 | } 438 | 439 | static void bvc() { 440 | if ((status & FLAG_OVERFLOW) == 0) { 441 | oldpc = pc; 442 | pc += reladdr; 443 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 444 | else clockticks6502++; 445 | } 446 | } 447 | 448 | static void bvs() { 449 | if ((status & FLAG_OVERFLOW) == FLAG_OVERFLOW) { 450 | oldpc = pc; 451 | pc += reladdr; 452 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 453 | else clockticks6502++; 454 | } 455 | } 456 | 457 | static void clc() { 458 | clearcarry(); 459 | } 460 | 461 | static void cld() { 462 | cleardecimal(); 463 | } 464 | 465 | static void cli() { 466 | clearinterrupt(); 467 | } 468 | 469 | static void clv() { 470 | clearoverflow(); 471 | } 472 | 473 | static void cmp() { 474 | penaltyop = 1; 475 | value = getvalue(); 476 | result = (uint16_t)a - value; 477 | 478 | if (a >= (uint8_t)(value & 0x00FF)) setcarry(); 479 | else clearcarry(); 480 | if (a == (uint8_t)(value & 0x00FF)) setzero(); 481 | else clearzero(); 482 | signcalc(result); 483 | } 484 | 485 | static void cpx() { 486 | value = getvalue(); 487 | result = (uint16_t)x - value; 488 | 489 | if (x >= (uint8_t)(value & 0x00FF)) setcarry(); 490 | else clearcarry(); 491 | if (x == (uint8_t)(value & 0x00FF)) setzero(); 492 | else clearzero(); 493 | signcalc(result); 494 | } 495 | 496 | static void cpy() { 497 | value = getvalue(); 498 | result = (uint16_t)y - value; 499 | 500 | if (y >= (uint8_t)(value & 0x00FF)) setcarry(); 501 | else clearcarry(); 502 | if (y == (uint8_t)(value & 0x00FF)) setzero(); 503 | else clearzero(); 504 | signcalc(result); 505 | } 506 | 507 | static void dec() { 508 | value = getvalue(); 509 | result = value - 1; 510 | 511 | zerocalc(result); 512 | signcalc(result); 513 | 514 | putvalue(result); 515 | } 516 | 517 | static void dex() { 518 | x--; 519 | 520 | zerocalc(x); 521 | signcalc(x); 522 | } 523 | 524 | static void dey() { 525 | y--; 526 | 527 | zerocalc(y); 528 | signcalc(y); 529 | } 530 | 531 | static void eor() { 532 | penaltyop = 1; 533 | value = getvalue(); 534 | result = (uint16_t)a ^ value; 535 | 536 | zerocalc(result); 537 | signcalc(result); 538 | 539 | saveaccum(result); 540 | } 541 | 542 | static void inc() { 543 | value = getvalue(); 544 | result = value + 1; 545 | 546 | zerocalc(result); 547 | signcalc(result); 548 | 549 | putvalue(result); 550 | } 551 | 552 | static void inx() { 553 | x++; 554 | 555 | zerocalc(x); 556 | signcalc(x); 557 | } 558 | 559 | static void iny() { 560 | y++; 561 | 562 | zerocalc(y); 563 | signcalc(y); 564 | } 565 | 566 | static void jmp() { 567 | pc = ea; 568 | } 569 | 570 | static void jsr() { 571 | push16(pc - 1); 572 | pc = ea; 573 | } 574 | 575 | static void lda() { 576 | penaltyop = 1; 577 | value = getvalue(); 578 | a = (uint8_t)(value & 0x00FF); 579 | 580 | zerocalc(a); 581 | signcalc(a); 582 | } 583 | 584 | static void ldx() { 585 | penaltyop = 1; 586 | value = getvalue(); 587 | x = (uint8_t)(value & 0x00FF); 588 | 589 | zerocalc(x); 590 | signcalc(x); 591 | } 592 | 593 | static void ldy() { 594 | penaltyop = 1; 595 | value = getvalue(); 596 | y = (uint8_t)(value & 0x00FF); 597 | 598 | zerocalc(y); 599 | signcalc(y); 600 | } 601 | 602 | static void lsr() { 603 | value = getvalue(); 604 | result = value >> 1; 605 | 606 | if (value & 1) setcarry(); 607 | else clearcarry(); 608 | zerocalc(result); 609 | signcalc(result); 610 | 611 | putvalue(result); 612 | } 613 | 614 | static void nop() { 615 | switch (opcode) { 616 | case 0x1C: 617 | case 0x3C: 618 | case 0x5C: 619 | case 0x7C: 620 | case 0xDC: 621 | case 0xFC: 622 | penaltyop = 1; 623 | break; 624 | } 625 | } 626 | 627 | static void ora() { 628 | penaltyop = 1; 629 | value = getvalue(); 630 | result = (uint16_t)a | value; 631 | 632 | zerocalc(result); 633 | signcalc(result); 634 | 635 | saveaccum(result); 636 | } 637 | 638 | static void pha() { 639 | push8(a); 640 | } 641 | 642 | static void php() { 643 | push8(status | FLAG_BREAK); 644 | } 645 | 646 | static void pla() { 647 | a = pull8(); 648 | 649 | zerocalc(a); 650 | signcalc(a); 651 | } 652 | 653 | static void plp() { 654 | status = pull8() | FLAG_CONSTANT; 655 | } 656 | 657 | static void rol() { 658 | value = getvalue(); 659 | result = (value << 1) | (status & FLAG_CARRY); 660 | 661 | carrycalc(result); 662 | zerocalc(result); 663 | signcalc(result); 664 | 665 | putvalue(result); 666 | } 667 | 668 | static void ror() { 669 | value = getvalue(); 670 | result = (value >> 1) | ((status & FLAG_CARRY) << 7); 671 | 672 | if (value & 1) setcarry(); 673 | else clearcarry(); 674 | zerocalc(result); 675 | signcalc(result); 676 | 677 | putvalue(result); 678 | } 679 | 680 | static void rti() { 681 | status = pull8(); 682 | value = pull16(); 683 | pc = value; 684 | } 685 | 686 | static void rts() { 687 | value = pull16(); 688 | pc = value + 1; 689 | } 690 | 691 | static void sbc() { 692 | penaltyop = 1; 693 | value = getvalue() ^ 0x00FF; 694 | result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY); 695 | 696 | carrycalc(result); 697 | zerocalc(result); 698 | overflowcalc(result, a, value); 699 | signcalc(result); 700 | 701 | #ifndef NES_CPU 702 | if (status & FLAG_DECIMAL) { 703 | clearcarry(); 704 | 705 | a -= 0x66; 706 | if ((a & 0x0F) > 0x09) { 707 | a += 0x06; 708 | } 709 | if ((a & 0xF0) > 0x90) { 710 | a += 0x60; 711 | setcarry(); 712 | } 713 | 714 | clockticks6502++; 715 | } 716 | #endif 717 | 718 | saveaccum(result); 719 | } 720 | 721 | static void sec() { 722 | setcarry(); 723 | } 724 | 725 | static void sed() { 726 | setdecimal(); 727 | } 728 | 729 | static void sei() { 730 | setinterrupt(); 731 | } 732 | 733 | static void sta() { 734 | putvalue(a); 735 | } 736 | 737 | static void stx() { 738 | putvalue(x); 739 | } 740 | 741 | static void sty() { 742 | putvalue(y); 743 | } 744 | 745 | static void tax() { 746 | x = a; 747 | 748 | zerocalc(x); 749 | signcalc(x); 750 | } 751 | 752 | static void tay() { 753 | y = a; 754 | 755 | zerocalc(y); 756 | signcalc(y); 757 | } 758 | 759 | static void tsx() { 760 | x = sp; 761 | 762 | zerocalc(x); 763 | signcalc(x); 764 | } 765 | 766 | static void txa() { 767 | a = x; 768 | 769 | zerocalc(a); 770 | signcalc(a); 771 | } 772 | 773 | static void txs() { 774 | sp = x; 775 | } 776 | 777 | static void tya() { 778 | a = y; 779 | 780 | zerocalc(a); 781 | signcalc(a); 782 | } 783 | 784 | //undocumented instructions 785 | #ifdef UNDOCUMENTED 786 | static void lax() { 787 | lda(); 788 | ldx(); 789 | } 790 | 791 | static void sax() { 792 | sta(); 793 | stx(); 794 | putvalue(a & x); 795 | if (penaltyop && penaltyaddr) clockticks6502--; 796 | } 797 | 798 | static void dcp() { 799 | dec(); 800 | cmp(); 801 | if (penaltyop && penaltyaddr) clockticks6502--; 802 | } 803 | 804 | static void isb() { 805 | inc(); 806 | sbc(); 807 | if (penaltyop && penaltyaddr) clockticks6502--; 808 | } 809 | 810 | static void slo() { 811 | asl(); 812 | ora(); 813 | if (penaltyop && penaltyaddr) clockticks6502--; 814 | } 815 | 816 | static void rla() { 817 | rol(); 818 | and(); 819 | if (penaltyop && penaltyaddr) clockticks6502--; 820 | } 821 | 822 | static void sre() { 823 | lsr(); 824 | eor(); 825 | if (penaltyop && penaltyaddr) clockticks6502--; 826 | } 827 | 828 | static void rra() { 829 | ror(); 830 | adc(); 831 | if (penaltyop && penaltyaddr) clockticks6502--; 832 | } 833 | #else 834 | #define lax nop 835 | #define sax nop 836 | #define dcp nop 837 | #define isb nop 838 | #define slo nop 839 | #define rla nop 840 | #define sre nop 841 | #define rra nop 842 | #endif 843 | 844 | 845 | static void (*addrtable[256])() = { 846 | /* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */ 847 | /* 0 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 0 */ 848 | /* 1 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 1 */ 849 | /* 2 */ abso, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 2 */ 850 | /* 3 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 3 */ 851 | /* 4 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 4 */ 852 | /* 5 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 5 */ 853 | /* 6 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, ind, abso, abso, abso, /* 6 */ 854 | /* 7 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 7 */ 855 | /* 8 */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* 8 */ 856 | /* 9 */ rel, indy, imp, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, /* 9 */ 857 | /* A */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* A */ 858 | /* B */ rel, indy, imp, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, /* B */ 859 | /* C */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* C */ 860 | /* D */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* D */ 861 | /* E */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* E */ 862 | /* F */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx /* F */ 863 | }; 864 | 865 | static void (*optable[256])() = { 866 | /* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */ 867 | /* 0 */ brk, ora, nop, slo, nop, ora, asl, slo, php, ora, asl, nop, nop, ora, asl, slo, /* 0 */ 868 | /* 1 */ bpl, ora, nop, slo, nop, ora, asl, slo, clc, ora, nop, slo, nop, ora, asl, slo, /* 1 */ 869 | /* 2 */ jsr, and, nop, rla, bit, and, rol, rla, plp, and, rol, nop, bit, and, rol, rla, /* 2 */ 870 | /* 3 */ bmi, and, nop, rla, nop, and, rol, rla, sec, and, nop, rla, nop, and, rol, rla, /* 3 */ 871 | /* 4 */ rti, eor, nop, sre, nop, eor, lsr, sre, pha, eor, lsr, nop, jmp, eor, lsr, sre, /* 4 */ 872 | /* 5 */ bvc, eor, nop, sre, nop, eor, lsr, sre, cli, eor, nop, sre, nop, eor, lsr, sre, /* 5 */ 873 | /* 6 */ rts, adc, nop, rra, nop, adc, ror, rra, pla, adc, ror, nop, jmp, adc, ror, rra, /* 6 */ 874 | /* 7 */ bvs, adc, nop, rra, nop, adc, ror, rra, sei, adc, nop, rra, nop, adc, ror, rra, /* 7 */ 875 | /* 8 */ nop, sta, nop, sax, sty, sta, stx, sax, dey, nop, txa, nop, sty, sta, stx, sax, /* 8 */ 876 | /* 9 */ bcc, sta, nop, nop, sty, sta, stx, sax, tya, sta, txs, nop, nop, sta, nop, nop, /* 9 */ 877 | /* A */ ldy, lda, ldx, lax, ldy, lda, ldx, lax, tay, lda, tax, nop, ldy, lda, ldx, lax, /* A */ 878 | /* B */ bcs, lda, nop, lax, ldy, lda, ldx, lax, clv, lda, tsx, lax, ldy, lda, ldx, lax, /* B */ 879 | /* C */ cpy, cmp, nop, dcp, cpy, cmp, dec, dcp, iny, cmp, dex, nop, cpy, cmp, dec, dcp, /* C */ 880 | /* D */ bne, cmp, nop, dcp, nop, cmp, dec, dcp, cld, cmp, nop, dcp, nop, cmp, dec, dcp, /* D */ 881 | /* E */ cpx, sbc, nop, isb, cpx, sbc, inc, isb, inx, sbc, nop, sbc, cpx, sbc, inc, isb, /* E */ 882 | /* F */ beq, sbc, nop, isb, nop, sbc, inc, isb, sed, sbc, nop, isb, nop, sbc, inc, isb /* F */ 883 | }; 884 | 885 | static const uint8_t ticktable[256] = { 886 | /* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */ 887 | /* 0 */ 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0 */ 888 | /* 1 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1 */ 889 | /* 2 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2 */ 890 | /* 3 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3 */ 891 | /* 4 */ 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4 */ 892 | /* 5 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5 */ 893 | /* 6 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6 */ 894 | /* 7 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7 */ 895 | /* 8 */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8 */ 896 | /* 9 */ 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9 */ 897 | /* A */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* A */ 898 | /* B */ 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* B */ 899 | /* C */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* C */ 900 | /* D */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* D */ 901 | /* E */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* E */ 902 | /* F */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* F */ 903 | }; 904 | 905 | 906 | void nmi6502() { 907 | push16(pc); 908 | push8(status); 909 | status |= FLAG_INTERRUPT; 910 | pc = (uint16_t)read6502(0xFFFA) | ((uint16_t)read6502(0xFFFB) << 8); 911 | } 912 | 913 | uint16_t getPC() { 914 | return pc; 915 | } 916 | 917 | void irq6502() { 918 | push16(pc); 919 | push8(status); 920 | status |= FLAG_INTERRUPT; 921 | pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8); 922 | } 923 | 924 | uint8_t callexternal = 0; 925 | void (*loopexternal)(); 926 | 927 | void exec6502(uint32_t tickcount) { 928 | clockgoal6502 += tickcount; 929 | 930 | while (clockticks6502 < clockgoal6502) { 931 | opcode = read6502(pc++); 932 | status |= FLAG_CONSTANT; 933 | 934 | penaltyop = 0; 935 | penaltyaddr = 0; 936 | 937 | (*addrtable[opcode])(); 938 | (*optable[opcode])(); 939 | clockticks6502 += ticktable[opcode]; 940 | if (penaltyop && penaltyaddr) clockticks6502++; 941 | } 942 | 943 | } 944 | 945 | void step6502() { 946 | opcode = read6502(pc++); 947 | status |= FLAG_CONSTANT; 948 | 949 | penaltyop = 0; 950 | penaltyaddr = 0; 951 | 952 | (*addrtable[opcode])(); 953 | (*optable[opcode])(); 954 | clockticks6502 += ticktable[opcode]; 955 | if (penaltyop && penaltyaddr) clockticks6502++; 956 | clockgoal6502 = clockticks6502; 957 | } 958 | 959 | --------------------------------------------------------------------------------