Page 1 of 1

stupid question

Posted: Fri Sep 28, 2007 5:56 am
by meshounah
I'm using nesasm and i can successfully compile a rom but i get squat when i run it on NesterJ

Code: Select all

; 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:

Posted: Fri Sep 28, 2007 6:58 am
by albailey
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

Posted: Fri Sep 28, 2007 9:40 am
by Bregalad
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.

Posted: Fri Sep 28, 2007 2:53 pm
by albailey
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: Select all



;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: Select all

 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

Posted: Fri Sep 28, 2007 3:20 pm
by tokumaru
albailey wrote:

Code: Select all

 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.

Posted: Fri Sep 28, 2007 3:26 pm
by meshounah
ahh it was included with nesasm(i think) but i found a tutorial focused around p65 is it better than nesasm?

Posted: Fri Sep 28, 2007 5:57 pm
by atari2600a
Just for the record, you might want to use binary (%) instead of hex when writing to $2000/$2001. It'll make things ALOT easier.

Posted: Fri Sep 28, 2007 6:26 pm
by tepples
Even easier is to define symbolic constants, combined with many assemblers' | (bitwise or) operator.

Code: Select all

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


Posted: Sat Sep 29, 2007 2:13 pm
by albailey
tokumaru wrote:
albailey wrote:

Code: Select all

 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

Posted: Sat Sep 29, 2007 2:59 pm
by Disch
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