Page 2 of 18

Posted: Mon Dec 27, 2010 6:28 am
by tepples
FinalZero wrote:
PPUSCROLL ($2005) is a port on the PPU.
Is there documentation that describes all those special things at addresses like that?
nesdevwiki: PPU registers
Have fun.
Also, while we're on the topic of character maps, how would something like Dual Tile Encoding be implemented?
Wikipedia explains.
Also, are there any Japanese games that implement dakuten and handakuten for their characters by having a dakuten/handakuten tile and simply overlapping it with another, as opposed to creating a whole new set of tiles with the dakuten/handakuten added?
Some games write kana on two rows of tiles, where the dakuten is at the lower right corner of the higher tile. You can't "overlap" tiles per se without sprites, and you can't fit more than 8 sprites on a row of text without some of them disappearing.
koitsu wrote:there's some history indicating only devel builds of ca65 support the .LOBYTE and "<" directives, as well as .HIBYTE and ">" directives.
Every build of ca65 for all the years I've used it has supported the < and > unary operators.

Posted: Mon Dec 27, 2010 6:41 am
by thefox
koitsu wrote: The &255 and /256 syntax appears to be a bunch of nonsense for getting the low and high bytes of the 16-bit address of a label (in this case, the low and high bytes, respectively, of font). I call it nonsense because there's some history indicating only devel builds of ca65 support the .LOBYTE and "<" directives, as well as .HIBYTE and ">" directives. God I hate that assembler. I seriously don't understand why people bother with it.
That's not true, you misunderstood the thread. The "issue" was about .LOBYTES/.HIBYTES, not .LOBYTE/.HIBYTE. LOBYTE/.HIBYTE/</> have always worked fine. And the problem Neil was having could have been fixed by specifying that ZP is a zero page segment with ".segment "ZP":zeropage".

Posted: Mon Dec 27, 2010 6:44 am
by thefox
FinalZero wrote: Digging through ca65's documentation there's a ".feature c_comments" option, thus allowing multiline comments.
Another way to do something similar is to use .if, like so:

Code: Select all

    .if 0
    lda #0
    sta xyzzy
    .endif
I seem to remember that the code between the .if block has to have valid syntax, though.

Posted: Mon Dec 27, 2010 2:33 pm
by koitsu
thefox wrote:
koitsu wrote: The &255 and /256 syntax appears to be a bunch of nonsense for getting the low and high bytes of the 16-bit address of a label (in this case, the low and high bytes, respectively, of font). I call it nonsense because there's some history indicating only devel builds of ca65 support the .LOBYTE and "<" directives, as well as .HIBYTE and ">" directives. God I hate that assembler. I seriously don't understand why people bother with it.
That's not true, you misunderstood the thread. The "issue" was about .LOBYTES/.HIBYTES, not .LOBYTE/.HIBYTE. LOBYTE/.HIBYTE/</> have always worked fine. And the problem Neil was having could have been fixed by specifying that ZP is a zero page segment with ".segment "ZP":zeropage".
Thank you for the clarification/correction. For me, even more disparaging -- and I didn't know this until reviewing ca65's user manual -- is the fact that there are multiple assembler pseudo-ops which are named near-identically:

.HIBYTE vs. .HIBYTES

.LOBYTE vs. .LOBYTES

.BYT vs. .DBYT

.DEFINE vs. .DEFINED

These might not be negatives to those already familiar with the assembler, but I can see an experienced person messing these up. The last example is a stretch given the syntax and operational context, but you get the idea. I'm sure someone could say the same about other assemblers and their syntactical pieces, but the above naming convention seems to imply either "creeping featurism" or an assembler that's trying to do too many things / cater to too many architectures.

Posted: Mon Dec 27, 2010 4:10 pm
by FinalZero
tepples wrote:
FinalZero wrote:
PPUSCROLL ($2005) is a port on the PPU.
Is there documentation that describes all those special things at addresses like that?
nesdevwiki: PPU registers
Have fun.
Also, while we're on the topic of character maps, how would something like Dual Tile Encoding be implemented?
Wikipedia explains.
Also, are there any Japanese games that implement dakuten and handakuten for their characters by having a dakuten/handakuten tile and simply overlapping it with another, as opposed to creating a whole new set of tiles with the dakuten/handakuten added?
Some games write kana on two rows of tiles, where the dakuten is at the lower right corner of the higher tile. You can't "overlap" tiles per se without sprites, and you can't fit more than 8 sprites on a row of text without some of them disappearing.
koitsu wrote:there's some history indicating only devel builds of ca65 support the .LOBYTE and "<" directives, as well as .HIBYTE and ">" directives.
Every build of ca65 for all the years I've used it has supported the < and > unary operators.
1) Thank you.
2) So, one would make a function to transform something from DTE that operates on every string desired? I don't quite understand.
3) Ah, interesting.
.BYT vs. .DBYT
What is the name ".dbyt" supposed to stand for anyways?

