Jump to content
pojr

Why can't the Atari 2600 display better graphics?

Recommended Posts

Or if you can trash X, use just 1 routine and save a byte of ram...

    lax     SWCHA                ;4  @4
    eor     lastTrack            ;3  @7
    stx     lastTrack            ;3  @10
    cmp     #$3F                 ;2  @12   carry set if Y axis changed
    and     #$30                 ;2  @14
    bne     .changeX             ;2³ @16/17
    nop                          ;2  @18
    .byte $A5  ; LDA zp, 3 cycles
.changeX:
    pla                          ;4  @21
    bcs     .changeY             ;2³ @23/24

    .byte $EE  ; INC absolute, 6 cycles
.changeY:
    inc     diffY                ;5  @29   "diffY" must also be high address of rom space

Share this post


Link to post
Share on other sites

Oops, made an error. :ponder:

 

New code attached. It takes 28 cycles. The code could be reduced, but right now I'm just looking at cycles. :)

    lax     SWCHA                ;4  @4
    eor     lastTrack            ;3  @7
    stx     lastTrack            ;3  @10
    cmp     #$3F                 ;2  @12       carry set if Y axis changed
    and     #$30                 ;2  @14
    bcc     .testX               ;2³ @16/17    Y not changed, see if X has 
    bne     .moveXY              ;2³ @18/19
;moveY
    nop                          ;2  @20
    inc     diffY                ;5  @25
    bcs     .endTrack            ;3  @28       always branch

.noChange:
    dec     $6E                  ;5  @25       waste 5 cycles
    bcc     .endTrack            ;3  @28       always branch

.testX:
    beq     .noChange            ;2³ @19/20
    nop                          ;2  @21
    bne     .moveX               ;3  @24       always branch

.moveXY:
    inc     diffY                ;5  @24
.moveX:
    pla                          ;4  @28
.endTrack:

Share this post


Link to post
Share on other sites

Cool. I bet I can tweak Stella and my LCD to come real close to what a CRT does. Thing is real CRT blooms vertically too. And the Blargg effects in Stella don't do that very well. I can always pull out the big guns and play with the MagicBrite settings on one of my older monitors.

I think you will find that higher quality CRT monitors (like those found in arcade cabs) do not bloom as much. The "blooming" is caused by consumer grade CRTs containing undersized power caps in the CRT yoke, or an insufficient power supply. Commercial monitors are overbuilt with components whose specs actually exceed normal usage conditions and tend not to exhibit blooming effects. Basically the CRT pulls more load as the display brightens, causing a temporary Vdrop on the beam and the horizontal and vertical positioning, causing the screen to grow or shrink. It can be especially annoying when the game has whole rows on screen that are white or black, with a vertical border that actually distorts on it's way up and down the sides. Blooming can be observed in games like Pacman on my NES when the blue maze flashes white at the end of the stage, the whole board shrinks and expands. Aging capacitors within the CRT yoke slowly drying over time likely do not help the cause.

Share this post


Link to post
Share on other sites

Cool stuff, Omegamatrix! :thumbsup:

 

Today I had a brief look at Milipede (CCE proto) and Centipede. In the former, the kernel is always very busy. So this probably won't work. But in Centipede, I found enough free CPU time (after a little bit of optimizing) for two routines which check X and Y direction every 9 lines.

 

The major problem now is, that there is no RAM free (using extra RAM is lame :)). I can get 1 byte from the x-axis acceleration code, but I need at least 4 more. Fortunately 4 bytes are only temporarily used, so probably I can share them with something else.

Share this post


Link to post
Share on other sites

Cool stuff, Omegamatrix! :thumbsup: Today I had a brief look at Milipede (CCE proto) and Centipede. In the former, the kernel is always very busy. So this probably won't work. But in Centipede, I found enough free CPU time (after a little bit of optimizing) for two routines which check X and Y direction every 9 lines. The major problem now is, that there is no RAM free (using extra RAM is lame :)). I can get 1 byte from the x-axis acceleration code, but I need at least 4 more. Fortunately 4 bytes are only temporarily used, so probably I can share them with something else.

