1

Background Information

I am currently developing a programming API for the Commodore C64 using KickC [in Beta] to allow me to more easily develop small programs, applications and possibly some games; it occurred to me that I may need a way to check if my code is running on PAL or NTSC machines, and in the latter case, which NTSC machine, as the old NTSC C64 has one fewer scanline than the newer C64 version.

After asking about for some help, Robin Harbron sent me a code snippet which works including with a CMD SuperCPU attached (my eventual target machine). As he sent it as assembly, I had to use most of it as it was, but use the ASM directive in KickC, as follows:

/**
 * This is the initialisation will
 * determine the machine type
 * by setting the getMachineType global
 * as follows:
 * 37 is PAL
 * 5 is NTSC (old)
 * 6 is NTSC (new)
 * 0 (or any other value) is unknown
 *
 * For safety, the initial value of 0xc000
 * is stored into the accumulator and
 * pushed onto the stack; it is then
 * restored after the getMachineType
 * global is set
 *
 * @author Robin Harbron
 */
void setMachineType() {
 asm {
 lda $c000
 pha
 sei
 __br1:
 lda $d011
 bmi __br1
 __br2:
 lda $d011
 bpl __br2
 __br3:
 lda $d012
 bit $d011
 bpl __ex1
 sta $c000
 bmi __br3
 __ex1:
 cli
 }
 
 getMachineType = peek(0xc000);
 
 asm {
 pla
 sta $c000
 }
}

At the top of my script, I have the getMachineType declared globally like this:

unsigned byte getMachineType;

and at the moment, my peek() function works like this:

/**
 * Returns a single byte from a specific
 * memory location
 */
unsigned char peek(unsigned short location) {
 unsigned char* memory = (char*)location;
 unsigned char returnByte = *memory;
 
 return returnByte;
}

So now I can determine the available number of scan lines on the host machine running my program, and therefore more easily create PAL and NTSC compatible executables.

KickC is available to download from CSDb.dk, and will build and assemble with Kick Assembler

asked Oct 5, 2021 at 13:41

1 Answer 1

2

The assembly code you shared is using the SCROLY register ($D011) and the RASTER register ($D012) of the VIC-II chip.

The high bit of $D011 is the most significant bit of the current raster scan line, while $D012 contains the lower 8 bits.

NTSC systems have 262 (or 261?) scan lines, PAL have 312.

The assembler routine waits for the instant the high bit is set , i.e. scan line 256.

IF the high bit is set it loops until it is not set:

 __br1:
 lda $d011
 bmi __br1 // read $d011 again if high bit is set

Then it loops while the high bit is clear, exiting the loop as soon as it becomes set:

 __br2:
 lda $d011
 bpl __br2 // read $ d011 again if high bit is clear

Then it falls through to load the lower 8 bits of the RASTER scanline from $d012

This keeps storing the lower 8 bits of the scanline value in $c000 while testing the high bit until it clears again. If it has cleared, don't store the lower 8 bits, instead exit the loop through __ex1

 __br3:
 lda $d012
 bit $d011
 bpl __ex1
 sta $c000
 bmi __br3
 __ex1:
 cli

The result should be The number of the highest scanline observed - 256. For NTSC with 262 scanlines this is where you get the return value of 6 (or 5 for that other NTSC model), it's zero-based so 5 would be the value for the 262 scanline NTSC version. Zero based scanline 312 would be 311, minus 256 = 55, in hex 37ドル .. The comments there should really have specified that the 37 was hexadecimal.

You can find information about these registers in the excellent "Mapping the Commodore 64" book.

You could translate all of this assembler into C (with the exception of setting the interrupt disable bit and clearing it: sei, cli), just assign a char * pointer the value 0xD011, and another 0xD012 and do the same thing with C code.

char machineType = 0;
signed char * SCROLY = 0xd011;
char * RASTER = 0xd012;
asm {
 sei
}
while (*SCROLY < 0) ; // spin until scaline wraps
while (*SCROLY > 0) ; // spin until high bit set again
while (true) {
 char lines = *RASTER;
 if (*SCROLY > 0)
 break;
 machineType = lines;
}
asm {
 cli
}
answered Dec 19, 2021 at 20:10
Sign up to request clarification or add additional context in comments.

2 Comments

I did wonder how to convert this into KickC but I wasn't sure about the branching. Thanks for the explanation.
Also, 261 scanlines on early revisions of the C64 in NTSC (and I think one extra cycle per scanline), but I'm not an expert on this stuff.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.