Поиск по сайту:

 


По базе:  

микроэлектроника, микросхема, микроконтроллер, память, msp430, MSP430, Atmel, Maxim, LCD, hd44780, t6963, sed1335, SED1335, mega128, avr, mega128  
  Главная страница > Программы

реклама

 




Мероприятия:




;===============================================================================
;  MSP430 Floating Point Package   Version 4.0
;
;  Basic Arithmetic Operations
;  Texas Instruments Deutschland
;  Date:    January, 13 1997
;  Version: 4.12  23.3.97 LB
;	  3.05	Sign generation for MPY/DIV in INITxx
;	  3.06	Completion unified
;	  3.07	Special treatment for smallest neg. number removed
;	  3.08	Error corrected (argument on TOS, least significant bit)
;	  3.09	Common normalize part for all 4 Basic Arithm. Operations
;	  3.10	FLT_CMP error corrected LB
;	  4.01	Hardware Multiplier included, comment enhancement
;	  4.12	FLT_CMP return: RPARG = RPRES = SP  (normal return)
;  Adapted to standalone FPP: 5/95  Franz Graf FRGR
;  Version: 1.01  Sep,28 1995 LB JC -> JHS where better descriptive
;  Version: 2.0   Nov,2  1995 by Stephan Bork (single file for both versions)
;  Version: 3.0   Dec,31 1995 by Lutz Bierl (shorter code and run time)
;  Version: 4.0   Dec,6  1996 by Lutz Bierl (inclusion of HW-Multiplier)
;==============================================================================
;  This Floating Point Package can handle two floating point number formats:
;  - .FLOAT  format (24 bit mantissa, 32 bit numbers)
;  - .DOUBLE format (40 bit mantissa, 48 bit numbers)
;  To select the required format the variable DOUBLE is used:
;  For 32 bit numbers set DOUBLE to 0   (DOUBLE .set 0)
;  For 48 bit numbers set DOUBLE to 1   (DOUBLE .set 1)
;
;  The definition of the registers is made in FPPDEF04.ASM
;  The definition of the variables is made in the customer's software.
;  This must be done before the FPPDEF04.ASM file is inserted.
;
; DOUBLE	  .set	  1		  ; 1: .DOUBLE	    0: .FLOAT      (default 0)
; SW_UFLOW	  .set	  1		  ; 1: Underflow is error   0: not (default 0)
; SW_RND	  .set	  0		  ; 1: Conversion rounds result	   (default 1)
; HW_MPY	  .set	  1		  ; 1: Hardware multiplier is used (default 0)
;
;  NOTE: the variables DOUBLE, SW_RND, SW_UFLOW, and HW_MPY must be defined
;	 within the user's software. They are predefined inside of the FPP.
;
;  The Floating Point Package V4.0 supports the following operations:
;
;  FLT_ADD         Addition          FLT_SAV    Save used registers
;  FLT_SUB         Subtraction       FLT_REC    Restore used registers
;  FLT_MUL         Multiplication    FLT_END	Common termination
;  FLT_DIV         Division
;  FLT_CMP         Comparison
;
;  Common Conventions:
;  -------------------
; - The arguments handed over from the main program to the floating point
;   package by pointers are not affected during operation (except if one
;   of the arguments is the last result on TOS which is overwritten with
;   the new result).
; - The special implementation of the FPP (nearly no subroutines, jumps
;   instead) results from the contradictionary claims to have a ROM-space
;   and speed optimized software package.
; - HELP.7 means bit 7 of the word or byte HELP
; - If an error occurs during an operation an errorcode is written to the
;   statusregister (SR). The results are shown for the .DOUBLE format
;
;  +--------------------+-------------------+------------------------+
;  | Error		|    Statusregister |	 Result 	     |
;  +--------------------+-------------------+------------------------+
;  | No error           |    N=0, C=x, Z=x  |	 xxxx xxxx xxxx      |
;  | Overflow positive  |    N=1, C=1, Z=1  |	 FF7F FFFF FFFF      |
;  | Overflow negative  |    N=1, C=1, Z=0  |	 FFFF FFFF FFFF      |
;  | Underflow          |    N=1, C=0, Z=0  |	 0000 0000 0000      |
;  | Division by zero   |    N=1, C=0, Z=1  |	 FF7F FFFF FFFF or   |
;  |                    |				    |	 FFFF FFFF FFFF      |
;  +--------------------+-------------------+------------------------+
;
;  The '.DOUBLE' format
;  --------------------
;  The '.DOUBLE' format represents a floating point number with 48 bits.
;  The 40 least significant bits (LSBs) represent the mantissa and the
;  8 most significant bits (MSBs) represent the exponent.
;
;  MSB.47         .39                              LSB.0
;  |-----------------------------------------------------|
;  | e.7 ... e.0 | sign | m.38 ..................... m.0 |
;  |--------------------.--------------------------------|
;   exponent E			mantissa M
;
;  Definitions: E = exponent of the floating point number
;	      M = mantissa of the floating point number (2 > M >= 1)
;	   sign = sign of the floating point number	(0 = pos  1 = neg)
;	      m = a bit of the mantissa (valency considered)
;	      e = a bit of the exponent (valency considered)
;      .0 to .38  bits corresponding to their valency
;
;  NOTE: this is NOT the usual two's complement notation!
;	 For more information see "MSP430 Family Floating Point Package" or
;	 the "Metering Application Report".
;
;  Zero is represented by 40 zero bits.
;--------------------------------------------------------------------------
;
;  The '.FLOAT' format
;  --------------------
;  The '.FLOAT' format represents a floating point number with 32 bits.
;  The 24 least significant bits (LSBs) represent the mantissa and the
;  8 most significant bits (MSBs) represent the exponent.
;
;  MSB.31         .23                              LSB.0
;  |-----------------------------------------------------|
;  | e.7 ... e.0 | sign | m.22 ..................... m.0 |
;  |--------------------.--------------------------------|
;   exponent E			mantissa M
;
;  Zero is represented by 32 zero bits.
;======================================================================
;  Conventions for the 4 basic arithmetical operations:
;
;  - The arguments are not affected by the operation (except if at TOS)
;  - The pointers RPARG and RPRES always point to the MSWord. (exp. + MSBs)
;  - After the operation both pointers and the stack pointer (SP) point
;    to the MSword of the result to ease the following calls.
;
;  Calling conventions (shown for .DOUBLE format): VAL1 x VAL2 - VAL3
;
;     CALL	#FLT_SAV     ; Save registers
;     SUB	#(ML/8)+1,SP ; Allocate stack for result
;     MOV	#VAL1,RPRES  ; Load result pointer with VAL1 address MSB
;     MOV	#VAL2,RPARG  ; Load argum. pointer with VAL2 address MSB
;     CALL	#FLT_MUL     ; Compute and load pointers with res.address
;     MOV	#VAL3,RPARG  ; Load argum. pointer with VAL3 address MSB
;     CALL	#FLT_SUB     ; Compute and load pointers with res.address
;     ...	....	     ; Continue with calculations
;     POP	RESULTMSB    ; Free stack from result: MSBs
;     POP	RESULTMID    ; Store result's middle part
;     POP	RESULTLSB    ; Store result's LSB part
;     CALL	#FLT_REC     ; Restore used registers
;     ...	....	     ; Continue with main program
;
; VAL1 .DOUBLE	 3003.70     ; Constants for calculations
; VAL2 .DOUBLE	 123.45E-1
; VAL3 .DOUBLE	 876.54
;
;  BEGIN OF THE FLOATING POINT PACKAGE
;
; Floating Point Save and Recall Subroutines

    .if DOUBLE=1
