事先,我为这个问题的开放性和一般的清醒道歉,因为老实说,我对这个话题的了解非常不完整,我发现很难描述我的问题.我真的不想发帖,但我完全被完全卡住了.
我已经启动了NES模拟器.它被解释(所以没有动态重新编译).
它可以加载和映射roms(mapper 0 roms)并执行init代码,直到我必须处理中断和PPU.那就是我被困住的地方.
这是我的emu atm的示例输出.执行从8000开始,我在800a处无限循环,我不知道如何从那里进步.
8002: LDA #$10 ; read immediate value to set PPU control registers
8004: STA $2000 ; store value
8007: LDX #$FF ; load immediate value into X register
8009: TXS ; store X register into stack
800a: LDA $2002 ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL ; test N flag, branch to 800a if not positive, (N is set)
800a: LDA $2002
800d: BPL
800a: …
Run Code Online (Sandbox Code Playgroud) 我正在模拟6502处理器,我差不多完成了(现在处于测试阶段)并且我正在使用来自nesdev站点的一些NES测试,它告诉我中断标志和未使用的第5个标志都是最初应该设置为1(即禁用中断),但为什么呢?我可以理解未使用的标志部分,因为它......很好......未使用,但我不明白中断标志.我试过在Google上搜索,有些网站确认它应该设置为1,但没有人解释这背后的原因.为什么中断应该从程序开始被阻止?
在业余时间,我开始为6502 CPU编写一个非常简单的C++仿真器.我以前写了很多的汇编代码为这个CPU,这样所有的操作码,寻址方式和其他的东西是不是一个大问题.
6502具有56种不同的指令和13种寻址模式,总共有151种不同的操作码.对我来说速度不是问题,所以不要写一个巨大的switch-case语句并反复重复相同的代码(不同的操作码可以使用不同的寻址模式引用相同的指令)我想将实际的指令代码与寻址模式代码:我发现这个解决方案很整齐,因为它需要只写13寻址模式功能和56个指令功能,无需重复自己.
这里的寻址模式功能:
// Addressing modes
uint16_t Addr_ACC(); // ACCUMULATOR
uint16_t Addr_IMM(); // IMMEDIATE
uint16_t Addr_ABS(); // ABSOLUTE
uint16_t Addr_ZER(); // ZERO PAGE
uint16_t Addr_ZEX(); // INDEXED-X ZERO PAGE
uint16_t Addr_ZEY(); // INDEXED-Y ZERO PAGE
uint16_t Addr_ABX(); // INDEXED-X ABSOLUTE
uint16_t Addr_ABY(); // INDEXED-Y ABSOLUTE
uint16_t Addr_IMP(); // IMPLIED
uint16_t Addr_REL(); // RELATIVE
uint16_t Addr_INX(); // INDEXED-X INDIRECT
uint16_t Addr_INY(); // INDEXED-Y INDIRECT
uint16_t Addr_ABI(); // ABSOLUTE INDIRECT
Run Code Online (Sandbox Code Playgroud)
它们都返回指令用来读/写操作数/结果的实际存储器地址(16位)
指令函数原型是:
void Op_ADC(uint16_t addr);
void Op_AND(uint16_t addr);
void Op_ASL(uint16_t addr); …
Run Code Online (Sandbox Code Playgroud) 我想了解Logisim中类似我的6502工作处理器项目的确切中断是什么。我知道中断会执行以下步骤:
装回未完成的数据,让程序继续正常运行。
我的问题是:在“某些”步骤中会发生什么?程序计数器是否重定向到要执行的特殊程序?像读取按钮的ASCII码并将其保存到寄存器或某个内存位置中一样?如果是这样,那个特殊程序通常存储在存储器中的什么位置?而且,您可以制造这样一种CPU来处理各种中断吗?也许如果您按下按钮“ a”,那么它的ASCII将被存储在A寄存器中,但是如果您按下按钮“ b”,那么它将被存储在X寄存器中?
任何帮助是极大的赞赏。
编辑:谢谢大家的答案。我学到了很多东西,现在可以继续进行我的项目了。
我正在努力学习CBM Program Studio.但我不能让宏为我工作.在宏观上,代码还可以.但是当我添加宏部分时,它在第7行给出了"无匹配结束定义".
任何的想法?
*=$c000 ; sys 49152
; set screen colors to black
lda #$00
sta $d020
sta $d021
defm waitmacro ;akumulatörü hac?l?yor
TYA
mloop DEY
BNE mloop
TAY
endm waitmacro
;color bars
LDX #$FF
loop LDY #$07
STY $d020
waitmacro
INY
STY $d020
waitmacro
DEX
BNE loop
RTS
Run Code Online (Sandbox Code Playgroud) 我试图找到关于6502 proccesor如何处理中断的信息,但我很困惑.我已经看过一些关于它的例子,但它就像一个普通的subrutine.
我对8086处理器有一些经验,我记得有一些代码可以处理不同的中断.
首先,如果有人能用一些代码解释NMI和IRQ之间的差异,我将非常感激.甚至更多,如果您获得有关处理中断的更多信息(例如)处理键盘中断.
我想将16位数除以2.我对这个问题的解决方案如下
lda $17 ;set high byte
ldx $32 ;set low byte
divide:
PHA ;push A to stack
TXA ;X > A
LSR ;divide low byte by 2
TAX ;A > X
PLA ;pull A from stack
LSR ;divide high byte by 2
BCC + ;C=0, skip
PHA ;while C=1
TXA ;add $80 to the lsb
ADC #$80
TAX
PLA
+
+printDecimal $0400+120
Run Code Online (Sandbox Code Playgroud)
所有PHA/PLA
技巧都是因为我的printDecimal
宏从A读取MSB,从X读取LSB.
当我在网上检查替代品时,我发现了4个指令替代我的简单划分例程.但我不明白.
div2:
LDA counter_hi ;Load the MSB
ASL ;Copy the sign bit into …
Run Code Online (Sandbox Code Playgroud) 下面是我在 Commodore 64 上进行内存复制的自我修改例程。
我写了char codes
并number of repeats
在一个表中,充满了screen_ram的这个套路。
我正在寻找优化建议。在这种情况下,我的优先事项是内存。
memCopy:
sourceAddress=*+1 ; mark self modifying addrres
fetchNewData:
lda data_table ; read char value into A
ldx data_table+1 ; read repeat value into x
inc sourceAddress
inc sourceAddress
cpx #00 ; if X=0
beq end ; finish copying
destination=*+1
- sta SCREEN_RAM
inc destination
dex
bne -
jmp fetchNewData
end:
rts
; data format: <char>,<number of repeats>,[<char>,<number of repeats>,...],00,00
data_table:
!by 01,03,02,02,......,00,00
Run Code Online (Sandbox Code Playgroud) 我从当时写的大量 6502 中了解到,并行数组比存储数据的结构更好。
想象一下,您想要一个怪物统计数据表,在 C 中可以像这样定义
struct Monster {
unsigned char hitPoints;
unsigned char damage;
unsigned char shieldLevel;
char* name;
};
Run Code Online (Sandbox Code Playgroud)
您可以将其存储为结构数组
static Monster s_monsters[] = {
{ 5, 1, 0, "orc", },
{ 50, 10, 5, "dragon", },
{ 10, 3, 1, "goblin", },
};
Run Code Online (Sandbox Code Playgroud)
或者您可以将其存储为并行数组(通常使用宏或工具来生成)。注意:我用 C 语言显示代码,但请想象它是 6502 汇编。
unsigned char Monster_hitPoints[] = { 5, 50, 10, };
unsigned char Monster_damage[] = { 1, 10, 3, },
unsigned char Monster_sheildLevel[] = { 0, 5, 1, };
unsigned char …
Run Code Online (Sandbox Code Playgroud) 我正在为 MOS6502 处理器构建一个模拟器,目前我正在尝试用代码模拟堆栈,但我真的无法理解堆栈在 6502 的上下文中是如何工作的。
6502 堆栈结构的特点之一是,当堆栈指针到达堆栈末尾时,它会回绕,但我什至不明白这个功能是如何工作的。
比方说,我们有64个最大值堆栈如果我们推值x
,y
并z
压入堆栈,我们现在有以下结构。堆栈指针指向 address 0x62
,因为这是压入堆栈的最后一个值。
+-------+
| x | 0x64
+-------+
| y | 0x63
+-------+
| z | 0x62 <-SP
+-------+
| | ...
+-------+
Run Code Online (Sandbox Code Playgroud)
一切都很好。但是现在如果我们从堆栈中弹出这三个值,我们现在有一个空堆栈,堆栈指针指向 value0x64
+-------+
| | 0x64 <-SP
+-------+
| | 0x63
+-------+
| | 0x62
+-------+
| | ...
+-------+
Run Code Online (Sandbox Code Playgroud)
如果我们第四次弹出堆栈,堆栈指针会环绕指向 address 0x00
,但是当0x00
??没有值时,这样做还有什么意义?堆栈中什么都没有,那么将堆栈指针包裹起来有什么意义????
我可以在推送值时理解这个过程,如果堆栈已满并且需要将值推送到堆栈,它将覆盖堆栈中最旧的值。这不适用于弹出。
有人可以解释一下,因为它没有意义。