+Andrew Davie Posted February 26, 2020 Share Posted February 26, 2020 (edited) 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 March 1, 2020 by Andrew Davie Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted February 26, 2020 Author Share Posted February 26, 2020 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 Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted February 26, 2020 Author Share Posted February 26, 2020 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 Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted March 1, 2020 Author Share Posted March 1, 2020 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? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.