home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / Assembly / CACHE.ASM < prev    next >
Assembly Source File  |  1979-12-31  |  16KB  |  270 lines

  1.  
  2. INTERRUPTS      SEGMENT AT 0H    ;This is where the disk interrupt
  3.         ORG     13H*4            ;holds the address of its service routine
  4. DISK_INT        LABEL   DWORD  
  5. DISK_INT_WORD   DW 2 DUP(0)
  6. INTERRUPTS      ENDS
  7.  
  8. CODE_SEG        SEGMENT
  9.         ASSUME  CS:CODE_SEG
  10.         ORG     100H            ;ORG = 100H to make this into a .COM file
  11. FIRST:  JMP     LOAD_CACHE      ;First time through jump to initialize routine
  12.                                 
  13.         CPY_RGT DB      '(C)1985 S.Holzner'     ;A signature in bytes
  14.   ;THIS IS THE ONLY PLACE YOU MUST SET THIS NUMBER. EACH SECTOR = 512 BYTES.
  15.         TBL_LEN DW      64 ;<-- # OF SECTORS TO STORE IN CACHE, MIN=24, MAX=124.
  16.         TIME    DW      0       ;Time used to time-stamp each sector
  17.         OLD_CX  DW      0       ;Stores original value of CX (CX is used often)
  18.         LOW_TIM DW      0       ;Used in searching for least recently used sect.
  19.         INT13H  LABEL DWORD
  20.         INT13H_WORD DW 2 DUP(0)       ;Stores the original INT 13H address
  21.         RET_ADR LABEL   DWORD   ;Playing games with the stack here to preserve 
  22.         RET_ADR_WORD    DW      2 DUP(0)            ;flags returned by Int 13H
  23.  
  24. DISK_CACHE      PROC    FAR     ;The Disk interrupt will now come here.
  25.         ASSUME  CS:CODE_SEG     
  26.         CMP     AX,201H         ;Is this a read (AH=2) of 1 sector (AL=1)?
  27.         JE      READ            ;Yes, jump to Read
  28.         CMP     AH,3            ;No. Perchance a write or format?
  29.         JB      OLD_INT         ;No, release control to old disk Int.
  30.         JMP     WRITE           ;Yes, jump to Write
  31. OLD_INT:PUSHF                   ;Pushf for Int 13H's final Iret
  32.         CALL    INT13H          ;Call the Disk Int
  33.         JMP     PAST            ;And jump past all usual Pops
  34. READ:   PUSH    BX              ;Push just about every register ever heard of
  35.         PUSH    CX
  36.         PUSH    DX
  37.         PUSH    DI      
  38.         PUSH    SI
  39.         PUSH    DS
  40.         PUSH    ES
  41.         MOV     DI,BX       ;Int 13H gets data address as ES:BX, switch to ES:DI
  42.         ASSUME  DS:CODE_SEG     ;Make sure all labels found correctly
  43.         PUSH    CS              ;Move CS into DS by pushing CS, popping DS
  44.         POP     DS
  45.         MOV     OLD_CX,CX       ;Save original CX since we're about to use it
  46.         CMP     DH,0            ;DH holds requested head -- head 0?        
  47.         JNE     NOT_FAT1        ;Nope, this can't be the first Fat sector  
  48.         CMP     CX,6            ;If this is the directory, check if we have a
  49.         JE      FAT1            ; new disk.
  50.         CMP     CX,2            ;Track 0 (CH)? Sector 2 (CL)?
  51.         JNE     NOT_FAT1        ;If not, this sure isn't the FAT1        
  52. FAT1:   CALL    FIND_MATCH  ;DOS reads in this sector first to check disk format
  53.         JCXZ    NONE            ;We'll use it for a check-sum. Do we have it
  54.         MOV     BX,DI           ; stored yet? CX=0-->no. If yes, restore BX
  55.         MOV     CX,OLD_CX       ; and CX from original values
  56.         PUSHF                   ;And now do the Pushf and call of Int13H to read
  57.         CALL    INT13H          ; FAT1
  58.         JC      ERR             ;If error, leave
  59.         MOV     CX,256          ;No error, FAT1 was read, check our value
  60.         CLD                     ;Make sure we increment.
  61. REPE    CMPSW                   ; with CMPSW -- if no match, disk was changed
  62.         JCXZ    BYE             ;Everything checks out, Bingo, exit.
  63.         LEA     SI,TABLE        ;New Disk! Zero all the old disk's sectors
  64.         MOV     CX,TBL_LEN      ;Loop over all entries, DL holds drive #
  65. CLR:    CMP     DS:[SI+2],DL    ;Is this stored sector from the old disk?
  66.         JNE     NO_CLR          ;Nope, don't clear this entry
  67.         MOV     WORD PTR DS:[SI],0      ;Match, zero this entry, zero first word
  68. NO_CLR: ADD     SI,518      ;Move on to next stored sector (512 bytes of stored 
  69.         LOOP    CLR         ; sector and 3 words of identification & time-stamp)
  70.         JMP     BYE             ;Reset for new disk, let's leave
  71. NONE:   CALL    STORE_SECTOR    ;Store FAT1 if there was no match to it
  72.         JC      ERR             ;Error -- exit ungraciously
  73.         JMP     BYE             ;No Error, Bye.
  74. NOT_FAT1:                       ;The requested sector was not FAT1. Let's
  75.         CALL    FIND_MATCH      ;get it. Or do we have it already?
  76.         JCXZ    NO_MATCH        ;No, jump to No_Match, store sector
  77.         MOV     CX,512          ;ES:DI and DS:SI already set up from Find_Match
  78.         CLD                     ;Make sure we increment.
  79. REP     MOVSB                   ;Move 512 bytes to requested memory area
  80.         CMP     WORD PTR [BX+4],0FFFFH          ;Is this a a directory sector?
  81.         JE      BYE             ;Yes, don't reset time (already highest poss.)
  82.         INC     TIME            ;No, reset the time, this sector just accessed
  83.         MOV     AX,TIME         ;Move time into Time word of sector's 3 words
  84.         MOV     [BX+4],AX       ; of identification
  85.         JMP     BYE             ;And leave. 
  86. NO_MATCH:                       
  87.         CALL    STORE_SECTOR    ;Don't have this sector yet, get it.
  88.         JC      ERR             ;If read failed, exit with error
  89. BYE:    CLC                     ;The exit point. Clear carry flag, set AX=1
  90.         MOV     AX,1            ; CY=0 --> no error, AH=0 --> error code = 0
  91. ERR:    POP     ES              ;If error, preserve flags and AX with error code
  92.         POP     DS              ;Pop all conceivable registers (except AX)
  93.         POP     SI
  94.         POP     DI
  95.         POP     DX
  96.         POP     CX              ;Now that the flags are set, we want to get the
  97.         POP     BX              ;old flags off the stack (put there by original
  98. PAST:   POP     CS:RET_ADR_WORD ;Int call) To do that we save the return address
  99.         POP     CS:RET_ADR_WORD[2]      ;first and then pop the flags harmlessly
  100.         POP     CS:OLD_CX       ;into Old_CX, and then jump to RET_ADR.
  101.         JMP     CS:RET_ADR      ;Done with read. Now let's consider write.
  102. WRITE:  PUSH    BX              ;Push all registers, past and present
  103.         PUSH    CX              
  104.         PUSH    DX
  105.         PUSH    DI
  106.         PUSH    SI
  107.         PUSH    DS
  108.         PUSH    ES
  109.         PUSH    AX
  110.         CMP     AX,301H         ;Is this a write of one sector?
  111.         JNE     NOSAVE          ;No, don't save it in the sector bank
  112.         PUSH    CS              ;Yep, set DS (for call to Int13H label) and
  113.         POP     DS              ; write this sector out
  114.         PUSHF     
  115.         CALL    INT13H
  116.         JNC     SAVE       ;If there was an error we don't want to save sector
  117.         POP     CS:OLD_CX       ;Save AH error code, Pop old AX into Old_CX
  118.         JMP     ERR             ;And jump to an ignoble exit
  119. SAVE:   MOV     OLD_CX,CX       ;We're going to save this sector.
  120.         MOV     DI,BX           ;Set up DI for string move (to store written
  121.         CALL    FIND_MATCH      ; sector. Do we have it in memory? (set SI)
  122.         JCXZ    LEAVE           ;Nope, Leave (like above's Bye).
  123.         XCHG    DI,SI           ;Exchange destination and source
  124.         PUSH    ES              ;Set up DS:SI to point to where data written
  125.         POP     DS              ; from. We'll then use a string move
  126.         PUSH    CS              ;Set up ES so ES:DI points to sector bank
  127.         POP     ES              ; SI was set by Find_Match, Xchg'd into DI
  128.         MOV     CX,512          ;Get ready to move 512 bytes
  129.         CLD                     ;Make sure we increment.
  130. REP     MOVSB                   ;Here we go
  131. LEAVE:  POP     AX              ;Here is the leave
  132.         JMP     BYE             ;Which only pops AX and then jumps to Bye
  133. NOSAVE: PUSH    CS              ;More than 1 sector written, don't save but
  134.         POP     DS              ; do zero stored sectors that will be written
  135.         MOV     AH,0            ;Use AX as loop index (AL=# of sectors to write)
  136. TOP:    PUSH    CX              ;Save CX since destroyed by Find_Match
  137.         CALL    FIND_MATCH      ;Do we have this one?
  138.         JCXZ    NOPE            ;Nope if CX = 0
  139.         MOV     WORD PTR [BX],0 ;There is a match, zero this sector
  140. NOPE:   POP     CX              ;Restore CX, the sector index
  141.         INC     CL              ;Move on to next one
  142.         DEC     AX              ;Decrement loop index
  143.         JNZ     TOP             ;And, unless that gives 0, go back again
  144. POPS:   POP     AX              ;Pop 'em all, starting with AX
  145.         POP     ES
  146.         POP     DS
  147.         POP     SI
  148.         POP     DI
  149.         POP     DX
  150.         POP     CX
  151.         POP     BX
  152.         JMP     OLD_INT         ;And go back to OLD_INT for write.
  153. DISK_CACHE      ENDP
  154.  
  155. FIND_MATCH      PROC    NEAR    ;This routine finds a sector in the sector bank
  156.         PUSH    AX              ;And returns SI set to sector's entry, BX set 
  157.         LEA     SI,SECTORS      ; to the beginning of the 'table' -- the 3 words
  158.         LEA     BX,TABLE        ;that precede all sectors. If there was no match
  159.         MOV     AX,TBL_LEN      ; CX=0. When Int13H called, CH=trk #, CL=sec. #
  160.         XCHG    AX,CX           ; DH=head #, DL=Drive #. Get Tbl_Len into CX
  161. FIND:   CMP     DS:[BX],AX      ;Compare stored sector's original AX to current 
  162.         JNE     NO              ;If not, not.
  163.         CMP     DS:[BX+2],DX    ;If so, check DX of stored sector with current
  164.         JE      GOT_IT          ;Yes, there is a match, leave
  165. NO:     ADD     BX,518          ;Point to next Table entry
  166.         ADD     SI,518          ;And next sector too
  167.         LOOP    FIND            ;Keep looping until there is a match
  168. GOT_IT: POP     AX              ;If there is no match, CX will be left 0
  169.         RET                     ;Return
  170. FIND_MATCH      ENDP
  171.  
  172. STORE_SECTOR    PROC    NEAR    ;This routine, as it says, stores sectors
  173.         MOV     BX,DI           ;Original BX (ES:BX was original data address)
  174.         MOV     CX,OLD_CX       ; and CX restored (CX=trk#, Sector#)
  175.         PUSHF                   ;Pushf for Int 13H's Iret and call it
  176.         CALL    INT13H
  177.         JNC     ALL_OK          ;If there was an exit, exit ignominiously
  178.         JMP     FIN             ;If error, leave CY flag set, code in AH, exit
  179. ALL_OK: PUSH    CX              ;No error, push used registers
  180.         PUSH    BX              ; and find space for sector in sector bank
  181.         PUSH    DX
  182.         LEA     DI,SECTORS      ;Point to sector bank
  183.         LEA     BX,TABLE        ; and Table
  184.         MOV     CX,TBL_LEN      ; and get ready to loop over all of them to
  185. CHK0:   CMP     WORD PTR DS:[BX],0      ;find if there is an unused sector
  186.         JE      FOUND           ;If the first word is 0, use this sector
  187.         ADD     DI,518          ;But this one isn't so update DI, SI and 
  188.         ADD     BX,518          ; loop again
  189.         LOOP    CHK0  
  190.         MOV     LOW_TIM,0FFFEH  ;All sectors were filled, find least recently
  191.         LEA     DI,SECTORS      ; used and write over that one
  192.         LEA     SI,TABLE
  193.         MOV     CX,TBL_LEN      ;Loop over all stored sectors
  194. CHKTIM: MOV     DX,LOW_TIM      ;Compare stored sector to so-far low time
  195.         CMP     [SI+4],DX       
  196.         JA      MORE_RECENT     ;If this one is more recent, don't use it
  197.         MOV     AX,DI           ;This one is older than previous oldest
  198.         MOV     BX,SI           ;Store sector bank address (DI) and table
  199.         MOV     DX,[SI+4]       ; entry (now in SI)
  200.         MOV     LOW_TIM,DX      ;And update the Low Time to this one
  201. MORE_RECENT:                    
  202.         ADD     DI,518          ;Move on to next stored sector
  203.         ADD     SI,518          ;And next table entry
  204.         LOOP    CHKTIM          ;Loop again until all covered
  205.         MOV     DI,AX           ;Get Sector bank address of oldest into DI
  206. FOUND:  POP     DX              ;Restore used registers
  207.         POP     SI              ;Old BX (data read-to-address) --> SI
  208.         POP     CX
  209.         MOV     [BX],CX         ;Store the new CX as the sector's first word
  210.         MOV     [BX+2],DX       ;2nd word of Table is sector's DX
  211.         INC     TIME            ;Now find the new time
  212.         MOV     AX,TIME         ;Prepare to move it into 3rd word of Table
  213.         CMP     DH,0            ;Is this directory or FAT? (time-->FFFF)
  214.         JNE     SIDE1           ;If head is not 0, check other head
  215.         CMP     CX,9            ;Head zero, trk# 0, first sector? (directory)
  216.         JLE     DIR             ;Yes, this is a piece we always want stored
  217.         JMP     NOT_DIR         ;No, definitely not FAT or directory
  218. SIDE1:  CMP     DH,1            ;Head 1?
  219.         JNE     NOT_DIR         ;No, this is not File Alloc. Table or directory
  220.         CMP     CX,2            ;Part of the top of the directory?
  221.         JA      NOT_DIR         ;No, go to Not_Dir and set time
  222. DIR:    MOV     AX,0FFFFH       ;Dir or FAT, set time high so always kept
  223. NOT_DIR:MOV     [BX+4],AX       ;Not FAT or dir, store the incremented time
  224.         PUSH    ES              ;And now get the data to fill the sector
  225.         POP     DS              ;SI, DI already set. Now set ES and DS for 
  226.         PUSH    CS              ; string move. 
  227.         POP     ES
  228.         MOV     CX,512          ;Move 512 bytes
  229.         CLD                     ;Make sure we increment.
  230. REP     MOVSB                   ;Right here
  231.         CLC                     ;Clear the carry flag (no error)
  232. FIN:    RET                     ;Error exit here (do not reset CY flag)
  233. STORE_SECTOR    ENDP
  234. TABLE:  DW      3 DUP(0)        ;Table and sector storage begins right here
  235. SECTORS:                        ;First thing to write over is the following
  236.                                 ; booster program.
  237. LOAD_CACHE        PROC    NEAR  ;This procedure intializes everything
  238.         LEA     BX,CLEAR
  239.         ASSUME  DS:INTERRUPTS   ;The data segment will be the Interrupt area
  240.         MOV     AX,INTERRUPTS
  241.         MOV     DS,AX
  242.         MOV     AX,DISK_INT_WORD        ;Get the old interrupt service routine
  243.         MOV     INT13H_WORD,AX          ; address and put it into our location
  244.         MOV     AX,DISK_INT_WORD[2]     ; INT13H so we can call it.
  245.         MOV     INT13H_WORD[2],AX 
  246.         MOV     DISK_INT_WORD,OFFSET DISK_CACHE ;Now load the address of Cache
  247.         MOV     DISK_INT_WORD[2],CS     ;routine into the Disk interrupt
  248.         MOV     AX,TBL_LEN              ;The number of sectors to store in cache
  249.         MOV     CX,518                  ;Multiply by 518 (3 words of id and 512
  250.         MUL     CX                      ; bytes of sector data)
  251.         MOV     CX,AX                   ;Also, zero all the bytes so that 
  252. ZERO:   MOV     BYTE PTR CS:[BX],0      ; Store_Sector will find 1st word a 0,
  253.         INC     BX                      ; indicating virgin territory.
  254.         LOOP    ZERO                    
  255.         MOV     DX,OFFSET TABLE         ;To attach in memory, add # bytes to 
  256.         ADD     DX,AX                   ;store to Table's location and use
  257.         INT     27H                     ; Int 27H
  258. LOAD_CACHE        ENDP
  259. CLEAR:
  260.         CODE_SEG        ENDS
  261.         END     FIRST           ;END "FIRST" so 8088 will go to FIRST first.
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.