; ===========================================================================
; Buffers.ASM - These are used to cache things like disk sectors into memory
;            - (c) Chris Evans 2008 
; ===========================================================================
;
; <128K of RAM, 360K disk    2            --
; <128K of RAM, > 360K       3            --
;  128K to 255K of RAM       5            2672
;  256K to 511K of RAM       10           5328
;  512K to 640K of RAM       15           7984

$CCBID   EQU 0CEh
$CCBEND  EQU -1
_CCBID   EQU 0
_CCBNEXT EQU 1
_CCBPREV EQU 3
_CCBSIZE EQU 5
$CCBDEFS EQU 532
_CCBRESV EQU 9

$FirstBuf    dw 0  ; -> ccbnext

CCB:
    ccbid    db $CCBID
    ccbnext  dw $CCBEND
    ccbprev  dw $CCBEND
    ccbSize  dw $CCBEND
    ccbresv  db _CCBRESV dup(0)          ; Paragraph boundry
CCB_SIZE EQU $ - CCB

; ===========================================================================
FirstCCB proc far
; ===========================================================================
    mov  dx, word ptr cs:[$FirstBuf]
    mov  es, dx
    xor  si, si
    add  si, CCB_SIZE
    ret
FirstCCB endp

; ===========================================================================
NextCCB  proc far
; ===========================================================================
    stc
    mov  dx, word ptr es:[si+_CCBNEXT]  ; <- ccbnext seg
    cmp  dx, -1
    je   short _lastccb
         clc
         mov  es, dx
         xor  si, si
         mov  al, byte ptr es:[si]
         cmp  al, $CCBID
         je   short nccb_ok
              _print ErrMsg0013, 1
              jmp short _lastccb
nccb_ok:
         add  si, CCB_SIZE
IF (DEBUG)
         pusha
         mov  ah, 0eh
         mov  al, '>'
         int  10h
         popa
ENDIF
_lastccb:
    ret
NextCCB  endp

; ===========================================================================
PrevCCB  proc far
; ===========================================================================
    stc
    mov  dx, word ptr es:[si+_CCBPREV]  ; <- ccbprev seg
    cmp  dx, 0
    je   short _firstccb
         clc
         mov  es, dx
         xor  si, si
         mov  al, byte ptr es:[si]
         cmp  al, $CCBID
         je   short pccb_ok
              _print ErrMsg0013, 1
              jmp short _firstccb
pccb_ok:
         add  si, CCB_SIZE
IF (DEBUG)
         pusha
         mov  ah, 0eh
         mov  al, '<'
         int  10h
         popa
ENDIF
_firstccb:
    ret
PrevCCB  endp

; ===========================================================================
LastCCB proc far
; ===========================================================================
    call FirstCCB
getLast_CCB:
         Call nextCCB
    jnc  getLast_CCB
    ret
LastCCB endp

; ===========================================================================
NewBuffer proc far
; CX    = Paragraphs requested
; Outputs:
; ES:SI = New Buffer Address 
; ===========================================================================
    cli
    xor  bx, bx
    inc  cx
    mov  ax, cs:$FirstBuf
    or   ax, ax
    jnz  short NBnFirst
         mov  bx, $CCBEND
         mov  es, bx
         jmp  short NBCool
NBnFirst:
    Call LastCCB
NBCool:
    push bx
    push es
    call AllocMemBlock
    pop  ds
    pop  bx
    ; ES = New Block
    ; DS = Last Block
    jc   short NBErr
NBmake:
    cmp  bx, $CCBEND
    jne  NBNoupFirst
         push es
         pop  ax
         mov  cs:[$FirstBuf], ax
NBNoupFirst:
    xor  di, di
    mov  ax, $CCBEND
    ; Set header
    ; Current.ID      = CE
    ; Prev.CCBNEXT    = Current.ES
    ; Current.CCBPREV = Prev.DS
    ; Current.CCBNEXT = -1
    ; Current.CCBSIZE = CX (Paragraphs)
    cmp  bx, $CCBEND
    je   short NBSetCurrent
         mov  word ptr ds:[di+_CCBNEXT], es
NBSetCurrent:
    mov  byte ptr es:[di+_CCBID], $CCBID
    mov  word ptr es:[di+_CCBPREV], ds
    mov  word ptr es:[di+_CCBNEXT], ax
    mov  word ptr es:[di+_CCBSIZE], cx
    xor  si, si
    add  si, CCB_SIZE
IF (DEBUG)
    pusha
    _newline
    _echo 'B'
    _echo ' '
    mov  ax, es
    call put_hex
    _echo ':'
    mov  ax, si
    call put_hex
    _newline
    mov  cx, 64
    call debugdump
    popa
ENDIF
    jmp  short NB_X
NBErr:
    mov ax, 8
IF (DEBUG)
    systemerror
ENDIF
    stc
NB_X:
    sti
    ret
NewBuffer endp

; ===========================================================================
FreeBuffer proc far
; ES = Buffer
; ===========================================================================
    cli
    xor  si, si
    mov  ax, cs:$FirstBuf
    mov  dx, ax
    or   ax, ax
    jz   short FBNot
         mov  al, byte ptr es:[si+_CCBID]
         cmp  al, $CCBID
         ; If it not ours then dont touch it
         jne  short FBNot 
FBCool:
    push ds
    mov  ax, word ptr es:[si+_CCBNEXT]    ; next
    mov  bx, word ptr es:[si+_CCBPREV]  ; prev
    ; Update Next packet up
    mov  ds, ax
    mov  word ptr ds:[si+_CCBPREV], bx  ; update prev
    ; Update Prev packet down
    mov  ds, bx
    mov  word ptr ds:[si+_CCBNEXT], ax  ; update next
    pop  ds
    call Free_Block
IF (DEBUG)
    pusha
    _newline
    _echo 'F'
    _echo ' '
    mov  ax, es
    call put_hex
    _newline
    xor  si, si
    mov  cx, 64
    call debugdump
    popa
ENDIF
    jmp  short FB_X
FBNot:
    mov  al, 7
IF (DEBUG)
    systemerror
ENDIF
    stc
FB_X:
    sti
    ret
FreeBuffer endp

; ===========================================================================
MkBuf proc far
; AX = Number
; ===========================================================================
    mov  cx, ax
    mov  ax, 0
mkBuf1:
         push cx
         push ax
         mov  cx, ($CCBDEFS / 16) 
         call NewBuffer
         pop  ax
         pop  cx
         ; ES:SI -> ptr
    loop mkBuf1
    ret
MkBuf endp

