	fname	"SAVEROM.COM"

; SaveROM.mac, tniASM version

	org	100h

start:
	ld	de,IntroMsg
	ld	c,9
	call	5

	ld	a,(5dh)
	cp	' '
	jr	z,ShowUsage
	ld	a,(6dh)
	cp	' '
	jr	nz,ShowUsage

	call	CheckMem
	call	input

	ld	de,SavingMsg
	ld	c,9
	call	5

	call	CreateFile
	call	SaveFile
	call	CloseFile

	ld	de,SaveOK
	ld	c,9
	call	5
	
	rst	0

ShowUsage:
	ld	de,usage
	ld	c,9
	call	5
	rst	0

input:
	ld	de,PrimMsg
	ld	hl,Prim
	call	do_inp
	ld	hl,(prim)
	ld	a,h
	or	a
	jr	nz,input
	ld	a,l
	cp	4
	jr	nc,input
	ld	(slot),a
	ld	bc,0fcc1h
	add	hl,bc
	ld	a,(hl)
	or	a
	jp	p,no_sec
input2:
	ld	de,SecMsg
	ld	hl,Sec
	call	do_inp
	ld	hl,(Sec)
	ld	a,h
	or	a
	jr	nz,input2
	ld	a,l
	cp	4
	jr	nc,input2
	sla	a
	sla	a
	or	80h
	ld	hl,slot
	or	(hl)
	ld	(hl),a
no_sec:
	ld	de,MegaMsg
	ld	c,9
	call	5
euh:
	ld	c,8
	call	5
	ld	c,1
	cp	'y'
	jr	z,okay
	cp	'Y'
	jr	z,okay
	dec	c
	cp	'n'
	jr	z,okay
	cp	'N'
	jr	nz,euh
okay:
	push	bc
	ld	de,Output
	ld	(de),a
	ld	c,9
	call	5
	pop	bc
	ld	a,c
	ld	(type),a
	or	a
	jp	z,normal
	; assume megarom
	ld	de,SwAdMsg
	ld	hl,swaddr
	call	do_inp
	ld	de,SaAdMsg
	ld	hl,saaddr
	call	do_inp
	ld	de,BlSizeMsg
	ld	hl,bloksize
	call	do_inp
ToHighFB:
	ld	de,FirstMsg
	ld	hl,firstblok
	call	do_inp
	ld	a,(firstblok+1)
	or	a
	jr	nz,ToHighFB
ToHighLB:
	ld	de,LastMsg
	ld	hl,lastblok
	call	do_inp
	ld	a,(lastblok+1)
	or	a
	ret	z
	jr	ToHighLB

do_inp:
	ld	(string),de
	ld	(des),hl
	ld	de,(string)
	ld	c,9
	call	5

	ld	hl,InputStr
	ld	b,4
NumbWrong:
	push	bc
	push	hl
	ld	c,8
	call	5
	pop	hl
	pop	bc
	cp	13
	jr	z,return
	cp	8
	jp	z,bs
	cp	7fh
	jp	z,bs
	ld	c,a
	ld	a,b
	or	a
	jr	z,NumbWrong
	ld	a,c
	sub	'0'
	jr	c,NumbWrong
	cp	10
	jr	c,NumbOk      
	ld	a,c
	cp	'f'+1
	jr	nc,NumbWrong
	and	NOT 32
	cp	'F'+1
	jr	nc,NumbWrong
	sub	'A'
	jr	c,NumbWrong
	add	a,10
NumbOk:
	; echo
	push	af
	push	bc
	push	hl
	ld	e,c
	ld	c,2
	call	5	 
	pop	hl
	pop	bc
	pop	af
	; store it
	ld	(hl),a
	inc	hl
	dec	b
	jr	NumbWrong
return:
	ld	a,b
	cp	4
	jr	z,NumbWrong
	push	bc
	push	hl
	ld	de,crlf
	ld	c,9
	call	5
	pop	hl
	pop	bc
	; do some parsing stuff
	ld	hl,InputStr
	ld	de,0
