It is currently Sat Oct 21, 2017 2:07 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 76 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next
Author Message
PostPosted: Tue Oct 08, 2013 6:41 am 
Offline
User avatar

Joined: Fri Mar 08, 2013 9:55 pm
Posts: 349
Location: Linköping, Sweden
janzdott wrote:
ulfalizer wrote:
You can look in http://nesdev.com/6502_cpu.txt to see what reads/writes are done for different instructions. Implementing the instructions like in that doc is feasible, and makes the timing work out "automagically" without tables. You can also factor out the fetch of the opcode and the byte after that, since all instructions do it.


Thanks, that's a pretty helpful page. I hadn't read that one before. But I'm a little confused. It says, "The processors also use a sort of pipelining. If an instruction does not store data in memory on its last cycle, the processor can fetch the opcode of the next instruction while executing the last cycle." So only the opcodes that don't store data in memory on the last cycle do that, or do all of them? Is it necessary to emulate that behavior?


It's invisible above the hardware level and does not need to be emulated. The most useful part of that doc is the timing charts near the end.

In case you're interested though, it has to do with the 6502 being able to overlap the final cycles of one instruction with the opcode and operand fetch for the next instruction. This is possible for instructions that change state internally within the CPU during their final cycles and don't need to access memory. For example, LDA #constant really takes three cycles internally rather than two, but the move of the fetched value (from an internal register) into the A register is overlapped with the opcode fetch for the next instruction, making it effectively a two-cycle instruction. From an emulation standpoint it's not important exactly when A is set though, as long as it happens before the next instruction can use the value, so it's easier to just set A before fetching the next opcode.


Top
 Profile  
 
PostPosted: Tue Oct 08, 2013 7:02 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
janzdott wrote:
I got it working now, and it executes a lot of code until it hits a loop.

The PPU needs some time to "warm up" and become usable (roughly a frame), so programs often have loops to wait a couple of VBlanks before using the PPU. You will remain stuck in these loops until you implement (or fake) the VBlank flag in register $2002 (PPUSTATUS).


Top
 Profile  
 
PostPosted: Tue Oct 08, 2013 12:09 pm 
Offline
User avatar

Joined: Fri Oct 04, 2013 11:56 pm
Posts: 42
Location: Wisconsin
@ulfalizer So by overlapping, you mean they happen at the same time? There's so many quirks that make this stuff hard to understand. I'm definitely gonna need to keep reading up on this stuff.

@tokumaro I checked the correct log file and compared it to mine. There's a bug in an opcode somewhere, but I'm not sure where yet. It's gonna help when I have the CPU log the opcodes and registers for each cycle in a file.

_________________
Current emulator progress http://forums.nesdev.com/viewtopic.php?f=3&t=10558


Top
 Profile  
 
PostPosted: Tue Oct 08, 2013 3:05 pm 
Offline
User avatar

Joined: Fri Mar 08, 2013 9:55 pm
Posts: 349
Location: Linköping, Sweden
janzdott wrote:
@ulfalizer So by overlapping, you mean they happen at the same time? There's so many quirks that make this stuff hard to understand. I'm definitely gonna need to keep reading up on this stuff.


Yup, the CPU carries out the final cycles of some instructions at the same time that it fetches the next instruction (a simple form of pipelining). Another example is ADC #immediate, which seems to actually be a four-cycle instruction internally, but overlaps the last two cycles with fetches for the next instruction (the opcode byte and the byte after that). The reason this is safe is that no other instruction looks at the value of A within the first two cycles.

This is just trivia though, and not something you will need to be aware of when writing an emulator (I learned how it works pretty recently). You can pretend that A holds the sum after the second cycle of ADC #immediate, and that's what all emulators do in practice. :)


Top
 Profile  
 
PostPosted: Wed Oct 09, 2013 3:57 pm 
Offline
User avatar

Joined: Fri Oct 04, 2013 11:56 pm
Posts: 42
Location: Wisconsin
Well its good I don't have to worry about emulating that then :)

I spent a lot of time on a class for logging CPU instructions. It can be enabled or disabled, because I suspect it'll effect performance down the road. For each instruction executed, the program counter, instruction, and register values are pushed to a circular buffer of a fixed length. The current buffer index is kept track of, so when I dump to a file, it writes them in the correct order.

I used a circular buffer so I could limit the number of instructions that are dumped to the file. If my emulator is running for 10 minutes and I want to dump the instructions to a file, it won't dump 100,000,000 instructions. Instead it'll only dump the 1000 most recent ones. It works great, and outputs to a nice format like this...

Code:
C000    4C F5 C5    JMP $C5F5      A:00  X:00  Y:00  P:24  S:FD


