This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

So I was playing around with NESICIDE's Hello World example

So I was playing around with NESICIDE's Hello World example
by on (#120649)
I've decided it could be fun if I could make it scroll (after changing text from HELLO WORLD to Hello, NES!), so I changed NMI routine. Unfortunately instead of coming from the other side, it just teleports into original place.

Here's my code:
Code:
;
; Russian Roulette game for NES
; Copyright 2010 Damian Yerrick
;
; Copying and distribution of this file, with or without
; modification, are permitted in any medium without royalty
; provided the copyright notice and this notice are preserved.
; This file is offered as-is, without any warranty.
;
.include "nes.h"
.p02

.segment "ZEROPAGE"

.segment "INESHDR"
  .byt "NES",$1A
  .byt 1  ; 16 KiB PRG ROM
  .byt 1  ; 8 KiB CHR ROM
  .byt 1  ; vertical mirroring; low mapper nibble: 0
  .byt 0  ; high mapper nibble: 0

.segment "VECTORS"
  .addr nmi, reset, irq

.segment "CODE"

; we don't use irqs yet
.proc irq
  rti
.endproc

.proc nmi
   lda $28
   clc
   adc #$01
   sta $28
   sta PPUSCROLL
   lda #$00
   sta PPUSCROLL
  rti
.endproc

.proc reset
  sei
  ; clearing $28 used to store x position of scroll.
   ldx #0
   stx $28
  ; Acknowledge and disable interrupt sources during bootup
  stx PPUCTRL    ; disable vblank NMI
  stx PPUMASK    ; disable rendering (and rendering-triggered mapper IRQ)
  lda #$40
  sta $4017      ; disable frame IRQ
  stx $4010      ; disable DPCM IRQ
  bit PPUSTATUS  ; ack vblank NMI
  bit $4015      ; ack DPCM IRQ
  cld            ; disable decimal mode to help generic 6502 debuggers
                 ; http://magweasel.com/2009/08/29/hidden-messagin/
  dex            ; set up the stack
  txs

  ; Wait for the PPU to warm up (part 1 of 2)
vwait1:
  bit PPUSTATUS
  bpl vwait1

  ; While waiting for the PPU to finish warming up, we have about
  ; 29000 cycles to burn without touching the PPU.  So we have time
  ; to initialize some of RAM to known values.
  ; Ordinarily the "new game" initializes everything that the game
  ; itself needs, so we'll just do zero page and shadow OAM.
  ldy #$00
  lda #$F0
  ldx #$00
clear_zp:
  sty $00,x
  inx
  bne clear_zp
  ; the most basic sound engine possible
  lda #$0F
  sta $4015

  ; Wait for the PPU to warm up (part 2 of 2)
vwait2:
  bit PPUSTATUS
  bpl vwait2

  ; Draw HELLO WORLD text
  jsr drawHelloWorld

  ; Turn screen on
  lda #0
  sta PPUSCROLL
  sta PPUSCROLL
  lda #VBLANK_NMI|BG_1000
  sta PPUCTRL
  lda #BG_ON
  sta PPUMASK


mainLoop:
  jmp mainLoop
.endproc


.proc cls
  lda #VBLANK_NMI
  sta PPUCTRL
  lda #$20
  ldx #$00
  stx PPUMASK
  sta PPUADDR
  stx PPUADDR
  ldx #240
:
  sta PPUDATA
  sta PPUDATA
  sta PPUDATA
  sta PPUDATA
  dex
  bne :-
  ldx #64
  lda #0
:
  sta PPUDATA
  dex
  bne :-
  rts
.endproc

.proc drawHelloWorld
  jsr cls

  ; set monochrome palette
  lda #$3F
  sta PPUADDR
  lda #$00
  sta PPUADDR
  ldx #8
:
  lda #$17
  sta PPUDATA
  lda #$38
  sta PPUDATA
  lda #$39
  sta PPUDATA
  lda #$3A
  sta PPUDATA
  dex
  bne :-

  ; load source and destination addresses
  lda #>helloWorld
  sta 1
  lda #<helloWorld
  sta 0
  lda #$20
  sta 3
  lda #$62
  sta 2
  ; fall through
.endproc
.proc printMsg
dstLo = 2
dstHi = 3
src = 0
  lda dstHi
  sta PPUADDR
  lda dstLo
  sta PPUADDR
  ldy #0
loop:
  lda (src),y
  beq done
  iny
  bne :+
  inc src+1
:
  cmp #10
  beq newline
  sta PPUDATA
  bne loop
newline:
  lda #32
  clc
  adc dstLo
  sta dstLo
  lda #0
  adc dstHi
  sta dstHi
  sta PPUADDR
  lda dstLo
  sta PPUADDR
  jmp loop
done:
  rts
.endproc

.segment "RODATA"
helloWorld:
  .byt "Hello, NES!",0


and the NES file is in attachment (so you can see what I meant by "teleporting").

//edit: All custom code, aside of changing palette a bit is in .proc nmi
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120655)
In my notes I have written for scrolling:

