Jump to content
IGNORED

Using EOR to invert a scanline counter


tschak909

Recommended Posts

Can somebody explain _WHY_ this works?

 

 

        LDA  ScanLine
        BPL  VvRefl             ; If on the bottom half of the screen,
        EOR  #$F8               ; reverse direction so we can mirror.
VvRefl  CMP  #$20
        BCC  VfDone             ; Branch if at bottom.

 

Is it simply a combination of a two-compliment flip, with a corresponding AND mask, as a side effect?

 

-Thom

 

Link to comment
Share on other sites

Sorry, this comes from the combat disassembly, inside the kernel:

 

 

;
; ------------------------------------------------------------
;
; Video OUT -- THE KERNAL
;
; We start with the score, then we render the playfield, players,
; and missiles simultaneously. All in all, an average day for a VCS.
;
VOUT    LDA #$20
    STA ScanLine ; We're assuming scanline $20.
    STA WSYNC
    STA HMOVE ; Move sprites horizontally.
VOUT_VB    LDA INTIM
    BNE VOUT_VB ; Wait for INTIM to time-out.
    STA WSYNC
    STA CXCLR ; Clear collision latches
    STA VBLANK ; End vertical blank
    TSX
    STX TMPSTK ; Save stack pointer
    LDA #$02
    STA CTRLPF ; Double, instead of reflect.
    LDX KLskip
Vskip1 STA WSYNC ; Skip a few scanlines...
    DEX
    BNE Vskip1
    LDA KLskip
    CMP #$0E ; "No Score" value of KLskip
    BEQ Vmain
    ;
    ; KLskip is set as such so that when the score is
    ; to be displayed, it waits for just the right time
    ; to start drawing the score, but if the score is
    ; not to be displayed, as when the score flashes
    ; signifying "time's almost up", it waits for just
    ; the right time to start drawing the rest of the
    ; screen.
    ;
    ; Draw the score:
    ;
    LDX #$05      ; Score is five bytes high.
    LDA #$00 ; Clear number graphics.
    STA NUMG0 ; They won't be calculated yet,
    STA NUMG1 ; but first time through the loop
         ; the game will try to draw with
         ; them anyway.
VSCOR    STA WSYNC ; Start with a fresh scanline.
    LDA NUMG0 ; Take last scanline's left score,
    STA PF1 ; and recycle it,
    ;
    ; Here, we begin drawing the next scanline's
    ; left score, as the electron beam moves towards
    ; the right score's position in this scanline.
    ;
    LDY SCROFF+2
    LDA NUMBERS,Y ; Get left digit.
    AND #$F0
    STA NUMG0
    LDY SCROFF
    LDA NUMBERS,Y ; Get right digit.
    AND #$0F
    ORA NUMG0
    STA NUMG0 ; Left score is ready to ship.
    LDA NUMG1 ; Take last scanline's right score,
    STA PF1 ; and recycle it.
    LDY SCROFF+3
    LDA NUMBERS,Y ; Left digit...
    AND #$F0
    STA NUMG1
    LDY SCROFF+1
    LDA NUMBERS,Y ; right digit...
    AND SHOWSCR
    ;
    ; Now, we use our fresh, new score graphics in this next scanline.
    ;
    STA WSYNC ; *COUNT*
    ORA NUMG1 ;Finish calculating (0) +3
    STA NUMG1 ;right score. (3) +3
    LDA NUMG0 ; (6) +3
    STA PF1 ; *9* +3
    ;
    ; We use this time to check whether we're at the end of our loop.
    ;
    DEX ; (12)+2
    BMI Vmain ; (14)+2 No Branch
    ;
    ; If so, we're out of here. Don't worry, the score will be
    ; cleared immediately, so nobody will know that we've gone
    ; past five bytes and are displaying garbage.
    ;
    INC SCROFF ; (16)+5
    INC SCROFF+2 ; Get ready to draw the next
    INC SCROFF+1 ; line of the byte.
    INC SCROFF+3
    LDA NUMG1
    STA PF1 ; Right score is in place.
    JMP VSCOR ; Go to next scanline,
    ;
    ; Main Kernal Display loop for the game itself
    ;
Vmain    LDA #$00 ; Inner Display Loop
    STA PF1 ; Clear the score.
    STA WSYNC
    LDA #$05
    STA CTRLPF ; Reflecting playfield.
    LDA Color0
    STA COLUP0 ; How often must THIS be done?
    LDA Color1
    STA COLUP1
Vfield    LDX #$1E ; Very Sneaky -
    TXS ; Set stack to missile registers
    SEC
    ;
    ; This yields which line of player 0 to draw.
    ;
    LDA TankY0
    SBC ScanLine ; A=TankY0-ScanLine
    AND #$FE ; Force an even number
    TAX ; Only sixteen bytes of
    AND #$F0 ; sprite memory, so...
    BEQ VdoTank ; If not valid,
    LDA #$00 ; blank the tank.
    BEQ VnoTank ; (unconditional branch)
