• How did Treasure Island work?

    From Groo Vee@21:1/5 to All on Thu Jul 16 00:29:23 2020
    There was a game, I'm _99%_ certain it was called Treasure Island, which had the top half of the screen blue and the bottom black (or maybe it was the other way around) INCUDING THE BORDER!! ie. the ENTIRE SCREEN'S TOP HALF was blue!!! This continued
    WHILE YOU PLAYED THE GAME!!!!!! It blew my mind at the time, so today, so many years later, I'd love to know how the HELL they pulled that off? What's going on?


    Thanks.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Volker Bartheld@21:1/5 to Groo Vee on Thu Jul 16 12:30:12 2020
    On Thu, 16 Jul 2020 00:29:23 -0700 (PDT), Groo Vee wrote:
    There was a game, I'm _99%_ certain it was called Treasure Island, which
    had the top half of the screen blue and the bottom black (or maybe it
    was the other way around) INCUDING THE BORDER!! ie. the ENTIRE SCREEN'S
    TOP HALF was blue!!! This continued WHILE YOU PLAYED THE GAME!!!!!! It
    blew my mind at the time, so today, so many years later, I'd love to
    know how the HELL they pulled that off? What's going on?

    Maskable interrupt handler [1], typically of the IM2 type (vectored
    interrupt) where - as opposed to the first example in [1] - the complete
    table is filled with #FEFE, so your interrupt handler always starts at
    address #FEFE, no matter what lower byte is provided by the "peripheral
    device" on the bus (since there usually is none or some Kempston joystick interface producing garbage).

    At #FEFE you would then have

    ORG #FEFE
    ; no need to di, Z80 does this automatically
    push af ; save carry flag
    push bc ; save bc register

    set border to blue

    ld a,#01 ; blue border
    out (#FE),a ; change color

    and wait a multiple of 48+176=224 T-States [2]

    ld bc,6408h
    wait: nop ; 4T
    nop ; 4T
    nop ; 4T
    dec bc ; 6T
    jp nc, wait ; 10T
    ; 28T for each loop, so 8 iterations gets you down one scan line

    then change the border color to black

    ld a,00h ; black border
    out (FEh),a ; change color

    , restore the registers and return from the interrupt handler

    pop bc ; restore bc
    pop af ; restore af
    ei ; re-enable interrupts
    reti ; return

    Hint: Don't ever use HALT in an interrupt handler and stay away from
    contended memory (everything below #8000 is managed by the ULA). Have a
    look at R. Zak's book "Programming the Z80" for details on machine code
    timing [3].

    Of course the example above is far from perfect (needs some nudging back
    and forth to perfectly syncronize with the start of a scanline, you could
    use OUTI/OTIR for even crazier stuff) and you can do this not only to the border, but also the attribute area (using LDI/LDIR), getting you
    multicolored attributes that overcome the 8x8 pixel limit.

    This is what I wrote, decades ago. It even returns you to ZX BASIC with the highres attributes on.

    10 CLEAR 65369
    20 LET d=65370
    30 FOR a=1 TO 33
    40 LET c=0
    50 READ a$
    60 READ check
    70 FOR e=1 TO 10 STEP 2
    80 LET b=(CODE a$(e)-48-(7 AND CODE a$(e)>57))*16
    90 LET b=b+CODE a$(e+1)-48-(7 AND CODE a$(e+1)>57)
    100 PRINT AT 10,0;d,b,: POKE d,b: LET d=d+1: LET c=c+b: NEXT e
    110 IF d>65535 THEN GO TO 160
    120 IF c<>check THEN PRINT "CHECKSUMERROR IN LINE ";(a-1)*10+9000: LET f=(a-1)*10+9000: LIST f: STOP
    130 NEXT a
    140 CLS : PRINT "HIGHRESOLUTION COLOUR ATTRIBUTES"'''
    150 PRINT "START:",65370'"LENGTH:",166'"INTERRUPT ON:",65370'"INTERRUPT OFF:",65384'''"LABELS:"'"STARTLN:",65393;" L=1"'"DEPTH:",65394;" L=1"'"HIATT:",65395;" L=2"'"IHANDLE:",65524
    160 STOP
    170 SAVE *"m";1;"HIGHRES-I"CODE 65370,166: VERIFY *"m";1;"HIGHRES-I"CODE
    180 STOP
    9000 DATA "F321FFFF36",840
    9010 DATA "183E3BED47",453
    9020 DATA "ED5EFBC9F3",1026
    9030 DATA "3E3FED47ED",670
    9040 DATA "56FBC90018",562
    9050 DATA "0000000000",0
    9060 DATA "00C5D5E5F5",884
    9070 DATA "ED7375FF31",773
    9080 DATA "79FF011802",403
    9090 DATA "0B78B120FB",591
    9100 DATA "3A71FF8787",696
    9110 DATA "87CAA0FF06",758
    9120 DATA "0F10FE0000",285
    9130 DATA "C83DC295FF",859
    9140 DATA "6F3A71FF67",640
    9150 DATA "CB3CCB1DCB",698
    9160 DATA "3CCB1DCB3C",555
    9170 DATA "CB1D110C58",349
    9180 DATA "19EB2A73FF",672
    9190 DATA "3A72FF0140",492
    9200 DATA "00D5EDA0ED",847
    9210 DATA "A0EDA0EDA0",954
    9220 DATA "EDA0EDA0ED",1031
    9230 DATA "A0EDA0D1E2",992
    9240 DATA "DBFF180000",498
    9250 DATA "E6FF18E4EB",972
    9260 DATA "0E2009EB3D",351
    9270 DATA "C2BCFFED7B",997
    9280 DATA "75FFF1E1D1",1047
    9290 DATA "C1FBC33800",695
    9300 DATA "00000000F3",243
    9310 DATA "C379FF0000",571
    9320 DATA "0000000000",0
    9330 DATA "0000000000",0
    9340 DATA "0000000000",0

    which disassembles as (no warrantee, no comments):

    ORG 0FF5Ah

    DI
    LD HL,0FFFFh
    LD (HL),18h
    LD A,3Bh
    LD I,A
    IM 2
    EI
    RET

    LFF68: DI
    LD A,3Fh
    LD I,A
    IM 1
    EI
    RET

    LFF71: NOP
    LFF72: JR LFF74

    LFF74: NOP
    LFF75: NOP
    NOP
    NOP
    NOP
    LFF79: PUSH BC
    PUSH DE
    PUSH HL
    PUSH AF
    LD (LFF75),SP
    LD SP,0FF79h
    LD BC,0218h
    LFF87: DEC BC
    LD A,B
    OR C
    JR NZ,LFF87
    LD A,(LFF71)
    ADD A,A
    ADD A,A
    ADD A,A
    JP Z,LFFA0
    LFF95: LD B,0Fh
    LFF97: DJNZ LFF97
    NOP
    NOP
    RET Z
    DEC A
    JP NZ,LFF95
    LFFA0: LD L,A
    LD A,(LFF71)
    LD H,A
    SRL H
    RR L
    SRL H
    RR L
    SRL H
    RR L
    LD DE,580Ch
    ADD HL,DE
    EX DE,HL
    LD HL,(LFF72+1)
    LD A,(LFF72)
    LFFBC: LD BC,0040h
    LFFBF: PUSH DE
    LDI
    LDI
    LDI
    LDI
    LDI
    LDI
    LDI
    LDI
    POP DE
    JP PO,LFFDB
    JR LFFD6

    LFFD6: NOP
    AND 0FFh
    JR LFFBF

    LFFDB: EX DE,HL
    LD C,20h
    ADD HL,BC
    EX DE,HL
    DEC A
    JP NZ,LFFBC
    LD SP,(LFF75)
    POP AF
    POP HL
    POP DE
    POP BC
    EI
    JP 0038h

    LFFF0: NOP
    NOP
    NOP
    NOP
    DI
    JP LFF79

    Also,

    https://www.youtube.com/watch?v=eGDLdf3nZL0 https://www.youtube.com/watch?v=wE1KylKQDrQ https://www.youtube.com/watch?v=79sg7UE6KAA https://www.youtube.com/watch?v=VB3mDqGgBag

    should give you a good impression of what is possible.

    HTH,
    Volker

    [1] https://codersbucket.blogspot.com/2015/04/interrupts-on-zx-spectrum-what-are.html
    [2] http://www.zxdesign.info/interrupts.shtml
    [3] http://www.z80.info/zaks.html

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chupo@21:1/5 to All on Thu Aug 27 05:08:35 2020
    In article <csj6yfu76aqj.dlg@news.bartheld.net>, Volker Bartheld <news2020@bartheld.net> says...
    https://www.youtube.com/watch?v=eGDLdf3nZL0 https://www.youtube.com/watch?v=wE1KylKQDrQ https://www.youtube.com/watch?v=79sg7UE6KAA https://www.youtube.com/watch?v=VB3mDqGgBag

    should give you a good impression of what is possible.


    I checked the videos because I find IM 2 routines very interesting and
    was surprised to see the IM 2 routine from the 1st video was by me :-)

    From your code I see you are using the same trick by placing interrupt
    vector in the ROM where all bytes are #FF and putting the opcode of the
    JR instruction (#18) at #FFFF which then takes byte #F3 (opcode of DI
    at address #0000) as relative jump offset of -13 and after:

    JR $-13

    the program continues at 65524 (#FFF4).

    The only difference is you load I register with #3B and I've been
    always using #39 where there are RST #38s (#FFs) too.

    This is how I've been setting up IM 2:

    di
    ld a,#39
    ld i,a
    ei
    ret

    org #fff4
    jp int_addr

    org #ffff
    defb #18
    --
    Let There Be Light
    Custom LED driveri prema specifikacijama
    http://tinyurl.com/customleddriver

    Chupo

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Volker Bartheld@21:1/5 to Chupo on Thu Aug 27 08:02:08 2020
    On Thu, 27 Aug 2020 05:08:35 +0200, Chupo wrote:
    In article <csj6yfu76aqj.dlg@news.bartheld.net>, Volker Bartheld <news2020@bartheld.net> says...
    https://www.youtube.com/watch?v=eGDLdf3nZL0
    https://www.youtube.com/watch?v=wE1KylKQDrQ
    https://www.youtube.com/watch?v=79sg7UE6KAA
    https://www.youtube.com/watch?v=VB3mDqGgBag
    should give you a good impression of what is possible.
    [Spectrum and IM 2] From your code I see you are using the same trick by placing interrupt vector in the ROM where all bytes are #FF and putting
    the opcode of the JR instruction (#18) at #FFFF which then takes byte
    #F3 (opcode of DI at address #0000) as relative jump offset of -13 and
    after: JR $-13 the program continues at 65524 (#FFF4).

    That's 100% correct. I found this a very obvious and straightforward
    approach, given the fact that the lower half of the IM 2 jump location is provided by the ZX Spectrum's bus, which could be anything at that time.
    Saves you a table of 256 useless Bytes in precious RAM.

    Greets,
    Volker

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)