Jump to content
IGNORED

Assembly on the 99/4A


matthew180

Recommended Posts

17 minutes ago, senior_falcon said:

In my example, 10 CALL LOAD(-2,3), you did not give your opinion as to whether the value 3 is placed at >FFFE. I am not sure whether you believe that or not, but most people who use the TI would think so, and certainly a few moments using a debugger would inevitably lead you to that opinion.

When I use a word processor, I have noticed that every time I press the "A" key that an A appears on the screen. If some jackwad then comes along and said "LOL, show me the code for that?" what would you think about that person. 

This is GPL for CALL LOAD:

***********************************************************
* ASSEMBLY LANGUAGE SUPPORT FOR 99/4
*
* LOAD, INIT, PEEK, LINK, CHARPAT      JDH  08/21/80
***********************************************************
* FORMAT FOR LOAD:
*  CALL LOAD open load-directive (comma load-directive)
*            close
*    load-directive = file-name / address (comma data)
*                     (null / file-name)
*    file-name      = string-expression
*    address        = numeric-expression
*    data           = numeric-expression
*
*  FILE TYPE = FIXED 80, DISPLAY , SEQUENTIAL FILE
*
* FUNCTION:
*  LOADS ASSEMBLY LANGUAGE CODE INTO EXPANSION RAM
*  ADDRESSES: >2000 - >>3FFF RELOCATING
*  RELOCATABLE CODE INTO AVAILABLE MEMORY, ABSOLUTE CODE
*  IS LOADED
*  INTO ITS ABSOLUTE ADDRESS, ENTRY POINTS ARE DEFINED BY
*  'DEF' STATEMENTS, AND ARE LOADED INTO HIGH END OF ERAM
*
*  RELOACATABLE OR ABSOLUTE CODE MAY BE STORED ON A FILE
*  9900 OBJECT CODE FORMAT.
*   VALID TAGS = 0, 5, 6, 7, 9, A, B, C, F,:
*         TAGS 1, 2, I, M, ARE IGNORED
*  THE SYMT OPTION IS NOT SUPPORTED.
*  ABSOLUTE CODE MAY BE LOADED DIRECTLY FROM PROGRAM
*  BY SPECIFYING AN ADDRESS INSTEAD OF A FILE NAME,
*  FOLLOWED BY THE DATA TO BE LOADED (WHICH IS PUT IN THE
*   RANGE 0 to 255
*  THE RANGE OF THE ADDRESS OR DATA IS LIMITED TO
*   32767 to -32768
*  MULTIPLE DIRECT LOADS CAN BE IN THE SAME LOAD COMMAND
*  PROVIDED THEY ARE SEPARATED BY EITHER A FILENAME OR A
*   NULL STRING.
*
* RXB CHANGED MVUP TO GPL MOVE AS MOVING 2 BYTES USING 14 
* BYTES OF GPL TO MOVE RAM TO SCRATCH PAD WAS SLOWER.
*
*  MVUP WAS USED TO TRANSFER DATA FROM CPU RAM TO ERAM
*  SINCE IT WAS NOT KNOWN AT FIRST THAT THE MOVE
*  INSTRUCTION COULD TRANSFER FROM CPU RAM TO ERAM
*   (PROVIDED THAT >8300 IS SUBTRACTED FROM THE ADDRESSES)
***********************************************************
* RXB PATCH CHANGED CALL INIT TO ROM 3
* REPLACING ORIGINAL TO ASSEMBY IN 1 CHUNK
***********************************************************
* RXB BRANCH TABLE FOR LONG GROMS
* >C010 was CALL LINK
***********************************************************
* CALL LOAD("DSK#.FILENAME"[,...])                              * 
* CALL LOAD(ADDRESS,LIST[,...])                           *
***********************************************************
LOAD   DST  >0001,@CHKSUM     {INITIALIZE FILE FLAG}
* GKXB Change load routine. Delete check for INIT
*      add to clear flag bits.
       CALL GKLOAD
LPD0   CEQ  LPARZ,@CHAT       SYNTAX ERROR if no "("
       BR   ERRSY1
       XML  PGMCHR            Skip over
* MAIN PARESE LOOP *
* Check for file-name or address
LDP1   XML  PARSE
       BYTE RPARZ           * PARSE up to ")" or ","
       CEQ  STRING,@FAC2      Process file name
       BS   LDP2
* Otherwise it is an address
* Convert address to integer, save in @PC
       XML  CFI               Convert FAC to integer
       CEQ  3,@FAC10          Check for overflow
       BS   ERRN01
       DST  @FAC,@PC          Save in ERAM location pointer
* Check for "," if there then data should folow
*  else end of load statement, goto LDP5
LDP4   CEQ  COMMAZ,@CHAT
       BR   LDP5
* DATA follows or a STRING if no more data
       XML  PGMCHR            Skip ","
       XML  PARSE             Get data value or string if
*                              end of data
       BYTE RPARZ           * Parse up to ")" or ","
       CEQ  STRING,@FAC2      No more data
       BS   LDP2
* FAC contains a numeric
       XML  CFI               FAC to INTEGER
       CEQ  3,@FAC10          Check for overflow
       BS   ERRN01
* GKXB Code for CPU write moved to LOADDT. Add code to
*      check VDP or GRAM bits and write to VDP.
       CLOG >08,@GKFLAG       Check VDP bit
       BS   LDGRAM            No, check GRAM bit
       ST   @FAC1,V*PC        Yes, write to VDP
       DINC @PC               Point to next byte
       B    LDP4              Continue with LOAD routine
* GROM ADDRESS >C088 FOR LDP5
* Check for ")"  IF there return ELSE SYNTAX ERROR
LDP5   CEQ  RPARZ,@CHAT       Return
       BS   LDRET
       B    ERRSY1            SYNTAX ERROR
* LDP2
* Process file name
LDP2   CZ   @FAC7             Check for null string
       BS   LDNE2
* GKXB Change 'LOAD FILE' to check for INIT
       CALL GKINIT
*************** LOAD DATA INTO ERAM ***********************
* LOAD FRESTA, FREEND from ERAM
       DST  FSLOC,@VARB          Source
       DST  FRESTA,@PAD          Destination
       DST  4,@ARG               # of bytes to move
       XML  MVUP                 Load
* Initialize PC, OFFSET in case of no "0" tag
       DST  @FRESTA,@PC
       DST  @FRESTA,@OFFADD   Base address for load module
* Read in one record, evaluate the TAG field
* LDRD - LDTG
LDRD   DST  0,@CHKSUM         Clear check sum
       CALL READIT            Rear in a record
LDTG   MOVE 5,V*BUFPNT,@TAG   Get TAG & field
       CALL LDIPCS            Add 5 to BUFPNT, add ASCII
       BYTE 5               * Value of chars. Read to check
* Convert @FIELD to numeric (from ASCII hex value)
* Store result: HIGH BYTE to FIELD, LOW BYTE to FIELD+1
* Convert HIGH BYTE first: @FIELD & @FIELD+1
* Store result in field
       SUB  >30,@FIELD        >30 = "0"
       CGT  9,@FIELD          Subtract ASCII difference
*                              between "9" and "A"
       BR   GC0C7
       SUB  7,@FIELD
GC0C7  SLL  4,@FIELD          FIELD=FILED*32
       SUB  >30,@FIELD+1
       CGT  9,@FIELD+1
       BR   GC0D5
       SUB  7,@FIELD+1
GC0D5  ADD  @FIELD+1,@FIELD   Add to HIGH BYTE
* Now convert LOW BYTE: @FIELD+2 & @FIELD+3
* Store result in LOW BYTE of FIELD to FIELD+1
       SUB  >30,@FIELD+2
       CGT  9,@FIELD+2
       BR   GC0E3
       SUB  7,@FIELD+2
GC0E3  ST   @FIELD+2,@FIELD+1 Store in LOW byte of result
       SLL  4,@FIELD+1        FIELD+1 = FIELD+1*32
       SUB  >30,@FIELD+3
       CGT  9,@FIELD+3
       BR   GC0F4
       SUB  7,@FIELD+3
GC0F4  ADD  @FIELD+3,@FIELD+1 Add to low byte
* Branch to evaluation procedure for TAG
       SUB  >30,@TAG          >30 = "0"
       CGE  0,@TAG            If TAG < "0" ILLEGAL CHAR
       BR   ERRUC1
       CGT  >0A,@TAG          TAGS "0" to ":"
       BS   GC11C
       CASE @TAG
       BR   TAG0              "0" RELOCATABLE LENGTH
       BR   LDTG              IGNORE "1" TAG
       BR   LDTG              IGNORE "2" TAG
       BR   ERRUC1            No external REF "3"
       BR   ERRUC1            No external REF "4"
       BR   TAG5              "5" relocatable entry DEF
       BR   TAG6              "6" Absolute entry    DEF
       BR   TAG7              "7" check sum
       BR   LDTG              "8" ignore check sum
       BR   TAG9              "9" Absolute LOAD address
       BR   LDDNE             ":" end of file
GC11C  SUB  >11,@TAG          Subtract offset so
*                              that "A" is =0
       CGE  0,@TAG            ";" to "@" illegal char
       BR   ERRUC1
* Skip over "I" tag - 8 char, program ID that follows
       CEQ  8,@TAG
       BS   LDTG2
* Skip over "M" TAG -10 char, program ID that follows
       CEQ  12,@TAG
       BR   LDTG3
       CALL LDIPCS
       BYTE 10
       B    LDTG
LDTG3  CGT  5,@TAG            TAGS "G" are legal
       BS   ERRUC1
       CASE @TAG
       BR   TAGA              "A" RELOCATABLE PROGRAM ADDRE
       BR   TAGB              "B" ABSOLUTE VALUE
       BR   TAGC              "C" RELATIVE ADDRESS
       BR   ERRUC1            "D" ERROR
       BR   ERRUC1            "E" ERROR - UNDEFINED
       BR   LDRD              "F" END OF RECORD
* TAG0 to TAGB
* EVALUATE TAG FIELDS
TAG0   DST  @FRESTA,@OFFADD   NEW BASE ADDRESS
       DST  @FRESTA,@PC       NEW PC
       DADD @FIELD,@FRESTA    ADD LENGTH TO FIND END OF
*                              RELOCATABLE PROGRAM WHICH IS
*                              START OF NEXT PROGRAM
* Make sure we won't run into routine name table now, so we
*  don't have to check every time we load a value into ERAM
*  routine table must make sure it doesn't run into
*  relocatable assembly language code through.
       DCHE @FREEND,@FRESTA   OUT OF MEMORY
       BS   ERRMF1
* SKIP OVER PROGRAM ID - 8 BYTES
LDTG2  CALL LDIPCS
       BYTE 8               * INC BUFPNT, COMPUTE CHECKSUM
       B    LDTG
TAG5   DADD @OFFADD,@FIELD    Add starting offset
* TAG6 is an absolute address so do not need to add offset
TAG6   MOVE 6,V*BUFPNT,@INDEX    Get symbol name
       CALL LDIPCS            INC BUPNT, COMPUT CHECKSUM
       BYTE 6              *  We read 6 chars
* Add symbol and its address - stopped in field - to the
*  routine entry table. It is put at the end of the table
*  (the end of the table is towards the low end of memory)
*  Since the table is searched from the end first, if there
*  are any duplicate labels the last one entered will have
*  precedence over the early one(s).
       DDECT @FREEND          Set to address field
* Load address (stored in field in CPU RAM) into routine
*  Name table which is in expansion RAM
       DST  FIELD,@VARB       Source
       DST  @FREEND,@PAD      Destination
       DST  2,@ARG            # bytes to move
       XML  MVUP              CPUR RAM to ERAM
* Load symbol into routine name table
       DSUB 6,@FREEND         Set to symbol field
       DST  INDEX,@VARB        Source
       DST  @FREEND,@PAD       Destination
       DST  6,@ARG             Move 6 bytes
       XML  MVUP              CPU RAM to ERAM
* Check to see if we've run into assembly language code
       DCHE @FREEND,@FRESTA   Out of memory
       BS   ERRMF1
       B    LDTG              If not then continue
***********************************************************
* ROUTINE NAME TABLE ENTRY
*
*                     0   1   2   3   4   5   6  7
*                   -----------------------------------
*        FREEND     | S | Y | M | B | O | L | ADDRESS |
*    (AFTER ENTRY)  -----------------------------------
*        FREEND     |   |   |   |   |   |   |         |
*    (BEFORE ENTRY) -----------------------------------
*
*  FREEND is initialized to >4000 by INIT, address is at
*   a higher memory location then symbol
***********************************************************
TAG7   DNEG @FIELD            Checksum is 1's compelement
       DCEQ @FIELD,@CHKSUM    Check sum error
       BR   ERRDE1
       B    LDTG
TAGA   DADD @OFFADD,@FIELD    PC = OFFADD ^ FIELD
* TAG 9 is an absolute address so no need to add offset
TAG9   DST  @FIELD,@PC
       B    LDTG
TAGC   DADD @OFFADD,@FIELD
* TAG B is an absolute entry so no need to add offset
* Relocatable code is checked to see if it will run into
*  is no need to check now. Absolute code can go anywhere.
*
* Load field into expansion RAM using MVUP routine
TAGB   DST  @PC,@PAD           Destination
       DST  FIELD,@VARB        Source
       DST  2,@ARG             Move 2 bytes
       XML  MVUP              CPU RAM to ERAM
       DINCT @PC              We loaded 2 bytes
       B    LDTG
********* END OF LOAD FOR CURRENT FILE ********************
*
* FRESTA & FREEND are stored in CPU RAM (>8308)
* While loading a file into expansion RAM.
* So if the values of FRESTA or FREEND are to be changed
* then word locations >8308 and >830A must be changed and
* not expansion RAM.
*
* LDDNE - LDNE2
*
*   DONE WITH LOAD
* Put FRESTA, FREEND back into expansion RAM
* If FRESTA is odd then make it even
*  so that the next program starts on an even boundry
LDDNE  CLOG 1,@FRESTA+1       Low byte odd?
       BS   GC1C1
       DINC @FRESTA           Force to next even boundry
GC1C1  DST  FRESTA,@VARB         Source
       DST  FSLOC,@PAD           Destination
       DST  4,@ARG               Load 4 bytes
       XML  MVUP              CPU RAM to ERAM
       CALL CLSIT             Close file
* Check for end of load command ")"
LDNE2  CEQ  RPARZ,@CHAT       Check for ")"
       BS   LDRET
       CEQ  COMMAZ,@CHAT      Syntax error
       BR   ERRSY1
       XML  PGMCHR            Skip comma
       B    LDP1              Continue in main loop
*************** LDRET - LDRET2 ****************************
*
* Return to calling routine
LDRET  XML  PGMCHR            Skip over
* Entry point for INIT
LDRET2 CALL CHKEND            Check for end of statement
       BR   ERRSY1            If not end then syntax error
       CALL RETURN            Return to caller
********************** CHKIN ******************************
* Check for INIT-FLAG = >AA55
* MOVE ERAM(INITF) to CPU *FAC
PAGE   EQU  $
CHKIN  DCEQ >AA55,@INITF  *** RXB REPLACEMENT ROUTINE ****
       BR   ERRSYN          * SYNTAX ERROR
* No files have been opened so if there is a syntax error
*  goto ERRSYN!
        RTN                 * RETURN TO CALLING ROUTINE
*********************** FILE ROUTINES *********************
***********************************************************
* INCREMENT BUFFER POINTER by value after call statement
* ADD VALUES READ TO CHECKSUM unless the first character
* is a "7" = >37 , then add only "7" character to checksum
* (other value is the checksum)
*
*************************** LDIPCS ************************
LDIPCS FETCH @INDEXC          Index = # of bytes read
       CEQ  >37,V*BUFPNT
       BR   GC213
       DADD >0037,@CHKSUM     Add value of "7" to checksum
       DADD 5,@BUFPNT         1 for "7", 4 for checksum
       B    GC224
GC213  ST   V*BUFPNT,@FAC1    Convert to 2 byte value
       CLR  @FAC              -----------------------------
       DADD @FAC,@CHKSUM      Add char to checksum
       DINC @BUFPNT
       DEC  @INDEXC           Do it index # of times
       CZ   @INDEXC
       BR   GC213
GC224  RTN
********************** OPENIT *****************************
OPENIT DST  @FAC6,@BYTES      Store actual spec length
       DADD PABLEN+80,@BYTES  Add in the PAB length and
*                              buffer length
       XML  VPUSH             Push possible temp string
       XML  GETSTR             and try to allocate space
       XML  VPOP              Restore original string data
*
* THE FOLLOWING VARIABLES CONTAIN IMPORTANT INFO
*
*   FAC4, FAC5    Start address of original device specific
*   FAC6, FAC7    Length of original device specifications
*   SREF          Location of PAB in VDP memory
*   BYTES         Length of entire PAB including specificat
       MOVE @FAC6,V*FAC4,V@PABLEN(@SREF) * Device pathname
       CLR  V*SREF               Clear the entire PAB
       MOVE PABLEN-1,V*SREF,V@1(@SREF)   * Clear PAB
       ST   @FAC7,V@NLEN(@SREF)  Copy specifications length
       ST   >60,V@SCR(@SREF)     Screen offset
       ST   4,V@FLG(@SREF)       Dis, fix, seq, input
       DADD @SREF,@FAC6          Calculate the address of
       DADD PABLEN,@FAC6          the buffer
       DST  @FAC6,V@BUF(@SREF) Store buffer address in PAB
       CALL DSRCAL
       RTN
***********************************************************
READIT DST  V@BUF(@SREF),@BUFPNT   INIT buffer pointer
       ST   2,V*SREF
       ST   V@LEN(@SREF),V@CHRCNT(@SREF)
       CALL DSRCAL
       RTN
************************* CLSIT ***************************
CLSIT  ST   1,V*SREF          Prepare to close
******************** DSRCAL - DSKERR **********************
DSRCAL DST  @SREF,@FAC12      Compute start address of spec
       DADD NLEN,@FAC12       Ready to call DSR routine
       CALL LINK              Call DSR thourgh program link
       BYTE 8               * Type = DSR (8)
       BS   DSKERR            Couldn't find the DSR
       CLOG >E0,V@FLG(@SREF)  Set condition bit if no error
       BR   DSKERR
       RTN
DSKERR DST  @FREPTR,@PABPTR   Set up dummy PAB
       DSUB 6,@PABPTR         Make it standard size
       DST  V*SREF,V@4(@PABPTR) Store error code
       CALL CLSNOE              Close File
       CALL ERRZZ               Issue I/O error
       BYTE 36              *
********************** CLSNOE *****************************
* Try to close the current file
* Ignore any errors from the closing of the file.
* Since the PAB is not in the normal PAB list
*  then we have to close the file in the load routine.
* ERRZZ will close the rest of the files.
*
** CLOSE IT ONLY IF IT HAS BEEN OPENED
CLSNOE DCEQ 1,@CHKSUM         Check file flag
       BS   GC2B9
       ST   1,V*SREF          Store close file code
       DST  @SREF,@FAC12      Compute start address of spec
       DADD NLEN,@FAC12       Ready to CALL DSR
       CALL LINK              CALL DSR through program link
       BYTE 8               * "8" is type of DSR
GC2B9  RTN
***********************************************************
* INIT                        JDH   9/02/80
***********************************************************
* CALL INIT                                               *
***********************************************************
* Check if expansion RAM present
* Load support into expansion RAM from GROM
INIT   CZ   @RAMTOP           If no ERAM, SYNTAX ERROR
       BS   ERRSYN
** Load Assembly header, support routines **
* GKXB Correct INIT routine.
       CLR  @>6004           * Set ROM PAGE 3 at >6004
       XML  CINIT            * Move from ROM 3 to RAM
       B    ECRTN            * RXB custom return routine
***********************************************************

You will notice there is nowhere that decimal integer is allowed.

If you look at XB token code of CALL LOAD(-2,3) in Classic99 debugger at >FFD0 is:

10 CALL LOAD(-2,3)

 

00 00 0A FF D6 12 9D C8 04 4C 4F 41 44 B7 C2 C8 01 32 B3 C8 01 33 B6 00 

                                        l   L  O  A  D    (   -   n    l   2   ,    n   l   3    )  e

                                        e                             u    e            u  e            n

                                        n                             m   n            m n            d

                                        g                              e   g             e g            

                                        t                               r   t              r  t     

                                        h                              i   h              i  h

                                                                       c                   c

 

This is the code that XML PARSE fetches from XB and as you can see it does what I have said all along.

00 0A is 0010 the line number.

04 and 01 and 01 are length of LOAD or number of digits of any number in character format.

B7 is token for ( character

C2 is minus sign in token character   

C8 is token for a number to follow in character token format.

32 is token for 2 character 

B3 is token for  comma character  

33 is token for 3  character   

B6 is token for ) character   

 

Thus this is the XB token format of XB programs for this line 10 CALL LOAD(-2,3) and this kind of maintains the original source.

I guess you could say the 2 and 3 are integers but as they are converted to token format so humans can see the source 

there is a reason to maintain the original source as typed in, but that is not how XB works.

 

It seems the confusion you guys have is you do not understand the token format and why it exists in first place for the Interpeter.

 

 

 

 

                                                          

 

Link to comment
Share on other sites

2 hours ago, RXB said:

Thus this is the XB token format of XB programs for this line 10 CALL LOAD(-2,3) and this kind of maintains the original source.

I guess you could say the 2 and 3 are integers but as they are converted to token format so humans can see the source 

there is a reason to maintain the original source as typed in, but that is not how XB works.

 

It seems the confusion you guys have is you do not understand the token format and why it exists in first place for the Interpeter.                                    

I think it would be safe to say that someone who could write a compiler for Extended BASIC would have a good working knowledge of how the XB lines are tokenized, and why.

 

It sure sounds like you do not believe that after CALL LOAD(-2,3), the value 3, or >03, or 00000011 is stored at memory location >FFFE. Hard to believe you might think that, but you are entitled to your (erroneous) opinion.

 

I feel like one of those unfortunate animals trapped in the La Brea tar pit. You struggle valiantly, but as you become mired deeper and deeper in the tar, you finally get worn down and at the end you finally accept there is nothing more you can do, and realizing that, you close your eyes and await.....oblivion.

 

Edited by senior_falcon
  • Like 3
Link to comment
Share on other sites

35 minutes ago, senior_falcon said:

I feel like one of those unfortunate animals trapped in the La Brea tar pit. You struggle valiantly, but as you become mired deeper and deeper in the tar, you finally get worn down and at the end you finally accept there is nothing more you can do, and realizing that, you close your eyes and await.....oblivion.

If you have any lives left, don't go near the tar pit again.

  • Haha 5
Link to comment
Share on other sites

@retrodroid I was reading an interview from the early 80's with John C Plaster, the author of Tombstone City , the educational cartridges and Chisholm Trail.  
It's well known that Tombstone City / Saguaro City was one of the games that was created using an actual TI99 rather than the 990 minicomputer and emulation.  During the interview he stated that he had most of the game running by May '81.  That tells us that the poor guy was using the 99/4 and not the 99/4A ... so he's done well there, written it all out in Assembly and used the calculator keyboard of the 99/4 to type on!  He said that learning the 9900 assembly wasn't difficult, but then again he was a master at mathematics.  He must have been loading the Editor Assembler from cartridge and storing his code on disks, and most likely drawing out his graphics on graph paper with pencils and a rubber. 

Then when we read about how Parsec was developed that's fascinating also - they did use a kind of prehistoric "magellan" in ways ... to do the graphics for the tumbling asteroids they used TI Logo and had it churn out the Hex codes for the patterns onto a disk.  I'd LOVE to have the same abilities with Assembly as the guys who made the original games.  

  • Like 3
Link to comment
Share on other sites

1 hour ago, senior_falcon said:

I think it would be safe to say that someone who could write a compiler for Extended BASIC would have a good working knowledge of how the XB lines are tokenized, and why.

It sure sounds like you do not believe that after CALL LOAD(-2,3), the value 3, or >03, or 00000011 is stored at memory location >FFFE. Hard to believe you might think that, but you are entitled to your (erroneous) opinion.

I feel like one of those unfortunate animals trapped in the La Brea tar pit. You struggle valiantly, but as you become mired deeper and deeper in the tar, you finally get worn down and at the end you finally accept there is nothing more you can do, and realizing that, you close your eyes and await.....oblivion.

 

 

As they are single byte values only, that does not change anything on how I said they got there from the XML PARSE as this routine is XB ROM  

Now I can say you are right about values at >FFFE with 3 being there but that is due to XML CFI is in ROM 0 not anywhere in XB ROM or GPL.

The exact place is at >0682 in ROM 0 that line that says: MOVB 11,*R2+ this is called from XML CFI which is a ROM 0 routine at >12B8

This line puts 3 at >FFFE or if you add in more values into CALL LOAD(-2,3,4,5) would put 3 at >FFFE, 4 at >FFFD, and 5 at >FFFE 

I stand corrected and I am mistaken as to why they are there, but everything else I said is true after all none of this is XB at all is it?

The routine uses an EQU to call CFI in ROM 0, again not in any GPL or XB ROM.

You are right about >FFFE being byte values I stand  corrected on that.

 

P.S. I have no clue why it would put these values there as they have no location in symbol tables so how would you find or use them?

      If you add line 5 X=3 and 10 CALL LOAD(-2,X) you will find at >FFC0 the floating-point number >40 03 00 00 00 00 00 00 and the

      X is in the symbol table pointing to it. Honestly it looks like those bytes at >FFFE are totally useless to XB as a side effect of ROM 0

Link to comment
Share on other sites

7 minutes ago, Retrospect said:

At least this argument you're both having is an educational one.  Some people will learn from this.  Not me though I'm clueless as usual.  :)

