; ==== ISUAL Flight Software -- Univ of California, Berkeley, SSL ====
; mm.a -- Mass Memory functions
;
; Revision History:
;  18-Dec-2002 - SPG - ISUAL Flight Software rev 7.3
;    First Official Release
;  31-dec-2002
;    Removed debug.i
;    Removed debug msg on timeout
;  9-Sep-2003
;    added MM_Test function
;  24-Sep-2003 - changed MM test addr list
;  25-Sep-2003 - removed extra mvi in MM_OFF
;   3-Oct-2003 
;    MM_OFF just sends 2 CDIs
;    changed MM_TEST list
;    on upset, turn off DCM
;  13-Oct-2003
;    MM_STORE does nothing if MM is off
;  14-Oct-2003
;    On MM upset, clear space craft buffer counts and switches
;  16-Oct-2003
;    set GBL_PVSTART to 0 on upset
;  27-Oct-2003 - zero "N MMCBs needing compression" on MM upset
;  31-Oct-2003 
;    on MM upset, set DCM and TM queues to empty
;    and GBL_RO_IDLE to 1
        include mm.i
        include gbl.i
        include cdi.i
        include pwr.i
        include util.i
        include ioports.i
        include debug.i
        
precharge db 0,0
limit_flag db 0
disabled db 1

MM_INIT:
; always turn on MM at startup

; Turn on Mass Memory
MM_ON:
        push psw
        push b
        push h

; Turn on Mass Memory power service
        mvi a,0        ; power service 0
        call PWR_SET_ON
        mvi c,100
; 100 ms wait 
www:    call wait_1ms
        dcr c
        jnz www
; release MM reset
        in MM_IM_DCM_STS_I
        ani 7Fh         ; turn off b7
        out MM_IM_DCM_CTL_O