FLT_SAV PUSH	HELP		; Save used registers
	PUSH	ARG1_MSB	;
	PUSH	ARG1_MID	;
	PUSH	ARG1_LSB	;
	PUSH	ARG2_MSB	;
	PUSH	ARG2_MID	;
	PUSH	ARG2_LSB	;
	PUSH	RESULT_MSB	;
	PUSH	RESULT_MID	;
	PUSH	RESULT_LSB	;
	PUSH	22(SP)		; Copy return address to TOS
	MOV	COUNTER,22(SP)	; Overwrite previous return address
	RET			;
    .else
FLT_SAV PUSH	HELP		; Save used registers
	PUSH	ARG1_MSB	;
	PUSH	ARG1_LSB	;
	PUSH	ARG2_MSB	;
	PUSH	ARG2_LSB	;
	PUSH	RESULT_MSB	;
	PUSH	RESULT_LSB	;
	PUSH	16(SP)		; Copy return address to TOS
	MOV	COUNTER,16(SP)	; Overwrite previous return address
	RET			;
    .endif

    .if DOUBLE=1
FLT_REC MOV	22(SP),COUNTER	; Restore saved registers
	POP	20(SP)		; Move return address to end
	POP	RESULT_LSB	;
	POP	RESULT_MID	;
	POP	RESULT_MSB	;
	POP	ARG2_LSB	;
	POP	ARG2_MID	;
	POP	ARG2_MSB	;
	POP	ARG1_LSB	;
	POP	ARG1_MID	;
	POP	ARG1_MSB	;
	POP	HELP		;
	RET			;
    .else
FLT_REC MOV	16(SP),COUNTER	; Restore saved registers
	POP	14(SP)		; Move return address to end
	POP	RESULT_LSB	;
	POP	RESULT_MSB	;
	POP	ARG2_LSB	;
	POP	ARG2_MSB	;
	POP	ARG1_LSB	;
	POP	ARG1_MSB	;
	POP	HELP		;
	RET			;
    .endif

; Floating Point Addition	Result on TOS = @RPRES + @RPARG

FLT_ADD CLR	HELP		; Clear Subtraction Bit (HELP.7)
	JMP	FSA		;

; Floating Point Subtraction    Result on TOS = @RPRES - @RPARG

FLT_SUB MOV	#80h,HELP	; Set Subtraction Bit (HELP.7)

