;************************************************************************** ;* ;* FLASH - Program FlashCard flash EPROM ;* ;* Module: flash.asm ;* Purpose: Program FlashCard flash EPROM ;* Entries: start ;* ;************************************************************************** ;* ;* Copyright (C) 1995-2003 Gero Kuhlmann ;* ;* 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 ' 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