I disassembled both Millipedes long ago. Maybe you can use at least one of them:

 

Millipedes (Omegamatrix).zip

 

I also realize now that the load can be nicely spread a little bit into two 17 cycle chunks, which might be better. The problem is the carry can't change before "line 2", and you need another ram register. I suppose if you want to bring it to 19 cycles each, then a simple ROL in line 1 and LSR in line 2 would preserve the carry (if that's a problem).

;line 1
    lax     SWCHA                ;4  @4
    eor     lastTrack            ;3  @7
    stx     lastTrack            ;3  @10
    cmp     #$3F                 ;2  @12       carry set if Y axis changed
    and     #$30                 ;2  @14
    sta     temp                 ;3  @17




;line 2, assuming carry has not changed..
    lda     temp                 ;3  @3
    bcc     .testX               ;2³ @5/6    Y not changed, see if X has
    bne     .moveXY              ;2³ @7/8
;moveY
    nop                          ;2  @9
    inc     diffY                ;5  @14
    bcs     .endTrack            ;3  @17       always branch

.noChange:
    dec     $6E                  ;5  @14       waste 5 cycles
    bcc     .endTrack            ;3  @17       always branch

.testX:
    beq     .noChange            ;2³ @8/9
    nop                          ;2  @10
    bne     .moveX               ;3  @13       always branch

.moveXY:
    inc     diffY                ;5  @13
.moveX:
    pla                          ;4  @17
.endTrack:

Share this post


Link to post
Share on other sites

If the carry proves to be a problem as noted in post 130 above, then this might work better. It's a 17/19 split instead of 19/19, but does require 1 more variable for the kernel (4 total).

;line 1
    lax     SWCHA                ;4  @4
    eor     lastTrack            ;3  @7
    stx     lastTrack            ;3  @10
    cmp     #$3F                 ;2  @12       carry set if Y axis changed
    and     #$30                 ;2  @14
    php                          ;3  @17




;line 2
    plp                          ;4  @4
    bcc     .testX               ;2³ @6/7      Y not changed, see if X has
    bne     .moveXY              ;2³ @8/9
;moveY
    inc     diffY                ;5  @13
.noChange:
    nop     $EA                  ;3  @13/16
    bcs     .endTrack            ;3  @16/19
    bcc     .endTrack            ;3  @19       always branch

.testX:
    beq     .noChange            ;2³ @9/10
    nop                          ;2  @11
    bne     .moveX               ;3  @14       always branch

.moveXY:
    inc     diffY                ;5  @14
.moveX:
    inc     diffX                ;5  @19
.endTrack:

Thomas, whatever you do I hope you expand the rom and put in a screen at the beginning for the user to spin the trackball, and auto-detect which one it is. IMHO that adds a nice touch and would be more user-friendly then multiple versions.

Share this post


Link to post
Share on other sites

I had another idea. This reduces the "line 2" of the routine to only 14 cycles. You don't have to worry about the state of the carry in between lines 1 and 2. Lines 1 and 2 can be far apart too.

;line 1
    lax     SWCHA                ;4  @4
    eor     lastTrack            ;3  @7
    stx     lastTrack            ;3  @10
    cmp     #$3F                 ;2  @12       carry set if Y axis changed
    and     #$30                 ;2  @14
    php                          ;3  @17




;line 2
    pla                          ;4  @4
    and    #$03                  ;2  @6
    tax                          ;2  @8     bit1 = X, bit0 = Y
    inc    diff,X                ;6  @14    increments 1 of 4 states, parse out movement later

It costs 2 more bytes of ram, but it's quick. :)

 

 

Edit: Just thought about it some more, and the first diff register we don't care about, so it can be shared as the register used for PHP/PLA, or the temp "lastTrack" register (since SWCHA has the 4 bottom bits set to output). Either way that frees up 1 ram register.

Share this post


Link to post
Share on other sites

