Simplify long, repetitive code.

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

sdm
Posts: 288
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Simplify long, repetitive code.

Post by sdm » Sat Jul 08, 2017 1:53 am

I have a problem with simplifying some code. I would like to minimize the size of this code, but the functionality must be identical:

Code: Select all

LEV_Check:

	LDA Variable
	CMP #1
	BNE No_01
	LDA #$02
	STA SPR_X
	JMP LEV01
No_01:
	LDA Variable
	CMP #2
	BNE No_02
	LDA #$02
	STA SPR_X
	JMP LEV02
No_02:
	LDA Variable
	CMP #3
	BNE No_03
	LDA #$02
	STA SPR_X
	JMP LEV03
No_03:
	LDA Variable
	CMP #4
	BNE No_04
	LDA #$02
	STA SPR_X
	JMP LEV04
No_04:
	LDA Variable
	CMP #5
	BNE No_05
	LDA #$02
	STA SPR_X
	JMP LEV05
No_05:
	LDA Variable
	CMP #6
	BNE No_06
	LDA #$02
	STA SPR_X
	JMP LEV06
No_06:
	LDA Variable
	CMP #7
	BNE No_07
	LDA #$02
	STA SPR_X
	JMP LEV07
No_07:
	LDA Variable
	CMP #8
	BNE No_08
	LDA #$02
	STA SPR_X
	JMP LEV08
No_08:
	LDA Variable
	CMP #9
	BNE No_09
	LDA #$02
	STA SPR_X
	JMP LEV09
No_09:
	LDA Variable
	CMP #10
	BNE No_10
	LDA #$02
	STA SPR_X
	JMP LEV10
No_10:
	LDA Variable
	CMP #11
	BNE No_11
	LDA #$02
	STA SPR_X
	JMP LEV11
No_11:
	LDA Variable
	CMP #12
	BNE No_12
	LDA #$02
	STA SPR_X
	JMP LEV12
No_12:
	LDA Variable
	CMP #13
	BNE No_13
	LDA #$02
	STA SPR_X
	JMP LEV13
No_13:
	LDA Variable
	CMP #14
	BNE No_14
	LDA #$02
	STA SPR_X
	JMP LEV14
No_14:
	LDA Variable
	CMP #15
	BNE No_15
	LDA #$02
	STA SPR_X
	JMP LEV15
No_15:
	LDA Variable
	CMP #16
	BNE No_16
	LDA #$02
	STA SPR_X
	JMP LEV16
No_16:
	LDA Variable
	CMP #17
	BNE No_17
	LDA #$02
	STA SPR_X
	JMP LEV17
No_17:
	LDA Variable
	CMP #18
	BNE No_18
	LDA #$02
	STA SPR_X
	JMP LEV18
No_18:
	LDA Variable
	CMP #19
	BNE No_19
	LDA #$02
	STA SPR_X
	JMP LEV19
No_19:
	LDA Variable
	CMP #20
	BNE No_20
	LDA #$02
	STA SPR_X
	JMP LEV20
No_20:
	LDA Variable
	CMP #21
	BNE No_21
	LDA #$02
	STA SPR_X
	JMP LEV21
No_21:
	LDA Variable
	CMP #22
	BNE No_22
	LDA #$02
	STA SPR_X
	JMP LEV22
No_22:
	LDA Variable
	CMP #23
	BNE No_23
	LDA #$02
	STA SPR_X
	JMP LEV23
No_23:
	LDA Variable
	CMP #24
	BNE No_24
	LDA #$02
	STA SPR_X
	JMP LEV24
No_24:
	LDA Variable
	CMP #25
	BNE No_25
	LDA #$02
	STA SPR_X
	JMP LEV25
No_25:
	LDA Variable
	CMP #26
	BNE No_26
	LDA #$02
	STA SPR_X
	JMP LEV26
No_26:
	LDA Variable
	CMP #27
	BNE No_27
	LDA #$02
	STA SPR_X
	JMP LEV27
No_27:
	LDA Variable
	CMP #28
	BNE No_28
	LDA #$02
	STA SPR_X
	JMP LEV28