It was a pain to convert the bytes into text that shows correct assembly instructions, but I felt it was necessary. I'm running nestest and looking at my log file. It seems to be executing most instructions correctly (Surprisingly :D ). Though, it does go off track at some point. I'll have to spend a lot of time looking through the log files to find where the problems are. I'm excited though. Things are coming along well :D

_________________
Current emulator progress http://forums.nesdev.com/viewtopic.php?f=3&t=10558


Last edited by janzdott on Wed Oct 09, 2013 5:58 pm, edited 2 times in total.

Top
 Profile  
 
PostPosted: Wed Oct 09, 2013 5:58 pm 
Offline
Formerly 65024U

Joined: Sat Mar 27, 2010 12:57 pm
Posts: 2257
Why in the world would you not output the same format as the other logs, compare them, and fix the ones that go off? It's not that hard at all to get CPU running, honestly, it's cake compared to PPU and audio.


Top
 Profile  
 
PostPosted: Wed Oct 09, 2013 6:02 pm 
Offline
User avatar

Joined: Fri Oct 04, 2013 11:56 pm
Posts: 42
Location: Wisconsin
3gengames wrote:
Why in the world would you not output the same format as the other logs, compare them, and fix the ones that go off? It's not that hard at all to get CPU running, honestly, it's cake compared to PPU and audio.


Isn't my format the same as the others? I'm comparing it to a log from nintendulator and it's the same, except I left out the cycle number, and one other number which I don't know the meaning of. But I decided I'm going to write a program to compare the logs for me, and just give me the first address where they differ. I would rather spend my time fixing bugs than reading through log files haha

_________________
Current emulator progress http://forums.nesdev.com/viewtopic.php?f=3&t=10558


Top
 Profile  
 
PostPosted: Wed Oct 09, 2013 6:33 pm 
Offline
Formerly 65024U

Joined: Sat Mar 27, 2010 12:57 pm
Posts: 2257
You won't find the debugs if you don't compare the logs though, see how you this is a needed step? I mean, I haven't written an emu, but I've written enough programs to know how to design them.


Top
 Profile  
 
PostPosted: Wed Oct 09, 2013 6:46 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
When I was verifying a Python 6502 simulator against neatest, I just read register values, PC, and CYC from each line of the Nintendulator log and compared those. That way I don't need to worry about disassembly.


Top
 Profile  
 
PostPosted: Wed Oct 09, 2013 6:57 pm 
Offline
User avatar

Joined: Fri Oct 04, 2013 11:56 pm
Posts: 42
Location: Wisconsin
3gengames wrote:
You won't find the debugs if you don't compare the logs though, see how you this is a needed step? I mean, I haven't written an emu, but I've written enough programs to know how to design them.

But I AM comparing the logs. I just said I was writing a program to do it for me, so I don't have to read through the files by hand. My computer reads much faster than I do :wink:

tepples wrote:
When I was verifying a Python 6502 simulator against neatest, I just read register values, PC, and CYC from each line of the Nintendulator log and compared those. That way I don't need to worry about disassembly.

^^This is exactly what I'm doing, except I added disassembly for readability

_________________
Current emulator progress http://forums.nesdev.com/viewtopic.php?f=3&t=10558


Top
 Profile  
 
PostPosted: Thu Oct 10, 2013 3:23 am 
Offline
User avatar

Joined: Fri Oct 04, 2013 11:56 pm
Posts: 42
Location: Wisconsin
I'm utterly stuck :( Could someone with their own emulator PLEASE help me out? I've been trying, and there's no way for me to find the source of my problem. This is from Nintendulator's log of nestest.

