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

stupid question

stupid question
by on (#27253)
I'm using nesasm and i can successfully compile a rom but i get squat when i run it on NesterJ
Code:
; INES header setup
    .inesprg    1   ; One 16k prg bank
    .ineschr    1   ; One 8k  chr bank
    .inesmir    1   ; Vertical map mirroring
    .inesmap    0   ; Use mapper 0

;Colour bars program by Mark Knibbs
    .bank 0
    .org  $C000       ;16Kb PRG-ROM, 8Kb CHR-ROM

   .db   "Colour bars display program v1.1 14-Nov-97 © 1997 by Mark Knibbs <mark_k@iname.com>"

Reset_Routine:
   cld            ;Clear decimal flag
   sei            ;Disable interrupts
.WaitV:   
   lda $2002
   bpl .WaitV      ;Wait for vertical blanking interval
   ldx #$00
   stx $2000
   stx $2001      ;Screen display off, amongst other things
   dex
   txs            ;Top of stack at $1FF

;Clear the NES' WRAM. This routine is ripped from "Duck Hunt" - I should probably clear all $800 bytes.
   ldy #$06      ;To clear 7 x $100 bytes, from $000 to $6FF?
    sty <$01        ;Store count value in $01
   ldy #$00
    sty <$00
   lda #$00

.Clear:
    sta [$00],y     ;Clear $100 bytes
   dey
   bne .Clear

    dec <$01       ;Decrement "banks" left counter
   bpl .Clear      ;Do next if >= 0


;Now we need to set up the palette and colour bar data.
   jsr   SetTables   ;Set up name and attribute table data
   ldy   #$00      ;Initial palette "position"
;Next instruction unnecessary since memory has just been cleared
;   sty <$02         ;Store palette position
   jsr   SetPalette   ;Set initial palette data

;Enable vblank interrupts, etc.
   lda   #$80
   sta   $2000
   lda   #$0B      ;Screen on, sprites off, show leftmost 8 pixels, colour
   sta   $2001
;   cli            ;Enable interrupts(?)

;Now just loop forever?
.Loop:
   jmp   .Loop




;We only need 4 distinct characters, like this:
;
;For low 2 bits of colour number = %00. Character byte number = 0.
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;
;For low 2 bits = %01. Character byte number = 1.
;
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;
;For low 2 bits = %10. Character byte number = 2.
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;   %00000000
;
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;
;For low 2 bits = %11. Character byte number = 3.
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;   %11111111
;
;----------
;
;The display is 256 pixels across. This is 8 columns of 32 pixels, or 16 columns of 16 pixels.
;I'll start off by using 8 columns of 32 pixels.
;
;NOTE: Need to carefully choose which colours to use for the bars. This is because of the "palette
;mirroring" effect (i.e., $3F00 mirrored to $3F04, $3F08 & $3F0C)
;Suitable palette entries to use would be:
; 1  2  3  5  6  7  9  10
;Initially these contain these colour numbers (see palette-setting routine below):
; 0  1  2  3  4  5  6  7


;We'll initially have colour #0 on the left, and colour #7 on the right. So the bytes of the name
;table (at $2000 in PPU space) need to be like this:
;
;Entry1   Entry2   Entry3   Entry5   Entry6   Entry7   Entry9   Entry10
;
;1 1 1 1  2 2 2 2  3 3 3 3  1 1 1 1  2 2 2 2  3 3 3 3  1 1 1 1  2 2 2 2
;
;Fill all 30 rows with this pattern.
;
;
;Now for the attribute table layout. The attr table is 64 bytes long, at $23C0 in PPU space.
;So all 8 rows of the attribute table will be filled with these bytes:
;
; %00000000 %00000000 %00000000 %01010101 %01010101 %01010101 %10101010 %10101010
;In decimal:
;     0         0         0         85        85        85       170       170



;Set the name ($2000) & attribute tables ($23C0)
;-----------------------------------------------
SetTables:

;Set the PPU memory address
   ldx   #$20      ;High byte of $2000
   stx   $2006
   ldx   #$00      ;Low byte of $2000
   stx   $2006

   ldy   #30         ;30 rows to do
.Row:   
   jsr   Set3columns   ;Do the first 3 columns
   jsr   Set3columns   ;Do the next 3 columns
;Now we do the last two bars (last 8 bytes in the row); these are set to 1 1 1 1 2 2 2 2.
   ldx   #$01
   jsr   Set2Columns
   dey
   bne   .Row


;We've set all name table bytes. Now for the attribute table. PPU memory address is already in
;the right place when we get here.
   ldy   #8      ;8 attribute rows to do
.AttrRow:
   ldx   #%00000000
   jsr   Store3      ;Store 0 0 0 in attr table
   ldx   #%01010101
   jsr   Store3      ;Store 85 85 85 in attr table
   ldx   #%10101010
   jsr   Store2      ;Store 170 170 in attr table
   dey
   bne   .AttrRow
   rts         ;That's it!

Set3columns:
   ldx   #$01      ;Start row with 1 1 1 1 bytes
   jsr   Store4
   inx         ;Then 2 2 2 2
Set2Columns
   jsr   Store4
   inx         ;Then 3 3 3 3

Store4:   
   stx   $2007
Store3:   
   stx   $2007
Store2:   
   stx   $2007
   stx   $2007
   rts


;Image palette is at $3F00 in PPU space. We just fill the $10 bytes of it like this initially:
;
;Palette entry #   Colour code
;---------------   -----------
;0         irrelevant
;1         0
;2         1
;3         2
;4         irrelevant
;5         3
;6         4
;7         5
;8         irrelevant
;9         6
;10         7
;11-15         irrelevant
;
;When we want to "rotate" the colour bars, just add 1 to each entry, or subtract 1 from each
;entry. This routine sets the palette data, given an initial colour # in Y
;
;Palette values are contained in the PPU memory space, at:
;$3F00   -   image palette
;$3F10   -   sprite palette   - not used here
;To set the PPU memory address, write high byte and then low byte to $2006.
;Then write to $2007 to "poke" the memory. The auto-increment depends on whether
;bit 2 of $2000 is set. If clear, increment = 1. If set, increment = 32.

SetPalette:

;Set PPU memory address to $3F01 (first palette entry not used)
    ldx #HIGH($3F01) ;High byte of $3F01
   stx   $2006
    ldx #LOW($3F01);Low byte of $3F01
   stx   $2006

   ldx   #3      ;Set three groups of (3 entries + 1 irrelevant)
.Write:
   sty   $2007
   iny
   sty   $2007
   iny
   sty   $2007
   iny

   sty   $2007      ;The irrelevant one
   dex
   bne   .Write
   rts         ;Done!

NMI_Routine:
;Read the controller buttons. Move to the next "colour set" if pressed.
;By shifting the palette values by 1, or -1, we can achieve a "scrolling" effect
;when buttons A & B are pressed.
;Re-write the image palette array if necessary. No need to modify name table data.

;First, save the registers
    php
   pha
   txa
   pha
   tya
   pha

    ldx <$00    ;Get previous button status byte
    stx <$01    ;Put it in $01

;Controller read routine, by Kevin Horton.

;Returns following bits in A:
; Bit      Button
; ---      ------
;  0      Right
;  1      Left
;  2      Down
;  3      Up
;  4      Start
;  5      Select
;  6      B
;  7      A

    ldy #$08        ;Number of iterations
    ldx #$01
    stx $4016       ;store 1 out the strobe
    dex
    stx $4016       ;store 0 out the strobe

.ReadBit:
    lda $4016       ;read the button
    ror A           ;transfer it to the carry flag
    txa
    rol A
    tax             ;rotate X left, storing the bit into the lowest pos.
    dey
    bne .ReadBit    ;loop 8 times for all 8 buttons
;   rts             ;return acc with status of all 8 buttons


;Now we compare the current and previous button values. We want to see if either button A or B
;is pressed, *AND* that button was *NOT* pressed last time.
;To do this:
;· get the current button status.
;· Logical AND with %11000000 (= $C0), giving "CBS", to see if either A or B is pressed. If not,
;  nothing to do.
;· Now we know that at least one of A, B is pressed.
;· get the previous button status.
;· NOT this previous status, giving "NPBS"
;· Logical AND "NPBS" with "CBS".
;· Then bits 6 & 7 are set iff the button is pressed now, but was not pressed last frame. So take
;  action based on this.

   and   #$C0      ;Only interested in A & B at the moment
    sta <$00        ;Use location 0 for storing current controller button data

;Next inst unnecessary since last inst was sta $00
;   lda <$00        ;Get current button status
   beq   .DoNothing   ;If neither button pressed

    lda <$01        ;Get previous button status
   eor   #$FF      ;NOT it
    and <$00        ;AND this with current status
   beq   .DoNothing   ;If no change from last time, do nothing

;Now we can see what action to take.
;If A pressed, shift bars one to the right (i.e., increment palette settings).
;If B pressed, shift bars one to the left (i.e., decrement palette settintgs).

    ldy <$02        ;Get current palette base
    rol A           ;So button A status in carry
   bcc   .NotA

;Shift palette "up by one"
   iny

.NotA:   
    rol A           ;So button B status in carry
   bcc   .NotB

;Shift palette "down by one"
   dey

.NotB:   
    sty <$02
   jsr   SetPalette

.DoNothing:         ;Restore registers and exit.
   pla
   tay
   pla
   tax
   pla
   plp

IRQ_Routine:      ;Dummy label
   rti


;That's all the code. Now we just need to set the vector table approriately.

    .bank 1
   .org   $FFFA
   .dw      NMI_Routine
   .dw      Reset_Routine
   .dw      IRQ_Routine      ;Not used, just points to RTI

    .bank 2
    .org  $0000
    .incbin "color.chr"







what is the problem? :roll:

by on (#27258)
OK, I downloaded this from Mark Knibbs site and the .nes rom he includes also doesnt work (which I assume he also compiled from that source).

I ran it in Nintendulator and the screen is grey. So I would say there is a bug in the code. It looks like the nametables are setup, but the screen doesnt display.

Are you trying to fix the code, or just trying compiling a sample program?


I dont have NESASM so I cant proceed ay further.

Al

by on (#27260)
Oh, my god, if you got it from an old tutorial that was intended to run on Nesticle you should almost throw it away. Maybe a few ideas in the code can give you some ideas how the basics of 6502 code works, but it won't work on hardware, only on Nesticle, unless serious modifications are brought in the code.

by on (#27262)
OK, I looked into it and I can get it to run, there are 2 lines to change and 3 to add. That wont make it good code to reference, but it will do what I think the author intended.


Find the reset subroutine and fix what is being written to $2000 and $2001

change $2000 so it writes $88 instead of $80
change $2001 so it writes $1E instead of $0B

Code:


;Enable vblank interrupts, etc.
        ;lda    #$80  ;change this
        lda     #$88 ; to this
        sta     $2000
        ;lda    #$0B       ;Screen on, sprites off, show leftmost 8 pixels, colour. Change this.
        lda #$1E ; to this
        sta     $2001
;       cli                             ;Enable interrupts(?)



That will at least show you the colour bars.
Problem is the NMI code that reads the joypad and alters them will now only show one color bar. That is because the SetPalette subroutine has altered the PPU pointer. So add these 3 lines just before the rts in SetPallete

Code:
 LDA #$00
 STA $2006
 STA $2006


I converted the code to CA65 , made those changes and it shows the color bars which will move across the screen when A or B is pressed.


Al

by on (#27263)
albailey wrote:
Code:
 LDA #$00
 STA $2006
 STA $2006

Just for the record, the "standard" way to set up scrolling before a frame is rendered is through one write to $2000 (to set the name table bits) and two writes to $2005.

Using $2006 to set the scrolling is a bit "hacky", and should be avoided unless necessary. Two $2006 writes alone are not enough to fully set the scrolling to any point in the name tables.

I'm saying this because many people "fix" demos by writing zeroes to $2006, while they should be using $2000 (writing %xxxxxx00) and $2005 (writing $00 twice) instead. Maybe it's because writing to $2006 is easier.

The cases where the use of $2006 is necessary are when you need to set the scroll after VBlank has ended (ie, when you enable rendering late or when you have a split screen). But even then, you need $2006 only if you have to set the vertical scroll.

by on (#27264)
ahh it was included with nesasm(i think) but i found a tutorial focused around p65 is it better than nesasm?

by on (#27265)
Just for the record, you might want to use binary (%) instead of hex when writing to $2000/$2001. It'll make things ALOT easier.

by on (#27266)
Even easier is to define symbolic constants, combined with many assemblers' | (bitwise or) operator.
Code:
PPUCTRL = $2000
NT_2000 = $00
NT_2400 = $01
NT_2800 = $02
NT_2C00 = $03
VRAM_DOWN = $04
OBJ_0000 = $00
OBJ_1000 = $08
OBJ_8X16 = $20
BG_0000 = $00
BG_1000 = $10
VBLANK_NMI = $80

PPUMASK = $2001
LIGHTGRAY = $01
BG_OFF = $00
BG_CLIP = $08
BG_ON = $0A
OBJ_OFF = $00
OBJ_CLIP = $10
OBJ_ON = $14

  lda #NT_2000|BG_0000|OBJ_8X16|VBLANK_NMI
  sta PPUCTRL
  lda #BG_ON|OBJ_ON
  sta PPUMASK


by on (#27275)
tokumaru wrote:
albailey wrote:
Code:
 LDA #$00
 STA $2006
 STA $2006

Just for the record, the "standard" way to set up scrolling before a frame is rendered is through one write to $2000 (to set the name table bits) and two writes to $2005.

Using $2006 to set the scrolling is a bit "hacky", and should be avoided unless necessary. Two $2006 writes alone are not enough to fully set the scrolling to any point in the name tables.

I'm saying this because many people "fix" demos by writing zeroes to $2006, while they should be using $2000 (writing %xxxxxx00) and $2005 (writing $00 twice) instead. Maybe it's because writing to $2006 is easier.

The cases where the use of $2006 is necessary are when you need to set the scroll after VBlank has ended (ie, when you enable rendering late or when you have a split screen). But even then, you need $2006 only if you have to set the vertical scroll.


There is no scrolling in this code as far as I can see. It is simulating a scrolling effect by cycling/updating the palette.
If you update the palette (or a nametable) dont you need to set your 2006 pointer back to $0000 or else screen updating will stsart from wherever it's currently pointed? Thats all I fixed for him.

Edit- I modified the code as you mentioned and it also works, as did just a single write to $2000 (without the $2005 writes). This makes sense. I wish I knew where the PPU addr pointed to after a write to $2000 (I assume its the start of that particular nametable)

Edit2: After re-reading your response I have a better understanding for what you were saying. The proper way to "reset" your PPU pointer is through a write to $2000, and resetting the scroll registers (whether they are being used or not).
I can see why manually resetting it (through writing $00 twice to $2006)
would be more of a hack.

Al

by on (#27276)
albailey wrote:
I wish I knew where the PPU addr pointed to after a write to $2000 (I assume its the start of that particular nametable)


$2000 does not [directly] change the address at all -- it would still point tot he same place it did before the write.

$2000 does, however, change the nametable bits in the temporary address (which gets copied to the actual PPU address at frame start).

$2000 sets only bits 10 and 11... other bits in the temp address remain unchanged. Therefore if the temp address is $2416 and you write 0 to $2000, the new temp address will be $2016