mirror of
https://github.com/xcat2/xNBA.git
synced 2024-12-12 06:16:29 +00:00
498 lines
12 KiB
NASM
498 lines
12 KiB
NASM
; Copyright (C) 1997 Markus Gutschke <gutschk@uni-muenster.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.
|
||
|
||
; Prepend this image file to an arbitrary ROM image. The resulting binary
|
||
; can be loaded from any BOOT-Prom that supports the "nbi" file format.
|
||
; When started, the image will reprogram 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.
|
||
|
||
|
||
#define SEGLOW 0xC800 /* lower range for EPROM segment */
|
||
#define SEGHIGH 0xE800 /* upper range for EPROM segment */
|
||
#define AMD_ID 0x2001 /* flash EPROM ID, only support AMD */
|
||
#define ERASE1_CMD 0x80 /* first cmd for erasing full chip */
|
||
#define ERASE2_CMD 0x10 /* second cmd for erasing full chip */
|
||
#define READID_CMD 0x90 /* cmd to read chip ID */
|
||
#define PROG_CMD 0xA0 /* cmd to program a byte */
|
||
#define RESET_CMD 0xF0 /* cmd to reset chip state machine */
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
|
||
.text
|
||
.org 0
|
||
|
||
; .globl _main
|
||
_main: mov ax,#0x0FE0
|
||
mov ds,ax
|
||
mov ax,magic ; verify that we have been loaded by
|
||
cmp ax,#0xE4E4 ; boot prom
|
||
jnz lderr
|
||
jmpi 0x200,0x0FE0 ; adjust code segment
|
||
lderr: mov si,#loaderr
|
||
cld
|
||
lderrlp:seg cs
|
||
lodsb ; loop over all characters of
|
||
or al,al ; string
|
||
jnz lderrnx
|
||
xor ah,ah
|
||
int 0x16 ; wait for keypress
|
||
jmpi 0x0000,0xFFFF ; reboot!
|
||
lderrnx:mov ah,#0x0E ; print it
|
||
mov bl,#0x07
|
||
xor bh,bh
|
||
int 0x10
|
||
jmp lderrlp
|
||
|
||
loaderr:.ascii "The flash EPROM utility has to be loaded from a BOOT-Prom"
|
||
.byte 0xa,0xd
|
||
.ascii "that knows about the 'nbi' file format!"
|
||
.byte 0xa,0xd
|
||
.ascii "Reboot to proceed..."
|
||
.byte 0
|
||
|
||
.org 510
|
||
.byte 0x55,0xAA
|
||
|
||
!----------------------------------------------------------------------------
|
||
|
||
start: mov ax,cs
|
||
mov ds,ax
|
||
mov ax,romdata ; verify that there is an Prom image
|
||
cmp ax,#0xAA55 ; attached to the utility
|
||
jnz resmag
|
||
mov al,romdata+2
|
||
or al,al ; non-zero size is required
|
||
jnz magicok
|
||
resmag: mov si,#badmagic ; print error message
|
||
reset: call prnstr
|
||
xor ah,ah
|
||
int 0x16 ; wait for keypress
|
||
jmpi 0x0000,0xFFFF ; reboot!
|
||
magicok:mov di,#clrline1
|
||
mov si,#welcome ; print welcome message
|
||
inpnew: call prnstr
|
||
inprest:xor bx,bx
|
||
mov cl,#0xC ; expect 4 nibbles input data
|
||
inploop:xor ah,ah
|
||
int 0x16
|
||
cmp al,#0x8 ; <Backspace>
|
||
jnz inpnobs
|
||
or bx,bx ; there has to be at least one input ch
|
||
jz inperr
|
||
mov si,#delchar ; wipe out char from screen
|
||
call prnstr
|
||
add cl,#4 ; compute bitmask for removing input
|
||
mov ch,cl
|
||
mov cl,#0xC
|
||
sub cl,ch
|
||
mov ax,#0xFFFF
|
||
shr ax,cl
|
||
not ax
|
||
and bx,ax
|
||
mov cl,ch
|
||
inploop1:jmp inploop
|
||
inpnobs:cmp al,#0x0D ; <Return>
|
||
jnz inpnocr
|
||
or bx,bx ; zero input -> autoprobing
|
||
jz inpdone
|
||
cmp cl,#-4 ; otherwise there have to be 4 nibbles
|
||
jz inpdone
|
||
inperr: mov al,#7 ; ring the console bell
|
||
jmp inpecho
|
||
inpnocr:cmp al,#0x15 ; <CTRL-U>
|
||
jnz inpnokl
|
||
mov si,di
|
||
call prnstr ; clear entire input and restart
|
||
jmp inprest
|
||
inpnokl:cmp cl,#-4 ; cannot input more than 4 nibbles
|
||
jz inperr
|
||
cmp al,#0x30 ; '0'
|
||
jb inperr
|
||
ja inpdig
|
||
or bx,bx ; leading '0' is not allowed
|
||
jz inperr
|
||
inpdig: cmp al,#0x39 ; '9'
|
||
ja inpnodg
|
||
mov ch,al
|
||
sub al,#0x30
|
||
inpnum: xor ah,ah ; compute new input value
|
||
shl ax,cl
|
||
add ax,bx
|
||
test ax,#0x1FF ; test for 8kB boundary
|
||
jnz inperr
|
||
cmp ax,#SEGHIGH ; input has to be below E800
|
||
jae inperr
|
||
cmp ax,#SEGLOW ; and above/equal C800
|
||
jae inpok
|
||
cmp cl,#0xC ; if there is just one nibble, yet,
|
||
jnz inperr ; then the lower limit ix C000
|
||
cmp ax,#0xC000
|
||
jb inperr
|
||
inpok: mov bx,ax ; adjust bitmask
|
||
sub cl,#4
|
||
mov al,ch
|
||
inpecho:call prnchr ; output new character
|
||
jmp inploop1
|
||
inpnodg:and al,#0xDF ; lower case -> upper case
|
||
cmp al,#0x41 ; 'A'
|
||
jb inperr
|
||
cmp al,#0x46 ; 'F'
|
||
ja inperr
|
||
mov ch,al
|
||
sub al,#0x37
|
||
jmp inpnum
|
||
inpdone:or bx,bx ; zero -> autoprobing
|
||
jnz probe
|
||
mov si,#automsg
|
||
call prnstr
|
||
mov cx,#0x10
|
||
mov bx,#SEGHIGH ; scan from E800 to C800
|
||
autoprb:sub bx,#0x0200 ; stepping down in 8kB increments
|
||
mov di,bx
|
||
call readid
|
||
cmp ax,#AMD_ID
|
||
jz prbfnd
|
||
loop autoprb
|
||
mov si,#failmsg
|
||
nofnd: mov di,#clrline2
|
||
jmp near inpnew ; failure -> ask user for new input
|
||
probe: mov di,bx
|
||
test bx,#0x07FF ; EPROM might have to be aligned to
|
||
jz noalign ; 32kB boundary
|
||
call readid
|
||
cmp ax,#AMD_ID ; check for AMDs id
|
||
jz prbfnd
|
||
mov si,#alignmsg
|
||
call prnstr
|
||
and bx,#0xF800 ; enforce alignment of hardware addr
|
||
noalign:call readid ; check for AMDs id
|
||
cmp ax,#AMD_ID
|
||
jz prbfnd
|
||
mov si,#nofndmsg ; could not find any EPROM at speci-
|
||
call prnstr ; fied location --- even tried
|
||
mov si,#basemsg ; aligning to 32kB boundary
|
||
jmp nofnd ; failure -> ask user for new input
|
||
prbfnd: mov si,#fndmsg
|
||
call prnstr ; we found a flash EPROM
|
||
mov ax,bx
|
||
call prnwrd
|
||
mov si,#ersmsg
|
||
call prnstr
|
||
call erase ; erase old contents
|
||
jnc ersdone
|
||
mov si,#failresmsg ; failure -> reboot machine
|
||
jmp near reset
|
||
ersdone:mov si,#prg1msg ; tell user that we are about
|
||
call prnstr ; to program the new data into
|
||
mov ax,di ; the specified range
|
||
call prnwrd
|
||
mov si,#prg2msg
|
||
call prnstr
|
||
xor dh,dh
|
||
mov dl,romdata+2
|
||
shl dx,#1
|
||
mov ah,dh
|
||
mov cl,#4
|
||
shl ah,cl
|
||
xor al,al
|
||
add ax,di
|
||
call prnwrd
|
||
mov al,#0x3A ; ':'
|
||
call prnchr
|
||
mov ah,dl
|
||
xor al,al
|
||
dec ax
|
||
call prnwrd
|
||
mov al,#0x20
|
||
call prnchr
|
||
mov dh,romdata+2 ; number of 512 byte blocks
|
||
push ds
|
||
mov ax,ds
|
||
add ax,#romdata>>4 ; adjust segment descriptor, so that
|
||
mov ds,ax ; we can handle images which are
|
||
prgloop:mov cx,#0x200 ; larger than 64kB
|
||
xor si,si
|
||
xor bp,bp
|
||
call program ; program 512 data bytes
|
||
jc prgerr ; check error condition
|
||
mov ax,ds
|
||
add ax,#0x20 ; increment segment descriptors
|
||
mov ds,ax
|
||
add di,#0x20
|
||
dec dh ; decrement counter
|
||
jnz prgloop
|
||
pop ds
|
||
mov si,#donemsg ; success -> reboot
|
||
prgdone:call prnstr
|
||
mov si,#resetmsg
|
||
jmp near reset
|
||
prgerr: pop ds ; failure -> reboot
|
||
mov si,#failresmsg
|
||
jmp prgdone
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; READID -- read EPROM id number, base address is passed in BX
|
||
; ======
|
||
;
|
||
; changes: AX, DL, ES
|
||
|
||
readid: mov dl,#RESET_CMD ; reset chip
|
||
call sendop
|
||
mov dl,#READID_CMD
|
||
call sendop ; send READID command
|
||
mov es,bx
|
||
seg es
|
||
mov ax,0x00 ; read manufacturer ID
|
||
mov dl,#RESET_CMD
|
||
jmp sendop ; reset chip
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; ERASE -- erase entire EPROM, base address is passed in BX
|
||
; =====
|
||
;
|
||
; changes: AL, CX, DL, ES, CF
|
||
|
||
erase: mov dl,#ERASE1_CMD
|
||
call sendop ; send ERASE1 command
|
||
mov dl,#ERASE2_CMD
|
||
call sendop ; send ERASE2 command
|
||
xor bp,bp
|
||
mov al,#0xFF
|
||
push di
|
||
mov di,bx
|
||
call waitop ; wait until operation finished
|
||
pop di
|
||
jnc erfail
|
||
mov dl,#RESET_CMD
|
||
call sendop ; reset chip
|
||
stc
|
||
erfail: ret
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; PROGRAM -- write data block at DS:SI of length CX into EPROM at DI:BP
|
||
; =======
|
||
;
|
||
; changes: AX, CX, DL, BP, ES, CF
|
||
|
||
program:mov dl,#PROG_CMD
|
||
call sendop ; send programming command
|
||
lodsb ; get next byte from buffer
|
||
mov es,di
|
||
seg es
|
||
mov byte ptr [bp],al ; write next byte into flash EPROM
|
||
call waitop ; wait until programming operation is
|
||
jc progdn ; completed
|
||
inc bp
|
||
loop program ; continue with next byte
|
||
clc ; return without error
|
||
progdn: ret
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; SENDOP -- send command in DL to EPROM, base address is passed in BX
|
||
; ======
|
||
;
|
||
; changes: ES
|
||
|
||
sendop: mov es,bx
|
||
seg es
|
||
mov byte ptr 0x5555,#0xAA ; write magic data bytes into
|
||
jcxz so1 ; magic locations. This unlocks
|
||
so1: jcxz so2 ; the flash EPROM. N.B. that the
|
||
so2: seg es ; magic locations are mirrored
|
||
mov byte ptr 0x2AAA,#0x55 ; every 32kB; the hardware address
|
||
jcxz so3 ; might have to be adjusted to a
|
||
so3: jcxz so4 ; 32kB boundary
|
||
so4: seg es
|
||
mov byte ptr 0x5555,dl
|
||
ret
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; WAITOP -- wait for command to complete, address is passed in DI:BP
|
||
; ======
|
||
;
|
||
; for details on the programming algorithm, c.f. http://www.amd.com
|
||
;
|
||
; changes: AX, DL, ES, CF
|
||
|
||
waitop: and al,#0x80 ; monitor bit 7
|
||
mov es,di
|
||
wait1: seg es ; read contents of EPROM cell that is
|
||
mov ah,byte ptr [bp] ; being programmed
|
||
mov dl,ah
|
||
and ah,#0x80
|
||
cmp al,ah ; bit 7 indicates sucess
|
||
je waitok
|
||
test dl,#0x20 ; bit 5 indicates timeout/error
|
||
jz wait1 ; otherwise wait for cmd to complete
|
||
seg es
|
||
mov ah,byte ptr [bp] ; check error condition once again,
|
||
and ah,#0x80 ; because bits 7 and 5 can change
|
||
cmp al,ah ; simultaneously
|
||
je waitok
|
||
stc
|
||
ret
|
||
waitok: clc
|
||
ret
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; PRNSTR -- prints a string in DS:SI onto the console
|
||
; ======
|
||
;
|
||
; changes: AL
|
||
|
||
prnstr: push si
|
||
cld
|
||
prns1: lodsb ; loop over all characters of
|
||
or al,al ; string
|
||
jz prns2
|
||
call prnchr ; print character
|
||
jmp prns1
|
||
prns2: pop si
|
||
ret
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; PRNWRD, PRNBYT, PRNNIB, PRNCHR -- prints hexadezimal values, or ASCII chars
|
||
; ====== ====== ====== ======
|
||
;
|
||
; changes: AX
|
||
|
||
prnwrd: push ax
|
||
mov al,ah
|
||
call prnbyt ; print the upper byte
|
||
pop ax
|
||
prnbyt: push ax
|
||
shr al,1 ; prepare upper nibble
|
||
shr al,1
|
||
shr al,1
|
||
shr al,1
|
||
call prnnib ; print it
|
||
pop ax
|
||
prnnib: and al,#0x0F ; prepare lower nibble
|
||
add al,#0x30
|
||
cmp al,#0x39 ; convert it into hex
|
||
jle prnchr
|
||
add al,#7
|
||
prnchr: push bx
|
||
mov ah,#0x0E ; print it
|
||
mov bl,#0x07
|
||
xor bh,bh
|
||
int 0x10
|
||
pop bx
|
||
ret
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
magic: .byte 0xE4,0xE4
|
||
|
||
badmagic:.byte 0xa,0xd
|
||
.ascii "There does not appear to be a ROM image attached to the"
|
||
.ascii "flash EPROM utility;"
|
||
.byte 0xa,0xd
|
||
resetmsg:.ascii "Reboot to proceed..."
|
||
.byte 0
|
||
|
||
welcome:.byte 0xa,0xd
|
||
.ascii "Flash EPROM programming utility V1.0"
|
||
.byte 0xa,0xd
|
||
.ascii "Copyright (c) 1997 by M. Gutschke <gutschk@uni-muenster.de>"
|
||
.byte 0xa,0xd
|
||
.ascii "==========================================================="
|
||
.byte 0xa,0xd
|
||
prompt: .byte 0xa,0xd
|
||
.ascii "Enter base address for AMD29F010 flash EPROM on FlashCard or"
|
||
.byte 0xa,0xd
|
||
.ascii "press <RETURN> to start autoprobing; the base address has"
|
||
.byte 0xa
|
||
clrline1:.byte 0xd
|
||
.ascii "to be in the range C800..E600: "
|
||
.ascii " "
|
||
.byte 0x8,0x8,0x8,0x8
|
||
.byte 0
|
||
|
||
delchar:.byte 0x8,0x20,0x8
|
||
.byte 0
|
||
|
||
automsg:.ascii "autoprobing... "
|
||
.byte 0
|
||
|
||
failmsg:.ascii "failed!"
|
||
basemsg:.byte 0xa
|
||
clrline2:.byte 0xd
|
||
.ascii "Enter base address: "
|
||
.ascii " "
|
||
.byte 0x8,0x8,0x8,0x8
|
||
.byte 0
|
||
|
||
fndmsg: .byte 0xa,0xd
|
||
.ascii "Found flash EPROM at: "
|
||
.byte 0
|
||
|
||
alignmsg:.byte 0xa,0xd
|
||
.ascii "FlashCard requires the hardware address to be aligned to a"
|
||
.byte 0xa,0xd
|
||
.ascii "32kB boundary; automatically adjusting..."
|
||
.byte 0
|
||
|
||
nofndmsg:.byte 0xa,0xd
|
||
.ascii "No AMD29F010 flash EPROM found"
|
||
.byte 0
|
||
|
||
ersmsg: .byte 0xa,0xd
|
||
.ascii "Erasing old contents... "
|
||
.byte 0
|
||
|
||
prg1msg:.ascii "done"
|
||
.byte 0xa,0xd
|
||
.ascii "Programming from "
|
||
.byte 0
|
||
|
||
prg2msg:.ascii ":0000 to "
|
||
.byte 0
|
||
|
||
donemsg:.ascii "done!"
|
||
.byte 0xa,0xd
|
||
.byte 0
|
||
|
||
failresmsg:
|
||
.ascii "failed!"
|
||
.byte 0xa,0xd
|
||
.byte 0
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
.align 16
|
||
.org *-1
|
||
.byte 0x00
|
||
romdata:
|