Jump to content

Photo

Can somebody post the bare minimum to read paddle?


41 replies to this topic

#1 potatohead OFFLINE  

potatohead

    River Patroller

  • 4,404 posts
  • Location:Portland, Oregon

Posted Wed Aug 3, 2005 10:13 AM

Here is what I learned so far:

%10000010 ---> VBLANK

(This is supposed to ground the paddles & enable vblank)

Question #1, do you have to enable vblank to get the paddle to work?

After some amount of time, you do this to let the paddles charge.

%00000010 ---> VBLANK

Same question here.

Then you start counting while looking at the paddle input, when you see a 1, you stop and that's your paddle reading right? How long it takes to get the 1, depends on the paddle position and it's resistance to the incoming current released by the command above.

paddlevalue = paddlevalue + 1

if bit 7 of INPT0 is 1 then stop counting.

Is this even close to being right?

Coupla other questions:

Can the timers be used while the users basic code is running? I see timers referenced in the assembly code, but don't know where to look to find out more about them, or it I suppose.

Edited by potatohead, Wed Aug 3, 2005 10:14 AM.


#2 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,832 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Wed Aug 3, 2005 11:36 AM

Here is what I learned so far:

%10000010 ---> VBLANK

(This is supposed to ground the paddles & enable vblank)

Question #1, do you have to enable vblank to get the paddle to work?

After some amount of time, you do this to let the paddles charge.

%00000010  ---> VBLANK

Same question here.

Then you start counting while looking at the paddle input, when you see a 1, you stop and that's your paddle reading right?  How long it takes to get the 1, depends on the paddle position and it's resistance to the incoming current released by the command above.

paddlevalue = paddlevalue + 1

if bit 7 of INPT0 is 1 then stop counting.

Is this even close to being right?

Coupla other questions:

Can the timers be used while the users basic code is running?  I see timers referenced in the assembly code, but don't know where to look to find out more about them, or it I suppose.

View Post

That stuff all looks right, or at least pretty close. Actually, upon rereading...I don't think it matters what you do to enable/disable vblank. I think you can charge the cap when enabling vblank and begin discharging when you disable vblank (which I think is the method I used in the 2600Arkanoid demos I wrote). So I think the answer to #1 is No.

The main issue with paddles is: the time to read the paddles ranges between less than 76 cycles (for the paddle all the way closed) to greater than an entire frame.

So to read paddles you must discharge the cap (I believe this is generally done when you disable vblank) and then periodically check INPT0-3 to see how long it takes to get a '1'. So you need to read INPT0-4 several times, often every scanline, during your kernel.

In other words, paddles require a specialized kernel, so if you want paddle support for bB you need to rewrite/write your own kernel or go make a request in the kernel request thread. :)

Regarding the timer (singular), I doubt you can use it in bB because bB probably uses it already so if you used it you would probably crash your program.

The way the timer works is like this:
You load the timer with a value and set how often it decrements. The values are once every 1 cycle, every 8 cycles, every 64 cycles, and every 1024 cycles.

Then you can read the timer directly.

So you can read the timer all you want (lda INTIM) in bB but if you overwrite the value in the timer you will probably crash your program. Assuming that bB uses the timer; which is probably a safe assumption. You can always find out by looking at the assembly source for your programs.

#3 potatohead OFFLINE  

potatohead

    River Patroller

  • Topic Starter
  • 4,404 posts
  • Location:Portland, Oregon

Posted Wed Aug 3, 2005 12:16 PM

Here is what I learned so far:

%10000010 ---> VBLANK

(This is supposed to ground the paddles & enable vblank)

Question #1, do you have to enable vblank to get the paddle to work?

After some amount of time, you do this to let the paddles charge.

%00000010  ---> VBLANK

Same question here.

Then you start counting while looking at the paddle input, when you see a 1, you stop and that's your paddle reading right?  How long it takes to get the 1, depends on the paddle position and it's resistance to the incoming current released by the command above.

paddlevalue = paddlevalue + 1

if bit 7 of INPT0 is 1 then stop counting.

Is this even close to being right?

Coupla other questions:

Can the timers be used while the users basic code is running?  I see timers referenced in the assembly code, but don't know where to look to find out more about them, or it I suppose.