VdoTank LDA HIRES,X ; Else, load the appropriate byte.
VnoTank STA WSYNC ; ----END OF ONE LINE----
    STA GRP0 ; Just for player 0.
    ;
    ; The infamous Combat Stack Trick:
    ;
    ; Keep in mind that at this point, the stack pointer
    ; is set to the missile registers, and the "zero-result"
    ; bit of the P register is the same at the bit ENAM0/1
    ; looks at.
    ;
    LDA MissileY1
    EOR ScanLine
    AND #$FE
    PHP ; This turns the missle 1 on/off
    LDA MissileY0
    EOR ScanLine
    AND #$FE
    PHP ; This turns the missle 0 on/off
    ;
    ; We've got the missile taken care of.
    ; Now let's see which line of the playfield to draw.
    ;
    LDA ScanLine
    BPL VvRefl ; If on the bottom half of the screen,
    EOR #$F8 ; reverse direction so we can mirror.
VvRefl    CMP #$20
    BCC VfDone ; Branch if at bottom.
    LSR
    LSR
    LSR ; Divide by eight,
    TAY ; and stow it in the Y-register.
    ;
    ; By now, the electron beam is already at the next
    ; scanline, so we don't have to do a STA WSYNC.
    ;
    ; This yields which line of Tank 1 to draw.
    ;
VfDone    LDA TankY1 ; TankY1 is other player's position.
    SEC
    SBC ScanLine ; A=TankY1 - ScanLine
    INC ScanLine ; Increment the loop.
    NOP
    ORA #$01 ; Add bit 0, force odd number.
    TAX
    ;
    AND #$F0 ; There are only sixteen bytes of
    BEQ VdoT1 ; sprite memory, so...
    LDA #$00 ; If tank is not ready, blank it.
    BEQ VnoT1
VdoT1 LDA HIRES,X ; Else, draw the tank
VnoT1 BIT PF_PONG
    STA GRP1
    BMI VnoPF ; If PF_PONG bit 7 set, don't write PF
    LDA (LORES),Y ; (this means game variation has blank
    STA PF0 ; background)
    LDA (LORES+2),Y
    STA PF1
    LDA (LORES+4),Y
    STA PF2
VnoPF    INC ScanLine ; One more up in the loop.
    LDA ScanLine
    EOR #$EC ; When we've reached the $ECth line,
    BNE Vfield ; we've had enough.
    LDX TMPSTK ; Restore stack pointer, which is
    TXS ; is used for calls in main game loop
    STA ENAM0 ; Clear a bunch of registers.
    STA ENAM1
    STA GRP0
    STA GRP1
    STA GRP0 ; In case GRP0 isn't COMPLETELY zeroed.
    STA PF0
    STA PF1
    STA PF2
    RTS 
Link to comment
Share on other sites

Apparently the maps for Combat are into ROM but only the top half, once the scanline count reaches half of screen, the EOR changes index so the half map is put out in reverse order.

 

Note how the value is put into Y register and later read indexed to put in playfield registers.

Link to comment
Share on other sites

Yes, that's what I'm understanding, the key instruction is the EOR #$F8 ... my question is _why_ ... it keeps the bottom three bits untouched, which...makes me believe it's a two's compliment/mask combo.

 

-Thom

That depends on the programmer style. It can be $F8, $FC, $FE or $FF because when dividing by 8 the lower 3 bits are lost. Only the top 5 bits matter, changing $00-$1f to $1f-$00 (after divide)

Link to comment
Share on other sites

Without knowing anything about the VCS here is my take:

 

 

At the bit level on any bit (B here is the value of that bit) the XOR truth table is like this:

1) B XOR 1 = NOT B

2) B XOR 0 = B

 

With F8 (11111000) as you notice the lower 3 bits are left untouched because of rule 2 above, the higher 5 bit are instead negated/inverted by rule 1 (the operation is also called 1-complement and not 2-complement).

 

 

Feel free to skip this next part if irrelevant to you, I just write it for completeness.

2-complements has meaning only on signed quantities and in that setting can be implemented by first negating everything (XOR FF) then adding 1, this sequence will return the negative form of any positive number < 128.

 

For example if you want to obtain -1 from 1 in 2-complement you have to go thru the steps:

Value = 00000001

/Value = 11111110

+1 = 11111111

 

so FF is the representation of -1 (quick way for me to remember how to read signed quantities is to invert the value of bit 7, example unsigned FF = 128 + 64 + 32 + ..... + 1 = 255 but for signed FF = -128 + 64 + 32 .... = -1 [and this is the 2-complement representation of -1 in 8 bits]

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...