1

背景资料

我目前正在使用 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下载,并将使用Kick Assembler构建和组装

4

1 回答 1

2

您共享的汇编代码使用 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 加载 RASTER 扫描线的低 8 位

这会继续将扫描线值的低 8 位存储在 $c000 中,同时测试高位,直到它再次清除。如果已经清零,则不存储低8位,而是通过__ex1退出循环

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

结果应该是观察到的最高扫描线的数量 - 256。对于具有 262 条扫描线的 NTSC,这是您获得返回值 6(或其他 NTSC 模型为 5)的地方,它是从零开始的,因此 5 将是262 扫描线 NTSC 版本。从零开始的扫描线 312 将是 311,负 256 = 55,十六进制 $37 .. 那里的注释确实应该指定 37 是十六进制的。

您可以在优秀的“ Mapping the Commodore 64 ”一书中找到有关这些寄存器的信息。

您可以将所有这些汇编程序翻译成 C(除了设置中断禁用位并清除它:sei, cli),只需将值 0xD011 和另一个 0xD012 分配给 char * 指针,然后对 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
}
于 2021-12-19T20:10:36.250 回答