summaryrefslogtreecommitdiffstats
path: root/contrib/flashimg/flashimg.asm
blob: 7a37ed5409b0e3cab927ebc62cf0f6b7257f6a1c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
; 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: