그러나 NES에는 CPU가있는 주소 지정 모드에 따라 2 또는 3 바이트 opcode가있는 것으로 보입니다. 각 바이트에 대해 읽어야하는 바이트 수를 계산하는 쉬운 방법은 생각할 수 없습니다. opcode.
opcode는 여전히 1 바이트입니다. 여분의 바이트는 명시 적 피연산자가있는 명령어의 피연산자를 지정합니다. 디코딩을 수행하려면 256 가지 경우로 switch
-block을 만들 수 있습니다 (실제로 일부 opcode는 불법이므로 256 가지 경우가 아님). 그것은이 같은 것을 볼 수 있었다 : 당신은 매우 효율적 (이기는하지만 약간 비 대한) 코드를하게 될 겁니다 있도록
opcode = ReadByte(PC++);
switch (opcode) {
...
case 0x4C: // JMP abs
address = ReadByte(PC++);
address |= (uint16_t)ReadByte(PC) << 8;
PC = address;
cycles += 3;
break;
...
}
컴파일러는 일반적으로 경우에 점프 테이블을 생성합니다.
또 다른 대안은 opcode 당 하나의 항목으로 배열을 만드는 것입니다. 이것은 단순히 opcode 당 하나의 함수를 가진 함수 포인터의 배열 일 수 있습니다. 또는 테이블에는 피연산자를 반입하기위한 하나의 함수에 대한 포인터, 실제 연산을 수행하기위한 포인터 및 명령에 필요한 사이클 수에 대한 정보가 포함될 수 있습니다. 이렇게하면 많은 코드를 공유 할 수 있습니다. 예 :
const Instruction INSTRUCTIONS[] =
{
...
// 0x4C: JMP abs
{&jmp, &abs_operand, 3},
...
};
는 또한주기를 계산하는 방법 계산에 문제가 있어요. 모든 것이 동기화되도록 프로그래밍 언어에서 시계를 만드는 방법은 무엇입니까?
CPU주기를 계산하는 것은 위의 코드 예제에서 보여 주었던 것처럼 카운터를 증가시키는 것입니다.
비디오를 CPU와 동기화하려면 가장 간단한 방법은 단일 스캔 라인의 활성 디스플레이 기간에 해당하는 사이클 양을 실행 한 다음 하나의 스캔 라인을 그린 다음 사이클 양만큼 CPU를 실행하는 것입니다 수평 블랭킹 기간에 해당하며 다시 시작합니다.
오디오 관련 작업을 시작하면 사용중인 오디오 API에 따라 작업을 동기화하는 방법이 달라질 수 있습니다. 예를 들어, 일부 API는 버퍼를 샘플로 채우고 생성 된 샘플 수를 반환하여 응답하는 콜백을 보낼 수 있습니다. 이 경우 이전 콜백 이후 에뮬레이션 된 CPU 사이클 수를 계산하고이를 기반으로 생성 할 샘플 수를 결정할 수 있습니다. NES는 리틀 엔디안이기 때문에 관련이없는 보조 노트에
는, 내가 올바른 op 코드를 얻을 수 programCounter를 읽을 다음 programCounter + 1을 읽고해야합니까?
opcode는 단일 바이트이고 6502의 명령어는 다른 CPU 아키텍처에서와 같은 단어로 묶이지 않기 때문에 엔디안 니스는 별 문제가되지 않습니다. 은이 16 비트 피연산자와 관련이 있지만, 반면 PC와 대부분의 휴대 전화는 리틀 엔디안 CPU를 기반으로합니다.
조회 테이블이 여기에 적합 할 것 같습니다. –