Jump to content

bogax

Members
  • Content Count

    902
  • Joined

  • Last visited

Posts posted by bogax


  1. 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

    • Like 1

  2. 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
    


  3. 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.

    • Like 1

  4.  

    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.

    • Like 1

  5. 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.


  6.  

    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?)


  7. 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)


  8.  

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

    • Like 1

  9. Finally installed bB :P

     

    macro set_hi_nibble
    {1}=(({2}*4*4^{1})&$F0)^{1}
    end
    

     

    Compiles 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
    


  10.  

    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.


  11. 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 a
    

     

    That 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
    end
    

     

    It 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)


  12. 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
    


  13. 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" then

    accumulating "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)


  14. 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.


  15. 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)


  16. 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
    
    


  17. 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
    


  18.  

    Well, I guess those are just some hints that something's seriously wrong with (CBM)BASIC... :D

    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 :)


  19. 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 :)

×
×
  • Create New...