* Always do scrolling LAST in NMI routine
* Always clear PPU address latches prior to writing to PPUSCROLL (bit PPUSTATUS does the trick)

So try chaning your NMI to this:

Code:
.proc nmi
   ; Added this line to reset PPU address latches
   bit PPUSTATUS
   lda $28
   clc
   adc #$01
   sta $28
   sta PPUSCROLL
   lda #$00
   sta PPUSCROLL
  rti
.endproc


Hope that helps
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120656)
You're using vertical mirroring, so the width of your scroll space is 512 pixels. You're only scrolling 0 to 255, hence the teleport.
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120665)
rainwarrior, that makes sense. How to change it into single screen mirroring? What I need to change in header?

Also I've changed it to scroll upwards, since I wanted to do it anyway, but when text is near top of the screen, there's sudden "jump". My current nmi is:

Code:
.proc nmi
   ;skipping NMI if $05 is set to $FF
   lda $05
   cmp #$FF
   beq eop
   ; Added this line to reset PPU address latches
   bit PPUSTATUS
   lda $28
   clc
   adc #$01
   sta $28
   lda #$00
   sta PPUSCROLL
   lda $28
   sta PPUSCROLL
   eop:
  rti
.endproc


I've added some debug code to skip NMI if I want (usable when testing things, I guess) but anyway I don't see why it "jumps". Again, .nes file:
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120666)
Your vertical scroll space is 240 pixels and you're scrolling 0 to 255 again.

I don't believe single screen mirroring is a header option in iNES 1. You have to use a mapper that comes with it, like AxROM.
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120700)
Hm. Now I've switched to horizontal mirroring and when scrolling upwards it "teleports", as expected. However how can I change it so it will scroll full two screens then come the other way? $2005 is a byte and thus it can only store values from 0..255 range and I'd need to go through 0..480 for which I'd need to have two bytes...
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120702)
Bits 0 and 1 of $2000 effectively change the high byte of the scroll.

Also is there any reason you're not naming more of your RAM? As in lda skipnmi instead of lda $05?
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120706)
It was done as quick hack. It is named now. By the way, do you have any code that can be used for easy addition/subtraction of 16bit numbers? Compatible with ca65 if possible (preferably as macro).
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120711)
Also how to toggle bits of $2000? While I'm familiar with bitwise logic, when I tried to
Code:
lda $2000
ldx #%00000010
stx $25
eor $25
sta $2000


after text passed first screen, screen turned green for some reason (as if palette changed - it was same shade of green used by text).
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120712)
Adding 16 bit numbers is pretty straight forward. The only difference between adding a 16 bit number and two 8 bit numbers is you don't clear the carry between bytes.

Code:
num1: .res 2
num2: .res 2
result: .res 2

clc
lda num1+0
adc num2+0
sta result+0
lda num1+1
adc num2+1
sta result+1
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120713)
The registers of the PPU are mostly not readable (Exceptions: $2002, $2004 and $2007). You'll need to keep track of the value you wrote to them, rather than being able to read the value back.
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120714)
darkhog wrote:
Also how to toggle bits of $2000? While I'm familiar with bitwise logic, when I tried to
Code:
lda $2000
ldx #%00000010
stx $25
eor $25
sta $2000


after text passed first screen, screen turned green for some reason (as if palette changed - it was same shade of green used by text).


$2000 is a write only register. I don't know what the result of reading it is. (Open bus?)

Just store a copy of the last thing you wrote to it somewhere. Looks like you already stored it at $25 so use that.
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120715)
$2000 is a write register, you cannot read the value from it. If you want to do things like that, store the value it is in RAM as well. Also, you don't need to use another register (X) like you did.

Code:
lda mirror2000
eor #%00000010
sta mirror2000
sta $2000
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120717)
rainwarrior wrote:
$2000 is a write only register. I don't know what the result of reading it is. (Open bus?)
The funny separate internal-to-the-PPU open bus. Still doesn't contain any useful information, though.
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120732)
OK, it's even worse now. I did as you said and now instead of crashing, it resets (I know because I've added code that changes palette upon reset :P)
Current code dealing with PPUCTRL:
Code:
lda #%00000010
   eor $25
   lda $25
   sta PPUCTRL


//edit: False alarm, forgot to put rti... Sorry.
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120734)
Code:
   lda #%00000010
   eor $25
   lda $25
   sta PPUCTRL


Quick note, you never store the result of that eor in the above code, so $25, and by extension PPUCTRL, are never changed.

Code:
   lda #%00000010
   eor $25
   sta $25
   sta PPUCTRL
Re: So I was playing around with NESICIDE's Hello World exam
by on (#120735)
Right! Probably brainfart or something.