View Post

That stuff all looks right, or at least pretty close. Actually, upon rereading...I don't think it matters what you do to enable/disable vblank. I think you can charge the cap when enabling vblank and begin discharging when you disable vblank (which I think is the method I used in the 2600Arkanoid demos I wrote). So I think the answer to #1 is No.

The main issue with paddles is: the time to read the paddles ranges between less than 76 cycles (for the paddle all the way closed) to greater than an entire frame.

So to read paddles you must discharge the cap (I believe this is generally done when you disable vblank) and then periodically check INPT0-3 to see how long it takes to get a '1'. So you need to read INPT0-4 several times, often every scanline, during your kernel.

In other words, paddles require a specialized kernel, so if you want paddle support for bB you need to rewrite/write your own kernel or go make a request in the kernel request thread. :)

Regarding the timer (singular), I doubt you can use it in bB because bB probably uses it already so if you used it you would probably crash your program.

The way the timer works is like this:
You load the timer with a value and set how often it decrements. The values are once every 1 cycle, every 8 cycles, every 64 cycles, and every 1024 cycles.

Then you can read the timer directly.

So you can read the timer all you want (lda INTIM) in bB but if you overwrite the value in the timer you will probably crash your program. Assuming that bB uses the timer; which is probably a safe assumption. You can always find out by looking at the assembly source for your programs.

View Post


Does this counting have to be done in kernel? I know it will be jittery if done in a non time-synced way, but that might be good enough for what I am thinking about.

As for the timer, I see it is being used. Perhaps I can get numbers from it anyway.... That's something I can go look through the assembly for.

Is there a minimum time between grounding the paddles and the charging cycle? Can I ground, then just open 'em up right away, or must I wait?

The bottom line is I want to try to read the paddles with the basic program. In order to do that, as a minimum, I need to be able to ground and unground the paddles when I want to. Looks like that might be a reality.

Can you tell me something about the latch (bit 6)? Does it have anything to do with the paddles?

--thanks, BTW.

#4 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,832 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Wed Aug 3, 2005 12:57 PM

Does this counting have to be done in kernel?  I know it will be jittery if done in a non time-synced way, but that might be good enough for what I am thinking about.

Well, you can count any way you please :D, but the point of counting during the kernel is you can get a value ranging from 0 to 192 that won't change as long as the paddle doesn't move.

So in your game loop: I suppose you could ground the cap at the very beginning of your loop, then start charging it, then read the paddle immediately, run a bunch of code, then read it again right before calling drawscreen and you would get one of two numbers. The problem is the largest range is going to be something like 35 scanlines between reads, which isn't a very large range on the physical paddle. But you could do it, I guess. :)

You can test this pretty easily in z26; just use the paddle flags...whatever they are. I think -)PC and -m0 are the two you want.

Is there a minimum time between grounding the paddles and the charging cycle?  Can I ground, then just open 'em up right away, or must I wait?

Dunno. Ask Eckhard, read emulator source, or just test it in an emulator or on real hardware. :)

Can you tell me something about the latch (bit 6)?  Does it have anything to do with the paddles?

I'm pretty sure this only has to do with the joystick triggers, but I might be wrong.

#5 djmips OFFLINE  

djmips

    Dragonstomper

  • 634 posts
  • scrolling
  • Location:Seattle

Posted Wed Aug 3, 2005 3:20 PM

I was a little curious about this myself, and I poked around in the Stella archives.

This post is interesting because although the resolution of the paddle read is low, it happens in the overscan.

Paddle reads in the overscan

Code from Quadracide:


;Start Overscan

      lda #2
      STA VBLANK; Make TIA output invisible, and charge paddles
      lda #30
      sta TIM64T

   lda #23
   sta Player0x
   sta Player1x
   sta Player2y
   sta Player3y


; jmp skippaddles

   ldy #22
nextpa0:
   lda #128
   bit INPT0
   bne donepa0 ;2/3
   dec Player0x;5
   jmp donepa0a;3
donepa0:
   nop
   nop
   sta $30;time waster
donepa0a:
   lda #128
   bit INPT1
   bne donepa1
   dec Player1x
   jmp donepa1a;3