; do MM "precharge"
        mvi a,MM_PRECHARGE  ; precharge all banks
        lxi h,precharge ; (data is don't-care?)
        call CDI_SEND
        mvi a,MM_MODE_INIT     ; Mode register
        call CDI_SEND

        mvi a,1
        sta GBL_MM_STATUS      ; it's on

        pop h
        pop b
        pop psw
        ret

MM_OFF: push psw
        push h
        lxi h,0
        mvi a,MM_PWR_A
        call CDI_AHL
        mvi a,MM_PWR_B
        call CDI_AHL
        mvi a,0
        sta GBL_MM_STATUS       ; it's off.
        pop h
        pop psw
        ret

MM_addr ds 4

setup:
; DE - points to 4-byte MM-address
; HL - points to RAM
        xchg

; set bank to F0
        mvi a,0F0h
        out BANK_SELECT_O

; clear MM timeout error latch
        in MM_IM_DCM_STS_I
        ori 04h
        out MM_IM_DCM_CTL_O

; copy MM address to local
        mov a,M
        sta MM_addr
        inx h
        mov a,M
        sta MM_addr+1
        inx h
        mov a,M
        sta MM_addr+2
        inx h
        mov a,M
        sta MM_addr+3
; DE - points to RAM
        ret

set_bank_regs:
; load 4 special registers
        lda MM_addr+0   ; MM addr bits 31..24
        out MM_BADR_3124_O
        lda MM_addr+1   ; MM addr bits 23..16 
        out MM_BADR_2316_O 
        lda MM_addr+2   ; MM addr bits 15..8
        out MM_BADR_1508_O
        mov h,a         
        lda MM_addr+3   ; MM addr bits 7..0
        mov l,a           
; HL - MM address bits 15..0
; shift left 2, isolate bits 11..0
        dad h
        dad h
; make a 16 bit byte address within 16K bank area
        mov a,h
        ani 3Fh 
        ori 40h         ; 4000..7FFF
        mov h,a
; MM address bits 0..11 are now in HL 2..13
; HL bits 14 and 15 are 01, to make an address
; within the banked RAM (4000h - 7FFFh).
; HL bits 0..1 (now 00) are used by the MM interface hardware
; to select bytes out of a word.

; returned: HL - pointer within 16K Bank window
        ret

inc_MM_addr:
        lda MM_addr+3
        adi 1           ; 1 word (4 bytes)
        sta MM_addr+3
        jnc iend        ; no carry
        lda MM_addr+2
        aci 0           ; propagate carry
        sta MM_addr+2
        jnc iend
        lda MM_addr+1
        aci 0
        sta MM_addr+1
        jnc iend
        lda MM_addr
        aci 0
        sta MM_addr
iend:
        ret

MM_FETCH:
; BC - number of words
; DE - points to 4-byte MM address
; HL - where data is to be stored in DPU memory
        push psw
; this limits MM timeout retries to one
        lda limit_flag
        cpi 1
        jnz first_try
        mvi a,0
        sta limit_flag
        pop psw
        ret
first_try:
        push b
        push d
        push h

; save current Bank
        in BANK_SELECT_I
        push psw

        call setup
; DE - points to RAM (where data is to be stored)
        
set_bank:
        call set_bank_regs
; HL - source (in 16K Bank window)
; DE - destination
; BC - word count

; reset watchdog timer
fl2:    out WATCHDOG_PET_O

; Copy 4-byte groups
        mov a,M         ; MM data[31:24] (wait states)
        stax d
        inx d
        inx h
        mov a,M         ; MM data[23:16] (no wait states)
        stax d
        inx d
        inx h
        mov a,M         ; MM data[15:8]  (  "  )
        stax d
        inx d
        inx h
        mov a,M         ; MM data[7:0]   (  "  )
        stax d
        inx d
        inx h
; increment MM word-pointer
        call inc_MM_addr
       
; decrement word-count
        dcx b
; when BC=0, transfer is complete
        mov a,b
        ora c
        jz fxit        ; BC=0 - transfer is complete

; If source offset went past end of 16K window,
; the bank registers have to be set again
        mov a,h
        cpi 80h         ; 8000
        jnz fl2         ; still in the window
        jmp set_bank

fxit:
; check MM timeout error latch
        in MM_IM_DCM_STS_I
        ani 04h         ; port 08, bit 2
        jz fxit2
; If there were any timeouts, repeat the transfer
        lxi h,GBL_SOH+108       ; IDH_MM_STATUS
        inr M           ; increment error counter
; restore all regs, then repeat the call
        mvi a,1
        sta limit_flag  ; no more than once
        pop psw
        out BANK_SELECT_O
        pop h
        pop d
        pop b
        pop psw
        jmp MM_FETCH

fxit2:
; restore original Bank
        pop psw
        out BANK_SELECT_O

        pop h
        pop d
        pop b
        pop psw
        ret


MM_STORE:
; BC - number of bytes
; DE - points to 4-byte MM destination address
; HL - addr of source in DPU memory
        push psw
; do nothing if MM is off
        lda GBL_PWR+2
        ani 1
        jnz itson       ; MM is on
        pop psw
        ret
itson:
; this limits MM timeout retries to one
        lda limit_flag
        cpi 1
        jnz first_trys
        mvi a,0
        sta limit_flag
        pop psw
        ret
first_trys:
        push b
        push d
        push h

; save current Bank
        in BANK_SELECT_I
        push psw

; copy MM address to local (MM_addr) 
        call setup
; DE - points to RAM (where data is to be fetched)

set_bank_s:
        call set_bank_regs
; HL - destination (in 16K Bank window)
; DE - source
; BC - word count

; reset watchdog timer
sl2:    out WATCHDOG_PET_O

; Copy 4-byte groups
; Write in this order (***rev E of ISDPGLU Actel):
; 1. Write MM_DATA[31:24]   to CPU_ADDR+0
; 2. Write MM_DATA[23:16]  to CPU_ADDR+1
; 3. Write MM_DATA[15:8] to CPU_ADDR+2
; 4. Write MM_DATA[7:0] to CPU_ADDR+3 (wait state happens here)

        ldax d
        mov M,a         ; store MM data[31:24] (no wait states)
        inx d
        inx h
        ldax d
        mov M,a         ; store MM data[23:16]
        inx d
        inx h
        ldax d
        mov M,a         ; store MM data[15:8]
        inx d
        inx h
        ldax d
        mov M,a         ; store MM data[7:0] (wait-states possible)

; set HL to next 4-byte group in banked area
        inx h
; step DE ahead to next 4-byte group
        inx d
; increment MM word-pointer
        call inc_MM_addr
; decrement word-count
        dcx b
; when BC=0, transfer is complete
        mov a,b
        ora c
        jz sxit        ; BC=0 - transfer is complete

; If destination offset went past end of 16K window,
; the bank registers have to be set again
        mov a,h
        cpi 80h         ; 8000 ?
        jnz sl2         ; still in the window
        jmp set_bank_s  ; outside -- change bank

sxit:
; check MM timeout error latch
        in MM_IM_DCM_STS_I
        ani 04h         ; port 08, bit 2
        jz fxit2
; If there were any timeouts, repeat the transfer
        lxi h,GBL_SOH+108       ; IDH_MM_STATUS
        inr M           ; increment error counter
; restore all regs, then repeat the call
        pop psw
        out BANK_SELECT_O    ; bank
        pop h
        pop d
        pop b
        pop psw
        jmp MM_STORE


;*** new code to support MM test
;*** added 9-Sep-2003
tad     ds 4
testval5 db 055h,055h,055h,055h
testvalA db 0AAh,0AAh,0AAh,0AAh
saved   ds 4
readback ds 4

GOOD equ 1
BAD  equ 0

checkit:
        cmp M
        rnz
        inx h
        cmp M
        rnz 
        inx h
        cmp M
        rnz 
        inx h
        cmp M
        ret

test_one_word:
        push b          ; save BC
        push h          ; save HL
; read and save location
        lxi h,saved
        lxi d,tad       ; point to MM addr
        lxi b,1         ; 1 word
        call mm_fetch
; write test value 55555555
        lxi h,testval5
        call mm_store
; increment address (there will be no carry)
        lxi h,tad+3
        inr M
; write test value AAAAAAAA
        lxi h,testvala
        call mm_store
; decrement address 
        lxi h,tad+3
        dcr M
; read back test value
        lxi h,readback
        call mm_fetch
; see if it's 555555555
        mvi a,55h
        call checkit
        jnz badd
; increment address
        lxi h,tad+3
        inr M
; read back
        lxi h,readback
        call mm_fetch
; see if it's AAAAAAAA
        mvi a,0AAh
        call checkit
        jnz bad
        mvi a,GOOD
; restore original value in location
rtn:    lxi h,saved
        lxi d,tad
        lxi b,1
        call mm_store
        pop b           ; restore BC
        pop h           ; restore HL
        ret
badd:   mvi a,BAD
        jmp rtn

mm_test_list:
        db 0,022h,0A3h,0FEh     ; tests lower MM
        db 3,0FFh,0FFh,0FEh     ; tests upper MM
        db 0FFh         ; FF marks end of list

tlp ds 2

; called from 1-Hz ISR (BGLOOP.a)
; this does a test of Mass Memory
MM_TEST:
        nop     ;  *** patch to RET to disable MM test
        push psw
        push b
        push d
        push h

; if MM has already been turned off, don't do test
        lda GBL_MM_STATUS
        cpi 1
        jnz end_of_list ; MM is off

; step thru list of test locations
        lxi h,mm_test_list
        shld tlp
mmloop: 
; copy MM address to temporary
        lhld tlp
        lxi d,tad
        mvi c,4
        call copy_bytes
; test this location and the next
        call test_one_word
; if good, test is OK
        cpi GOOD
        jnz bad_MM
; next location in list
ok:     
        lhld tlp
        lxi d,4         ; step to next 4-byte addr
        dad d
        shld tlp
        mov a,M         ; FF marks end of list
        cpi 0FFh
        jnz mmloop
end_of_list:
        pop h
        pop d
        pop b
        pop psw
        ret
 
; Mass Memory   upset detected
; ==========================
bad_MM:

; turn MM off
        call MM_off

; Spacecraft buffers are now lost,
; so reset the counts and switches
        mvi a,0
        sta GBL_SC_BUF1
        sta GBL_SC_BUF2
        lxi h,0
        shld GBL_SOH+71
        shld GBL_SOH+73
        shld GBL_SOH+27    ; N MMCBs needing compression = 0
; force DCM restart
        mvi a,0FFh
        sta GBL_DCM_STATUS

; set DCM and TM queues to empty
        mvi a,0FFh
        sta GBL_DCM_QHEAD
        sta GBL_TM_QHEAD
; set Readouts idle
        mvi a,1
        sta GBL_RO_IDLE
; also set "idle" switches for DCM and TM tasks
        sta GBL_DCM_IDLE
        sta GBL_TM_IDLE

; Turn off DCM
        mvi a,1
        call PWR_SET_OFF

; set switch: PVCF_START needs to be run
        mvi a,0
        sta GBL_PVSTART

; log an MM-upset event
        lxi h,GBL_SOH+29
        inr M

; make BGLOOP do an I_STANDBY command,
; wait 2 seconds, then turn MM back on
        mvi a,1
        sta GBL_MM_UPSET

        jmp end_of_list


        
        