Revisiting the idea of doing everything at once, I found it can be shaved down to 26 cycles total:

    lax    SWCHA                 ;4  @4
    eor    lastTrack             ;3  @7
    stx    lastTrack             ;3  @10
    cmp    #$3F                  ;2  @12       carry set if Y axis changed
    and    #$30                  ;2  @14
    bcc    .testX                ;2³ @16/17    Y not changed, see if X has 
    beq    .changeY              ;2³ @18/19
    inc    diff_XY               ;5  @23       both axises have changed...
    bcs    .endTrack             ;3  @26       always branch
    
.changeY:
    pla                          ;4  @23       sp = diffY
    bcs    .endTrack             ;3  @26       always branch

.noChange:
    beq    .waste3               ;3  @23       always branch
.waste3:
    beq    .endTrack             ;3  @26       always branch
    
.testX:
    beq    .noChange             ;2³ @19/20
    nop                          ;2  @21
    inc    diffX                 ;5  @26
.endTrack:

There's only 3 temp variables used, but it does trash the SP and X register. However since it only takes 26 cycles and it is handling both axises at once, that's not bad. You just have to add diff_XY to both diffX and diffY(SP) after the kernel and you've got your counts.

Share this post


Link to post
Share on other sites

I have a 24 cycle solution now. It updates both axises in 24 cycles. It requires an entire page for a lookup table, but with an expanded rom that's no problem. It uses 4 temp registers (lastTrack can be doubled up with the first diff register, I think).

    lax    SWCHA                 ;4  @4
    eor    lastTrack             ;3  @7
    stx    lastTrack             ;3  @10
    tax                          ;2  @12
    lda    RegisterTab,X         ;4  @16
    tax                          ;2  @18
    inc    diff,X                ;6  @24


RegisterTab:
    .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    .byte 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    .byte 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    .byte 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    .byte 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    .byte 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    .byte 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    .byte 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3

As before there is one register set when both axises have changed, so after the kernel you would have to extract the true count:

diff        ds 4
lastTrack   equ diff     ; this should be okay, lower 4 bits of SWCHA are output and set to 0.
diffX       equ diff+1
diffY       equ diff+2
diff_XY     equ diff+3



    lax    diff_XY
    clc
    adc    diffX
    sta    diffX   ; correct
    txa
    adc    diffY   ; carry should still be clear
    sta    diffY   ; correct

A 22 cycle solution is also possible, but you would have to steal the Y register too, and that's not practical. Here it is anyhow:

    lax    SWCHA                 ;4  @4
    eor    lastTrack             ;3  @7
    stx    lastTrack             ;3  @10
    tay                          ;2  @12
    ldx    RegisterTab,Y         ;4  @16
    inc    diff,X                ;6  @22

Share this post


Link to post
Share on other sites

Thanks for the disassemblies and your ideas.

 

Unfortunately in Centipede, I cannot use SP, because the kernel is heavily loading data from stack.

Share this post


Link to post
Share on other sites

Thanks for the disassemblies and your ideas.

 

Unfortunately in Centipede, I cannot use SP, because the kernel is heavily loading data from stack.

No problem. Well, maybe you can use the solution from post 134 (right above yours) then. I like that solution the best.

Share this post


Link to post
Share on other sites

Success! At least for some of you. ;)

Attached you find a trackball version of Centipede. This only works for the CX-22.

Please do not expect a CX-80 (or Amiga mouse) version soon. The encoding of the CX-22 is different from the CX-80 and this difference (especially the isolated direction bits) allows some shortcuts which juuust made this hack possible.

 

Someone should test this hack on real hardware, because I don't own a CX-22.

