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:
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".