-----

I still can't get the Hello World Example to work. It assembles, but doesn't work.

-----

I used the following code in nbasic to read the first gamepad. I suppose it spoiled me, because I can't figure out how to transform the set C1_... lines into ca65 assembly. Am I supposed to push the results onto the stack?

Code: Select all

// Updates the statuses of the first gamepad's buttons.
UpdateGamepad1:
	// Strobe Bytes
	set $4016 1 // First
	set $4016 0 // Second
	
	set C1_A      & [$4016] 1
	set C1_B      & [$4016] 1
	set C1_Select & [$4016] 1
	set C1_Start  & [$4016] 1
	set C1_Up     & [$4016] 1
	set C1_Down   & [$4016] 1
	set C1_Left   & [$4016] 1
	set C1_Right  & [$4016] 1
	
	return
//------------------------------------------------------------

Posted: Mon Dec 27, 2010 4:16 pm
by clueless
This might help. It is my entire joypad read routine, coded for ca65:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;      joypad_read
;;
;;      On input: Nothing.
;;      On Exit: 'joypad1' and 'joypad2' contain 8 button states, in normal NES order:
;;      a, b, sel, start, up, down, left, right
;;      Destroys X.
;;      Code taken from http://nesdevwiki.org/index.php/Gamepad_code.

;; WARNING: Will randomly fail if using DCPM sound channel.
;; http://nocash.emubase.de/everynes.htm, "Controllers - Joypads"

.segment        "KERNEL"
.proc           joypad_read

                lda     joypad1_orig
                sta     joypad1_prev    ; Used for calculating 'one-shot' button mode.
                lda     joypad2_orig
                sta     joypad2_prev

                ldx     #09             ; Set counter to '8' and set strobe bit
                stx     JOYPAD_1        ; Strobe pad #1 + #2
                dex                     ; X = 8 (loop counter)
                stx     JOYPAD_1        ; Clear strobe bits.
:               lda     JOYPAD_1        ; bit0 = input button.
                lsr                     ; bit0 -> carry
                rol     joypad1         ; bit0 <- carry
                lda     JOYPAD_2
                lsr
                rol     joypad2
                dex
                bne     :-

                lda     joypad1
                sta     joypad1_orig    ; Needed for future one-shot calculation.
                lda     joypad2
                sta     joypad2_orig

                rts
.endproc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;      joypad_debounce
;;
;;      Pass bitmask of buttons to debounce in 'A'.  That is, if the button
;;      was pushed last frame, and this frame, then make it appear OFF this frame.

.segment        "KERNEL"
.proc           joypad_debounce

;; On entry, Acc is mask of buttons to cook.
                pha                             ; Save mask for joypad #2
                and     joypad1                 ; Which buttons are pressed down?
                and     joypad1_prev            ; Where they down last frame?
                eor     joypad1                 ; Turn them off this frame.
                sta     joypad1
                pla
                and     joypad2
                and     joypad2_prev
                eor     joypad2
                sta     joypad2
                rts
.endproc


Posted: Mon Dec 27, 2010 4:28 pm
by clueless
(slightly off topic): If my dual-joypad reading and debouncing code is acceptable to the powers-that-be, then feel free to add it to the wiki.

In my own game I am contemplating merging the two functions. I just have to track down all calls to each to ensure that I never read without debouncing immediately afterwards.

I also have the following in my "./src/nes.inc" header file:

Code: Select all

JOYPAD_1                = $4016
JOYPAD_2                = $4017

BTN_A                   = $80
BTN_B                   = $40
BTN_SEL                 = $20
BTN_START               = $10
BTN_UP                  = $08
BTN_DOWN                = $04
BTN_LEFT                = $02
BTN_RIGHT               = $01
BTN_ALL                 = $ff
And this in yet another file:

Code: Select all

djenkins@hera ~/code/nesyar $ grep joypad src/globals.s
joypad1:                .byte   0               ; Cooked value for this frame.
joypad2:                .byte   0
joypad1_prev:           .byte   0               ; Original value from last frame.
joypad2_prev:           .byte   0
joypad1_orig:           .byte   0               ; Original value from this frame.
joypad2_orig:           .byte   0

Posted: Mon Dec 27, 2010 4:38 pm
by FinalZero

Code: Select all

                lda     joypad1_orig 
                sta     joypad1_prev    ; Used for calculating 'one-shot' button mode. 
                lda     joypad2_orig 
                sta     joypad2_prev 