Yes you are very correct, I did learn something from this and took all day doing research on it.

And no you are a really smart guy as far as I can tell.

  • Thanks 1
Link to comment
Share on other sites

7 minutes ago, RXB said:

Yes you are very correct, I did learn something from this and took all day doing research on it.

And no you are a really smart guy as far as I can tell.

Thanks.  I do okay in the my own field.  I can't say I'm smart though.  Just winging it.  You guys are the real intelligent ones.  Yourself, Falcon, and others.  I just create fantastic arcade games ;)

  • Like 2
Link to comment
Share on other sites

I have newbie questions regarding the best way to debug my AL code.

 

Currently, when something doesn't immediately work the way I intended (2/3 of the time it seems), I fire up the Classic99 Debugger, and usually I'll use a technique like moving a known value or values into R14 at the locations where I want to set a breakpoint. So say step 1, LI R14,>AAAA  a little further down, LI R14, >BBBB.  Then I set a breakpoint with R14 for either of those values, examine the other CPU registers at that point, and try to glean why they don't contain the nice neat values I am expecting. With this technique I can also resume execution for another cycle, etc. to see how things unfold a bit.  It basically works, but is it time-consuming and very simplistic.

 

What I would *like* to be able to do, is follow the source AL  files as it executes, have all the referenced memory locations in the current source line shown so I can see the memory contents of everything being read or written, beyond the registers, without having to figure out what the resolved memory addresses are for each thing myself.  Is there a debugger out there that can do that?

 

