; (C) copyright 2023 Peter Ped Helcmanovsky, license: MIT
; name: Test keyboard and Sinclair Joystick reading on all-key/specific ULA ports
; public git repo: https://github.com/MrKWatkins/ZXSpectrumNextTests/
;
; history: 2023-04-19: v1.0 - initial version
;
; purpose: to confirm the observed behaviour of several +2 machines:
;   code `xor a : in a,(254)` does NOT see the Sinclair joystick 1/2 presses on grey +2 model!
; to assemble (with z00m's sjasmplus https://github.com/z00m128/sjasmplus/ v1.20.2+)
; run: sjasmplus ulavssjs.asm
;
; screen results:
; - shows live readings of three ports: 0x00FE (all keys), 0xEFFE (keys 67890), 0xF7FE (keys 54321)
;   (reading all of them twice to see if the state didn't change in those ~120T, re-reads if yes)
; - if ever the press read from EFFE or F7FE is missing in 00FE
;   the extra message "difference detected" is displayed
;   this means the SJS joystick sends results only to specific EFFE or F7FE port, but not into full
;   matrix reading on port 00FE
;
; memory setup:
; - CLEAR $7FFF, entry point $8000, disabled interrupt, using BASIC loader stack
;

    DEFINE SNA_FILENAME "ULAvsSJS.sna"
    DEFINE TAP_FILENAME "ULAvsSJS.tap"
    DEFINE TRD_FILENAME "ULAvsSJS.trd"
    OPT --syntax=abf
    DEVICE zxspectrum48, $7FFF

ROM_ATTR_P: EQU     $5C8D
ROM_CLS:    EQU     $0DAF
ROM_PRINT:  EQU     $203C
ATTR_00FE:  EQU     $5800 + 3*32 + 12
ATTR_F7FE:  EQU     $5800 + 4*32 + 12
ATTR_EFFE:  EQU     $5800 + 5*32 + 12
ATTR_DIFF:  EQU     $5800 + 7*32

    ORG     $8000
code_start:
        ld      a,7<<3
        ld      (ROM_ATTR_P),a  ; ATTR-P = PAPER 7 : INK 0 : BRIGHT 0 : FLASH 0
        call    ROM_CLS
        ld      de,head_txt     ; print all texts on screen
        call    print_FFstr
    ; start live reading of inputs and evaluating the weirdness on +2 joysticks
main_loop:
        di
    ; read all ports twice in succession into registers [A,H,L] vs [C,D,E]
        ld      bc,$00FE
        in      a,(c)
        ld      bc,$EFFE
        in      h,(c)
        ld      bc,$F7FE
        in      l,(c)
        ld      bc,$EFFE
        in      d,(c)
        ld      bc,$F7FE
        in      e,(c)
        ld      bc,$00FE
        in      c,(c)
    ; check if all port readings didn't change between, restart reading if they did
        xor     c
        and     $1F
        jr      nz,main_loop
        ld      a,h
        xor     d
        and     $1F
        jr      nz,main_loop
        ld      a,l
        xor     e
        and     $1F
        jr      nz,main_loop
    ; C = 00FE, D = EFFE, E = F7FE value, display it live
        ld      a,c
        ld      hl,ATTR_00FE
        call    display_pressed
        ld      a,d
        ld      hl,ATTR_EFFE
        call    display_pressed
        ld      a,e
        ld      hl,ATTR_F7FE
        call    display_pressed
    ; evaluate if the weird difference between readings is present, then uncover extra message
        ld      a,c
        and     $1F
        ld      c,a         ; 00FE reading without extra top bits
        and     d           ; all zero bits in EFFE should be also zero in 00FE
        cp      c
        jr      nz,show_difference_txt
        ld      a,c
        and     e           ; all zero bits in F7FE should be also zero in 00FE
        cp      c
        jr      z,main_loop
    ; weird difference detected (reading from SJS port not visible in 00FE), uncover message
show_difference_txt:
        ld      hl,ATTR_DIFF
        ld      bc,$1755    ; bright-red-cyan, 23x
.loop:  ldi     (hl),c      ; fake
        djnz    .loop
        jr      main_loop

; A = port value, HL = attribute address for b0, destroys B, HL, AF
display_pressed:
        ld      b,5
.loop:
        rra
        push    af
        sbc     a,a         ; $FF released, $00 pressed
        and     %01'111'111 ; convert it to bright-white-white for released
        or      %01'010'101 ; and bright-red-cyan for pressed
        ldd     (hl),a      ; fake
        pop     af
        djnz    .loop
        ret

; print string terminated by $FF (and having all chars -1) from DE address
print_FFstr.loop:
        rst     $10
print_FFstr:
        ld      a,(de)
        inc     de
        cp      $FF
        jr      nz,.loop
        ret

head_txt:
        DB      "v1.0 2023-04-19 Ped7g",13,13
        DB      "Reading keyboard ports:",13
        DB      "0x00FE: ##### (whole 8x5 matrix)",13
        DB      "0xF7FE: ##### (54321)",13
        DB      "0xEFFE: ##### (67890)",13,13
        DB      $10,7,"  difference detected",13  ; INK 7 to hide this
        DB      $FF

code_end:
    ;; produce SNA file with test code
        SAVESNA SNA_FILENAME, code_start

    ;; produce TAP file with the test code
CODE        EQU     $AF
USR         EQU     $C0
LOAD        EQU     $EF
CLEAR       EQU     $FD
RANDOMIZE   EQU     $F9
REM         EQU     $EA

        DEFINE prog_name "ULAvsSJS"

        ;; 10 CLEAR 32767:LOAD  "ULAvsSJS"CODE
        ;; 20 RANDOMIZE USR 32768
        ORG     $5C00
tap_bas:
        DB      0,10    ;; Line number 10
        DW      .l10ln  ;; Line length
.l10:   DB      CLEAR,"32767",$0E,0,0
        DW      code_start-1
        DB      0,':'
        DB      LOAD," \""
.fname: DB      prog_name
        ASSERT  ($ - .fname) <= 10
        DB      '"',CODE,$0D
.l10ln: EQU     $-.l10
        DB      0,20    ;; Line number 20
        DW      .l20ln
.l20:   DB      RANDOMIZE,USR,"32768",$0E,0,0
        DW      code_start
        ASSERT  32768 == code_start
        DB      0,$0D
.l20ln: EQU     $-.l20
        DB      0,99    ;; Line number 99
        DW      .l99ln
.l99:   DB      REM,"https://github.com/MrKWatkins/ZXSpectrumNextTests/\r"
.l99ln: EQU     $-.l99
.l:     EQU     $-tap_bas

        EMPTYTAP TAP_FILENAME
        SAVETAP  TAP_FILENAME,BASIC,prog_name,tap_bas,tap_bas.l,1
        SAVETAP  TAP_FILENAME,CODE,prog_name,code_start,code_end-code_start,code_start

    ;; produce TRD file with the test code

        ;; 10 CLEAR 32767:RANDOMIZE USR 15619:REM:LOAD "ULAvsSJS"CODE
        ;; 20 RANDOMIZE USR 32768
        ORG     $5C00
trd_bas:
        DB      0,10    ;; Line number 10
        DW      .l10ln  ;; Line length
.l10:   DB      CLEAR,"32767",$0E,0,0
        DW      code_start-1
        DB      0,':'
        DB      RANDOMIZE,USR,"15619",$0E,0,0
        DW      15619
        DB      0,':',REM,':',LOAD,'"'
.fname: DB      prog_name
        ASSERT  ($ - .fname) <= 8
        DB      '"',CODE,$0D
.l10ln: EQU     $-.l10
        DB      0,20    ;; Line number 20
        DW      .l20ln
        ASSERT  32768 == code_start
.l20:   DB      RANDOMIZE,USR,"32768",$0E,0,0
        DW      code_start
        DB      0,$0D
.l20ln: EQU     $-.l20
        DB      0,99    ;; Line number 99
        DW      .l99ln
.l99:   DB      REM,"https://github.com/MrKWatkins/ZXSpectrumNextTests/\r"
.l99ln: EQU     $-.l99
.l:     EQU     $-trd_bas

        EMPTYTRD TRD_FILENAME
        SAVETRD  TRD_FILENAME,"boot.B",trd_bas,trd_bas.l,10
        SAVETRD  TRD_FILENAME,"ULAvsSJS.C",code_start,code_end-code_start