NextNumb:
	ld	c,(hl)
	ld	a,b
	cp	4
	jr	z,NumbComplete
	inc	b
	inc	hl
	sla	e
	rl	d
	sla	e
	rl	d
	sla	e
	rl	d
	sla	e
	rl	d
	ld	a,e
	or	c
	ld	e,a
	jr	NextNumb
NumbComplete:
	ld	hl,(des)
	ld	(hl),e
	inc	hl
	ld	(hl),d
	ret

bs:
	ld	a,b
	cp	4
	jp	nc,NumbWrong
	push	bc
	push	hl
	ld	c,2
	ld	e,127
	call	5
	pop	hl
	pop	bc
	dec	hl
	inc	b
	jp	NumbWrong

normal:
	ld	de,BeginAdMsg
	ld	hl,firstadd
	call	do_inp
	ld	de,EndAdMsg
	ld	hl,lastadd
	jp	do_inp

CreateFile:
	ld	bc,39
	ld	de,FCB+1
	ld	hl,FCB
	ldir
	ld	hl,5ch
	ld	de,FCB
	ld	bc,12
	ldir
	ld	de,FCB
	ld	c,16h
	call	5
	or	a
	jr	z,CreateOK
	ld	de,CreateErr
	ld	c,9
	call	5
	rst	0
CreateOK:
	ld	hl,1
	ld	(FCB+14),hl
	ld	l,h		; clears HL
	ld	(FCB+33),hl
	ld	(FCB+35),hl
	ret

FileSave:
	push	af
	push	bc
	push	de
	push	hl
	ld	de,FCB
	ld	c,26h
	call	5
	or	a
	jr	nz,SaveError
	pop	hl
	pop	de
	pop	bc
	pop	af
	ret
SaveError:
	ld	de,SaveErr
	ld	c,9
	call	5
	rst	0

CloseFile:
	ld	de,FCB
	ld	c,10h
	call	5
	or	a
	ret	z
	ld	de,SaveErr
	ld	c,9
	call	5
	rst	0

CheckMem:
	ld	hl,(6)
	ld	a,h
	cp	0c0h
	ret	nc
	ld	de,MemoryErr
	ld	c,9
	call	5
	rst	0

SaveFile:
	ld	a,(type)
	or	a
	jr	z,SaveStdROM
	; assume megarom
	; we will use the routine for Standard ROMs for
	; every blok. Iterates from (firstblok) to
	; (lastblok).
	ld	hl,(saaddr)
	ld	(firstadd),hl
	ld	de,(bloksize)
	add	hl,de
	dec	hl
	ld	(lastadd),hl
	; the actual loop
	ld	a,(firstblok)
	ld	e,a
	ld	a,(lastblok)
	ld	d,a
	cp	e
	jr	c,NextBlokI
NextBlok:
	push	de
	ld	a,(slot)
	ld	hl,(swaddr)
	call	14h
	call	SaveStdROM
	pop	de
	inc	e
	ld	a,d
	or	a
	jr	z,Till1
	cp	e
	jr	nc,NextBlok
	ret
Till1:
	ld	a,e
	dec	a
	jr	nz,NextBlok
	ret
NextBlokI:
	push	de
	ld	a,(slot)
	ld	hl,(swaddr)
	call	14h
	call	SaveStdROM
	pop	de
	dec	e
	ld	a,d
	or	a
	jr	z,TillFF
	ld	a,e
	cp	d
	jr	nc,NextBlokI
	ret
TillFF:
	ld	a,e
	inc	a
	jr	nz,NextBlokI
	ret

; this funtion saves memory area (firstadd - lastadd) in 
; slot (slot) to disk