Barring that, what are the best practices for debugging AL that you all use?  Are there any tutorials or other reference material available?

 

Edited by retrodroid
  • Like 1
Link to comment
Share on other sites

54 minutes ago, retrodroid said:

I have newbie questions regarding the best way to debug my AL code.

 

Currently, when something doesn't immediately work the way I intended (2/3 of the time it seems), I fire up the Classic99 Debugger, and usually I'll use a technique like moving a known value or values into R14 at the locations where I want to set a breakpoint. So say step 1, LI R14,>AAAA  a little further down, LI R14, >BBBB.  Then I set a breakpoint with R14 for either of those values, examine the other CPU registers at that point, and try to glean why they don't contain the nice neat values I am expecting. With this technique I can also resume execution for another cycle, etc. to see how things unfold a bit.  It basically works, but is it time-consuming and very simplistic.

 

What I would *like* to be able to do, is follow the source AL  files as it executes, have all the referenced memory locations in the current source line shown so I can see the memory contents of everything being read or written, beyond the registers, without having to figure out what the resolved memory addresses are for each thing myself.  Is there a debugger out there that can do that?

 

Barring that, what are the best practices for debugging AL that you all use?  Are there any tutorials or other reference material available?

 

With those nice break points installed switch classic99 to the Disasm view .

