Jump to content
IGNORED

Pal / NTSC Differences


snicklin

Recommended Posts

Who can let me know the best books / webpages which can tell me the differences between programming for NTSC and Pal machines?

 

The program that I am developing is currently working (in what it can currently do) in PAL. However, with NTSC, it crashes (at least in Atari800Win).

 

Previously I was of the belief that NTSC machines just handled timing and colours differently. I didn't realise that I would have to code things differently apart from changing timing routines / colours. I can see I was wrong...

Link to comment
Share on other sites

NTSC has siginificantly fewer cycles per frame (262*114 vs 312*114)

 

The VBlank NMI is triggered just after the normal 240 scanline area you can see. If the total VBlank Interrupt process including user code and the OS code doesn't finish before the normal display starts again, you can get glitches.

 

For NTSC, that's only ~ 22 scanlines = 2,508 cycles, infact a bit less due to refresh cycles.

 

PAL has the luxury of ~ 72 scanlines = 8,208 cycles which is more than triple the time.

 

Of course, graphical glitches can be sorted in most cases by tweaking your code.

Probably the more frequently reported problem is if you have a massive amount of work being done which can't fit within the time of one frame.

 

One thing you might try. Have a flag that you clear at the end of your VBlank routine. Test and set it at the start... if it's already set, then you know you have overrun and need to take <whatever> action - that action would usually be to skip most of your routine.

Link to comment
Share on other sites

Thank you both gentlemen.

 

I believe that you may well have hit the nail on the head with this. I do do a LOT of calculations in the VBI and that is probably what is causing my problems.

 

I'll try to restructure my logic to do more logic within the main section of code, out of the VBI time period.

Link to comment
Share on other sites

It's always a good idea to avoid such crashes with a semaphore:

 

VBI:

ldx InVBI

bne exitVBI

inx

stx InVBI

 

...your VBI code here...

 

ldx #0

stx InVBI

exitVBI:

...

 

This may result in a drop of a 'frame', but prevents 'strange' states.

Of course setting e.g. a visual indicator when a frame is dropped is a good idea during development too.

 

CU

Irgendwer

Link to comment
Share on other sites

A typical cause of crashes with over CPU use is the re-entrant interrupt code (or lack of). If your interrupt routine does the pha tya pha then pla tay pla type of entry then you tend to get glitches rather than crashes. If you're doing the sta stx sty then lda ldx ldy type then that's not safe if a DLI triggers when the VBL code is already running (trashes the registers after all the interrupt code has exited) and even adding the stuff Irgendwer posted above will make no difference because it's already too late.

 

 

Pete

Edited by PeteD
Link to comment
Share on other sites

...and even adding the stuff Irgendwer posted above will make no difference because it's already too late...

 

When using the OS VBI mechanism, the OS saves the registers, so the code above is OK.

 

Edit: Of course DLIs have to use PHAs/PLAs/Txx to be 'safe' - but this wasn't my point.

Edited by Irgendwer
Link to comment
Share on other sites

Seems that your cars AI will be very smart!icon_lust.gif

 

!! I wish !! I've only programmed the mechanism for moving a car around in 360 degrees! I've improved what I had in my last demo and it's kind of 95% there with a single car's movement.

 

As for AI for the other cars, for each level I'll have a list of target coordinates for each car to head for. If they get bumped, they can correct their course.

Link to comment
Share on other sites

A typical cause of crashes with over CPU use is the re-entrant interrupt code (or lack of). If your interrupt routine does the pha tya pha then pla tay pla type of entry then you tend to get glitches rather than crashes. If you're doing the sta stx sty then lda ldx ldy type then that's not safe if a DLI triggers when the VBL code is already running (trashes the registers after all the interrupt code has exited) and even adding the stuff Irgendwer posted above will make no difference because it's already too late.

 

 

Pete

 

I'm using the first described method (with pushing and pulling) for my DLI's and yeah, it is rather glitchy to say the least. I'd hoped to correct that later on.

 

