[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Boot ROM + Prodos loader listing with comments



Sanjaya wrote:
> Is  this from a book?

Yes.  See the supplements to Beneath
Apple ProDOS.  The ProDOS boot code is
also commented in the book.  Below is
another version that I found online.

--
Paul R. Santa-Maria
Monroe, Michigan USA



******************************************************************
*                                                                *
*                       THE BOOT PROCESS                         *
*                                                                *
******************************************************************
*                                                                *
*      The following disassembly describes the boot process for  *
* a slave disk.  In order to TRULY understand this listing, you  *
* should first be familiar with the exact sequence and coding of *
* disk bytes used in track formatting.  This information can be  *
* found in chapter 3 of the book BENEATH APPLE DOS.  (The        *
* distinctions between booting a slave disk versus a master disk *
* are described in chapter 8 of the same reference.)             *
*      The boot process loads DOS into the machine as a series   *
* of discrete packages.  After each package is loaded, it is     *
* executed to load in the next section of DOS.  The last         *
* instruction of the boot process jumps into DOS's coldstart     *
* routine to build the DOS buffers, set up the page-three vector *
* table and run the "HELLO" program.                             *
*      Because DOS is loaded in stages, any protected disk can   *
* cracked by tracing the boot.  If you modify each section of    *
* the boot to stop after loading the next section, you can       *
* inspect the different stages of the boot to discover the       *
* protection scheme(s) used.  (P.S.  In order to modify BOOT0,   *
* you must first move it down to a RAM location defined by:      *
* $hs00, where h = high nibble of an address that is low enough  *
* to accomodate DOS in free memory above and, s = present slot   *
* number housing the disk controller card.)                      *
*                                                                *
******************************************************************




*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*
*                                                                *
*                        BOOT 0                                  *
*                                                                *
*----------------------------------------------------------------*
*                                                                *
* - relocatable code resident on the disk controller's ROM.      *
* - because the code is relocatable, the disk controllers card   *
*   can be used in different slots.  Execution begins at $Cs00,  *
*   where s = slot number (ex. $C600 for card in slot 6).        *
* - When BOOT0 is executed it:                                   *
*       (1) builds a table of indices which are used to convert  *
*           the disk bytes into 6/2 encoded bytes which are      *
*           needed by RWTS to translate the disk bytes into      *
*           normal memory bytes.                                 *
*       (2) recalibrates the disk arm by moving it to trk0/sec0. *
*       (3) reads BOOT1 into $800 to $8FF (from trk0/sec0).      *
*       (4) jumps to $801 to begin the execution of BOOT1.       *
*                                                                *
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*

(Cs00)
BOOT0    LDX #$20     ;Controller card's identification byte.

* Construct a read-translate table which
* we will need to convert disk bytes to
* encoded memory bytes.  (The encoded memory
* bytes later go trough further decoding to
* convert them to normal memory bytes.)
*
* We construct the table by sequentially
* incrementing (x) and testing it to see
* if it meets the folowing criteria of a
* disk byte:
*   (1) it must have at least one pair of
*       adjacent 1's in bits 0 to 6.
*   (2) it must not have more than one pair
*       of adjacent 0's in bits 0 to 6.
* (Note that we use the x-value to represent
* only the lower seven bits of a disk byte
* because all disk bytes are negative.)
*
* Each time we find an (x) that represents
* a simulated disk byte, we increment (y).
* (Y) is then placed in the read table at an
* offset of (x) from the beginning of the table.
* The table generated is shown below.  The
* empty bytes represent offsets where (x)
* did not meet the criteria of a disk byte.
* The values in parentheses represent the
* (x)-values tested.
*      36C-    00   01   --   --
*             (16) (17) (18) (19)
*      370-    02   03   --   04   05   06   --  --
*             (1A) (1B) (1C) (1D) (1E) (1F) (20) (21)
*      378-    --   --   --   --   07   08   --   --
*             (22) (23) (24) (25) (26) (27) (28) (29)
*      380-    --   09   0A   0B   0C   0D   --   --
*             (2A) (2B) (2C) (2D) (2E) (2F) (30) (31)
*      388-    0E   0F   10   11   12   13   --   14
*             (32) (22) (34) (35) (36) (37) (38) (39)
*      390-    15   16   17   18   19   1A   --   --
*             (3A) (3B) (3C) (3D) (3E) (3F) (40) (41)
*      398-    --   --   --   --   --   --   --   --
*             (42) (43) (44) (45) (46) (47) (48) (49)
*      3A0-    --   1B   --   1C   1D   1E   --   --
*             (4A) (4B) (4C) (4D) (4E) (4F) (50) (51)
*      3A8-    --   1F   --   --   20   21   --   22
*             (52) (53) (54) (55) (56) (57) (58) (59)
*      3B0-    23   24   25   26   27   28   --   --
*             (5A) (5B) (5C) (5D) (5E) (5F) (60) (61)
*      3B8-    --   --   --   29   2A   2B   --   2C
*             (62) (63) (64) (65) (66) (67) (68) (69)
*      3C0-    2D   2E   2F   30   31   32   --   --
*             (6A) (6B) (6C) (6D) (6E) (6F) (70) (71)
*      3C8-    33   34   35   36   37   38   --   39
*             (72) (73) (74) (75) (76) (77) (78) (79)
*      3D0-    3A   3B   3C   3D   3E   3F   --   --
*             (7A) (7B) (7C) (7D) (7E) (7F)


(Cs02)   LDY #0       ;Initialize the (y) index.
(Cs04)   LDX #3       ;"3" is used for controller ID.  Any number
                      ;between 0 and #$16 could be used.  Except
                      ;for ID purposes, the operand isn't even
                      ;relevant until it is #$16 (dec #22).
BUILDTBL STX BT0SCRTH ;Save potential index seed in the zero page.
(Cs06)

* Transfer (x) to (a) and test to see if it
* meets the following disk byte criteria:
*  (1) has at least one pair of adjacent 1's
*      in bits 0 to 6.
*  (2) has no more than one pair of adjacent
*      0's in bits 0 to 6.

* Test for adjacent 1's.
*
* Note:  by comparing a shifted version of
* the seed (in accumulator) with the original
* version of the seed (in BT0SCRTH, $3C) we are
* actually testing adjacent bits as shown below:
*        Shifted:  b6   b5   b4   b3   b2   b1  b0   0
*        Orignal:  b7   b6   b5   b4   b3   b2  b1  b0
*                  -----------------------------------
*        Testing: b6,7 b5,6 b4,5 b3,4 b2,3 b1,2 b0,1 -

(Cs08)   TXA
         ASL
(Cs0A)   BIT BT0SCRTH ;Conditions the z-flag of the status.
                      ;(If any bits match, z-flag=1.)
(Cs0C)   BEQ GETNEWX  ;Branch if value was illegal.
                      ;Illegal value = z-flag=1 = no match = no
                      ;adjacent 1's.

* Got at least 1 pair of adjacent 1's, so
* now prepare to test for adjacent 0's.
* (Note:  the previous "BIT" instruction
* alters the z-flag in the status but
* does not affect the accumulator.)
(Cs0E)   ORA BT0SCRTH ;Merge shifted version of seed with orig.
(Cs10)   EOR #$FF     ;Take 1's compliment of shifted version to
                      ;swap 1's for 0's and 0's for 1's.
(Cs12)   AND #%01111110 ;Throw away the hi and least significant
                      ;bits so will be testing:
                      ;    b5,6  b4,5  b3,4  b2,3 b1,2 b0,1.

* Test for pairs of adjacent 0's.
* Remember, only 1 pair of adjacent 0's is
* allowed.  Because we did a 1's compliment
* of the merged bits above, a SET BIT NOW
* DENOTES A PAIR OF ADJACENT 0's.  We can
* therefore test for a pair of adjacent 0's
* by shifting a bit into the carry:
*  - if (c) = 1 = at least one pair of adjacent 0's
*    is present.
*  - if (c) = 1 AND the remaining byte = 0 then
*    we have only one pair of adjacent 0's so
*    value is legal.
*  - if (c) = 1 AND the remaining byte < > 0, we
*    have more than one pair of adjacent 0's so
*    value is illegal.
(Cs14)
TESTCARY BCS GETNEWX  ;Always fall through on very first entry.
                      ;If branch is taken, got illegal value
                      ;because more than 1 pr of adjacent 0's.
(Cs16)   LSR          ;Shift a bit into the carry (if carry set
                      ;have at least 1 pr of adjacent 0's).
(Cs17)   BNE TESTCARY ;Take branch when remaining byte is not
                      ;zero.  Got at least 1 pr of adjacent 0's.
                      ;Go test carry to see if another pair has
                      ;already been detected.

* Index byte was legal.  We either got no
* adjacent 0's or else only one pair of
* adjacent 0's.
(Cs19)   TYA          ;Store the counter that corresponds to a
(Cs1A)   STA BTNIBL-$16,X ;legal nibble.  The first (x) value used
                      ;is #$16, last is #$7F.  The first (y) value
                      ;stored is 0, the last is #$3F.
(Cs1D)   INY
GETNEWX  INX
(Cs1F)   BPL BUILDTBL ;Keep on trying to build table until (x)
                      ;increments to #$80.

* Find out which slot the disk controller
* card resides in.
(Cs21)   JSR MONRTS   ;Jsr to an RTS to put the present address on
                      ;the stack.  The hi byte of the present addr
                      ;($Cs) tells us what slot (s) the card is
                      ;located in.

                      * An RTS instruction in monitor ROM.
                      (FF58)
                      MONRTS   RTS

(Cs24)   TSX          ;Put the value of the stack pointer in (x).
(Cs25)   LDA STACK,X  ;Get the hi byte of the controllers address
                      ;($Cs) from the stack.
(Cs28)   ASL          ;Multiply by 16 (throwing away original hi
         ASL          ;nibble) so we are left with #$s0.
         ASL
         ASL          ;(a) = slot * 16.
         STA SLT16ZPG ;Save slot*16 in a zero-page location.
(Cs2E)   TAX          ;Set (x) = slot * 16 so we can index the
                      ;base addresses associated with the drive
                      ;functions.
(Cs2F)   LDA Q7L,X    ;Set the READ mode.
         LDA Q6L,X
         LDA SELDRV1  ;Select drive 1.
(Cs38)   LDA MTRON,X  ;Spin the disk.

* Move disk arm to track 0 by doing a
* recalibration.  (That is, force the arm
* against the stop by pretending that it
* is presently at trk decimal 40.)
* (The arm is moved by sequentially turning
* a series of magnets off and on.)
(Cs3B)   LDY #80      ;Pretend arm is at trk40 (dec 80 half-trks).
MAGNTOFF LDA MAG0FF,X ;Turn the presently aligned magnet off.
(Cs40)   TYA          ;Calculate the next magnet that should be
                      ;turned on to suck the arm over.
(Cs41)   AND #%00000011 ;Only keep the lower two bits because we
                      ;only want a maximum value of 3 because
                      ;there are only 4 magnets (which are indexed
                      ;by values 0 to 3).  The sequence used in
                      ;this loop is: 3,2,1,0,3...
(Cs43)   ASL          ;Multiply by 2 so the index is directed to
                      ;an address that turns a magnet ON.  The
                      ;sequence used is:  6,4,2,0,6...0.
(Cs44)   ORA SLT16ZPG ;Merge the index with the slot * 16 value.
         TAX          ;Put the calculated index in (x).
         LDA MAG0N,X  ;Turn the appropriate magnet ON.
(Cs4A)   LDA #$56     ;Delay approximately 20 000 machine cycles
                      ;(approximately 20 milliseconds.)  (Gives 
(Cs4C)   JSR WAIT     ;arm time to align with energized magnet
                      ;and reduces overshoot or bounce.)

                      * Monitor ROM's main delay routine.
                      * Delay z number of cycles based on
                      * the formula:
                      *    z = ((5 * a^2) + (27 * a) +26) / 2
                      *    where a = value in the accumulator on entry.
                      (FCA8)
                      WAIT     SEC          ;Prepare for subtraction.
                      WAIT2    PHA          ;Save (a) on the stack.
                      WAIT3    SBC #1       ;Keep on reducing (a) until it equals 0.
                               BNE WAIT3
                               PLA
                               SBC #1       ;Reduce the original (a) down to 0 again.
                               BNE WAIT2
                      (FCB3)   RTS

(Cs4F)   DEY          ;Reduce trk # count.
(Cs50)   BPL MAGNTOFF ;Not at trk0 yet, so go move arm some more.

* Initialize the buffer pointer and trk/sec values.
* (On entry:  (x) = slot *16, (y) = #$FF & (a) = $00.)
(Cs52)   STA PT2BTBUF ;Set the low byte of the buf pointer to $00.
         STA BOOTSEC  ;Initialize for sector 0 on track 0.
         STA BOOTRK
         LDA #8       ;Set the hi byte of the buf pointer to $08
(Cs5A)   STA PT2BTBUF+1 ;(that is, direct pointer at $800).

* Prepare to start reading a prologue.
(Cs5C)
BTRDSEC  CLC          ;(c) = 0 = signal to read an addr prologue.

* Begin reading a prologue.
(Cs5D)
PRSRVFLG PHP          ;Preserve the status denoting if reading
                      ;address ((c)=0) or data ((c)=1) prologue.

* Look for an address prologue ("D5 AA 96")
* or a data prologue ("D5 AA AD").
(Cs5E)
STARTSEQ LDA Q6L,X    ;Read a disk byte.
         BPL STARTSEQ ;Wait for a full byte.
BTRYD5   EOR #$D5     ;Is it a "D5"?
         BNE STARTSEQ ;No - restart sequence.
BTRYAA   LDA Q6L,X    ;Read next byte in header.
         BPL BTRYAA   ;Wait for a full byte.
         CMP #$AA     ;Is it an "AA"?
         BNE BTRYD5   ;No - restart sequence.
         NOP          ;Delay 2 cycles.
BTRY96   LDA Q6L,X    ;Read third byte in header.
         BPL BTRY96   ;Wait for a full byte.
         CMP #$96     ;Is it a "96"?
Cs78)    BEQ RDVLTKSC ;Found an address prologue, so now go read
                      ;the vol, trk, sec values in the header.

* The first two bytes were "D5 AA".
* The 3rd byte was not "96".  Therefore,
* although we know this isn't an address
* prologue, maybe it is a data prologue.
(Cs7A)   PLP          ;Get the status back off the stack so we can
                      ;check if we were looking for an address or
                      ;data prologue.
(Cs7B)   BCC BTRDSEC  ;Branch back to try again if we were looking
                      ;for an address prologue but didn't find it.

* We were looking for a data prologue so
* now compare the 3rd byte with that of a
* data prologue.
(Cs7D)
BTRYAD   EOR #$AD     ;Is it an "AD"?
         BEQ RDBTDATA ;Yes - found data prol so now read in data.
(Cs81)   BNE BTRDSEC  ;No - go try again to find sequence 4 data.

* Read volume, track and sector values in
* the address header.
* Remember, @ of these pieces of information
* are housed in two bytes in an odd-even encoded
* format:   1rst byte:   1 b7  1 b5  1 b3  1 b1  (odd-encoded).
*            2nd byte:   1 b6  1 b4  1 b2  1 b1  (even-encoded).
* We must decode these bytes to check if we located
* the correct volume, track and sector.
(Cs83)
RDVLTKSC LDY #3       ;Set counter for 3 decoded bytes.
MOREBYTS STA BOOTEMP  ;Only relevant the last time through the
(Cs85)                ;loop at which time it contains the decoded
(Cs87)                ;track number read off the disk.
BTRDODD  LDA Q6L,X    ;Read odd-encoded byte.
         BPL BTRDODD  ;Wait for a full byte.
(Cs8C)   ROL          ;Throw away the hi bit & shift the odd bits
                      ;to their regular position.
(Cs8D)   STA BT0SCRTH ;Save realigned version of odd-encoded byte.
BTRDEVEN LDA Q6L,X    ;Read the even-encoded byte.
         BPL BTRDEVEN ;Wait for a full byte.
         AND BT0SCRTH ;Merge the two bytes.
         DEY          ;Reduce counter for # of bytes to rebuild.
         BNE MOREBYTS ;Branch if more bytes to patch back together.
         PLP          ;Throw the status on the stack away.
         CMP BOOTSEC  ;Is the sector read = sector wanted?
         BNE BTRDSEC  ;No - go back to find correct sector.
         LDA BOOTEMP  ;Get decoded trk # just read off disk.
         CMP BOOTRK   ;Is trk found = trk wanted?
         BNE BTRDSEC  ;No - go back to try again.
(CsA4)   BCS PRSRVFLG ;ALWAYS - just read addr field, so now go
                      ;         read the data prologue.

* Read the sector's data bytes.

* Read the first 86 ($56) bytes of the sector.  Use
* the disk byte as an index to the BTNIBL table ($36C-$3D5).
* Get the value from BTNIBL table & EOR it with the
* previous EOR result (except on entry, use
* #0 EOR BTNIBL-$96,Y) to produce a 2-encoded nibble.
* (On entry, (a) = 0.)
(CsA6)
BTRDATA  LDY #$56     ;Read $56 (dec #86) bytes.
KEEPCNT1 STY BT0SCRTH ;Save the counter.
RDDSK1   LDY Q6L,X    ;Read a disk data byte.
         BPL RDDSK1   ;Wait for a full byte.
(CsAF)   EOR BTNIBL-$96,Y ;Use disk byte as an index to the table
                      ;and EOR to decode to a 2-encoded nibble.
(CsB2)   LDY BT0SCRTH ;Retrieve the counter.
         DEY          ;Reduce the counter (& condition z-flag).
         STA BUF300,Y ;Store 2-encoded nibble in page 3 buffer.
(CSB8)   BNE KEEPCNT1 ;Branch if more bytes to read.

* Read the rest of the sector (256 disk bytes
* remaining).  Use disk byte as an index to BTNIBL
* table.  Get value from nibble table and EOR it
* with previous EOR result to yeild a 6-encoded
* nibble.  (On entry, (y) = 0.)
(CsBA)
KEEPCNT2 STY BT0SCRTH ;Set disk byte counter = 0.
RDDSK2   LDY Q6L,X    ;Read a disk byte.
         BPL RDDSK2   ;Wait for a full byte.
(CsC1)   EOR BTNIBL-$96,Y ;Use disk byte as an index to the nibble
                      ;table and EOR it with previous result to
                      ;produce a 6-encoded nibble.
(CsC4)   LDY BT0SCRTH ;Get index to buffer.
         STA (PT2BTBUF),Y ;Store 6-encoded nibble in buffer.
         INY          ;Kick up offset into buffer.
(CsC9)   BNE KEEPCNT2

* Read and test the data checksum.
* On entry, (a) = result of previous cummulative
* EORing.  Therefore, any non-cancelling errors are
* detected at the BNE instruction below.
(CsCB)
RDCK     LDY Q6L,X    ;Read the data checksum.
         BPL RDCK     ;Wait for a full byte.
(CsD0)   EOR BTNIBL-$96,Y ;EOR byte read with the previous
                      ;cummulative result.
TSTRERD  BNE BTRDSEC  ;Bad checksum so branch back to re-read.
(CsD3)                ;(Also branches to here if got a good read
                      ;but there are more sectors to read if the
                      ;first byte of BOOT1 is modified to allow
                      ;BOOT0 to read more than 1 sector (see
                      ;comments below).

* Convert 6-and-2 encoded buffer bytes to
* normal 8-bit memory bytes.
(CsD5)   LDY #0       ;Initialize index to target memory byte.
SETX56   LDX #$56     ;Set index to buf containing encoded bytes.
DOWNX    DEX          ;Reduce index for next buffer byte.
         BMI SETX56   ;Reset index to encoded buffer.
         LDA (PT2BTBUF),Y ;Get (a) = 6-encoded nibble.
         LSR BUF300,Y ;Put a bit from the 2-encoded buffer in (c)
         ROL          ;and then roll it into the 6-encoded nibble.
         LSR BUF300,Y ;Do the same with the next bit of the pair.
         ROL
         STA (PT2BTBUF),Y ;Store the re-constructed 8-bit byte in memory.
         INY          ;Increase the offset to the buffer.
(CsE9)   BNE DOWNX    ;Branch back if more bytes to reconstruct.

* Prepare to read in the next sector.
* NOTE:  Normaly only trk0/sec0 (which
* represents BOOT1) is read in by BOOT0.
* The number of sectors read in by BOOT0 is
* determined by the first byte of BOOT1.
* Whereas BOOT1 resides in memory on an 48K
* INITed disk at $B600 - $B6FF, we can zap a
* disk at $B600 with the # of sectors we 
* we would like BOOT0 to read in if we want
* it to read in more than 1 sector.
(CsEB)   INC PT2BTBUF+1 ;Just crossed page boundary, so kick up
                      ;the hi byte of the target address.
(CsED)   INC BOOTSEC  ;Set value for next sector wanted.
         LDA BOOTSEC  ;Get next sector wanted.
(CsF1)   CMP $800     ;Test if read enough sectors.
                      ;First byte of image of BOOT1 normally
                      ;contains #$01 which denotes only 1 sector
                      ;(sec0/trk0) should be read in by BOOT0.
(CsF4)   LDX SLT16ZPG ;(x) = slot *16.
         BCC TSTRERD  ;Branch back to read more sectors.
(CsF8)   JMP BT1EXC08 ;Jumps into BOOT1 (which was copied into
         ------------ ;page 8 from trk0/sec0) to begin execution
                      ;of BOOT1.


*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*
*                                                                *
*                        BOOT 1                                  *
*                                                                *
*----------------------------------------------------------------*
*                                                                *
* - stored on trk0/sec0.                                         *
* - IMAGE in memory on a 48K system resides at $B600 - $B6FF.    *
* - read into $800 to $8FF by the disk controller ROM (BOOT0).   *
* - execution begins at $801 & uses the controller's read sector *
*   subroutine (BTRDSEC, Cs00, where s = slot # of card) to read *
*   in trk0/sec9 down to trk0/sec1 ($BFFF --> $B600).            *
* - NOTE:  In order to generate an accurate symbol table that    *
*   can be applied 2 both the formatted & linear disassemblies,  *
*   and because different assemblers vary in their abilities to  *
*   accept certain OBJect values or re-ORG during assembly, the  *
*   following special label system has been created:             *
*   Image label/adr   Execution label/adr         Comments       *
*   ---------------   -------------------   -------------------- *
*   SEC2RDB6, $B600    SEC2RD08, $800      ;Defines # of secs to *
*                                          ;be read in by boot0. *
*   BT1EXCB6, $B601    BT1EXC08, $801      ;Start of boot1.      *
*                                          ;Boot0 jumps to this  *
*                                          ;location.            *
*   SKPRELB6, $B61F    SKPREL08, $81F      ;Target labl 4 brnch. *
*   PRP4B2B6, $B639    PRP4B208, $839      ;Target labl 4 brnch. *
*     IMG8FD, $B6FD    BT1LDADR, $8FD      ;Boot1 load address.  *
*                                          ;Varies from $B600 to *
*                                          ;$BF00.  Eventually   *
*                                          ;pts 2 start of boot2 *
*                                          ;($B700).             *
*     IMG8FF, $B6FF    BT1PG2RD, $8FF      ;Contains # of secs 2 *
*                                          ;be read in when      *
*                                          ;executing boot1. Also*
*                                          ;doubles as logical   *
*                                          ;sec #. Varies from:  *
*                                          ;$09 --> $00 --> $FF. *
* - As indicated above, SEC2RD08 ($800) defines the number of    *
*   sectors to be read in by boot0.  This value is normally $01  *
*   (meaning read only sector0 of track0).  However, you can zap *
*   trk0/sec0/offset0 with a larger value ($01 to $10) to read   *
*   more sectors from trk0.  Also note that most references say  *
*   that SEC2RD08 normally contains a "$00" (rather than a       *
*   "$01").  Because the test at $CsF6 uses the carry, either    *
*   value will only cause one sector to be read in.  However,    *
*   "$01" is the value used by DOS.  (Confusion may stem from    *
*   the fact that Applesoft later stores a $00 in memory at      *
*   $800.)                                                       *
*                                                                *
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*


(B600)  <============= image address.
SEC2RDB6
(800)  <============== execution address.
SEC2RD08 HEX 01       ;Defines the number of sectors to be read
                      ;in from track 0 during BOOT0.

(B601)
BT1EXCB6
(801)
BT1EXC08 LDA PT2BUF+1 ;Get the next page to read in.
         CMP #$09     ;Is it page 9 (ie. first page read by BOOT1)?
         BNE SKPREL08 ;No - already used by BOOT1 to read page 9,
                      ;so skip pointer initialization given below.

* Initialize the pointer (PT2RDSC) to point
* at BOOT0's read sector subroutine (BTRDSEC,
* $Cs5C, where s = slot #, normally $C65C).
(B607)
(807)    LDA SLT16ZPG ;(a) = slot *16.
         LSR          ;Divide by 16.
         LSR
         LSR
         LSR
         ORA $C0      ;Merge with $C0 to get $Cs, where s=slot#.
         STA PTR2RDSC+1 ;Store the hi byte of the address of the
                      ;controller's read sector subroutine.
         LDA #<BTRDSEC ;Get low byte of addr of subroutine.
         STA PTR2RDSC ;Low byte is a constant (#$5C) and is
                      ;therefore not variable with the slot used
                      ;(as is the hi byte).

* Read in the 9 sectors represented by
* trk0/sec9 down to trk0/sec1 into
* $BFFF to $B600.  Note that the sectors
* are read in from higher to lower memory.
* These sectors contain the IMAGE of BOOT1,
* part of the File Manager and almost all
* of RWTS and it's associated routines.

* Calculate target address for the first sector
* to be read in.
(B615)
(815)    CLC
         LDA BT1LDADR+1 ;Contains $B6 on 48K slave.
         ADC BT1PG2RD ;Contains #$09 on 48K slave.
         STA BT1LDADR+1 ;(a) = #$BF on 48K slave.

* Determine the number of sectors left to read,
* the physical sector number & the target address.
* Then, go read in the next sector.
(B61F)
SKPRELB6
(81F)
SKPREL08 LDX BT1PG2RD ;(x) = pages left to read in less 1.
                      ;(Also doubles as logical sector number.
                      ;Varies from $09 --> $FF.)
         BMI PRP4B208 ;When (x) = $FF, we have read all the
                      ;sectors in so go exit.
         LDA PHYSECP8-$AE00,X ;Convert the logical sector number
                      ;to a physical sector number. (Equivalent
                      ;to "LDA $84D,X".)
         STA BOOTSEC  ;Store physical sector number in page0.
         DEC BT1PG2RD ;Reduce sectors (pages) left to read for
                      ;the next time around.
         LDA BT1LDADR+1 ;Point the buffer pointer at the target
         STA PT2BTBUF+1 ;address. (Varies from $BF to $B6 on a
                      ;48K slave.)
         DEC BT1LDADR+1 ;Reduce the hi byte of the I/O buffer for
                      ;the next time around. (Varies from $BF to
                      ;$B5 on a 48K slave.)
         LDX SLT16ZPG ;Set (x) = slot*16.
(836)    JMP (PTR2RDSC) ;Equivalent to "JMP ($8FD)" or "JMP $Cs5C"
(B636)   ------------ ;to go read in the next sector.
                      ;***************** NOTE *******************
                      ;* GOES TO BT1EXC08 ($801) AFTER @ SECTOR *
                      ;* IS READ IN. (BT1EXCB6 is a carbon copy *
                      ;* of BT1EXC08.)                          *
                      ;******************************************

* Prepare for BOOT2.
(B639)
PRP4B2B6
(839)
PRP4B208 INC BT1LDADR+1 ;Point at the load address for BOOT2.
         INC BT1LDADR+1 ;(After the INCs = $B7 on 48K slave.)

* Set full screen text & designate the
* keyboard and screen as the I/O devices.
(B63F)
(83F)    JSR SETKBD   ;Simulate an IN#0.  (See dis'mbly below.)
         JSR SETVID   ;Simulate an PR#0.  (See dis'mbly below.)
         JSR INIT     ;Simulate a "TEXT" statement. (See dis'mbly
                      ;in APPLE II REFERENCE MANUAL at $FB2F.)
         LDX SLT16ZPG ;(x) = slot * 16.
     
* Go to BOOT2.
(B64A)
(84A)    JMP (BT1LDADR) ;Jump to BOOT2 ($B700 on 48K slave).
         --------------


*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*
*                                                                *
*                       BOOT2                                    *
*                                                                *
*----------------------------------------------------------------*
*                                                                *
* - Reads in the rest of DOS starting at trk02/sec04 down to     *
*   trk00/sec0A ($B5FF --> $9B00).  (P.S. Sectors 0A and 0B of   *
*   track 0 are empty ($9CFF - $9B00).)                          *
* - After the rest of DOS is read in, execution jumps to DOS's   *
*   coldstart routine (DOSCLD, $9D84).                           *
* - Note that on entry:  (x) = slot * 16                         *
*                                                                *
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*


* Prepare RWTS's input-output block (IOB)
* and designate the number of sectors to read.
(B700)
BOOT2    STX IBSLOT   ;(x) = slot*16 wanted.
         STX IOBPSN   ;Last-used slot*16 value.
         LDA #1       ;Set both the last-used and wanted drives
         STA IOBDPDN  ;as drive #1.
         STA IBDRVN
         LDA NMPG2RD  ;Set number of pages (ie. secs) to read.
         STA BT2PGCTR ;Counter for for number of pages to read.
         LDA #2       ;Start with trk02/sec04.
         STA IBTRK    ;Track.
         LDA #4
         STA IBSECT   ;Sector.
(B71E)   LDY BT1MGADR+1 ;(y) = hi byte of the address of the image
                      ;of BOOT1 (#$B6 on a 48K slave).
(B721)   DEY          ;Define I/O buf as 1 page below boot1.
         STY IBBUFP+1
         LDA #1       ;Opcode for read.
(B727)   STA IBCMD

* Convert from (x) = slot*16 to (x) = slot.
(B72A)   TXA          ;(x) = slot * 16.
         LSR          ;Divide by 16.
         LSR
         LSR
         LSR
(B72F)   TAX          ;(x) = slot.

* Initialize the page-four locations with
* the track numbers associated with the drives.
(B730)   LDA #0
         STA TRK4DRV2,X
(B735)   STA TRK4DRV1,X

* Call the routine to read in the rest of DOS.
(B738)   JSR RWPAGES

                      * READ/write a group of pages.
                      (B793)
                      RWPAGES  LDA ADROFIOB+1 ;Init (a)/(y) with the hi/low bytes of the
                               LDY ADROFIOB ;addr of RWTS's IOB for entry to RWTS.
                      (B799)   JSR ENTERWTS ;Enter RWTS to read/write sector.

                                            * Entry to RWTS.
                                            (B7B5)
                                            ENTERWTS PHP          ;Save status register on the stack.
                                            (B7B6)   SEI          ;Set the interrupt disable flag to prevent
                                                                  ;any further maskable interrupts when doing
                                                                  ;real-time programming.
                                            (B7B7)   JSR RWTS     ;Enter RWTS proper to do the operation:
                                                                  ; $00=seek, $01=read, $02=write, $03=format.

                                                                  * RWTS proper.
                                                                  (BD00)
                                                                  RWTS     .
                                                                           .
                                                                  (See dis'mbly in RWTSDRVR using READ.)
                                                                           .
                                                                           .
                                                                           (RTS)

                                            (B7BA)   BCS ERRENTER ;Operation was NOT successful.
                                                     PLP          ;Retrieve saved status off the stack.
                                            (B7BE)   RTS
                                                     ============

                                            (B7BF)
                                            ERRENTER PLP          ;Throw the saved status off the stack.
                                                     SEC          ;Signal operation was unsuccessful.
                                            (B7C1)   RTS
                                                     ============

                      (B79C)   LDY IBSECT   ;Get # of the sector just read or written.
                      (B79F)   DEY          ;Set value for next sector 2 read.  When
                                            ;executing BOOT1, goes from $09 to $FF.
                      (B7A0)   BPL SAMETRK  ;Branch to use the same track.

                      * Start a new track.
                      (B7A2)   LDY #$0F     ;Start with sector 15.
                               NOP
                               NOP
                      (B7A6)   DEC IBTRK    ;Reduce number of track wanted.

                      * Reduce the addr of the target memory location.
                      * Test if more sectors to read.
                      (B7A9)
                      SAMETRK  STY IBSECT   ;Store the sector wanted.
                               DEC IBBUFP+1 ;Reduce buf addr of target memory location.
                               DEC BT2PGCTR ;Reduce counter for # of sectors to read.
                               BNE RWPAGES  ;More sectors to read.
                      (B7B4)   RTS

(B73B)   LDX #$FF     ;Completely clear out the stack.
         TXS
         STX IBVOL    ;Set the volume to $FF (compliment of 0).
(B741)   JMP CLOBCARD
         ------------

* Patch to clobber the language card
* and set video output.
(BFC8)
CLOBCARD JSR SETVID   ;Select the video screen.

                      * Monitor ROM's routine to designate the
                      * video screen as the output device.
                      * (Simulate a "PR#0" statement.)
                      (FE93)
                      SETVID   LDA #0       ;Designate slot 0.
                      OUTPORT  STA A2L
                      OUTPRT   LDX #<CSW    ;Set offset from start of zero page to OUTPUT hook.
                               LDY #<COUT1
                      IOPRT    LDA A2L
                               AND #$0F
                      (FE9F)   BEQ IOPRT1   ;ALWAYS.

                      (FEA7)
                      IOPRT1   LDA #>COUT1  ;(Hi byte of addr of KEYIN & COUT1 are equal.)
                      IOPRT2   STY LOC0,X   ;Set CSW: COUT1.
                               STA LOC1,X
                      (FEAD)   RTS

(BFCB)   LDA $C081    ;Write enable the RAM card.
         LDA $C081    ;(Read motherboard / write card bank 2.)
         LDA #0       ;Set the language identifying byte on the
(BFD3)   STA BASICCLD ;card to $00 so if card is tested (during
                      ;an FP command), the machine will be forced
                      ;to use the motherboard version of FP.
(BFD6)   JSR CONTCLOB ;Now clobber the 80-column card.

                      * Clobber the 80-column card.
                      (BA76)
                      CONTCLOB LDA #$FF     ;Set the mode flag for card.
                               STA $4FB     ;Scratch pad memory for slot 3 peripheral.
                               STA $C00C    ;Turn off the alternate character set.
                               STA $C00E
                      (BA81)   JMP INIT     ;Simimulate a TEXT statement.
                               ------------

                      * Monitor ROM's Init routine.
                      (FB2F)
                      INIT     .
                               .
                      (See dis'mbly in APPLE II REFERENCE MANUAL.)
                               .
                               .
                      - simulate a text statement.
                        (Ie. set window to full screen text.)
                               .
                               .
                               (RTS)

(BFD9)   JMP BK2BOOT2 ;Return to original part of BOOT2.
         ------------

* Return back to original part of BOOT2.
(B744)
BK2BOOT2 JSR SETKBD   ;Select the keyboard.

                      * Monitor ROM's routine to designate the
                      * keyboard as the input device.
                      * (Simulate a "IN#0" statement.)
                      (FE89)
                      SETKBD   LDA #0       ;Pretend using slot 0.
                      INPORT   STA A2L
                      INPRT    LDX #<KSW    ;Set offset from start of zero page to INPUT hook.
                               LDY #<KEYIN
                      (FE91)   BNE IOPRT    ;ALWAYS.

                      (FE9B)
                      IOPRT    LDA A2L
                               AND #$0F
                      (FE9F)   BEQ IOPRT1   ;ALWAYS.

                      (FEA7)
                      IOPRT1   LDA #>COUT1  ;(Hi byte of the addr of KEYIN & COUT1 are equal.)
                      IOPRT2   STY LOC0,X   ;Set KSW: KEYIN.
                               STA LOC1,X
                      (FEAD)   RTS

(B747)   JMP DOSCOLD  ;Jump into DOS's coldstart routine to build
         ------------ ;the DOS buffers and the page-three vector
         .            ;table and then run the "HELLO" program.
         .            ;*************** N O T E *****************
         .            ;* This instruction is a hacker's dream. *
         .            ;* For instance, you can change the jump *
         .            ;* to point to you own password or time- *
         .            ;* bomb routine that you have deviously  *
         .            ;* embedded in an unused section of DOS. *
         .            ;*****************************************
         .
         .
         .
*---------------------*
* SEE dis'mbly titled *
*    "DOSCOLDSTART"   *
*---------------------*
         .
         .
         .