After each break point just press F2 to single step the code one instruction at a time.

Press F1 to run to the next break-point

It's awesome.

image.thumb.png.f2fc89457006c5be693986702ad4db29.png

 

 

 

  • Like 2
  • Thanks 2
Link to comment
Share on other sites

1 hour ago, TheBF said:

With those nice break points installed switch classic99 to the Disasm view .

After each break point just press F2 to single step the code one instruction at a time.

Press F1 to run to the next break-point

It's awesome.

What he said. One thing TheBF omitted is that you can press F3 when you are at a subroutine like BLWP @VMBW or BL @MYSUB.  This will do the subroutine and come back to the next line of your code.

 

Finding the break points. Let's say you want to set a break point at 3 places in your code: LOOP1, LOOP2, and SETREG

Find an unused part of memory. Let's say you know >B000 is safe.

AORG >B000

DATA LOOP1

DATA LOOP2

DATA SETREG

RORG      In my first post I forgot this.

Now when you load the assembly code you can use the debugger to look at >B000 and there you will find the addresses for LOOP1, LOOP2, and SETREG

If LOOP1 is >3456 you can set a breakpoint to it with *3456 which breaks whenever activity happens there.  <3456 breaks when that address is read from, so that is probably even better, but I got in the habit of doing it the other way.