; It is supposed that |argument 1| > |argument 2| !
; If this is not true the arguments are exchanged and the sign is
; modified so that the result is correct.
; The sign of the |greater argument| (argument 1) is the result's sign.
; Initialize the registers with the values of the input arguments.
; Test the arguments for zero. The result of the test is written to COUNTER.
;
FSA	CALL	#INIAS			; Initialization for ADD/SUB
	MOV	ARG1_LSB,RESULT_LSB	; Argument 1 to RESULT
    .if DOUBLE=1
	MOV	ARG1_MID,RESULT_MID
    .endif
	MOV	ARG1_MSB,RESULT_MSB
	AND	#80h,ARG1_MSB		; Sign of ARG1 to
	MOV.B	ARG1_MSB,2(SP)		; Result location (MSBs) on stack
;
; Special treatment if one of the arguments is 0. Info in COUNTER
;
	BIT	#2,COUNTER		; If ARG2 = 0:
	JNZ	EXIT			; Result is ARG1 (in RESULT)
        BIT     #1,COUNTER              ; ARG1 = 0?
	JZ	FA12			; Both arguments are non-zero
	MOV	ARG2_LSB,RESULT_LSB	; ARG1 = 0:
    .if DOUBLE=1
	MOV	ARG2_MID,RESULT_MID	; Result is neg. ARG2
    .endif
	MOV	ARG2_MSB,RESULT_MSB	; Depends on operation:
	XOR	HELP,RESULT_MSB 	; change sign if subtraction
	JMP	EXIT			; Result is ARG1 (in RESULT)
;
; Create the operation bit (HELP.7) with the following operation:
; (subtraction bit) .XOR. (sign ARG1) .XOR. (sign ARG2)
; Operation bit = 0:   addition is needed
; Operation bit = 1:   subtraction is needed

FA12	XOR	RESULT_MSB,HELP       ;
	XOR	ARG2_MSB,HELP	      ;
	BIC	#0FF7Fh,HELP	      ; Leave only operation bit
;
	BIS	#80h,RESULT_MSB       ; Set hidden bits to one
	BIS	#80h,ARG2_MSB	      ;
;
; The absolute greater argument is written to RESULT and the absolute
; smaller argument to ARG2. The sign of the result is corrected
;
	CMP	ARG2_MSB,RESULT_MSB   ; Compare the MSBs
	JNE	FA1
    .if DOUBLE=1
	CMP	ARG2_MID,RESULT_MID   ; Compare the MIDs
	JNE	FA1
    .endif
	CMP	ARG2_LSB,RESULT_LSB   ; Compare the LSBs
	JEQ	FA2		      ; |ARG1| = |ARG2|
FA1	JHS	FA3		      ; |ARG1| > |ARG2|

; |argument 1| < |ARG2|
; The greater argument2 is written to RESULT.
; The smaller argument1 is written to ARG2.
; If the operation is subtraction (operation bit = 1, HELP.7)
; the sign of the result is the inverted sign of argument1.

	MOV	ARG2_MSB,ARG1_MSB     ; Exchange MSBs
	MOV	RESULT_MSB,ARG2_MSB
	MOV	ARG1_MSB,RESULT_MSB
    .if DOUBLE=1
	MOV	ARG2_MID,ARG1_MID     ; Exchange MIDs
	MOV	RESULT_MID,ARG2_MID
	MOV	ARG1_MID,RESULT_MID
    .endif
	MOV	ARG2_LSB,ARG1_LSB     ; Exchange LSBs
	MOV	RESULT_LSB,ARG2_LSB
	MOV	ARG1_LSB,RESULT_LSB
	XOR	HELP,2(SP)	      ; Correct sign of result
	JMP	FA3		      ;

; |argument 1| = |argument 2|: Result is zero if subtraction

FA2	TST	HELP		      ; Check operation: 0 = ADD
	JNZ	RES0		      ; If subtraction: result = 0

; The exponent of the result is built: ARG1exp - ARG2exp = COUNTER

FA3	CLR	ARG1_LSB	      ; Clear least LSB
	MOV	RESULT_MSB,COUNTER    ; Store the difference of the
	SWPB	COUNTER 	      ; Exponents in COUNTER
	MOV.B	COUNTER,3(SP)	      ; Save exponent of result
	SWPB	ARG2_MSB	      ;
	SUB.B	ARG2_MSB,COUNTER      ; To lower byte, build difference
	SWPB	ARG2_MSB	      ; and back again to higher byte
	JZ	FA6		      ; If exponents are equal
				      ; then start operation

; If the difference of the exponents of the arguments (stored in COUNTER)
; is greater than ML - greater than the number of bits in the mantissa -
; it is the same as an addition or subtraction with zero. No
; operation is made in this case.
; Otherwise the mantissa of the smaller argument (ARG2) is shifted right
; until the exponent of the smaller argument equals the exponent of
; the greater argument (RESULT).
; ARG1_LSB.15 is used to store the LSB-1. It is needed for rounding
;
	CMP	#ML+1,COUNTER	; If difference of the exponents > ML
	JHS	DDRNZ		; then result is the value in ARG1