SaveStdROM:
	ld	hl,(firstadd)
	ld	a,h
	cp	40h
	jr	nc,SavePage1
	call	Page0Copy
	ld	hl,(firstadd)
	ld	de,8000h
	add	hl,de
	ex	de,hl
	ld	c,1ah
	call	5
	ld	de,(firstadd)
	ld	hl,(lastadd)
	ld	a,h
	cp	040h
	jr	c,NoOF0
	ld	hl,3fffh
NoOF0:
	or	a
	sbc	hl,de
	inc	hl
	call	FileSave
SavePage1:
	ld	hl,(firstadd)
	ld	a,h
	cp	080h
	jr	nc,SavePage2
	ld	hl,(lastadd)
	ld	a,h
	cp	040h
	ret	c
	call	Page1Copy
	ld	hl,(firstadd)
	ld	a,h
	cp	040h
	jr	nc,NoOF10
	ld	hl,4000h
NoOF10:
	; set write address
	push	hl
	ld	de,4000h
	add	hl,de
	ex	de,hl
	ld	c,1ah
	call	5
	; calc length
	ld	hl,(lastadd)
	ld	a,h
	cp	080h
	jr	c,NoOF11
	ld	hl,7fffh
NoOF11:
	pop	de
	or	a
	sbc	hl,de
	inc	hl
	call	FileSave	
SavePage2:
	ld	hl,(firstadd)
	ld	a,h
	cp	0c0h
	jr	nc,SavePage3
	ld	hl,(lastadd)
	ld	a,h
	cp	080h
	ret	c
	call	Page2Copy
	ld	hl,(firstadd)
	ld	a,h
	cp	080h
	jr	nc,NoOF20
	ld	hl,8000h
NoOF20:
	; set write address
	push	hl
	ex	de,hl
	ld	c,1ah
	call	5
	; calc length
	ld	hl,(lastadd)
	ld	a,h
	cp	0c0h
	jr	c,NoOF21
	ld	hl,0bfffh
NoOF21:
	pop	de
	or	a
	sbc	hl,de
	inc	hl
	call	FileSave
SavePage3:
	ld	hl,(lastadd)
	ld	a,h
	cp	0c0h
	ret	c
	call	Page3Copy
	ld	hl,(firstadd)
	ld	a,h
	cp	0c0h
	jr	nc,NoOF30
	ld	hl,0c000h
NoOF30:
	; set write address
	push	hl
	ld	de,4000h
	or	a
	sbc	hl,de
	ex	de,hl
	ld	c,1ah
	call	5
	; calc length
	ld	hl,(lastadd)
	pop	de
	or	a
	sbc	hl,de
	inc	hl
	jp	FileSave

; These functions copy memory pages 0, 1, 2 or 3 from
; (slot) to page 2 RAM. Used for saving them.

Page0Copy:
	di
	ld	a,(0f342h)
	ld	h,40h
	call	024h
	ld	a,(0f343h)
	ld	h,80h
	call	024h
	ld	hl,MoveIt
	ld	de,4000h
	ld	bc,100h
	ldir
	jp	4000h
MoveIt:
	di
	ld	a,(slot)
	bit	7,a
	jr	nz,SubSlots
	and	3
	ld	c,a
	in	a,(0a8h)
	ld	(4100h),a
	and	0fch
	or	c
	out	(0a8h),a
	ld	hl,0
	ld	de,8000h
	ld	bc,4000h
	ldir
	ld	a,(4100h)
	out	(0a8h),a
	ei
	ret
SubSlots:
	ld	e,a
	ld	a,(0ffffh)
	cpl
	ld	c,a
	in	a,(0a8h)
	ld	b,a
	ld	(4100h),bc	
	ld	a,e
	and	3
	ld	d,a
	rrca
	rrca
	or	d
	ld	d,a
	ld	a,b
	and	03ch
	or	d
	out	(0a8h),a
	ld	a,(0ffffh)
	cpl
	and	0fch
	ld	d,a
	ld	a,e
	rrca
	rrca
	and	3
	or	d
	ld	(0ffffh),a
	ld	hl,0
	ld	de,8000h
	ld	bc,4000h
	ldir
	ld	bc,(4100h)
	ld	a,b
	out	(0a8h),a
	ld	a,c
	ld	(0ffffh),a
	ei
	ret