Edited by senior_falcon
  • Like 3
  • Thanks 1
Link to comment
Share on other sites

10 hours ago, RXB said:

I stand corrected and I am mistaken as to why they are there, but everything else I said is true after all none of this is XB at all is it?

 

P.S. I have no clue why it would put these values there as they have no location in symbol tables so how would you find or use them?

      If you add line 5 X=3 and 10 CALL LOAD(-2,X) you will find at >FFC0 the floating-point number >40 03 00 00 00 00 00 00 and the

      X is in the symbol table pointing to it. Honestly it looks like those bytes at >FFFE are totally useless to XB as a side effect of ROM 0

It doesn't matter if it's Extended BASIC or something else. It just has to make an integer of the address and data, and out of the data it uses only eight bits at a time, or it would not work.

It also doesn't matter if Extended BASIC calls CFI in the console's ROM or does it by itself. It still happens on Extended BASIC's behalf.

The CALL LOAD(-2,3) is just an example. You can pick any address. The principle is the same. But to find it again you can use CALL PEEK, of course.

  • Like 1
Link to comment
Share on other sites

9 hours ago, retrodroid said:

Barring that, what are the best practices for debugging AL that you all use?

Now I haven't done much of that in recent years. But the emulators are of course fantastic, compared to what we had when it was the machine itself only. It's more like what they had at TI when they used their TI 990 computers for development.