FA7	CLRC			;
	RRC.B	ARG2_MSB	; Rotate right ARG2 until
    .if DOUBLE=1
	RRC	ARG2_MID	; the exponents are equal
    .endif
	RRC	ARG2_LSB	;
	RRC	ARG1_LSB	; Save the LSB-1 of ARG2_LSB
	DEC	COUNTER 	; into the  MSB of ARG1_LSB
	JNZ	FA7		;

; Exponents are equal: we are ready for the addition or subtraction

FA6	TST	HELP		; HELP contains operation bit
	JZ	FA8		; Jump if addition (bit = 0)
;
; Subtraction with rounding.
;
	BIT	#8000h,ARG1_LSB       ; 'least' LSB of ARG2_LSB
	ADC	ARG2_LSB	      ; Rounding in case of subtraction
    .if DOUBLE=1
	ADC	ARG2_MID	      ;
    .endif
	ADC	ARG2_MSB	      ; No overflow possible here
	SUB	ARG2_LSB,RESULT_LSB   ; Subtraction ARG1 - ARG2
    .if DOUBLE=1
	SUBC	ARG2_MID,RESULT_MID
    .endif
	SUBC.B	ARG2_MSB,RESULT_MSB

FA10	TST.B	RESULT_MSB	; If hidden bit is set: finished
	JN	DDRNZ		; else shift left result until MSB = 1
	RLC	ARG1_LSB	; Stored LSB-1 of ARG2_LSB to Carry
	RLC	RESULT_LSB	; corrects 1st rounding by 1 bit
	CLR	ARG1_LSB	; Clear the LSB-1 info, it
    .if DOUBLE=1		; is only needed for the first shift
	RLC	RESULT_MID	; the following shifts always shift
    .endif			; a zero into the register
	RLC.B	RESULT_MSB
	DEC.B	3(SP)		; Decrement exponent of result:
	JHS	FA10		; Exponent >= 0: go on
	JMP	DBL_UNDERFLOW	; Underflow: exponent 00 -> FF
;
; Addition with rounding
;
FA8	ADD	ARG2_LSB,RESULT_LSB   ; Addition
    .if DOUBLE=1
	ADDC	ARG2_MID,RESULT_MID
    .endif
	ADDC.B	ARG2_MSB,RESULT_MSB
	JNC	FA11		      ; Jump if no mantissa overflow
	RRC.B	RESULT_MSB	      ; Shift right mantissa one bit
    .if DOUBLE=1
	RRC	RESULT_MID
    .endif
	RRC	RESULT_LSB
	RRC	ARG1_LSB	      ; Save the LSB-1
	INC.B	3(SP)		      ; Increment exponent of result
	JC	DBL_OVERFLOW

; round if necessary in case of addition

FA11	RLC	ARG1_LSB	; Shift stored LSB-1 to carry
	JMP	NORMLZ		; To common normalize part
;=============================================================================
; Floating Point Multiplication       Result on TOS = @RPRES x @RPARG

FLT_MUL CALL	#INIMD		; Read arguments, zero test, sign prep.
;	MOV.B	HELP,2(SP)	; Sign of result in HELP.7
	BIT	#3,COUNTER	; LSBs contain zero test results
	JNZ	EXIT		; Result = 0 if one argument is zero
;
; Calculate the exponent of the result by adding the exponents of
; argument 1 and argument 2. Test for overflow and underflow

	MOV	ARG1_MSB,HELP	; Fetch exponent of argument 1
	BIC	#00FFh,HELP	; Avoid influence of mantissa
	ADD	ARG2_MSB,HELP	; argument 1 + argument 2 -> HELP
	JC	FM1		;
	SUB	#8000h,HELP	; Toggle sign bit of exponent
	JC	FM2		; Jump if no borrow
	JMP	DBL_UNDERFLOW	; Underflow: result = 0
FM1	SUB	#8000h,HELP	; Toggle sign bit of exponent
	JC	DBL_OVERFLOW	; Jump if no borrow
FM2	SWPB	HELP		; Exponent to low byte
	MOV.B	HELP,3(SP)	; Save exponent of result
;
; Multiplication loop for the mantissa: different for hardware multiplier
; and software multiplication
;
	BIS.B	#80h,ARG2_MSB	; Set hidden bit in ARG2
	BIS.B	#80h,ARG1_MSB	; Set hidden bit in ARG1

    .if HW_MPY=0
;
; Software multiplication loop:
;
	MOV.B	#ML,COUNTER	; Mantissa length to counter
FM4	CLRC			; Reset CARRY for the next command
	RRC.B	ARG2_MSB	; Shift LSB of ARG2 into Carry
    .if DOUBLE=1
	RRC	ARG2_MID
    .endif
	RRC	ARG2_LSB
	JNC	FM3		      ; Bit = 0: no addition
	ADD	ARG1_LSB,RESULT_LSB   ; Add only if Carry = 1
    .if DOUBLE=1
	ADDC	ARG1_MID,RESULT_MID   ; RESULT = RESULT + ARG1
    .endif
	ADDC	ARG1_MSB,RESULT_MSB