Some history:
The Centipede kernel is pretty busy, but finding 20..25 cycles was no major problem. Also freeing up some ROM was not that difficult. The biggest problem was to find enough free RAM because Centipede uses almost every bit of every byte available. The first byte was easy, because that was used for faster x-movement in the old joystick code. Originally I thought I would need three more RAM bytes, but I only found one more which could be used without major impact (game variation selection doesn't work in demo mode anymore).

 

Yesterday, Omegamatrix provided an idea how so save one byte by sharing the last tracking value in one variable. Since I found no third RAM byte, I today decided to share the movement counters for X and Y direction. Since they only have 4 bit each now, they may overrun when you move very fast. and affect each other. But I doubt that will happen a lot.

 

As of now the code tracks both directions in every 9th scan line during the by far most utilized kernel. There are two other kernels, but those are executed only once or twice per frame. If you find the controls not responsive enough, I can try to add the trackball code into those kernels too.

BTW: I have reduced the vertical gun speed by 50%, because IMO that works better. Let me know if you find it too slow

Centipede CX-22 Hack (NTSC) v1.0.bin

  • Like 9

Share this post


Link to post
Share on other sites

Thank you, Thomas!!! I will give this a go tonight after work on real hardware.

 

And thanks to all the contributors who helped figure out how the read the Trak-Ball input efficiently enough to make it work.

 

 

Sent from my iPhone using Tapatalk

  • Like 1

Share this post


Link to post
Share on other sites

Ah, my secret plan is coming together - I've got two of the brightest, most talented minds who currently work in the hobby both thinking about Trak-Ball code following my comment about a "Centipede-TB" ...

 

Now I just need a secret lair under a volcano and an analogous plan to control the world with my burgeoning army of disposable henchmen ...

 

Hey, Thomas and I were discussing this about two weeks ago in a different thread. :)

 

I'm waking up to discover that Trak-Ball implementation for 2600 Centipede seems to have been accomplished without a code hack/rewrite using a DPC or ARM… :) Best news of the morning!

Edited by Lynxpro

Share this post


Link to post
Share on other sites

I am (mainly) looking for the most efficient code for existing ROM like Centipede or Reactor. So only PLA may work.

 

BTW: I regained the extra 2 cycles by using:

  lda #%11000000
  sta SWACNT

This sets the unused lower bits to output, so they never change on reading. That makes masking the bits inside the kernel superfluous.

 

 

Holy shnikes! Reactor is being tested?

 

If you can get 2600 Reactor to work with the Trak-Ball without extra hardware then I guess all previous assumptions are off the table such as both versions of Crystal Castles on A8 not being able to use Trak-Ball because the code is too CPU/kernel intense...

Share this post


Link to post
Share on other sites

Newer technologies are primarily to blame for derezzing Atari 2600 program graphics like the MCP:

post-30777-0-32428600-1441725790_thumb.png

 

Modern television? Check, and it adds a lag to derezz the gameplay too.

Composite mod? Check - goodbye artifacts.

Emulator? Check - goodbye artifacts (a new emulator is in the works so this may change).

Junior with broken TIA? Check, can't play Kool-aid man/handle demo graphics.

 

Paddles are OK :)

 

Share this post


Link to post
Share on other sites

Yesterday I worked on Millipede. I might be able to find cycles for trackball. Not too sure, but maybe 18 samples each axis per frame. I do have a question. Fundamental Main problem is moving many pixels at a time. Collisions have to be updated so that you dont jump over a block. Or should you be allowed to do that? I'm not at home. Is Centipede same as Milipede with blocks in your way?

Share this post


Link to post
Share on other sites

Success! At least for some of you. ;)

 

Attached you find a trackball version of Centipede. This only works for the CX-22.

 

Please do not expect a CX-80 (or Amiga mouse) version soon. The encoding of the CX-22 is different from the CX-80 and this difference (especially the isolated direction bits) allows some shortcuts which juuust made this hack possible.

 

Someone should test this hack on real hardware, because I don't own a CX-22.

 

 

As promised, I tested this tonight with my CX-22. FANTASTIC! It's so much better with the Trak-Ball than it ever was with a joystick. The natural movement and feel of the arcade version are captured perfectly. Incredibly well-done, sir! Bravo.

 

