execbase=4
allocmem=-198
freemem=-210
memf_public=1
memf_clear=$10000
openlibrary=-552
closelibrary=-414
open=-30
close=-36
read=-42
write=-48
mode_old=1005
mode_new=1006
output=-60
lock=-84
unlock=-90
examine=-102

Go:	move.l a0,commandlineaddress
		
	move.l execbase,a6
	moveq #33,d0		;version (1.2 or greater)
	lea dosname(pc),a1
	jsr openlibrary(a6)
	tst.l d0
	bne.s getcli
	moveq #1,d0		;error code
	rts
	
getcli:	move.l d0,dosbase
	move.l d0,a6
	jsr output(a6)			; Call output function
	move.l d0,clihandle		; Find handle of CLI

	cmp.b #$0a,(a0)		;is it an end-of-line command?
	beq help

	move.l #300,d0			;length of infoblock
	bsr allocate
	tst.l d0
	bne.s .gotmem
	move.l #err3,d2
	move.l #err3end-err3,d3
	bsr print			;print error message
.gotmem	move.l d0,infoblock

	move.l #49486,d0		;length of larger (KGB) file
	bsr allocate
	tst.l d0
	bne.s .gotmm2
	move.l #err3,d2
	move.l #err3end-err3,d3
	bsr print			;print error message
.gotmm2	move.l d0,filemem
	move.l d0,loadadr	

	move.l commandlineaddress,a0
preparse:
	cmp.b #"-",(a0)+	;skip over "MK" etc
	beq gotminus
	cmp.b #$0a,(a0)
	bne.s preparse
	bra help

Parser:	move.l commandlineaddress,a0
	cmp.b #$0a,(a0)
	beq convertyet
.parse	cmp.b #" ",(a0)+	;find command
	bne.s command
	cmp.b #$0a,(a0)
	bne.s .parse
	bra convertyet
	
command:
	sub.l #1,a0
	cmp.b #"-",(a0)+
	bne.s dest

gotminus
	move.b (a0)+,d1		;K|M|I
	cmp.b #$0a,(a0)
	beq help
	bsr uppercase

K:	cmp.b #"K",d1
	bne.s M
	move.l #49486,d6
	move.w #1,from
	bra fromfile

M:	cmp.b #"M",d1
	bne.s I
	move.l #49179,d6
	add.l #105,loadadr		;read in to this adr
	move.w #2,from
	bra fromfile
		
I:	cmp.b #"I",d1
	bne help
	cmp.b #"o",1(a0)
	beq IMirage
	cmp.b #"O",1(a0)
	beq IMirage
	bra IKGB

dest:	sub.l #1,a0
	tst.w from	;if got source then this could be destination file
	beq help
	tst.w to	;if got destination already then exit
	bne help
	cmp.w #1,from	;KGB source?
	beq toM		;then destination is Mirage
	bra toK		;else KGB is

IKGB:	;determine interrupt type and write words in temp store
	;-I OFF|5|10|25|50
	moveq.l #0,d1 
	move.b (a0)+,d1
	cmp.b #$0a,(a0)
	beq .5
	cmp.b #" ",(a0)
	beq .5
.off	cmp.b #"o",d1
	bne.s .byte2
	move.b (a0)+,d1
	bsr uppercase
	lsl.w #8,d1
	move.b (a0)+,d1
	bsr uppercase
	cmp.w #"FF",d1
	bne help
	move.l #$00000,Kint
	bra Iout
	
.5	cmp.b #"5",d1
	bne help
	move.l #$1000a,Kint
	bra Iout	
	
.byte2	lsl.w #8,d1
	move.b (a0)+,d1
	cmp.b #$0a,(a0)
	beq .10
	cmp.b #" ",(a0)
	bne help
	
.10	cmp.w #"10",d1
	bne.s .25
	move.l #$20005,Kint
	bra Iout
	
.25	cmp.w #"25",d1
	bne.s .50	
	move.l #$30002,Kint
	bra Iout
	
.50	cmp.w #"50",d1
	bne help
	move.l #$40001,Kint
	bra Iout
	
IMirage:;determine interrupt mode and whether ON/OFF then store
	;-I0|1|2+ON|OFF	.. therefore either 3 or 4 bytes long
	moveq.l #0,d1
	move.b (a0)+,d1	;get mode number
	lsl.w #8,d1
	move.b (a0)+,d1
	bsr uppercase
	lsl.l #8,d1
	move.b (a0)+,d1
	bsr uppercase
	cmp.b #$0a,(a0)
	beq.s .0on
	cmp.b #" ",(a0)
	beq.s .0on
	lsl.l #8,d1
	move.b (a0)+,d1
	bsr uppercase