donepa1:
   nop
   nop
   sta $30;time waster
donepa1a:
   lda #128
   bit INPT2
   bne donepa2
   dec Player2y
   jmp donepa2a;3
donepa2:
   nop
   nop
   sta $30;time waster
donepa2a:
   lda #128
   bit INPT3
   bne donepa3
   dec Player3y
   jmp donepa3a;3
donepa3:
   nop
   nop
   sta $30;time waster
donepa3a:

   dey
   bpl nextpa0

skippaddles:

OverscanWait:
      lda     INTIM
      bne     OverscanWait

      JMP  MainLoop     ;Continue forever.


#6 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,832 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Wed Aug 3, 2005 3:25 PM

I was a little curious about this myself, and I poked around in the Stella archives.

This post is interesting because although the resolution of the paddle read is low, it happens in the overscan.

That's pretty interesting. I wonder how well that worked.

#7 potatohead OFFLINE  

potatohead

    River Patroller

  • Topic Starter
  • 4,404 posts
  • Location:Portland, Oregon

Posted Wed Aug 3, 2005 4:29 PM

I was a little curious about this myself, and I poked around in the Stella archives.

This post is interesting because although the resolution of the paddle read is low, it happens in the overscan.

That's pretty interesting. I wonder how well that worked.

View Post



--maybe we are gonna find out! Thanks for finding that.

#8 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,680 posts
  • begin 644 contest

Posted Wed Aug 3, 2005 4:39 PM

I was a little curious about this myself, and I poked around in the Stella archives.

This post is interesting because although the resolution of the paddle read is low, it happens in the overscan.

That's pretty interesting. I wonder how well that worked.

View Post

I modified the Alpha 0.2 assembly/kernel to use the paddle, mostly as an experiment. The problem is, it doesn't seem to work in Stella, but it does in z26. I have no idea why. I haven't tested on the real thing, either.

Perhaps someone who knows paddles better than I do may know what the problem is. Here's the kernel - note that you lose missile 0, and you must have a dim paddle0=missile0x at the start of your program. The return value from the paddle will be in the variable paddle0, and it returns 0-88, so you may need to multiply by two and do some bounds checking if you are using it for a horizontal position.

EDIT: kernel removed due to timing error - hopefully a fixed version is posted below.

Edited by batari, Thu Aug 4, 2005 3:35 PM.


#9 supercat OFFLINE  

supercat

    Quadrunner

  • 6,401 posts

Posted Wed Aug 3, 2005 4:39 PM

[quote name='potatohead' date='Wed Aug 3, 2005 5:29 PM']
This post is interesting because although the resolution of the paddle read is low, it happens in the overscan. [/quote]
[/quote]

Another approach I was thinking of which would probably be workable for adding a single paddle read to bB would be to take the previous measured pot position, divide by the number of scan lines for each 'tile' row (there are 11 tile rows in bB if I recall), and then release the dumping transistor at tile row (10-that_result). Then read the pot input during the "score" block (which should be expanded to be somewhat larger than a tile row.

If the pot input trips before the start of the score, then on the next frame the dumping transistor should be on for an extra tile row. If the pot input hasn't tripped by the end of the score, then the dumping transistor should be turned off a tile row earlier. Otherwise, if the pot input trips somewhere during the score, that will provide an accurate indication of the pot position.

If the tile rows are 16 pixels each and the score block is 20 pixels tall, this would allow the pot to be read with 192-unit resolution, subject to the caveat that it could only move by 16 units per frame. I would think that should be an acceptable compromise, given that it would only require one checking operation per tile row, rather than one per scan line. The approach wouldn't be usable for reading more than one paddle (unless different paddles were read on different frames), but for a single-paddle game it should be fine.

Anyone like that idea?

#10 Luigi301 OFFLINE  

Luigi301

    Moonsweeper

  • 372 posts

Posted Wed Aug 3, 2005 10:40 PM

[quote name='batari' date='Wed Aug 3, 2005 5:39 PM']
[quote name='vdub_bobby' date='Wed Aug 3, 2005 4:25 PM'][quote name='djmips' date='Wed Aug 3, 2005 2:20 PM']
Perhaps someone who knows paddles better than I do may know what the problem is. Here's the kernel - note that you lose missile 0, and you must have a dim paddle0=missile0x at the start of your program. The return value from the paddle will be in the variable paddle0, and it returns 0-88, so you may need to multiply by two and do some bounds checking if you are using it for a horizontal position.

View Post

[/quote]

Thank you! Now I can get to work getting paddle support for better control :)