No_28:
	LDA Variable
	CMP #29
	BNE No_29
	LDA #$02
	STA SPR_X
	JMP LEV29
No_29:
	LDA Variable
	CMP #30
	BNE No_30
	LDA #$02
	STA SPR_X
	JMP LEV30
No_30:
	LDA Variable
	CMP #31
	BNE No_31
	LDA #$02
	STA SPR_X
	JMP LEV31
No_31:
	LDA Variable
	CMP #32
	BNE No_32
	LDA #$02
	STA SPR_X
	JMP LEV32
No_32:
	LDA Variable
	CMP #33
	BNE No_33
	LDA #$02
	STA SPR_X
	JMP LEV33
No_33:
	LDA Variable
	CMP #34
	BNE No_34
	LDA #$02
	STA SPR_X
	JMP LEV34
No_34:
	LDA Variable
	CMP #35
	BNE No_35
	LDA #$02
	STA SPR_X
	JMP LEV35
No_35:
	LDA Variable
	CMP #36
	BNE No_36
	LDA #$02
	STA SPR_X
	JMP LEV36
No_36:
	LDA Variable
	CMP #37
	BNE No_37
	LDA #$02
	STA SPR_X
	JMP LEV37
No_37:
	LDA Variable
	CMP #38
	BNE No_38
	LDA #$02
	STA SPR_X
	JMP LEV38
No_38:
	LDA Variable
	CMP #39
	BNE No_39
	LDA #$02
	STA SPR_X
	JMP LEV39
No_39:
	LDA Variable
	CMP #40
	BNE No_40
	LDA #$02
	STA SPR_X
	JMP LEV40
No_40:
	LDA Variable
	CMP #41
	BNE No_41
	LDA #$02
	STA SPR_X
	JMP LEV41
No_41:
	LDA Variable
	CMP #42
	BNE No_42
	LDA #$02
	STA SPR_X
	JMP LEV42
No_42:
	LDA Variable
	CMP #43
	BNE No_43
	LDA #$02
	STA SPR_X
	JMP LEV43
No_43:
	LDA Variable
	CMP #44
	BNE No_44
	LDA #$02
	STA SPR_X
	JMP LEV44
No_44:
	LDA Variable
	CMP #45
	BNE No_45
	LDA #$02
	STA SPR_X
	JMP LEV45
No_45:
	LDA Variable
	CMP #46
	BNE No_46
	LDA #$02
	STA SPR_X
	JMP LEV46
No_46:
	LDA Variable
	CMP #47
	BNE No_47
	LDA #$02
	STA SPR_X
	JMP LEV47
No_47:
	LDA Variable
	CMP #48
	BNE No_48
	LDA #$02
	STA SPR_X
	JMP LEV48
No_48:
	LDA Variable
	CMP #49
	BNE No_49
	LDA #$02
	STA SPR_X
	JMP LEV49
No_49:
	LDA Variable
	CMP #50
	BNE No_50
	LDA #$02
	STA SPR_X
	JMP LEV50
No_50:
	LDA Variable
	CMP #51
	BNE No_51
	LDA #$02
	STA SPR_X
	JMP LEV51
No_51:
	LDA Variable
	CMP #52
	BNE No_52
	LDA #$02
	STA SPR_X
	JMP LEV52
No_52:
	LDA Variable
	CMP #53
	BNE No_53
	LDA #$02
	STA SPR_X
	JMP LEV53
No_53:
	LDA Variable
	CMP #54
	BNE No_54
	LDA #$02
	STA SPR_X
	JMP LEV54
No_54:
	LDA Variable
	CMP #55
	BNE No_55
	LDA #$02
	STA SPR_X
	JMP LEV55
No_55:
	LDA Variable
	CMP #56
	BNE No_56
	LDA #$02
	STA SPR_X
	JMP LEV56
No_56:
	LDA Variable
	CMP #57
	BNE No_57
	LDA #$02
	STA SPR_X
	JMP LEV57
No_57:
	LDA Variable
	CMP #58
	BNE No_58
	LDA #$02
	STA SPR_X
	JMP LEV58
No_58:
	LDA Variable
	CMP #59
	BNE No_59
	LDA #$02
	STA SPR_X
	JMP LEV59