.0off	cmp.l #"0OFF",d1
	bne.s .1off
	move.w #$0000,Mint
	bra Iout
.1off	cmp.l #"1OFF",d1
	bne.s .2off
	move.w #$0001,Mint
	bra Iout
.2off	cmp.l #"2OFF",d1
	bne help
	move.w #$0002,Mint
	bra Iout
	
.0on	cmp.l #"0ON",d1
	bne.s .1on
	move.w #$ff00,Mint
	bra.s Iout
.1on	cmp.l #"1ON",d1
	bne.s .2on
	move.w #$ff01,Mint
	bra.s Iout
.2on	cmp.l #"2ON",d1
	bne help
	move.w #$ff02,Mint

Iout	cmp.b #$0a,(a0)
	beq convertyet		
	move.l a0,commandlineaddress
	bra Parser
	
fromfile:
	move.l a0,fileold	;adr of source file path/name
	move.l #fileold,a1
	bsr putterm
	move.l a0,commandlineaddress	
	move.l dosbase,a6
	move.l fileold,d1
	move.l #-2,d2		;read only
	jsr lock(a6)
	bsr source
.gotlok	move.l d0,d1
	move.l d0,filelock
	move.l infoblock,d2
	jsr examine(a6)
	bsr source
	move.l filelock,d1
	jsr unlock(a6)
.gotinf	move.l infoblock,a1
	add.l #124,a1
	move.l (a1),d4
	cmp.l d6,d4		;length of type of file in d6
	beq.s .sizeok
	cmp.l #49486,d6
	bne.s .msize
	move.l #err1,d2
	move.l #err1end-err1,d3
	bra.s .mksize
.msize	move.l #err2,d2
	move.l #err2end-err2,d3
.mksize	bsr print
	bra OUT
	rts
.sizeok	move.l fileold,d1
	move.l #mode_old,d2
	jsr open(a6)
	bsr source
	move.l d0,fileoldhandle
.read	move.l d0,d1
	move.l loadadr,d2
	move.l d6,d3		;length of file to d3
	jsr read(a6)
	bsr source
.out	move.l fileoldhandle,d1	
	jsr close(a6)
*	bsr source	;this fails for source RAM: files (why???)
	tst.w eol
	beq Parser
	bra convertyet
		
toK	tst.w to
	bne.s opend	;if already got a destination file then next command  
	move.w #1,to
	bra.s tofile
	
toM	tst.w to
	bne.s opend
	move.w #2,to
	
tofile:
	move.l a0,filenew
	move.l #filenew,a1
	bsr putterm
	move.l a0,commandlineaddress
	move.l dosbase,a6
	move.l filenew,d1
	move.l #mode_new,d2
	jsr open(a6)
	bsr destination
	move.l d0,filenewhandle	
opend	tst.w eol
	beq Parser

convertyet:	
	tst.w from
	beq help
	tst.w to
	bne .which
	move.w #3,d0	;if no output file, then output=input
	sub.w from,d0
	move.w d0,to	;to = not from
	
	move.l fileold,filenew	;reopen original file for output
	move.l dosbase,a6
	move.l filenew,d1
	move.l #mode_new,d2
	jsr open(a6)
	bsr destination
	move.l d0,filenewhandle

.which	cmp.w #1,from
	beq K2M

M2K:	move.l filemem,a0
	add.l #$c084,a0		;point to after 48k mem
	move.l filemem,a1
	add.l #105,a1		;point to Mirage register data
	move.b #$a,$85(a0)	;?
	move.b #1,$87(a0)	;for Colour|B/W
	move.l Kint,$88(a0)	;Interrupt mode
	move.b #1,$8d(a0)	;?
	move.b #1,$8e(a0)	;?
	move.b #1,$91(a0)	;Colour mode
	move.b #1,$93(a0)	;?
	move.b #$7d,$95(a0)	;?
	move.b $e(a1),$96(a0)	;b
	move.b $d(a1),$97(a0)	;c
	move.b 6(a1),$98(a0)	;b'	
	move.b 5(a1),$99(a0)	;c'	
	move.b $c(a1),$9a(a0)	;d	
	move.b $b(a1),$9b(a0)	;e	
	move.b 4(a1),$9c(a0)	;d'	
	move.b 3(a1),$9d(a0)	;e'	
	move.b $a(a1),$9e(a0)	;h	
	move.b 9(a1),$9f(a0)	;l
	move.b 2(a1),$a0(a0)	;h'
	move.b 1(a1),$a1(a0)	;l'
	move.b $12(a1),$a2(a0)	;ix high	
	move.b $11(a1),$a3(a0)	;ix low
	move.b $10(a1),$a4(a0)	;iy high
	move.b $f(a1),$a5(a0)	;iy low
	move.b (a1),$a6(a0)	;i
	move.b $14(a1),$a7(a0)	;r
	move.b 7(a1),d0
	bsr f2sr
	move.w d1,$a8(a0)	;f'
	move.b 8(a1),$ab(a0)	;a'		
	move.b $16(a1),$ad(a0)	;a
	move.b $15(a1),d0
	bsr f2sr	
	move.w d1,$b0(a0)	;f
	moveq.l #0,d0
	movep $18(a1),d0
	move.b $17(a1),d0	;get SP
	move.w d0,d1
	add.w #2,d1		;update SP
	move.w d1,$b8(a0)	;new SP
	sub.w #$4000,d0		;first 16k (rom)
	move.l filemem,a1
	add.l #$84,a1		;point to 48k ram
	add.l d0,a1		;a1=sp
	movep 1(a1),d0
	move.b (a1),d0		;get PC from stack
	move.w d0,$b4(a0)	;pc	
	
	move.l #32,d0		;move ROM to start of file
	lea ROM(pc),a1
	move.l filemem,a0