Are these defined somewhere earlier?

Edit: Nevermind. Serves me right for not refreshing the page before posting...

Posted: Mon Dec 27, 2010 4:44 pm
by clueless
:) I should have made one post instead of two.

It helps if you know what I mean by "joypad debouncing". I don't know if others use the same terms. I adopted "debounce" from the idea of electrically debouncing push buttons using a timer circuit (like a 555 in one-shot mode).

In my game, the user can hold down "B" to make the Yar fly "faster" (like in SMB). But the user must press and release "A" to fire a bullet. Select changes the "weapon/gun" type, and Start pauses/unpauses the game. Both start and select must be debounced, or if the user holds them down the mode will switch every frame. So I want to debounce "A" and not "B" nor the direction keys. So my actual game engine does this:

Code: Select all

		jsr	joypad_read
		lda	#(BTN_A | BTN_SEL | BTN_START)
		jsr	joypad_debounce
		jsr	check_for_pause_unpause

Posted: Mon Dec 27, 2010 5:00 pm
by FinalZero
I was able to infer from the context what you meant. I've already implemented such a thing in nbasic. There was an example that showed me how.

Code: Select all

// Handles input from the first controller.
HandleInput:
	// Updates the first gamepad.
	gosub UpdateGamepad1
//	gosub UpdateGamepad2
	
	// A Button
	if C1_A = 0 set C1_AIsPressed 0
	
	if C1_A = 1 if C1_AIsPressed = 0 then
		set C1_AIsPressed 1
		
		set SpriteNum + SpriteNum 1
		endif

	// B Button
	if C1_B = 0 set C1_BIsPressed 0

	if C1_B = 1 if C1_BIsPressed = 0 then
		set C1_BIsPressed 1
		
		set SpriteNum - SpriteNum 1
		endif
	
	// Start Button
	if C1_Start = 0 set C1_StartIsPressed 0
	
	if C1_Start = 1 if C1_StartIsPressed = 0 then
		set C1_StartIsPressed 1
		
		set SpriteX 128 // 128 * 2 = 256
		set SpriteY 120 // 120 * 2 = 240
		endif
	
	// Select Button
	if C1_Select = 0 set C1_SelectIsPressed 0
	
	if C1_Select = 1 if C1_SelectIsPressed = 0 then
		set C1_SelectIsPressed 1
	
		set SpriteNum + SpriteNum $F // Spritnum += 16
		
		// Displays the menu.
		if MenuIsDisplayed = 0 then
			set MenuIsDisplayed 1
			// fix
			endif
			
		endif
	
	// Up
	if C1_Up = 1
		set SpriteY - SpriteY C1_Up
		goto EndHandleInput
	
	// Down
	if C1_Down = 1
		set SpriteY + SpriteY C1_Down
		goto EndHandleInput
	
	// Left
	if C1_Left = 1
		set SpriteX - SpriteX C1_Left
		goto EndHandleInput
	
	// Right
	if C1_Right = 1
		set SpriteX + SpriteX C1_Right
		goto EndHandleInput

	EndHandleInput:
	return
//------------------------------------------------------------
Edit:
Ok, so here's a simple piece of code which I think would work to read in stuff from controller without debouncing. I'm itching to try it out!

Code: Select all

; Gamepad Locations
GamepadA = $4016
GamepadB = $4017
;---------------------------------------------------------------------------

; Button Flags
Button_A      = %10000000
Button_B      = %01000000
Button_Select = %00100000
Button_Start  = %00010000
Button_Up     = %00001000
Button_Down   = %00000100
Button_Left   = %00000010
Button_Right  = %00000001
;---------------------------------------------------------------------------

GamepadAFlags: .byte 0
GamepadBFlags: .byte 0
;GamepadAPrev:  .byte 0
;GamepadBPrev:  .byte 0
;GamepadAOrig:  .byte 0
;GamepadBOrig:  .byte 0
;---------------------------------------------------------------------------

; Updates the flags for the first gamepad.
UpdateGamepadAFlags:
	; Strobe Bytes
	; First
	ldx 1
	stx GamepadA
	
	; Second
	ldx 0
	stx GamepadA

	.repeat 8
		lda GamepadA      ; bit0 = current button
		shr               ; bit0 -> carry
		rol GamepadAFlags ; bit0 <- carry
	.endrepeat
	
	rts
;---------------------------------------------------------------------------
Edit: Another question: What's the difference between .proc and .scope for ca65? Their descriptions are nearly the same in the documentation:
http://www.cc65.org/doc/ca65-11.html#ss11.79
http://www.cc65.org/doc/ca65-11.html#ss11.86