If Z is currently player0x, then I have to make paddle0 equal Z * 2 for my rectangle's position?

17 player0x = z
18 player1x = o
19 player0y = y
20 player1y = p
21 z = paddle0 * 2

Edited by Luigi301, Wed Aug 3, 2005 10:54 PM.


#11 Luigi301 OFFLINE  

Luigi301

    Moonsweeper

  • 372 posts

Posted Wed Aug 3, 2005 10:40 PM

EDIT: double post

Edited by Luigi301, Wed Aug 3, 2005 10:40 PM.


#12 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,680 posts
  • begin 644 contest

Posted Thu Aug 4, 2005 1:11 AM

17 player0x = z
18 player1x = o
19 player0y = y
20 player1y = p
21 z = paddle0 * 2

View Post

That should work. But after multiplying, the range of z (0-176) slightly exceeds the range of the screen, which is only 160 pixels wide, so you should do some bounds checking to make sure the player doesn't wrap to the other side.

#13 Luigi301 OFFLINE  

Luigi301

    Moonsweeper

  • 372 posts

Posted Thu Aug 4, 2005 7:06 AM

That's odd... the left 20 pixels or so are one pixel lower than the rest of the screen!?

Attached Thumbnails

  • Untitled_4.png


#14 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash, THREE·S, Star Castle

  • 23,942 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany, Europe, Earth

Posted Thu Aug 4, 2005 7:10 AM

Looks like the writes to the playfield data are not in sync with the TV beam. The writes for the left part are happening too late.

#15 Luigi301 OFFLINE  

Luigi301

    Moonsweeper

  • 372 posts

Posted Thu Aug 4, 2005 7:24 AM

Well, I do have 4 sets or so of these...

  rem row 1-1 - all bit reads except 6 and 7 are inverted
  if a(7) then pfhline 0 4 2 on
  if a(6) then pfhline 3 4 5 on
  if !a(5) then pfhline 6 4 8 on
  if !a(4) then pfhline 9 4 11 on
  if !a(3) then pfhline 12 4 14 on
  if !a(2) then pfhline 15 4 17 on
  if !a(1) then pfhline 18 4 20 on
  if !a(0) then pfhline 21 4 23 on
  rem row 1-2 - only 7-5 are used, 4-0 are ignored
  if !a(5) then pfhline 24 4 26 on
  if a(6) then pfhline 27 4 29 on
  if a(7) then pfhline 30 4 31 on

Edited by Luigi301, Thu Aug 4, 2005 7:24 AM.


#16 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash, THREE·S, Star Castle

  • 23,942 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany, Europe, Earth

Posted Thu Aug 4, 2005 8:18 AM

Well, I do have 4 sets or so of these...

The problem is kernel related, maybe there is a bug in cycle counting (e.g. page penalties).

You could try moving your code around, but I am not sure if that helps.

#17 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,680 posts
  • begin 644 contest

Posted Thu Aug 4, 2005 3:34 PM

Well, I do have 4 sets or so of these...

The problem is kernel related, maybe there is a bug in cycle counting (e.g. page penalties).

You could try moving your code around, but I am not sure if that helps.

View Post

You're right - it's a cycle counting problem. I'm not sure what happened, but I did miscount and everything got shifted four cycles, so the players look fine but the playfield (which requires precise timing) looks funky.

I've fixed it and deleted the problem kernel above, and while I was at it, I found enough cycles for reading a second paddle, and decided to eliminate both missiles and add the ball to this kernel. ballx,bally and ballheight are the variables to access the ball, and you should do dim paddle0=missile0x and dim paddle1=missile1x to get at both paddles.

EDIT: The kernel I posted here originally didn't work... see a later message in this thread for a correction.

Edited by batari, Fri Aug 5, 2005 11:34 PM.


