Tuesday, November 22, 2011

TUTORIAL #2 – MAIN PROGRAM



I will be going through the Main Program subroutine line-by-line and explaining what each line of code is doing and how it affects the outcome of the program.



38     *********************************************



This is just a comment line breaker and helps to space out each subroutine or section of code.



39     *****                   MAIN PROGRAM          *************



This is the main comment line telling the reader where the starting section of code begins for the main program.  Remember; an * is what represents a comment field.



40     BEGIN                 JSR    PGM



Lines 40 thru 82 consist of the main subroutine, and the header name of this subroutine is called BEGIN.  For the program to jump to specific subroutines within the program it needs to see the header name.  Line 40 is where the program starts and goes from line to line in a top-down fashion telling the program to “[J]ump to [S]ub[R]outine” with the header PGM.  Once the subroutine PGM finishes it will return back to this line and continue down the rest of the program.  Subroutine PGM is where the screen is blanked out and cleared of text and graphics.  PGM will be explained in more detail later in the blog.



41                                  JSR    INITIAL



After subroutine PGM completes and returns, line 41 tells the program to “[J]ump to [S]ub[R]outine” to the subroutine with the header INITIAL.   Subroutine INITIAL is where all starting variables for the map, character, and tiles graphics are initialized to a value of [0] or predetermined values.  INITIAL will be explained in more detail later in the blog.



42     START8               JSR    PREMAP



After subroutine INITIAL completes and returns, line 42 tells the program to “[J]ump to [S]ub[R]outine” to the subroutine with the header PREMAP.   Line 42 also has a header name so it can also be referenced and can be called to run just line BEGIN was.  When the game starts and your character is placed on the world map this region is defined ahead of time by a ROW and COLUMN value.  Subroutine PREMAP helps define where the ULTIMA 1 world map will start from based on the row number it see, which is predefined in the INITIAL subroutine when the program starts.  The world map is made up of 84 ROWS from top to bottom.  This row number is used in PREMAP to search through the map address for certain values to obtain the starting map corner location.  Subroutine PREMAP will be explained in more detail later in the blog.  START8 is a subroutine within BEGIN that is used when after the main program starts and all variables have been initialized for the first time, once the ULTIMA map needs to be redrawn again you can’t have the program call BEGIN or it would reset everything, so START8 let you redraw the map but with updated character movements and current variable.



43                                  JSR    PREPROW



After subroutine PREMAP completes and returns, line 43 tells the program to “[J]ump to [S]ub[R]outine” to the subroutine with the header PREPROW.   Since we know the world map is 84 rows deep, it is also made up of numerous columns. Also, because memory usage is critical on the APPLE computer I had to figure out a way to compress the map data that would be read to figure out the number of columns and tiles which make up the entire world map width.  PREPMAP is used to obtain the specific number of data strings which are represented in each separate map row.  Subroutine PREPROW will be explained in more detail later in the blog.



44                                  JSR    FRNTBYT



After subroutine PREMAP completes and returns, line 44 tells the program to “[J]ump to [S]ub[R]outine” to the subroutine with the header FRNTBYT.   FRNTBYT is used to help uncompress the map data so it can read a HIGH byte and a LOW byte to figure out the number and type of tile which is used in the given ROW of the world map.  Subroutine FRNTBYT will be explained in more detail later in the blog.



45                                  JSR    TILEPLC



After subroutine FNRTBYT completes and returns, line 45 tells the program to “[J]ump to [S]ub[R]outine” to the subroutine with the header TILEPLC.   Earlier in my BLOG I explained how since I was trying to save memory by compressing the map data, I had to come up with a way to compress the way the number of tiles and type of tiles that were being used on each row of the world map.  This compression process uses a number of subroutines to help uncompress the map data and put the number of tile and type of tiles in temporary storage memory regions.  The subroutine TILEPLC uses the HIGH and LOW byte values found in FRNTBYT and breaks it down so it counts out each tile type on the world map row and stores it in an array variable.  This array stores each map tile from the starting row and column up to the next 20 tiles because the screen only represents 20 graphic tiles at a time.  Subroutine TILEPLC will be explained in more detail later in the blog.



46                                  LDA   #$00



After subroutine TILEPLC completes and returns, line 46 is used to “[L]oa[D] the [A]ccumulator” or register A with the HEX value of zero!  So you could think of it as [A] holding the value of [0].



On the Apple 6502, there are six instructions that load and store the registers. 

These are:

            LDA  v              Load the A register with v

            LDX  v              Load the X register with v

            LDY  v              Load the Y register with v

            STA  v              Store the A register with v

            STX  v               Store the Y register with v

            STY  v               Store the Y register with v



Here LD stands for “LOAD”; ST stands for “STORE”; and v can be and cell in the main memory.



47                                  INC   ROWNO



Line 47 is used to “[INC]rement” whatever value is in ROWNO by 1!  This is to get ready to help draw the next row of graphics tile on the screen.



There are six instructions on the 6502 which increment and decrement: 



            INC   v              increment v

            DEC  v              decrement v

            INX                   Increment the X register

            DEX                  Decrement the X register

            INY                   Increment the Y register

            DEY                  Decrement the Y register



Here v can be any cell in the main memory, as before.  Note that we cannot increment or decrement, the A register!!!



48                                  JSR    LOADMAP



Line 48 tells the program to “[J]ump to the [S]ub[R]outine” with the header LOADMAP.   This subroutine take the [20] row tiles that will be displayed on the screen and stores them into a MAPSTORE array, to be used after all 200 tiles have been stored and are ready for the screen. Subroutine LOADMAP will be explained in more detail later in the blog.