Back in the days I had two favorite tools for debugging.

  1. The Hewlett-Packard HP 16C. Since it's a calculator that can handle binary math and also is programmable, you could enter your algorithms as a program on it and test them. You can set the word size to 16 bits and use the registers to emulate the TMS 9900 on it. It even has double multiply and divide, which works just like MPY and DIV.
  2. The Explorer program from Miller's graphics. It allows you to test at least sections of your programs in an emulated way, where you can see everything happening on the screen.

Now I mainly wrote assembly programs for use with the p-system. There the best way was to write the program in Pascal first, then convert that to assembly, once I was convinced there was nothing wrong with the structure of the program itself. That worked as long as I could do what I needed to do from Pascal.

  • Like 2
Link to comment
Share on other sites

13 hours ago, TheBF said:

With those nice break points installed switch classic99 to the Disasm view .

After each break point just press F2 to single step the code one instruction at a time.

Press F1 to run to the next break-point

It's awesome.

image.thumb.png.f2fc89457006c5be693986702ad4db29.png

 

 

 

Wow - not sure how I missed that!  I'm always just trying to get my "thing" working and not spending enough time exploring a bit more. On that note, what are the "Bug99 Window" and "Heatmap" options in Classic99 for?  I've tried them but neither shows anything.

 

12 hours ago, senior_falcon said:

What he said. One thing TheBF omitted is that you can press F3 when you are at a subroutine like BLWP @VMBW or BL @MYSUB.  This will do the subroutine and come back to the next line of your code.

 

Finding the break points. Let's say you want to set a break point at 3 places in your code: LOOP1, LOOP2, and SETREG

Find an unused part of memory. Let's say you know >B000 is safe.

AORG >B000

DATA LOOP1

DATA LOOP2

DATA SETREG

RORG      In my first post I forgot this.

Now when you load the assembly code you can use the debugger to look at >B000 and there you will find the addresses for LOOP1, LOOP2, and SETREG

If LOOP1 is >3456 you can set a breakpoint to it with *3456 which breaks whenever activity happens there.  <3456 breaks when that address is read from, so that is probably even better, but I got in the habit of doing it the other way.

Nice!  Will certainly keep this in my back pocket.  

Link to comment
Share on other sites

51 minutes ago, retrodroid said:

Wow - not sure how I missed that!  I'm always just trying to get my "thing" working and not spending enough time exploring a bit more. On that note, what are the "Bug99 Window" and "Heatmap" options in Classic99 for?  I've tried them but neither shows anything.

 

Bug99 is Thierry Nouspikel’s debugger.

 

The Bugg99 window and Heatmap are discussed in the Classic99 manual, which is available through this option:

 

image.thumb.png.4b844c1b3271618c0a3e1262e50d5bf9.png

...lee

  • Like 1
Link to comment
Share on other sites

3 hours ago, Lee Stewart said:

 

Bug99 is Thierry Nouspikel’s debugger.

 

The Bugg99 window and Heatmap are discussed in the Classic99 manual, which is available through this option:

 

image.thumb.png.4b844c1b3271618c0a3e1262e50d5bf9.png

...lee

 

3 hours ago, senior_falcon said:

Ah yes, the dreaded words we all hate to hear. RTFM.

Indeed!  Actually, I did try that but I'm running a one-off build of Classic99_64.exe on Wine, on an M2 mac, so it didn't work. 

...so then I dug through the wine "C" drive and found a copy of it there.  Interestingly, Memory Map doesn't render at all with my config.
 

I will review the Debug section - no doubt a wise time investment.

 

Link to comment
Share on other sites

On 2/22/2023 at 1:29 AM, retrodroid said:

I have newbie questions regarding the best way to debug my AL code.

 