FM3	RRC	RESULT_MSB	      ; CARRY is always zero here
    .if DOUBLE=1
	RRC	RESULT_MID	      ; Shift right 1 Bit RESULT
    .endif
	RRC	RESULT_LSB
	RRC	HELP		      ; Save the LSB-1 of RESULT
	DEC	COUNTER 	      ; if multiplication isn't finished
	JNZ	FM4		      ; Continue loop
    .else			      ; End of software multiplication loop
;
; Hardware Multiplication sequence:
;
;			       31		 0
;			      +----+----+----+----+
;			      |    mid1 x lsb2	  |
;			      +----+----+----+----+
;			      +----+----+----+----+
;			      |    lsb1 x mid2	  |
;		     47       +----+----+----+----+
;		    +----+----+----+----+
;		    | 00 | msb1 x lsb2	|
;		    +----+----+----+----+
;		    +----+----+----+----+
;		    | 00 | lsb1 x msb2	|
;		    +----+----+----+----+
;		    +----+----+----+----+
;		    |	 mid1 x mid2	|
;	   63	    +----+----+----+----+
;	  +----+----+----+----+
;	  | 00 | msb1 x mid2  |
;	  +----+----+----+----+
;	  +----+----+----+----+
;	  | 00 | mid1 x msb2  |
;	  +----+----+----+----+
;	  +----+----+
;	  |msb1xmsb2|
;	  +----+----+
; ----------------------------------------------------
;	  +----+----+----+----+----+----+
;	  |   MSB   |	MID   |   LSB	| RESULT_xxx
;	  +----+----+----+----+----+----+
;
    .if DOUBLE = 1			; .DOUBLE MPY sequence
	MPY	ARG2_LSB,ARG1_MID	;	      XXXX XXXX
	MAC	ARG1_LSB,ARG2_MID	;	    c XXXX XXXX
	ADD	&ResHi,RESULT_LSB	;
	ADDC	&SumExt,RESULT_MID	;
	MPY	ARG1_MSB,ARG2_LSB	;	 00XX XXXX
	MAC	ARG1_LSB,ARG2_MSB	;	 0XXX XXXX
	MAC	ARG1_MID,ARG2_MID	;      c XXXX XXXX
	ADD	&ResLo,RESULT_LSB	;
	ADDC	&ResHi,RESULT_MID	;
	ADDC	&SumExt,RESULT_MSB	;
	MPY	ARG1_MSB,ARG2_MID	;   00XX XXXX
	MAC	ARG2_MSB,ARG1_MID	;   0XXX XXXX
	ADD	&ResLo,RESULT_MID	;
	ADDC	&ResHi,RESULT_MSB	;
	MPY	ARG1_MSB,ARG2_MSB     ;0000 XXXX
	ADD	&ResLo,RESULT_MSB	;    MSB  MID  LSB  ---
;
    .else				; .FLOAT MPY sequence
;
;		     31 	       0
;		    +----+----+----+----+
;		    |	 lsb1 x lsb2	|
;	   47	    +----+----+----+----+
;	  +----+----+----+----+
;	  | 00 | lsb1 x msb2  |
;	  +----+----+----+----+
;	  +----+----+----+----+
;	  | 00 | msb1 x lsb2  |
;	  +----+----+----+----+
;	  +----+----+
;	  |msb1xmsb2|
;	  +----+----+
; ------------------------------------------
;	  +----+----+----+----+
;	  |   MSB   |	LSB   | RESULT_xxx
;	  +----+----+----+----+
;
; NOTE: The  MPY   ARG1_LSB,ARG2_MSB  is replaced by a
;	     MOV   ARG2_MSB,&0138h    due to speed reasons
;
	MPY	ARG1_LSB,ARG2_LSB	;	      XXXX XXXX
	MOV	&ResHi,RESULT_LSB	;
	MOV	ARG2_MSB,&0138h 	;!!	 00XX XXXX
	MAC	ARG2_LSB,ARG1_MSB	;	 0XXX XXXX
	ADD	&ResLo,RESULT_LSB	;
	ADDC	&ResHi,RESULT_MSB	;
	MPY	ARG1_MSB,ARG2_MSB	;   0000 XXXX
	ADD	&ResLo,RESULT_MSB	;	  MSB  LSB  ---
    .endif
;
; The hardware multiplier result is located falsely:
; Shift right result 8 bits to get FPP mantissa format (shown for .DOUBLE):
; .FLOAT   1234 5678	  -> 0012 3456 xx__
; .DOUBLE  1234 5678 9ABC -> 0012 3456 789A xx__   (xx in HELP for rounding)
;
	SWPB	RESULT_LSB		; 9ABC -> BC9A
	MOV	RESULT_LSB,HELP 	; BC9A (contains LSB-1, LSB-2)
	MOV.B	RESULT_LSB,RESULT_LSB	; 009A
    .if DOUBLE = 1
	MOV.B	RESULT_MID,COUNTER	; 0078 -> COUNTER
	SWPB	COUNTER 		; 7800
	ADD	COUNTER,RESULT_LSB	; 789A -> RESULT_LSB
	SWPB	RESULT_MID		; 7856
	MOV.B	RESULT_MID,RESULT_MID	; 0056
	MOV.B	RESULT_MSB,COUNTER	; 0034 -> COUNTER
	SWPB	COUNTER 		; 3400
	ADD	COUNTER,RESULT_MID	; 3456 -> RESULT_MID
    .else
	MOV.B	RESULT_MSB,COUNTER	;
	SWPB	COUNTER 		;
	ADD	COUNTER,RESULT_LSB	;
    .endif
	SWPB	RESULT_MSB		; 3412
	MOV.B	RESULT_MSB,RESULT_MSB	; 0012 -> RESULT_MSB
    .endif				; End of hardware MPY sequence
