Some of these ideas I don't really need at this time, but looking at what I may need from the perspective of a very large NES project, I have tried to implement things I may need in the future.
High Level code constructs
This is slowly evolving as I find things that don't quite work perfectly or something small gets added. See the documentation here: https://www.assembla.com/spaces/ca65hl/wiki
There is no code created by these macros. They work by creating labels, which CA65 can do utilizing the .sprint() and .ident() built-in functions. I may explain how they work at the macro level in more detail later, but as far as the IF-ENDIF structure, once a stack macro is implemented, tracking logical blocks and spitting out labels is not too difficult. The more difficult part was implementing the flexibility of what can be included as a 'boolean expression'.
Organizing code with libraries and header files
This is a simple but very nice way to organize chunks of code that can be reused later. This simple example is NES controller reading. You could code the routine once, and never have to worry about it again. (This example ignores the DPMC conflict.)
First, write the 'library' code. I've standardized on prefixing all filenames with 'lib_', so this is: lib_controller.inc
The .inc indicates that this is to be included somewhere in the project, it could be in a separate module. (Note, in this code func is a custom macro.)
Code:
.ifndef   _LIB_CONTROLLER_
_LIB_CONTROLLER_ = 1
.scope _LIB_CONTROLLER_ ; keep everything in its own scope
.pushseg
.segment "ZEROPAGE"
    pressed:          .res    2    ; new this frame - held down
    pressedLastFrame: .res    2    ; last frame / call
    pressedNew:       .res    2    ; newly pressed since last frame
    releasedNew:      .res    2    ; newly released since last frame
.popseg
exportfunc         readPort
exportfunc         readPort0
exportfunc         readPort1
.export pressed
.export pressedLastFrame
.export pressedNew
.export releasedNew
func readPort0
    ldx #0
    .byte $CD           ; compare absolute, skip ldx #1
endfunc
func readPort1
    ldx #1
endfunc
func readPort
; IN : player number in reg X = 0, or 1 => 1 or 2
; OUT: Y: undefined, A: PadsNewReleased, X: unchanged
    lda pressed,x         ; save last frame's joystick
    sta pressedLastFrame,x
    lda #1
    sta pressed,x         ; set bit0 to activate carry in do-while loop
    sta $4016
    lsr a                    ; a has 0
    sta $4016
    :
        lda $4016,x
        and #3               ; famicom
        cmp #1              ; friendly reads
        rol pressed,x
    bcc :-
    lda pressed,x
    eor pressedLastFrame,x
    tay
    and pressed,x
    sta pressedNew,x
    tya
    eor pressedNew,x
    sta releasedNew,x
    
    rts
    
endfunc
.endscope
.endif
If this has been included somewhere, now you can access this functionality from any module by including the header file: int_iController.h; Interface for lib_controller.inc
.ifndef _INT_CONTROLLER_H_
_INT_CONTROLLER_H_ = 1
.scope iController
    
    importfunc readPort0
    importfunc readPort1
    importfunc readPort
    
    
    .importZP pressed
    .importZP pressedLastFrame  
    .importZP pressedNew 
    .importZP releasedNew
    
.endscope
.endif
Any module that includes the header file can access the controller reading functionality and the variables via the iController scope:Somewhere in code:
; include the header: .include "int_iController.h"
; elsewhere: lda iController::pressednew and #BUTTON_A bne buttonApressed
This has the advantage of quickly reusing code and speeding up assembly of large projects, since the library code will never have to be assembled again if it is not changed.
Some minor improvements
Pass "-I headerFilefolder -I libraryFileFolder" to the command line of CA65 and keep all headers and libraries in a standard location.
I have standardized on a header file format of prefixing with int_ and created a macro to help make things a bit nicer.
Somewhere in code:
uses iControllerThis will attempt to include "int_iController.h" More to come next time.
