constants with bitwise logic

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
User avatar
nyanberrycake
Posts: 19
Joined: Mon Mar 30, 2020 4:35 pm

constants with bitwise logic

Post by nyanberrycake » Fri Sep 11, 2020 6:34 pm

Im trying to make a page with project settings that I can reuse. the problem is that ca65 doesnt allow bitwise operations in constants assignments

is there a better way to do this?

Code: Select all

BASE_NAMETABLE = 0;keep this here for ease of change
VRAM_INCREMENT = 1;0: add 1, going across; 1: add 32, going down
SPRITE_TABLE = 0;0: $0000, 1: $1000, ignored in 8x16 mode
BACKGROUND_TABLE = 1;0: $0000 1: $1000
SPRITE_SIZE = 1;0: 8x8 pixels 1: 8x16 pixels
PPU_MASTER_SLAVE = 0;leave this alone
GENERATE_NMI = 1; leave default as on

PPU_SETTINGS = BASE_NAMETABLE | (VRAM_INCREMENT << 2) | (SPRITE_TABLE << 3) | (BACKGROUND_TABLE << 4) | (SPRITE_SIZE << 5) |(PPU_MASTER_SLAVE << 6) | GENERATE_NMI << 7)
I could do the same thing but with each option in binary and then just add them all up, but this way is much easier to read

User avatar
dougeff
Posts: 2735
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: constants with bitwise logic

Post by dougeff » Fri Sep 11, 2020 6:51 pm

| GENERATE_NMI << 7)

is this a typo?

should be

| (GENERATE_NMI << 7)

anyway, if it doesn't work, I would just do the bit shifting yourself.

GENERATE_NMI = 1

becomes

GENERATE_NMI = $80
Last edited by dougeff on Fri Sep 11, 2020 6:55 pm, edited 2 times in total.
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: constants with bitwise logic

Post by tokumaru » Fri Sep 11, 2020 6:53 pm

nyanberrycake wrote:
Fri Sep 11, 2020 6:34 pm
the problem is that ca65 doesnt allow bitwise operations in constants assignments
It doesn't? I don't see any reason why this method wouldn't work... What error are you getting?

User avatar
Dwedit
Posts: 4350
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: constants with bitwise logic

Post by Dwedit » Fri Sep 11, 2020 6:55 pm

I once had to simulate Logical Or in a script where you could only use the basic arithmetic operators.

Then you use the rules:
AND(x,y) = x * y
NOT(x) = (1 - x)

From those, you derive OR:

OR(x,y) = NOT(AND(NOT(x), NOT(y))
OR(x,y) = (1 - (1 - x) * (1 - y))
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!

User avatar
nyanberrycake
Posts: 19
Joined: Mon Mar 30, 2020 4:35 pm

Re: constants with bitwise logic

Post by nyanberrycake » Fri Sep 11, 2020 6:59 pm

tokumaru wrote:
Fri Sep 11, 2020 6:53 pm
nyanberrycake wrote:
Fri Sep 11, 2020 6:34 pm
the problem is that ca65 doesnt allow bitwise operations in constants assignments
It doesn't? I don't see any reason why this method wouldn't work... What error are you getting?
Im getting a "Trailing junk characters" error. let me try with that syntax fix from a previous reply

lidnariq
Posts: 9655
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: constants with bitwise logic

Post by lidnariq » Fri Sep 11, 2020 7:00 pm

The convention I've seen on other 8-bit micros is to instead have a set of defines more like... well, this thing I use in my ca65 stuff:

Code: Select all

PPU_CTRL = $2000
.enum PPUCTRL
        NT0 = 0
        NT1 = 1
        NT2 = 2
        NT3 = 3
        INC1 = 0
        INC32 = 4
        SPR_LEFT = 0
        SPR_RIGHT = 8
        BKGD_LEFT = 0
        BKGD_RIGHT = 16
        SPR_8X8 = 0
        SPR_8X16 = 32
        NMI_DIS = 0
        NMI_ENA = 128
.endenum
To express what I want, I can then write:

Code: Select all

LDA #PPUCTRL::NT0 | PPUCTRL::INC1 | PPUCTRL::SPR_RIGHT | PPUCTRL::BKGD_LEFT | PPUCTRL::SPR_8X8 | PPUCTRL::NMI_ENA
STA PPU_CTRL
On the other hand, this is horrifically wordy and long, and my habit on other ISAs is to instead just explain out the bitfields in a comment

Code: Select all

lda #%10001000 ; NmiEn always0 Spr8x8 BkgdLeft SprRight Inc1 2:nt0
sta PPU_CTRL

User avatar
nyanberrycake
Posts: 19
Joined: Mon Mar 30, 2020 4:35 pm

Re: constants with bitwise logic

Post by nyanberrycake » Fri Sep 11, 2020 7:06 pm

dougeff wrote:
Fri Sep 11, 2020 6:51 pm
| GENERATE_NMI << 7)

is this a typo?

should be

| (GENERATE_NMI << 7)

anyway, if it doesn't work, I would just do the bit shifting yourself.

GENERATE_NMI = 1

becomes

GENERATE_NMI = $80
lol thanks you got it. I missed on parenthesis in both the ppu and the mask one I made.

User avatar
nyanberrycake
Posts: 19
Joined: Mon Mar 30, 2020 4:35 pm