;
; Common completion part:
; Result in RESULT: 40 0000 to FF FFFE (40 0000 0000 to FF FFFF FFFE
; Normalization is made to get MSB = 1 and rounding with LSB-1
;
	TST.B	RESULT_MSB	; If hidden Bit is not set
	JGE	FM5		; then jump
	INC.B	3(SP)		; New RESULT-exponent: hidden bit = 1
	JNC	FM6
	JMP	DBL_OVERFLOW	; Exponent-overflow (FF to 00)
FM5	RLC	HELP		; LSB-1 of RESULT to carry
	RLC	RESULT_LSB	; to format the mantissa
    .if DOUBLE=1
	RLC	RESULT_MID
    .endif
	RLC.B	RESULT_MSB

; round with LSB-1 resp. LSB-2

FM6	RLC	HELP		; Next LSB-1 to CARRY
	JMP	NORMLZ		; Go to common completion part
;=============================================================================
; Floating Point Division       Result on TOS = @RPRES/@RPARG

; Check if dividend is zero: result is zero
; Check if divisor  is zero: result is signed max. number (overflow error)

FLT_DIV CALL	#INIMD		; Read arguments, zero test, sign prep.
;	MOV.B	HELP,2(SP)	; Sign of result in HELP.7
	BIT	#1,COUNTER	; If argument1 is zero:
	JNZ	EXIT		; Result is zero
	BIT	#2,COUNTER	; If argument2 is zero:
	JNZ	DIV_BY_ZERO	; signed overflow

; Calculate the exponent of the result by subtraction of the exponents
; of argument1 and argument2

	MOV	ARG1_MSB,HELP	; Fetch exponent of argument 1
	BIS	#0FFh,HELP	; Avoid influence from mantissa
	SUB	ARG2_MSB,HELP	; argument 1 - argument 2 -> HELP
	JC	FD1		;
	ADD	#8000h,HELP	; Toggle sign bit of exponent
	JC	FD2		;
	JMP	DBL_UNDERFLOW	; Underflow: result = 0
FD1	ADD	#8000h,HELP	; Toggle sign bit of exponent
	JC	DBL_OVERFLOW	; Overflow: largest signed number
FD2	SWPB	HELP		;
	MOV.B	HELP,3(SP)	; Save exponent of result

; Division-loop for mantissa calculation
;
	BIS.B	#80h,ARG2_MSB	      ; Set hidden bit argument 2
	BIS.B	#80h,ARG1_MSB	      ; Set hidden bit argument 2
	MOV.B	#ML,COUNTER	      ; Mantissa length to COUNTER

FD4	SUB	ARG2_LSB,ARG1_LSB     ; ARG1 - ARG2
    .if DOUBLE=1
	SUBC	ARG2_MID,ARG1_MID     ;
    .endif
	SUBC	ARG2_MSB,ARG1_MSB     ;
	JC	FD3		      ; ARG1 >= ARG2
	ADD	ARG2_LSB,ARG1_LSB     ; ARG1 < ARG2: restore ARG1
    .if DOUBLE=1
	ADDC	ARG2_MID,ARG1_MID     ;
    .endif
	ADDC	ARG2_MSB,ARG1_MSB     ;
	CLRC			      ;
FD3	RLC	RESULT_LSB	      ; Carry to result
    .if DOUBLE=1
	RLC	RESULT_MID
    .endif
	RLC	RESULT_MSB
	RLA	ARG1_LSB	      ;
    .if DOUBLE=1
	RLC	ARG1_MID	      ;
    .endif
	RLC	ARG1_MSB	      ;
	DEC.B	COUNTER 	      ; If division is not finished:
	JNZ	FD4		      ; continue loop

	TST.B	RESULT_MSB	      ; Hidden bit set (normalized)?
	JN	FD5		      ; Yes
	INC.B	COUNTER 	      ; No, go through loop once more
	DEC.B	3(SP)		      ; Correct exponent
	JHS	FD4		      ;
	JMP	DBL_UNDERFLOW	      ; Underflow: result = 0
;
; Result in RESULT: 80 0000 to FF FFFE (80 0000 0000 to FF FFFF FFFE)
; Rounding is made with LSB-1
;
FD5	SUBC	ARG2_LSB,ARG1_LSB     ; Calculate LSB-1
    .if DOUBLE=1
	SUBC	ARG2_MID,ARG1_MID     ;
    .endif
	SUBC	ARG2_MSB,ARG1_MSB     ; Rounding info in Carry
;==============================================================================
; Common completion part: Mantissa in RESULT_xxx
;			Sign	 in 2(SP) MSB	(hidden bit)
;			Exponent in 3(SP)
;			LSB-1	 in Carry for rounding
;
; Rounding info in carry, no error, sign and exponent get inserted
;
NORMLZ	ADC	RESULT_LSB	      ; Round mantissa with LSB-1
    .if DOUBLE=1
	ADC	RESULT_MID
    .endif
	ADC.B	RESULT_MSB
	ADC.B	3(SP)		      ; Round exponent with Carry
	JC	DBL_OVERFLOW	      ; Exponent overflow 0FFh to 00h
;
; No rounding, no error, sign and exponent get inserted
;
DDRNZ	BIC.B	#80h,RESULT_MSB       ; Clear hidden Bit (and higher byte)
	BIS	2(SP),RESULT_MSB      ; Insert exponent and sign bit
;
; All done, result is placed on top of stack (TOS)
;
EXIT	CLR	HELP		      ; N=0, no error
EXITE	MOV	RESULT_MSB,2(SP)      ; Result (RESULT) to Stack
    .if DOUBLE=1
	MOV	RESULT_MID,4(SP)      ;
	MOV	RESULT_LSB,6(SP)      ;
    .else
	MOV	RESULT_LSB,4(SP)      ;
    .endif
;
; Termination subroutine: error code in HELP (0 = no error)
; Subroutine can be used by user written FP subroutines
;
FLT_END MOV	SP,RPRES	      ; Result pointer to result
	ADD	#2,RPRES	      ; Correction (SP points to return addr.)
	MOV	RPRES,RPARG	      ; Argument pointer to result
	BIC	#FN+FZ+FC,SR	      ; Clear N,Z and C in SR
	BIS	HELP,SR 	      ; Set SR according to error status
	RET			      ; Stored in HELP
;==============================================================================
; Floating Point Error Handling: underflow, overflow, division by zero
;
;  +--------------------+-------------------+------------------------+
;  | Error		|    Statusregister |	 Result 	     |
;  +--------------------+-------------------+------------------------+
;  | No error		|    N=0, C=x, Z=x  |	 xxxx xxxx xxxx      |
;  | Overflow positive	|    N=1, C=1, Z=1  |	 FF7F FFFF FFFF      |
;  | Overflow negative	|    N=1, C=1, Z=0  |	 FFFF FFFF FFFF      |
;  | Underflow		|    N=1, C=0, Z=0  |	 0000 0000 0000      |
;  | Division by zero	|    N=1, C=0, Z=1  |	 FF7F FFFF FFFF or   |
;  |			|		    |	 FFFF FFFF FFFF      |
;  +--------------------+-------------------+------------------------+
;
DBL_UNDERFLOW			; Underflow: Result = 0
    .if SW_UFLOW=1		; Error only if SW_UFLOW = 1
	MOV	#FN,HELP	; Error code N=1, C=0, Z=0
	JMP	RES01
    .endif
RES0	CLR	HELP		; Result is 0: N = 0 (No error)
RES01	CLR	RESULT_MSB	; Errorfree zero result
    .if DOUBLE=1
	CLR	RESULT_MID
    .endif
	CLR	RESULT_LSB
	JMP	EXITE		; To normal completion

DBL_OVERFLOW			; Overflow: Insert largest signed number
	MOV	#FN+FC,HELP	; Error code N=1, C=1, Z=Sign
	TST.B	2(SP)		; Sign of result is stored here
	JN	L$1		; Neg. sign: Z=0
	BIS	#FZ,HELP	; Pos. sign: Z=1
L$1	MOV	#0FF7Fh,RESULT_MSB
	BIS	2(SP),RESULT_MSB      ; Insert sign
    .if DOUBLE=1
	MOV	#0FFFFh,RESULT_MID    ;
    .endif
	MOV	#0FFFFh,RESULT_LSB    ;
	JMP	EXITE		      ;

DIV_BY_ZERO                  ;Division by Zero: Insert largest signed number
	MOV	#FN+FZ,HELP	; Error code N=1, C=0, Z=1
	JMP	L$1		; Result like overflow

;=============================================================================
; Floating Point Comparison
;
;  Call of the Comparison:
;
;     MOV     #ARG1,RPRES     ; Pointer to Argument 1 MSBs
;     MOV     #ARG2,RPARG     ; Pointer to Argument 2 MSBs
;     CALL    #FLT_CMP	      ; Comparison call
;     JEQ     EQUAL	      ; If arg1 = arg2
;     JHS     A1_GT_A2	      ; If arg1 > arg2
;     ...     ...	      ; If arg1 < arg2
;
;  The result of the compare is written to the status register SR and HELP
; RPARG and RPRES point with SP to actual result area (normal return)
;
;  +--------------------------+------------------------------+
;  | Condition		      |    Statusregister	     |
;  +--------------------------+------------------------------+
;  | Argument 1 =  Argument 2 | ZERO = 1, CARRY = 1, NEG = 0 |
;  | Argument 1 <  Argument 2 | ZERO = 0, CARRY = 0, NEG = 0 |
;  | Argument 1 >  Argument 2 | ZERO = 0, CARRY = 1, NEG = 0 |
;  +--------------------------+------------------------------+
;
FLT_CMP MOV	@RPARG+,ARG2_MSB	; Copy argument 2 to regs
	.if	DOUBLE=1
	MOV	@RPARG+,ARG2_MID
	.endif
	MOV	@RPARG+,ARG2_LSB
	MOV	@RPRES+,ARG1_MSB	; Copy argument 1 to regs
	.if	DOUBLE=1
	MOV	@RPRES+,ARG1_MID
	.endif
	MOV	@RPRES+,ARG1_LSB
;
	TST.B	ARG2_MSB		; Arg1, Arg2: check signs
	JN	FC2			; Arg2 = neg.
	TST.B	ARG1_MSB		; Arg2 = pos.
	JN	A1LTA2			; Arg2 = +, Arg1 = -: A1 < A2
	CMP	ARG2_MSB,ARG1_MSB	; Arg1 = +, Arg2 = +
	JNE	FC4			; Check values
	.if	DOUBLE=1
	CMP	ARG2_MID,ARG1_MID
	JNE	FC4
	.endif
	CMP	ARG2_LSB,ARG1_LSB
	JEQ	A1EQA2			; Arg1 = Arg2
FC4	JLO	A1LTA2			; Arg1 < Arg2
A1GTA2	MOV	#FC,HELP		; Carry = 1, Zero = 0
	JMP	FLT_END 		; To completion part
;
FC2	TST.B	ARG1_MSB		; Arg2 = -
	JGE	A1GTA2			; Arg1 = +: A1 > A2
	CMP	ARG2_MSB,ARG1_MSB	; Arg1 = -, Arg2 = -
	JNE	FC5			; Check values
	.if	DOUBLE=1
	CMP	ARG2_MID,ARG1_MID
	JNE	FC5
	.endif
	CMP	ARG2_LSB,ARG1_LSB
	JEQ	A1EQA2			; Arg1 = Arg2
FC5	JLO	A1GTA2			; Arg1 > Arg2
A1LTA2	CLR	HELP			; Carry = 0, Zero = 0
	JMP	FLT_END 		; Modify SR with HELP
A1EQA2	MOV	#FZ+FC,HELP		; Arg1 = Arg2: Z = C = 1
	JMP	FLT_END 		; To completion part
;=============================================================================
; Floating Point Subroutines
;
; INIMD creates the sign of the result for MPY and DIV in HELP.7
; INIAS is used too

INIMD	MOV.B	@RPRES,HELP	; Calculate sign of result:
	XOR.B	@RPARG,HELP	; Sign arg2 .xor. sign arg1
	AND.B	#080h,HELP	; Leave only the calculated sign

; INIAS  loads the arguments to ARG1_xxx and ARG2_xxx
;      clears the variables RESULT_xxx
;      tests the arguments to zero and stores the result in
;      COUNTER - if argument1 is zero: COUNTER.0 is 1
;		 if argument2 is zero: COUNTER.1 is 1
;		 else COUNTER is 0

INIAS	MOV	@RPARG+,ARG2_MSB     ; Fetch Argument 2
    .if DOUBLE=1
	MOV	@RPARG+,ARG2_MID     ;
    .endif
	MOV	@RPARG,ARG2_LSB      ;
;
	MOV	@RPRES+,ARG1_MSB     ; Fetch Argument 1
    .if DOUBLE=1
	MOV	@RPRES+,ARG1_MID     ;
    .endif
	MOV	@RPRES,ARG1_LSB      ;
	MOV.B	HELP,4(SP)	     ; Insert sign
	CLR	RESULT_MSB	; Clear RESULT
    .if DOUBLE=1
	CLR	RESULT_MID	;
    .endif
	CLR	RESULT_LSB	;

	CLR	COUNTER 	; Clear COUNTER
	TST	ARG1_MSB	; If ARG1 = 0:
	JNZ	FNZ1		; set LSB of COUNTER
    .if DOUBLE=1
	TST	ARG1_MID	;
	JNZ	FNZ1		;
    .endif
	TST	ARG1_LSB	;
	JNZ	FNZ1		;
	BIS	#1,COUNTER	; ARG1 = 0
;
FNZ1	TST	ARG2_MSB	; If ARG2 = 0:
	JNZ	FNZ2		; set LSB+1 of COUNTER
    .if DOUBLE=1
	TST	ARG2_MID	;
	JNZ	FNZ2		;
    .endif
	TST	ARG2_LSB	;
	JNZ	FNZ2		;
	BIS	#2,COUNTER	; ARG2 = 0
FNZ2	RET			; Zero info in COUNTER, sign in HELP
;
;  END OF THE FLOATING POINT BASIC ARITHMETIC OPERATIONS







 
Впервые? | Реклама на сайте | О проекте | Карта портала
тел. редакции: +7 (995) 900 6254. e-mail:info@eust.ru
©1998-2023 Рынок Микроэлектроники