.loop	move.l (a1)+,(a0)+
	dbf d0,.loop
	
*** now save the file
	move.l filenewhandle,d1
	move.l filemem,d2
	move.l #49486,d3
	move.l dosbase,a6
	jsr write(a6)
	bsr destination
	bra OUT	

f2sr:	;d0=f
	move.w #$2000,d1		;pseudo SR
.c	btst #0,d0
	beq.s .v
	bset #0,d1		;set C
.v	btst #2,d0
	beq.s .z
	bset #1,d1		;set V
.z	btst #6,d0
	beq.s .n
	bset #2,d1		;set Z
.n	btst #7,d0
	beq.s .out
	bset #3,d1		;set N ('S' in Spectrum jargon)
.out	rts
	

K2M:	move.l filemem,a0
	add.l #105,a0
	move.l filemem,a1
	add.l #$c084,a1
	move.b $a6(a1),(a0)	;i
	move.b $a1(a1),1(a0)	;l'
	move.b $a0(a1),2(a0)	;h'
	move.b $9d(a1),3(a0)	;e'
	move.b $9c(a1),4(a0)	;d'
	move.b $99(a1),5(a0)	;c'
	move.b $98(a1),6(a0)	;b'
	move.w $a8(a1),d0
	bsr sr2f
	move.b d1,7(a0)		;f'
	move.b $ab(a1),8(a0)	;a'
	move.b $9f(a1),9(a0)	;l
	move.b $9e(a1),$a(a0)	;h
	move.b $9b(a1),$b(a0)	;e
	move.b $9a(a1),$c(a0)	;d
	move.b $97(a1),$d(a0)	;c
	move.b $96(a1),$e(a0)	;b
	move.b $a5(a1),$f(a0)	;iy low
	move.b $a4(a1),$10(a0)	;iy high
	move.b $a3(a1),$11(a0)	;ix low
	move.b $a2(a1),$12(a0)	;ix high
	move.b Mint,$13(a0)	;bit 2 set if interrupts enabled 
	move.b $a7(a1),$14(a0)	;r
	move.w $b0(a1),d0
	bsr sr2f
	move.b d1,$15(a0)	;f
	move.b $ad(a1),$16(a0)	;a
	moveq.l #0,d0
	move.w $b8(a1),d0
	move.w d0,d1
	subq.w #2,d1		;update SP
	move.b d1,$17(a0)	;sp low
	lsr.w #8,d1
	move.b d1,$18(a0)	;sp high
	move.b Mint+1,$19(a0)	;interrupt mode (0,1 or 2)
	move.b #0,$1a(a0)	;filler (not used)
	sub.w #$4002,d0		;discard 16k rom and update SP
	move.w $b4(a1),d1	;PC
	move.l filemem,a1
	add.l #$84,a1
	add.l d0,a1		;a1=2nd free space on stack
	move.b d1,(a1)+		;put PCl on stack
	lsr.w #8,d1
	move.b d1,(a1)		;put PCh on stack
	
*** now save the file
	move.l filenewhandle,d1
	move.l filemem,d2
	add.l #105,d2
	move.l #49179,d3
	move.l dosbase,a6
	jsr write(a6)
	bsr destination
	bra OUT

sr2f:	;d0=sr
	moveq #0,d1
.c	btst #0,d0
	beq.s .v
	bset #0,d1
.v	btst #1,d0
	beq.s .z
	bset #2,d1
.z	btst #2,d0
	beq.s .n
	bset #6,d1
.n	btst #3,d0
	beq.s .out
	bset #7,d1
.out	rts

		
uppercase:
	cmp.b #"a",d1
	blt.s .done
	sub.b #32,d1	;convert to UPPERCASE