Page1Copy:
	di
	ld	a,(slot)
	ld	h,40h
	call	024h
	ld	a,(0f343h)
	ld	h,80h
	call	024h
	ld	hl,4000h
	ld	de,8000h
	ld	bc,4000h
	ldir
	ld	a,(0f342h)
	ld	h,40h
	call	024h
	ei
	ret
Page2Copy:
	di
	ld	a,(slot)
	ld	h,80h
	call	024h
	ld	hl,8000h
	ld	de,4000h
	ld	bc,4000h
	ldir
	ld	a,(0f343h)
	ld	h,80h
	call	024h
	ld	hl,4000h
	ld	de,8000h
	ld	bc,4000h
	ldir
	ei
	ret
Page3Copy:
	di
	ld	a,(0f343h)
	ld	h,80h
	call	024h
	ld	a,(slot)
	bit	7,a
	jr	nz,SubSlots2
	rrca
	rrca
	and	0c0h
	ld	c,a
	in	a,(0a8h)
	ld	(temp),a
	and	03fh
	or	c
	out	(0a8h),a
	ld	hl,0c000h
	ld	de,08000h
	ld	bc,04000h
	ldir
	ld	a,(temp)
	out	(0a8h),a
	ei
	ret
SubSlots2:
	ld	c,a
	rrca
	rrca
	and	0c0h
	ld	b,a
	ld	a,(0ffffh)
	cpl
	ld	(temp+1),a
	in	a,(0a8h)
	ld	(temp),a
	and	03fh
	or	b
	out	(0a8h),a
	ld	a,(0ffffh)
	cpl
	and	03fh
	ld	b,a
	ld	a,c
	rlca
	rlca
	rlca
	rlca
	and	0c0h
	or	b
	ld	(0ffffh),a
	ld	hl,0c000h
	ld	de,08000h
	ld	bc,04000h
	ldir
	ld	a,(temp)
	out	(0a8h),a
	ld	a,(temp+1)
	ld	(0ffffh),a
	ei
	ret

; "temp" variables
string: 	dw	0
des:		dw	0
temp:		dw	0
; information about cartridge to save
Prim:		dw	0
Sec:		dw	0
slot:		db	0
type:		db	0
swaddr: 	dw	0
saaddr: 	dw	0
bloksize:	dw	0
firstblok:	dw	0
lastblok:	dw	0
firstadd:	dw	0
lastadd:	dw	0

; strings

Output: 	db	0
crlf:		db	13,10,'$'
IntroMsg:	db	'SaveROM 1.1',13,10,'By Sean Young 1997, 1998, '
		db	'BiFi 2007',13,10,10,'$'
PrimMsg:	db	'Primary Slot: $'
SecMsg: 	db	'Secondary Slot: $'
MegaMsg:	db	'MegaROM (y/n)? $'
SwAdMsg:	db	'Switch Address: $'
SaAdMsg:	db	'Save Address: $'
BlSizeMsg:	db	'Block Size: $'
FirstMsg:	db	'First Block: $'
LastMsg:	db	'Last Block: $'
BeginAdMsg:	db	'Begin Address: $'
EndAdMsg:	db	'End Address: $'
InputStr:	db	'0000',13,10
Usage:		db	'Usage:',13,10,10
		db	'     saverom <filename>',13,10,'$'
SavingMsg:	db	13,10,'Saving...',13,10,'$'
CreateErr:	db	'File creation error!',13,10,'$'
MemoryErr:	db	'Not enough memory!',13,10,'$'
SaveErr:	db	'Save error!',13,10,'$'
SaveOK: 	db	'Save completed.',13,10,'$'
FCB:		db	0
