Jump to content
IGNORED

Neato LO/HI/BANK/state machine table definitions


Andrew Davie

Recommended Posts

Moved/continued at

 

 

 

I finally figured out an "elegant" way to define multiple low/high/bank/parameter tables using DASM macros.

Fortunately, you can pass the name of a macro to use TO another macro, as a parameter. So that macro can call the other macro... indirectly.

I use it to create tables of pointers.

 

In the example below, I define a macro to generate an equate to reference each 'state' of a state machine (used as an index into the tables to get the correct entry), and also a macro to plonk down the low byte of the function address, another for the high byte, and another for a parameter (in this case, time).

The nice thing here, you only define each state on a single line (in the TABDEF macro) and you never have to worry about getting your ordering correct in the LOW/HIGH tables, or missing an entry. Just change in one line, and everything else auto-adjusts.

 

So, here's the boilerplate macros...

    MAC AIN
AI_{2} SET {1}				; define an equate as an index to a stat entry
    ENDM

    MAC LO
    .byte <ai{2}			; low byte table pointer
    ENDM

    MAC HI
    .byte >ai{2}			; high byte table pointer
    ENDM

    MAC BK
    .byte BANK_ai{2}		; bank table pointer
    ENDM

    MAC TM
    .byte {3}				; "time" table for each state
    ENDM

    ; In TABDEF (below) we list all the states, one per line
    ; The first parameter is the macro to call for that line (passed in as parameter 1 of TABDEF)
    ; The second parameter is a unique ident # for state, so you can go something like "lda #AI_DrawMoves // jsr JumpToState"
    ;  - note, these MUST be numerically ordered, no gaps. I'd use a macro to auto-generate with SET/increment, but DASM borks
    ; The third parameter is the name of the state. 

    MAC TABDEF ; {1} = macro to use
        ; and per-line, {1} = #, {2} = name, {3} = time
    {1}  0, BeginSelectMovePhase, 40
    {1}  1, SelectStartSquare, 40
    {1}  2, StartSquareSelected, 40
    {1}  3, DrawMoves, 40
    ENDM

    

 

The TABDEF macro has one line per state (or function in the tables you want to create), with the basic unadorned name of the function that handles that state. I add a couple of prefixes ("ai" to the function name, and "AI_" to the equate) just because that's how my existing code is expecting stuff. You can use anythingyou want here as long as there's something different bewteen the generated equate and the function name.

Now very easy (instead of 4 tables you have to manage and make sure all the entries are in the right order)... you just do this
 

	; Macros are defined, now here's the actual table generation.
   

    TABDEF AIN					; generates the equates for each state
    DEF AiVectorLO
    TABDEF LO					; creates a low-byte table
    DEF AiVectorHI
    TABDEF HI					; creates a high-byte table
    DEF AiVectorBANK
    TABDEF BK					; creates a bank table
    DEF AiTimeRequired
    TABDEF TM					; creates a table for times
    

Those TABDEF lines are calling the macro TABDEF and passing the name of the macro for tabdef to use on its contents.

So inside tabdef we see (for example, one line...)

 

    {1}  1, SelectStartSquare, 40

So where we go "TABDEF HI", that will pass "HI" to tabdef, and that will then become

 

    HI 1, SelectStartSquare, 40

Which in turn calls the "HI" macro (once for each line in TABDEF, actually) and passes the parameters on the line.

HI macro can do whatever it wants with the parameters, but in this case it just plonks down a ".byte >ai{2}", which is the high byte of the function name.

 

Finally, we define the actual subroutines.

    ; Now we define the actual functions. I use a "DEF" macro to make that easy...
    
        MAC DEF               ; {1} = name of subroutine
BANK_{1}        SET _CURRENT_BANK           ; bank in which this subroutine resides
{1}                                     	; entry point
    ENDM


	; So, defining the 4 state handlers...
    
    DEF aiBeginSelectMovePhase
    ; stuff here for this state
    rts
    
    DEF aiSelectStartSquare
    ; stuff here for this state
    lda #AI_StartSquareSelected
    sta state							; switch to new state for next time
    rts
    
    DEF aiStartSquareSelected
    ; stuff here for this state
    rts
    
    DEF aiDrawMoves
    ; stuff here for this state
    lda #AI_BeginSelectMovePhase
    sta state							; switch back to 1st state
    rts

 

I'm sure this is as clear as mud. But, if you study it a bit, and generalise... it becomes a very clean and simple way to define LO/HI tables using macros.

 

Or any tables, really, for which you have multiple values to retrieve, LO/HI/BANK/Speed/Points/Time... whatever, which share a single index/entry #

And you only have to define all the table values on a single line (inside TABDEF).

 

Hope this helps someone out.

I've been wanting to be able to do something like this for absolutely YONKS.

 

 

 

 

Edited by Andrew Davie
Link to comment
Share on other sites

