ped7g / zesarux

"temporary" fork of ZEsarUX with some fixes of TBBlue (ZX Next) called "ZESERUse" - I don't plan to develop it actively, hoping Cesar will obsolete this by fixing mainline, but so far this is unfortunately vastly superior to current ZEsarUX 9.2 in terms of Next emulation, so still keeping this fork around...
https://wiki.specnext.dev/ZESERUse:known_bugs
6 stars 0 forks source link

direct load of NEX file with entry bank doesn't seem to work #1

Closed ped7g closed 2 months ago

ped7g commented 2 months ago

See: https://github.com/z00m128/sjasmplus/issues/236#issue-2458343247

Both zeseruse and current vanilla ZEsarUX are failing.

As I did refactor direct nex loader implementation long time ago, it's more likely there is some init/reinit code later in the loading path cancelling the mapping of entry bank than completely ignoring entry bank in the loader itself, but somebody will have to check the code to be sure. Yay!

(also it's just my guess it's the missing mapping of the bank before jumping into the code. It could be also wrongly accepted interrupt handler as first instruction after load, while technically it should be in DI state and start with the code from the NEX file).

OnceBitten commented 2 months ago

I have another example of discrepancy between ZEsarUX v.X and real hardware, continuing on from the last.

Two nex files are compiled from the code below: layer2_experiment_s1.nex and layer2_experiment_s2.nex. The former is obtained by uncommenting just the 2 nextreg lines in /* Section 1 */. The latter is obtained by uncommenting just the 2 writes to the Layer 2 Access Port in /* Section 2 */.

On real hardware both nex files produce visually-identical results, comprised of: (a) a 320x256-mode Layer 2 screen covered with a mostly random jumble of multicoloured pixels, except for a fushia-coloured stripe on the leftmost 1/5th, being the fill of the first 16KiB-bank of the display with byte 133. (b) a pale pink border, with no flashing. This pale pink is the transparency fallback colour hex CF, I believe. Please find attached a photo of this on a TV via HDMI. Unfortunately, a Layer 2 screenshot taken using the NMI yellow button only seems to assume 256x192 mode, so there the fushia stripe is horizontal and occupies 1/3rd of the screen.

On ZEsarUX v.X calling directly layer2_experiment_s1.nex: (a) an entirely black 320x256-mode Layer 2 screen. (b) a multicolour flashing border as in nex_experiment.nex, but smaller due to 320x256 Layer 2 being displayed rather than ULA.

On ZEsarUX v.X calling directly layer2_experiment_s2.nex: (a) a mostly-black 320x256-mode Layer 2 screen, with a fushia-coloured stripe on the left 1/5th, being the fill of the first 16KiB-bank of the display with byte 133. (b) a multicolour flashing border as in nex_experiment.nex, but smaller due to 320x256 Layer 2 being displayed rather than ULA.

I should add that further experimentation with Layer 2 start bank locations indicate that the Layer 2 display is indeed enabled in the _s1.nex case.

The code is as follows:

  OPT --syntax=abfw --zxnext
;-------------------------------------------------------------------------------

  DEVICE ZXSPECTRUMNEXT ; ZX Spectrum Next (8 slots, 224 8Ki-Banks = "pages" in sjasm-speak, slot size 0x2000 = 1.75MiB RAM)
                        ; default banks map: [ 14,  15,  10,  11,  4,  5,            0,                1] = [7, 5, 2, 0] in 16KiB terms, like ZXSPECTRUM128
                        ; nexload banks map: [255, 255,  10,  11,  4,  5, 2*entry_bank, 2*entry_bank + 1]
                        ; default slot = 7 = $E000 - $FFFF
  LABELSLIST "layer2_experiment.lbl"

  MACRO PORT16BIT_WRITE port, value
    ld A, value
    ld BC, port
    out (C), A
  ENDM

; 8-bit Ports

ULA_CONTROL_PORT_WRITE                        EQU $FE

; 16-bit Ports

LAYER_2_ACCESS_PORT                           EQU $123B

; Next registers

LAYER_2_RAM_PAGE                              EQU $12
GLOBAL_TRANSPARENCY                           EQU $14
SPRITE_AND_LAYERS_SYSTEM                      EQU $15
LAYER_2_X_OFFSET                              EQU $16
LAYER_2_Y_OFFSET                              EQU $17
CLIP_WINDOW_LAYER_2                           EQU $18
CLIP_WINDOW_CONTROL                           EQU $1C
MEMORY_MANAGEMENT_SLOT_0_BANK                 EQU $50
MEMORY_MANAGEMENT_SLOT_1_BANK                 EQU $51
MEMORY_MANAGEMENT_SLOT_2_BANK                 EQU $52
MEMORY_MANAGEMENT_SLOT_3_BANK                 EQU $53
MEMORY_MANAGEMENT_SLOT_4_BANK                 EQU $54
MEMORY_MANAGEMENT_SLOT_5_BANK                 EQU $55
MEMORY_MANAGEMENT_SLOT_6_BANK                 EQU $56
MEMORY_MANAGEMENT_SLOT_7_BANK                 EQU $57
ULA_CONTROL                                   EQU $68
DISPLAY_CONTROL_1                             EQU $69
TILEMAP_CONTROL                               EQU $6B
LAYER_2_CONTROL                               EQU $70
LAYER_2_X_OFFSET_MSB                          EQU $71
TRANSPARENCY_COLOUR_FALLBACK                  EQU $4A