#18 supercat OFFLINE  

supercat

    Quadrunner

  • 6,401 posts

Posted Thu Aug 4, 2005 4:47 PM

I've fixed it and deleted the problem kernel above, and while I was at it, I found enough cycles for reading a second paddle, and decided to eliminate both missiles and add the ball to this kernel.  ballx,bally and ballheight are the variables to access the ball, and you should do dim paddle0=missile0x and dim paddle1=missile1x to get at both paddles.

View Post


Batari--did you see my suggestion about a possible alternate way to read a single paddle? Does it seem at all interesting?

#19 potatohead OFFLINE  

potatohead

    River Patroller

  • Topic Starter
  • 4,404 posts
  • Location:Portland, Oregon

Posted Thu Aug 4, 2005 8:34 PM

...about the timer.

How accurate is Stella? If somebody is trying something new, is there a fair chance the emulation won't reflect the hardware behavior?

My core idea was to use the timer during gamecode execution to help determine the paddle value and correct for program execute time variances. If the paddle can be resolved to within a few values, it can be used in programs and said programs can keep the kernel that allows the display of both players and both missiles. I know there will be time variance, but maybe it can be kept fairly low. Won't know the answer to that just yet however, because the timer does not seem to work correctly.

In the assembly file, produced by the bb compiler, I inserted the following 4 lines, right at the beginning of the basic code that happens after drawscreen is done:

LDA #60 ; pick a number
STA TIM1T ; set the one cycle count interval and set the timer to the number value to start. So timer = 60 and starts counting down every system cycle.

LDA INTIM ; read the timer and store that in variable u for use in the basic program
STA u

Looking at the assembly file tells me I have control of the machine during this time, and the most cycles to do work I want done. If I take too long here, the frame won't get drawn in time. The way it seems to work out is every other frame is drawn, with the game running at half speed. A quick delay loop that consumes too much time confirms this behavior.

After reading the RIOT docs, I see the value of the timer, put into variable u, should be a little less than 60. It only takes a coupla cycles to read the timer and the instruction that tells the cpu do actually do that. I expected a number in the high 50's. What I get, no matter what I do is the number 69. I can read the timer right away, several times, after a while, etc... still 69.

Either I am missing something about how the timer works, or the emulator is not correctly emulating the hardware in this case, or I'm missing out on just how the timer is being used elsewhere. In the latter case, I would assume my tinkering with the timer would hose something else up. The intervals I saw were fairly short and made sense in the context of syncing up the screen. I'm pretty sure the timer goes unused during the basic program code that executes after the drawscreen.

During the ~2000 cycle time the program is running after the drawscreen, I should be able to set this thing and get a value later. The kernel appears to set it for it's own purposes and appears to get the values it needs. Why can't I do the same thing?

Also the emulator does not seem to correctly reproduce the paddle concept shown above either. I tried a very simple, ground the paddles, unground them, count, and wait until a 1 is seen. Program never sees the 1, no matter the paddle setting. I've read elsewhere Stella has a problem with paddles. Anyone know more about this? I should have gotten a rough paddle value, but didn't.

#20 supercat OFFLINE  

supercat

    Quadrunner

  • 6,401 posts

Posted Thu Aug 4, 2005 8:47 PM

In the latter case, I would assume my tinkering with the timer would hose something else up.  The intervals I saw were fairly short and made sense in the context of syncing up the screen.  I'm pretty sure the timer goes unused during the basic program code that executes after the drawscreen.

View Post


The timer is absolutely essential during the code that executes after the drawscreen. I'm not quite sure why your store to TIM1T didn't mess things up, but the timer is the only way the system can know where the electron beam is the next time you call drawscreen and wait for it to be at the bottom of the screen before triggering vertical retrace.

#21 potatohead OFFLINE  

potatohead

    River Patroller

  • Topic Starter
  • 4,404 posts
  • Location:Portland, Oregon

Posted Thu Aug 4, 2005 9:55 PM

In the latter case, I would assume my tinkering with the timer would hose something else up.  The intervals I saw were fairly short and made sense in the context of syncing up the screen.  I'm pretty sure the timer goes unused during the basic program code that executes after the drawscreen.

View Post


