bogax
-
Content Count
902 -
Joined
-
Last visited
Posts posted by bogax
-
-
it appears there's a zp version of sax so ...
ldx #$0F clc ror ;abcdefgh 0 ror ror ror sax temp ;fgh0abcd e 0000abcd adc temp ;fghabcde 0 carry zeroed for the next round
14 cycles for a 3 bit rotate plus the ldx, clc overhead
probably as fast or faster to do something else for other
rotates.
even numbers
RIGHT_4 ;12 cycles asl adc #$80 rol RIGHT_6 ; 6 cycles asl adc #$80 rol
odd numbers
RIGHT_5 ;10 cycles asl adc #$80 rol RIGHT_7 ; 4 cycles cmp #$80 rol
-
... lsr ; 000000A E Z flag =0 for F and S =0 ...
I see I goofed that comment up.
Perhaps it would be better phrased like this

lsr ; 000000A E Z flag will be set if F and S =0
-
I'm still not sure if that's even close to what you want,
but just for the hell of it I tryed to see how many cycles
I could squeeze out of that preamble to the loop.
This is the best I could come up with.
If we can assume that bit 0 of FrameNum will always =0
and noting that if we add two bits (call them F, S)
the sum is F eor S and the carry is F and S
lda POslot ; xxxxxxS ? S=bit 0 of POslot and #$01 ; 000000S ? ora FrameNum ; xxxxxFS ? F is bit 1 of FrameNum. assumes bit 0 of FrameNum always =0 and #$03 ; 00000FS ? lsr ; 000000F S adc #$00 ; 00000AE 0 add S to F the sum, E, is F eor S the carry out, A, is F and S lsr ; 000000A E Z flag =0 for F and S =0 php lda #$FF adc #$00 ;if the carry is 1 the result will be $00 else $FF ldx POshift eor MaskTable,x tay ldx #$15 .LOOP tya and P0buffer,x sta P0buffer,x dex bpl .LOOP plp beq .SKIP inc POslot .SKIP rts
Maybe I was wrong and it can't be streamlined much