Posted: Tue Dec 28, 2010 7:58 am
by tepples
FinalZero wrote:So, one would make a function to transform something from DTE that operates on every string desired?
There are two ways to do this: A. make a function that takes a DTE string and returns a decompressed string, or B. make a function that starts a decoding process and retrieves the next decompressed character.
.BYT vs. .DBYT
What is the name ".dbyt" supposed to stand for anyways?
Double byte, I guess.

The difference I can see between .proc and .scope is that .proc defines a label in the outer scope for the start.

Posted: Wed Dec 29, 2010 5:33 pm
by FinalZero
The difference I can see between .proc and .scope is that .proc defines a label in the outer scope for the start.
I understand now.

Well, since the hello world example given earlier doesn't work, I've begun to look elsewhere. The following is from lj65's source.

Code: Select all

.segment "INESHDR"

  .byt "NES", 26
  .byt 1  ; number of 16 KB program segments
  .byt 1  ; number of 8 KB chr segments
  .byt 0  ; mapper, mirroring, etc
  .byt 0  ; extended mapper info
  .byt 0  ; number of 8 KB RAM segments
; The next two bytes are supposed to define PAL/NTSC versions
; of a given ROM, but they make Nintendulator cry.
.ifdef PAL
  .byt 0
  .byt %00000000
.else
  .byt 0
  .byt %00000000
.endif
  .byt 0
  .byt 0,0,0,0  ; DiskDude detection
1) What does the ".segment "INESHDR" do? There's no predefined segment by that name, so I'm confused. What would happen if it was left out?
2) Does "number of 16 KB program segments" mean that one has go through one's source and count how many segments there are?
3) What is a mapper? Why do different games use different ones? I keep finding lists of them, but nothing that actually explains what they are and do.
4) What is a nametable? What's stored in them? And yes, I've read http://wiki.nesdev.com/w/index.php/PPU_nametables
5) From http://wiki.nesdev.com/w/index.php/Mirroring :
Vertical [...] This is most commonly used for games which only scroll horizontally. Games that scroll vertically (by any amount and without status bar) and that does [sic] never scroll horizontally by more than one screen would use this mirroring (e.g. Lode Runner, Bomberman, Fire Emblem, Crystal Mines), so that they don't have to load anything when scrolling horizontally.
I'm confused because it seems to contradict itself. Does that mean it's used for games that scroll horizontally or not?

Also, why doesn't one need ".org $0000" at the beginning of the header? Is it implied?

Posted: Wed Dec 29, 2010 5:52 pm
by clueless
In ca65, you let the linker assign the final location in the output file of each segment. You are discouraged from using ".org".

It seems that each of us that uses ca65 builds our "ines" headers a bit differently (as far as how we get the linker to pre-pend it to the beginning of our ROMs). My example is below. This is for a game that I tinkered with a few years ago and gave up on. But it does link and execute properly.

Specifically, look at "src/linker.cfg", then at "src/kernel/header.s".

In your ".s" files, you just set the "segment" and then write code and define data bytes (words or whatever you need). You tell the linker, through a config file, how to lay each segment out into the ROM image. The linker will take care of doing the "fixups", so that "lda player1_health" gets the correct address for the symbol "player1_health". However, ca65 knows NOTHING about bankswitching. You must ensure that the correct banks are switched in (using the "mapper") before accessing a symbol unique to that bank.

My game uses MMC1 with a very large PROG-ROM. I have code in a few banks.

If you know what "subversion" (revision control system) is, you can obtain a complete copy of my source and build it on Linux. YMMV when compiling on win32 (my windows build scripts assume that you have msdev studio 98 (vc6.0) installed).

https://www.ecoligames.com/svn/nes-game/trunk/

Subversion copy:
svn co https://www.ecoligames.com/svn/nes-game/trunk clueless-game

View source with syntax highlighting via "trac":
https://www.ecoligames.com/trac/nes-game/browser/trunk
(I forget the user/pass that you'll need. If you want it, ask and I'll go dig it up).

I hope that the above helps you. If not, I know that many others use ca65 and can help too.

Posted: Wed Dec 29, 2010 6:35 pm
by FinalZero
(I forget the user/pass that you'll need. If you want it, ask and I'll go dig it up).
Could you please?

Posted: Wed Dec 29, 2010 6:45 pm
by clueless
I thought that I had posted it to this forum in 2008. So I went back and dug through my posts. I did not find the "public" user/pass, so I will reset it in a moment. But I did find this (about ca65 and linking). Maybe it will help you as well:

http://nesdev.com/bbs/viewtopic.php?p=37306

The user / pass for "trac" is "anonymous" and "nesdev". It should have full read access to the trac repository. Note that you shouldn't need a user/pass to do an "svn co".