Code:
CFBF  85 FF     STA $FF = 00                    A:00 X:55 Y:69 P:27 SP:FB CYC: 16 SL:1
CFC1  A9 04     LDA #$04                        A:00 X:55 Y:69 P:27 SP:FB CYC: 25 SL:1
CFC3  85 00     STA $00 = 00                    A:04 X:55 Y:69 P:25 SP:FB CYC: 31 SL:1
CFC5  A9 5A     LDA #$5A                        A:04 X:55 Y:69 P:25 SP:FB CYC: 40 SL:1
CFC7  8D 00 02  STA $0200 = 00                  A:5A X:55 Y:69 P:25 SP:FB CYC: 46 SL:1
CFCA  A9 5B     LDA #$5B                        A:5A X:55 Y:69 P:25 SP:FB CYC: 58 SL:1
CFCC  8D 00 03  STA $0300 = 00                  A:5B X:55 Y:69 P:25 SP:FB CYC: 64 SL:1
CFCF  A9 5C     LDA #$5C                        A:5B X:55 Y:69 P:25 SP:FB CYC: 76 SL:1
CFD1  8D 03 03  STA $0303 = 00                  A:5C X:55 Y:69 P:25 SP:FB CYC: 82 SL:1
CFD4  A9 5D     LDA #$5D                        A:5C X:55 Y:69 P:25 SP:FB CYC: 94 SL:1
CFD6  8D 00 04  STA $0400 = 00                  A:5D X:55 Y:69 P:25 SP:FB CYC:100 SL:1
CFD9  A2 00     LDX #$00                        A:5D X:55 Y:69 P:25 SP:FB CYC:112 SL:1
CFDB  A1 80     LDA ($80,X) @ 80 = 0200 = 5A    A:5D X:00 Y:69 P:27 SP:FB CYC:118 SL:1
CFDD  C9 5A     CMP #$5A                        A:5A X:00 Y:69 P:25 SP:FB CYC:136 SL:1
CFDF  D0 1F     BNE $D000                       A:5A X:00 Y:69 P:27 SP:FB CYC:142 SL:1
CFE1  E8        INX                             A:5A X:00 Y:69 P:27 SP:FB CYC:148 SL:1
CFE2  E8        INX                             A:5A X:01 Y:69 P:25 SP:FB CYC:154 SL:1
CFE3  A1 80     LDA ($80,X) @ 82 = 0300 = 5B    A:5A X:02 Y:69 P:25 SP:FB CYC:160 SL:1
CFE5  C9 5B     CMP #$5B                        A:5B X:02 Y:69 P:25 SP:FB CYC:178 SL:1
CFE7  D0 17     BNE $D000                       A:5B X:02 Y:69 P:27 SP:FB CYC:184 SL:1
CFE9  E8        INX                             A:5B X:02 Y:69 P:27 SP:FB CYC:190 SL:1
CFEA  A1 80     LDA ($80,X) @ 83 = 0303 = 5C    A:5B X:03 Y:69 P:25 SP:FB CYC:196 SL:1
CFEC  C9 5C     CMP #$5C                        A:5C X:03 Y:69 P:25 SP:FB CYC:214 SL:1
CFEE  D0 10     BNE $D000                       A:5C X:03 Y:69 P:27 SP:FB CYC:220 SL:1
CFF0  A2 00     LDX #$00                        A:5C X:03 Y:69 P:27 SP:FB CYC:226 SL:1
CFF2  A1 FF     LDA ($FF,X) @ FF = 0400 = 5D    A:5C X:00 Y:69 P:27 SP:FB CYC:232 SL:1
CFF4  C9 5D     CMP #$5D                        A:5D X:00 Y:69 P:25 SP:FB CYC:250 SL:1


The instruction at CFBF stores the value 00 at the address FF. In my emulator, this is the ONLY time this address is written to, up until my problem. My problem is the instruction at CFF2. X = 0, so this instruction looks up an address at FF and 0100. The thing is, FF is 0, and 0100 is never written to in my emulator. If both of them were 00, that points to address 0000, which is 04. That's the number my emulator loads into the accumulator. It's not right, because Nintendulator's log says it should be 5D.

I've tried and tried, and there's no way for me to find the source of the problem. It could be an instruction writing the wrong value to an address, or it could be an instruction writing a value to the wrong address. Since it's a problem with an instruction that uses indirect x addressing, that makes it even harder to find the problem. I've tracked the memory reads and writes, and that didn't help. Basically I need someone with a working emulator to help me. If someone could just tell me one thing...

1. Which instructions write to the addresses 0000, 00FF, and 0100?

If someone could just add a check for writes to those addresses before CFF4, that would help me SO MUCH. I'm horribly stuck and I don't know how to find the source of the problem

EDIT: I just thought of something... Does indirect addressing wrap around back to 00 when you go over FF? If so, that could be my problem. I'll have to try it out tomorrow because I'm exhausted. I'll let you guys know when I find out.

_________________
Current emulator progress http://forums.nesdev.com/viewtopic.php?f=3&t=10558


Top
 Profile  
 
PostPosted: Thu Oct 10, 2013 5:24 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
Zero page indexing wraps within zero page. ($80,X) with X=$7F reads the low byte from $00FF and the high byte from $0000.

Two of the writes that set up this test are at $CFBF and $CFC3.


Top
 Profile  
 
PostPosted: Thu Oct 10, 2013 10:02 am 
Offline
User avatar

Joined: Fri Oct 04, 2013 11:56 pm
Posts: 42
Location: Wisconsin
tepples wrote:
Zero page indexing wraps within zero page. ($80,X) with X=$7F reads the low byte from $00FF and the high byte from $0000.

Two of the writes that set up this test are at $CFBF and $CFC3.


Sure enough, that was the problem :D I've made it almost half way through the test, and now I'm stuck on another one which should be simple, but doesn't seem to make any sense at all. My problem is at DBB5, the instuction JMP ($02FF). The value at the address 02FF is A900. I know this is correct, because that's the value in my emulator, and the Nintendulator log conveniently shows the value after the instruction like so, "JMP ($02FF) = A900".