;-------------------------------------------------------------------------------
; Reset values

SOFT_RESET_GLOBAL_TRANSPARENCY     EQU $E3

;-------------------------------------------------------------------------------
; My stuff

MY_TRANSPARENCY_COLOUR_FALLBACK    EQU $CF
MY_LAYER_2_STRIPE_COLOUR           EQU 133
MY_LAYER_2_START_BANK16K           EQU 77

;-------------------------------------------------------------------------------

  ORG $4000 ; Start of slot 2, default page 10

entry:
  call initialise_screens
cycle_border:
  xor A         ; A <- 0
.loop:
  out (ULA_CONTROL_PORT_WRITE), A  ; set border colour
  inc A
  bit 3, A
  jr z, .loop
  jr cycle_border

initialise_screens:
  nextreg TRANSPARENCY_COLOUR_FALLBACK, MY_TRANSPARENCY_COLOUR_FALLBACK   ; Set fallback colour for pixels uncoloured by all layers (transparent or layer disabled)
  nextreg GLOBAL_TRANSPARENCY,          SOFT_RESET_GLOBAL_TRANSPARENCY        ; Set palette index for transparency in Layer 2, ULA, LoRes and 1-bit Tilemap layers
  nextreg ULA_CONTROL,              %1'01'0'0'0'0'0  ; disable ULA output, no ULA/Tilemap blending, disable ULA+ and ULA half-pixel scroll, disable stencil mode
  nextreg SPRITE_AND_LAYERS_SYSTEM, %0'0'1'000'1'0   ; disable LoRes
                                                     ; sprite 0 lowermost
                                                     ; SLU layer order
                                                     ; enable sprites and clipping "over border"
                                                     ; disable Sprite layer
  nextreg TILEMAP_CONTROL,          %0'0'0'0'0'0'0'0 ; disable Tilemap
                                                     ; 40x32 mode
                                                     ; use attribute byte
                                                     ; first Tilemap palette
                                                     ; disable 1-bit Tilemap
                                                     ; 256 tile mode
                                                     ; Tilemap below ULA
  nextreg DISPLAY_CONTROL_1,        %0'0'00000       ; disable Layer 2
                                                     ; disable ULA shadow display
                                                     ; Timex Sinclair bits 5-0 redundant as ULA output disabled
  nextreg LAYER_2_CONTROL,          %00'01'0000      ; 320x256x8bpp, set this before setting clip window
                                                     ; Zero palette offset
  nextreg LAYER_2_Y_OFFSET, 0 
  nextreg LAYER_2_X_OFFSET, 0 
  nextreg LAYER_2_X_OFFSET_MSB, 0 

  nextreg CLIP_WINDOW_CONTROL, %0000'1'0'1'1 ; Reset clip-window register indices for Sprite, Layer 2, Tilemap layers

  nextreg CLIP_WINDOW_LAYER_2, 0             ; X1 X-coordinates are doubled for 320x256 mode, so actually 0
  nextreg CLIP_WINDOW_LAYER_2, 159           ; X2 X-coordinates are doubled for 320x256 mode, so actually 318
  nextreg CLIP_WINDOW_LAYER_2, 0             ; Y1
  nextreg CLIP_WINDOW_LAYER_2, 255           ; Y2

  nextreg LAYER_2_RAM_PAGE, MY_LAYER_2_START_BANK16K ; 5 16KiB-banks needed for 320x256

  /* Section 1 */
  ;nextreg MEMORY_MANAGEMENT_SLOT_0_BANK, 2*MY_LAYER_2_START_BANK16K
  ;nextreg MEMORY_MANAGEMENT_SLOT_1_BANK, 2*MY_LAYER_2_START_BANK16K + 1
  /* End Section 1 */

  /* Section 2 */
  ;PORT16BIT_WRITE LAYER_2_ACCESS_PORT, %00'0'0'0'1'0'1
  ;PORT16BIT_WRITE LAYER_2_ACCESS_PORT, %000'1'0'000
  /* End Section 2 */

  ld HL, $0000 ; Write vertical stripe (set all of first Bank16k)
  ld BC, $3FFF
.loop
  ld (HL), MY_LAYER_2_STRIPE_COLOUR
  inc HL
  ld A, C
  or B
  jp z, finish
  dec BC
  jp .loop

finish:
  nextreg DISPLAY_CONTROL_1, %1'0'000000      ; enable Layer 2
  ret

;-------------------------------------------------------------------------------
;  SAVENEX pseudo-ops
;-------------------------------------------------------------------------------
;
  SAVENEX OPEN  "layer2_experiment.nex", entry, $0000, 0, 2 ; strictly nex file standard V1.2
  SAVENEX CORE  3, 0, 6    ; 320x256 Layer 2 required
  SAVENEX CFG   5, 1, 0, 1 ; cyan border, file handle in BC, default NextRegs, 2MB required
  SAVENEX AUTO
  SAVENEX CLOSE  

