diff options
author | fpc <fpc@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-05-16 18:37:41 +0000 |
---|---|---|
committer | fpc <fpc@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-05-16 18:37:41 +0000 |
commit | f206a9c2b1ae1d8727ca27a96d448b61fdb4c766 (patch) | |
tree | f28256ff9964c1fc7c0f7fb00891268a117b745d /rtl/m68k | |
download | fpc-f206a9c2b1ae1d8727ca27a96d448b61fdb4c766.tar.gz |
initial import
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@1 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'rtl/m68k')
-rw-r--r-- | rtl/m68k/lowmath.inc | 920 | ||||
-rw-r--r-- | rtl/m68k/m68k.inc | 329 | ||||
-rw-r--r-- | rtl/m68k/makefile.cpu | 7 | ||||
-rw-r--r-- | rtl/m68k/math.inc | 949 | ||||
-rw-r--r-- | rtl/m68k/readme | 7 | ||||
-rw-r--r-- | rtl/m68k/set.inc | 428 | ||||
-rw-r--r-- | rtl/m68k/setjump.inc | 34 | ||||
-rw-r--r-- | rtl/m68k/setjumph.inc | 37 |
8 files changed, 2711 insertions, 0 deletions
diff --git a/rtl/m68k/lowmath.inc b/rtl/m68k/lowmath.inc new file mode 100644 index 0000000000..f5a0c3fd92 --- /dev/null +++ b/rtl/m68k/lowmath.inc @@ -0,0 +1,920 @@ +{ + $Id: lowmath.inc,v 1.5 2005/02/14 17:13:30 peter Exp $ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Carl-Eric Codere, + member of the Free Pascal development team + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + 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. + + **********************************************************************} +{*************************************************************************} +{ lowmath.inc } +{ Ported to FPC-Pascal by Carl Eric Codere } +{ Terms of use: This source code is freeware. } +{*************************************************************************} +{ This inc. implements low-level mathemtical routines for the motorola } +{ 68000 family of processors. } +{*************************************************************************} +{ single floating point routines taken from GCC 2.5.2 Atari compiler } +{ library source. } +{ Original credits: } +{ written by Kai-Uwe Bloem (I5110401@dbstu1.bitnet). } +{ Based on a 80x86 floating point packet from comp.os.minix, } +{ written by P.Housel } +{ Patched by Olaf Flebbe (flebbe@tat.physik.uni-tuebingen.de) } +{ Revision by michal 05-93 (ntomczak@vm.ucs.ualberta.ca) } +{*************************************************************************} +{--------------------------------------------------------------------} +{ LEFT TO DO: } +{ o Add support for FPU if present. } +{ o Verify if single comparison works in all cases. } +{ o Add support for NANs in SINGLE_CMP } +{ o Add comp (80-bit) multiplication,addition,substract,division, } +{ shift. } +{ o Add stack checking for the routines which use the stack. } +{ (This will probably have to be done in the code generator). } +{--------------------------------------------------------------------} + + + +Procedure Single_Norm;[alias : 'FPC_SINGLE_NORM'];Assembler; +{--------------------------------------------} +{ Low-level routine to normalize single e } +{ IEEE floating point values. Never called } +{ directly. } +{ On Exit: } +{ d0 = result. } +{ Registers destroyed: d0,d1 } +{--------------------------------------------} +Asm + tst.l d4 { rounding and u.mant == 0 ? } + bne @normlab1 + tst.b d1 + beq @retzok +@normlab1: + clr.b d2 { "sticky byte" } +@normlab3: + move.l #$ff000000,d5 +@normlab4: + tst.w d0 { divide (shift) } + ble @normlab2 { denormalized number } + move.l d4,d3 + and.l d5,d3 { or until no bits above 23 } + beq @normlab5 +@normlab2: + addq.w #1,d0 { increment exponent } + lsr.l #1,d4 + or.b d1,d2 { set "sticky" } + roxr.b #1,d1 { shift into rounding bits } + bra @normlab4 +@normlab5: + and.b #1,d2 + or.b d2,d1 { make least sig bit "sticky" } + asr.l #1,d5 { #0xff800000 -> d5 } +@normlab6: + move.l d4,d3 { multiply (shift) until } + and.l d5,d3 { one in "implied" position } + bne @normlab7 + subq.w #1,d0 { decrement exponent } + beq @normlab7 { too small. store as denormalized number } + add.b d1,d1 { some doubt about this one * } + addx.l d4,d4 + bra @normlab6 +@normlab7: + tst.b d1 { check rounding bits } + bge @normlab9 { round down - no action neccessary } + neg.b d1 + bvc @normlab8 { round up } + move.w d4,d1 { tie case - round to even } + { dont need rounding bits any more } + and.w #1,d1 { check if even } + beq @normlab9 { mantissa is even - no action necessary } + { fall through } +@normlab8: + clr.w d1 { zero rounding bits } + add.l #1,d4 + tst.w d0 + bne @normlab10 { renormalize if number was denormalized } + add.w #1,d0 { correct exponent for denormalized numbers } + bra @normlab3 +@normlab10: + move.l d4,d3 { check for rounding overflow } + asl.l #1,d5 { #0xff000000 -> d5 } + and.l d5,d3 + bne @normlab4 { go back and renormalize } +@normlab9: + tst.l d4 { check if normalization caused an underflow } + beq @retz + tst.w d0 { check for exponent overflow or underflow } + blt @retz + cmp.w #255,d0 + bge @oflow + + lsl.w #8,d0 { re-position exponent - one bit too high } + lsl.w #1,d2 { get X bit } + roxr.w #1,d0 { shift it into sign position } + swap d0 { map to upper word } + clr.w d0 + and.l #$7fffff,d4 { top mantissa bits } + or.l d4,d0 { insert exponent and sign } + movem.l (sp)+,d2-d5 + rts + +@retz: + { handling underflow should be done here... } + { by default simply return 0 as retzok... } +@retzok: + moveq.l #0,d0 + lsl.w #1,d2 + roxr.l #1,d0 { sign of 0 is the same as of d2 } + movem.l (sp)+,d2-d5 + rts + +@oflow: + move.l #$7f800000,d0 { +infinity as proposed by IEEE } + + tst.w d2 { transfer sign } + bge @ofl_clear { (mjr++) } + bset #31,d0 { } +@ofl_clear: + or.b #2,ccr { set overflow flag. } + movem.l (sp)+,d2-d5 + rts +end; + + +Procedure Single_AddSub; Assembler; +{--------------------------------------------} +{ Low-level routine to add/subtract single } +{ IEEE floating point values. Never called } +{ directly. } +{ On Exit: } +{ d0 = result -- from normalize routine } +{ Flags : V set if overflow. } +{ on underflow d0 = 0 } +{ Registers destroyed: d0,d1 } +{--------------------------------------------} +Asm +{--------------------------------------------} +{ On Entry: } +{ d1-d0 = single values to subtract. } +{--------------------------------------------} +XDEF SINGLE_SUB + eor.l #$80000000,d0 { reverse sign of v } +{--------------------------------------------} +{ On Entry: } +{ d0, d1 = single values to add. } +{--------------------------------------------} +XDEF SINGLE_ADD + movem.l d2-d5,-(sp) { save registers } + move.l d0,d4 { d4 = d0 = v } + move.l d1,d5 { d5 = d1 = u } + + move.l #$7fffff,d3 + move.l d5,d0 { d0 = u.exp } + move.l d5,d2 { d2.h = u.sign } + swap d0 + move.w d0,d2 { d2 = u.sign } + and.l d3,d5 { remove exponent from u.mantissa } + + move.l d4,d1 { d1 = v.exp } + and.l d3,d4 { remove exponent from v.mantissa } + swap d1 + eor.w d1,d2 { d2 = u.sign ^ v.sign (in bit 15)} + clr.b d2 { we will use the lowest byte as a flag } + moveq.l #15,d3 + bclr d3,d1 { kill sign bit u.exp } + bclr d3,d0 { kill sign bit u.exp } + btst d3,d2 { same sign for u and v? } + beq @slabel1 + cmp.l d0,d1 { different signs - maybe x - x ? } + seq d2 { set 'cancellation' flag } +@slabel1: + lsr.w #7,d0 { keep here exponents only } + lsr.w #7,d1 +{--------------------------------------------------------------------} +{ Now perform testing of NaN and infinities } +{--------------------------------------------------------------------} + moveq.l #-1,d3 + cmp.b d3,d0 + beq @alabel1 + cmp.b d3,d1 + bne @nospec + bra @alabel2 +{--------------------------------------------------------------------} +{ u is special. } +{--------------------------------------------------------------------} +@alabel1: + tst.b d2 + bne @retnan { cancellation of specials -> NaN } + tst.l d5 + bne @retnan { arith with Nan gives always NaN } + + addq.w #4,a0 { here is an infinity } + cmp.b d3,d1 + bne @alabel3 { skip check for NaN if v not special } +{--------------------------------------------------------------------} +{ v is special. } +{--------------------------------------------------------------------} +@alabel2: + tst.l d4 + bne @retnan +@alabel3: + move.l (a0),d0 + bra @return +{--------------------------------------------------------------------} +{ Return a quiet nan } +{--------------------------------------------------------------------} +@retnan: + moveq.l #-1,d0 + lsr.l #1,d0 { 0x7fffffff -> d0 } + bra @return +{ Ok, no inifinty or NaN involved.. } +@nospec: + tst.b d2 + beq @alabel4 + moveq.l #0,d0 { x - x hence we always return +0 } +@return: + movem.l (sp)+,d2-d5 + rts + +@alabel4: + moveq.l #23,d3 + bset d3,d5 { restore implied leading "1" } + tst.w d0 { check for zero exponent - no leading "1" } + bne @alabel5 + bclr d3,d5 { remove it } + addq.w #1,d0 { "normalize" exponent } +@alabel5: + bset d3,d4 { restore implied leading "1" } + tst.w d1 { check for zero exponent - no leading "1" } + bne @alabel6 + bclr d3,d4 { remove it } + addq.w #1,d1 { "normalize" exponent } +@alabel6: + moveq.l #0,d3 { (put initial zero rounding bits in d3) } + neg.w d1 { d1 = u.exp - v.exp } + add.w d0,d1 + beq @alabel8 { exponents are equal - no shifting neccessary } + bgt @alabel7 { not equal but no exchange neccessary } + exg d4,d5 { exchange u and v } + sub.w d1,d0 { d0 = u.exp - (u.exp - v.exp) = v.exp } + neg.w d1 + tst.w d2 { d2.h = u.sign ^ (u.sign ^ v.sign) = v.sign } + bpl @alabel7 + bchg #31,d2 +@alabel7: + cmp.w #26,d1 { is u so much bigger that v is not } + bge @alabel9 { significant ? } +{--------------------------------------------------------------------} +{ shift mantissa left two digits, to allow cancellation of } +{ most significant digit, while gaining an additional digit for } +{ rounding. } +{--------------------------------------------------------------------} + moveq.l #1,d3 +@alabel10: + add.l d5,d5 + subq.w #1,d0 { decrement exponent } + subq.w #1,d1 { done shifting altogether ? } + dbeq d3,@alabel10 { loop if still can shift u.mant more } + moveq.l #0,d3 + + cmp.w #16,d1 { see if fast rotate possible } + blt @alabel11 + or.w d4,d3 { set rounding bits } + clr.w d4 + swap d4 + subq.w #8,d1 + subq.w #8,d1 + bra @alabel11 + +@alabel12: + move.b d4,d2 + and.b #1,d2 + or.b d2,d3 + lsr.l #1,d4 { shift v.mant right the rest of the way } +@alabel11: + dbra d1,@alabel12 { loop } + +@alabel8: + tst.w d2 { are the signs equal ? } + bpl @alabel13 { yes, no negate necessary } + + + tst.w d3 { negate rounding bits and v.mant } + beq @alabel14 + addq.l #1,d4 +@alabel14: + neg.l d4 + +@alabel13: + add.l d4,d5 { u.mant = u.mant + v.mant } + bcs @alabel9 { needn not negate } + tst.w d2 { opposite signs ? } + bpl @alabel9 { do not need to negate result } + + neg.l d5 + not.l d2 { switch sign } +@alabel9: + move.l d5,d4 { move result for normalization } + clr.l d1 + tst.l d3 + beq @alabel15 + moveq.l #-1,d1 +@alabel15: + swap d2 { put sign into d2 (exponent is in d0) } + jmp FPC_SINGLE_NORM { leave registers on stack for norm_sf } +end; + + +Procedure Single_Mul;Assembler; +{--------------------------------------------} +{ Low-level routine to multiply two single } +{ IEEE floating point values. Never called } +{ directly. } +{ Om Entry: } +{ d0,d1 = values to multiply } +{ On Exit: } +{ d0 = result. } +{ Registers destroyed: d0,d1 } +{ stack space used (and restored): 8 bytes. } +{--------------------------------------------} +Asm +XDEF SINGLE_MUL + movem.l d2-d5,-(sp) + move.l d0,d4 { d4 = v } + move.l d1,d5 { d5 = u } + + move.l #$7fffff,d3 + move.l d5,d0 { d0 = u.exp } + and.l d3,d5 { remove exponent from u.mantissa } + swap d0 + move.w d0,d2 { d2 = u.sign } + + move.l d4,d1 { d1 = v.exp } + and.l d3,d4 { remove exponent from v.mantissa } + swap d1 + eor.w d1,d2 { d2 = u.sign ^ v.sign (in bit 15)} + + moveq.l #15,d3 + bclr d3,d0 { kill sign bit } + bclr d3,d1 { kill sign bit } + tst.l d0 { test if one of factors is 0 } + beq @mlabel1 + tst.l d1 +@mlabel1: + seq d2 { 'one of factors is 0' flag in the lowest byte } + lsr.w #7,d0 { keep here exponents only } + lsr.w #7,d1 + +{--------------------------------------------------------------------} +{ Now perform testing of NaN and infinities } +{--------------------------------------------------------------------} + moveq.l #-1,d3 + cmp.b d3,d0 + beq @mlabel2 + cmp.b d3,d1 + bne @mnospec + bra @mlabel3 +{--------------------------------------------------------------------} +{ first operand is special } +{--------------------------------------------------------------------} +@mlabel2: + tst.l d5 { is it NaN? } + bne @mretnan +@mlabel3: + tst.b d2 { 0 times special or special times 0 ? } + bne @mretnan { yes -> NaN } + cmp.b d3,d1 { is the other special ? } + beq @mlabel4 { maybe it is NaN } +{--------------------------------------------------------------------} +{ Return infiny with correct sign } +{--------------------------------------------------------------------} +@mretinf: + move.l #$ff000000,d0 { we will return #0xff800000 or #0x7f800000 } + lsl.w #1,d2 + roxr.l #1,d0 { shift in high bit as given by d2 } +@mreturn: + movem.l (sp)+,d2-d5 + rts + +{--------------------------------------------------------------------} +{ v is special. } +{--------------------------------------------------------------------} +@mlabel4: + tst.l d4 { is this NaN? } + beq @mretinf { we know that the other is not zero } +@mretnan: + moveq.l #-1,d0 + lsr.l #1,d0 { 0x7fffffff -> d0 } + bra @mreturn +{--------------------------------------------------------------------} +{ End of NaN and Inf } +{--------------------------------------------------------------------} +@mnospec: + tst.b d2 { not needed - but we can waste two instr. } + bne @mretzz { return signed 0 if one of factors is 0 } + moveq.l #23,d3 + bset d3,d5 { restore implied leading "1" } + subq.w #8,sp { multiplication accumulator } + tst.w d0 { check for zero exponent - no leading "1" } + bne @mlabel5 + bclr d3,d5 { remove it } + addq.w #1,d0 { "normalize" exponent } +@mlabel5: + tst.l d5 + beq @mretz { multiplying zero } + + moveq.l #23,d3 + bset d3,d4 { restore implied leading "1" } + tst.w d1 { check for zero exponent - no leading "1" } + bne @mlabel6 + bclr d3,d4 { remove it } + addq.w #1,d1 { "normalize" exponent } +@mlabel6: + tst.l d4 + beq @mretz { multiply by zero } + + add.w d1,d0 { add exponents, } + sub.w #BIAS4+16-8,d0 { remove excess bias, acnt for repositioning } + + clr.l (sp) { initialize 64-bit product to zero } + clr.l 4(sp) +{--------------------------------------------------------------------} +{ see Knuth, Seminumerical Algorithms, section 4.3. algorithm M } +{--------------------------------------------------------------------} + move.w d4,d3 + mulu.w d5,d3 { mulitply with bigit from multiplier } + move.l d3,4(sp) { store into result } + + move.l d4,d3 + swap d3 + mulu.w d5,d3 + add.l d3,2(sp) { add to result } + + swap d5 { [TOP 8 BITS SHOULD BE ZERO !] } + + move.w d4,d3 + mulu.w d5,d3 { mulitply with bigit from multiplier } + add.l d3,2(sp) { store into result (no carry can occur here) } + + move.l d4,d3 + swap d3 + mulu.w d5,d3 + add.l d3,(sp) { add to result } + { [TOP 16 BITS SHOULD BE ZERO !] } + movem.l 2(sp),d4-d5 { get the 48 valid mantissa bits } + clr.w d5 { (pad to 64) } + + move.l #$0000ffff,d3 +@mlabel7: + cmp.l d3,d4 { multiply (shift) until } + bhi @mlabel8 { 1 in upper 16 result bits } + cmp.w #9,d0 { give up for denormalized numbers } + ble @mlabel8 + swap d4 { (we''re getting here only when multiplying } + swap d5 { with a denormalized number; there''s an } + move.w d5,d4 { eventual loss of 4 bits in the rounding } + clr.w d5 { byte -- what a pity 8-) } + subq.w #8,d0 { decrement exponent } + subq.w #8,d0 + bra @mlabel7 +@mlabel8: + move.l d5,d1 { get rounding bits } + rol.l #8,d1 + move.l d1,d3 { see if sticky bit should be set } + and.l #$ffffff00,d3 + beq @mlabel9 + or.b #1,d1 { set "sticky bit" if any low-order set } +@mlabel9: + addq.w #8,sp { remove accumulator from stack } + jmp FPC_SINGLE_NORM{ (result in d4) } + +@mretz: + addq.w #8,sp { release accumulator space } +@mretzz: + moveq.l #0,d0 { save zero as result } + lsl.w #1,d2 { and set it sign as for d2 } + roxr.l #1,d0 + movem.l (sp)+,d2-d5 + rts { no normalizing neccessary } +end; + + +Procedure Single_Div;Assembler; +{--------------------------------------------} +{ Low-level routine to dividr two single } +{ IEEE floating point values. Never called } +{ directly. } +{ Om Entry: } +{ d1/d0 = u/v = operation to perform. } +{ On Exit: } +{ d0 = result. } +{ Registers destroyed: d0,d1 } +{ stack space used (and restored): 8 bytes. } +{--------------------------------------------} +ASM +XDEF SINGLE_DIV + { u = d1 = dividend } + { v = d0 = divisor } + tst.l d0 { check if divisor is 0 } + bne @dno_exception + + move.l #$7f800000,d0 + btst #31,d1 { transfer sign of dividend } + beq @dclear + bset #31,d0 +@dclear: + rts + +@dno_exception: + move.l d1,d4 { d4 = u, d5 = v } + move.l d0,d5 + movem.l d2-d5,-(sp) { save registers } + + move.l #$7fffff,d3 + move.l d4,d0 { d0 = u.exp } + and.l d3,d4 { remove exponent from u.mantissa } + swap d0 + move.w d0,d2 { d2 = u.sign } + + move.l d5,d1 { d1 = v.exp } + and.l d3,d5 { remove exponent from v.mantissa } + swap d1 + eor.w d1,d2 { d2 = u.sign ^ v.sign (in bit 15) } + + moveq.l #15,d3 + bclr d3,d0 { kill sign bit } + bclr d3,d1 { kill sign bit } + lsr.w #7,d0 + lsr.w #7,d1 + + moveq.l #-1,d3 + cmp.b d3,d0 { comparison with #0xff } + beq @dlabel1 { u == NaN ;; u== Inf } + cmp.b d3,d1 + beq @dlabel2 { v == NaN ;; v == Inf } + tst.b d0 + bne @dlabel4 { u not zero nor denorm } + tst.l d4 + beq @dlabel3 { 0/ ? } + +@dlabel4: + tst.w d1 + bne @dnospec + + tst.l d5 + bne @dnospec + bra @dretinf { x/0 -> +/- Inf } + +@dlabel1: + tst.l d4 { u == NaN ? } + bne @dretnan { NaN/ x } + cmp.b d3,d1 + beq @dretnan { Inf/Inf or Inf/NaN } +{ bra dretinf ; Inf/x ; x != Inf && x != NaN } +{--------------------------------------------------------------------} +{ Return infinity with correct sign. } +{--------------------------------------------------------------------} +@dretinf: + move.l #$ff000000,d0 + lsl.w #1,d2 + roxr.l #1,d0 { shift in high bit as given by d2 } +@dreturn: + movem.l (sp)+,d2-d5 + rts + +@dlabel2: + tst.l d5 + bne @dretnan { x/NaN } +{ bra dretzero ; x/Inf -> +/- 0 } +{--------------------------------------------------------------------} +{ Return correct signed zero. } +{--------------------------------------------------------------------} +@dretzero: + moveq.l #0,d0 { zero destination } + lsl.w #1,d2 { set X bit accordingly } + roxr.l #1,d0 + bra @dreturn + +@dlabel3: + tst.w d1 + bne @dretzero { 0/x ->+/- 0 } + tst.l d4 + bne @dretzero { 0/x } +{ bra dretnan 0/0 } +{--------------------------------------------------------------------} +{ Return NotANumber } +{--------------------------------------------------------------------} +@dretnan: + move.l d3,d0 { d3 contains 0xffffffff } + lsr.l #1,d0 + bra @dreturn +{--------------------------------------------------------------------} +{ End of Special Handling } +{--------------------------------------------------------------------} +@dnospec: + moveq.l #23,d3 + bset d3,d4 { restore implied leading "1" } + tst.w d0 { check for zero exponent - no leading "1" } + bne @dlabel5 + bclr d3,d4 { remove it } + add.w #1,d0 { "normalize" exponent } +@dlabel5: + tst.l d4 + beq @dretzero { dividing zero } + + bset d3,d5 { restore implied leading "1" } + tst.w d1 { check for zero exponent - no leading "1"} + bne @dlabel6 + bclr d3,d5 { remove it } + add.w #1,d1 { "normalize" exponent } +@dlabel6: + + sub.w d1,d0 { subtract exponents, } + add.w #BIAS4-8+1,d0 { add bias back in, account for shift } + add.w #34,d0 { add loop offset, +2 for extra rounding bits} + { for denormalized numbers (2 implied by dbra)} + move.w #27,d1 { bit number for "implied" pos (+4 for rounding)} + moveq.l #-1,d3 { zero quotient (for speed a one''s complement) } + sub.l d5,d4 { initial subtraction, u = u - v } +@dlabel7: + btst d1,d3 { divide until 1 in implied position } + beq @dlabel9 + + add.l d4,d4 + bcs @dlabel8 { if carry is set, add, else subtract } + + addx.l d3,d3 { shift quotient and set bit zero } + sub.l d5,d4 { subtract, u = u - v } + dbra d0,@dlabel7 { give up if result is denormalized } + bra @dlabel9 +@dlabel8: + addx.l d3,d3 { shift quotient and clear bit zero } + add.l d5,d4 { add (restore), u = u + v } + dbra d0,@dlabel7 { give up if result is denormalized } +@dlabel9: + subq.w #2,d0 { remove rounding offset for denormalized nums } + not.l d3 { invert quotient to get it right } + + clr.l d1 { zero rounding bits } + tst.l d4 { check for exact result } + beq @dlabel10 + moveq.l #-1,d1 { prevent tie case } +@dlabel10: + move.l d3,d4 { save quotient mantissa } + jmp FPC_SINGLE_NORM{ (registers on stack removed by norm_sf) } +end; + + +Procedure Single_Cmp; Assembler; +{--------------------------------------------} +{ Low-level routine to compare single two } +{ single point values.. } +{ Never called directly. } +{ On Entry: } +{ d1 and d0 Values to compare } +{ d0 = first operand } +{ On Exit: } +{ Flags according to result } +{ Registers destroyed: d0,d1 } +{--------------------------------------------} +Asm +XDEF SINGLE_CMP + tst.l d0 { check sign bit } + bpl @cmplab1 + neg.l d0 { negate } + bchg #31,d0 { toggle sign bit } +@cmplab1: + tst.l d1 { check sign bit } + bpl @cmplab2 + neg.l d1 { negate } + bchg #31,d1 { toggle sign bit } +@cmplab2: + cmp.l d0,d1 { compare... } + rts +end; + + + +Procedure LongMul;Assembler; +{--------------------------------------------} +{ Low-level routine to multiply two signed } +{ 32-bit values. Never called directly. } +{ On entry: d1,d0 = 32-bit signed values to } +{ multiply. } +{ On Exit: } +{ d0 = result. } +{ Registers destroyed: d0,d1 } +{ stack space used and restored: 10 bytes } +{--------------------------------------------} +Asm +XDEF LONGMUL + cmp.b #2,Test68000 { Are we on a 68020+ cpu } + blt @Lmulcontinue + muls.l d1,d0 { yes, then directly mul... } + rts { return... result in d0 } +@Lmulcontinue: + move.l d2,a0 { save registers } + move.l d3,a1 + + move.l d0,-(sp) + move.l d1,-(sp) + + movem.w (sp)+,d0-d3 { u = d0-d1, v = d2-d3 } + + move.w d0,-(sp) { sign flag } + bpl @LMul1 { is u negative ? } + neg.w d1 { yes, force it positive } + negx.w d0 +@LMul1: + tst.w d2 { is v negative ? } + bpl @LMul2 + neg.w d3 { yes, force it positive ... } + negx.w d2 + not.w (sp) { ... and modify flag word } +@LMul2: + ext.l d0 { u.h <> 0 ? } + beq @LMul3 + mulu.w d3,d0 { r = v.l * u.h } +@LMul3: + tst.w d2 { v.h <> 0 ? } + beq @LMul4 + mulu.w d1,d2 { r += v.h * u.l } + add.w d2,d0 +@LMul4: + swap d0 + clr.w d0 + mulu.w d3,d1 { r += v.l * u.l } + add.l d1,d0 + move.l a1,d3 + move.l a0,d2 + tst.w (sp)+ { should the result be negated ? } + bpl @LMul5 { no, just return } + neg.l d0 { else r = -r } +@LMul5: + rts +end; + + + +Procedure Long2Single;Assembler; +{--------------------------------------------} +{ Low-level routine to convert a longint } +{ to a single floating point value. } +{ On entry: d0 = longint value to convert. } +{ On Exit: } +{ d0 = single IEEE value } +{ Registers destroyed: d0,d1 } +{ stack space used and restored: 8 bytes } +{--------------------------------------------} +Asm +XDEF LONG2SINGLE + movem.l d2-d5,-(sp) { save registers to make norm_sf happy} + + move.l d0,d4 { prepare result mantissa } + move.w #BIAS4+32-8,d0 { radix point after 32 bits } + move.l d4,d2 { set sign flag } + bge @l2slabel1 { nonnegative } + neg.l d4 { take absolute value } +@l2slabel1: + swap d2 { follow SINGLE_NORM conventions } + clr.w d1 { set rounding = 0 } + jmp FPC_SINGLE_NORM +end; + + +Procedure LongDiv; [alias : 'FPC_LONGDIV'];Assembler; +{--------------------------------------------} +{ Low-level routine to do signed long } +{ division. } +{ On entry: d0/d1 operation to perform } +{ On Exit: } +{ d0 = quotient } +{ d1 = remainder } +{ Registers destroyed: d0,d1,d6 } +{ stack space used and restored: 10 bytes } +{--------------------------------------------} +asm +XDEF LONGDIV + cmp.b #2,Test68000 { can we use divs ? } + blt @continue + tst.l d1 + beq @zerodiv2 + move.l d1,d6 + clr.l d1 { clr } + tst.l d0 { check sign of d0 } + bpl @posdiv + move.l #$ffffffff,d1{ sign extend into d1 } +@posdiv: + divsl.l d6,d1:d0 + rts +@continue: + + move.l d2,a0 { save registers } + move.l d3,a1 + move.l d4,-(sp) { divisor = d1 = d4 } + move.l d5,-(sp) { divident = d0 = d5 } + + move.l d1,d4 { save divisor } + move.l d0,d5 { save dividend } + + clr.w -(sp) { sign flag } + + clr.l d0 { prepare result } + move.l d4,d2 { get divisor } + beq @zerodiv { divisor = 0 ? } + bpl @LDiv1 { divisor < 0 ? } + neg.l d2 { negate it } + not.w (sp) { remember sign } +@LDiv1: + move.l d5,d1 { get dividend } + bpl @LDiv2 { dividend < 0 ? } + neg.l d1 { negate it } + not.w (sp) { remember sign } +@LDiv2: +{;== case 1) divident < divisor} + cmp.l d2,d1 { is divident smaller then divisor ? } + bcs @LDiv7 { yes, return immediately } +{;== case 2) divisor has <= 16 significant bits} + move.l d4,d6 { put divisor in d6 register } + lsr.l #8,d6 { rotate into low word } + lsr.l #8,d6 + tst.l d6 + bne @LDiv3 { divisor has only 16 bits } + move.w d1,d3 { save dividend } + clr.w d1 { divide dvd.h by dvs } + swap d1 + beq @LDiv4 { (no division necessary if dividend zero)} + divu d2,d1 +@LDiv4: + move.w d1,d0 { save quotient.h } + swap d0 + move.w d3,d1 { (d0.h = remainder of prev divu) } + divu d2,d1 { divide dvd.l by dvs } + move.w d1,d0 { save quotient.l } + clr.w d1 { get remainder } + swap d1 + bra @LDiv7 { and return } +{;== case 3) divisor > 16 bits (corollary is dividend > 16 bits, see case 1)} +@LDiv3: + moveq.l #31,d3 { loop count } +@LDiv5: + add.l d1,d1 { shift divident ... } + addx.l d0,d0 { ... into d0 } + cmp.l d2,d0 { compare with divisor } + bcs @LDiv6 + sub.l d2,d0 { big enough, subtract } + addq.w #1,d1 { and note bit into result } +@LDiv6: + dbra d3,@LDiv5 + exg d0,d1 { put quotient and remainder in their registers} +@LDiv7: + tst.l d5 { must the remainder be corrected ? } + bpl @LDiv8 + neg.l d1 { yes, apply sign } +{ the following line would be correct if modulus is defined as in algebra} +{; add.l sp@(6),d1 ; algebraic correction: modulus can only be >= 0} +@LDiv8: + tst.w (sp)+ { result should be negative ? } + bpl @LDiv9 + neg.l d0 { yes, negate it } +@LDiv9: + move.l a1,d3 + move.l a0,d2 + move.l (sp)+,d5 + move.l (sp)+,d4 + rts { en exit : remainder = d1, quotient = d0 } +@zerodiv: + move.l a1,d3 { restore stack... } + move.l a0,d2 + move.w (sp)+,d1 { remove sign word } + move.l (sp)+,d5 + move.l (sp)+,d4 +@zerodiv2: + move.l #200,d0 + jsr FPC_HALT_ERROR { RunError(200) } + rts { this should never occur... } +end; + + +Procedure LongMod;[alias : 'FPC_LONGMOD'];Assembler; +{ see longdiv for info on calling convention } +asm +XDEF LONGMOD + jsr FPC_LONGDIV + move.l d1,d0 { return the remainder in d0 } + rts +end; + +{ + $Log: lowmath.inc,v $ + Revision 1.5 2005/02/14 17:13:30 peter + * truncate log + +} diff --git a/rtl/m68k/m68k.inc b/rtl/m68k/m68k.inc new file mode 100644 index 0000000000..4e98dcde26 --- /dev/null +++ b/rtl/m68k/m68k.inc @@ -0,0 +1,329 @@ +{ + $Id: m68k.inc,v 1.6 2005/02/14 17:13:30 peter Exp $ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Carl-Eric Codere, + member of the Free Pascal development team. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + 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. + + **********************************************************************} +{**************************************************************************** + + m68k.inc : Processor dependent implementation of system unit + For Motorola 680x0 Processor. + +*****************************************************************************} + +{****************************************************************************} +{ Credit where credit is due: } +{ -Some of the copy routines taken from the Atari dlib source code: } +{ Dale Schumacher (alias: Dalnefre') dal@syntel.uucp } +{ 399 Beacon Ave. St. Paul, MN 55104,USA } +{ -Some of the routines taken from the freeware ATARI Sozobon C compiler } +{ 1988 by Sozobon, Limited. Author: Johann Ruegg (freeware) } +{ Thanks to all these people wherever they maybe today! } +{****************************************************************************} + + +procedure fpc_cpuinit; + begin + end; + +{$define FPC_SYSTEM_HAS_GET_FRAME} +function get_frame : pointer; assembler; + asm + move.l a6,d0 + end; + + +{$define FPC_SYSTEM_HAS_GET_CALLER_ADDR} +function get_caller_addr(framebp : pointer) : pointer; + begin + asm + move.l FRAMEBP,a0 + cmp.l #0,a0 + beq @Lnul_address + move.l 4(a0),a0 + @Lnul_address: + move.l a0,@RESULT + end ['a0']; + end; + + +{$define FPC_SYSTEM_HAS_GET_CALLER_FRAME} +function get_caller_frame(framebp : pointer) : pointer; + begin + asm + move.l FRAMEBP,a0 + cmp.l #0,a0 + beq @Lnul_frame + move.l (a0),a0 + @Lnul_frame: + move.l a0,@RESULT + end ['a0']; + end; + + +{$define FPC_SYSTEM_HAS_SPTR} +function Sptr : Longint; + begin + asm + move.l sp,d0 + add.l #8,d0 + move.l d0,@RESULT + end ['d0']; + end; + + +{$define FPC_SYSTEM_HAS_FILLCHAR} +procedure FillChar(var x;count:longint;value:byte);[public,alias: 'FPC_FILL_OBJECT']; + begin + asm + move.l 8(a6), a0 { destination } + move.l 12(a6), d1 { number of bytes to fill } + move.b 16(a6),d0 { fill data } + cmpi.l #65535, d1 { check, if this is a word move } + ble @LMEMSET3 { use fast dbra mode } + bra @LMEMSET2 + @LMEMSET1: + move.b d0,(a0)+ + @LMEMSET2: + subq.l #1,d1 + cmp.l #-1,d1 + bne @LMEMSET1 + bra @LMEMSET5 { finished slow mode , exit } + + @LMEMSET4: { fast loop mode section 68010+ } + move.b d0,(a0)+ + @LMEMSET3: + dbra d1,@LMEMSET4 + + @LMEMSET5: + end ['d0','d1','a0']; + end; + + +{$ifdef dummy} +{ procedure strcopy(dstr,sstr : pointer;len : longint);[public,alias: 'STRCOPY'];} +procedure strcopy; assembler;[public,alias: 'FPC_STRCOPY']; +{---------------------------------------------------} +{ Low-level routine to copy a string to another } +{ string with maximum length. Never call directly! } +{ On Entry: } +{ a1.l = string to copy to } +{ a0.l = source string } +{ d0.l = maximum length of copy } +{ registers destroyed: a0,a1,d0,d1 } +{---------------------------------------------------} +asm +{ move.l 12(a6),a0 + move.l 16(a6),a1 + move.l 8(a6),d1 } + move.l d0,d1 + + move.b (a0)+,d0 { Get source length } + and.w #$ff,d0 + cmp.w d1,d0 { This is a signed comparison! } + ble @LM4 + move.b d1,d0 { If longer than maximum size of target, cut + source length } +@LM4: + andi.l #$ff,d0 { zero extend d0-byte } + move.l d0,d1 { save length to copy } + move.b d0,(a1)+ { save new length } + { Check if copying length is zero - if so then } + { exit without copying anything. } + tst.b d1 + beq @Lend + bra @LMSTRCOPY55 +@LMSTRCOPY56: { 68010 Fast loop mode } + move.b (a0)+,(a1)+ +@LMSTRCOPY55: + dbra d1,@LMSTRCOPY56 +@Lend: +end; + + +{ Concatenate Strings } +{ PARAMETERS ARE REVERSED COMPARED TO NORMAL! } +{ therefore online assembler may not parse the params as normal } +procedure strconcat(s1,s2 : pointer);[public,alias: 'STRCONCAT']; + begin + asm + move.b #255,d0 + move.l s1,a0 { a0 = destination } + move.l s2,a1 { a1 = source } + sub.b (a0),d0 { copyl:= 255 -length(s1) } + move.b (a1),d6 + and.w #$ff,d0 { Sign flags are checked! } + and.w #$ff,d6 + cmp.w d6,d0 { if copyl > length(s2) then } + ble @Lcontinue + move.b (a1),d0 { copyl:=length(s2) } +@Lcontinue: + move.b (a0),d6 + and.l #$ff,d6 + lea 1(a0,d6),a0 { s1[length(s1)+1] } + add.l #1,a1 { s2[1] } + move.b d0,d6 + { Check if copying length is zero - if so then } + { exit without copying anything. } + tst.b d6 + beq @Lend + bra @ALoop +@Loop: + move.b (a1)+,(a0)+ { s1[i] := s2[i]; } +@ALoop: + dbra d6,@Loop + move.l s1,a0 + add.b d0,(a0) { change to new string length } +@Lend: + end ['d0','d1','a0','a1','d6']; + end; + +{ Compares strings } +{ DO NOT CALL directly. } +{ a0 = pointer to first string to compare } +{ a1 = pointer to second string to compare } +{ ALL FLAGS are set appropriately. } +{ ZF = strings are equal } +{ REGISTERS DESTROYED: a0, a1, d0, d1, d6 } +procedure strcmp; assembler;[public,alias:'FPC_STRCMP']; +asm + move.b (a0)+,d0 { Get length of first string } + move.b (a1)+,d6 { Get length of 2nd string } + + move.b d6,d1 { Save length of string for final compare } + + cmp.b d0,d6 { Get shortest string length } + ble @LSTRCONCAT1 + move.b d0,d6 { Set length to shortest string } + + @LSTRCONCAT1: + tst.b d6 { Both strings have a length of zero, exit } + beq @LSTRCONCAT2 + + andi.l #$ff,d6 + + + subq.l #1,d6 { subtract first attempt } + { if value is -1 then don't loop and just compare lengths of } + { both strings before exiting. } + bmi @LSTRCONCAT2 + or.l d0,d0 { Make sure to set Zerfo flag to 0 } + @LSTRCONCAT5: + { Workaroung for GAS v.134 bug } + { old: cmp.b (a1)+,(a0)+ } + cmpm.b (a1)+,(a0)+ + @LSTRCONCAT4: + dbne d6,@LSTRCONCAT5 { Repeat until not equal } + bne @LSTRCONCAT3 + @LSTRCONCAT2: + { If length of both string are equal } + { Then set zero flag } + cmp.b d1,d0 { Compare length - set flag if equal length strings } + @LSTRCONCAT3: +end; +{$endif dummy} + + +{$define FPC_SYSTEM_HAS_MOVE} +procedure move(var source;var dest;count : longint); +{ base pointer+8 = source } +{ base pointer+12 = destination } +{ base pointer+16 = number of bytes to move} +begin + asm + clr.l d0 + move.l 16(a6),d0 { number of bytes } + @LMOVE0: + move.l 12(a6),a1 { destination } + move.l 8(a6),a0 { source } + + cmpi.l #65535, d0 { check, if this is a word move } + ble @LMEMSET00 { use fast dbra mode 68010+ } + + cmp.l a0,a1 { check copy direction } + bls @LMOVE4 + add.l d0,a0 { move pointers to end } + add.l d0,a1 + bra @LMOVE2 + @LMOVE1: + move.b -(a0),-(a1) { (s < d) copy loop } + @LMOVE2: + subq.l #1,d0 + cmpi.l #-1,d0 + bne @LMOVE1 + bra @LMOVE5 + @LMOVE3: + move.b (a0)+,(a1)+ { (s >= d) copy loop } + @LMOVE4: + subq.l #1,d0 + cmpi.l #-1,d0 + bne @LMOVE3 + bra @LMOVE5 + + @LMEMSET00: { use fast loop mode 68010+ } + cmp.l a0,a1 { check copy direction } + bls @LMOVE04 + add.l d0,a0 { move pointers to end } + add.l d0,a1 + bra @LMOVE02 + @LMOVE01: + move.b -(a0),-(a1) { (s < d) copy loop } + @LMOVE02: + dbra d0,@LMOVE01 + bra @LMOVE5 + @LMOVE03: + move.b (a0)+,(a1)+ { (s >= d) copy loop } + @LMOVE04: + dbra d0,@LMOVE03 + { end fast loop mode } + @LMOVE5: + end ['d0','a0','a1']; +end; + + +{$define FPC_SYSTEM_HAS_FILLWORD} +procedure fillword(var x;count : longint;value : word); + begin + asm + move.l 8(a6), a0 { destination } + move.l 12(a6), d1 { number of bytes to fill } + move.w 16(a6),d0 { fill data } + bra @LMEMSET21 + @LMEMSET11: + move.w d0,(a0)+ + @LMEMSET21: + subq.l #1,d1 + cmp.b #-1,d1 + bne @LMEMSET11 + end ['d0','d1','a0']; + end; + + +{$define FPC_SYSTEM_HAS_ABS_LONGINT} +function abs(l : longint) : longint; + begin + asm + move.l 8(a6),d0 + tst.l d0 + bpl @LMABS1 + neg.l d0 + @LMABS1: + move.l d0,@RESULT + end ['d0']; + end; + + +{ + $Log: m68k.inc,v $ + Revision 1.6 2005/02/14 17:13:30 peter + * truncate log + +} diff --git a/rtl/m68k/makefile.cpu b/rtl/m68k/makefile.cpu new file mode 100644 index 0000000000..be1724efeb --- /dev/null +++ b/rtl/m68k/makefile.cpu @@ -0,0 +1,7 @@ +# +# Here we set processor dependent include file names. +# + +CPUNAMES=m68k lowmath math set +CPUINCNAMES=$(addsuffix .inc,$(CPUNAMES)) + diff --git a/rtl/m68k/math.inc b/rtl/m68k/math.inc new file mode 100644 index 0000000000..c2608289ee --- /dev/null +++ b/rtl/m68k/math.inc @@ -0,0 +1,949 @@ +{ + $Id: math.inc,v 1.4 2005/02/14 17:13:30 peter Exp $ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by several people + member of the Free Pascal development team. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + 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. + + **********************************************************************} +{*************************************************************************} +{ math.inc } +{*************************************************************************} +{ Copyright Abandoned, 1987, Fred Fish } +{ } +{ This previously copyrighted work has been placed into the } +{ public domain by the author (Fred Fish) and may be freely used } +{ for any purpose, private or commercial. I would appreciate } +{ it, as a courtesy, if this notice is left in all copies and } +{ derivative works. Thank you, and enjoy... } +{ } +{ The author makes no warranty of any kind with respect to this } +{ product and explicitly disclaims any implied warranties of } +{ merchantability or fitness for any particular purpose. } +{-------------------------------------------------------------------------} +{ Copyright (c) 1992 Odent Jean Philippe } +{ } +{ The source can be modified as long as my name appears and some } +{ notes explaining the modifications done are included in the file. } +{-------------------------------------------------------------------------} +{ Copyright (c) 1997 Carl Eric Codere } +{ } +{*************************************************************************} +{ This is the Motorola 680x0 specific port of the math include. } +{*************************************************************************} +{ } +{ o all reals are mapped to the single type under the motorola version } +{ } +{ What is left to do: } +{ o add support for sqrt with fixed. } + +type + TabCoef = array[0..6] of Real; + + +const + PIO2 = 1.57079632679489661923; { pi/2 } + PIO4 = 7.85398163397448309616E-1; { pi/4 } + SQRT2 = 1.41421356237309504880; { sqrt(2) } + SQRTH = 7.07106781186547524401E-1; { sqrt(2)/2 } + LOG2E = 1.4426950408889634073599; { 1/log(2) } + SQ2OPI = 7.9788456080286535587989E-1; { sqrt( 2/pi )} + LOGE2 = 6.93147180559945309417E-1; { log(2) } + LOGSQ2 = 3.46573590279972654709E-1; { log(2)/2 } + THPIO4 = 2.35619449019234492885; { 3*pi/4 } + TWOOPI = 6.36619772367581343075535E-1; { 2/pi } + lossth = 1.073741824e9; + MAXLOG = 8.8029691931113054295988E1; { log(2**127) } + MINLOG = -8.872283911167299960540E1; { log(2**-128) } + + DP1 = 7.85398125648498535156E-1; + DP2 = 3.77489470793079817668E-8; + DP3 = 2.69515142907905952645E-15; + +const sincof : TabCoef = ( + 1.58962301576546568060E-10, + -2.50507477628578072866E-8, + 2.75573136213857245213E-6, + -1.98412698295895385996E-4, + 8.33333333332211858878E-3, + -1.66666666666666307295E-1, 0); + coscof : TabCoef = ( + -1.13585365213876817300E-11, + 2.08757008419747316778E-9, + -2.75573141792967388112E-7, + 2.48015872888517045348E-5, + -1.38888888888730564116E-3, + 4.16666666666665929218E-2, 0); + + + + + function int(d : real) : real; + begin + { this will be correct since real = single in the case of } + { the motorola version of the compiler... } + int:=real(trunc(d)); + end; + + function trunc(d : real) : longint; + var + l: longint; + Begin + asm + move.l d,d0 { get number } + move.l d2,-(sp) { save register } + move.l d0,d1 + swap d1 { extract exp } + move.w d1,d2 { extract sign } + bclr #15,d1 { kill sign bit } + lsr.w #7,d1 + + and.l #$7fffff,d0 { remove exponent from mantissa } + bset #23,d0 { restore implied leading "1" } + + cmp.w #BIAS4,d1 { check exponent } + blt @zero { strictly factional, no integer part ? } + cmp.w #BIAS4+32,d1 { is it too big to fit in a 32-bit integer ? } + bgt @toobig + + sub.w #BIAS4+24,d1 { adjust exponent } + bgt @trunclab2 { shift up } + beq @trunclab7 { no shift (never too big) } + + neg.w d1 + lsr.l d1,d0 { shift down to align radix point; } + { extra bits fall off the end (no rounding) } + bra @trunclab7 { never too big } + @trunclab2: + lsl.l d1,d0 { shift up to align radix point } + @trunclab3: + cmp.l #$80000000,d0 { -2147483648 is a nasty evil special case } + bne @trunclab6 + tst.w d2 { this had better be -2^31 and not 2^31 } + bpl @toobig + bra @trunclab8 + @trunclab6: + tst.l d0 { sign bit set ? (i.e. too big) } + bmi @toobig + @trunclab7: + tst.w d2 { is it negative ? } + bpl @trunclab8 + neg.l d0 { negate } + bra @trunclab8 + @zero: + clr.l d0 { make the whole thing zero } + bra @trunclab8 + @toobig: + moveq #-1,d0 { ugh. Should cause a trap here. } + bclr #31,d0 { make it #0x7fffffff } + @trunclab8: + move.l (sp)+,d2 + move.l d0,l + end; + if l = $7fffffff then + RunError(207) + else + trunc := l + end; + + + + + + function abs(d : Real) : Real; + begin + if( d < 0.0 ) then + abs := -d + else + abs := d ; + end; + + + function frexp(x:Real; var e:Integer ):Real; + {* frexp() extracts the exponent from x. It returns an integer *} + {* power of two to expnt and the significand between 0.5 and 1 *} + {* to y. Thus x = y * 2**expn. *} + begin + e :=0; + if (abs(x)<0.5) then + While (abs(x)<0.5) do + begin + x := x*2; + Dec(e); + end + else + While (abs(x)>1) do + begin + x := x/2; + Inc(e); + end; + frexp := x; + end; + + + function ldexp( x: Real; N: Integer):Real; + {* ldexp() multiplies x by 2**n. *} + var r : Real; + begin + R := 1; + if N>0 then + while N>0 do + begin + R:=R*2; + Dec(N); + end + else + while N<0 do + begin + R:=R/2; + Inc(N); + end; + ldexp := x * R; + end; + + + function polevl(var x:Real; var Coef:TabCoef; N:Integer):Real; + {*****************************************************************} + { Evaluate polynomial } + {*****************************************************************} + { } + { SYNOPSIS: } + { } + { int N; } + { double x, y, coef[N+1], polevl[]; } + { } + { y = polevl( x, coef, N ); } + { } + { DESCRIPTION: } + { } + { Evaluates polynomial of degree N: } + { } + { 2 N } + { y = C + C x + C x +...+ C x } + { 0 1 2 N } + { } + { Coefficients are stored in reverse order: } + { } + { coef[0] = C , ..., coef[N] = C . } + { N 0 } + { } + { The function p1evl() assumes that coef[N] = 1.0 and is } + { omitted from the array. Its calling arguments are } + { otherwise the same as polevl(). } + { } + { SPEED: } + { } + { In the interest of speed, there are no checks for out } + { of bounds arithmetic. This routine is used by most of } + { the functions in the library. Depending on available } + { equipment features, the user may wish to rewrite the } + { program in microcode or assembly language. } + {*****************************************************************} + var ans : Real; + i : Integer; + + begin + ans := Coef[0]; + for i:=1 to N do + ans := ans * x + Coef[i]; + polevl:=ans; + end; + + + function p1evl(var x:Real; var Coef:TabCoef; N:Integer):Real; + { } + { Evaluate polynomial when coefficient of x is 1.0. } + { Otherwise same as polevl. } + { } + var + ans : Real; + i : Integer; + begin + ans := x + Coef[0]; + for i:=1 to N-1 do + ans := ans * x + Coef[i]; + p1evl := ans; + end; + + + + + + function sqr(d : Real) : Real; + begin + sqr := d*d; + end; + + + function pi : Real; + begin + pi := 3.1415926535897932385; + end; + + + function sqrt(d:Real):Real; + {*****************************************************************} + { Square root } + {*****************************************************************} + { } + { SYNOPSIS: } + { } + { double x, y, sqrt(); } + { } + { y = sqrt( x ); } + { } + { DESCRIPTION: } + { } + { Returns the square root of x. } + { } + { Range reduction involves isolating the power of two of the } + { argument and using a polynomial approximation to obtain } + { a rough value for the square root. Then Heron's iteration } + { is used three times to converge to an accurate value. } + {*****************************************************************} + var e : Integer; + w,z : Real; + begin + if( d <= 0.0 ) then + begin + if( d < 0.0 ) then + RunError(207); + sqrt := 0.0; + end + else + begin + w := d; + { separate exponent and significand } + z := frexp( d, e ); + + { approximate square root of number between 0.5 and 1 } + { relative error of approximation = 7.47e-3 } + d := 4.173075996388649989089E-1 + 5.9016206709064458299663E-1 * z; + + { adjust for odd powers of 2 } + if odd(e) then + d := d*SQRT2; + + { re-insert exponent } + d := ldexp( d, (e div 2) ); + + { Newton iterations: } + d := 0.5*(d + w/d); + d := 0.5*(d + w/d); + d := 0.5*(d + w/d); + d := 0.5*(d + w/d); + d := 0.5*(d + w/d); + d := 0.5*(d + w/d); + sqrt := d; + end; + end; + + + + + function Exp(d:Real):Real; + {*****************************************************************} + { Exponential Function } + {*****************************************************************} + { } + { SYNOPSIS: } + { } + { double x, y, exp(); } + { } + { y = exp( x ); } + { } + { DESCRIPTION: } + { } + { Returns e (2.71828...) raised to the x power. } + { } + { Range reduction is accomplished by separating the argument } + { into an integer k and fraction f such that } + { } + { x k f } + { e = 2 e. } + { } + { A Pade' form of degree 2/3 is used to approximate exp(f)- 1 } + { in the basic range [-0.5 ln 2, 0.5 ln 2]. } + {*****************************************************************} + const P : TabCoef = ( + 1.26183092834458542160E-4, + 3.02996887658430129200E-2, + 1.00000000000000000000E0, 0, 0, 0, 0); + Q : TabCoef = ( + 3.00227947279887615146E-6, + 2.52453653553222894311E-3, + 2.27266044198352679519E-1, + 2.00000000000000000005E0, 0 ,0 ,0); + + C1 = 6.9335937500000000000E-1; + C2 = 2.1219444005469058277E-4; + var n : Integer; + px, qx, xx : Real; + begin + if( d > MAXLOG) then + RunError(205) + else + if( d < MINLOG ) then + begin + Runerror(205); + end + else + begin + + { Express e**x = e**g 2**n } + { = e**g e**( n loge(2) ) } + { = e**( g + n loge(2) ) } + + px := d * LOG2E; + qx := Trunc( px + 0.5 ); { Trunc() truncates toward -infinity. } + n := Trunc(qx); + d := d - qx * C1; + d := d + qx * C2; + + { rational approximation for exponential } + { of the fractional part: } + { e**x - 1 = 2x P(x**2)/( Q(x**2) - P(x**2) ) } + xx := d * d; + px := d * polevl( xx, P, 2 ); + d := px/( polevl( xx, Q, 3 ) - px ); + d := ldexp( d, 1 ); + d := d + 1.0; + d := ldexp( d, n ); + Exp := d; + end; + end; + + + function Round(d: Real): longint; + var + fr: Real; + tr: Real; + Begin + fr := Frac(d); + tr := Trunc(d); + if fr > 0.5 then + Round:=Trunc(d)+1 + else + if fr < 0.5 then + Round:=Trunc(d) + else { fr = 0.5 } + { check sign to decide ... } + { as in Turbo Pascal... } + if d >= 0.0 then + Round := Trunc(d)+1 + else + Round := Trunc(d); + end; + + + function Ln(d:Real):Real; + {*****************************************************************} + { Natural Logarithm } + {*****************************************************************} + { } + { SYNOPSIS: } + { } + { double x, y, log(); } + { } + { y = ln( x ); } + { } + { DESCRIPTION: } + { } + { Returns the base e (2.718...) logarithm of x. } + { } + { The argument is separated into its exponent and fractional } + { parts. If the exponent is between -1 and +1, the logarithm } + { of the fraction is approximated by } + { } + { log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). } + { } + { Otherwise, setting z = 2(x-1)/x+1), } + { } + { log(x) = z + z**3 P(z)/Q(z). } + { } + {*****************************************************************} + const P : TabCoef = ( + { Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + 1/sqrt(2) <= x < sqrt(2) } + + 4.58482948458143443514E-5, + 4.98531067254050724270E-1, + 6.56312093769992875930E0, + 2.97877425097986925891E1, + 6.06127134467767258030E1, + 5.67349287391754285487E1, + 1.98892446572874072159E1); + Q : TabCoef = ( + 1.50314182634250003249E1, + 8.27410449222435217021E1, + 2.20664384982121929218E2, + 3.07254189979530058263E2, + 2.14955586696422947765E2, + 5.96677339718622216300E1, 0); + + { Coefficients for log(x) = z + z**3 P(z)/Q(z), + where z = 2(x-1)/(x+1) + 1/sqrt(2) <= x < sqrt(2) } + + R : TabCoef = ( + -7.89580278884799154124E-1, + 1.63866645699558079767E1, + -6.41409952958715622951E1, 0, 0, 0, 0); + S : TabCoef = ( + -3.56722798256324312549E1, + 3.12093766372244180303E2, + -7.69691943550460008604E2, 0, 0, 0, 0); + + var e : Integer; + z, y : Real; + + Label Ldone; + begin + if( d <= 0.0 ) then + RunError(207); + d := frexp( d, e ); + + { logarithm using log(x) = z + z**3 P(z)/Q(z), + where z = 2(x-1)/x+1) } + + if( (e > 2) or (e < -2) ) then + begin + if( d < SQRTH ) then + begin + { 2( 2x-1 )/( 2x+1 ) } + Dec(e, 1); + z := d - 0.5; + y := 0.5 * z + 0.5; + end + else + begin + { 2 (x-1)/(x+1) } + z := d - 0.5; + z := z - 0.5; + y := 0.5 * d + 0.5; + end; + d := z / y; + { /* rational form */ } + z := d*d; + z := d + d * ( z * polevl( z, R, 2 ) / p1evl( z, S, 3 ) ); + goto ldone; + end; + + { logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) } + + if( d < SQRTH ) then + begin + Dec(e, 1); + d := ldexp( d, 1 ) - 1.0; { 2x - 1 } + end + else + d := d - 1.0; + + { rational form } + z := d*d; + y := d * ( z * polevl( d, P, 6 ) / p1evl( d, Q, 6 ) ); + y := y - ldexp( z, -1 ); { y - 0.5 * z } + z := d + y; + + ldone: + { recombine with exponent term } + if( e <> 0 ) then + begin + y := e; + z := z - y * 2.121944400546905827679e-4; + z := z + y * 0.693359375; + end; + + Ln:= z; + end; + + + + function Sin(d:Real):Real; + {*****************************************************************} + { Circular Sine } + {*****************************************************************} + { } + { SYNOPSIS: } + { } + { double x, y, sin(); } + { } + { y = sin( x ); } + { } + { DESCRIPTION: } + { } + { Range reduction is into intervals of pi/4. The reduction } + { error is nearly eliminated by contriving an extended } + { precision modular arithmetic. } + { } + { Two polynomial approximating functions are employed. } + { Between 0 and pi/4 the sine is approximated by } + { x + x**3 P(x**2). } + { Between pi/4 and pi/2 the cosine is represented as } + { 1 - x**2 Q(x**2). } + {*****************************************************************} + var y, z, zz : Real; + j, sign : Integer; + + begin + { make argument positive but save the sign } + sign := 1; + if( d < 0 ) then + begin + d := -d; + sign := -1; + end; + + { above this value, approximate towards 0 } + if( d > lossth ) then + begin + sin := 0.0; + exit; + end; + + y := Trunc( d/PIO4 ); { integer part of x/PIO4 } + + { strip high bits of integer part to prevent integer overflow } + z := ldexp( y, -4 ); + z := Trunc(z); { integer part of y/8 } + z := y - ldexp( z, 4 ); { y - 16 * (y/16) } + + j := Trunc(z); { convert to integer for tests on the phase angle } + { map zeros to origin } + if odd( j ) then + begin + inc(j); + y := y + 1.0; + end; + j := j and 7; { octant modulo 360 degrees } + { reflect in x axis } + if( j > 3) then + begin + sign := -sign; + dec(j, 4); + end; + + { Extended precision modular arithmetic } + z := ((d - y * DP1) - y * DP2) - y * DP3; + + zz := z * z; + + if( (j=1) or (j=2) ) then + y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 ) + else + { y = z + z * (zz * polevl( zz, sincof, 5 )); } + y := z + z * z * z * polevl( zz, sincof, 5 ); + + if(sign < 0) then + y := -y; + sin := y; + end; + + + + + function Cos(d:Real):Real; + {*****************************************************************} + { Circular cosine } + {*****************************************************************} + { } + { Circular cosine } + { } + { SYNOPSIS: } + { } + { double x, y, cos(); } + { } + { y = cos( x ); } + { } + { DESCRIPTION: } + { } + { Range reduction is into intervals of pi/4. The reduction } + { error is nearly eliminated by contriving an extended } + { precision modular arithmetic. } + { } + { Two polynomial approximating functions are employed. } + { Between 0 and pi/4 the cosine is approximated by } + { 1 - x**2 Q(x**2). } + { Between pi/4 and pi/2 the sine is represented as } + { x + x**3 P(x**2). } + {*****************************************************************} + var y, z, zz : Real; + j, sign : Integer; + i : LongInt; + begin + { make argument positive } + sign := 1; + if( d < 0 ) then + d := -d; + + { above this value, round towards zero } + if( d > lossth ) then + begin + cos := 0.0; + exit; + end; + + y := Trunc( d/PIO4 ); + z := ldexp( y, -4 ); + z := Trunc(z); { integer part of y/8 } + z := y - ldexp( z, 4 ); { y - 16 * (y/16) } + + { integer and fractional part modulo one octant } + i := Trunc(z); + if odd( i ) then { map zeros to origin } + begin + inc(i); + y := y + 1.0; + end; + j := i and 07; + if( j > 3) then + begin + dec(j,4); + sign := -sign; + end; + if( j > 1 ) then + sign := -sign; + + { Extended precision modular arithmetic } + z := ((d - y * DP1) - y * DP2) - y * DP3; + + zz := z * z; + + if( (j=1) or (j=2) ) then + { y = z + z * (zz * polevl( zz, sincof, 5 )); } + y := z + z * z * z * polevl( zz, sincof, 5 ) + else + y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 ); + + if(sign < 0) then + y := -y; + + cos := y ; + end; + + + + function ArcTan(d:Real):Real; + {*****************************************************************} + { Inverse circular tangent (arctangent) } + {*****************************************************************} + { } + { SYNOPSIS: } + { } + { double x, y, atan(); } + { } + { y = atan( x ); } + { } + { DESCRIPTION: } + { } + { Returns radian angle between -pi/2 and +pi/2 whose tangent } + { is x. } + { } + { Range reduction is from four intervals into the interval } + { from zero to tan( pi/8 ). The approximant uses a rational } + { function of degree 3/4 of the form x + x**3 P(x)/Q(x). } + {*****************************************************************} + const P : TabCoef = ( + -8.40980878064499716001E-1, + -8.83860837023772394279E0, + -2.18476213081316705724E1, + -1.48307050340438946993E1, 0, 0, 0); + Q : TabCoef = ( + 1.54974124675307267552E1, + 6.27906555762653017263E1, + 9.22381329856214406485E1, + 4.44921151021319438465E1, 0, 0, 0); + + { tan( 3*pi/8 ) } + T3P8 = 2.41421356237309504880; + { tan( pi/8 ) } + TP8 = 0.41421356237309504880; + + var y,z : Real; + Sign : Integer; + + begin + { make argument positive and save the sign } + sign := 1; + if( d < 0.0 ) then + begin + sign := -1; + d := -d; + end; + + { range reduction } + if( d > T3P8 ) then + begin + y := PIO2; + d := -( 1.0/d ); + end + else if( d > TP8 ) then + begin + y := PIO4; + d := (d-1.0)/(d+1.0); + end + else + y := 0.0; + + { rational form in x**2 } + + z := d * d; + y := y + ( polevl( z, P, 3 ) / p1evl( z, Q, 4 ) ) * z * d + d; + + if( sign < 0 ) then + y := -y; + Arctan := y; + end; + + function frac(d : Real) : Real; + begin + frac := d - Int(d); + end; + +{$ifdef fixed} + + + function sqrt(d : fixed) : fixed; + begin + end; + + function int(d : fixed) : fixed; assembler; + {*****************************************************************} + { Returns the integral part of d } + {*****************************************************************} + asm + move.l d,d0 + and.l #$ffff0000,d0 { keep only upper bits .. } + end; + + + function trunc(d : fixed) : longint; + {*****************************************************************} + { Returns the Truncated integral part of d } + {*****************************************************************} + begin + trunc:=longint(integer(d shr 16)); { keep only upper 16 bits } + end; + + function frac(d : fixed) : fixed; assembler; + {*****************************************************************} + { Returns the Fractional part of d } + {*****************************************************************} + asm + move.l d,d0 + and.l #$ffff,d0 { keep only decimal parts - lower 16 bits } + end; + + function abs(d : fixed) : fixed; + {*****************************************************************} + { Returns the Absolute value of d } + {*****************************************************************} + var + w: integer; + begin + w:=integer(d shr 16); + if w < 0 then + begin + w:=-w; { invert sign ... } + d:=d and $ffff; + d:=d or (fixed(w) shl 16); { add this to fixed number ... } + abs:=d; + end + else + abs:=d; { already positive... } + end; + + + function sqr(d : fixed) : fixed; + {*****************************************************************} + { Returns the Absolute squared value of d } + {*****************************************************************} + begin + {16-bit precision needed, not 32 =)} + sqr := d*d; +{ sqr := (d SHR 8 * d) SHR 8; } + end; + + + function Round(x: fixed): longint; + {*****************************************************************} + { Returns the Rounded value of d as a longint } + {*****************************************************************} + var + lowf:integer; + highf:integer; + begin + lowf:=x and $ffff; { keep decimal part ... } + highf :=integer(x shr 16); + if lowf > 5 then + highf:=highf+1 + else + if lowf = 5 then + begin + { here we must check the sign ... } + { if greater or equal to zero, then } + { greater value will be found by adding } + { one... } + if highf >= 0 then + Highf:=Highf+1; + end; + Round:= longint(highf); + end; +{$endif fixed} + + function power(bas,expo : real) : real; + begin + if bas=0.0 then + begin + if expo<>0.0 then + power:=0.0 + else + HandleError(207); + end + else if expo=0.0 then + power:=1 + else + { bas < 0 is not allowed } + if bas<0.0 then + handleerror(207) + else + power:=exp(ln(bas)*expo); + end; + + function power(bas,expo : longint) : longint; + begin + if bas=0 then + begin + if expo<>0 then + power:=0 + else + HandleError(207); + end + else if expo=0 then + power:=1 + else + begin + if bas<0 then + begin + if odd(expo) then + power:=-round(exp(ln(-bas)*expo)) + else + power:=round(exp(ln(-bas)*expo)); + end + else + power:=round(exp(ln(bas)*expo)); + end; + end; + +{ + $Log: math.inc,v $ + Revision 1.4 2005/02/14 17:13:30 peter + * truncate log + +} diff --git a/rtl/m68k/readme b/rtl/m68k/readme new file mode 100644 index 0000000000..0d769d90fd --- /dev/null +++ b/rtl/m68k/readme @@ -0,0 +1,7 @@ +This directory contains only RTL parts specific +to the processor M68K family. + + +Missing units are : + strings.pp (you can the strings unit in the template directory) + getopts.pp diff --git a/rtl/m68k/set.inc b/rtl/m68k/set.inc new file mode 100644 index 0000000000..72275a016d --- /dev/null +++ b/rtl/m68k/set.inc @@ -0,0 +1,428 @@ +{ + $Id: set.inc,v 1.4 2005/02/14 17:13:30 peter Exp $ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Carl-Eric Codere, + member of the Free Pascal development team. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + 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. + + **********************************************************************} +{*************************************************************************} +{ Converted by Carl Eric Codere } +{*************************************************************************} +{ This inc. implements low-level set operations for the motorola } +{ 68000 familiy of processors. } +{ Based on original code bt Florian Kl„mpfl for the 80x86. } +{*************************************************************************} + + + { add the element b to the set pointed by p } + { On entry } + { a0 = pointer to set } + { d0.b = element to add to the set } + { Registers destroyed: d0,a1,d6 } + procedure do_set;assembler; + asm + XDEF SET_SET_BYTE + move.l d0,d6 + { correct long position: } + { -> (value div 32)*4 = longint } + { (value shr 5)*shl 2 } + lsr.l #5,d6 + lsl.l #2,d6 + adda.l d6,a0 { correct offset from start address of set } + + move.l d0,d6 { bit is now in here } + andi.l #31,d0 { bit number is = value mod 32 } + + { now bit set the value } + move.l (a0),d0 { we must put bits into register } + bset.l d6,d0 { otherwise btst will be a byte } + { put result in carry flag } { operation. } + bne @LDOSET1 + andi.b #$fe,ccr { clear carry flag } + bra @LDOSET2 + @LDOSET1: + ori.b #$01,ccr { set carry flag } + @LDOSET2: + move.l d0,(a0) { restore the value at that location } + { of the set. } + end; + + { Finds an element in a set } + { a0 = address of set } + { d0.b = value to compare with } + { CARRY SET IF FOUND ON EXIT } + { Registers destroyed: d0,a0,d6 } + procedure do_in; assembler; + { Returns Carry set then = in set , otherwise carry is cleared } + { (D0) } + asm + XDEF SET_IN_BYTE + move.l d0,d6 + { correct long position: } + { -> (value div 32)*4 = longint } + { (value shr 5)*shl 2 } + lsr.l #5,d6 + lsl.l #2,d6 + adda.l d6,a0 { correct offset from start address of set } + + move.l d0,d6 { bit is now in here } + andi.l #31,d0 { bit number is = value mod 32 } + + move.l (a0),d0 { we must put bits into register } + btst.l d6,d0 { otherwise btst will be a byte } + { put result in carry flag } { operation. } + bne @LDOIN1 + andi.b #$fe,ccr { clear carry flag } + bra @LDOIN2 + @LDOIN1: + ori.b #$01,ccr { set carry flag } + @LDOIN2: + end; + + + + { vereinigt set1 und set2 und speichert das Ergebnis in dest } + + procedure add_sets(set1,set2,dest : pointer);[public,alias: 'SET_ADD_SETS']; + { PSEUDO-CODE: + type + destination = array[1..8] of longint; + for i:=1 to 8 do + destination(dest^)[i] := destination(set1^)[i] OR destination(set2^)[i]; + } + begin + asm + { saved used register } + move.l a2,-(sp) + + move.l 8(a6),a0 + move.l 12(a6),a1 + move.l 16(a6),a2 + + move.l #32,d6 + + @LMADDSETS1: + + move.b (a0)+,d0 + or.b (a1)+,d0 + move.b d0,(a2)+ + subq.b #1,d6 + bne @LMADDSETS1 + { restore register } + move.l a2,(sp)+ + end ['d0','d6','a0','a1']; + end; + + { computes the symetric diff from set1 to set2 } + { result in dest } + + procedure sym_sub_sets(set1,set2,dest : pointer);[public,alias: 'SET_SYMDIF_SETS']; + + begin + asm + { saved used register } + move.l a2,-(sp) + + move.l 8(a6),a0 + move.l 12(a6),a1 + move.l 16(a6),a2 + + move.l #32,d6 + + @LMADDSETS1: + + move.b (a0)+,d0 + move.b (a1)+,d1 + eor.b d1,d0 + move.b d0,(a2)+ + subq.b #1,d6 + bne @LMADDSETS1 + { restore register } + move.l a2,(sp)+ + end; + end; + + + { bad implementation, but it's very seldom used } + procedure do_set(p : pointer;l,h : byte);[public,alias: 'SET_SET_RANGE']; + + begin + asm + move.b h,d0 + @LSetRLoop: + cmp.b l,d0 + blt @Lend + move.w d0,-(sp) + { adjust value to correct endian } + lsl.w #8,d0 + pea p + jsr SET_SET_BYTE + sub.b #1,d0 + bra @LSetRLoop + @Lend: + end; + end; + + + { bildet den Durchschnitt von set1 und set2 } + { und speichert das Ergebnis in dest } + + procedure mul_sets(set1,set2,dest : pointer);[public,alias: 'SET_MUL_SETS']; + { type + larray = array[0..7] of longint; + for i:=0 to 7 do + larray(dest^)[i] := larray(set1^)[i] AND larray(set2^)[i]; + } + begin + asm + { saved used register } + move.l a2,-(sp) + move.l 8(a6),a0 + move.l 12(a6),a1 + move.l 16(a6),a2 + + move.l #32,d6 + + @LMMULSETS1: + + move.b (a0)+,d0 + and.b (a1)+,d0 + move.b d0,(a2)+ + subq.b #1,d6 + bne @LMMULSETS1 + { restore register } + move.l a2,(sp)+ + end ['d0','d6','a0','a1']; + end; + + + { bildet die Differenz von set1 und set2 } + { und speichert das Ergebnis in dest } + + procedure sub_sets(set1,set2,dest : pointer);[public,alias: 'SET_SUB_SETS']; + { type + larray = array[0..7] of longint; + begin + for i:=0 to 7 do + larray(dest^)[i] := larray(set1^)[i] AND NOT (larray(set2^)[i]); + end; + } + begin + asm + { saved used register } + move.l a2,-(sp) + move.l 8(a6),a0 + move.l 12(a6),a1 + move.l 16(a6),a2 + + move.l #32,d6 + + @LSUBSETS1: + move.b (a0)+,d0 + move.b (a1)+,d1 + not.b d1 + and.b d1,d0 + move.b d0,(a2)+ + sub.b #1,d6 + bne @LSUBSETS1 + { restore register } + move.l a2,(sp)+ + end ['d0','d1','d6','a0','a1']; + end; + + { compare both sets } + { compares set1 and set2 } + { zeroflag is set if they are equal } + { on entry : a0 = pointer to first set } + { : a1 = pointer to second set } + procedure comp_sets; assembler; + + asm + XDEF SET_COMP_SETS + move.l #32,d6 + @LMCOMPSETS1: + move.b (a0)+,d0 + move.b (a1),d1 + cmp.b d1,d0 + bne @LMCOMPSETEND + adda.l #1,a1 + sub.b #1,d6 + bne @LMCOMPSETS1 + { we are here only if the two sets are equal } + { we have zero flag set, and that what is expected } + cmp.b d0,d0 + @LMCOMPSETEND: + end; + + procedure do_set(p : pointer;b : word);[public,alias: 'SET_SET_WORD']; + begin + asm + move.l 8(a6),a0 + move.w 12(a6),d6 + andi.l #$fff8,d6 + lsl.l #3,d6 + adda.l d6,a0 + move.b 12(a6),d6 + andi.l #7,d6 + + move.l (a0),d0 { we must put bits into register } + btst.l d6,d0 { otherwise btst will be a byte } + { put result in carry flag } { operation. } + bne @LBIGDOSET1 + andi.b #$fe,ccr { clear carry flag } + bra @LBIGDOSET2 + @LBIGDOSET1: + ori.b #$01,ccr { set carry flag } + @LBIGDOSET2: + end ['d0','a0','d6']; + end; + + { testet, ob das Element b in der Menge p vorhanden ist } + { und setzt das Carryflag entsprechend } + + procedure do_in(p : pointer;b : word);[public,alias: 'SET_IN_WORD']; + begin + asm + move.l 8(a6),a0 + move.w 12(a6),d6 + andi.l #$fff8,d6 + lsl.l #3,d6 + adda.l d6,a0 { correct offset from start address of set } + + move.b 12(a6),d6 + andi.l #7,d6 + + move.l (a0),d0 { we must put bits into register } + btst.l d6,d0 { otherwise btst will be a byte } + { put result in carry flag } { operation. } + bne @LBIGDOIN1 + andi.b #$fe,ccr { clear carry flag } + bra @LBIGDOIN2 + @LBIGDOIN1: + ori.b #$01,ccr { set carry flag } + @LBIGDOIN2: + end ['d0','a0','d6']; + end; + + + { vereinigt set1 und set2 und speichert das Ergebnis in dest } + { size is the number of bytes in the set } + + procedure add_sets(set1,set2,dest : pointer;size : longint);[public,alias: 'SET_ADD_SETS_SIZE']; + begin + asm + { saved used register } + move.l a2,-(sp) + move.l 8(a6),a0 + move.l 12(a6),a1 + move.l 16(a6),a2 + + move.l 20(a6),d6 + + @LBIGMADDSETS1: + + move.l (a0)+,d0 + or.l (a1)+,d0 + move.l d0,(a2)+ + subq.l #4,d6 + bne @LBIGMADDSETS1 + { restore register } + move.l a2,(sp)+ + end ['d0','d6','a0','a1']; + end; + + + procedure mul_sets(set1,set2,dest : pointer;size : longint);[public,alias: 'SET_MUL_SETS_SIZE']; + { bildet den Durchschnitt von set1 und set2 } + { und speichert das Ergebnis in dest } + { size is the number of bytes in the set } + begin + asm + { saved used register } + move.l a2,-(sp) + move.l 8(a6),a0 + move.l 12(a6),a1 + move.l 16(a6),a2 + + move.l 20(a6),d6 + + @LBIGMMULSETS1: + + move.l (a0)+,d0 + and.l (a1)+,d0 + move.l d0,(a2)+ + subq.l #4,d6 + bne @LBIGMMULSETS1 + { restore register } + move.l a2,(sp)+ + end ['d0','d6','a0','a1']; + end; + + + { bildet die Differenz von set1 und set2 } + { und speichert das Ergebnis in dest } + { size is the number of bytes in the set } + + procedure sub_sets(set1,set2,dest : pointer;size : longint);[public,alias: 'SET_SUB_SETS_SIZE']; + begin + asm + { saved used register } + move.l a2,-(sp) + move.l 8(a6),a0 + move.l 12(a6),a1 + move.l 16(a6),a2 + + move.l 20(a6),d6 + + @BIGSUBSETS1: + + move.l (a0)+,d0 + not.l d0 + and.l (a1)+,d0 + move.l d0,(a2)+ + subq.l #4,d6 + bne @BIGSUBSETS1 + { restore register } + move.l a2,(sp)+ + end ['d0','d6','a0','a1']; + end; + + + { vergleicht Mengen und setzt die Flags entsprechend } + + procedure comp_sets(set1,set2 : pointer;size : longint);[public,alias: 'SET_COMP_SETS_SIZE']; + + + begin + asm + move.l 8(a6),a0 { set1 - esi} + move.l 12(a6),a1 { set2 - edi } + move.l 16(a6),d6 + @MCOMPSETS1: + move.l (a0)+,d0 + move.l (a1),d1 + cmp.l d1,d0 + bne @BIGMCOMPSETEND + add.l #4,a1 + subq.l #1,d6 + bne @MCOMPSETS1 + { we are here only if the two sets are equal } + { we have zero flag set, and that what is expected } + cmp.l d0,d0 + @BIGMCOMPSETEND: + end; + end; + +{ + $Log: set.inc,v $ + Revision 1.4 2005/02/14 17:13:30 peter + * truncate log + +} diff --git a/rtl/m68k/setjump.inc b/rtl/m68k/setjump.inc new file mode 100644 index 0000000000..baf7a01e9e --- /dev/null +++ b/rtl/m68k/setjump.inc @@ -0,0 +1,34 @@ +{ + $Id: setjump.inc,v 1.4 2005/02/14 17:13:30 peter Exp $ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by xxxx + member of the Free Pascal development team + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + 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. + + **********************************************************************} + +{********************************************************************** + Set_Jmp/Long_jmp + **********************************************************************} + +Function SetJmp (Var S : Jmp_buf) : longint;assembler;[Public, alias : 'FPC_SETJMP']; + +asm +end; + +Procedure longJmp (Var S : Jmp_buf; value : longint); assembler;[Public, alias : 'FPC_LONGJMP']; + +asm +end; + + $Log: setjump.inc,v $ + Revision 1.4 2005/02/14 17:13:30 peter + * truncate log + +} diff --git a/rtl/m68k/setjumph.inc b/rtl/m68k/setjumph.inc new file mode 100644 index 0000000000..1b6884e927 --- /dev/null +++ b/rtl/m68k/setjumph.inc @@ -0,0 +1,37 @@ +{ + $Id: setjumph.inc,v 1.6 2005/02/14 17:13:30 peter Exp $ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by xxxx + member of the Free Pascal development team + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + 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. + + **********************************************************************} + +{********************************************************************** + Declarations for SetJmp/LongJmp + **********************************************************************} + +Type + jmp_buf = packed record + fp : longint; { frame pointer } + sp : longint; { stack pointer } + pc : longint; { program counter } + aregs : array[0..3] of dword; { address registers (a2,a3,a4,a5) } + end; + PJmp_buf = ^jmp_buf; + +Function Setjmp (Var S : Jmp_buf) : longint; +Procedure longjmp (Var S : Jmp_buf; value : longint); + +{ + $Log: setjumph.inc,v $ + Revision 1.6 2005/02/14 17:13:30 peter + * truncate log + +} |