Assembly CPU: Flags

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Assembly CPU: Flags
by on (#78931)
I am writing the CPU for my NES emulator in assembly, but I am getting confused by the difference between the assembly I am coding in and the 6502 assembly that the NES uses, particularly the flags.

This is my code for setting/clearing flags:
Code:
MODIFYFLAGS MACRO Sign, Overflow, Zero, Carry

   ; Clear all the flags if they are passed.
   pushfd
   IFNB <Sign>
      and CPU.F, 01111111b
   ENDIF
   IFNB <Overflow>
      and CPU.F, 10111111b
   ENDIF
   IFNB <Zero>
      and CPU.F, 11111101b
   ENDIF
   IFNB <Carry>
      and CPU.F, 11111110b
   ENDIF
   popfd
   
   ; Set the flags that are passed to the macro.
   
   IFNB <Sign>
      pushfd
      sets dl
      shl dl, 7
      or CPU.F, dl
      popfd
   ENDIF
   IFNB <Overflow>
      pushfd
      seto dl
      shl dl, 6
      or CPU.F, dl
      popfd
   ENDIF
   IFNB <Zero>
      pushfd
      setz dl
      shl dl, 1
      or CPU.F, dl
      popfd
   ENDIF
   IFNB <Carry>
      pushfd
      setc dl
      or CPU.F, dl
      popfd
   ENDIF
ENDM

Does this create separate flags or use the existing flags of the assembly language I am coding in? If it's the latter, is there a way to keep certain instructions from setting flags? Any general information on this would be appreciated.

by on (#79164)
If anybody who knows assembly language, particularly anyone who has coded an emulator in assembly, is reading this, please help. I would like to get my CPU working better before I deal with many other aspects of my emulator. If anyone is confused by what I'm asking, I found the following document that discusses this issue (and many other things): http://nesdev.icequake.net/NES%20emulat ... ussion.txt

by on (#79165)
It would be better to put all flags in separate bytes so you can use setCC individually on each flag. Here's how I've been doing it:

Code:
.saveSZCV:
   seto [cpu.flag.v]
.saveSZC:
   setc [cpu.flag.c]
.saveSZ:
   sets [cpu.flag.s]
   setz [cpu.flag.z]
   ret

;
; Read operations
; al = the value read from memory
;
.and:
   and [cpu.a], al
   jmp .saveSZ

.eor:
   xor [cpu.a], al
   jmp .saveSZ

.ora:
   or [cpu.a], al
   jmp .saveSZ

.lda:
   mov [cpu.a], al
   test al, al
   jmp .saveSZ


i.e. cpu.flags is just a struct with one byte for each flag.
Whenever the status register is read (like when it's pushed onto the stack), you will then need to pack those bytes together to an 8-bit value.

by on (#79169)
These days, there really isn't a very good reason that I can think of to code an NES emulator in assembly anymore. With the exception of nemulator, who needs to run 32 emulators at the same time, why would you go through the pain to do that?

by on (#79185)
You can always peek at the LoopyNES source code and see how that emulator did it.

by on (#79186)
Zelex wrote:
These days, there really isn't a very good reason that I can think of to code an NES emulator in assembly anymore. [...] why would you go through the pain to do that?

For the same reason people start writing new emulators eventhough there already are plenty of good ones out there - it's just fun to have something to tinker with in your spare time. Working with assembly, you also tend to learn a lot about microprocessors and operating systems in general.
As for optimization, a compiler will almost always do a better job than a human so performance is not a reason to prefer assembly over C++.

But yeah, modern computers are fast enough to emulate the NES perfectly even in a VM. I wrote a "pixel-perfect" emulator in Java a couple of years ago and it ran at full speed. I see you're working on one in JavaScript, should work fine since Google's V8 is incredibly fast.

I wonder if we'll ever see a NES emu written in python or perl? :)

by on (#79187)
lol :) NES emulator in perl... oh god!

Yeah, learning and experimenting is always a good reason! :)

by on (#79202)
I might be one of the only people left (?) who has done a 6502 emulator in actual x86 assembly. I wonder how many people here remember the qNES project (no, it was never released).

It'll be a cold day in hell before I re-learn x86 though. Worst processor on the planet. Ugh.

by on (#79217)
Hey, x86 has its uses... Disassembling and hacking Japanese Windows programs so you can translate them, checking how good a compiler is at optimizing code, and that's about it.
Re: Assembly CPU: Flags
by on (#79222)
6T4 wrote:
This is my code for setting/clearing flags:
Code:
MODIFYFLAGS MACRO Sign, Overflow, Zero, Carry

Quote:
Does this create separate flags or use the existing flags of the assembly language I am coding in?

If it's your code, surely you should know what it does? [But it's not "your code", it's a direct copy from cpu.asm of NEStreme. Might be a good idea to mention that...] I'm sorry but you can't expect somebody to walk you through all of this.

by on (#79225)
Thank you for the replies so far, especially the example from Nessie. I will continue to work on this and let everyone know my progress.

Dwedit wrote:
You can always peek at the LoopyNES source code and see how that emulator did it.

I wasn't aware that LoopyNES was open source. Do you have a link to its source code?

koitsu wrote:
I wonder how many people here remember the qNES project (no, it was never released).

You mean QuantumNES? I removed the buggy CPU from it and corrected the iNES header viewer and released that as NESFaCE Version 0.01 Alpha.

thefox wrote:
But it's not "your code", it's a direct copy from cpu.asm of NEStreme. Might be a good idea to mention that...

By "my code", I meant the code I was currently using. I did not intend to imply that it was my original work. I have stated on this forum before that I was basing my emulator on NEStreme (and will be basing it on many other emulators in the future). Right now, I am studying the errors in NEStreme to correct them and/or program some areas in a more optimal way to eventually become NESFaCE. However, I agree that maybe I should have been clearer about this. I will try to be more careful in the future.

by on (#79226)
6T4 wrote:
koitsu wrote:
I wonder how many people here remember the qNES project (no, it was never released).

You mean QuantumNES? I removed the buggy CPU from it and corrected the iNES header viewer and released that as NESFaCE Version 0.01 Alpha.


Nope, this qNES. Probably before your time (note article date). God damn I'm old. Anyway the article should amuse folks present-day, since it was before we knew what we do now (no decimal mode, different PPU behaviour, etc.). Here's a brief mention of the discontinuation of qNES. Ahh, memories of my old projects...

by on (#79227)
6T4 wrote:
Dwedit wrote:
You can always peek at the LoopyNES source code and see how that emulator did it.

I wasn't aware that LoopyNES was open source. Do you have a link to its source code?


Look on his page, http://home.comcast.net/~olimar/NES/

by on (#79238)
Quote:
I wonder if we'll ever see a NES emu written in python or perl?


I began writing an NES emulator in Perl back in 2004 or something like that, but I ditched it after a while to work on other projects. I think I had finished most of the CPU, plus some other stuff, but I don't know if I still have the code.