diff --git a/README.md b/README.md index d372f1f..cee3fa0 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ Read on for more information. The [Applications Tested](#applications-tested) se + If the emulator is started with no SD Card, or with an empty SD Card, then it will emulate a 16K ZX81 + To switch to always starting emulating a ZX80, a populated SD Card is required. If it is present, the machine that is emulated is specified by the `config.ini` file in the root directory, see [configuring the emulator](#configuring-the-emulator) + If the contents of the [examples](examples) directory have been copied to the SD Card, then the included programs can be loaded. Press `F2` to see files in the current directory that can be loaded -+ To make picozx81 emulate a an original 4K ZX80, without changing `config.ini`, either a ZX80 program can be loaded, or the computer type `ZX80-4K` can be selected from the Modify menu. Press F6 to bring up the Modify menu. To emaulate a ZX80 upgraded with a 8K ROM , select `ZX80-8K` from the modify menu ++ To make picozx81 emulate a an original 4K ZX80, without changing `config.ini`, either a ZX80 program can be loaded, or the computer type `ZX80-4K` can be selected from the Modify menu. Press F6 to bring up the Modify menu. To emulate a ZX80 upgraded with a 8K ROM , select `ZX80-8K` from the modify menu + The current settings used by the emulator can be viewed by pressing `F3` + The following sections describe how to configure the emulator and provide links to programs that can be downloaded, copied to the SD Card and then run using the emulator @@ -186,7 +186,7 @@ The following can be configured: | FrameSync | Synchronises screen updates to the start of the display frame. Option to synchronise frame pairs for programs that display interlaced images| Off |`On` reduces "tearing" in programs with horizontal scrolling, at the expense of a possible small lag. `Interlaced` reduces flickering in programs that display interlaced images| | CHR128 | Enables emulation of a 128 character user defined graphics board (CHR$128) in Low memory. | Off|When enabled LowRAM is forced to On, WRX and QSUDG are forced to off| | QSUDG | Enables emulation of the QS user defined graphics board| Off |Memory automatically limited to 16 when selected | -| Sound | Selects sound card (if any) | Off | Valid options are `QUICKSILVA`, `ZONX`, `TV`, `CHROMA` and `OFF` | +| Sound | Selects sound card type (if any) | None | Valid options are `QUICKSILVA`, `ZONX`, `TV`, `CHROMA` and `NONE` or `OFF`| | ACB | Enables ACB stereo if sound card enabled | Off | | | NTSC | Enables emulation of NTSC (60Hz display refresh)| Off | As for the "real" ZX81, SLOW mode is slower when NTSC is selected| | VTOL | Specifies the tolerance in lines of the emulated TV display detecting vertical sync| 25 | See notes below| @@ -237,7 +237,7 @@ Examples of the `config.ini` files used to test the programs listed in this [sec ### Editing `config.ini` The `config.ini` file *cannot* be edited within the emulator. Modify the `config.ini` file using another computer. -After replacing the SD Card into the emulator, the pico *must* be restarted, either via a Power cycle, or by pressing the run / reset button on the board, before any edits will be visible to the emulator +After replacing the SD Card into the emulator, the Pico *must* be restarted, either via a Power cycle, or by pressing the run / reset button on the board, before any edits will be visible to the emulator ### Need for reset of emulated machine The emulated machine is always reset if any of the following options are changed: @@ -254,7 +254,7 @@ The original ZX80/ZX81 40 key keyboard does not have function keys. A "double sh 2. Shift is released, without another key being pressed 3. Within one second shift is pressed again 4. Shift is released, without another key being pressed -5. To generate a function key, within one second, a numeric key in the range `1` to `5` is pressed without shift being pressed. If `0` is pressed `Escape` is generated +5. To generate a function key, within one second, a numeric key in the range `1` to `8` is pressed without shift being pressed. If `0` is pressed `Escape` is generated This mechanism is enabled by default. To disable it set `DoubleShift` to `Off` in the configuration file ### F1 - Reset @@ -363,7 +363,7 @@ The original ZX81 used tape as a storage media, with no concept of a directory s ### Using the ROM routines The `LoadUsingROM` and `SaveUsingROM` configuration options allow the ROM code to be executed. This emulates the loading and saving of program files (but not data blocks) in the same time that it would take on a real ZX80/ZX81 -PicoZX81 generates realistic load and save sounds and graphics for the 8K ROM. The 4K ROM generates sounds and graphics when saving, which PicoZX81 emulates. The 4K ROM does not generate a load screen. PicoZX81 will show a black screen when the 4K ROM is loading a program +Picozx81 generates realistic load and save sounds and graphics for the 8K ROM. The 4K ROM generates sounds and graphics when saving, which picozx81 emulates. The 4K ROM does not generate a load screen. Picozx81 will show a black screen when the 4K ROM is loading a program The save sounds generated for both the 4K and 8K ROMs have been recorded as wav files and then successfully loaded into the EightyOne emulator @@ -505,6 +505,8 @@ To enable chroma support set LowRAM on, and Memory to 48kB + [rezurrection](https://bodo4all.fortunecity.ws/zx/rezurrection.html) + With default settings, the logo on the final screen "flashes" after the scrolling is complete. This is because the logo is displayed interlaced, at roughly 52Hz. Set `FrameSync` to `Interlaced` to display the final screen correctly without flashes. A frame rate adjusted version of the final Rezurrection screen exists in the [Demos](examples/ZX81/Demos) example directory: [head.p](examples/ZX81/Demos/heap.p) and [config.ini](examples/ZX81/Demos/config.ini). When run with `FiveSevenSix` and `FrameSync` set to `on` or `interlaced` a stable interlaced image can be seen after the scrolling is complete ++ [ZX80 Kong](http://www.fruitcake.plus.com/Sinclair/ZX80/Chroma/ZX80_ChromaInterface_Software_ColourisationDefinitions.htm) and [ZX80 Pacman](http://www.fruitcake.plus.com/Sinclair/ZX80/Chroma/ZX80_ChromaInterface_Software_ColourisationDefinitions.htm) + + The Chroma 80 4K ROM versions use a loader program to set the colour data and then load the main program. The loader available in the supplied links uses a custom tape load routine that is not detected by picozx81. To create a compatible loader that uses that standard 4K ROM load routine use the [Chroma Program Enhancement Creator](http://www.fruitcake.plus.com/Sinclair/ZX81/Chroma/ChromaInterface_Software_ChromaProgramEnhancementCreator.htm). As the 4K ROM `LOAD` command does not take an argument, picozx81 will display the contents of the current directory when the loader program is run. Select the main program from the directory list and it will load and run, using the colour data loaded earlier # Building **Notes:** + Prebuilt executable files for the 7 supported board types can be found [here](uf2/) @@ -550,7 +552,7 @@ This will be named `picozx81_vga.uf2` **Notes:** + The [`buildall`](buildall) script in the root directory of `picozx81` will build `uf2` files for all supported board types -6. Upload the `uf2` file to the pico +6. Upload the `uf2` file to the Pico 7. Populate a micro SD Card with files you wish to run. Optionally add `config.ini` files to the SD Card. See [here](examples) for examples of config files # Extra Information @@ -558,7 +560,7 @@ This will be named `picozx81_vga.uf2` + The original intention of the emulator was to provide an authentic '80s feel. It emulated the hardware that was advertised in the early '80s i.e. QS UDG, Sound, joystick, hi-res mono graphics. It has now been extended to provide emulation of some of the amazing ZX81 developments of recent years, such as [Chroma 81](http://www.fruitcake.plus.com/Sinclair/ZX81/Chroma/ChromaInterface.htm). It supports the loading and saving of memory blocks, using a syntax similar to ZXpand + The ["Big Bang"](https://www.sinclairzxworld.com/viewtopic.php?t=2986) ROM is supported, as this accelerates BASIC execution, and runs on the original ZX81 hardware + Program debug support is limited to that provided by the ZX81 "in period", i.e. non-existent. It is recommended that one of the PC or Linux based ZX81 emulators with single step and breakpoint support are used to debug Z80 assembly programs -+ To achieve a full speed emulation the Pico is overclocked to 250MHz (640x480) and 270MHz (720x576). There is a very slight risk that this may damage the Pico. However many other applications run the Pico at this frequency. By default the stock voltage is used (1.1V), this has been successfully tested on multiple Picos. If the emulator appears unstable it can be built to use 1.2V, add `-DOVER_CLOCK` to the cmake command ++ To achieve a full speed emulation the Pico is overclocked to 252MHz (640x480) and 270MHz (720x576). There is a very slight risk that this may damage the Pico. However many other applications run the Pico at this frequency. By default the stock voltage is used (1.1V), this has been successfully tested on multiple Picos. If the emulator appears unstable it can be built to use 1.2V, add `-DOVER_CLOCK` to the cmake command + The Pico only has 1 USB port. The Pimoroni, Olimex and Waveshare PiZero boards can be powered through a second on board USB power connector, allowing a keyboard to be connected to the Pico using an OTG adaptor + To connect more than one peripheral (e.g. a keyboard and joystick) at the same time, a powered USB OTG hub is required. These 3 hubs have been successfully tested. [1](https://www.amazon.co.uk/dp/B083WML1XB), [2](https://www.amazon.co.uk/dp/B078M3Z84Z), [3](https://www.amazon.co.uk/dp/B07Z4RHJ2D). Plug the hub directly into the USB port on the Pico. The USB-A connector on the PICOZX boards can also be used **Note:** Testing has shown that all of these hubs can support OTG and power delivery to the Pico simultaneously @@ -569,7 +571,7 @@ This will be named `picozx81_vga.uf2` + The board can be back powered by some TVs. This can cause the board to not start correctly. If this happens either connect the power before attaching the HDMI cable, or press the reset button on the board ### PicoMiteVGA + The PicoMiteVGA board has a PS/2 keyboard socket. Currently this is not supported, a USB keyboard must be used -+ PicomiteVGA only supports 1 level of Red and Blue, so it cannot display the full range of colours that Chroma can generate ++ PicoMiteVGA only supports 1 level of Red and Blue, so it cannot display the full range of colours that Chroma can generate + Some versions of the PicoMiteVGA board have a jumper to select between RGB and GRN mode. Select RGB mode ### PICOZX + PICOZX has a bank of 4 extra keys below the SD Card. These act as function keys. `Menu` maps to `F1`, `Reload` to `F2` etc. If shift is pressed 4 is added to the function number. e.g. `shift` + `Menu` gives `F5` (and so displays the keyboard) @@ -577,7 +579,7 @@ This will be named `picozx81_vga.uf2` + The PICOZX + LCD shares outputs with VGA. If the board is configured for VGA output, the intensity of the backlight of the LCD will vary with the contents of the VGA display + The PICOZX for the ZX-Spectrum case has two extra buttons on the back (in addition to a reset button). Without shift these two buttons will generate `F2` and `F5`. With shift they will generate `F3` and `F6` + Use the double shift mechanism to access all menus when using the PICOZX family -+ To enter BOOTSEL mode on the PICOZX for the ZX-Spectrum press and hold the `R` key then press the `F2` menu key. This allows new firmware to be loaded without needing to press the BOOTSEL key on the pico ++ To enter BOOTSEL mode on the PICOZX for the ZX-Spectrum press and hold the `R` key then press the `F2` menu key. This allows new firmware to be loaded without needing to press the BOOTSEL key on the Pico ### Waveshare Pico-ResTouch-LCD-2.8 + The Waveshare Pico-ResTouch-LCD-2.8 board has a touch controller, but the emulator does not support its use ### Olimex RP2040-PICO-PC @@ -621,7 +623,7 @@ All options are set in the `[default]` section of the `config.ini` file in the r e.g. to set `LCDReflect` to true, add the following to the `[default]` section of the configuration file: `LCDReflect = True` **Notes:** - 1. If the configuration appears correct for a display, but no image appears, or the image is not stable, it could be that the display cannot support the SPI bus speed required to display every frame, or that cross talk is occuring between the wires connecting the display. In this case set `LCDFrameSkip = True` + 1. If the configuration appears correct for a display, but no image appears, or the image is not stable, it could be that the display cannot support the SPI bus speed required to display every frame, or that cross talk is occurring between the wires connecting the display. In this case set `LCDFrameSkip = True` 2. It is recommended to use the Cytron maker board with the Pico pre-soldered, as this version can support higher bus speeds. If the version with a socket for a Pico is used, then the LCD display may not function correctly unless `LCDFrameSkip` is set to `True` 3. If `LCDFrameSkip` equals `True`, then if `FrameSync` is set to `Interlaced` it will be interpreted as `On` @@ -675,7 +677,7 @@ One intention of this project was to show what can be quickly achieved by levera Thanks to [Paul Farrow](http://www.fruitcake.plus.com/) for information on the Chroma expansion boards and the `.p81` file format ## Use with an original ZX80/ZX81 keyboard -There are not enough unused GPIO pins on the Pimoroni demo boards to allow the direct connection of a ZX80/81 keyboard, but it can be done by using another Pico to convert the ZX80/81 keyboard into a USB keyboard. It may seem excessive to use a whole pico as a keyboard controller, but they are cheap and there is enough space to put the Pimoroni board, plus another Pico, plus a small USB hub into a ZX80 or ZX81 case +There are not enough unused GPIO pins on the Pimoroni demo boards to allow the direct connection of a ZX80/81 keyboard, but it can be done by using another Pico to convert the ZX80/81 keyboard into a USB keyboard. It may seem excessive to use a whole Pico as a keyboard controller, but they are cheap and there is enough space to put the Pimoroni board, plus another Pico, plus a small USB hub into a ZX80 or ZX81 case Code to convert a ZX8x keyboard to USB can be found at [ZX81_USB_KBD](https://github.com/ikjordan/ZX81_USB_KBD). This code has been used to successfully connect a ZX81 keyboard to this emulator. If the keyboard is the only peripheral, then it can be plugged straight into the USB port of the Pico on the emulator board with the power connected to the USB power socket of the Pimoroni board. If other USB peripherals (such as another keyboard, or a USB joystick) also need to be connected then the ZX80/81 keyboard can be connected via a USB hub @@ -686,7 +688,9 @@ The picozx board does support keyboard and joystick. This is achieved by using e ## Performance and constraints In an ideal world the latest versions of the excellent sz81 or EightyOne emulators would have been ported. An initial port showed that they are too processor intensive for an (overclocked) ARM M0+. An earlier version of sz81 ([2.1.8](https://github.com/ikjordan/sz81_2_1_8)) was used as a basis, with some Z80 timing corrections and back porting of the 207 tstate counter code from the latest sz81 (2.3.12). See [here](#applications-tested) for a list of applications tested -The initial port from sz81 2.3.12 onto the Pico ran at approximately 10% of real time speed. Use of the Z80 emulator originally written for xz80 by Ian Collier, plus optimisation of the ZX81 memory access, display and plot routines allows the emulator to run at 100% of real time speed. The display of a full 320 by 240 image in real time (e.g. [Maxhrg](https://bodo4all.fortunecity.ws/zx/maxdemo.html)) uses approximately 92% of the available CPU clock cycles with sound disabled and 96% with Zonx sound enabled when picozx81 is running with a 640x460 display +The initial port from sz81 2.3.12 onto the Pico ran at approximately 10% of real time speed. Use of the Z80 emulator originally written for xz80 by Ian Collier, plus optimisation of the ZX81 memory access, display and plot routines allows the emulator to run at 100% of real time speed. The display of a full 320 by 240 image in real time (e.g. [Maxhrg](https://bodo4all.fortunecity.ws/zx/maxdemo.html)) uses approximately 83% of the available CPU clock cycles with sound disabled and 87% with Zonx sound enabled when picozx81 is running with a 640x460 display and ZX81 hardware emulation + +ZX80 hardware emulation takes more CPU. Emulating an idle ZX80 with Zonx sound enabled takes approximately 94% of a 252 MHz Pico. Due to the nature of the ZX80 hardware display emulation, the CPU load drops, both in B&W and Chroma, when a ZX80 program is running The 640x480 display mode uses an overclock to 252MHz. The 720x576 display mode uses an overclock to 270MHz diff --git a/buildall b/buildall index 781fe37..8b60534 100755 --- a/buildall +++ b/buildall @@ -6,7 +6,7 @@ build_uf2() board=$1"board .." uf2="picozx81_"$1".uf2" - cmake -DHDMI_SOUND=OFF -DCMAKE_BUILD_TYPE=Release -DTIME_SPARE=OFF -DPICO_BOARD=${board} + cmake -DHDMI_SOUND=OFF -DPICOZX_LCD=OFF -DCMAKE_BUILD_TYPE=Release -DTIME_SPARE=OFF -DPICO_BOARD=${board} make -j4 cp ./${uf2} ../uf2/${uf2} } @@ -16,7 +16,7 @@ build_uf2_hdmi() board=$1"board .." uf2="picozx81_"$1"_hdmi_sound.uf2" - cmake -DHDMI_SOUND=ON -DCMAKE_BUILD_TYPE=Release -DTIME_SPARE=OFF -DPICO_BOARD=${board} + cmake -DHDMI_SOUND=ON -DPICOZX_LCD=OFF -DCMAKE_BUILD_TYPE=Release -DTIME_SPARE=OFF -DPICO_BOARD=${board} make -j4 cp ./${uf2} ../uf2/${uf2} } @@ -26,7 +26,7 @@ build_uf2_lcd() board=$1"board .." uf2="picozx81_"$1"_lcd.uf2" - cmake -DPICOZX_LCD=ON -DCMAKE_BUILD_TYPE=Release -DTIME_SPARE=OFF -DPICO_BOARD=${board} + cmake -DHDMI_SOUND=OFF -DPICOZX_LCD=ON -DCMAKE_BUILD_TYPE=Release -DTIME_SPARE=OFF -DPICO_BOARD=${board} make -j4 cp ./${uf2} ../uf2/${uf2} } diff --git a/src/common.h b/src/common.h index 15da824..b92fce5 100644 --- a/src/common.h +++ b/src/common.h @@ -48,7 +48,8 @@ extern unsigned char mem[MEMORYRAM_SIZE]; extern unsigned char *memptr[64]; extern int memattr[64]; extern int sound_type; -extern unsigned long tstates,tsmax; +extern unsigned long tstates; +extern const unsigned long tsmax; extern int ramsize; extern int autoload; extern int zx80; @@ -77,7 +78,7 @@ extern "C" { #endif extern unsigned int in(int h, int l); -extern unsigned int out(int h, int l, int a); +extern void out(int h, int l, int a); extern bool save_p(int name_addr, bool defer_rom); extern bool load_p(int name_addr, bool defer_rom); diff --git a/src/edops.h b/src/edops.h index 72f2baf..ebe157c 100644 --- a/src/edops.h +++ b/src/edops.h @@ -54,7 +54,7 @@ instr(0x40,8); endinstr; instr(0x41,8); - tstates+=out(b,c,b); + out(b,c,b); endinstr; instr(0x42,11); @@ -90,7 +90,7 @@ instr(0x48,8); endinstr; instr(0x49,8); - tstates+=out(b,c,c); + out(b,c,c); endinstr; instr(0x4a,11); @@ -127,7 +127,7 @@ instr(0x50,8); endinstr; instr(0x51,8); - tstates+=out(b,c,d); + out(b,c,d); endinstr; instr(0x52,11); @@ -163,7 +163,7 @@ instr(0x58,8); endinstr; instr(0x59,8); - tstates+=out(b,c,e); + out(b,c,e); endinstr; instr(0x5a,11); @@ -201,7 +201,7 @@ instr(0x60,8); endinstr; instr(0x61,8); - tstates+=out(b,c,h); + out(b,c,h); endinstr; instr(0x62,11); @@ -241,7 +241,7 @@ instr(0x68,8); endinstr; instr(0x69,8); - tstates+=out(b,c,l); + out(b,c,l); endinstr; instr(0x6a,11); @@ -282,7 +282,7 @@ instr(0x70,8); endinstr; instr(0x71,8); - tstates+=out(b,c,0); + out(b,c,0); endinstr; instr(0x72,11); @@ -313,7 +313,7 @@ instr(0x78,8); endinstr; instr(0x79,8); - tstates+=out(b,c,a); + out(b,c,a); endinstr; instr(0x7a,11); @@ -373,7 +373,7 @@ instr(0xa3,12); /* I can't determine the correct flags outcome for the flag is left unchanged and N is set to 1, but that doesn't seem to be the case... */ {unsigned char x=fetch(hl); - tstates+=out(b,c,x); + out(b,c,x); if(!++l)h++; b--; f=(f&1)|0x12|(b&0xa8)|((b==0)<<6); @@ -411,7 +411,7 @@ endinstr; instr(0xab,12); {unsigned char x=fetch(hl); - tstates+=out(b,c,x); + out(b,c,x); if(!l--)h--; b--; f=(f&1)|0x12|(b&0xa8)|((b==0)<<6); @@ -455,7 +455,7 @@ endinstr; instr(0xb3,12); {unsigned char x=fetch(hl); - tstates+=out(b,c,x); + out(b,c,x); if(!++l)h++; b--; f=(f&1)|0x12|(b&0xa8)|((b==0)<<6); @@ -497,7 +497,7 @@ endinstr; instr(0xbb,12); {unsigned char x=fetch(hl); - tstates+=out(b,c,x); + out(b,c,x); if(!l--)h--; b--; f=(f&1)|0x12|(b&0xa8)|((b==0)<<6); diff --git a/src/emuapi.cpp b/src/emuapi.cpp index 2a765ff..92a1237 100755 --- a/src/emuapi.cpp +++ b/src/emuapi.cpp @@ -1235,8 +1235,8 @@ void emu_WaitFor50HzTimer(void) int32_t sound = sound_count + sound_prev; sound_prev = -sound_count; - printf("Spare ms in 10sec: %lld Under: %lu\n", total_time / 1000, underrun); - printf("int: %lld sound: %ld\n", ints, sound); + printf("ms spare: %lld U: %lu\n", total_time / 1000, underrun); + printf("I: %lld S: %ld\n", ints, sound); total_time = 0; underrun = 0; } diff --git a/src/loadp.c b/src/loadp.c index 93bde9a..8d32a16 100644 --- a/src/loadp.c +++ b/src/loadp.c @@ -44,7 +44,7 @@ static BitState_t bit_state = ZERO_BIT; static PulseState_t pulse_state = SILENCE_PULSE; static uint32_t pulse_length_max = LOADP_SILENCE_INTRO_LENGTH; -static uint pulse_count = 0; +static uint32_t pulse_count = 0; static char byte_to_send = 0; static void moveToNextByte(void); @@ -250,7 +250,7 @@ EMU_LOCK_SDCARD { ret = getNextByte(&read_buffer); } while (ret && ((read_buffer & 0x80) == 0)); - + EMU_UNLOCK_SDCARD return ret; } diff --git a/src/todo.txt b/src/todo.txt deleted file mode 100644 index 8f8a56c..0000000 --- a/src/todo.txt +++ /dev/null @@ -1,38 +0,0 @@ -TO DO: -1. Move to Pimoroni SD driver - by default should have right pins, use stand alone test? DONE -2. Parse ini file to set joystick. Write test program to parse ini file for 332, then maker, then vga using Pimoroni SD driver DONE - maker TO DO -3. Integrate into picozx81 DONE -4. check in pico ZX81 - remove sound at that point DONE -5. Take pictures DONE -6. Try to move to vga demo - disable UART DONE -7. Move to Maker TO DO -8. Try out sound (e.g. for C64) DONE -9. Make 222 ladder -10. Wire second VGA cable -11. Test audio and vga 222 on maker -12. Start to develop drivers for real keyboard and joystick on ZXPICO -13. Investigate port of sz81 common DONE - 12 times too slow :-( -14. Use DMA rather than 31.25kHz interrupt 32k interrupt better than DMA, as vgaboard has audio over two slices DONE -15. Time remaining CPU when running QS Defenda with sound over 15% at 200MHz - DONE ok -16. Look at high res issues in Celebration - Hack / workaround to avoid losing tstates each line - DONE -17. Dual mono for 2 speakers - DONE - ACB stereo also done -18. Write read me DONE -19. Port sz81 sound DONE -20. Build menu system DONE -21. Make FatFS a sub-module Not DONE as there is no definitive github store -22. Better solution for extern C DONE -23. QS UDG DONE -24. Configure WRX SRAM and UDG explicitly. DONE - LowRAM defines RAM in 8k to 16K. - WRX Means RAM can be used for graphics - always true if 2k or less RAM - UDG Enables QS character board. Memory then limited to max of 16kB as board mapped at 0x8400. Enable UDG automatically, if selected, after first - write to 0x8400 - 0x87FF -25. Limit memory to range 1k to 48K DONE -26. Display keyboard image DONE - Glitch found and fixed through triple buffer (was not keyboard related) DONE -27. Add NTSC example directory with maxtext, QS Defenda, Spiro, Nova2005 DONE -28. Check hrdemo3 with NTSC DONE -29. Raise bug report against 2.3.12 in Github -30. Investigate WRX1K1 not working in 1K DONE - BASIC prog will not fit in 1K. It will run in "1K" on the latest EightyOne, - but that is because "1K" is actually 2K - Peek 16389 gives 72 -31. Implement I2S on vgaboard DONE diff --git a/src/z80.c b/src/z80.c index d72164e..0ca125d 100644 --- a/src/z80.c +++ b/src/z80.c @@ -29,7 +29,7 @@ #define parity(a) (partable[a]) -unsigned char partable[256]={ +unsigned char partable[256] = { 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, @@ -48,17 +48,19 @@ unsigned char partable[256]={ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4 }; -unsigned long tstates=0,tsmax=65000,frames=0; +unsigned long tstates = 0; +const unsigned long tsmax = 65000; +static unsigned long ts = 0; static unsigned char* scrnbmp_new = 0; #ifdef SUPPORT_CHROMA static unsigned char* scrnbmpc_new = 0; #endif -static int vsx=0; -static int vsy=0; -static int nrmvideo=1; -int ay_reg=0; +static int vsx = 0; +static int vsy = 0; +static int nrmvideo = 1; +int ay_reg = 0; int LastInstruction; bool frameNotSync = true; @@ -95,19 +97,20 @@ static int RasterX = 0; static int RasterY = 0; static int dest; -static int adjustStartX=0; -static int adjustStartY=0; +static int adjustStartX = 0; +static int adjustStartY = 0; static int startX = 0; static int startY = 0; +static int syncX = 0; static int endX = 0; static int endY = 0; -static int int_pending, nmi_pending, hsync_pending; +static int nmi_pending, hsync_pending; static int NMI_generator; static int VSYNC_state, HSYNC_state, SYNC_signal; static int psync, sync_len; -static int rowcounter=0; -static int hsync_counter=0; +static int rowcounter = 0; +static int hsync_counter = 0; static bool rowcounter_hold = false; static void setRemainingDisplayBoundaries(void); @@ -143,7 +146,7 @@ unsigned short pc; unsigned short ix, iy, sp; unsigned char radjust; unsigned char ixoriy, new_ixoriy; -unsigned char intsample=0; +unsigned char intsample = 0; unsigned char op; unsigned short m1cycles; @@ -211,6 +214,7 @@ static void setRemainingDisplayBoundaries(void) adjustStartY = emu_CentreY(); startX = disp.start_x - adjustStartX - 6; startY = disp.start_y - adjustStartY; + syncX = disp.start_x - adjustStartX; endX = disp.end_x - adjustStartX; endY = disp.end_y - adjustStartY; } @@ -226,28 +230,29 @@ void adjustChroma(bool start) void resetZ80(void) { - a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1=h1=l1=i=iff1=iff2=im=r=0; - ixoriy=new_ixoriy=0; - ix=iy=sp=pc=0; - tstates=radjust=0; - intsample=0; - m1cycles=0; - tstates=0; - frames=0; - vsy=0; - nrmvideo=0; + a = f = b = c = d = e = h = l = 0; + a1 = f1 = b1 = c1 = d1 = e1 = h1 = l1 = i = iff1 = iff2 = im = r = 0; + ixoriy = new_ixoriy = 0; + ix= iy = sp = pc = 0; + tstates = radjust = 0; + intsample = 0; + m1cycles = 0; + tstates = 0; + ts = 0; + vsx = vsy = 0; + nrmvideo = 0; RasterX = 0; RasterY = 0; psync = 1; sync_len = 0; running_rom = false; frameNotSync = true; + LastInstruction = LASTINSTNONE; /* ULA */ - NMI_generator=0; - int_pending=0; - hsync_pending=0; - VSYNC_state=HSYNC_state=0; + NMI_generator = 0; + hsync_pending = 0; + VSYNC_state = HSYNC_state = 0; setDisplayBoundaries(); dest = disp.offset + (adjustStartY * disp.stride_bit) + adjustStartX; @@ -275,8 +280,8 @@ void resetZ80(void) /* Ensure chroma is turned off */ chromamode = 0; #ifdef SUPPORT_CHROMA - bordercolour=0x0f; - bordercolournew=0x0f; + bordercolour = 0x0f; + bordercolournew = 0x0f; displayResetChroma(); #endif @@ -298,7 +303,8 @@ void resetZ80(void) if(autoload) { // Have already read the new specific parameters - if (rom4k) { + if (rom4k) + { /* Registers (common values) */ a = 0x00; f = 0x44; b = 0x00; c = 0x00; d = 0x07; e = 0xae; h = 0x40; l = 0x2a; @@ -308,22 +314,17 @@ void resetZ80(void) d1 = 0xd8; e1 = 0xf0; h1 = 0xd8; l1 = 0xf0; iff1 = 0x00; iff2 = 0x00; im = 0x02; radjust = 0x6a; + /* Machine Stack (common values) */ - if (ramsize >= 16) { - sp = 0x8000 - 4; - } else { - sp = 0x4000 - 4 + ramsize * 1024; - } + sp = (ramsize >= 16) ? (0x8000 - 4) : (0x4000 - 4 + ramsize * 1024); + mem[sp + 0] = 0x47; mem[sp + 1] = 0x04; - mem[sp + 2] = 0xba; + mem[sp + 2] = (ramsize >= 16) ? 0x22 : 0xba; mem[sp + 3] = 0x3f; - /* Now override if RAM configuration changes things - * (there's a possibility these changes are unimportant) */ - if (ramsize == 16) { - mem[sp + 2] = 0x22; - } - } else { + } + else + { /* Registers (common values) */ a = 0x0b; f = 0x00; b = 0x00; c = 0x02; d = 0x40; e = 0x9b; h = 0x40; l = 0x99; @@ -333,23 +334,24 @@ void resetZ80(void) d1 = 0x00; e1 = 0x2b; h1 = 0x00; l1 = 0x00; iff1 = 0; iff2 = 0; im = 2; radjust = 0xa4; + /* GOSUB Stack (common values) */ - if (ramsize >= 16) { - sp = 0x8000 - 4; - } else { - sp = 0x4000 - 4 + ramsize * 1024; - } + sp = (ramsize >= 16) ? (0x8000 - 4) : (0x4000 - 4 + ramsize * 1024); + mem[sp + 0] = 0x76; mem[sp + 1] = 0x06; mem[sp + 2] = 0x00; mem[sp + 3] = 0x3e; - /* Now override if RAM configuration changes things, - without these changes Multi-scroll sometimes fail to start */ - if (ramsize >= 4) { + + /* Update values for larger RAM sizes, + without these changes Multi-scroll sometimes fails to start */ + if (ramsize >= 4) + { d = 0x43; h = 0x43; a1 = 0xec; b1 = 0x81; c1 = 0x02; radjust = 0xa9; } + /* System variables */ mem[0x4000] = 0xff; /* ERR_NR */ mem[0x4001] = 0x80;; /* FLAGS */ @@ -362,8 +364,8 @@ void resetZ80(void) mem[0x4008] = 0xff; /* PPC hi */ } - /* finally, load. It'll reset (via reset81) if it fails. */ - load_p(32768, false); + /* finally, load. Reset (via resetZ80) occurs if load fails. */ + load_p(0x8000, false); } } @@ -449,7 +451,7 @@ static void __not_in_flash_func(displayAndNewScreen)(bool sync) static void __not_in_flash_func(vsync_raise)(void) { /* save current pos - in screen coords*/ - vsx = RasterX - (disp.start_x - adjustStartX); + vsx = RasterX - syncX + (ts << 1); vsy = RasterY - startY; // move to next valid pixel @@ -473,7 +475,7 @@ static void __not_in_flash_func(vsync_raise)(void) /* for vsync on -> off */ static void __not_in_flash_func(vsync_lower)(void) { - int nx = RasterX - (disp.start_x - adjustStartX); + int nx = RasterX - syncX + (ts << 1); int ny = RasterY - startY; // Move to the next valid pixel @@ -500,9 +502,9 @@ static void __not_in_flash_func(vsync_lower)(void) if((ny < vsy) || ((ny == vsy) && (nx < vsx))) { // wrapping around frame, so display bottom - uint8_t* start = scrnbmp_new+vsy*disp.stride_byte+(vsx>>3)-1; + uint8_t* start = scrnbmp_new + vsy * disp.stride_byte + (vsx >> 3) - 1; *start++ = (0xff >> (vsx & 0x7)); - memset(start, 0xff, disp.stride_byte*(disp.height-vsy)-(vsx>>3)-1); + memset(start, 0xff, disp.stride_byte * (disp.height - vsy) - (vsx >> 3) - 1); // check for case where wrap ends at bottom if ((nx == 0) && (ny == 0)) return; @@ -512,8 +514,8 @@ static void __not_in_flash_func(vsync_lower)(void) vsy = 0; } - uint8_t* start = scrnbmp_new+vsy*disp.stride_byte+(vsx>>3)-1; - uint8_t* end = scrnbmp_new+ny*disp.stride_byte+(nx>>3); + uint8_t* start = scrnbmp_new + vsy * disp.stride_byte + (vsx >> 3) - 1; + uint8_t* end = scrnbmp_new + ny * disp.stride_byte + (nx >> 3); *start++ = (0xff >> (vsx & 0x7)); // end bits? @@ -526,38 +528,21 @@ static void __not_in_flash_func(vsync_lower)(void) // especially when displaying the loading screen if (end > start) { - memset(start, 0xff, end-start); + memset(start, 0xff, end - start); } } void __not_in_flash_func(execZX81)(void) { - unsigned long ts; - unsigned char v; - bool videodata; - - int addr; - int k; - int kh; - int kl; - -#ifdef SUPPORT_CHROMA - unsigned char colour = 0; -#endif - do { - LastInstruction = LASTINSTNONE; - - if(intsample && !((radjust-1)&64) && iff1) - int_pending=1; - if(nmi_pending) { ts = nmi_interrupt(); tstates += ts; + nmi_pending = 0; } - else if (int_pending) + else if (iff1 && intsample && !((radjust - 1) & 0x40)) { ts = z80_interrupt(); hsync_counter = -2; /* INT ACK after two tstates */ @@ -569,86 +554,58 @@ void __not_in_flash_func(execZX81)(void) // Get the next op, calculate the next byte to display and execute the op op = fetchm(pc); + // After this instruction can have interrupt intsample = 1; - m1cycles = 1; - if (m1not && pc<0xC000) - { - videodata = false; - } - else + if (((pc & 0x8000) && (!m1not || (pc & 0x4000)) && !(op & 0x40))) { - videodata = (pc&0x8000) ? true: false; - } - - if(videodata && !(op & 0x40)) - { - if ((i < 0x20) || (i < 0x40 && LowRAM && (!useWRX))) + if ((RasterX >= startX) && + (RasterX < endX) && + (RasterY >= startY) && + (RasterY < endY)) { - if (chr128 && i > 0x20 && i & 1) - addr = ((i & 0xfe) << 8) | ((((op & 0x80) >> 1) | (op & 0x3f)) << 3)|rowcounter; - else - addr = ((i & 0xfe) << 8) | ((op & 0x3f) << 3) | rowcounter; + unsigned char v; + int addr; - if (UDGEnabled && (addr >= 0x1E00) && (addr < 0x2000)) + if ((i < 0x20) || ((i < 0x40) && LowRAM && (!useWRX))) { - v = mem[addr + ((op & 0x80) ? 0x6800 : 0x6600)]; + if (!(chr128 && (i > 0x20) && (i & 1))) + addr = ((i & 0xfe) << 8) | ((op & 0x3f) << 3) | rowcounter; + else + addr = ((i & 0xfe) << 8) | ((((op & 0x80) >> 1) | (op & 0x3f)) << 3) | rowcounter; + + if (UDGEnabled && (addr >= 0x1E00) && (addr < 0x2000)) + { + v = mem[addr + ((op & 0x80) ? 0x6800 : 0x6600)]; + } + else + { + v = mem[addr]; + } + } + else if (useWRX) + { + v = mem[(i << 8) | (r & 0x80) | (radjust & 0x7f)]; } else { - v = mem[addr]; + v = 0xff; } - } - else if (useWRX) - { - v = mem[(i << 8) | (r & 0x80) | (radjust & 0x7f)]; - } - else - { - v = 0xff; - } - v = (op & 0x80) ? ~v : v; + v = (op & 0x80) ? ~v : v; #ifdef SUPPORT_CHROMA - if (chromamode) - { - colour = (chromamode & 0x10) ? fetch(pc) : fetch(0xc000 | ((((op & 0x80) >> 1) | (op & 0x3f)) << 3) | rowcounter); - chroma_set = (colour ^ fullcolour) & 0xf0; - } -#endif - /* The CPU sees a nop - so skip the Z80 emulation loop */ - pc++; - radjust++; - - ts = 4; - tstates += 4; - // Plot data in shift register - // Note subtract 6 as this leaves the smallest positive number - // of bits to carry to next byte (2) - #ifdef SUPPORT_CHROMA - if ((v || chroma_set) && - #else - if (v && - #endif - (RasterX >= startX) && - (RasterX < endX) && - (RasterY >= startY) && - (RasterY < endY)) - { - #ifdef SUPPORT_CHROMA if (chromamode) { - k = (dest + RasterX) >> 3; - scrnbmpc_new[k] = colour; + int k = (dest + RasterX) >> 3; + scrnbmpc_new[k] = (chromamode & 0x10) ? fetch(pc) : fetch(0xc000 | ((((op & 0x80) >> 1) | (op & 0x3f)) << 3) | rowcounter); scrnbmp_new[k] = v; - chroma_set = 0; } else +#endif { - #endif - k = dest + RasterX; - kh = k >> 3; - kl = k & 7; + int k = dest + RasterX; + int kh = k >> 3; + int kl = k & 7; if (kl) { @@ -659,47 +616,51 @@ void __not_in_flash_func(execZX81)(void) { scrnbmp_new[kh] = v; } - #ifdef SUPPORT_CHROMA } - #endif } + /* The CPU sees a nop - so skip the Z80 emulation loop */ + pc++; + radjust++; + + ts = 4; + tstates += ts; } else { ts = z80_op(); - } - } - - nmi_pending = int_pending = 0; - - switch(LastInstruction) - { - case LASTINSTOUTFD: - NMI_generator = 0; - anyout(); - break; - case LASTINSTOUTFE: - NMI_generator = 1; - anyout(); - break; - - case LASTINSTINFE: - if (!NMI_generator) + switch(LastInstruction) { - if (VSYNC_state == 0) - { - VSYNC_state = 1; - vsync_raise(); - } - } - break; + case LASTINSTOUTFD: + NMI_generator = 0; + anyout(); + break; + + case LASTINSTOUTFE: + NMI_generator = 1; + anyout(); + break; + + case LASTINSTINFE: + if (!NMI_generator) + { + if (VSYNC_state == 0) + { + VSYNC_state = 1; + vsync_raise(); + } + } + LastInstruction = LASTINSTNONE; + break; - case LASTINSTOUTFF: - anyout(); - break; + case LASTINSTOUTFF: + anyout(); + break; + } + } } + // Determine changes to sync state int states_remaining = ts; int since_hstart = 0; int tswait = 0; @@ -710,8 +671,8 @@ void __not_in_flash_func(execZX81)(void) tstate_inc = states_remaining > MAX_JMP ? MAX_JMP: states_remaining; states_remaining -= tstate_inc; - hsync_counter+=tstate_inc; - RasterX += (tstate_inc<<1); + hsync_counter += tstate_inc; + RasterX += (tstate_inc << 1); if (hsync_counter >= HLEN) { @@ -720,14 +681,14 @@ void __not_in_flash_func(execZX81)(void) } // Start of HSYNC, and NMI if enabled - if (hsync_pending==1 && hsync_counter>=HSYNC_START) + if ((hsync_pending == 1) && (hsync_counter >= HSYNC_START)) { if (NMI_generator) { nmi_pending = 1; - if (ts==4) + if (ts == 4) { - tswait = 14 + (3-states_remaining - (hsync_counter - HSYNC_START)); + tswait = 14 + (3 - states_remaining - (hsync_counter - HSYNC_START)); } else { @@ -768,115 +729,72 @@ void __not_in_flash_func(execZX81)(void) } while (states_remaining); } - while (tstates= startX) && + (RasterX < endX) && + (RasterY >= startY) && + (RasterY < endY)) { - if (chr128 && i > 0x20 && i & 1) - addr = ((i & 0xfe) << 8) | ((((op & 0x80) >> 1) | (op & 0x3f)) << 3)|rowcounter; - else - addr = ((i & 0xfe) << 8) | ((op & 0x3f) << 3) | rowcounter; + unsigned char v; + int addr; - if (UDGEnabled && (addr >= 0x1E00) && (addr < 0x2000)) + if ((i < 0x20) || ((i < 0x40) && LowRAM && (!useWRX))) { - v = mem[addr + ((op & 0x80) ? 0x6800 : 0x6600)]; + if (!(chr128 && (i > 0x20) && (i & 1))) + addr = ((i & 0xfe) << 8) | ((op & 0x3f) << 3) | rowcounter; + else + addr = ((i & 0xfe) << 8) | ((((op & 0x80) >> 1) | (op & 0x3f)) << 3) | rowcounter; + + if (UDGEnabled && (addr >= 0x1E00) && (addr < 0x2000)) + { + v = mem[addr + ((op & 0x80) ? 0x6800 : 0x6600)]; + } + else + { + v = mem[addr]; + } + } + else if (useWRX) + { + v = mem[(i << 8) | (r & 0x80) | (radjust & 0x7f)]; } else { - v = mem[addr]; + v = 0xff; } - } - else if (useWRX) - { - v = mem[(i << 8) | (r & 0x80) | (radjust & 0x7f)]; - } - else - { - v = 0xff; - } - v = (op & 0x80) ? ~v : v; - -#ifdef SUPPORT_CHROMA - if (chromamode) - { - colour = (chromamode & 0x10) ? fetch(pc) : fetch(0xc000 | ((((op & 0x80) >> 1) | (op & 0x3f)) << 3) | rowcounter); - chroma_set = (colour ^ fullcolour) & 0xf0; - } -#endif - /* The CPU sees a nop - so skip the Z80 emulation loop */ - pc++; - radjust++; + v = (op & 0x80) ? ~v : v; - ts = 4; - tstates += 4; - // Plot data in shift register - // Note subtract 6 as this leaves the smallest positive number - // of bits to carry to next byte (2) -#ifdef SUPPORT_CHROMA - if ((v || chroma_set) && -#else - if (v && -#endif - (RasterX >= startX) && - (RasterX < endX) && - (RasterY >= startY) && - (RasterY < endY)) - { #ifdef SUPPORT_CHROMA if (chromamode) { - k = (dest + RasterX) >> 3; - scrnbmpc_new[k] = colour; + int k = (dest + RasterX) >> 3; + scrnbmpc_new[k] = (chromamode & 0x10) ? fetch(pc) : fetch(0xc000 | ((((op & 0x80) >> 1) | (op & 0x3f)) << 3) | rowcounter); scrnbmp_new[k] = v; - chroma_set = 0; } else - { #endif - k = dest + RasterX; - kh = k >> 3; - kl = k & 7; + { + int k = dest + RasterX; + int kh = k >> 3; + int kl = k & 7; if (kl) { @@ -887,27 +805,41 @@ void __not_in_flash_func(execZX80)(void) { scrnbmp_new[kh] = v; } -#ifdef SUPPORT_CHROMA } -#endif } + + /* The CPU sees a nop - so skip the Z80 emulation loop */ + pc++; + radjust++; + + ts = 4; + tstates += ts; + + // Update the flip flop + prevVideoFlipFlop3Q = videoFlipFlop3Q; + + if (videoFlipFlop3Clear) + { + videoFlipFlop3Q = videoFlipFlop2Q; + } + videoFlipFlop2Q = !videoFlipFlop1Q; } else { ts = z80_op(); - } - // Update the flip flop - prevVideoFlipFlop3Q = videoFlipFlop3Q; + // Update the flip flop + prevVideoFlipFlop3Q = videoFlipFlop3Q; - for (int i = 0; i < m1cycles; i++) - { - if (videoFlipFlop3Clear) + for (int i = 0; i < m1cycles; ++i) { - videoFlipFlop3Q = videoFlipFlop2Q; - } + if (videoFlipFlop3Clear) + { + videoFlipFlop3Q = videoFlipFlop2Q; + } - videoFlipFlop2Q = !videoFlipFlop1Q; + videoFlipFlop2Q = !videoFlipFlop1Q; + } } if (!videoFlipFlop3Q) @@ -921,9 +853,9 @@ void __not_in_flash_func(execZX80)(void) } // execute an interrupt - if (intsample && !((radjust - 1) & 0x40) && iff1) + if (iff1 && intsample && !((radjust - 1) & 0x40)) { - tstore = z80_interrupt(); + unsigned long tstore = z80_interrupt(); tstates += tstore; ts += tstore; @@ -962,6 +894,7 @@ void __not_in_flash_func(execZX80)(void) videoFlipFlop3Q = 1; } } + LastInstruction = LASTINSTNONE; break; case LASTINSTINFE: // VSync start @@ -978,6 +911,7 @@ void __not_in_flash_func(execZX80)(void) videoFlipFlop3Clear = 0; videoFlipFlop3Q = 0; rowcounter = 0; + LastInstruction = LASTINSTNONE; break; default: @@ -1001,15 +935,16 @@ void __not_in_flash_func(execZX80)(void) if (sync_len <= ZX80HSyncAcceptanceDuration) { sync_type = SYNCTYPEH; + if (scanline_len >= ZX80HSyncAcceptancePixelPosition) + { + lineClockCarryCounter = ts; + scanline_len = scanlinePixelLength; + } } else - { - sync_type = SYNCTYPEV; - } - - if (sync_type == SYNCTYPEV) { int overhangPixels = scanline_len - scanlinePixelLength; + sync_type = SYNCTYPEV; if (overhangPixels < 0) { @@ -1029,28 +964,23 @@ void __not_in_flash_func(execZX80)(void) scanline_len = scanlinePixelLength; } } - else if (scanline_len >= ZX80HSyncAcceptancePixelPosition) - { - lineClockCarryCounter = ts; - scanline_len = scanlinePixelLength; - } } - // If we are at the end of a zx80 line then process it + // If we are at the end of a line then process it if (!((scanline_len < scanlineThresholdPixelLength) && (sync_type == SYNCNONE))) { if (sync_type == SYNCTYPEV) { - // Frames synchonised after second vsyncs in range + // Frames synchonised after second vsync in range if (vsyncFound) { - frameNotSync = !((RasterY >= VSYNC_TOLERANCEMIN) && (RasterY <= VSYNC_TOLERANCEMAX) && - (scanlineCounter >= VSYNC_TOLERANCEMIN) && (scanlineCounter <= VSYNC_TOLERANCEMAX)); + frameNotSync = !((RasterY >= VSYNC_TOLERANCEMIN) && (RasterY < VSYNC_TOLERANCEMAX) && + (scanlineCounter >= VSYNC_TOLERANCEMIN) && (scanlineCounter < VSYNC_TOLERANCEMAX)); vsyncFound = !frameNotSync; } else { - vsyncFound = (scanlineCounter >= VSYNC_TOLERANCEMIN) && (scanlineCounter <= VSYNC_TOLERANCEMAX); + vsyncFound = (scanlineCounter >= VSYNC_TOLERANCEMIN) && (scanlineCounter < VSYNC_TOLERANCEMAX); } scanlineCounter = 0; @@ -1063,15 +993,12 @@ void __not_in_flash_func(execZX80)(void) } else { - if (scanlineCounter < VSYNC_TOLERANCEMAX) + if (sync_type == SYNCTYPEH) { - if (sync_type == SYNCTYPEH) - { - scanlineCounter++; - } + scanlineCounter++; } - if (((sync_type == SYNCNONE) && videoFlipFlop3Q) || (scanlineCounter == VSYNC_TOLERANCEMAX)) + if (((sync_type == SYNCNONE) && videoFlipFlop3Q) || (scanlineCounter >= VSYNC_TOLERANCEMAX)) { frameNotSync = true; vsyncFound = false; @@ -1103,26 +1030,26 @@ void __not_in_flash_func(execZX80)(void) if (S_RasterY >= VSYNC_TOLERANCEMAX) { S_RasterX = 0; - sync_type=SYNCTYPEV; + sync_type = SYNCTYPEV; if (sync_len < HSYNC_MINLEN) { - sync_len=HSYNC_MINLEN; + sync_len = HSYNC_MINLEN; } } } - if (sync_len HSYNC_TOLERANCEMAX) { - S_RasterX=0; + S_RasterX = 0; S_RasterY++; } - if (S_RasterY>=VSYNC_TOLERANCEMAX || - (sync_len>VSYNC_MINLEN && S_RasterY>VSYNC_TOLERANCEMIN)) + if (((sync_len > VSYNC_MINLEN) && (S_RasterY > VSYNC_TOLERANCEMIN)) || + (S_RasterY >= VSYNC_TOLERANCEMAX)) { if (nosync_lines >= FRAME_SCAN) { @@ -1139,11 +1066,6 @@ void __not_in_flash_func(execZX80)(void) } } - // Update data for new ZX80 scanline - RasterX = S_RasterX; - RasterY = S_RasterY; - dest = disp.offset + (disp.stride_bit * (adjustStartY + RasterY)) + adjustStartX; - if (sync_type != SYNCNONE) { sync_type = SYNCNONE; @@ -1154,19 +1076,22 @@ void __not_in_flash_func(execZX80)(void) if (lineClockCarryCounter > 0) { scanline_len = lineClockCarryCounter << 1; - RasterX += scanline_len; lineClockCarryCounter = 0; } else { scanline_len = 0; } + + // Update data for new ZX80 scanline + RasterX = S_RasterX + scanline_len; + RasterY = S_RasterY; + dest = disp.offset + (disp.stride_bit * (adjustStartY + RasterY)) + adjustStartX; } } - while (tstates= HSYNC_MINLEN && sync_len <= (HSYNC_MAXLEN + MAX_JMP) && RasterX>=HSYNC_TOLERANCEMIN ) || - ( tolchk && RasterX>=HSYNC_TOLERANCEMAX ) ) + if ( ( !tolchk && sync_len >= HSYNC_MINLEN && sync_len <= (HSYNC_MAXLEN + MAX_JMP) && RasterX >= HSYNC_TOLERANCEMIN ) || + ( tolchk && RasterX >= HSYNC_TOLERANCEMAX ) ) { RasterX = ((hsync_counter - HSYNC_END) < MAX_JMP) ? ((hsync_counter - HSYNC_END) << 1) : 0; RasterY++; @@ -1255,8 +1180,8 @@ static inline void __not_in_flash_func(checkhsync)(int tolchk) static inline void __not_in_flash_func(checkvsync)(int tolchk) { - if ( ( !tolchk && sync_len >= VSYNC_MINLEN && RasterY>=VSYNC_TOLERANCEMIN ) || - ( tolchk && RasterY>=VSYNC_TOLERANCEMAX ) ) + if ( ( !tolchk && sync_len >= VSYNC_MINLEN && RasterY >= VSYNC_TOLERANCEMIN ) || + ( tolchk && RasterY >= VSYNC_TOLERANCEMAX ) ) { if (sync_len>(int)tsmax) { @@ -1310,6 +1235,8 @@ static inline void __not_in_flash_func(checksync)(int inc) static void __not_in_flash_func(anyout)(void) { + LastInstruction = LASTINSTNONE; + if (VSYNC_state) { VSYNC_state = 0; diff --git a/src/z80.h b/src/z80.h index 66a25c9..599f737 100644 --- a/src/z80.h +++ b/src/z80.h @@ -26,7 +26,6 @@ #define LASTINSTOUTFD 3 #define LASTINSTOUTFF 4 -extern unsigned long tstates,tsmax,frames; extern int ay_reg; extern int LastInstruction; extern bool frameNotSync; @@ -54,12 +53,10 @@ void adjustChroma(bool start); #define AY_STORE_CHECK(x,y) \ if(sound_type==SOUND_TYPE_QUICKSILVA) {\ - switch(x){\ - case 0x7fff:\ - ay_reg=((y)&0x0F); break;\ - case 0x7ffe:\ - sound_ay_write(ay_reg,(y));\ - }\ + if(x==0x7fff)\ + ay_reg=((y)&0x0F);\ + else if (x==0x7ffe)\ + sound_ay_write(ay_reg,(y));\ }\ #define QSUDG_STORE_CHECK(x,y) \ diff --git a/src/z80ops.h b/src/z80ops.h index f91b57a..55bbd1e 100644 --- a/src/z80ops.h +++ b/src/z80ops.h @@ -1077,7 +1077,7 @@ instr(0xd2,10); endinstr; instr(0xd3,11); - tstates+=out(a,fetch(pc),a); + out(a,fetch(pc),a); pc++; endinstr; diff --git a/src/zx8x.c b/src/zx8x.c index 8e4a112..08a4786 100755 --- a/src/zx8x.c +++ b/src/zx8x.c @@ -36,7 +36,7 @@ int signal_int_flag=0; int ramsize=16; /* the keyboard state and other */ -static uint8_t keyboard[ 8 ] = {0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff}; +static uint8_t keyboard[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int zx80=0; int rom4k=0; int autoload=1; @@ -70,8 +70,6 @@ static char tapename[64]={0}; unsigned int __not_in_flash_func(in)(int h, int l) { - int data=0x80; - if ((h == 0x7f) && (l == 0xef)) { #ifdef SUPPORT_CHROMA @@ -80,24 +78,26 @@ unsigned int __not_in_flash_func(in)(int h, int l) #ifdef DEBUG_CHROMA printf("Insufficient RAM Size for Chroma!\n"); #endif - return 0xFF; + return 0xff; } else if (!emu_chromaSupported()) { #ifdef DEBUG_CHROMA printf("Display does not support Chroma \n"); #endif - return 0xFF; + return 0xff; } return 0x02; /* chroma 80 and 81 available*/ #else - return 0xFF; + return 0xff; #endif } if (!(l&1)) { + int data=0x80; LastInstruction=LASTINSTINFE; + if (((sound_type == SOUND_TYPE_VSYNC) || ((sound_type == SOUND_TYPE_CHROMA) && frameNotSync))) { sound_beeper(0); @@ -113,14 +113,14 @@ unsigned int __not_in_flash_func(in)(int h, int l) switch(h) { - case 0xfe: return(keyboard[0]^data); - case 0xfd: return(keyboard[1]^data); - case 0xfb: return(keyboard[2]^data); - case 0xf7: return(keyboard[3]^data); - case 0xef: return(keyboard[4]^data); - case 0xdf: return(keyboard[5]^data); - case 0xbf: return(keyboard[6]^data); - case 0x7f: return(keyboard[7]^data); + case 0xfe: return(keyboard[0] ^ data); + case 0xfd: return(keyboard[1] ^ data); + case 0xfb: return(keyboard[2] ^ data); + case 0xf7: return(keyboard[3] ^ data); + case 0xef: return(keyboard[4] ^ data); + case 0xdf: return(keyboard[5] ^ data); + case 0xbf: return(keyboard[6] ^ data); + case 0x7f: return(keyboard[7] ^ data); default: { @@ -130,23 +130,24 @@ unsigned int __not_in_flash_func(in)(int h, int l) * support this is AND together any for which the corresponding * bit is zero. */ - for(i=0,mask=1;i<8;i++,mask<<=1) - if(!(h&mask)) - retval&=keyboard[i]; - return(retval^data); + for(i = 0, mask = 1; i < 8; i++, mask <<= 1) + { + if(!(h & mask)) retval &= keyboard[i]; + } + return(retval ^ data); } } } - return(255); + return 0xff; } -unsigned int __not_in_flash_func(out)(int h, int l, int a) +void __not_in_flash_func(out)(int h, int l, int a) { if ((sound_type == SOUND_TYPE_VSYNC) || ((sound_type == SOUND_TYPE_CHROMA) && frameNotSync)) sound_beeper(1); #ifdef SUPPORT_CHROMA - if ((h==0x7f) && (l==0xef)) + if ((h == 0x7f) && (l == 0xef)) { /* chroma */ if (emu_chromaSupported()) { @@ -182,8 +183,8 @@ unsigned int __not_in_flash_func(out)(int h, int l, int a) printf("Chroma requested, but not supported.\n"); #endif } - LastInstruction=LASTINSTOUTFF; - return 0; + LastInstruction = LASTINSTOUTFF; + return; } #endif @@ -209,11 +210,11 @@ unsigned int __not_in_flash_func(out)(int h, int l, int a) case 0xfe: LastInstruction = LASTINSTOUTFE; break; - } - if (LastInstruction == LASTINSTNONE) - LastInstruction=LASTINSTOUTFF; - return 0; // No additional tstates + default: + LastInstruction = LASTINSTOUTFF; + break; + } } static char fname[256]; diff --git a/uf2/picozx81_dvi.uf2 b/uf2/picozx81_dvi.uf2 index c1a8579..70dd9a0 100644 Binary files a/uf2/picozx81_dvi.uf2 and b/uf2/picozx81_dvi.uf2 differ diff --git a/uf2/picozx81_dvi_hdmi_sound.uf2 b/uf2/picozx81_dvi_hdmi_sound.uf2 index 5bbb7dc..87bd7c2 100644 Binary files a/uf2/picozx81_dvi_hdmi_sound.uf2 and b/uf2/picozx81_dvi_hdmi_sound.uf2 differ diff --git a/uf2/picozx81_lcdmaker.uf2 b/uf2/picozx81_lcdmaker.uf2 index 40fde5d..ba234a0 100644 Binary files a/uf2/picozx81_lcdmaker.uf2 and b/uf2/picozx81_lcdmaker.uf2 differ diff --git a/uf2/picozx81_lcdws28.uf2 b/uf2/picozx81_lcdws28.uf2 index fd512d9..fb70a81 100644 Binary files a/uf2/picozx81_lcdws28.uf2 and b/uf2/picozx81_lcdws28.uf2 differ diff --git a/uf2/picozx81_olimexpc.uf2 b/uf2/picozx81_olimexpc.uf2 index b904826..4fb4716 100644 Binary files a/uf2/picozx81_olimexpc.uf2 and b/uf2/picozx81_olimexpc.uf2 differ diff --git a/uf2/picozx81_olimexpc_hdmi_sound.uf2 b/uf2/picozx81_olimexpc_hdmi_sound.uf2 index 8fc5703..12b28fe 100644 Binary files a/uf2/picozx81_olimexpc_hdmi_sound.uf2 and b/uf2/picozx81_olimexpc_hdmi_sound.uf2 differ diff --git a/uf2/picozx81_picomitevga.uf2 b/uf2/picozx81_picomitevga.uf2 index 886f7ac..ec2b837 100644 Binary files a/uf2/picozx81_picomitevga.uf2 and b/uf2/picozx81_picomitevga.uf2 differ diff --git a/uf2/picozx81_picozx.uf2 b/uf2/picozx81_picozx.uf2 index a9f6d64..1e49505 100644 Binary files a/uf2/picozx81_picozx.uf2 and b/uf2/picozx81_picozx.uf2 differ diff --git a/uf2/picozx81_picozx_lcd.uf2 b/uf2/picozx81_picozx_lcd.uf2 index 3270cf5..bc4dc44 100644 Binary files a/uf2/picozx81_picozx_lcd.uf2 and b/uf2/picozx81_picozx_lcd.uf2 differ diff --git a/uf2/picozx81_picozxreal.uf2 b/uf2/picozx81_picozxreal.uf2 index bd160d3..18134f4 100644 Binary files a/uf2/picozx81_picozxreal.uf2 and b/uf2/picozx81_picozxreal.uf2 differ diff --git a/uf2/picozx81_vga.uf2 b/uf2/picozx81_vga.uf2 index 6d82001..54fe140 100644 Binary files a/uf2/picozx81_vga.uf2 and b/uf2/picozx81_vga.uf2 differ diff --git a/uf2/picozx81_vga332.uf2 b/uf2/picozx81_vga332.uf2 index 7908a49..004076b 100644 Binary files a/uf2/picozx81_vga332.uf2 and b/uf2/picozx81_vga332.uf2 differ diff --git a/uf2/picozx81_vgamaker222c.uf2 b/uf2/picozx81_vgamaker222c.uf2 index 4b662ea..497a29d 100644 Binary files a/uf2/picozx81_vgamaker222c.uf2 and b/uf2/picozx81_vgamaker222c.uf2 differ diff --git a/uf2/picozx81_wspizero_hdmi_sound.uf2 b/uf2/picozx81_wspizero_hdmi_sound.uf2 index 140997b..a65aa51 100644 Binary files a/uf2/picozx81_wspizero_hdmi_sound.uf2 and b/uf2/picozx81_wspizero_hdmi_sound.uf2 differ