Here's a minimal code example with just lo/hi tables.

 

    processor 6502
    org $1000

    MAC LO
    .byte <{1}
    ENDM

    MAC HI
    .byte >{1}
    ENDM


    MAC TABDEF ; {1} = macro to use
        ; and per-line, {1} = function
    {1}  Func1
    {1}  Func2
    {1}  Func3
    ENDM

LO_Table
    TABDEF LO
HI_Table
    TABDEF HI


Func1
    rts

Func2
    rts

Func3
    rts

 

 

Listing file...

------- FILE ./test.asm LEVEL 1 PASS 2
      1  1008					      processor	6502
      2  1000					      org	$1000
      3  1000
      4  1000					      MAC	lo
      5  1000					      .byte	<{1}
      6  1000					      ENDM
      7  1000
      8  1000					      MAC	hi
      9  1000					      .byte	>{1}
     10  1000					      ENDM
     11  1000
     12  1000
     13  1000					      MAC	tabdef
     14  1000							; and per-line, {1} = function
     15  1000					      {1}	Func1
     16  1000					      {1}	Func2
     17  1000					      {1}	Func3
     18  1000					      ENDM		; {1} = macro to use
     19  1000
     20  1000				   LO_Table
      0  1000					      TABDEF	LO
      1  1000
      0  1000					      LO	Func1
      1  1000		       06		      .byte.b	<Func1
      0  1001					      LO	Func2
      1  1001		       07		      .byte.b	<Func2
      0  1002					      LO	Func3
      1  1002		       08		      .byte.b	<Func3
     22  1003				   HI_Table
      0  1003					      TABDEF	HI
      1  1003
      0  1003					      HI	Func1
      1  1003		       10		      .byte.b	>Func1
      0  1004					      HI	Func2
      1  1004		       10		      .byte.b	>Func2
      0  1005					      HI	Func3
      1  1005		       10		      .byte.b	>Func3
     24  1006
     25  1006
     26  1006				   Func1
     27  1006		       60		      rts
     28  1007
     29  1007				   Func2
     30  1007		       60		      rts
     31  1008
     32  1008				   Func3
     33  1008		       60		      rts

 

 

test.asm

Link to comment
Share on other sites

Minor update. It is possible to auto-generate the index/equates.

I just switched from a local variable for the value, to a global... and it worked.
Here's the state table definition from my game Chess...

 

P SET 0
    MAC AIN
AI_{1} SET P
P SET P+1
    ENDM

    MAC LO
    .byte <ai{1}
    ENDM

    MAC HI
    .byte >ai{1}
    ENDM

    MAC BK
    .byte BANK_ai{1}
    ENDM

    MAC TM
    .byte {2}
    ENDM

    MAC TABDEF ; {1} = macro to use
        ; and per-line, {1} = #, {2} = name, {3} = time
    {1} BeginSelectMovePhase, 40
    {1} SelectStartSquare, 40
    {1} StartSquareSelected, 40
    {1} DrawMoves, 40
    {1} ShowMoveCaptures, 40
    {1} SlowFlash, 40
    {1} DrawTargetSquares, 40
    {1} SelectDestinationSquare, 40
    {1} Quiescent, 40
    {1} Halt, 40
    {1} ReselectDebounce, 40
    {1} StartMoveGen, 40
    {1} StepMoveGen, 40
    {1} LookForCheck, 40
    {1} StartClearBoard, 40
    {1} ClearEachRow, 40
    {1} DrawEntireBoard, 40
    {1} DEB2, 40
    {1} FlipBuffers, 40
    {1} FB0, 40
    {1} FB2, 40
    {1} FB3, 40
    {1} WriteStartPieceBlank, 40
    {1} MarchToTargetA, 40
    {1} MarchB, 40
    {1} MarchToTargetB, 40
    {1} MarchB2, 40
    {1} FinalFlash, 40
    {1} SpecialMoveFixup, 40
    {1} InCheckBackup, 40
    {1} InCheckDelay, 40
    {1} PromotePawnStart, 40
    {1} RollPromotionPiece, 40
    {1} ChoosePromotePiece, 40
    {1} ChooseDebounce, 40
    ENDM

    TABDEF AIN
    DEF AiVectorLO
    TABDEF LO
    DEF AiVectorHI
    TABDEF HI
    DEF AiVectorBANK
    TABDEF BK
    DEF AiTimeRequired
    TABDEF TM

 

Link to comment
Share on other sites

Here's a similar, but more concise, way to define lo/hi tables...

 

    MAC POSTAB
    .byte {1}PositionalValue_PAWN
    .byte {1}PositionalValue_PAWN
    .byte {1}PositionalValue_KNIGHT
    .byte {1}PositionalValue_BISHOP
    .byte {1}PositionalValue_ROOK
    .byte {1}PositionalValue_QUEEN
    .byte {1}PositionalValue_KING_MIDGAME
    ENDM


PosValVecLO POSTAB <
PosValVecHI POSTAB >

 

Neat, huh?

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...