Commodore C64 如何检测 PAL 或 NTSC
Commodore C64 how to detect PAL or NTSC
背景资料
我目前正在使用 KickC [测试版] 为 Commodore C64 开发程序 API,以允许我更轻松地开发小程序、应用程序和可能的一些游戏;我突然想到我可能需要一种方法来检查我的代码在 PAL 或 NTSC 机器上是否是 运行,在后一种情况下,是哪台 NTSC 机器,因为旧的 NTSC C64 比新的 C64 少了一条扫描线版本。
在寻求帮助后,Robin Harbron 向我发送了一个代码片段,该代码片段可以与附加的 CMD SuperCPU(我最终的目标机器)一起使用。由于他把它作为汇编发送,我只好按原样使用大部分,而是使用KickC中的ASM指令,如下:
/**
* 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
}
}
在我的脚本顶部,我有这样的全局声明的 getMachineType
:
unsigned byte getMachineType;
目前,我的 peek()
函数是这样工作的:
/**
* 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;
}
所以现在我可以确定主机上可用的扫描线数 运行 我的程序,因此更容易创建 PAL 和 NTSC 兼容的可执行文件。
KickC 可从 CSDb.dk, and will build and assemble with Kick Assembler
下载
您分享的汇编代码使用的是VIC-II芯片的SCROLY寄存器($D011)和RASTER寄存器($D012)。
$D011的高位为当前光栅扫描行的最高位,而$D012为低8位。
NTSC 系统有 262(或 261?)扫描线,PAL 有 312。
汇编程序等待设置高位的瞬间,即扫描行 256。
如果设置了高位,它将循环直到未设置:
__br1:
lda $d011
bmi __br1 // read $d011 again if high bit is set
然后在高位清零的情况下循环,一旦置位就退出循环:
__br2:
lda $d011
bpl __br2 // read $ d011 again if high bit is clear
然后失败,从$d012
加载光栅扫描线的低8位
这会在测试高位时将扫描线值的低 8 位存储在 $c000 中,直到再次清除。如果已经清零,则不存储低8位,而是通过__ex1
退出循环
__br3:
lda $d012
bit $d011
bpl __ex1
sta $c000
bmi __br3
__ex1:
cli
结果应该是观察到的最高扫描线的数量 - 256。对于具有 262 条扫描线的 NTSC,这是您获得 return 值 6(或其他 NTSC 型号为 5)的地方,它为零-based 所以 5 将是 262 扫描线 NTSC 版本的值。
从零开始的扫描线 312 将是 311,减去 256 = 55,十六进制 $37 ..那里的评论真的应该指定 37 是十六进制的。
您可以在优秀的“Mapping the Commodore 64”一书中找到有关这些寄存器的信息。
您可以将所有这些汇编程序翻译成 C(设置中断禁用位并清除它除外:sei
、cli
),只需将值 0xD011 分配给 char * 指针, 和另一个 0xD012 并用 C 代码做同样的事情。
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
}
背景资料
我目前正在使用 KickC [测试版] 为 Commodore C64 开发程序 API,以允许我更轻松地开发小程序、应用程序和可能的一些游戏;我突然想到我可能需要一种方法来检查我的代码在 PAL 或 NTSC 机器上是否是 运行,在后一种情况下,是哪台 NTSC 机器,因为旧的 NTSC C64 比新的 C64 少了一条扫描线版本。
在寻求帮助后,Robin Harbron 向我发送了一个代码片段,该代码片段可以与附加的 CMD SuperCPU(我最终的目标机器)一起使用。由于他把它作为汇编发送,我只好按原样使用大部分,而是使用KickC中的ASM指令,如下:
/**
* 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
}
}
在我的脚本顶部,我有这样的全局声明的 getMachineType
:
unsigned byte getMachineType;
目前,我的 peek()
函数是这样工作的:
/**
* 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;
}
所以现在我可以确定主机上可用的扫描线数 运行 我的程序,因此更容易创建 PAL 和 NTSC 兼容的可执行文件。
KickC 可从 CSDb.dk, and will build and assemble with Kick Assembler
下载您分享的汇编代码使用的是VIC-II芯片的SCROLY寄存器($D011)和RASTER寄存器($D012)。
$D011的高位为当前光栅扫描行的最高位,而$D012为低8位。
NTSC 系统有 262(或 261?)扫描线,PAL 有 312。
汇编程序等待设置高位的瞬间,即扫描行 256。
如果设置了高位,它将循环直到未设置:
__br1:
lda $d011
bmi __br1 // read $d011 again if high bit is set
然后在高位清零的情况下循环,一旦置位就退出循环:
__br2:
lda $d011
bpl __br2 // read $ d011 again if high bit is clear
然后失败,从$d012
加载光栅扫描线的低8位这会在测试高位时将扫描线值的低 8 位存储在 $c000 中,直到再次清除。如果已经清零,则不存储低8位,而是通过__ex1
退出循环 __br3:
lda $d012
bit $d011
bpl __ex1
sta $c000
bmi __br3
__ex1:
cli
结果应该是观察到的最高扫描线的数量 - 256。对于具有 262 条扫描线的 NTSC,这是您获得 return 值 6(或其他 NTSC 型号为 5)的地方,它为零-based 所以 5 将是 262 扫描线 NTSC 版本的值。 从零开始的扫描线 312 将是 311,减去 256 = 55,十六进制 $37 ..那里的评论真的应该指定 37 是十六进制的。
您可以在优秀的“Mapping the Commodore 64”一书中找到有关这些寄存器的信息。
您可以将所有这些汇编程序翻译成 C(设置中断禁用位并清除它除外:sei
、cli
),只需将值 0xD011 分配给 char * 指针, 和另一个 0xD012 并用 C 代码做同样的事情。
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
}