Jump to content
IGNORED

Introduction: 2600 Programming for Newbies


Recommended Posts

oh, ok, so then I need to use two separate registers, one for the sprite and one for the playfield. Is that right?

Normally you use the same register for the sprite that you do for your scanline counter. That does require the use of zero page pointers for the sprite graphics. In Collect those are Player0Ptr and Player1Ptr.

 

Have you finished going thru the Collect blog series? Later on in the series the X register is replaced with RAM variable ArenaIndex, which would have let you use X like you did. Namely:

 

ArenaLoop:
  tya
  and #%11
  bne SkipX
  inc ArenaIndex <-- this used to be inx
...
  ldx ArenaIndex
  lda ArenaPF0,x
  sta PF0
  ...
Link to comment
Share on other sites

Wow- that's really advanced. Pushing processor status on to the stack? I'm not sure why that would work since all I know is the stack keeps track of addresses for subroutines.

 

Now, if I could only figure out why that ball isn't moving...

The status register holds all of the flags for the processor. When you look in Stella's debugger this is it:

 

post-7074-0-81596000-1449336376_thumb.jpg

 

 

That register holds a bunch of individual bits. A bit can either be 0 or 1 (high or low). The lowercase letters represent 0's, and the uppercase represent 1's. The letter that we are interested in here is the 'z' (z-flag) which when you look at it matches the position of the bit used in the enable registers.

 

post-7074-0-65268100-1449336389_thumb.jpg

 

 

post-7074-0-31326100-1449336922_thumb.jpg

 

 

Pushing the processor reads the contents of the status register and writes it to where the stack pointer is indexed to. If the stack pointer is pointing to the ENABL register ($1F) then the PHP (Push Processor) will set or clear ENABL with its z-flag. The other bits are ignored because the ENAxx register doesn't use them. Also the PHP instruction decrements the stack pointer by 1 each time it's used. So if the stack pointer was pointing at ENABL ($1F) and PHP was used, then the stack pointer would then be pointing at ENAM1 ($1E). This makes it easy to set up a routine that will set ENABL, ENAM1, and ENAM0 sequentially.

 

 

Finally, about the z-flag. It stands for zero flag. It gets set 'Z' or cleared 'z' a few different ways. In this particular example we are concerned with setting or clearing it with a compare instruction. With a compare the z-flag will set when the value compared to matches exactly, and cleared otherwise.

 

Here's a little bit of a code using this trick from a game I'm converting:

; Earlier in the code, set up stack pointer
    ldx    #ENABL
    txs


; Y holds the current scanline
    cpy    ball_Line   
    php              ; ENABL, SP decrements from $1F to $1E (ENAM1)
    cpy    m1_Line
    php              ; ENAM1, SP decrements from $1E to $1D (ENAM0)
    cpy    m0_Line
    php              ; ENAM0, SP decrements from $1D to $1C

By using a few ram registers and throwing this all in a loop, you have a fast way of setting or clearing all the enable registers. If this all seems convoluted just remember you only have 76 cycles per line, and that can fill up quickly. This routine is fast.

  • Like 1
Link to comment
Share on other sites

Thanks.. Its making some sense but:

 

Are you saying some of the locations the stack pointer runs through are registers for graphics and other stuff? I guess I imagined that it only looks at program code locations.

 

I think I have a good idea of the processor status register, but can't grasp why we would have Z the way we wanted for D1 for ENABL.

Link to comment
Share on other sites

The stack pointer can be anywhere from $00 to $FF. Normally use of the stack pointer is to initialize it to a known ram location (usually $FF) and leave it alone. Every time you jump to subroutine (JSR) the return address gets pushed on the stack and the stack pointers decrements for each byte pushed on the stack. The addresses are two bytes, so the stack pointer would go from $FF to $FD when you do a JSR. When you do a return from subroutine (RTS) the address you return to is pulled from the stack. The stack pointer 'points' to the location to get the return address.

 

As to where the stack pointer can be, locations $80 to $FF are the zero page RIOT ram and $00 to $2F are one of the mirrors of the TIA registers. The stack pointer can point to anywhere in that space. In this case we are deliberately setting it up to ENABL to perform this trick.

 

 

In the code from the previous post, the idea is to have Ball, M0, and M1 appear for 1 scanline wherever we want on the screen. By using a separate ram register for each we have made the lines independent for each object. We could have M0 on line 56, the ball on line 130, and so on. The code is meant to be put in a loop that draws the kernel allowing this to happen.

 

 

