I'm replying to several postings at once here, since I'm in digest mode
anyway... We all know the subject by now, doing bignum arithmetic in F77
on a PDP-11, and all the side topics this have generated...
From: "Jerome H. Fine" <jhfinexgs2 at
compsys.to>
Johnny Billquist wrote:
Jerome H.
Fine wrote:
As for endian issues, I can define the most
significant word to be
at either end, but I tend to think that I will place the most significant
at the high end of the word since this allows FORTRAN 77 to use
octal to output the value correctly with 64 bit floating point values.
??? Not sure what you actually say here. Floating point values hardly have
anything to do with this. Pick whatever byte order you want, and stick
with it. Output is something you'll have to figure out anyway, and you
deal with any byte order you decided on then. Either way is not that
difficult. However, I'd recommend using little-endian, since that is the
"natural" order of the PDP-11, and F77 on the machine. That means you can
let it deal with 16-bit quantities natively without having to to byte
swapping.
Jerome Fine replies:
Please define little-endian and big endian.
This have now been covered, so I think I can safely skip this. If you
really need some help in figuring out what little and bigendian is, then
say so, and we'll take a crash course.
Also, I should have explained what I meant!
Specifically,
it should be possible to use floating point variables
as arguments to subroutines and let FORTRAN 77 take
care of allocating the actual storage by doing so:
And I don't see the need. When you pass arrays as arguments in FORTRAN,
you only pass pointers, and actually access the parameters in the callers
address space. So no allocation is done, nor need to be done.
Using REAL*8 as a return value from the function is actually what you are
most interested in anyway when you go down this lane, since it's the
result you might want to allocate space for automatically. However, it
will not help you beond 64 bits anyway, so it's a dead end. Bite the
bullet and do it in a way that will deal with arbitrary large values, if
that's what you want.
1000 FORMAT ( O25, O25 )
REAL * 8 Value1, Value2
CALL I64ADD ( Value1, Value2 )
TYPE 1000, Value1, Value2
I64ADD::
Mov R0,-(SP)
Mov R1,-(SP)
Mov 2(R5),R0
Mov 4(R5),R1
Add (R0)+,(R1)+
Adc (R1)
Add (R0)+,(R1)+
Adc (R1)+
Add (R0)+,(R1)+
Adc (R1)+
Add (R0)+,(R1)+
Mov (SP)+,R1
Mov (SP)+,R0
Return
.End
This code has a bug in it, as has been pointed out. You actually needs to
do the ADC for all subsequent words after each add step, since every ADC
in turn also can generate a carry.
If I am correct, the above code assumes that the low
order
words/bytes are the least significant and the high order
words/bytes are the most significant. Is this little-endian
or big-endian?
Yes, and that is little-endian.
Well, actually, your code only assumes that the *words* are little endian.
You don't look at individual bytes, and thus the CPU can have them either
little or bigendian without you knowing.
NOTE that if the most significant bit is in the most
significant word and byte (as per the above MACRO-11
subroutine), then the most significant of everything
is in the highest address of everything. HOWEVER, from
looking at the order of bytes, words and bits in the
PDP-11 manual (Chapter 10 of Microcomputer Processor
Handbook), when the most significant bit is in the
word with the lowest address, the most significant
bit (actually the sign bit and the exponent of real
floating point numbers) is in byte 1 rather than byte 0.
Please stop looking at floating point data, since it's a whole other game.
I'll even repeat this: DON'T TRY TO USE FP, IT'S A WHOLE OTHER ISSUE IN
ALL ASPECTS! Even endianess don't actually apply to fp.
If you look at how 16-bit integers are stored in memory, you'll see that
the most significant bit of the 16 is stored in bit 7 of byte 1. And thus,
the least significan bit is stored in bit 0 of byte 0, which is a
small-endian machine.
[...]
Date: Sat, 30 Jul 2005 21:54:05 -0400
From: "Jerome H. Fine" <jhfinexgs2 at compsys.to>
Subject: Re: FORTRAN 77 on PDP-11
To: General Discussion: On-Topic and Off-Topic Posts
<cctalk at classiccmp.org>
Message-ID: <42EC2F3D.1080901 at compsys.to>
Content-Type: text/plain; charset=us-ascii; format=flowed
Johnny Billquist wrote:
Jerome H.
Fine wrote:
More seriously, if I am using all 16 bits as
unsigned integers, then
the high order bit can't be easily eliminated.
True. And if you don't use all 16 bits, then the MUL instruction deals
with the sign itself anyway, so there is no need to take absolute values
and so on either... In short, a good suggestion in theory, but one that
don't work in real life.
But of course you still haven't reflected on the fact that in FORTRAN-77
you can do 32-bit integer multiplication already...
Jerome Fine replies:
OK. I just checked how FORTRAN 77 internally handles:
INTEGER * 4 ITest1, ITest2, ITest3
REAL * 8 RTest1, RTest2, RTest3
ITest1 = 65536
ITest2 = 10
ITest1 = ITest1 * ITest2
The integer instruction Mul allows only 2 signed 16 bit numbers
that then produce a 32 bit number. When 2 signed 32 bit numbers
are multiplied, FORTRAN 77 first converts them to floating point
numbers, multiplies them as 2 real 64 bit numbers and converts the
result back to an integer.
What FORTRAN 77 are you using??? You gotta be kidding. Here is my small
example code:
-----------
PDP-11 FORTRAN-77 V5.4-26 20:35:33 31-JUL-05 Page 1
TMUL.FTN;1
0001 PROGRAM TEST
0002 INTEGER*4 X,Y,Z
0003 X = 42
0004 Y = 4711
0005 Z = X*Y
0006 END
PDP-11 FORTRAN-77 V5.4-26 20:35:33 31-JUL-05 Page 2
TMUL.FTN;1
.TITLE TEST
.IDENT 31JUL
000000 .PSECT $CODE1
000000 JSR PC,OTI$
000004 MOV #76400,-(SP)
000010 MOV #76733,R4
000014 JSR R4,@$NAM$
; 0003
000020 MOV #-3,$SEQC
000026 MOV #52,X
000034 CLR X+2
; 0004
000040 MOV #11147,Y
000046 CLR Y+2
; 0005
000052 MOV X+2,-(SP)
000056 MOV X,-(SP)
000062 MOV Y+2,-(SP)
000066 MOV Y,-(SP)
000072 JSR R4,MLJS$
000076 MOV (SP)+,Z
000102 MOV (SP)+,Z+2
; 0006
000106 JSR PC,EXIT$
------------
Notice how the compiler pushes two 32-bit integers on the stack and calls
MLJS$
Where did you find any FP stuff???
The rest of your questions about F77 are irrelevant, since you are asking
things on the compiler, but the compiler clearly don't do what you say.
Johnny (or anyone else), can you please comment on if
it is
necessary for FORTRAN 77 to use the stack? If it is not
needed, why does FORTRAN 77 use this approach?
The reason for using the stack is that FORTAN-77 have a calling convention
using R4 as the argument pointer. And since the function for doing 32-bit
multiplications is just a function, the parameters needs to be passed
somehow, and the stack is a very good choise.
As for the algoritm for the sieve, I'll skip that part, since I haven't
given it enough thought to see if what you say make sense or not. And I'm
not overly interested in primes, so please don't ask me. I remember from
my math classes that a sieve is both memory inefficient and slow. Doing
factorization is rather fast in comparision, so unless you want to print
all primes you can think of, it would be faster. Doing them all will be
slower, but will use a fixed, very small amount of memory anyhow.
[---]
Date: Sat, 30 Jul 2005 22:28:28 -0400 (EDT)
From: der Mouse <mouse at Rodents.Montreal.QC.CA>
Subject: Re: FORTRAN 77 on PDP-11
To: "General Discussion: On-Topic and Off-Topic Posts"
<cctalk at classiccmp.org>
Message-ID: <200507310254.WAA18849 at Sparkle.Rodents.Montreal.QC.CA>
Content-Type: text/plain; charset="iso-8859-1"
Please define little-endian and big endian.
Little-endian and big-endian apply whenever you have a multi-digit
value broken up into smaller ordered multi-digit units. (Usually this
is for base-2 digits, but it doesn't have to be.) Most often, the
smaller units are 8-bit bytes, with the order being memory addressing,
but this doesn't have to be so. (An example that violates all of those
assumptions is sending multi-bit bytes over a bit-serial line, where
the "smaller..units" are individual bits, ordered by chronology on the
wire.)
[...]
Good enough that we hopefully can terminate that question?
The PDP-11 is an odd case. The hardware is
little-endian, but the
hardware is 16-bit. Some languages store 32-bit integers in what we
might call "schizophrenic endian": that 12345678 value is stored in
four consecutive bytes as 34 12 78 56: it is broken into two 16-bit
words with the more-significant one stored first, but those 16-bit
words are then stored little-endian in the bytes making them up.
The (I believe) official term is "middle-endian". :-)
And like I believe I said before, FORTRAN-77 on the PDP-11 is pure
little-endian. FORTRAN IV however, is middle-endian.
I think I've written a small test program in most languages that have
32-bits integers on the PDP-11, which shows what byte order they use, if
someone is interested.
[...]
I64ADD::
Mov R0,-(SP)
Mov R1,-(SP)
Mov 2(R5),R0
Mov 4(R5),R1
Add (R0)+,(R1)+
Adc (R1)
Add (R0)+,(R1)+
Adc (R1)+
Add (R0)+,(R1)+
Adc (R1)+
Add (R0)+,(R1)+
Mov (SP)+,R1
Mov (SP)+,R0
Return
I see two problems here. First, you have to eliminate the
postincrement on the second and third ADC instructions.
Yup.
Second, this
loses carries resulting from the ADCs.
Yup.
(Also,
the return instruction is normally spelled "ret", not "return".)
Nope.
The PDP-11 don't have a RET instruction. RETURN is actually a macro, and
is the usual name used for this.
If you want the actuall assembler mnemonic, it's "RTS PC" :-)
CALL is the same deal... Don't exist either, and is instead a macro, so
"CALL nnn" gets translated to "JSR PC,nnn"
Johnny
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: bqt at update.uu.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol