Jump to content

bogax

Members
  • Content Count

    902
  • Joined

  • Last visited

Posts posted by bogax


  1. You don't need to be afraid of gosubs but you do need to use them sparingly because there isn't much stack.

    Your code is kind of convoluted and I didn't try very hard to follow it so I may misunderstand your intentions.

     

    It looks to me like you're using gosubs where you don't need them and probably don't want them.

     

    You're also doing way to much bank swithching in my opinion. (bank switching is expensive in both time and space)


  2. 1 hour ago, Lewis2907 said:

    Thanks. I was thinking too many on gosub. I will probably work on it as tomorrow when I get some free time.

     

    I think you've got 5 spots on the stack with the multisprite kernel

    on gosub uses two but one of them only while it executes

    on gosub pushes it's target on to the stack from a table then does a return so it "returns" to it's target (it also leaves a real return address on the stack)

    on goto does the same without first pushing a (real) return address, so on goto uses one level of stack

     

    it's possible with a microscopic amount of assembler (a single jmp indirect instruction) to do the on goto without using the stack

    but then you have to do the address table yourself (not hard)


  3. You have 12 copies (or so) of this code (probably the same for Up Down)

     

    on _Frame_Counter gosub __Frame_LR_00 __Frame_LR_01 __Frame_LR_02 __Frame_LR_01 : return

     

    just put one copy in one place and change it to an on goto then jump to that.

    eliminate the redundancy and one gosub less deep


  4. 2 hours ago, freshbrood said:

    What is the $ sign in front of the 20 for?

     

    I recall somewhere reading that it's simple to change the indivibual numbers in the score/it has it's own built in 3 variables? But I can't find where I read that anywhere.

     

    I simply want to be able to toggle individual numbers in the score off and on without affecting the overall score or other numbers in it. I know this is easy but I can't remember where I saw how to do it. Please help


    The $ indicates a hexadecimal number


    In decimal the digits are 0..9
    in hexidecimal the digits are 0..15 except we don't use decimal numbers for 10..15 we use A..F
    So the hexidecimal digits are 0..F
    normally you'd get a carry from the lo digit to the hi digit at F in hexadecimal
    1 + F = $10 which is 16 in decimal
    With bcd (binary coded decimal) the digits only go from 0..9 and the carry comes from any number over 9 
    So $20 is hexadecimal for (decimal) 32 (2 * 16) which is interpreted as 20 decimal in bcd (normally 20 decimal would be $14 in hexadecimal ie 1*16 + 4)


    The score is six bcd digits in three bytes except they are backwards in memory score[0] to score[2] from HIGHEST to lowest
    each bcd digit is a 4 bit nibble
    RT has some stuff about dealing with nibbles

    • Thanks 1

  5. One thing I would really like to see in bB

    Is some way to control bB's emission of "#" in macro parameters


    RevEng "fixed" it for somebody and now bB sticks "#" all kinda places I don't want them

    (although to be fair, they don't seem to do any harm. DASM seems to ignore extraneous "#"
    and the fix does fix what it intended to I think)



  6. The standard kernel keeps the playfield data in RAM and there isn't much of that.


    Each row in the playfield need 4 bytes of RAM


    You can jimmy the standard kernel to display more rows but you'll give up 4 variables for each extra row


    I don't know what the actual limit would be but if nothing else you'd be limited by the amount of RAM you could make available for the playfield

    • Thanks 1

  7. On 3/6/2021 at 2:53 PM, splendidnut said:

    My advice to @bogax

     

    It really sounds to me like you should just jump over the cliff and fully use assembly language.  Especially since you are asking for an IF CARRY construct.

    Yes and no

     

    I suppose my ideal would be an assembler with syntax similar to bB where appropriate.

    Something that would facilitate the abstractions with out having them get in the way.

    Something slightly "higher level" than the usual assembler macros.

     

    And speaking of cycle counting, wouldn't it be nice if the language could report byte count or tote up cycles for you

    (but that's not something I'd expect to see in bB. on the other hand it might be worth while if the purpose of bB is to ease you into assembly)

    • Like 2

  8. 11 hours ago, Gemintronic said:

    Could a lateral solution work?  Some combination of an assembly include file with new routines and a code pre-processor that converts certain new commands into inline assembly?

     

    Yeah, this is a badly explained idea that I hardly understand myself :)

     

    Just trying to think of solutions that don't require extra attention/effort on batari or RevEng.

    Sure, some of it

    Thats what I mean  a lot of this is not hard to do in bB
    but it could be more convenient.

    It does get kind of messy some times.

     


    Some of it would probably better be integrated into bB

    If I just want to stuff some sound registers from tables indexed with a common index
    that's not too complicated

     

    If I want to modify player x and y positions where the player is specified by an index
    it might be doable but cost as much as it saved.

     


    Some of it might just be messy

    I'm not sure how you'd introduce an "if CARRY"
    with out either recreating some of bB to get the bB syntax or introducing a different syntax for your if statments
    That is to say I think you'd end up replacing some of bB with your preprocessor rather than just having a more
    convenient way to express some of your bB code

     


    Having said that I don't expect RevEng to drop what he's doing and modify bB to my specitications
    (you know, "your greatest command is my slightest wish")

    The most I might hope for is somthing like RevEng saying to him self
    'suppressing the loading of x is would be useful without messing things up too much and
    it would only take another line of code, so maybe next time'


    If I knew more about how bB works I might try it myself
    Except peeing in other peoples soup isn't very polite.

     

     

    I do like the idea of some sort of macro prepocessor
    You wouldn't risk messing up bB but it would add another layer of kruft
    And I'm not sure you wouldn't just end up recreating bB
    (I haven't thought about it much, certainly that wouldn't be the case for a lot of it)


    How would you integrate the preprocessor in to the bB syntax?
    eg in comments? or a block like PREPROCESSOR ... END


  9. 2 hours ago, Karl G said:

    I'm not positive what you mean with these two items. Could you expand on what you are wanting?


      f{idx} = 1  ; idx must be a number 0..7, it can't be an expression or variable, it can't even be a named constant
    
      if f{idx} then ...
    
    


     Tables some thing like this


      ;  v0t name of volume table
      ;  c0t name of control table
      ;  f0t name of frequency table
    
      data v0t c0t f0t
      v0, c0, f0  ;  sets of values defining a note/sound the (values would presummably
      v1, c1, f1  ;  be numbers and the set of values would be like 9, 12, 23 etc)
      v2, c2, f2
      etc
    end
    
    


     but they'd go into seperate tables
     and you access them as if you'd put all the vx's in a table named v0t like wise the c's and f's
     so v0t[0] specifys v0, f0t[2] specifys f2
     it would be as if you'd defined tables like this


      data v0t
      v0, v1, v2
    end
    
      data c0t
      c0, c1, c2
    end
    
      data f0t
      f0, f1, f2
    end
    
    


     and your code would be something like (using the above suggested syntax,
     I'd normally do it in assembly and macros)

    
      note_ptr = note_ptr + 1
      LDX note_ptr
      AUDV0 = v0t[XREG]
      AUDC0 = c0t[XREG]
      AUDF0 = f0t[XREG]
    
    



  10.   There are things I wish you could do (more directly) in bB
      And there are common idioms that I think it would be useful to have built in
      Things that are not hard to do now but could be more convenient

     

      Karl G suggested in another thread some facility for multidefinition sprites for animations and such

     

      Ranged random numbers is another that comes up frequently

     

      Computed bit indexes

     

      Maybe transposed tables so you could specify values in sets for eg the sound registers and have them go into seperate tables

     

      Perhaps some built in division-by-a-constant routines similar to mutiplication by a constant

     

     

      My wish list is more nuts and bolts

     

      I'd like more direct access to the CPU registers and flags

      It would be nice if the registers were more fully integrated in to the syntax
      But even a few assembly instructions would help

     

      ACC = [expression]  do the normal thing but suppress the assignment just leave the result in the accumulator

     

      var = mem[XREG]     do the normal thing but suppress the loading of x

     

      TAX, TXA, LDX, STX

     

      so you could do something like

     

      ACC = [expression] : TAX : Px = tablex[XREG] : Py = tabley[XREG]

     

      without generating a lot of extranious load and store instructions

      (of course XREG = [expression] would be nicer)

     

      Some dedicated if constructs for testing flags would be nice

     

      if CARRY then ...  or  if !CARRY then ...   no predicate expression, just test the carry flag
      (likewise for the z, n, v flags)


      I generally like the way macros work, although I like to hide the callmacro key word with a def statement
      But using macros gets messy when trying to let the assembler know what it needs to know about what bB knows

      Perhaps I need a preprocessor ...


      I'd be curious to see other's wish lists

    • Like 1

  11. 50 minutes ago, Karl G said:

    As it stands now, sharing sprite data requires going "under the hood" and setting pointers, making sure the data is defined in the right place, and making sure the data does not cross a page boundary, which are things a bB programmer doesn't usually need to worry about. Since I am trying to help with bB maintenance, I was brainstorming how sharing sprite data could be accomplished in a more user-friendly way via changes to the language itself. E.g. perhaps a "spritedata" keyword could be added that would automatically put data in the graphics bank, and ensure that the data doesn't cross page boundaries. What do you think?


     heh heh
     
     I think they ought to just bite the bullet and learn enough about what's
     going on under the hood to know what they're doing
     Its not THAT complicated.


     I think it would be useful to have some lowest-common-denominator way of choosing
     among multiple sprite definitions for animations and such built in to bB
     Something more stream-lined than the usual clumsy, wasteful string of if-thens

     

     Given the variety of ways it might be done and the possible tradeoffs
     it might be better to have a utility that generated bB or assembly
     and could be more general (in addition to whatever got included in bB)


     

    Besides, if bB is going to be augmented I'd rather see the effort
    go in to other things.


  12. 1 hour ago, Karl G said:

    That is true, but not what I meant. If an individual table crosses a page boundary in the middle, it will likely result in screen distortion this is what Freshbrood experienced with his Mortal Kombat work-in-progress. I have been brainstorming ways to get around this problem, such as perhaps having the ability to define a data statement in a way that forces it to be aligned properly at compile time. Alternate leg, perhaps a way could be devised to Define Sprites without assigning them, and allow them to be assigned to multiple player objects. 

    hmm

    You shouldn't need to align the table as a whole.

     

    Freshbrood didn't post his code so it's hard to know what's going on there.

     

    As far as aligning the table goes, what's wrong with the align directive you were using?

     

    bB sometimes includes some assembly to generate the correct padding. (15 is the length of the table -1)

     

       2511  f730                  -          if    (<*) > (<(*+15))
       2512  f730                  -          repeat    ($100-<*)
       2513  f730                  -          .byte    0
       2514  f730                  -          repend
       2515  f730                          endif
    

     

       


  13. 1 hour ago, vitoco said:

    Ok... the trick is to assign the following for each player when needed:

      playerXpointerlo = <BITMAP
      playerXpointerhi = >BITMAP
      playerXheight = HEIGHT

    Thanks!

     

    correct and as needed so eg in the example I pointed to the height never changes so it's set once

     

    A slight elucidation of Karl G's point, the table can span a page boundary but an individual sprite definition should not cross a page boundary

    If all the definitions are in a single page then you'll only need to change the lo byte

    • Like 1

  14. On 2/19/2021 at 6:47 AM, Gemintronic said:

    I know gosubs have overhead.. what about functions?

     

    Functions are gosubs with additional overhead

    They always pass two parameters whether you specify them or not (but bB is likely to complain if you don't pass any parameters)

    You can sometimes sort of use them in place of an operand or an expression

    But I'd just use a subroutine.  More predicable.

    Functions are so finicky they're almost (but not quite) useless

     

    Subroutines have overhead, but not much.

    A gosub uses 12 cycles and two bytes of the stack

    a = b + c uses 11 cycles

     

    Depending on the kernel, the stack might be only 6 bytes so you could only go 3 levels deep provided

    you don't use any expressions that use stack (and I think drawscreen goes 3 deep)

    And the way bB uses the stack in expressions is all kinds of goofy  

    • Like 1
    • Thanks 1

  15. If like Karl G you find tables and indexes and sprite timing and addition and subtraction and stuff painful, assembly will be pure agony
    Best stick with writing out multiple copies of your sprite data and strings of redundant if then spaghetti going "is this it? is this it?"
    Any way you don't need any assembly for your sprite tables


    tl;dr "loading player graphics from data tables is a pain, so avoid it if you can." is an exceptionally silly sentiment
     


  16.  

    1 hour ago, freshbrood said:

    if the 12th row of playfield blocks can't even be shown, why does the tia still waste cycles attempting to draw it?

    That's kinda like asking "why does this clock keep ticking when I'm not looking at the time"

    That's pretty much all the TIA does

     

    The 12th row is for scrolling I assume

     

    Here's 12 rows (well, more actually)

    • Like 1

  17. I avoid using the forum to edit replys as much as possible
    I use a text editor and then just paste it wholesale then
    maybe fix it in the forum editor if I think it relly needs it
    Seems like it always messes something up

     

     

    Your colors are not a multiple of 24 (or 23, your player defintion is
    23 lines)


    You avoid division if possible because it takes a long time and quite often
    there's something else you can do to avoid or minimize the use of division

     

     

    It occurs to me that you may be getting confused by the way the names are used
    So here's a bit of a ramble throught some of the intricacies

     

    First the processor deals in bytes and, generally, so does bB
    A byte is 8 bits and can represent values 0..255

    That's not enough for some stuff, memory addresses in particular
    So two bytes are used which gives you 0..65535
    But they still only get dealt with one byte at a time
    It's kinda like a two digit decimal number has a ones place and a tens place
    except we have a ones place and a 256 place


    Each of the 256 place is a "page" of 256 bytes


    With indexing you start with a 16 bit number and add a 8 bit number to it
    ie you start with a value 0..65535 and add a value 0..255 to it


    Kinda like (in decimal) taking a 0..99 number and adding a number 0..9


    If the result of adding the ones places is more than the ones place can "hold"
    you need to do a carry.

    That takes extra time and that messes up the kernel timing

    (Its only going to matter for stuff used in the kernel where timing is tight,

    not for ordinary data in bB)


    So you need to be sure that the result of adding your index to your base location
    doesn't result in a location in the next page, ie doesn't cause a carry into the
    256's byte of your 16 bit address


    For example, in the case of the your color table with 24 colors,

    if the player0colors is a two byte, 16 bit memory location which specifies a memory location (of the color table)
    then if the ones byte ie the value contained in player0colorslo is within 24 of 256

    ie if it's greater than 255 - 24, then the kernel will try to reach into the next page and that will mess up the timing


    Mind you the complete table of colors can cross the page boundary as long as
    there's a whole group of 24 on this side of the page boundary and a whole group on the other side
    Assuming they're contiguous then the one in the next page must start at zero in the page


    As long as they're wholly contained in a page it doesn't matter where they are in the page
    and normally that's how it works with individual color defintions


    Putting them all in one table means they have to align with a page boundary

    (if the overall table straddles the page boundary)

     

     

    Player0pointerlo is the name for the memory address for the first byte of the 16 bit address
    in memory of the table that contains the player definition

     

    To the assembler its a constant, $8A as defined in 2600basic.h
    In the kernel it's the first byte of the two bytes of memory that contain the address (location)

    in memory of the player definition table

     
    bB take it as an alias for the value it contains, the lo byte of that address


    So player0pointerlo is also the constant $8A

     

    If I define a constant as player0pointerlo + 1 that constant name will be an alias for

    the same value as player0pointerhi, $8B which will be the address of the location in

    memory after (the location specified by) player0pointerlo, ie it will be location $8B

     

    In bB if I say a = player0pointer + 1 it will get the contents of memory location $8A add one to it
    and put the result in memory location $D4 (the location in memory of variable a, also specified in 2600basic.h)
    (of course, it actually compiles code to do that)

     

    Now back to the decimal anology

     

    Suppose memory is 100 locations 00..99 

    Each "byte" (location) can hold a single digit

    Our player height is 3 and we want 5 possible color schemes of 3 bytes each
    Our color table will be 15 bytes

     

    Say the colors table just happens to begin at location 65
    Player0colors will contain 5 and the location after player0colors will contain 6


    the kernel will look at player0colors find 65, add 2 to it and look into the table at location 67 for the first color
    For three lines (the player height) with three colors the index values will be 0..2.  The locations in the table will be 65..67


    The high byte, ie the "page" will be 6 for each of those locations and doesn't change.  No carry.
    The second set of colors will start after the first set beginning at location 68


    We choose it by setting (the location in memory refered to by) player0colors to 8 and the following location to 6


    Now when the kernel looks for line one it gets 68 adds 2 and gets 70.

    The page has changed, that needs a carry to the page digit, that takes extra time, that screws up the kernel timing.


    The second set of colors straddles the page boundary at locations 68..70.


    To fix it we can add padding, two zeros to align the colors boundary with the page boundary

    65..66 will contain 0
    the colors table will start at 67
    the individual color sets will be at locations 67..69, 70..72, 73..75 etc


    Each set is wholly contained within a page.


    You won't be able to do that if the whole table straddles more than one page boundary

    and the color sets are not an integral divisor of the page length

    ie (in this decimal anology with "pages" of 10 "bytes") it cant be done for two pages if the player height is 3
    but a player height of 5 will work

     

    You could add padding to the middle of the table or something like that but it would screw up the regularity of the table

    in which case a look up table would definitely work better than multiplying

     

    Also the individual color tables don't have to be in one big table, even if you're multiplying to get the index

    You would want them to be contiguous if you're multiplying
     

    • Thanks 1


  18. I realized I should be doing an increment or a reset of seconds/minutes, not both
    since I'm going for speed

    And now the table needs padding to page align

    Shaves 36 cycles so worst case is ~80 cycles

      set optimization noinlinedata
    
      dim frames         = t.s
      dim seconds_lo     = player0pointerlo
      dim seconds_hi     = player0pointerhi
      dim minutes_lo     = player1pointerlo
      dim minutes_hi     = player1pointerhi
      dim seconds        = seconds_hi.seconds_lo
      dim minutes        = minutes_hi.minutes_lo
    
      def frame_time     = 4.274
      def reset_seconds  = seconds_lo = Pxtlo : seconds_hi = Pxthi
      def reset_minutes  = minutes_lo = Pxtlo : minutes_hi = Pxthi
      def inc_seconds    = seconds = seconds + 0.02
      def inc_minutes    = minutes = minutes + 0.02
    
    
      const max          = 59 * 5
      const rollover     = Pxtbl + max
      const Pxthi        = >Pxtbl
      const Pxtlo        = <Pxtbl
      const rollover_hi  = >rollover
      const rollover_lo  = <rollover
    
      player0x = 79 : player1x = 70
      player0y = 40 : player1y = 40
      player0height = 4 : player1height = 4
      reset_seconds
      reset_minutes
    
    
    loop
    
      COLUP0 = $1C : COLUP1 = $1C
      drawscreen
    
      temp1 = t
      frames = frames + frame_time
      if t > temp1 then loop
    
      if seconds_lo <> rollover_lo then inc_seconds : goto loop   ;  the player height and the bytes per page are coprime
                                                                  ;  so rollover_lo only occurs once per cycle
      reset_seconds
    
      if minutes_lo <> rollover_lo then inc_minutes : goto loop
    
      reset_minutes
    
      goto loop
    
      data table_padding                                          ;  padding to align player definitions with a page boundary
      $00
    end
    
      data Pxtbl
      $77, $55, $55, $55, $77, $71, $51, $51, $51, $71
      $77, $54, $57, $51, $77, $77, $51, $57, $51, $77
      $71, $51, $57, $55, $75, $77, $51, $57, $54, $77
      $77, $55, $57, $54, $77, $71, $51, $51, $51, $77
      $77, $55, $57, $55, $77, $77, $51, $57, $55, $77
      $17, $15, $15, $15, $17, $11, $11, $11, $11, $11
      $17, $14, $17, $11, $17, $17, $11, $17, $11, $17
      $11, $11, $17, $15, $15, $17, $11, $17, $14, $17
      $17, $15, $17, $14, $17, $11, $11, $11, $11, $17
      $17, $15, $17, $15, $17, $17, $11, $17, $15, $17
      $77, $45, $75, $15, $77, $71, $41, $71, $11, $71
      $77, $44, $77, $11, $77, $77, $41, $77, $11, $77
      $71, $41, $77, $15, $75, $77, $41, $77, $14, $77
      $77, $45, $77, $14, $77, $71, $41, $71, $11, $77
      $77, $45, $77, $15, $77, $77, $41, $77, $15, $77
      $77, $15, $75, $15, $77, $71, $11, $71, $11, $71
      $77, $14, $77, $11, $77, $77, $11, $77, $11, $77
      $71, $11, $77, $15, $75, $77, $11, $77, $14, $77
      $77, $15, $77, $14, $77, $71, $11, $71, $11, $77
      $77, $15, $77, $15, $77, $77, $11, $77, $15, $77
      $17, $15, $75, $55, $57, $11, $11, $71, $51, $51
      $17, $14, $77, $51, $57, $17, $11, $77, $51, $57
      $11, $11, $77, $55, $55, $17, $11, $77, $54, $57
      $17, $15, $77, $54, $57, $11, $11, $71, $51, $57
      $17, $15, $77, $55, $57, $17, $11, $77, $55, $57
      $77, $15, $75, $45, $77, $71, $11, $71, $41, $71
      $77, $14, $77, $41, $77, $77, $11, $77, $41, $77
      $71, $11, $77, $45, $75, $77, $11, $77, $44, $77
      $77, $15, $77, $44, $77, $71, $11, $71, $41, $77
      $77, $15, $77, $45, $77, $77, $11, $77, $45, $77
    end
    
    

    hour_clock_02.bas hour_clock_02.bas.bin



  19. Here is another clock
    It counts up seconds to one hour

    It uses a brute force approach with every thing in 300 bytes of tables/ROM

    It's more accurate and uses 16 fractional bits (of a second) for the increment

    it takes about 110 cycles (not counting drawscreen) for the loop in the worst case, ie rollover to 00 00

      set optimization noinlinedata
    
      dim frames         = t.s
      dim seconds_lo     = player0pointerlo
      dim seconds_hi     = player0pointerhi
      dim minutes_lo     = player1pointerlo
      dim minutes_hi     = player1pointerhi
      dim seconds        = seconds_hi.seconds_lo
      dim minutes        = minutes_hi.minutes_lo
    
      def frame_time     = 4.274
      def reset_seconds  = seconds_lo = Pxtlo : seconds_hi = Pxthi
      def reset_minutes  = minutes_lo = Pxtlo : minutes_hi = Pxthi
    
      const max          = 60 * 5
      const rollover     = Pxtbl + max
      const Pxthi        = >Pxtbl
      const Pxtlo        = <Pxtbl
      const rollover_hi  = >rollover
      const rollover_lo  = <rollover
    
      player0x = 79 : player1x = 70
      player0y = 40 : player1y = 40
      player0height = 4 : player1height = 4
      reset_seconds
      reset_minutes
    
    
    loop
    
      COLUP0 = $1C : COLUP1 = $1C
      drawscreen
    
      temp1 = t
      frames = frames + frame_time
      if t > temp1 then loop
    
      seconds = seconds + 0.02
      if seconds_lo <> rollover_lo then loop            ;  the player height and the bytes per page are coprime
                                                        ;  so rollover_lo only occurs once per cycle
      reset_seconds
    
      minutes = minutes + 0.02
      if minutes_lo <> rollover_lo then loop
    
      reset_minutes
      goto loop
    
    
      data Pxtbl
    
      $77, $55, $55, $55, $77, $71, $51, $51, $51, $71
      $77, $54, $57, $51, $77, $77, $51, $57, $51, $77
      $71, $51, $57, $55, $75, $77, $51, $57, $54, $77
      $77, $55, $57, $54, $77, $71, $51, $51, $51, $77
      $77, $55, $57, $55, $77, $77, $51, $57, $55, $77
      $17, $15, $15, $15, $17, $11, $11, $11, $11, $11
      $17, $14, $17, $11, $17, $17, $11, $17, $11, $17
      $11, $11, $17, $15, $15, $17, $11, $17, $14, $17
      $17, $15, $17, $14, $17, $11, $11, $11, $11, $17
      $17, $15, $17, $15, $17, $17, $11, $17, $15, $17
      $77, $45, $75, $15, $77, $71, $41, $71, $11, $71
      $77, $44, $77, $11, $77, $77, $41, $77, $11, $77
      $71, $41, $77, $15, $75, $77, $41, $77, $14, $77
      $77, $45, $77, $14, $77, $71, $41, $71, $11, $77
      $77, $45, $77, $15, $77, $77, $41, $77, $15, $77
      $77, $15, $75, $15, $77, $71, $11, $71, $11, $71
      $77, $14, $77, $11, $77, $77, $11, $77, $11, $77
      $71, $11, $77, $15, $75, $77, $11, $77, $14, $77
      $77, $15, $77, $14, $77, $71, $11, $71, $11, $77
      $77, $15, $77, $15, $77, $77, $11, $77, $15, $77
      $17, $15, $75, $55, $57, $11, $11, $71, $51, $51
      $17, $14, $77, $51, $57, $17, $11, $77, $51, $57
      $11, $11, $77, $55, $55, $17, $11, $77, $54, $57
      $17, $15, $77, $54, $57, $11, $11, $71, $51, $57
      $17, $15, $77, $55, $57, $17, $11, $77, $55, $57
      $77, $15, $75, $45, $77, $71, $11, $71, $41, $71
      $77, $14, $77, $41, $77, $77, $11, $77, $41, $77
      $71, $11, $77, $45, $75, $77, $11, $77, $44, $77
      $77, $15, $77, $44, $77, $71, $11, $71, $41, $77
      $77, $15, $77, $45, $77, $77, $11, $77, $45, $77
    end
    
    

     

     

     

    hour_clock.bas hour_clock.bas.bin


  20. I guess the answer then is that every thing is precalculated and kept in ROM

    In the case of a player you just set a pointer to a table in ROM

    In the case of the playfield the table in ROM gets copied to RAM


    But you don't have to do it that way


    According to RT's page you get 1675 cycles in vblank
     
    If your clock needed to update every frame and you used 4 digits of 8 bytes each ie 128 pixels,
    probably not enough time to do a pixel at a time.

    If your clock only needs to update once a second it probably is enough time.


    The code I posted takes around 150 cycles to compose the two 3 x 4 digits
    but it doesn't do a pixel at a time


    as for accuracy

    I don't think glitching would be a problem
    but crystals aren't all that accurate to begin with
    a really good crystal would be like +-1 second a day

    I calculate the code I posted at 106 seconds for the 100 second count down
    I measured it to be 105 in Stella
     



  21. I don't think you're describing what you want very well


    Here's a 2 digit count down timer that uses player0 in RAM

    Pressing joy0fire resets the counter to 100 and it proceeds to count down by seconds to 00

    You could put the numbers in ROM and it would be faster and save the four variables it uses

    It would be 400 bytes of ROM for 100 numbers

     

      dim time = t.s
      dim d0 = temp2
      dim d1 = temp3
    
      COLUPF = $2C
    
      player0x = 80 : player0y = 44
    
      player0height = 4
      player0pointerlo = $EA : player0pointerhi = $00  ; set player0pointer to point to variable w
      COLUP0 = $1C
      
      gosub update_player
    
    
    loop
      COLUP0 = $1C
      drawscreen
    
      if joy0fire && !f then t = 100 : s = 0   ;  set time to 99
      if joy0fire then f = 255 else f = 0
    
      if !(t | s) then loop                   ;  if time = 0 skip decremting the timer
    
      temp1 = time
      time = time - 0.017                     ;  decrement time by ~1/60
    
      if time > 99 then t = 0 : s = 0         ;  if underflow, set time to 0
    
      if temp1 = time  then loop              ;  if the decrement didn't change the integer part of time skip updating the display
    
      temp1 = time / 16
      dec temp1 = (time & $0F) + 0 + dnib[temp1]  ;  convert to bcd
    
      gosub update_player
      goto loop
    
    
    update_player
      d0 = temp1 & 15
      d1 = temp1 / 16
    
      z = l0[d1] & $F0 : z = (l0[d0] & $0F) | z
      y = l1[d1] & $F0 : y = (l1[d0] & $0F) | y
      x = l2[d1] & $F0 : x = (l2[d0] & $0F) | x
      w = l3[d1] & $F0 : w = (l3[d0] & $0F) | w
    
      return
    
    
      data l0
      $77, $22, $77, $77, $55, $77, $33, $77, $77, $77
    end
    
      data l1
      $55, $66, $33, $33, $77, $66, $66, $11, $77, $55
    end
    
      data l2
      $55, $22, $66, $11, $11, $11, $55, $22, $55, $33
    end
    
      data l3
      $77, $22, $77, $77, $11, $66, $77, $22, $77, $66
    end
    
      data dnib
      $00, $16, $32, $48, $64, $80, $96
    end
    
    

     

    count_down_timer.bas count_down_timer.bas.bin


  22. Your color tables are not multiples of 24


    I guess what you want would best be done with a look up table for the multiplication

      dim tmp88 = temp2.temp1
    
    
      temp2 = 0 : temp1 = mpy24[o]
    
      P0c_pointer = P0c_pointer + tmp88
    
      data mpy24
      0, 24, 48, 72, 96, 120, 144  etc
    end
    
    

      Or you could do the multiplication in bB

      temp1 = ((o * 2) + o) * 8
    
    

    • Confused 1
×
×
  • Create New...