Only saves four cycles.
Not sure it's worth it, apart from
requiring bit 0 of FrameNum to be 0
its less obvious what's going on.
But since you wanted to minimize cylces,
there it is.
-
1
-
-
It would be rather lengthy to explain the Slot implementation I came up with, so I'll try and explain it as concise as I can.
I'm just looking at your routine I don't
know enough about the context it's in
to tell if my assumptions are correct
so let me show you my reasoning.
First I'm assuming that the FrameNum
is multiplied by two so that if bit
one of FrameNum is set it's an odd frame
and you want to and with 10 binary
ldy P0shift ;Sprite shift amount ldx MaskTable,Y ;Get proper bit masking by shift amount ldy Counter ;Fetch sprite index 15 to 0 lda P0buffer,Y ;Get sprite data to work on sax P0buffer,Y ;Apply mask and save new data lda #$FF ;Compare value, needed for addressing a 0 index? dcp Counter ;Decrement and compare bne .MaskN ;More sprite data to work on?
Assuming POshift doesn't change during the loop
you can pull that lookup out of the loop.
I'd just stick the mask in y for quick access
Now you don't need to use x in the loop so why not
use x for Counter?
Something like:
ldx POshift ldy MaskTable,x ldx #$15 .LOOP tya and P0buffer,x sta P0buffer,x dex bpl .LOOP
The mask needs to be inverted if POslot and FrameNum
are either both odd or both even.
you can get that by eoring them.
lda FrameNum lsr eor POslot lsr ;carry will be 0 if FrameNum and POslot are the same lda #$FF adc #$00 ;add that to $FF a will be 00 if carry was 1 and $FF if carry was 0 ldx POshift eor Masktable,x tay
Need a flag if FrameNum and POslot are both odd so we
will know to increment POslot.
Here's one way:
lda FrameNum lsr and POslot lsr ;carry is one if both were odd php ;stash it on the stack for later
So you'd end up with something like this:
lda FrameNum lsr and POslot lsr ;carry is one if both were odd php ;stash it on the stack for later lda FrameNum lsr eor POslot lsr ;carry will be 0 if FrameNum and POslot are the same lda #$FF adc #$00 ;add that to $FF a will be 00 if carry was 1 and $FF if carry was 0 ldx POshift eor MaskTable,x tay ldx #$15 .LOOP tya and P0buffer,x sta P0buffer,x dex bpl .LOOP plp bcc .SKIP inc POslot rts .SKIP
I hope I got that all correct at least you should get an
idea of what I'm suggesting.
I expect that could be streamlined some.
Obviously it's untested.
-
1
-
-
That reply I made then quickly fixed would be the typo
I should proof before I hit reply. Sorry to confuse! It should be anded with decimal 10 or HEX (A).For the first 16 values of FrameNum ie 0-15,
if you and with decimal 10 you take the beq branch when
FrameNum 0,1,4,5 the rest fall thru and that repeats
for every subsequent 16 values. That doesn't look like
odd frames to me except for the first 8 ie 0-7
The odd frames fall thru.
-
It would be nice to eliminate MaskR2 as the only difference vs MaskR is that I need to increase the sprites GFXoutput slot number, as determined by being on the Oddslot set and reverse masking.
Having looked a little closer
It looks to me like all those loops are basically the same
If you have an even slot and an even frame or if you have
an odd slot and an odd frame you invert the mask.
If you have an odd slot and an odd frame you inc POslot.
You mention reverse order but I don't see any reverse order.
I assume you want this as fast as possible, looks like there's
stuff you could pull out of the loops.
eg POshift doesn't change. (does it?)
-
I use (AND #10) since my frame counter counts only even values...
Not sure why you count each frame twice, but this should read AND #%10.
OH, duh! (palm-to-forehead) (I've been wracking my brains trying to figure
that one out)
-
It would be nice to eliminate MaskR2 as the only difference vs MaskR is that I need to increase the sprites GFXoutput slot number, as determined by being on the Oddslot set and reverse masking.
I just gave it a cursory look and am not really sure what you're doing so
sorry if this is non sequitor
The only difference I see between MaskR2 and MaskR is the inc POslot
instruction at the end so the obvious thing would be to set a flag
and inc or not depending on the flag or possibly set an increment
value of 0 or 1 (if you need constant time)
EvenSlots: ;Slots 0,2,4,6,8,10 in GFXoutput ;This was tricky, since I have to know which frame I am on for correct masking order lda FrameNum ;Load current frame number and #10 ;Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames beq .MaskR ;CHANGE PLACES! Mask in reverse order
This seems to be intended to differentiate between odd and even frames in
which case you need to and #01
.MaskN ;Mask Normal order ;Data used in Frame1 ldy P0shift ;Sprite shift amount ldx MaskTable,Y ;Get proper bit masking by shift amount ldy Counter ;Fetch sprite index 15 to 0 lda P0buffer,Y ;Get sprite data to work on sax P0buffer,Y ;Apply mask and save new data lda #$FF ;Compare value, needed for addressing a 0 index? dcp Counter ;Decrement and compare bne .MaskN ;More sprite data to work on? rts ;Done, return
The sax I'm (not really) familiar with takes an immediate value.
so sax P0buffer,Y makes no sense to me.
Counter starts out positive and counts down so bpl should do
ie dec Counter, bpl .MaskN and you can leave out the lda #$FF
assuming you don't need a to be $FF for some other reason
(and obviously Counter will be $FF when you fall through the bpl)
-
... .RORa lda SPRITE,x ;[]+4 Load Sprite byte to be rotated and RorAndTbl,y ;[]+4 ror ;[]+2 eor SPRITE,x ;[]+4 and RorAndTbl,y ;[]+4 eor SPRITE,x ;[]+4 = 18 extra cycles to preserve X and make ror faster jmp (.vec) ;[]+5 ...
I don't think you need that first and
eg
.RORa lda SPRITE,x ; ? abcdefgh ror ; h ?abcdefg eor SPRITE,x ; h xxxxxxxx and RorAndTbl,y ; h 0000xxxx eor SPRITE,x ; h abcddefg ror ; g habcddef ror ; f ghabcdde ror ; e fghabcdd ror ; d efghabcd
an alternative
lda SPRITE,x ; ? abcdefgh and RorAndTbl,y ; ? abcd0000 clc adc SPRITE,x ; a bcd0efgh ror ; h abcd0efg ror ; g habcd0ef ror ; f ghabcd0e ror ; e fghabcd0 ror ; 0 efghabcd
of course you have to invert the mask(s)
and if you know the carry will be clear
you could leave out the clc and possibly
gain a couple cycles
for rol
lda SPRITE,x ; ? abcdefgh asl ; a bcdefgh0 adc #$80 ; b ?cdefgha rol ; ? cdefghab
ie three cycles per bit if you do them in pairs
but I think you'd need a seperate routine for
an odd number of bits
-
1
-
-
See if this looks OK:
http://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#nybblemacrodef
Thanks.
It might be worth pointing out that there's a reason
for using eg *4*4 instead of *16
-
Finally installed bB

macro set_hi_nibble {1}=(({2}*4*4^{1})&$F0)^{1} endCompiles just as one would hope
.L00 ; macro set_hi_nibble MAC set_hi_nibble .L01 ; {1} = ( ( {2} * 4 * 4 ^ {1} ) & $F0 ) ^ {1} ; complex statement detected LDA {2} asl asl asl asl EOR {1} AND #$F0 EOR {1} STA {1} ENDM -
Here's a simple example that just gives a nybble variable the value of five:
POKE_My_Variable 5
Oh, OK, I get it
def is a simple substitution so that that expands to something like:
callmacro set_lo_nibble a 5
The def statement supplies the first parameter and you supply the
second where you invoke the def'd name.
-
I'm getting lost.
Here's an excerpt of the code from:
http://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#nybblemethis
rem **************************************************************** rem * Reusable macros for nybble variables. rem * macro set_lo_nibble {1}={1}&$F0 {1}={1}|({2}&$0F) end macro set_hi_nibble asm lda {1} and #$0f sta {1} lda {2} asl asl asl asl ora {1} sta {1} end end rem **************************************************************** rem * One variable is split into two thanks to rem * macro and def. rem * def PEEK_Game_Level=a&$0F def POKE_Game_Level=callmacro set_lo_nibble a def PEEK_Hit_Points=a/16 def POKE_Hit_Points=callmacro set_hi_nibble aThat looks to me like set_lo_nibble and set_hi_nibble both want
two parameters and are both only being passed one,
am I missing something?
If you use exclusive or to swap in nibbles
you'll only get the bit's you mask for,
So I'd (re)write RevEng's code like this:
macro set_hi_nibble asm lda {2} asl asl asl asl eor {1} and #$F0 eor {1} sta {1} end endIt might even be possible to write something that
swapped different nibbles depending on a parameter
(I haven't tryed, didn't seem worth it)
I haven't figured out when and where bBasic will choke
on complex expressions.
If bBasic fails to recognize powers of 2 greaer than 3,
would something like this work (again using an xor swap)
(1)=(2)*4*4^(1)&$F0^(1)
(I don't know how many parentheses you'd have to stick in
there to get the order of execution right or if that would
make bBasic choke)
-
As I have decided to use the playfield as the scoreboard for my Monaco GP 2600 project, I have hit a minor snag.
I am using score digits that are 3 pixels wide (technically 4, but the digits only use 3), and using that in PF0 is fine. However, trying to load this into PF1 is a problem.
I want to load 4-bit data into half of PF1, and a different set of 4-bit data into the other half. How can I do this?
Sorry if this sounds slightly confusing. Here is a crappy MS Paint picture to help.
Not sure I understand maybe this will help
A eor A = 0
A eor 0 = A
so
A eor B eor A = B
so you've got two bytes (letters are nibbles) ab, cd
lda ab ; the byte containg ab eor cd ; the byte containg cd and #$F0 ; the high nibble of the accumulator is a eor c the low nibble is 0 eor cd ; the high nibble is a eor c eor c = a the low nibble is 0 eor d ; that is, the accumulator is now ad -
You get bonus points for shooting more than one playfield pixel with the same missile. The first one will be 10 points, second 15, third 20, fourth 25, fifth 30, and so on. I'm not sure what the limit should be. Right now in my tests, a bonus for 7 playfield pixels in a row is the limit. I don't want to give players too many points, but the bonus needs to be high enough to be worth it. I'll have to keep playing with it to see what seems right.btw you do know that accumulating a constant in "a" thenaccumulating "a" in "score" will make "score" go up quadratically
(graph "score" and it will be parabolic)
I don't understand them thar big words, but I am trying to add 10, then 15, then 20, then 25, then 30, then 35, and so on.
Thanks.
It's probably nothing
The score goes up proportional to the square of the
number of bonuses you get so it's going to go up fast.
Potentially the first points you score could be microscopic
compared to the last points you score.
Since you limit it to 7 it's not going to get too far out.
You know what you want and I don't so take this with
a grain of salt, but I would have guessed that a smaller
increment for "a" and a larger limit would work better.
(And I'm not at all sure I know what's going on with game
play so like I said a grain of salt ie I'm probably speaking
out of turn, it's just my gut reaction to the numbers)
-
I'm not that familiar with batari Basic but it would be something like:
if (a & $0F) > 9 then a = a + 6 if (a & $F0) > $90 then a = a + $60
Oops, I think I misunderstood what you're doing here. This should be done *after* adding to a, correct?
Correct but like I said it's only sure to work if
there's no carry out from a digit, which can't happen
if what you add <= 6
it should always result in a BCD compliant number
but it may not be the right number if you add more
than 6 to a digit.
-
One thing I'll need is how you can use an if-then to limit a = a + 5. Decimal and hex don't seem to match up. For example, if a < 65 then score = score + a will limit it to 175, but I don't know how or why.
Thanks.
I may be completely off here because I get 180 not 175
so maybe I don't understand what you're doing.
Assuming "a" and "score" both start at 0 and both are BCD,
65 looks like 41 BCD so the last "a" you add to "score"
will be 40 and by that time "score" will be 180 ie presummably
the IF statement does't know the difference and just treats
both as straight binary.
btw you do know that accumulating a constant in "a" then
accumulating "a" in "score" will make "score" go up quadratically
(graph "score" and it will be parabolic)
-
How can I make sure a variable is always a BCD compliant number? The following will work at the beginning, but as the number grows, the score will be incorrect or become garbled as you would expect:
a = a + $05 : score = score + a
A for-next loop will solve the problem:
a = a + $05 : for temp5 = 1 to a : score = score + 1 : next
But is that the best solution? Is there some special magic with AND or OR that could be done to make sure the variable is always a BCD compliant number as long as it is less than 100?
Thanks.
I don't know what you're doing but making sure "a" is BCD compliant may not be enough.
You may have to make "a" BCD. That is treat, it as BCD.
If you never add more than 6 to "a" then it's relatively simple, mask off the digits
individually and test if they're greater than 9 and if a digit is greater than 9 add
6 to it, starting with the ones digit. If you add more than 6 it starts getting messy.
If you do add more than 6 there's the possibility of a carry out of the ones digit which
you'd have to detect independent of what ever you add to the tens digit.
Probably be easiest to treat the digits seperately, ie add the digits one at a time,
add the ones digit then adjust, then add the tens digit and adjust.
I'm not that familiar with batari Basic but it would be something like:
if (a & $0F) > 9 then a = a + 6 if (a & $F0) > $90 then a = a + $60
Edit:
That code is just to make "a" BCD compliant
(it doesn't convert binary to BCD)
Here's code to add "n" to "a" (I hope
)"n" doesn't (necessarily) need to be BCD
(if "n" is a single hex digit 0-F it should work)
Not sure if this is proper batari Basic
temp = (a & $0F) + (n & $0F) : REM seperate ones digit and add them : REM result in temp so they can be : REM decimal adjusted seperately if temp > 9 then temp = temp + 6 : REM decimal adjust the ones digit a = (a & $F0) + temp + (n & $F0) : REM add it all together if a > $9F then a = a + $60 : REM decimal adjust the tens digit -
here's a minimum space routine
(untested)
sec rol ByteToSwap LOOP ror asl ByteToSwap bne LOOP
-
Table lookup would be fastest, but cost a fair bit of space.
ldx ByteToSwap lda SwapTable,x ... ... SwapTable .byte 0,$80,$40,$C0,$20 ... etc. for values 5-256
Or maybe just use a lookup table per nybble, but that still means using bit-shifts and might end up slower than Post #2.
enter with byte to reverse in a
tables not shown
code is untested
tax and #$0F tay txa lsr lsr lsr lsr tax lda hi_tbl,y ora lo_tbl,x
-
LDA #0 ASL ByteToSwap ROR ASL ByteToSwap ROR ASL ByteToSwap ROR ASL ByteToSwap ROR ASL ByteToSwap ROR ASL ByteToSwap ROR ASL ByteToSwap ROR ASL ByteToSwap ROR STA SwappedByte
You don't need to intialize the accumulator (you're shifting it all out any way)
-
Well, I guess those are just some hints that something's seriously wrong with (CBM)BASIC...
Or to put it positively: There's lots of potential to optimize your (CBM)BASIC code today!

Also I don't think you need to get the constant out of
the initial asignment of I, but I did that just in case too

Well, now that I think of it, shouldn't it be FASTER if you leave the constants in? [EDIT: Yes, it is.]
I mucked it up some what.
I have seen BASICs where it appeared that the end value expression
was re interpreted each time through the loop, I couldn't remember if
the CBM BASIC was one of them.
However I'd expect to initialize the beginning and ending "constants"
near the beginning of the program and then just use the loop as needed.
As an aside on optimizing BASIC programs, it is (iirc) usually faster
to use a dummy FOR-NEXT loop than a GOTO if possible.
The FOR-NEXT remembers where it's supposed to go, the GOTO has to scan the
line list.
And there's lots of other stuff you can do.
A little Googling should turn up more.
Years ago I timed all that stuff on the VIC20
Some where I've got a compilation of times in "milli-jiffies"
No idea where it's gotten to now though

-
I have no doubt you'll prefer the machine code version,
but you should be able to improve the BASIC by taking
the constant evaluations and the redundant math
out of the loop.
Try this:
F=55296:L=56295:FOR I=F TO L:POKE I,N:NEXT
I don't recall how muti statement lines compare
speed wise to going to the next line, but I'd put
it all on one line just in case

Also I don't think you need to get the constant out of
the initial asignment of I, but I did that just in case too

-
Assuming you were willing to use self modifying code and reserve the X register
to the pupose you could
TSX
CPY #
PHP
oops, that should be
TXS
CPY #
PHP

Request for programming tips
in 2600 Programming For Newbies
Posted · Edited by bogax
Basically, any instruction that affects the contents
of A, X or Y will set the N and Z flags accordingly.
Also inc, dec, shift memory.
If you need the flag later you can push the status
register to the stack and pull it later.
So if you dey and don't do anything that affects
N or Z they'll reflect what the dey did untill
you do do something that affects N or Z.
If you dey then ldx they now reflect the effects of
ldx.
and, of course, there are instructions that don't
affect the registers but do affect the flags,
compare instructions, bit, plp, rti