The timer is absolutely essential during the code that executes after the drawscreen. I'm not quite sure why your store to TIM1T didn't mess things up, but the timer is the only way the system can know where the electron beam is the next time you call drawscreen and wait for it to be at the bottom of the screen before triggering vertical retrace.

View Post


I'm sorry but I don't think that is quite true.

I've spent the better part of this evening reading through some other assembly program sources. (Thanks Kirk for yours! The red line thing is excellent.)


The way it really works, I believe, is that the basic program is assumed to take less time than what is available, and it runs in the overscan period where things don't need to be synced in the way the kernel does. When control passes to the display kernel, it waits for a sync, then uses the timer to delay for specific things related to the display. When the frame is done, control then passes to the basic program again for the next cycle.

Batari? Am I way off here? What I don't know is if the vblank section of code is using the timer or not.

Edit: Instead of dribbling this out, here was my plan.

Ground the paddles, trigger the timer at the beginning of the execute time available to the basic program, write a zero to the paddle variable and enable interrupts.

I did a search on the riot chip today to better understand how it worked. And it's got an interrupt capability! Another quick search of the stella list suggests this capability is not being used. So that begs the question, is the interrupt even connected to the CPU? If not, this is all moot. But I think it is, so I'm moving forward on that assumption.

The next step, in reading the paddles outside the display kernel, involves releasing the ground on the paddles, letting them charge, so that gets done asap.

While they are charging, the timer triggers it's interrupt multiple times in sequence, adding one to a variable accessable to the basic program, if the paddle does not yet show the charged state. Once the paddles are charged enough to show a true result, the interrupts quit adding. If this never happens, the last interrupt puts things back to normal so the display kernel never knows what happened and it uses the timer the way it always does. Interrupts would be disabled at this time.

Of course this slows the basic program down, but maybe there would still be plenty of time for things to happen anyway. In the case of the ooze game, I could break actions across frames and still keep things fairly fast and furious. (Which is what I want the paddles for. the game is fun now, but the joystick kind of limits what could be happening.)

The alternative would be to check the paddle throughout the program, using the timer count to correct for variances in the program execute time, thus bringing the paddle accuracy to a useable level.

Sorry for not detailing that sooner. I really didn't formulate the entire idea until I saw the Interrupt capability and also saw that it really hasn't been used much, if at all.

And that brings me back to the emulator question. I didn't see the behavior I expected today. It's as if the timer is being ignored, where on a real machine it would be doing something. Probably breaking something, but at least I would know.

Being a newbie, feel free to slap this idea down hard. I'll learn something good either way, but you don't get unless you ask, so I'm asking!

...what's the cheapest way to get code running on a real 7800, which is what I have actually?

Edited by potatohead, Thu Aug 4, 2005 11:54 PM.


#22 supercat OFFLINE  

supercat

    Quadrunner

  • 6,401 posts

Posted Thu Aug 4, 2005 10:19 PM

The assembly file does a jsr drawscreen.  The timer is used in there for sure.


I haven't examined Batari's kernel, but oftentimes the timer will not be used during actual screen drawing, since the programmer will himself be keeping track of how long things take.

However when the program returns to the basic code, the timer is unused.  In fact, if it were being used and it was actually capable of interrupting the basic program to continue to sync the screen, excessive runtimes would not affect the screen, but would instead not be completed.  That's not the case.


The 6507 processor used in the Atari 2600 does not have any external interrupt pins, and consequently cannot be interrupted by a timer overflow. Code can poll the timer to see if it's overflowed yet, but that's all it can do.

Look at the assembly file and start from the beginning of your program and see.


I've not examined Batari's generated code, but I have written games on the 2600 and know how they need to work.

The way it really works, I believe, is that the basic program is assumed to take less time than what is available.  When control passes to the display kernel, it waits for a sync, then uses the timer to delay for specific things related to the display.  When the frame is done, control then passes to the basic program again for the next cycle.


The TIA will generate horizontal sync pulses by itself once every 76 clock cycles and will perfectly happily keep doing so all day long. It will only generate vertical sync pulses, however, when the processor explicitly tells it to do so. The processor uses the timer so it can tell when it should do that.

