Jump to content

ScumSoft

Members
  • Content Count

    415
  • Joined

  • Last visited

Posts posted by ScumSoft


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

    Now I am completely confused. :?

    I have that effect on people :D I always meant for it to be decimal 10, but I typed by total accident that it was supposed to be Hex (10). However decimal 10 is indeed the correct one needed.

    [edit]Correct only in the fact that I didn't mean Hex 10 as mentioned before. AND #2 works the same for this :P

    Okay, no more confusion!


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

    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.

     

    My 96-pixel playfield is segmented to a 6-byte buffer which is updated every frame, numbered 0 through 5. All sprite data is updated into this buffer each scanline ready to be drawn on the next scanline. It is an interlaced kernal with black Logic scanlines where this is performed. As such I translate the 96-pixel positions to a virtual 12-byte buffer (used abstractly in code) to determine which slot the player resides in.

     

    Say the player is in slot 0. If we shift right 3 pixels he will now be 3 pixels into slot 1. However slot 1 is drawn on Frame 2, and is really slot 0. So if I number the slots 0 through 11 instead, and then do a -

               lda P0slot              ;Divide slot by 2
               lsr                     ;-
               sta P0slot              ;Save result 

    afterwards, then I get slots 0 through 5 each frame. But I get to address the slots 0 through 11 when working on them. I'm pretty sure I overcomplicated things by nature, but this is how my brain saw it working so I implemented it to the best of my current skill set.

     

    I needed to determine which slot gets the overflowed sprite data, I didn't write any notes as to why I had to increase the slot number, but I am pretty sure it had to do with making sure the slot used during drawing frame 2 would alway match the correct overflow slot and vice versa.

     

    You can ignore the need for that routine right now if it is cumbersome to work with, I'll get it reimplemented in an elegant way later on if need be.


  3. Oops that would be a typo on my part, it should be HEX 10, not decimal 10. so AND #$10 is the correct command. It let's me know when I am on Frames 2 and 4.

    Are you 100% sure? You are checking bit 3 and not bit 1. Why? :?

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


  4. Shifting the Players each scanline takes too much time and I don't have any cycles left over to update the playfield. It would certainly look better but shifting 8 pixels is a compromise with little more flicker I've made for now.

     

    I was unaware that DEC modified the flags, so that is why I overlooked its operation. I've since updated my code where I've been using DCP :) thank you.

     

    [edit]You've posted while I was typing this out. If something looks really dumb then just ask me since it most likely is, I am still very new to programming and trying new things just for the sake of doing them. I was using two mask tables before and when I rewrote the Mask routines I switched to EOR #$FF for some reason, I'll switch back to the second table then.

     

    Since my 4 frame kernal flicks quite a bit I probably won't use it, but that is what FrameNum handles. It counts 0,2,4,6 which is used to index the JumpTable for which kernal to use, then in the overscan I determine what the frame was by AND #$0A (I typed AND #10 which is the same), as it returns 0 if I am on Frames 1 or 3. That way I know which order to mask the bytes in. FrameNum is incremented twice before each frame, sorry I forgot to mention this.

     

    MaskR2 is indeed superfluous, but I just couldn't think of a method to fit INC P0slot into the normal routines without a bunch of checks. So just to get things working for now I threw the extra code in till a better method is found.

     

    Which is where you come in :) to guide me in my ways. I'll meet anyone half way if you think the answers are so simple I should already know them, just lead the way and I'll understand.


  5. I use (AND #10) since my frame counter counts only even values, so I check if I am on frames 2 or 4 for the odds. I use it as an offset to a frame jump table, so I need it to increment twice for convenience later. Otherwise I would just do a LSR to see if bit one is set for odd frames.

     

    SAX will AND the Acc with the X register and Store in memory.


  6. I like the suggestions given so thanks for your time. I'll be working on my level generation code this weekend, after that I will fully implement these new sprite rotation ideas. Thanks for the help.

     

    Since this thread is about me posting code and getting feedback, I might as well get some feedback on my display output kernal and masking routine.

    I no doubt overcomplicated the design of it, so refinement is always welcome!

     

    The basic idea(implemented already and works well) I had was split the screen into 2 48-pixel sprites that are updated in sections each frame, visually like this:

    frame1s.jpg

    Then on the next frame, reposition to the right 8-pixels

    frame2v.jpg

     

    So in order to move a sprite, we rotate/mask an 8/16-byte buffer for each sprite we want to draw. Each strip of pixel data on the screen is indexed 0 through 5, but treated as a 12-byte index. Since both frames share a 6-byte buffer for display output I initially index 0 to 11, then translate down to which of the 6-bytes were really talking to for the next frame data.

     

    I ran into an issue with mid-byte positioning, but eventually got that figured out with the masking routine here:

    (Variable names changed for clarity and to address only one sprite for example purposes)

    ;********************************
    ;     [MASKING ROUTINES]
    ;********************************
    MaskData:
       lda #15                 ;[]+2 16 byte sprite
       sta Counter             ;[]+3 Byte index counter
       lda P0slot              ;[]+3 Check slot number, even or odd (indexed 0 to 11) Frame1 is even slots, 2 is odds
                               ;- so if the player origin is in an Odd slot, then moving to the right would place him in an Even slot, and vice versa
       lsr                     ;[]+2 Odd values always have bit 1 set
       bcs OddSlots            ;[]+2/3 Branch if carry set
       
    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            ;[]+3 Load current frame number
       and #10                 ;[]+2 Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames
       beq .MaskR              ;[]+2/3 CHANGE PLACES! Mask in reverse order
    
    .MaskN ;Mask Normal order 
       ;Data used in Frame1
       ldy P0shift             ;[]+3 Sprite shift amount
       ldx MaskTable,Y         ;[]+4 Get proper bit masking by shift amount
       ldy Counter             ;[]+3 Fetch sprite index 15 to 0
       lda P0buffer,Y          ;[]+4 Get sprite data to work on
       sax P0buffer,Y          ;[]+4 Apply mask and save new data
       lda #$FF                ;[]+2 Compare value, needed for addressing a 0 index?
       dcp Counter             ;[]+5 Decrement and compare
       bne .MaskN              ;[]+2/3 More sprite data to work on?
       rts                     ;[]+6 Done, return
    
    .MaskR ;Mask Reverse order
       ;Data will be used in Frame2
       ldy P0shift             ;[]+3 Sprite shift amount
       lda MaskTable,Y         ;[]+4 Get proper bit masking by shift amount
       eor #$FF                ;[]+2 Reverse mask
       tax                     ;[]+2 Used for SAX instruction
       ldy Counter             ;[]+3 Fetch sprite index 15 to 0
       lda P0buffer,Y          ;[]+4 Get sprite data to work on
       sax P0buffer,Y          ;[]+4 Apply mask and save new data
       lda #$FF                ;[]+2 Compare value, needed for addressing a 0 index?
       dcp Counter             ;[]+5 Decrement and compare
       bne .MaskR              ;[]+2/3 More sprite data to work on?
       rts                     ;[]+6 Done, return
       
    OddSlots:  ;Slots 1,3,5,7,9,11 in GFXoutput
       lda FrameNum            ;[]+3 Load current frame number
       and #10                 ;[]+2 Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames
       beq .MaskN              ;[]+2/3 CHANGE PLACES! Mask Normally here instead of reverse
    
    .MaskR2  ;Mask Reverse 2
       ;Data will be used in Frame2 but in next slot number
       ldy P0shift             ;[]+3 Sprite shift amount
       lda MaskTable,Y         ;[]+4 Get proper bit masking by shift amount
       eor #$FF                ;[]+2 Reverse mask
       tax                     ;[]+2 Used for SAX instruction
       ldy Counter             ;[]+3 Fetch sprite index 15 to 0
       lda P0buffer,Y          ;[]+4 Get sprite data to work on
       sax P0buffer,Y          ;[]+4 Apply mask and save new data
       lda #$FF                ;[]+2 Compare value, needed for addressing a 0 index?
       dcp Counter             ;[]+5 Decrement and compare
       bne .MaskR2             ;[]+2/3 More sprite data to work on?
       inc P0slot              ;[]+5 Adjust for mid byte roll over
       rts                     ;[]+6 Done, return
    
    MaskTable:
          ;ShiftAMT
          ;$00,$01,$02,$03,$04,$05,$06,$07
     .byte $FF,$7F,$3F,$1F,$0F,$07,$03,$01
    

    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 will spend more time looking at how other people manage such things and will definitely learn from them.

    So all the assistance I get is VERY much appreciated :D


  7. Vblanks time is entirely used for working on the remaining sprites, level construction, sounds and game logic, and masking the buffers to get them ready for drawing. Only the player and monsters are 8x16 sprites and therefore take the most time to work on, so I do them in the overscan first, everything else are 8x8 sprites and not an issue.

     

    I'll probably rearrange the workload as need be later on, I just need the entire games functionality in place first. But I wanted to see if there was a way to optimize this routine now as it dictates how large of a sprite I can toss in my game and still have time left over for other things. If 8x8 is the largest feesable sprite to work on then I have to design the game around this accordingly see? But I am sure I can get some 8x16 ones in here.


  8. You win if you can tell me what operation is being performed on the operand. ;)

    NOP       = do nothing, waste 2 cycles
    NOP #0    = do nothing, waste 2 cycles and an extra byte
    NOP VSYNC = do nothing, waste 3 cycles and an extra byte
    NOP.w     = do nothing, waste 4 cycles and 2 extra bytes

     

    All of the above are the same as:

    X = X

     

    But vary in cycles used and space taken.

    So, "I yam what I yam" is the answer.


  9. I do appreciate the help, I'll see how much of an impact this new setup makes. What is most important is to get the entire routine to minimal cycles used, So I really like the hybrid shift + preshifted sprite idea, one thing I definitely didn't think of using before.

     

    I am over budget by 456 cycles in the overscan because I moved from 8x8 sprites to 8x16. 8x8 just didn't have the space to make the player look right, but this also added quite a bit of presprite overhead to the routines. I need preshifted data due to the way my software output buffers align to the 96x96 screen space I have setup right now.

    The player position registers aren't moving along with the sprite like your typical game does, instead they are stationary and split into 6 sections per frame, then aligned to form a 12x24 software settable block of pixels.

     

    Ok, off to test the code. Be back later on.


  10. I need to optimize what this routine does, even tho I wrote it myself I can't seem to find a way to make it faster.

    Or substitute a different method in it's place NOT preshifting every sprite sacrificing rom space for cycles, it's a much better learning experience to think of a way to do this faster.

     

    ;********************************
    ;     [ROTATE ROUTINES]
    ;********************************
    ;I test RotateAMT before entering the routine, skipping when not needed.
    
    RotateBytes:
       lda #15                 ;[]+2 Work on 16 bytes of data 0-15
       sta Counter             ;[]+3 Set counter 
       lda RotateAMT           ;[]+3 Fetch rotate amount
       cmp #5                  ;[]+2 Faster to do ROL?
       bpl .doROL              ;[]+2/3 Branch if yes
       
       ;Rotate values 1 through 4
    .RORa  
       ldx RotateAMT           ;[]+3 Load amount to rotate
       ldy Counter             ;[]+2 Use counter as byte index, Y is trashed so reload counter    
       lda SPRITE,Y            ;[]+4 Load Sprite byte to be rotated
    .RORloop
       ;8-bit rotate
       tay                     ;[]+2 Save byte being worked on
       ror                     ;[]+2 Rotate data into carry
       tya                     ;[]+2 Restore byte being worked on
       ror                     ;[]+2 Shift carry into byte
       dex                     ;[]+2 Countdown rotate amount, worst case cycles for single byte = 52, best = 12
       bne .RORloop            ;[]+2/3 Loop if more to rotate
       ldy Counter             ;[]+3 General counter
       sta SPRITE,Y            ;[]+4 Store Result into 16-byte SPRITE buffer
       lda #$FF                ;[]+2 Compare value
       dcp Counter             ;[]+5 Decrement counter, compare with #$FF
       bne .RORa               ;[]+2/3 Branch if more bytes to rotate
       rts    
    
    .doROL ;Rotate values 5 through 7
       ;A holds RotateAMT right now
       eor #6                  ;[]+2 Set value to 1,0, or 3
       bne .ROLa               ;[]+2/3 Does rotate value = 0
       lda #2                  ;[]+2 Yes then load corrected value
    .ROLa
       sta RotateAMT           ;[]+3 Save new value
    .ROLb  
       ldx RotateAMT           ;[]+3 Load amount to rotate
       ldy Counter             ;[]+2 Use counter as byte index, Y is trashed so reload counter     
       lda SPRITE,Y            ;[]+4 Load Sprite byte to be rotated
    .ROLloop
       ;8-bit rotate
       tay                     ;[]+2 Save byte being worked on
       rol                     ;[]+2 Rotate data into carry
       tya                     ;[]+2 Restore byte being worked on
       rol                     ;[]+2 Shift carry into byte
       dex                     ;[]+2 Countdown rotate amount, worst case cycles for single byte = 52, best = 12
       bne .ROLloop            ;[]+2/3 Loop if more to rotate
       ldy Counter             ;[]+3 General counter
       sta SPRITE,Y            ;[]+4 Store Result into 16-byte SPRITE buffer
       lda #$FF                ;[]+2 Compare value
       dcp Counter             ;[]+5 Decrement counter, compare with #$FF
       bne .ROLb               ;[]+2/3 Branch if more bytes to rotate
       rts   


  11. Very nice, I don't see anything wrong on initial glance. Makes the tutorials much easier to follow along with.

     

    all we need to remember is that the first thing to send is that reset trigger (called VSYNCH)
    Oh wait just noticed this in "Session 7" under Reset Signal. It should say "VSYNC" minus the H.

  12. Wouldn't the very first line explain it all?

    "an operand is the part of a computer instruction which specifies what data is to be manipulated or operated on, whilst at the same time representing the data itself"

    If you believe this is too wordy read it out loud, you should take a breath at the comma and at no other time :) (except before reading it of course)

     

    Operand - the quantity on which an operation is to be done. In other words, an operand may simply be a variable in an equation.

    Using "In other words" is a re-explanation and therefore redundant.


  13. Yeah I figured as much, the 2600 isn't controlling the TV so much as it is walking along with it. I became curious if sending a VSYNC signal would tell the TV to stop what it was doing and return the beam to the VBLANK period prematurely. If this was possible you could refresh the screen a second time much quicker thus hitting the phosphors again in a shorter period. Even if the refresh was off you wouldn't have any roll since you'd be controlling the beam the entire time.

     

    Now then, you can draw however many scanlines you wish, so long as the TV's timing is still sent the VBLANK signal once you're done. Case and point in the following demos where none of them have an Overscan period. As soon as the desired number of scanlines are drawn, we can hop back to the VBLANK and start drawing again. Although in order to avoid the roll, the required number of scanlines has to be drawn as seen in the case of the 170scanline demo, even though the scanline number is consistent, it still rolls. (I believe this can be avoided with careful timing)

     

    I was hoping we could force a non-standard refresh rate on the TV, as this would open up some really nice tricks.

     

    I've been plugging along with my game and desire to use a 4-frame flickerblind kernal without any flicker. If I could skip the overscan and refresh the screen once every other frame, this would eliminate the flicker. It works well in Stella, so I might make a version that uses this trick just for emulation play and use my other kernal for the real units.

     

    Well, it was worth a shot.

     

    [edit] Whoops forgot to add the 170scanline.bin

    262Interlaced.bin

    262Scanlines.bin

    170Scanlines.bin


  14. Is it possible to force a VSYNC instead of performing the Overscan? It seems to work on Stella, but on the real console the TV seems to always perform the Overscan.

     

    I would very much like to tell the TV to skip the Overscan and reset the frame to perform a fast redraw on the screen that would minimize/eliminate flicker on a 4 frame kernal.

     

    It would be nice if possible, as the turn around time would minimize the length of time between phosphor hits and thus offering brighter colors and minimize or eliminate the flicker seen. After 4 frames have been drawn, then we go to the Overscan and process the needed logic. Lather rinse repeat.


  15. EPROM, Erasable Programmable Read Only Memory.

    EEPROM, Electrically Erasable Programmable Read Only Memory.

     

    EPROM's had to be erased with UV light.

    EEPROMS can be erased via software commands, like a flash drive or bios.

     

    Now you shall never forget ;)


  16. Don't know if it's intentional design, but start the game and walk left till you fall, nothing happens, so then walk right and jump. Now you've warped to a different part of the level.

     

    You can also walk into the walls and jump up over and over. The enemies if not defeated, as you move to the next screen will fall off the sides of the screen and continue shooting at you.

     

    Just a bit odd. By the way, the only real voting option is obviously the 6th choice ;)

     

    Aside from that, pretty neat. Also I am not hearing any sound, is it me or is the game just silent?


  17. Oh yes I did, simple typo on my part.

     

    I've realized that there isn't a need to do any of this at all, I simply don't have to do the shifting during the draw phase and can preshift the data during Vsync and Overscan time then store the result in an 8byte buffer for each object to be displayed on screen.

    My game is using less than 1/3 of the 128 bytes of ram, so this isn't a problem as there is only ever 4 objects on the screen maximum.

     

    I'll look into using the DPC+ for future improvements to this kernal which provides much more ram space to work with ;)


  18. Right, that was already completely understood. Although having eor $ram modify the ram contents directly would be a nice addressing mode though it would take the same amount of cycles to perform. That is what macros are for right :)

     

    okay then.

    Lets calculate real quick the ram requirements of storing 7x the amount of data for one 8x8 sprite = 448 bytes.

     

    However being clever I could store half the data by sharing bytes, so half that is 224 bytes per sprite.

    My game has 3 different 8x24 player sprites so that would be with byte sharing 2016 bytes for the just the player graphics.

    Combine that with the object and monster sprites and I am well over 16k just for graphic data.

     

    I think I'll need to simplify them a bit, and cut back on the detail to make this way work. I would have hoped there existed some mathematical tricks to dividing a sprite by 4,6 and 8 without all the shifts.

     

    I'm looking into some other methods of mid byte positioning and well see which one would be most ideal then.

     

    Thanks for the continued support.

×
×
  • Create New...