;---------------------------------------------------------------------------
;
;  Patches to Altair Extended BASIC 4.0 to allow it to run on a Z80
;  (or 8080) processor.
;
;  Mike Douglas, June 16, 2013 
;
;  For the most part, the Z80 is code compatible with the 8080 processor.
;  However, the Z80 sets the parity flag in the status register differently
;  than the 8080, so code which uses the parity flag may not operate
;  properly. For math operations (add, subtract, increment, decrement and
;  compare instructions), the Z80 uses the parity bit to indicate overflow
;  instead of parity. Most 8080 code didn't use the parity bit since
;  there weren't a lot of uses for it, however, Microsoft loved tricky,
;  space saving code in those days and used the parity bit to provide
;  an additional return status flag from some subroutines. These subroutines
;  are the source of Z80 compatibilty problems with Altair BASIC.  
;
;  This file contains patches to Extended BASIC 4.0 to allow it to run on
;  a Z80 processor. Most of the patches jump to subroutines in this file to
;  fix the parity bit after a math operation would have set it incorrectly
;  in a Z80. Unfortunately, there is at least one point remaining in BASIC
;  where the parity bit is checked in which the type of operation prior to
;  the parity check cannot be determined, and therefore, the parity bit 
;  cannot be properly fixed (if it even needs to be). So far, I have not
;  found a BASIC program that triggers this section of code.  
;
;---------------------------------------------------------------------------
;
;  This file contains subroutines to fix the parity bit for several
;  specific combinations of code. For each of these sections of code
;  within BASIC, a patch must be applied to jump to the appropriate
;  "repair" routine in this file. 
;
;  The content of this file is initially at the end of the BASIC image
;  on tape, however, BASIC reclaims RAM after initialization by freeing
;  up the space used by the initialization code (and possibly trig functions
;  based on user responses during initialization). The initialization code
;  is at the end of the BASIC image, so our patch code would be freed and
;  overwritten as well if left in the same location.
;
;  To get around this problem, the initialization code for this file
;  copies the patch subroutines down into the BASIC image immediately
;  following the trig routines. The BASIC code that adjusts the start
;  of RAM (end of BASIC) point after initialization is patched below.
;  This patch puts the start of RAM just past the last address in this
;  file after relocation.
;
;---------------------------------------------------------------------------


;*************************************************************************
;
;  Patch information begins here
;
;*************************************************************************


;------------------------------------------------------------------------
;  To prevent the BASIC memory size initialization from clobbering
;  the code in this file, replace the instruction at location 39fc:
;
;	lxi h,3b5ch
;  with
;	lxi h,3c10h
;------------------------------------------------------------------------


	org	3bb0h		;initial location of this code
;------------------------------------------------------------------------
;
;  patInit - This routine copies the patch subroutines from their
;	current location down into the BASIC image just past the trig
;	functions. The end of BASIC address (start of RAM) is modified
;	to point just past these subroutines.
;    
;  Replace the following instructions at location 3a77:
;	xchg
;	mvi m,0
;  with
;	call patInit
;
;------------------------------------------------------------------------
patInit	equ	$
	push	b		;save registers
	push	h
	lxi	d,pStart	;de=source address
	lxi	h,pDest		;hl=destination address
	mvi	b,pSize		;b=length to copy
pMove	ldax	d		;copy from pSource to pDest
	mov	m,a
	inx	h
	inx	d
	dcr	b
	jnz	pMove

; Patched BASIC code expects the address for the end of BASIC to be
;   in register d.

	pop	h		;restore registers
	pop	b
	lxi	d,pEnd-pOffset	;d=address for end of BASIC
	xchg			;do original xchg
	mvi	m,0		;do original move
	ret

pStart	equ	$		;start of patch subroutines
;-------------------------------------------------------------------------
;
;  doDcr3 - This routine provides proper 8080 results for the following
;    statements found at 169D and 193E:
;
;	dcr a
;	dcr a
;	dcr a
;
;  Patch these three statements as follows:
;
;	call doDcr3-pOffset	;see equates at the end of this file
;
;-------------------------------------------------------------------------
doDcr3	dcr	a		;do the original three dcr instructions
	dcr	a
	dcr	a
	call	fixPrty-pOffset	;fix parity bit
	ret

