Things to do on startup

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
abonetochew
Posts: 34
Joined: Mon Sep 20, 2004 4:07 pm
Location: South Dakota

Things to do on startup

Post by abonetochew »

I've been working on a simple code library to make my life a bit easier, and I was wondering what my code has to do on startup. Currently, my startup routine does this:

Code: Select all

sei             ;disable interrupts (just IRQ/BRK?)
cld             ;decimal mode off (pointless?)
ldx #$ff        ;initialize stack
txs

jsr vbl         ;wait for vblank twice (why?)
jsr vbl

lda #$40
sta $4017       ;disable some kind of IRQ?
Am I missing anything? Is all of this required?
- abonetochew
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

CLD won't make a difference. SEI should be safe to omit if you don't use IRQ's anywhere, ever, but I'd probably keep it anyways.

It'd probably be a good idea to init some other registers at the beginning, too. I always write zero to $2000, $2001, and $4015 before doing the vblank waits. Keeping in mind it's the reset routine, it could be from someone hitting the reset button rather than power. Not that 1/30th of a second of glitching would be noticable, but hey.

As to why you have to wait a couple vblanks, it's pretty much because the PPU needs to warm up. After one full frame it's ready to go (so by waiting for 2, I guess it'll wait 1.1 frames at the least). I don't know what it's doing exactly, but a program that I wrote that started writing to VRAM without waiting had totally corrupt results. Just adding the waits fixed it.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Memblers wrote:It'd probably be a good idea to init some other registers at the beginning, too.
My startup code will clear CPU RAM between the vblank waits.
I always write zero to $2000, $2001, and $4015 before doing the vblank waits.
I thought the program wasn't supposed to do any PPU writes until the PPU warmed up. But if your technique works on real hardware, shouldn't lda #0 sta $2001 be enough to hide everything?
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

tepples wrote: I thought the program wasn't supposed to do any PPU writes until the PPU warmed up. But if your technique works on real hardware, shouldn't lda #0 sta $2001 be enough to hide everything?
Right, but it's a register, not a VRAM access. Seems to be ok to write registers right away, though I haven't tested that much.

The reason I clear $2000 though is to disable NMIs.
Hyde
Posts: 101
Joined: Mon Sep 27, 2004 11:51 pm

Post by Hyde »

BTW Memblers, are you going to set up a new board so people can start posting routines that work on real hardware (as was discussed on the older boards)?
User avatar
abonetochew
Posts: 34
Joined: Mon Sep 20, 2004 4:07 pm
Location: South Dakota

Post by abonetochew »

What exactly does the write to $4017 do?
- abonetochew
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

Hyde wrote:BTW Memblers, are you going to set up a new board so people can start posting routines that work on real hardware (as was discussed on the older boards)?
We might as well do it in the main NESdev forum here, once the code checks out ok would could add it to the site's wiki or something.

abonetochew:
There's a couple things $4017 writes do that I can think of, the big one is the IRQ source select. It can be set to either use internally-generated IRQs, or external (cartridge) ones. The other writable setting is for the 'frame IRQ' interval or whatever it was called. It affects the timing on the sound channels. But I don't remember which bit is which, that's probably the only NES register I don't have memorized actually, heheh. Because I pretty much only write it once in a program, and more often not at all.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Post by Quietust »

Er, not quite. $4017 has only one function - it controls the APU's frame timer. If D7 is set, it runs in a 5-step sequence (48Hz) for pitch bends, timers, etc.; if clear, it runs in a 4-step sequence (60Hz). Clearing D6 causes IRQs to be generated at the end of the 4-step sequence (but not the 5-step one, oddly enough, so setting D6 *or* D7 will turn them off).

[Edit] Whoops, fixed a little bit
Last edited by Quietust on Tue Nov 02, 2004 2:00 pm, edited 1 time in total.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

Aha. I can't remember where I got that idea from. Thanks for the explanation.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Probably because the APU frame IRQs made it appear as an "IRQ source select".

Can anybody with dev hardware confirm an answer to the following question:
Is 'ldx #0 stx $2000 stx $2001' safe before waiting for two vblanks?
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Post by Quietust »

tepples wrote:Is 'ldx #0 stx $2000 stx $2001' safe before waiting for two vblanks?
It most certainly is; in fact, MANY licensed games do exactly this.
It's definitely something you want to do, since otherwise the PPU will possibly be rendering garbage AND generating NMIs during those two frames.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

So does the following init code (not tested) skip anything that the real NES requires?

Code: Select all

BOOTEDSIG0 = $b0
BOOTEDSIG1 = $07
BOOTEDSIG2 = $ed

PPUCTRL = $2000
PPUMASK = $2001
PPUSTATUS = $2002
PPUADDR = $2006
PPUDATA = $2007
SNDCHN = $4015
JOY2 = $4017


nes_start:
  sei
  cld

;; OMIT: Should reset the mapper here.

;; Disable frame IRQ, picture, and sound, and set up stack pointer
  ldx #$40
  stx JOY2
  ldx #0
  stx SNDCHN
  stx PPUCTRL
  stx PPUMASK
  dex
  txs

;; OMIT: Should initialize the lockout defeat here on carts that
;; need it controlled in software (e.g. Color Dreams).

;; Wait for the PPU to warm up.  Must read two vblanks from $2002
;; before any writes to $2003-$2007 or $4014.
@vbl1:
  bit PPUSTATUS
  bpl @vbl1

;; While waiting for the PPU to warm up, prepare the CPU.
;; First clear most of CPU RAM.
  lda #0
  tax
@clrloop:
  sta $00,x
  sta $100,x
  sta $200,x
  sta $300,x
  sta $400,x
  sta $500,x
  sta $600,x
  inx
  bne @clrloop

;; Clear reset-saved CPU RAM
  lda #BOOTEDSIG1
  ldx #BOOTEDSIG2
  ldy #BOOTEDSIG3
  cmp $700
  bne @clrsave
  cpx $701
  bne @clrsave
  cpy $702
  beq @vbl2
@clrsave:
  sta $700
  stx $701
  sty $702
  ldx #3
  lda #0
@clrsaveloop:
  sta $700,x
  inx
  bne @clrsaveloop

;; Second of two waits for the PPU to warm up
@vbl2:
  bit PPUSTATUS
  bpl @vbl2

;; Now we're free to write to the PPU, so clear the nametables.
;; Except on 1-screen mapper and 4-screen mappers, writing to
;; $2400-$2BFF should clear everything.
  ldx #$24
  stx PPUADDR
  ldx #$00
  stx PPUADDR
  lda #' '
@ppuclrloop:
  sta PPUDATA
  sta PPUDATA
  sta PPUDATA
  sta PPUDATA

  sta PPUDATA
  sta PPUDATA
  sta PPUDATA
  sta PPUDATA
  inx
  bne @ppuclrloop

;; Current state:  palette not written, OAM address set but data not
;; written, blank nametables, CHR RAM data not written (on applicable
;; carts), blank CPU RAM (except $703-$7FF if soft reset), video and
;; sound turned off, SP = $01FF, 4-step APU frame counter w/o IRQ,
;; PPUCTRL = #$00
  jmp main
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

Looks like it has everything. Pretty fast, too. Be sure the OAM is cleared before the screen is turned on, also.
family_programmer
Posts: 20
Joined: Mon Apr 11, 2005 6:04 am
Location: Kiev, Ukraine
Contact:

bootsig

Post by family_programmer »

what's the bootsig $700-$702 stuff about (sorry n00b question)?
"Wearing of this garment does not enable you to fly."
-- On a child sized Superman costume.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Post by Bregalad »

I'd just reccomand to write #$00 to $2000 and $2001 as soon as possible after the reset vector (I does this just after the sei; cld myself) because a NMI can be trigerred between the reset signal and the write to $2000
Also I don't know it it's needed to initialize the CPU ram between the two VBlank waits. I think initialise it before both of them make more sense to me (however it doesn't do any difference).
About the $700-$702 stuff, I think he's just checking for particular value in theese 3 bytes, to check if it's the first boot or not. So, he doesn't clear $700-$7ff if it isn't the first boot. I think only one byte would be enough, if the value checked as as much bits set than clear (so it's the values the RAM has the less chances to take on power up). Typically, $aa or $55 works well (Final Fantasy does a similar thing to determine if it has to show the intro or not, and it uses $4b for this value).
Useless, lumbering half-wits don't scare us.
Post Reply