.done	rts	

putterm:	;put the zero byte file terminator at end of file name
	move.b (a0)+,d1
	cmp.b #34,d1	;is it a quote (")
	bne.s .space
	add.l #1,(a1)	;don't include quote in file name
	move.w #34,d2
	cmp.b #$0a,(a0)	;is it just a quote (illegal)?
	addq #1,a0
	beq .put0
	bra.s .findend
.space	move.w #32,d2
	cmp.b #$0a,(a0)	;is it a single letter file name followed by a $0A?
	bne.s .findend
	addq #1,a0	;now $00 put in place of $0A
	bra .put0
.findend
	move.b (a0)+,d1
	cmp.b d2,d1
	beq.s .put0
	cmp.b #$0a,(a0)	;EOL?
	bne.s .findend
	addq #1,a0
	move.w #1,eol	;end of command line reached
.put0	move.b #0,-1(a0)	;a zero means end of file name
	rts

allocate:	;length in d0, on return d0=adr
	move.l execbase,a6
	move.l #memf_clear+memf_public,d1
	jsr allocmem(a6)
	rts
	
help:
	move.l #helpy,d2
	move.l #helpend-helpy,d3
	bsr print			;print error message
OUT:	
	move.l filenewhandle,d1
	tst.l d1
	beq.s closelib
	move.l dosbase,a6
	jsr close(a6)

closelib:
	move.l 4,a6
	move.l dosbase,a1
	cmp.l #0,a1
	beq.s freememory
	jsr closelibrary(a6)
	
freememory:
	move.l filemem,a1
	cmp.l #0,a1
	beq.s .notallocated1
	move.l #49486,d0
	jsr freemem(a6)
.notallocated1
	move.l infoblock,a1
	cmp.l #0,a1
	beq.s .notallocated2
	move.l #300,d0
	jsr freemem(a6)
.notallocated2
	moveq #0,d0
	rts

	
dosname:
	dc.b "dos.library",0
	even
dosbase:
	dc.l 0
clihandle:
	dc.l 0
fileold:
	dc.l 0
fileoldhandle:
	dc.l 0
filenew:
	dc.l 0
filenewhandle:
	dc.l 0
	
ROM:	incbin df1:ROM$84.Binary	;last 132 ($84) bytes of Speccy ROM
	even				;used at start of KGB files

print:	move.l dosbase,a6
	move.l clihandle,d1
	jsr write(a6)
	rts

err1:	dc.b "Invalid LENGTH - KGB file must be 49486 bytes long",$a
err1end:even

err2:	dc.b "Invalid LENGTH - Mirage file must be 49179 bytes long",$a
err2end:even

err3:	dc.b "Could not Allocate enough memory",$a
err3end:even

source:
	tst.l d0
	bne.s .out
	move.l #err4,d2
	move.l #err4end-err4,d3
	bsr print			;print error message
	tst.l (sp)+			;adjust return address
	bra OUT
.out	rts

err4:	dc.b "Error occured while accessing source file",$a
err4end:even

destination:
	tst.l d0
	bne.s .out
	move.l #err5,d2
	move.l #err5end-err5,d3
	bsr print			;print error message
	tst.l (sp)+			;adjust return address
	bra OUT
.out	rts

err5:	dc.b "Error occured while accessing Destination file",$a
err5end:even

helpy:	dc.b $a
	dc.b $9b,"1;2;4mSpectrum File Format Converter",$9b,"0m  - ",$9b,"1mTC",$9b,"0m(92) v1.04",$a,$a
	dc.b "This programs converts between KGB and Mirage format",$a
	dc.b "KGB files must be 49486 bytes long, Mirage files must be 49179 bytes long.",$a,$a
	dc.b $9b,"1mUSAGE:",$9b,"0m >MK -K|M[",$22,"]source[",$22,"] [[",$22,"]destination[",$22,"]] [-Ioff|5|10|25|50]  (for KGB)",$a
	dc.b "                                                [-I0|1|2+on|off] (for Mirage)",$a
	dc.b "      ",$9b,"3m(KGB interrupts default to OFF and Mirage to 1ON - Mode 1, ON)",$9b,"0m",$a
helpend:even
	
from:	dc.w 0	;0=no format, 1=KGB, 2=Mirage
to:	dc.w 0	;same as above
Kint:	dc.w 0,0;4,1=on	,default is interrupt OFF
Mint:	dc.w $ff01	;$0000=off, $ff01=on
filelock:
	dc.l 0
infoblock:
	dc.l 0	;adr of file infoblock
filemem:
	dc.l 0	;adr of mem for file
temp:	dc.l 0
commandlineaddress:
	dc.l 0
loadadr:dc.l 0
eol:	dc.w 0