;--------------------------------------------------------------------------
;
;  doCpi5 - This routine provides proper 8080 results for the following
;    statements. Patch the jpe instruction found at address 322E:
;
;	cpi 5
;	jpe 03288h
;  	(next statement is at address 3231h)
;
;  Patch these two statements as follows:
;
;	cpi 5
;	jmp doCpi5-pOffset	;see equates at the end of this file
;
;--------------------------------------------------------------------------
doCpi5	push	d		;save d for later restore
	mov	d,a		;save a in d
	sui	5		;use sui instead of cpi so a is modified
	call	fixPrty-pOffset
	mov	a,d		;get back original a
	pop	d		;restore d
	jpe	3288h		;do the original compare
	jmp	3231h

;--------------------------------------------------------------------------
;
;  doSbba - This routine provides proper 8080 results for the following
;    statements. Patch starting at the rnz instruction at address 2B1F:
;
;	sbb a
;	rnz
;	inr a
;	ret
;
;  Patch these four statements as follows:
;
;	sbb a
;	jmp	doSbba-pOffset	;see equates at the end of this file
;
;--------------------------------------------------------------------------
doSbba	call	fixPrty-pOffset	;fix parity of the preceding sbb
	rnz			;do the original rnz
	inr	a		;do the original inr
	call	fixPrty-pOffset	;fix the parity bit
	ret			;do the original return

;--------------------------------------------------------------------------
;
;  doSui4 - This routine provides proper 8080 results for the following
;    statements. Patch the jc instruction found at address 1B73:
;
;	sui 004h
;	jc 1B7Bh
;  	(next statement is at address 1B76h)
;
;  Patch these two statements as follows:
;
;	sui 004h
;	jmp doSui4-pOffset	;see equates at the end of this file
;
;--------------------------------------------------------------------------
doSui4	call	fixPrty-pOffset	;fix parity of the preceding sui 4
	jc	1b7bh		;do the original compare
	jmp	1b76h


;--------------------------------------------------------------------------
;
;  fixPrty - Fix Parity Bit
;	This routine will fix the parity bit in the status flags and leave
;	all other status flags unaffected IF the instruction to fix
;	fix modifed the accumulator. For example, subtract, add, inc,
;	dec, etc., will be properly adjusted. However, for compare
;	instructions, parity is computed on the result of the compare
;	subtraction, not the value in A.
;
;  8080 status flags in memory (from PUSH PSW)
;     7  6  5  4  3  2  1  0
;     S  Z  0  AC 0  P  1  C
;
;--------------------------------------------------------------------------
fixPrty	push	b		;save bc for later restore
	push	psw		;move a and status flags into b,c
	pop	b		;   (parity bit in c is wrong)
	ora	a		;real parity flag now correct for 8080
	mov	a,c		;a=flags with parity wrong
	jpe	setPrty-pOffset	;if parity even, go set parity flag
	ani	0fbh		;otherwise, clear the parity flag
	jmp	fixExit-pOffset

setPrty	ori	4		;set the parity flag

fixExit	mov	c,a		;c=final 8080 sbb status flags
	push	b		;put a and flags on stack
	pop	psw		;and put them back in a and in flags
	pop	b		;restore bc
	ret

;-----------------------------------------------------------------------------
;
;  Equates
;
;-----------------------------------------------------------------------------
pEnd	equ	$		;end of code address
pDest	equ	39b5h		;destination address of patch subroutines
pOffset	equ	pStart-pDest	;offset of addresses to final location
pSize	equ	pEnd-pStart	;length of patch code

doDcr3F	equ	doDcr3-pOffset	;final location of doDcr3
doCpi5F	equ	doCpi5-pOffset	;final location of doCpi5
doSbbaF	equ	doSbba-pOffset	;final location of doSbba
doSui4F	equ	doSui4-pOffset	;final location of doSui4

	end