It just amazes me the differences between NTSC and PAL. I'll see what I can do (thanks to all suggestions so far gentlemen) but if I cannot fix my problems, I may drop NTSC support altogether. In the age of emulators where you can switch PAL and NTSC, is it really that important to have both?

 

The question is, do most people use emulators most of the time or real hardware? I predominantly use emulation. (Not when I get my new house though, I'll have a proper Atari set-up there)!!

Link to comment
Share on other sites

...and even adding the stuff Irgendwer posted above will make no difference because it's already too late...

 

When using the OS VBI mechanism, the OS saves the registers, so the code above is OK.

 

Edit: Of course DLIs have to use PHAs/PLAs/Txx to be 'safe' - but this wasn't my point.

 

:roll:

Link to comment
Share on other sites

Next course is make the code more efficient.

 

If that's no doable, then maybe some kind of multiplexing of tasks between frames although the results there mightn't necessarily look right.

 

Plenty of arcade games just use the "hold" method. Fairly sure Flying Shark and Twin Cobra did. When there's a lot of onscreen stuff, the game just slows down. Still retains smoothness and playability, usually more desirable than some of the alternatives.

Link to comment
Share on other sites

My :roll: is in response to your needless post. I was merely making clear in my earlier post that despite your code (useful though it may be) IF not using the OS interrupt routines and IF using sta/x/y instead of pushing registers to the stack pretty much anything would crash semaphore or not.

 

I sometimes get the feeling people are way too defensive about what they say on this forum and take any post mentioning them by name or quoting a bit of their post to be some kind of attack or correction to what they've said. I didn't say your code wasn't ok, I have no intention on guessing your "point" just adding extra info to help Snicklin.

 

Enough said.

 

 

Pete

Link to comment
Share on other sites

Next course is make the code more efficient.

 

If that's no doable, then maybe some kind of multiplexing of tasks between frames although the results there mightn't necessarily look right.

 

Plenty of arcade games just use the "hold" method. Fairly sure Flying Shark and Twin Cobra did. When there's a lot of onscreen stuff, the game just slows down. Still retains smoothness and playability, usually more desirable than some of the alternatives.

 

I only have 1 car moving at the moment (and I've coded it so that up to 2 players can play at once). But there are 4 cars in all, so I think I'll first put in some dummy routines to move the other 2/3 cars (maybe in a rectangle shape around the screen). Then I'll see just how slow/fast that they move and then I'll look at optimisation. The problem is, I always code with optimisation in mind and so I'm not currently sure what can be optimised. If I can't optimise it more, I'll do what you mentioned with "multiplexing" the car movements. Thanks for your input.

Link to comment
Share on other sites

What about doing the actual calculations for car movement in the main line code, and just updating the cars position and other graphics in VBI? You could probably set it up so that the cars maintain their course/speed, if your calculations/AI processing is not quite done yet.

 

If that's what you are already doing, then ignore this post. :)

 

PS. I always find that even though I think it's optimized, there is always some guy smarter than me that can optimize it further. Quite a few of the people here (and in the 2600 forums) are wizards in that regard.

Edited by Shawn Jefferson
Link to comment
Share on other sites

Sounds to me like something in your code is taking way longer than it should.

 

How are you doing PMG movement? If you're doing some huge loop to clear the entire thing, then painting the car in, then that's a huge waste right there.

There's optimised ways of doing PMG movement that use very little CPU time.

 

Or, how about the screen - are you just doing LMS updates, or actually moving the data around?

 

The old colour bar technique is a quick and easy way to work out what's taking longer than it should.

 

Just add some code to landmark parts of the VBI to do something like:

 

. WSYNC, change COLBAK to green, WSYNC again, change back to black.

. WSYNC, change COLBAK to red, WYSYNC, back to black.

. etc...

 

Then you can just pause in the emulator and have a rough guide to how much CPU each step is taking.

Edited by Rybags
Link to comment
Share on other sites

What about doing the actual calculations for car movement in the main line code, and just updating the cars position and other graphics in VBI? You could probably set it up so that the cars maintain their course/speed, if your calculations/AI processing is not quite done yet.

 

If that's what you are already doing, then ignore this post. :)

 

PS. I always find that even though I think it's optimized, there is always some guy smarter than me that can optimize it further. Quite a few of the people here (and in the 2600 forums) are wizards in that regard.

 

The calculations for car movement were originally done in the main code and then updating in the VBI. The problem that I had with this was that I could have 2 lots of main code run and then the VBI (or was it the other way around) and at other times, 3 lot of main code and then the VBI (or the other way around). I need it to be consistent.

 

As for optimisation, I work heavily on it but do realise that my code isn't perfect, I know that, because I'll probably optimise it more next week!

Link to comment
Share on other sites

As for updating the screen, I do the following:

 

-> LMS updates for the scrolling.

-> I paint a few blank lines above the PMG, paint the PMG, paint a few blank lines below the PMG

 

Do remember that I'm putting a lot of time into slowing the car down also.

 

I have a 2D array of signed chars for the directions of the car for each angle of 30 degrees between 0 and 360. In there I have X and Y delta values. When I hold down the trigger, a counter builds up 1 by 1. When this hits 255-(speed*fudge factor), the car will move one place. The counter is then reset to 0.

 

When I next get chance, I'll try the tricks for checking the processor usage with the VBI. I've got to go to work soon though and then I've got to tidy the home up, it's a mess. I have a 2nd job also and I'm about to buy my first house, so Atari isn't getting enough of my attention at the moment!!

 

When I get chance, I'll share some code by PM request.

Link to comment
Share on other sites

If your mainline code was running too often just do something similar to irgendwer's semaphore. In the VBI code increment a counter in ram, in the mainline code loop round, lda counter loop: cmp counter beq loop as soon as it gets past that loop you know you're on a new frame and when you jump back to it you know it won't fall out of the loop again till the next frame.

 

My logic for that loop may be off? I just woke up after only about 2hrs sleep :(

 

 

Pete

Link to comment
Share on other sites

  • 3 weeks later...

Thank you gentlemen, I've finally got around to looking into the code.

 

I've found that it all boils down to my LMS update code on NTSC. It is fine however on PAL.

 

Here's my 'C' code and I have two commented out sections.... neither strategy appears to be quick enough....

 

The 1st strategy attempts to roll out the code for speed and then use additions of 320 so that further calculations use less bytes.

The 2nd strategy attempts to keep things simple and update the LMS address appropriately.

 

In both cases I attempt to see if an update is even required. ORIGIN_ADDRESS is the address of the top left hand corner of the screen.

 

void updateScreenLocation(void)

{

unsigned int line_origin=PEEKW(ORIGIN_ADDRESS);

static unsigned int line_origin_prev=0;

 

if(line_origin_prev!=line_origin)

{

/*

POKEW(1546U,line_origin);

POKEW(1549U,line_origin+80);

POKEW(1552U,line_origin+160);

POKEW(1555U,line_origin+240);

line_origin+=320;

 

POKEW(1558U,line_origin);

POKEW(1561U,line_origin+80);

POKEW(1564U,line_origin+160);

POKEW(1567U,line_origin+240);

line_origin+=320;

 

POKEW(1570U,line_origin);

POKEW(1573U,line_origin+80);

POKEW(1576U,line_origin+160);

POKEW(1579U,line_origin+240);

line_origin+=320;

 

POKEW(1582U,line_origin);

POKEW(1585U,line_origin+80);

POKEW(1588U,line_origin+160);

POKEW(1591U,line_origin+240);

line_origin+=320;

 

POKEW(1594U,line_origin);

POKEW(1597U,line_origin+80);

POKEW(1600U,line_origin+160);

POKEW(1603U,line_origin+240);

line_origin+=320;

 

POKEW(1606U,line_origin);

POKEW(1609U,line_origin+80);

*/

/*

unsigned int val;

unsigned int newLineOrigin=line_origin;

 

for(val=1546;val<1612;val+=3)

{

POKEW(val,newLineOrigin);

newLineOrigin+=80;

}

*/

}

line_origin_prev=line_origin;

 

POKE(54276U,PEEK(207));

POKE(54277U,PEEK(208));

}

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