# -------------------------------------------------------------------
# EEPROM TUTORIAL                      (c) Copyright 1997 Nat! & KKP
# -------------------------------------------------------------------
# These are some of the results/guesses that Klaus and Nat! found
# out about the Jaguar with a few helpful hints by other people, 
# who'd prefer to remain anonymous. 
#
# Since we are not under NDA or anything from Atari we feel free to 
# give this to you for educational purposes only.
#
# Please note, that this is not official documentation from Atari
# or derived work thereof (both of us have never seen the Atari docs)
# and Atari isn't connected with this in any way.
#
# Please use this informationphile as a starting point for your own
# exploration and not as a reference. If you find anything inaccurate,
# missing, needing more explanation etc. by all means please write
# to us:
#    nat@zumdick.ruhr.de
# or
#    kp@eegholm.dk
#
# If you could do us a small favor, don't use this information for
# those lame flamewars on r.g.v.a or the mailing list.
#
# HTML soon ?
# -------------------------------------------------------------------
# $Id: eeprom.htmll,v 1.7 1997/11/16 18:14:40 nat Exp $
# -------------------------------------------------------------------

EEPROM tutorial:
=-=-=-=-=-=-=-=-=

This is just a little code, probably all you ever going to need to
access the EEPROM. This is written with PURE-ASM in mind in case
you're wondering about the slightly strange (and not 100% optimal)
register usage/wastage. Anyway this code runs fine on my Jaguar and
I am convinced I got the timing right.
This is coded for a 68000. For a 68030 be sure to put a NOP behind 
all external hardware register accesses, because the 68030 has a 
delayed write feature, where the NOP syncs. Then add a few NOPs for 
timing purposed. One NOP -> 4 cycles, 


CLOCK  = EEPROM_CLOCK
RDATA  = EEPROM_RDATA
WDATA  = EEPROM_WDATA
STROBE = EEPROM_STROBE

      
; --------------------------------------------------------------
;                        read_whole_eeprom
; --------------------------------------------------------------
; Read EEPROM into 128 bytes of wordaligned buffer space (A0)
; wasting D1-D2 in the process
;
read_whole_eeprom:
                  MOVE.W    D3,-(A7)

                  CLR.W     D3               ; cell counter

.copy:            MOVE.W    D3,D0
                  JSR       eeprom_read 
                  MOVE.W    D0,(A0)+
                  ADDQ.W    #1,D3
                  CMP.W     #$40,D3
                  BNE.B     .copy

                  MOVE.W    (A7)+,D3
                  RTS
                  
   


; --------------------------------------------------------------
;                      write_whole_eeprom
; --------------------------------------------------------------
; Write complete EEPROM with 128 bytes of user data pointed to
; by A0, which contains of course an even address
; This can take up to 750ms even in successful writes
; wastes D1-D2
; returns in D0: 0: success  

write_whole_eeprom:
                  BSR      eeprom_unlock

                  MOVE.W   D3,-(A7)
                  CLR.W    D3

.copy:             
                  MOVE.W   (A0)+,D0            ;; get word
                  MOVE.W   D3,D1               ;; get cell # in D1
                  BSR      eeprom_write        ;; write it down
                  BEQ      .failed             ;; timeout ->
                  ADDQ.W   #1,D3               ;; try the next
                  CMP.W    #$40,D3
                  BNE.B    .copy

.failed:           
                  MOVE     D0,D3               ;; save write status
                  BSR      eeprom_lock         ;; lock cart again
                  MOVE     D3,D0               ;; restore status
                  MOVE.W   (A7)+,D3         
                  SUB.W    #1,D0               ;; make C-like status
                  RTS
   
                           

; --------------------------------------------------------------
;                        eeprom_unlock
; --------------------------------------------------------------
; Unlock the EEPROM for writing
; 
; D0: wasted
; D1: wasted
; D2: wasted
;
eeprom_unlock:
                  LEA       CLOCK,A1
                  MOVE.W    #$130,D0
                  BRA       eeprom_w_cmd
   

; --------------------------------------------------------------
;                        eeprom_lock
; --------------------------------------------------------------
; Lock the EEPROM against writing
; 
; D0: wasted
; D1: wasted
; D2: wasted
;
eeprom_lock:
                  LEA       CLOCK,A1
                  MOVE.W    #$100,D0
                  BRA       eeprom_w_cmd
                    