If the timer didn't exist, it would be necessary for user code to count ALL of the scan lines that go at any and all times during program execution. Although there are a few games where the code is tightly enough written to do this, there aren't many. Instead, the approach that is almost invariably used in Atari 2600 code is to set the timer to reach a certain value (many people use zero, others use something else) on a known scan line (typically the last one before the vertical sync should begin). The program than runs whatever batch of stuff needs to be done and then waits for the timer. Whether the program is running or waiting, the TIA will clock out a horizontal sync pulse every 76 cycles keeping the TV happy. After the timer expires, the software waits for the end of that scan line and then turns on the vertical sync pulse. It then typically goes on to draw the rest of the display (though some programs will set the timer again, this time to expire just before the first non-blank scan line, and do more game calculations).

To be sure, the way things are done on the Atari may seem very strange and bizarre, but it allows an amazingly versatile game machine to be built with what's actually a surprisingly small amount of circuitry. Indeed, I know of no other game system that requires the main processor to generate vertical sync. For all its bizarreness, though, that's what the 2600 does.

#23 Luigi301 OFFLINE  

Luigi301

    Moonsweeper

  • 372 posts

Posted Thu Aug 4, 2005 10:39 PM

Still a minor problem with display, now ALL pfpixel scanline breaks are 1 pixel too high! Paddle works though, thanks for the kernel.

For everyone's information, when drawing a playfield with PF0=128, the left boundary is 31 and the right is 151, giving you a 120 pixel playfield.

Also, what do I have to do to enable the ball? Just give it an X, Y, and height? I'm assuming a height of 0 disables it.

Attached Files


Edited by Luigi301, Thu Aug 4, 2005 10:45 PM.


#24 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,680 posts
  • begin 644 contest

Posted Thu Aug 4, 2005 11:50 PM

I've fixed it and deleted the problem kernel above, and while I was at it, I found enough cycles for reading a second paddle, and decided to eliminate both missiles and add the ball to this kernel.  ballx,bally and ballheight are the variables to access the ball, and you should do dim paddle0=missile0x and dim paddle1=missile1x to get at both paddles.

View Post


Batari--did you see my suggestion about a possible alternate way to read a single paddle? Does it seem at all interesting?

View Post

I had to read it several times before I knew what you were suggesting, but I'm still not totally sure how it would work. There are only 5 free cycles (IIRC) in the blank line between playfield blocks to do anything, maybe even less since things are going to change to get the ball in the kernel. In the score block, there are only 4 free cycles.

Well, I may be misunderstanding it still since I've never written a paddle game, so if you can explain with a little bit of sample code, I might understand better.

#25 potatohead OFFLINE  

potatohead

    River Patroller

  • Topic Starter
  • 4,404 posts
  • Location:Portland, Oregon

Posted Fri Aug 5, 2005 12:06 AM

Well, I just spent some time editing my post only to find yours supercat --and a few others!

Know I didn't question your overall knowledge of how a program worked. Thanks for your reply. It's hot here. What I really meant to say was look at the timer use in the batari kernel and tell me what you think about the timer.

No interrupt pin is a bummer.... Too bad, that capability would have been handy. That explains why it's not being used.

After reading your reply, I found where the timer is being used. It's set for ~3000 cycles. That's the overscan + vblank ---and the vblank waits until a specific time to do it's thing.

So, the timer is actually counting while the basic program is running. At least that's the only reason I can see for such a large value. So every 64 cycles of basic code should yield a different number. Maybe I just didn't get lucky with my samples. (trying that again.)

That brings up emulator accuracy questions then because I should be able to get different numbers, do some math, and arrive at a reasonably time corrected paddle reading. That's not happening in emulation.

I stuck a lda timeroutput, sta variable name at various places in the program only to get the number 69....

Since I'm on Linux, Stella is basically the emulator I'm going to be running. At some point, I'll give the latest a try and see if it behaves differently. I also found a posting about a paddle bug. It seems the version of Stella I have, does not handle the paddles correctly anyway.

I'll likely put this issue aside for a bit and tackle it later. Thanks everyone for your replies. Learned lots of new things.

Edited by potatohead, Fri Aug 5, 2005 12:16 AM.





0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users