Each object will only be 1 scanline in height. To make them taller the code becomes longer. This I won't show here, but if you look at Star Wars Arcade, the crosshairs and stars are all set with this trick. The cross hairs are several scanlines in height, but the stars are all 1 scanline in height.

 

 

Back to how it works with the Z flag... you use a compare instruction, in this case CPY. The Y register in this example is holding the current scanline number and will either get decremented or incremented (your choice). In the ram location you are comparing it to is the scanline you want the particular object to appear on. When Y is the same as that value the Z-flag goes high. When it is any other scanline the z-flag is low.

 

 

What we are doing with PHP is taking the contents of the status register (which includes the Z-Flag in the D1 bit position) and writing it to ENAxx. On every line that we do that we are either setting or clearing ENAxx.

Link to comment
Share on other sites

Good Morning.. Can anyone explain this a little bit? I've never seen the DCP command before (looks like it means decrement and compare but I can't find documentation on it) Also, I have no idea how the .byte even does anything here. I thought .byte just placed data in memory.

 

lda #HUMAN_HEIGHT-1 ; 2 15 - height of the humanoid graphics, subtract 1 due to starting with 0

dcp HumanDraw ; 5 20 - Decrement HumanDraw and compare with height
bcs DoDrawGrp0 ; 2 22 - (3 23) if Carry is Set, then humanoid is on current scanline
lda #0 ; 2 24 - otherwise use 0 to turn off player0
.byte $2C ; 4 28 - $2C = BIT with absolute addressing, trick that
; causes the lda (HumanPtr),y to be skipped

Edited by BNE Jeff
Link to comment
Share on other sites

Good Morning.. Can anyone explain this a little bit? I've never seen the DCP command before (looks like it means decrement and compare but I can't find documentation on it) Also, I have no idea how the .byte even does anything here. I thought .byte just placed data in memory.

Both are answered in the comments of Step 4 of the Collect series.

Link to comment
Share on other sites

Thanks!

 

Is it fair to say that the BITabs doesn't really produce anything useful here? The instruction causes consistent cycles, and also performs a mini-branch, but whatever value is the result, is not used- correct?

BIT is used because it won't trash A when you are skipping over the next instruction. In the DoDraw code you posted it doesn't matter what BIT does, but in general everyone has to be aware of what flags an instruction affects. I always use this page for a 6502 instruction set. You can see from that page that BIT affects the N, V, and Z flags.

 

 

You will sometimes see people use the illegal NOP's instead of BIT for this skipping purpose, because NOP affects no flags. The absolute NOP instruction is $0C.

Link to comment
Share on other sites

Thanks- I like that instruction link a lot...

 

I think I could use some help figuring out why my ball doesn't move. In my start up code, I have:

 

LDA #1
STA CTRLPF
STA HMBL ;Ball Speed

 

Then in the main loop I have:

 

LDA #2
STA VSYNC
STA WSYNC
STA WSYNC
STA WSYNC
STA HMOVE ;Move Ball

 

and this is in the kernel:

 

CheckBall
CPY Ball
BNE NoBall
LDA #2
STA ENABL

NoBall

 

Does anything look wrong? Its an HMOVE immediately after a WSYNC, 1 is a legitimate speed for HMBL. The ball shows up (sort of) but doesn't move..

 

Thanks!

Link to comment
Share on other sites

The 4 bits used for hmove are in the left nibble.