; --------------------------------------------------------------
;                        eeprom_write
; --------------------------------------------------------------
; D0:   data 
; D1:   cell #
;
; retuens:
; D0:   0 = successful
; A1:   wasted
; D2:   wasted
eeprom_write:
                  LEA       CLOCK,A1
                  MOVE      D0,D2
                  MOVEQ     #$3F,D0
                  AND       D1,D0
                  ORI.W     #$140,D0         ;; set prepare to write bits
                  BSR       eeprom_w_cmd
                        
                  MOVE      D2,D0
                  BSR       eeprom_w_data

                  bra       eeprom_wait      ;; you MUST pull CS down now
   

; --------------------------------------------------------------
;                        eeprom_read
; --------------------------------------------------------------
; Read a word from an EEPROM cell
; 
; D0: cellnumber, returned data also in D0
; D1: wasted
; D2: wasted
;
   module eeprom_read
                  LEA       CLOCK,A1
                  AND.W     #$3F,D0
                  ORI.W     #$180,D0         ;; set prepare to read bits
                  BSR       eeprom_w_cmd
;                  BRA       eeprom_r_data    ;; fall thru
                  
        
; --------------------------------------------------------------
;                        eeprom_r_data
; --------------------------------------------------------------
;  Read 16 bits of data over the serial line
;  return them in D0
;  wasting D1-D2
;
eeprom_r_data:
                  MOVEQ     #0,D0 
                  MOVEQ     #$F,D2           ;; do 16 bits
.readbit:         TST.W     CLOCK-CLOCK(A1)  ;; EEPROM has max 500ns time to
                  NOP                        ;; provide us with the data                
                  NOP   
                  MOVE.W    RDATA-CLOCK(A1),D1 
                  LSR.W     #1,D1            ;; get LSB into X
                  ADDX.W    D0,D0            ;; shift left and add X
                  DBF       D2,.readbit 
                  RTS 
   
   

; --------------------------------------------------------------
;                        eeprom_w_data
; --------------------------------------------------------------
;
; write 16 bits of D0 data, wasting D1 in the process
;
eeprom_w_data::   
                  MOVEQ     #$F,D1           ;; wanna do 16 bits
                  BRA.B     _writebit
        

; --------------------------------------------------------------
;                        eeprom_w_cmd
; --------------------------------------------------------------
; Initiate command mode by doing the CS ChipSelect
; then write 9 bits of D0 data onto the serial line,
; wasting D1 in the process
;
eeprom_w_cmd:  
                  ROL.W     #7,D0            ;; move 9th bit into MSB
                  TST.W     STROBE-CLOCK(A1) ;; pull CS down
                  MOVEQ     #8,D1            ;; wanna do 9 bits

_writebit:
.loop:            ROL.W     #1,D0            ;; get MSB into LSB
                  MOVE.W    D0,WDATA-CLOCK(A1) ;; write it down #1#
                                             ;; wait 1us for EEPROM           
                  DBF       D1,.loop         ;; 8 + 8 + 10 -> 28 > 13.3
                  RTS 
   
            

; --------------------------------------------------------------
;                        eeprom_busy
; --------------------------------------------------------------
; Just check whether the damn thing is still busy.  Not very 
; useful this routine, but heck for completeness..
; returns:  1=ready  0=busy
eeprom_busy:
                  TST.W     STROBE-CLOCK(A1)   ;; pull CS down shortly
                  MOVEQ     #1,D0              ;; wait for 500ns until
                  AND.W     RDATA-CLOCK(A1),D0 ;; we read the data 
                  RTS
   

; --------------------------------------------------------------
;                        eeprom_wait
; --------------------------------------------------------------
; Check whether the EEPROM is still busy writing. It must do this
; in a timespan of 10ms. Busy waiting. ARGH!
;
; wastes D1 in the process!!
; returns in D0:  1=ready  0: timeouted!!
eeprom_wait:
                  MOVE.W    #5200,D1          ;; > 10ms timeout
                  TST.W     STROBE-CLOCK(A1)  ;; pull CS down
.loop:                                        ;; inner loop:
                  MOVEQ     #1,D0             ;; 4 + 12 + 10 -> 26 cycles
                  AND.W     RDATA-CLOCK(A1),D0  
                  DBNE      D1,.loop
                  RTS
   



; #1# the PURE-ASM optimizes this!

Nat! (nat@zumdick.ruhr.de)
Klaus (kp@eegholm.dk)

$Id: eeprom.htmll,v 1.7 1997/11/16 18:14:40 nat Exp $