Re: constants with bitwise logic

Post by nyanberrycake » Fri Sep 11, 2020 7:10 pm

lidnariq wrote:
Fri Sep 11, 2020 7:00 pm
The convention I've seen on other 8-bit micros is to instead have a set of defines more like... well, this thing I use in my ca65 stuff:

Code: Select all

PPU_CTRL = $2000
.enum PPUCTRL
        NT0 = 0
        NT1 = 1
        NT2 = 2
        NT3 = 3
        INC1 = 0
        INC32 = 4
        SPR_LEFT = 0
        SPR_RIGHT = 8
        BKGD_LEFT = 0
        BKGD_RIGHT = 16
        SPR_8X8 = 0
        SPR_8X16 = 32
        NMI_DIS = 0
        NMI_ENA = 128
.endenum
To express what I want, I can then write:

Code: Select all

LDA #PPUCTRL::NT0 | PPUCTRL::INC1 | PPUCTRL::SPR_RIGHT | PPUCTRL::BKGD_LEFT | PPUCTRL::SPR_8X8 | PPUCTRL::NMI_ENA
STA PPU_CTRL
On the other hand, this is horrifically wordy and long, and my habit on other ISAs is to instead just explain out the bitfields in a comment

Code: Select all

lda #%10001000 ; NmiEn always0 Spr8x8 BkgdLeft SprRight Inc1 2:nt0
sta PPU_CTRL
Yeah I saw how cumbersome that would be so I created a "not going to change much" setting, and then made a couple of alternators on things I might actually use. like this

Code: Select all

BASE_NAMETABLE = 0;keep this here for ease of change
VRAM_INCREMENT = 1;0: add 1, going across; 1: add 32, going down
SPRITE_TABLE = 0;0: $0000, 1: $1000, ignored in 8x16 mode
BACKGROUND_TABLE = 1;0: $0000 1: $1000
SPRITE_SIZE = 1;0: 8x8 pixels 1: 8x16 pixels
PPU_MASTER_SLAVE = 0;leave this alone
GENERATE_NMI = 1; leave default as on

;PPU_SETTINGS is my general purpose cpu control. and I can add in the options below
PPU_SETTINGS = BASE_NAMETABLE | (VRAM_INCREMENT << 2) | (SPRITE_TABLE << 3) | (BACKGROUND_TABLE << 4) | (SPRITE_SIZE << 5) |(PPU_MASTER_SLAVE << 6) | (GENERATE_NMI << 7)

;PPU_SETTINGS options
DISABLE_NMI = %01111111;AND 
INCREMENT_ONE = %11111011;AND 
NAMETABLE_1 = %00000001;OR 
NAMETABLE_2 = %00000010;OR
NAMETABLE_3 = %00000011;OR


User avatar
Movax12
Posts: 526
Joined: Sun Jan 02, 2011 11:50 am

Re: constants with bitwise logic

Post by Movax12 » Sat Sep 12, 2020 10:19 am

Another example of how to do it:

Code: Select all

; General NES constant values

; ports

PPU_CTRL     = $2000
PPU_MASK     = $2001

; For ctrl

CT_NMI            = %10000000
CT_PPUSLAVE       = %01000000
CT_SPRITE8x16     = %00100000
CT_BACKADDR1000   = %00010000
CT_SPRADDR1000    = %00001000
CT_ADDRINC32      = %00000100
CT_NAMETABLE2000  = %00000000
CT_NAMETABLE2400  = %00000001
CT_NAMETABLE2800  = %00000010
CT_NAMETABLE2C00  = %00000011


; For mask

MA_PALETTE_BLUE   = %10000000
MA_PALETTE_GREEN  = %01000000
MA_PALETTE_RED    = %00100000
MA_SPRITESVISIBLE = %00010000
MA_BACKVISIBLE    = %00001000
MA_SPRNOCLIP      = %00000100
MA_BACKNOCLIP     = %00000010
MA_MONOCHROME     = %00000001

.macro ldaPPUctrlBits mask
    lda PPUctrl
    .ifnblank mask
        and mask
    .endif
.endmacro

.macro staPPUctrlBits setbits,update
    .ifnblank setbits
        ora setbits          ; make sure these bits are on
    .endif
    sta PPUctrl              ; shadow
    .ifnblank update
        sta PPU_CTRL         ; hardware			
    .endif
.endmacro

.macro ldaPPUmaskBits mask
    lda PPUmask
    .ifnblank mask
        and mask
    .endif
.endmacro

.macro staPPUmaskBits setbits,update
    .ifnblank setbits
        ora setbits
    .endif
    sta PPUmask
    .ifnblank update
        sta PPU_MASK
    .endif
.endmacro

; examples:

; turn off rendering (wait for your vblank/nmi routine to update the PPU from the shadow):
ldaPPUmaskBits #<~(MA_SPRITESVISIBLE | MA_BACKVISIBLE)
staPPUmaskBits 

; turn on rendering:
ldaPPUmaskBits 
staPPUmaskBits #(MA_SPRITESVISIBLE | MA_BACKVISIBLE)

; turn on NMI requests:
ldaPPUctrlBits 
staPPUctrlBits #CT_NMI, now   ; write to register now, don't wait for vblank


Post Reply