Correct me if I'm wrong, but doesn't that mean jump to A900? My emulator correctly executes an indirect jump at DB7B just before this... I know my indirect addressing is working correctly, and my emulator jumps to A900. The Nintendulator log shows that it should jump to 0300. I don't understand...

Code:
DB7B  6C 00 02  JMP ($0200) = DB7E              A:DB X:07 Y:00 P:E5 SP:FB CYC:326 SL:62
DB7E  A9 00     LDA #$00                        A:DB X:07 Y:00 P:E5 SP:FB CYC:  0 SL:63
DB80  8D FF 02  STA $02FF = 00                  A:00 X:07 Y:00 P:67 SP:FB CYC:  6 SL:63
DB83  A9 01     LDA #$01                        A:00 X:07 Y:00 P:67 SP:FB CYC: 18 SL:63
DB85  8D 00 03  STA $0300 = 89                  A:01 X:07 Y:00 P:65 SP:FB CYC: 24 SL:63
DB88  A9 03     LDA #$03                        A:01 X:07 Y:00 P:65 SP:FB CYC: 36 SL:63
DB8A  8D 00 02  STA $0200 = 7E                  A:03 X:07 Y:00 P:65 SP:FB CYC: 42 SL:63
DB8D  A9 A9     LDA #$A9                        A:03 X:07 Y:00 P:65 SP:FB CYC: 54 SL:63
DB8F  8D 00 01  STA $0100 = 00                  A:A9 X:07 Y:00 P:E5 SP:FB CYC: 60 SL:63
DB92  A9 55     LDA #$55                        A:A9 X:07 Y:00 P:E5 SP:FB CYC: 72 SL:63
DB94  8D 01 01  STA $0101 = 00                  A:55 X:07 Y:00 P:65 SP:FB CYC: 78 SL:63
DB97  A9 60     LDA #$60                        A:55 X:07 Y:00 P:65 SP:FB CYC: 90 SL:63
DB99  8D 02 01  STA $0102 = 00                  A:60 X:07 Y:00 P:65 SP:FB CYC: 96 SL:63
DB9C  A9 A9     LDA #$A9                        A:60 X:07 Y:00 P:65 SP:FB CYC:108 SL:63
DB9E  8D 00 03  STA $0300 = 01                  A:A9 X:07 Y:00 P:E5 SP:FB CYC:114 SL:63
DBA1  A9 AA     LDA #$AA                        A:A9 X:07 Y:00 P:E5 SP:FB CYC:126 SL:63
DBA3  8D 01 03  STA $0301 = 00                  A:AA X:07 Y:00 P:E5 SP:FB CYC:132 SL:63
DBA6  A9 60     LDA #$60                        A:AA X:07 Y:00 P:E5 SP:FB CYC:144 SL:63
DBA8  8D 02 03  STA $0302 = 00                  A:60 X:07 Y:00 P:65 SP:FB CYC:150 SL:63
DBAB  20 B5 DB  JSR $DBB5                       A:60 X:07 Y:00 P:65 SP:FB CYC:162 SL:63
DBB5  6C FF 02  JMP ($02FF) = A900              A:60 X:07 Y:00 P:65 SP:F9 CYC:180 SL:63
0300  A9 AA     LDA #$AA                        A:60 X:07 Y:00 P:65 SP:F9 CYC:195 SL:63


My emulator correctly executes DB7B "JMP ($0200) = DB7E" by jumping to DB7E. At DBB5, my emulator executes "JMP ($02FF) = A900" and jumps to A900 instead of 0300 like the Nintendulator log says it should. I'm absolutely clueless here. Is the Nintendulator log correct? There has to be an explanation for this... :?

EDIT: The guys on EFnet explained the "hardware quirk" with the indirect jump. I've gotta say, it amazes me how active and helpful the nesdev community is. Thank you guys for helping out a noob like me :)

_________________
Current emulator progress http://forums.nesdev.com/viewtopic.php?f=3&t=10558


Top
 Profile  
 
PostPosted: Thu Oct 10, 2013 12:29 pm 
Offline
User avatar

Joined: Fri Oct 04, 2013 11:56 pm
Posts: 42
Location: Wisconsin
A little after halfway through nestest, I hit some weird NOPs that I wasn't expecting (opcodes 04, 44, and 64). Those are unofficial opcodes right? I wasn't planning on implementing unoffical ones until my emulator is running. If I'm hitting those, is it safe to say my official ones are working and I can move on?

_________________
Current emulator progress http://forums.nesdev.com/viewtopic.php?f=3&t=10558


Top
 Profile  
 
PostPosted: Thu Oct 10, 2013 1:16 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
There are both homebrew and commercial games that use unofficial opcodes. Among them are Puzznic, Super Cars, Driar, and STREEMERZ: Super Strength Emergency Squad Zeta. They're used because they're useful.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 76 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group