IMG_2015

ped7g commented 2 months ago

Thank you for another test case, but in this case only vanilla ZEsarUX is struggling, my fork works correctly (well, it doesn't randomize the memory content, but I don't find that worth of putting more effort into the dead fork), here are ZEsarUX 10.3 vs ZESERUse latest vs #CSpect 2.19.4.4 (CSpect does also randomize the memory). The cyan filling is my adjustment to the source code doing ~MY_LAYER_2_STRIPE_COLOUR fill color (122 instead of 133), so I can tell if I'm running first or second variant of the code:

image

Generally speaking ZEsarUX is not exactly the most accurate emulator around, that's why I initially tried to help with pull requests fixing some of the bugs and later forked the project as Cesar was struggling to incorporate my pull requests while being comfortable to further develop and maintain his project.

You can check Next wiki for known discrepancies in the emulators, although I didn't update these for most recent versions (yet .. I'm sort of on forced hiatus WRT to Next stuff, but I hope I will be back eventually): https://wiki.specnext.dev/ZEsarUX:known_bugs https://wiki.specnext.dev/ZESERUse:known_bugs https://wiki.specnext.dev/CSpect:known_bugs

If you are interested into overall most current emulator which is being developed, then you should try CSpect. My ZESERUse fork is slightly more accurate if you don't mind being stuck on core 3.1.5 features (and I have no plans to work on it any further, although small bug fixes still happen). ZEsarUX author is at this moment least pro-actively fixing bugs, usually he prefers to receive the released game which does not work correctly, and fix emulation based on that, he's not very enthusiastic about fixing code based on test cases or work in progress projects AFAIK. At least my test suite keeps being ignored... :D


BTW I don't mind chatting about ZEsarUX bugs even here, but I would appreciate if you would then put effort into testing also against my fork (so I know if the bug/discrepancy happens in both ZEsarUX and ZESERUse), and also cross-check against known bugs list and if you have good test for bug which is not described at all, feel free to update the wiki as well and provide the test here (ideally we can cooperate to turn it into test in https://github.com/MrKWatkins/ZXSpectrumNextTests/ collection, so I can re-check the bug with every new release of any emulator)

Although with ZEsarUX there's too many small inaccuracies, so for example your code is covered by rather general:

ULA+tilemode does not support stencil mode, and transparency fallback color is not used in some edge cases (disabled ULA + clipped tiles)

I would document stuff more thoroughly and provide more test cases if there would be interest from the author, but seems I usually overwhelmed him so quickly, that such extra activity was in the end detrimental to the result. :) After all, it's a hobby and he has full right to proceed at the pace he likes and can sustain.

ped7g commented 2 months ago

The issue is that the snap.c void load_nex_snapshot(char *archivo) will call tbblue_out_port_32765(nex_header[139]);

which does

                //para indicar a la MMU la  pagina en los segmentos 6 y 7
                tbblue_registers[80+6]=(value&7)*2;
                tbblue_registers[80+7]=(value&7)*2+1;

so instead of requested bank 77 the bank 5 is mapped to the top of the RAM.

Guessing the fix, the loader maybe could or should call tbblue_out_port_32765 with value 0 to set Bank 0 first (and do all kind of other inits that routine does), and then switch only the MMU banks as if nextregisters were written? That way I will keep all that memory related stuff there, as it's not clear if it is needed or not (and I will never figure it out).

Sending the entry bank number to the tbblue_out_port_32765 is wrong, that port doesn't accept full 8 bit bank number, but includes ROM selection/etc IIRC, so that's another issue with load_nex_snapshot implementation.

OnceBitten commented 2 months ago

Thank you for your informative responses, and also for tracking down the bug. So the 16KiB-bank number 77 was masked with 7, surprisingly, resulting in the incorrect entry bank 5. I will follow your advice, set up both ZESARUse and CSpect - the latter appears to be essential for cross-platform development at this time - and if and when I find an interesting bug, upload it to MrKWatkins' GitHub page.

ped7g commented 2 months ago

nah, the test suite is not about bugs, it's about tests used to check the behaviour. I depend strongly on that test suite to verify all that stuff noted on "known bugs" pages, so whenever somebody reports some bug in emulator, but I don't have test, the info gets outdated as there are newer versions of the emulator, as I generally don't care about testing it.

So the more stuff the test suite covers, the more verified newer version of emulators are. :) But writing good tests is not trivial, I'm not even fully happy about the ones which I already wrote, some of them are rather cryptic to "read" while running it, if you are not familiar with what the test does, sometimes even I have to check the txt or source to remember if something works as expected or not. :)

OnceBitten commented 2 months ago

OK, I have been warned: don't underestimate the task of turning a bug into a test for it.

ped7g commented 2 months ago

@OnceBitten I will show the fix (for entry bank in NEX file) to Cesar, maybe he will apply it to vanilla ZEsarUX too. On this fork it's fixed.

OnceBitten commented 2 months ago

Thank you, ped7g.