Currently, when something doesn't immediately work the way I intended (2/3 of the time it seems), I fire up the Classic99 Debugger, and usually I'll use a technique like moving a known value or values into R14 at the locations where I want to set a breakpoint. So say step 1, LI R14,>AAAA  a little further down, LI R14, >BBBB.  Then I set a breakpoint with R14 for either of those values, examine the other CPU registers at that point, and try to glean why they don't contain the nice neat values I am expecting. With this technique I can also resume execution for another cycle, etc. to see how things unfold a bit.  It basically works, but is it time-consuming and very simplistic.

 

What I would *like* to be able to do, is follow the source AL  files as it executes, have all the referenced memory locations in the current source line shown so I can see the memory contents of everything being read or written, beyond the registers, without having to figure out what the resolved memory addresses are for each thing myself.  Is there a debugger out there that can do that?

 

Barring that, what are the best practices for debugging AL that you all use?  Are there any tutorials or other reference material available?

 

The js99er debugger is not on par with the debugger in classic99, but it does offer the possibility to load a listing file generated by xas99.

With that you basically can follow the source AL file. 

 

Oh and with classic99 you can include some dummy opcodes as data statements that allow you to log the values of memory locations to the debugger log.

That comes in very handy as well. Used that a couple of times while working on stevie, my programming editor.

  • Like 4
Link to comment
Share on other sites

Folks, I'm really pleased with my progress thus far. I have all of my player-movement types and animations implemented and tuned and it plays like a dream. I also have a basic screen-navigation scheme working so I can run and jump and climb and fall my way through a small initial map of different screens. There have been many difficult days where the simplest code just wouldn't do what it was "supposed" to, but I've worked through them (with some of your help) and am at a point where my basic game loop is working really well. I'm also finding that small tweaks are amazingly simple to implement now, with everything being managed at a per-frame level (actually, intra-frame because of my approach to implementing velocity).  I've even gone back and optimized certain routines that were a bit sloppy with the CPU and realized significant gains. It's been a very rewarding experience.  :)

 

I'm now ready to refactor my code to run off a cart (been using E/A option #3 to load and run until now), and the "reality cheque" is arriving in terms of my memory requirements and some sloppy code I've used that now wants to be able to write to ROM.  lol.

 

So a few questions on the best way to organize things on a cart. Keep in mind my goal is to run off a multi-bank cart on a stock 16K console.

 

From a quick and dirty analysis, my storage requirements appear to be approx:

  • Compiled code:  5K (will increase)
  • Char patterns / sprites:  5K (will increase)
  • Maps:  9K now, going to ???

As I understand it, I can use as many 8K banks of ROM as required for my cartridge, and dynamically switch between them each time I need to access something from one or the other. EDIT>> I just noticed this:

Quote

- cartridges that can be plugged directly into the console can provide upto 40K of GROM and upto 16K of ROM,

Is that a real restriction nowadays?

 

My question is, how many banks can I have accessible at one time? I am assuming 2?  So one for executing code, and another for whatever resources you are needing to load (char patterns, or maps, in my case)?

 

Would it make sense to have one bank for code, one for char / sprite patterns, and multiple for maps as required?  This would require dynamically swapping the 2nd char pattern / map banks, but possibly only when the player travels to a new map screen (so not every frame).

 

Is there a performance penalty for switching banks? Does this mean I should really try to keep my main loop code under 8K so it fits on a single bank?

 

Any resources on this stuff somewhere I can review?  Thanks in advance!

 

 

 

 

Edited by retrodroid
  • Like 1
Link to comment
Share on other sites

27 minutes ago, retrodroid said:

My question is, how many banks can I have accessible at one time? I am assuming 2?  So one for executing code, and another for whatever resources you are needing to load (char patterns, or maps, in my case)?

Unfortunately only one 8K bank in the >6000->7FFF region at a time. So it's much easier if you run the code from 32K RAM. If you don't want 32K as a requirement you could perhaps load graphics from GROM? Otherwise you need to have banks with both code and graphics.

29 minutes ago, retrodroid said:

Would it make sense to have one bank for code, one for char / sprite patterns, and multiple for maps as required?  This would require dynamically swapping the 2nd char pattern / map banks, but possibly only when the player travels to a new map screen (so not every frame).

Sure.

30 minutes ago, retrodroid said:

Is there a performance penalty for switching banks? Does this mean I should really try to keep my main loop code under 8K so it fits on a single bank?

It doesn't take longer than the instruction to switch the bank.

  • Like 1
Link to comment
Share on other sites

20 minutes ago, Asmusr said:

Unfortunately only one 8K bank in the >6000->7FFF region at a time. So it's much easier if you run the code from 32K RAM. If you don't want 32K as a requirement you could perhaps load graphics from GROM? Otherwise you need to have banks with both code and graphics.

Sure.

It doesn't take longer than the instruction to switch the bank.

Well that does complicate things.  I have a burning desire to not require 32KB expansion, probably some latent negative feelings towards it from when I was a kid and didn't have it then. ;)

I have nothing against GROM, however, just not sure how to configure my code to use it. The char patterns and map data could all live happily in GROMs. I'm fairly confident my game code can fit in a single 8K ROM.

 

Suggestions on where to find a tutorial or reference for configuring GROMs?   I'm using Classic99 for development, btw.

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