Helps if you write in hexadecimal (#$):

 

LDA #1
STA CTRLPF

LDA #$10 ;%00010000
STA HMBL ;Ball Speed

 

Remember, once you write a HMOVE value, it keeps until you set HMCLR (hmove clear)

I set HMCLR every frame, so I aways know the frame starts with all HMOVE as 0.

Link to comment
Share on other sites

  • 2 weeks later...

Good Morning, I'm looking through some code and found some commands I don't recognize.. what are these Basic-looking commands? They're not really indented which makes me think they are labels for a subroutine, but they repeat which makes me think they can't be.

 

Random:
lda Rand8
lsr
ifconst Rand16
rol Rand16
endif
bcc noeor
eor #$B4
noeor
sta Rand8
ifconst Rand16
eor Rand16
endif
rts

Link to comment
Share on other sites

Good Morning, I'm looking through some code and found some commands I don't recognize.. what are these Basic-looking commands?

 

While I don't specifically point it out, there's comments in the code of step 10 of the Collect series which explain what those do. It's also covered in dasm.txt, the manual that comes with dasm, under the section titled PSEUDOPS:

 

They're not really indented which makes me think they are labels for a subroutine, but they repeat which makes me think they can't be.

A single space is all that's required to indent something. When using jEdit, the different syntax coloring of inconst and endif helps to reinforce that they're not subroutine labels:

post-3056-0-83642700-1450538785_thumb.png

Link to comment
Share on other sites

I guess I'm pretty lost on this one and might have to drop it for now. I read through half of the DASM.txt and so much of it was above my head that I wasn't getting anything out of it. I read Collect #10 and I could follow, except for the terms "endif, and "ifconst", and the rest that I was specifically looking for- just not getting it. I could only figure that they were used in conjunction with the LFSG. I did learn what LFSG was- pretty cool.. and downloaded JEdit which I figured I'd have to start using eventually anyway. (It says its an editor for the "mature" programmer. uh-oh..)

 

My idea after completing Collect #4 with some difficulty was to just go ahead and read through one of your more complete versions of a Collect assembly to get a sense of as many parts as possible of the entire program. I've been really enjoying that and learning a lot..

 

Thanks for the help!

Link to comment
Share on other sites

Does anyone have a working sample program that includes a skipdraw routine? I have seen many postings of the code for just the routine, but never a simple program that draws a sprite on the screen using skip draw. I have tried for the past few weeks, but can't seem to get it to work. I think if I saw a simple example that works, then I could see where I am going wrong. Any help would be much appreciated.


Thanks.


Link to comment
Share on other sites

  • 2 weeks later...

Moose.. I'm not sure if it will help, but I believe Spiceware's Collect program uses DoDraw which looks identical to SkipDraw to me (though its supposed to be different in some way.)

 

There's an explanation in the comments at Step 4:

http://atariage.com/forums/blog/blog-148/cat-188-collect

Edited by BNE Jeff
Link to comment
Share on other sites

Good evening..

 

I finally downloaded Makewav, created a file for my Starpath Supercharger, played one of my little programs on an actual Atari, and it worked! However, all of the colors were completely wrong. The black background was orange, and the gray playfield was black. Anybody know why that might happen?

Link to comment
Share on other sites

Does anyone have any tips on adding variable playfield graphics to a kernel? I'm trying to have a prize (just a dot) show up in a random location using PF1 and can't figure out how to get the kernel deal with it. I've thought about decrementing and comparing a memory location or displaying an entirely new playfield just to show the one dot but those ways seem over-complicated and/or wrong. Note: my playfield is otherwise blank in the prize location.

 

Thanks!

Link to comment
Share on other sites

  • 3 months later...

Good Morning!

 

I had to put this (post above) aside for a bit while finishing up a certification I needed for work.. I decided to start by just having the kernel look to a single RAM location and then storing it in PF1. I've been working at it all morning and I just cant figure out why nothing shows. Here is the relevant code (Note this started as Darrell Spice's "Collect"):

 

​Here is where I set aside 6 bytes for 6 or more prizes:

 

PillPF: ds 6 ; stored in $9D,9E,9F,A0,A1,A2

 

Here is where I put in a test value:

 

InitSystem:
; CLEAN_START is a macro found in macro.h
; it sets all RAM, TIA registers and CPU registers to 0
CLEAN_START


lda #%10101010 ;added to test if pills will display
sta PillPF ;added to test if pills will display

 

And here is what is in the kernal. It's supposed to use PillPF,0 to make 2 sets of stripes on the screen. It doesn't show up:

 

; start of line 1 of the 2LK
sta GRP1 ; 3 3 - @0-22, update player1 graphics
stx ENAM1 ; 3 6 - @0-22, update missile1 graphics
ldx ArenaIndex ; 3 9
lda ArenaPF0,x ; 4 13 - get current scanline's playfield pattern
sta PF0 ; 3 16 - @0-22 and update it
lda PillPF ; 4 20 - get pill PF . Also deleted offset
sta PF1 ; 3 23 - @71-28 and update it
lda ArenaPF2,x ; 4 27 - get current scanline's playfield pattern
sta PF2 ; 3 30 - @60-39

 

Any ideas?

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