No_59:
	LDA Variable
	CMP #60
	BNE No_60
	LDA #$02
	STA SPR_X
	JMP LEV60
No_60:
	LDA Variable
	CMP #61
	BNE No_61
	LDA #$02
	STA SPR_X
	JMP LEV61
No_61:
	LDA Variable
	CMP #62
	BNE No_62
	LDA #$02
	STA SPR_X
	JMP LEV62
No_62:
	LDA Variable
	CMP #63
	BNE No_63
	LDA #$02
	STA SPR_X
	JMP LEV63
No_63:
	LDA Variable
	CMP #64
	BNE No_64
	LDA #$02
	STA SPR_X
	JMP LEV64
No_64:
	RTS

calima
Posts: 999
Joined: Tue Oct 06, 2015 10:16 am

Re: Simplify long, repetitive code.

Post by calima » Sat Jul 08, 2017 2:15 am

- you don't need to "lda variable" more than once, cmp does not change A
- lda #2; sta spr_x happens in every option except 64, so make that its own check at the start

Oziphantom
Posts: 767
Joined: Tue Feb 07, 2017 2:03 am

Re: Simplify long, repetitive code.

Post by Oziphantom » Sat Jul 08, 2017 3:26 am

Code: Select all

LEV_Check:
   LDX Variable
   CPX #64
   BEQ _exit
   LDA #$02
   STA SPR_X
   LDA LvlFuncPtrTableLo,x
   STA $100
   LDA LvlFuncPtrTableHi,x
   STA $101
   JMP ($100)
_exit
   RTS
LvlFuncPtrTableLo
   .byte <LEV01,<LEV02,<LEV03,<LEV04,<LEV05,<LEV06,<LEV07(..snip...),<LEV63
LvlFuncPtrTableHi
   .byte >LEV01,>LEV02,>LEV03,>LEV04,>LEV05,>LEV06,>LEV07(..snip...),>LEV63

User avatar
thefox
Posts: 3141
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Simplify long, repetitive code.

Post by thefox » Sat Jul 08, 2017 5:36 am

Obvious first step when you have repetitive code like that (in ca65 syntax):

Code: Select all

.repeat 64, i
   LDA Variable
   CMP #i+1
   BNE :+
   LDA #$02
   STA SPR_X
   JMP .ident(.sprintf("LEV%02d", i+1))
   :
.endrepeat
This doesn't reduce the size of the binary, but makes the code much more readable and maintainable. Next step is to refactor the code to minimize code size, as shown by Oziphantom (his example is not 100% functionally equivalent, though, but shows the main idea).

EDIT: Had "i" instead of "i+1".
Last edited by thefox on Sat Jul 08, 2017 6:50 am, edited 1 time in total.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi

Oziphantom
Posts: 767
Joined: Tue Feb 07, 2017 2:03 am

Re: Simplify long, repetitive code.

Post by Oziphantom » Sat Jul 08, 2017 5:45 am

oh yeah, ooppss

Code: Select all

LEV_Check:
   LDX Variable
   CPX #65
   BCS _exit
   LDA #$02
   STA SPR_X
   LDA LvlFuncPtrTableLo,x
   STA $100
   LDA LvlFuncPtrTableHi,x
   STA $101
   JMP ($100)
_exit
   RTS
LvlFuncPtrTableLo
   .byte <LEV01,<LEV02,<LEV03,<LEV04,<LEV05,<LEV06,<LEV07(..snip...),<LEV63
LvlFuncPtrTableHi
   .byte >LEV01,>LEV02,>LEV03,>LEV04,>LEV05,>LEV06,>LEV07(..snip...),>LEV63

Garth
Posts: 148
Joined: Wed Nov 30, 2016 4:45 pm
Location: Southern California
Contact:

Re: Simplify long, repetitive code.

Post by Garth » Sat Jul 08, 2017 1:34 pm

Do adjust the table for being 1-based rather than 0-based though.

A way to do it without variables is to put the address on the stack and use the RTS as the jump itself, not just the default return:

Code: Select all

   LDA  LvlFuncPtrTableHi,x    ; (high byte first)
   PHA
   LDA  LvlFuncPtrTableLo,x
   PHA
_exit
   RTS
and you'll save a few bytes of code too. Remember that RTS requires the 16-bit addr to be the target minus 1.

This is from section 11 entitled "Synthesizing instructions with RTS, RTI, and JSR" (intentionally written in that order) of my 6502 stacks treatise.
http://WilsonMinesCo.com/ lots of 6502 resources

sdm
Posts: 288
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Simplify long, repetitive code.

Post by sdm » Sat Jul 08, 2017 5:59 pm

Oziphantom wrote:oh yeah, ooppss

Code: Select all

LvlFuncPtrTableLo
   .byte <LEV01,<LEV02,<LEV03,<LEV04,<LEV05,<LEV06,<LEV07(..snip...),<LEV63
LvlFuncPtrTableHi
   .byte >LEV01,>LEV02,>LEV03,>LEV04,>LEV05,>LEV06,>LEV07(..snip...),>LEV63

An error pops up - "syntax error in expression!" :( I use NESASM3.

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

Re: Simplify long, repetitive code.

Post by tokumaru » Sat Jul 08, 2017 6:09 pm

Use LOW() and HIGH () instead of < and >. You may need to use .db instead of .byte too, but I'm not sure.

sdm
Posts: 288
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Simplify long, repetitive code.

Post by sdm » Sun Jul 09, 2017 3:36 am

usage.txt from NESASM3 says:
HIGH() - Returns the high byte of a value.

LOW() - Returns the low byte.

DB - Store one or more data bytes at the current location.

DW - Store data words.

BYTE - Same as DB.
I changed and should be fine, but.. Unfortunately again NESASM3 displays an error. "syntax error in expression!" :/



I may have described it incompletely. LEV01-64 are labels such as:

Code: Select all

LEV01:

    ;some data here (like sprites, monsters etc, nametable change, map variables etc

RTS
"LEV_Check" is in infinite loop. Byte "Variable" will have a value of #$01 - #$64 randomly saved, and depending on what value it will write, then LEV_Check will run the corresponding JMP LEV01 to LEV64.

Oziphantom
Posts: 767
Joined: Tue Feb 07, 2017 2:03 am

Re: Simplify long, repetitive code.

Post by Oziphantom » Sun Jul 09, 2017 5:08 am

can you post the code as you have it written, bit hard to tell what is wrong, also give us the exact error?

Although personally I would say ditch NESASM and get a real assembler. I recommend 64tass but it will need to to make your own NES header. Or if NESASM has a binary include you could abuse NESASM to just make the .nes file for you with the code and data built by 64tass.

User avatar
OmegaMax
Posts: 83
Joined: Wed Sep 21, 2016 8:55 am
Location: Calgary.Alberta,Canada

Re: Simplify long, repetitive code.

Post by OmegaMax » Sun Jul 09, 2017 8:46 am

Most of us don't use NESASM so we don't know the syntax,you can also use words instead of high,low bytes

Code: Select all

LEV_Check:
   LDA Variable
   CMP #64
   BEQ _exit
   LDA #$02
   STA SPR_X
   LDA Variable
   ASL
   TAX
   LDA LvlFuncPtrTable+0,x
   STA $00
   LDA LvlFuncPtrTable+1,x
   STA $01
   JMP ($00)
_exit
   RTS
LvlFuncPtrTable
   .dw LEV01,LEV02,LEV03,LEV04,LEV05,LEV06,LEV07(.All other function labels...),LEV63

sdm wrote:
I may have described it incompletely. LEV01-64 are labels such as:

Code: Select all

LEV01:

    ;some data here (like sprites, monsters etc, nametable change, map variables etc

RTS
"LEV_Check" is in infinite loop. Byte "Variable" will have a value of #$01 - #$64 randomly saved, and depending on what value it will write, then LEV_Check will run the corresponding JMP LEV01 to LEV64.



Yes that's all fine sdm





If you want a low and high byte address table this needs to be done

Code: Select all

LEV_Check:
   LDX Variable
   CPX #64
   BEQ _exit
   LDA #$02
   STA SPR_X
   LDA LvlFuncPtrTableLo,x
   STA $00
   LDA LvlFuncPtrTableHi,x
   STA $01
   JMP ($00)
_exit
   RTS
LvlFuncPtrTableLo
   .byte LOW(LEV01),LOW(LEV02),LOW(LEV03),LOW(LEV04),LOW(LEV05),LOW(LEV06),LOW(LEV07)(..ect...),LOW(LEV63)
LvlFuncPtrTableHi
   .byte HIGH(LEV01),HIGH(LEV02),HIGH(LEV03),HIGH(LEV04),HIGH(LEV05),HIGH(LEV06),HIGH(LEV07)(..ect...),HIGH(LEV63)

sdm
Posts: 288
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Simplify long, repetitive code.

Post by sdm » Wed Jul 12, 2017 3:11 pm

Thanks for the help.

NESASM3 probably has some limitations, for example:

Code: Select all

	.dw LEV01,LEV02,LEV03,LEV04,LEV05,LEV06,LEV07,LEV08,LEV09,LEV10,LEV11,LEV12,LEV13,LEV14,LEV15,LEV16,LEV17,LEV18,LEV19,LEV20,LEV21 (ect)
Displays error "Syntax error in expression!"


Only then is done ok: (I also see the length of the label name does matter. 100 characters total on one line?)

Code: Select all

	.dw LEV01,LEV02,LEV03,LEV04,LEV05,LEV06,LEV07,LEV08,LEV09,LEV10,LEV11,LEV12,LEV13,LEV14,LEV15,LEV16,LEV17,LEV18,LEV19,LEV20
	.dw LEV21,LEV22,LEV23,LEV24,LEV25,LEV26,LEV27,LEV28,LEV29,LEV30,LEV31,LEV32,LEV33,LEV34,LEV35,LEV36,LEV25,LEV26,LEV27,LEV28
(ect)

Garth
Posts: 148
Joined: Wed Nov 30, 2016 4:45 pm
Location: Southern California
Contact:

Re: Simplify long, repetitive code.

Post by Garth » Wed Jul 12, 2017 8:49 pm

Once again: You don't need to store the indirect address in variable space and use JMP(ind). Put the address on the stack and use the RTS as the jump itself, not just the default return:

Code: Select all

   [...]
   LDA  LvlFuncPtrTableHi,x    ; (high byte first)
   PHA
   LDA  LvlFuncPtrTableLo,x
   PHA
_exit
   RTS
and you'll save 5-7 bytes of code too. Remember that RTS requires the 16-bit addr to be the target minus 1, so make that adjustment when you form the table.
http://WilsonMinesCo.com/ lots of 6502 resources

User avatar
Memblers
Site Admin
Posts: 3760
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Simplify long, repetitive code.

Post by Memblers » Wed Jul 12, 2017 10:26 pm

Oziphantom wrote: Or if NESASM has a binary include you could abuse NESASM to just make the .nes file for you with the code and data built by 64tass.
I'd recommend against that, because (even in the newest versions) of NESASM it behaves badly when you overflow an 8kB bank boundary (creates a malformed ROM and doesn't give any error or warning). Unfortunately many people still insist on using it (WHY :? ), so I still have to fiddle around with that kind of crap when I collaborate with anyone. I can say I've used worse assemblers though..

Oziphantom
Posts: 767
Joined: Tue Feb 07, 2017 2:03 am

Re: Simplify long, repetitive code.

Post by Oziphantom » Wed Jul 12, 2017 11:21 pm

Yeah but Garth, they are having trouble making an array of Words, lets keep the -1, stack push tricks to latter yeah ;)

Memblers... it is the assembler that just keeps on giving.. between it and WLA-X in the SNES section, I'm thinking taking the time to find the NES tutorials, and doing a convert to TASS would save us a lot of help requests. As I guess once people learn this is the thing you type to do the thing, and they don't really understand it, getting them to move to another assembler is hard.. then they become so entrenched into it that all their code library is in its style that they just end up stuck in it... I can only imagine how many people find the tutorials hit some random garbage the old tools throw at them and just quit.. not even making it here to ask.

Post Reply