49                                  INC   CHKER1



Line 49 is used to “[INC]rement” whatever value is in CHKER1 by 1!  This variable is part of an incremental counter within the LOADMAP subroutine to check when all ten screen line of tiles have been stored in the MAPSTORE array.



50                                  LDA   CHKER1



Line 50 is used to “[L]oa[D] the [A]ccumulator” or register A with the value from CHKER1 after it has been incremented in line 49. 



51                                  CMP  #$0A



Once the value of CHKER1 is loaded into register A, Line 51 is used to “[C]o[MP]are” what is in register A to the HEX value of $0A or 10.  The value of 10 is the number of horizontal line on the screen that will hold graphic tiles.



52                                  BLT   START8



Line 52 is used to “[B]ranch on [L]ess [T]han”, which means that as long as the value in register A is less than [<] 10 it will continue to call the subroutine with the header START8.  Once the value of A is greater than [>] 10 it will bypass line 52 and continue to line 53.



53                                  LDA   #$00



Line 53 is used to “[L]oa[D] the [A]ccumulator” with the HEX value of zero!  So you could think of it as [A] holding the value of [0].



54                                  STA   CHKER1



Line 54 is used to “[ST]ore the [A]ccumulator” which has the value of zero into the variable CHKER1.  So the variable CHKER1 will equal zero after line 54 completes.



55                                  JSR    CHARTILE



Line 55 tells the program to “[J]ump to the [S]ub[R]outine” with the header CHARTILE.   This subroutine is used to load the type of character graphic tile that will be displayed on the screen, such as the fighter, the horse, the cart, etc…  Subroutine CHARTILE will be explained in more detail later in the blog.



56                                  LDX   #$00



Line 56 is used to “[L]oa[D] the [X] register” with the HEX value of zero!  So you could think of it as [x] holding the value of [0].



57                                  STX   MAPCOUNT



Line 57 is used to “[ST]ore the [X] register” which holds the HEX value of zero into the variable MAPCOUNT!  Remember that MAPCOUNT is going to be used as a step counter in another subroutine.  So you could think of it as, variable MAPCOUNT is equal to the value of [0].



58   START1                 JSR    LOADSHP



Line 58 tells the program to “[J]ump to the [S]ub[R]outine” with the header LOADSHP.   Line 58 also has a header name so it can also be referenced and can be called to run just line START8 was.  Subroutine LOADSHP takes each map address stored into MAPSTORE which represent a single graphic tile and start to recreate the tile from individual bytes and once it creates the entire shape it then draws it to the screen from top to bottom and left to right!  Subroutine LOADSHP will be explained in more detail later in the blog.  START1 is a SUB-subroutine OR “a subroutine within a subroutine” which is also within the BEGIN subroutine that is used to load each shape into a tile graphic and draw it to the screen for each of the 20 graphics tiles shown across the screen.  START1 is part of a loop that when it finishes drawing the 20 tiles it continues on to the rest of the main subroutine.



59                                  JSR    DRAW



Line 59 tells the program to “[J]ump to the [S]ub[R]outine” with the header DRAW.   This subroutine is used to DRAW the actual graphic tile to the screen.  Since each graphic tile in Ultima is made up of two bytes wide and two byte deep, the DRAW subroutine draws the two byte right next to each other one line at a time until it draws the entire column of 10 tiles or 160 graphic lines down the screen.  Subroutine DRAW will be explained in more detail later in the blog.



60                                  INC   LINEA



Line 60 is used to “[INC]rement” whatever value is in LINEA by 1!  This variable LINEA is part of an incremental counter within the START1 SUB-subroutine of the subroutine BEGIN that counts up to 20 to check for each ROW of graphic tiles on the screen as the DRAW subroutine is called.  Once LINEA reaches a certain value the counter check will be completed and the next statement will be bypassed.



61                                  LDA   LINEA



Line 61 is used to “[L]oa[D] the [A]ccumulator” with the value that is in variable LINEA!  So you could think of it as [A] holding the value of variable LINEA.



62                                  CMP  #$14



Once the value of LINEA is loaded into register A, Line 62 is used to “[C]o[MP]are” what is in register A to the HEX value of $14 or 20.  The value of 20 is the number of horizontal lines the graphics tiles, which are two bytes high, are drawn on.  Remember, a graphic tile is 2x2 bytes, so it is two bytes high and there are 10 graphic tiles that run from the top of the screen down to the bottom of the screen.



63                                  BLT   START1



Line 63 is used to “[B]ranch on [L]ess [T]han”, which means that as long as the value in register A is less than [<] 20 “in this case” it will continue to call the subroutine with the header START1.  Once the value of A is greater than [>] 20 it will bypass line 63 and continue to line 64.



64                                  RTS



Line 64 is used to “[R]e[T]urn from [S]ubroutine”, which means that everything in this subroutine has completed and will be returned back the statement line which called it.  In this case, this means since this is the Main Program Subroutine “BEGIN”, this return statement will END the program altogether.


As always, please email me any questions you might have.

ultima_revisited@yahoo.com

Joe




1 comment:

  1. Great to see this! If you ever turn this into a large article, feel free to submit it to http://codex.ultimaaiera.com

    We already have fairly detailed tech documents on several of the Ultima games, and we'd love one more!

    http://codex.ultimaaiera.com/wiki/Template:Internal

    ReplyDelete