Yesterday I worked on Millipede. I might be able to find cycles for trackball. Not too sure, but maybe 18 samples each axis per frame. I do have a question. Fundamental Main problem is moving many pixels at a time. Collisions have to be updated so that you dont jump over a block. Or should you be allowed to do that? I'm not at home. Is Centipede same as Milipede with blocks in your way?

 

In answer to your question, I played the unaltered original Atari Centipede tonight after playing Thomas's "Centipede CX-22." In both cases, the original and Thomas's, the player cursor can move through the blocks/mushrooms. This is not like the arcade original, of course, nor the 8-bit and 7800 ports. It doesn't really detract from playability. I forgot to test Millipede, however.

Edited by DrVenkman
  • Like 1

Share this post


Link to post
Share on other sites

2600's Millipede "archer" shooter does not collide with the mushrooms.

Moves right through them.

Still a hard game with A+ heart pounding gameplay.

 

 

My average game is lucky to get to 50,000, and one time I went way into 100,000, but have never sent 100,000 since.

I usually take pictures of my high score, but with the 100,000+ one I hit the fire button and wiped it out :mad: !

 

I'd love to have trackball support in Millipede as I like it more than the arcade version.

As for Centipede I like the arcade version more than the 2600, but I am going to try this out.

Share this post


Link to post
Share on other sites

I just got home and tested both Millipede and Centipede. Yeah, in both you do pass through the blocks (or mushrooms?). I don't know why I thought they blocked you. In any case this makes it easier. I will try to find the remaining cycles I need.

Share this post


Link to post
Share on other sites

Centipede CX-22 Hack is a dream to play!

Link_to_post_with_binary_here

Works great, and I didn't notice anything different about firing.

During the death animation the trackball still moves the archer around. It doesn't move around during dying in the joystick version.

 

 

Also I have a CX-80. Happy to know it has the CX-22 output! I got it NIB from e-bay a few years ago. Never knew they made CX-80 Trackballs with 2 different outputs.

I guess that's why I couldn't get 2600 Missile Command CX-80 working. Missile Command CX-22 works with my CX-80 Trackball.

 

Thanks Thomas and Omegamatrix!

Not only did we get a "can't be done" today, we also got a hardly mentioned complete 2600 8K never released 1983 game Arkyology about Noah's Ark!

Quite the historic day, this day after Labor Day 2015!

Edited by iesposta
  • Like 2

Share this post


Link to post
Share on other sites

I guess I never should say never. :)

 

After some more thinking and experimenting, I managed to create CX-80 and Amiga Mouse versions too! I also changed the CX-22 version to use the same code.

 

For those who are interested, here is the main kernel code:

; this polls the trackball every 9 scan lines:
    lda    SWCHA                ; 4
    lsr                         ; 2
    lsr                         ; 2
    lsr                         ; 2
    lsr                         ; 2
    tax                         ; 2
    clc                         ; 2 = 16
    ...
    txa                         ; 2
    ldx    lastTrack            ; 3
    sta    lastTrack            ; 3         0..15
    eor    NextTrackTbl,x       ; 4
    tax                         ; 2 = 14
    ...
    lda    diffXY               ; 3
    adc    AddTrackTbl,x        ; 4         adds $01 for X, $10 for Y
    sta    diffXY               ; 3
    lda    trackDir             ; 4         these are the lower 4 bits of SWCHA!
    ora    DirTrackTbl,x        ; 4         sets direction bits for X and Y
    sta    trackDir             ; 4 = 22    
It is not most efficient in ROM, but it can be spread over multiple scan lines, only uses 20 bits of RAM and works for all three supported controllers. SWACNT is set to %00001111 to be able to use the lower 4 bits as RAM replacement.

 

The resulting positions are updated outside the kernel based on diffXY and trackDir.

Centipede CX-22 Hack v1.1 (NTSC).bin

Centipede CX-80 Hack v1.1 (NTSC).bin

Centipede Amiga Mouse Hack v1.1 (NTSC).bin

  • Like 6

Share this post


Link to post
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.

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...