;**************************************************************************
;*
;* FLASH - Program FlashCard flash EPROM
;*
;* Module: flash.asm
;* Purpose: Program FlashCard flash EPROM
;* Entries: start
;*
;**************************************************************************
;*
;* Copyright (C) 1995-2003 Gero Kuhlmann <gero@gkminix.han.de>
;*
;* This program is free software; you can redistribute it and/or modify
;* it under the terms of the GNU General Public License as published by
;* the Free Software Foundation; either version 2 of the License, or
;* any later version.
;*
;* This program is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;* GNU General Public License for more details.
;*
;* You should have received a copy of the GNU General Public License
;* along with this program; if not, write to the Free Software
;* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;*
;**************************************************************************
;*
;
;**************************************************************************
;
; The purpose of this program is to program the flash EPROM on the FlashCard
; ISA card. The flash EPROM has to be an AMD 29F010, and the programming
; algorithm is the same as that suggested by AMD in the appropriate data
; sheets.
;
.model small,pascal
.stack 256 ; 256 stack bytes should be sufficient
;
;**************************************************************************
;
; Miscellaneous defines:
;
CMDLINE equ 00080h ; offset of command line into PSP
BUFSIZE equ 512 ; size of read buffer
FNAMSIZE equ 64 ; maximum size of filename
SEGLOW equ 0C800h ; lower range for EPROM segment
SEGHIGH equ 0E800h ; upper range for EPROM segment
SEGMASK equ 0FE00h ; mask for 8kB boundary
AMD_ID equ 2001h ; flash EPROM ID, only support AMD
ERASE1_CMD equ 080h ; first command for erasing full chip
ERASE2_CMD equ 010h ; second command for erasing full chip
READID_CMD equ 090h ; command to read chip ID
PROG_CMD equ 0A0h ; command to program a byte
RESET_CMD equ 0F0h ; command to reset chip state machine
;
;**************************************************************************
;
; Constant segment:
;
.const
cpymsg db 'flash - Flash EPROM programming utility',0Dh,0Ah
db 'Copyright (C) 1996-2003 Gero Kuhlmann',0Dh,0Ah
db 0Dh,0Ah,'$'
segerr db 'Illegal segment '
db '(must be between C800 and E800 on 8kB boundary)'
db 0Dh,0Ah,'$'
useerr db 'usage: flash <seg-addr> <file name>'
db 0Dh,0Ah,'$'
filerr db 'Cannot open input file'
db 0Dh,0Ah,'$'
rderr db 'Cannot read from input file'
db 0Dh,0Ah,'$'
iderr db 'Invalid manufacturer ID or no Flash-EPROM installed'
db 0Dh,0Ah,'$'
prgerr db 'Timeout while programming or erasing Flash-EPROM'
db 0Dh,0Ah,'$'
prgmsg db 'Programming... $'
endmsg db 'finished'
db 0Dh,0Ah,'$'
;
;**************************************************************************
;
; Data segment:
;
.data
fseg dw 0D000h ; flash EPROM segment
handle dw 0 ; data file handle
filename db FNAMSIZE dup (0) ; file name buffer
buf db BUFSIZE dup (0) ; read buffer
;
;**************************************************************************
;
; Program start
;
.code
assume cs:_text
assume ds:nothing
assume es:nothing
start: mov ax,@data
mov es,ax
assume es:dgroup
; First analyze the command line. The only arguments for this program
; are the EPROM segment address in hex and the data file name.
mov si,CMDLINE + 1
call skipblank
cmp al,0Dh
je short start5
call gethex ; get hex number
cmp bx,SEGLOW ; should be in the range of C800h
jb short start2 ; and E800h
cmp bx,SEGHIGH
ja short start2
test bx,not SEGMASK ; segment has to be on 8kB boundary
jz short start4
start2: mov dx,offset segerr
start3: mov ax,@data
mov ds,ax
start1: mov ah,09h ; print error message
int 21h
jmp doend
start4: mov es:fseg,bx ; save EPROM segment address
call skipblank
cmp al,0Dh
je short start5
call copyfnam ; copy filename
call skipblank ; nothing should follow anymore
cmp al,0Dh
je short start6
start5: mov dx,offset useerr ; print usage message
jmp short start3
; We now analyzed the whole command line, so the PSP segment in DS is
; no longer needed. Setup all segment registers correctly, and then try
; to open the data file.
start6: mov ax,@data
mov ds,ax ; set segment registers
mov es,ax
assume ds:dgroup
assume es:dgroup
mov dx,offset cpymsg ; print copyright
mov ah,09h
int 21h
mov ax,3D00h
mov dx,offset filename ; open the data file
int 21h
mov dx,offset filerr
jc short error ; print error message if unsuccessful
mov handle,ax ; save file handle
; Read the flash EPROM ID to check if there really is an AMD flash EPROM
; where the user says it should be. Then erase the whole chip to allow
; programming lateron.
call readid ; read manufacturer ID from chip
mov dx,offset iderr
cmp bx,AMD_ID ; check for AMD
jne short error
call erase
mov dx,offset prgerr ; erase the whole chip
jc short error
; Now read every block from the data file and program it into the flash
; EPROM. Verification of the programmed data is not necessary, as the
; flash EPROM will do that by itself. It will return an unsuccessful
; programming cycle if it's internal verification showed an error.
mov dx,offset prgmsg
mov ah,09h ; print programming message
int 21h
xor bx,bx
start7: push bx
mov ax,3F00h
mov bx,handle
mov cx,BUFSIZE ; read next block from data file
mov dx,offset buf
int 21h
pop bx
mov dx,offset rderr ; check for read error
jc short error
or ax,ax ; check for end of file
jz short start8
mov cx,ax
call program ; program the data block into the
mov dx,offset prgerr ; flash EPROM and check for a pro-
jnc short start7 ; gramming error
error: jmp start1
start8: mov dx,offset endmsg
mov ah,09h ; print end-of-programming message
int 21h
doend: mov ax,4C01h ; terminate program
int 21h
ret
;
;**************************************************************************
;
; Skip blanks on command line.
; Input: DS:SI - pointer to command line
; Output: DS:SI - pointer to first non-blank
; AL - first non-blank character
; Registers changed: AX, SI
;
skipblank proc near
cld
skip1: lodsb
cmp al,' ' ; skip blanks
je short skip1
cmp al,09h ; skip tabs
je short skip1
dec si ; point SI to first non-blank
ret
skipblank endp
;
;**************************************************************************
;
; Return hex number from string pointed to by DS:SI.
; Input: DS:SI - pointer to string
; Output: DS:SI - pointer to first character after hex number
; BX - hex number
; Registers changed: AX, BX, CX, SI
;
gethex proc near
xor bx,bx
geth1: lodsb
cmp al,'0'
jb short geth9 ; check for valid hex digit
cmp al,'9'
jbe short geth3
cmp al,'A'
jb short geth9
cmp al,'a'
jb short geth2
sub al,20h ; convert character to upper case
geth2: cmp al,'F'
ja short geth9
sub al,7
geth3: sub al,'0' ; convert character to digit
and al,0Fh
mov cl,4
shl bx,cl ; include digit into result
or bl,al
jmp short geth1 ; get next character
geth9: dec si ; point SI to last non-digit
ret
gethex endp
;
;**************************************************************************
;
; Copy filename from command line into buffer
; Input: DS:SI - pointer to string
; Output: DS:SI - pointer to first character after filename
; Registers changed: AX, CX, SI, DI
;
copyfnam proc near
push es
mov ax,@data
mov es,ax
mov cx,FNAMSIZE - 1 ; don't copy past filename buffer
mov di,offset filename ; put address to filename buffer
cld ; into ES:DI
copyf1: lodsb
or al,al
jz short copyf9 ; check for valid filename character
cmp al,' '
jbe short copyf9
cmp al,7Fh
jae short copyf9
stosb ; copy character
loop short copyf1
copyf9: xor al,al
stosb ; copy terminating null
dec si
pop es
ret
copyfnam endp
;
;**************************************************************************
;
; Read manufacturer ID from Flash-EPROM
; Input: none
; Output: BX - manufacturer ID
; Registers changed: AX, BX
;
readid proc near
mov al,READID_CMD
call sendop ; send READID command
push es
mov es,fseg
mov bx,es:[0000h] ; read manufacturer ID
pop es
mov al,RESET_CMD
call sendop ; reset chip
ret
readid endp
;
;**************************************************************************
;
; Erase whole chip
; Input: none
; Output: carry flag set if error
; Registers changed: AX, BX
;
erase proc near
mov al,ERASE1_CMD
call sendop ; send ERASE1 command
mov al,ERASE2_CMD
call sendop ; send ERASE2 command
xor bx,bx
mov al,0FFh
call waitop ; wait until operation finished
jnc short erase9
mov al,RESET_CMD
call sendop ; reset chip
stc
erase9: ret
erase endp
;
;**************************************************************************
;
; Program Flash-EPROM with contents in read buffer
; Input: BX - offset to next byte to program
; CX - number of bytes to program
; Output: BX - offset to byte after last programmed byte
; carry flag set if error
; Registers changed: AX, BX, CX, SI
;
program proc near
mov si,offset buf
prog1: mov al,PROG_CMD
call sendop ; send programming command
lodsb ; get next byte from buffer
push es
mov es,fseg
mov es:[bx],al ; write next byte into flash EPROM
pop es
call waitop ; wait until programming operation is
jc short prog9 ; completed
inc bx
loop prog1 ; continue with next byte
clc ; return without error
prog9: ret
program endp
;
;**************************************************************************
;
; Send OP code to Flash_EPROM. This involves writing three bytes into the
; flash EPROM at exactly specified locations. See AMD data sheets for
; further information.
; Input: AL - command byte
; Output: none
; Registers changed: none
;
sendop proc near
push es
mov es,fseg
mov byte ptr es:[5555h],0AAh
jcxz @F
@@: jcxz @F
@@: mov byte ptr es:[2AAAh],055h
jcxz @F
@@: jcxz @F
@@: mov byte ptr es:[5555h],al
pop es
ret
sendop endp
;
;**************************************************************************
;
; Wait for the chip to process programming/erase. When programming is in
; progress, the flash EPROM toggles the highest bit, and converts it back
; to it's original value when the programming is done. For a further ex-
; planation of this algorithm see the AMD data sheets.
; Input: AL - programmed byte
; BX - offset to programming location
; Output: carry flag set if error
; Registers changed: AX
;
waitop proc near
push cx
and al,10000000b
push es
mov es,fseg
wait1: mov ah,es:[bx]
mov ch,ah
and ah,10000000b
cmp al,ah
je short wait8
test ch,00100000b
jz short wait1
mov ah,es:[bx]
and ah,10000000b
cmp al,ah
je short wait8
stc
jmp short wait9
wait8: clc
wait9: pop es
pop cx
ret
waitop endp
;
;**************************************************************************
;
end start
syntax highlighted by Code2HTML, v. 0.9.1