PDP-11 architecture

The PDP-11 architecture[1] is an instruction set architecture (ISA) developed by Digital Equipment Corporation (DEC). It is implemented by central processing units (CPUs) and microprocessors used in PDP-11 minicomputers. It was in wide use during the 1970s, but was eventually overshadowed by the more powerful VAX-11 architecture in the 1980s.

MemoryEdit

Data formatsEdit

Sixteen-bit words are stored little-endian (with least significant bytes first). Thirty-two-bit data—supported as extensions to the basic architecture, e.g., floating point in the FPU Instruction Set, double-words in the Extended Instruction Set or long data in the Commercial Instruction Set—are stored in more than one format, including an unusual middle-endian format[2][3] sometimes referred to as "PDP-endian".

Memory managementEdit

The PDP-11's 16-bit addresses can address 64 KB. By the time the PDP-11 yielded to the VAX, 8-bit bytes and hexadecimal notation were becoming standard in the industry; however, numeric values on the PDP-11 always use octal notation, and the amount of memory attached to a PDP-11 is always stated as a number of words. The basic logical address space is 32K words, but the high 4K of physical address space (addresses 1600008 through 1777778 in the absence of memory management) are not populated because input/output registers on the bus respond to addresses in that range. So originally, a fully loaded PDP-11 had 28K words.

The processor reserves low memory addresses for two-word vectors that give a program counter and processor status word with which to begin a service routine. When an I/O device interrupts a program, it places the address of its vector on the bus to indicate which service routine should take control. The lowest vectors are service routines to handle various types of trap. Traps occur on some program errors, such as an attempt to execute an undefined instruction; and also when the program executes an instruction such as BPT, EMT, IOT, or TRAP to request service from the operating system.

Memory expansionEdit

The article PDP-11 describes how the 16-bit logical address space became an insurmountable limitation. During the life of the PDP-11, the following techniques were used to work around the limitation:

  • Later-model PDP-11 processors included memory management to support virtual addressing. The physical address space was extended to 18 or 22 bits, hence allowing up to 256 KB or 4 MB of RAM. The logical address space (that is, the address space available at any moment without changing the memory mapping table) remained limited to 16 bits.
  • Some models, beginning with the PDP-11/45, can be set to use 32K words (64 KB) as the "instruction space" for program code and a separate 32K words of "data space". Some operating systems—notably Unix since edition V7, and RSX11-M+—rely on this feature.
  • Programming techniques, such as overlaying a block of stored instructions or data with another as needed, can conceal paging issues from the application programmer. For example, the Modula-2 compiler produces code under which the run-time system swaps 8 Kb pages into memory as individual procedures receive control. (See the external reference here.)

CPU registersEdit

DEC PDP-11 registers
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 (bit position)
Main registers
R0 Register 0
R1 Register 1
R2 Register 2
R3 Register 3
R4 Register 4
R5 Register 5
Stack pointer
R6 / SP Register 6 / Stack Pointer
Program counter
R7 / PC Register 7 / Program Counter
Status flags
  I T N Z V C Processor Status Word
    Floating Point Status Register

The CPU contains eight general-purpose 16-bit registers (R0 to R7). Register R7 is the program counter (PC). Although any register can be used as a stack pointer, R6 is the stack pointer (SP) used for hardware interrupts and traps. R5 is often used to point to the current procedure call frame. To speed up context switching, some PDP-11 models provide dual R1-R5 register sets. Kernel, Supervisor (where present), and User modes have separate memory maps, and also separate stack pointers (so that a user program cannot cause the system to malfunction by storing an invalid value in the stack pointer register).

Addressing modesEdit

Most instructions allocate six bits to specify an operand. Three bits select one of eight addressing modes, and three bits select a general register.

The encoding of the six bit operand addressing mode is as follows:

5 3 2 0
Mode Register


In the following sections, each item includes an example of how the operand would be written in assembly language. Rn means one of the eight registers, written R0 through R7.

General register addressing modesEdit

The following eight modes can be applied to any general register. Their effects when applied to R6 (the stack pointer, SP) and R7 (the program counter, PC) are set out separately in the following sections.

Code Name Example Description
0n Register Rn The operand is in Rn
1n Register deferred (Rn) Rn contains the address of the operand
2n Autoincrement (Rn)+ Rn contains the address of the operand, then increment Rn
3n Autoincrement deferred @(Rn)+ Rn contains the address of the address of the operand, then increment Rn by 2
4n Autodecrement −(Rn) Decrement Rn, then use the result as the address of the operand
5n Autodecrement deferred @−(Rn) Decrement Rn by 2, then use the result as the address of the address of the operand
6n Index X(Rn) Rn+X is the address of the operand
7n Index deferred @X(Rn) Rn+X is the address of the address of the operand

In index and index deferred modes, X is a 16-bit value taken from a second word of the instruction. In double-operand instructions, both operands can use these modes. Such instructions are three words long.

Autoincrement and autodecrement operations on a register are by 1 in byte instructions, by 2 in word instructions, and by 2 whenever a deferred mode is used, since the quantity the register addresses is a (word) pointer.

Program counter addressing modesEdit

When R7 (the program counter) is specified, four of the addressing modes naturally yield useful effects:

Code Name Example Description
27 Immediate #n The operand is the next word of the instruction
37 Absolute @#a The address of the operand is the next word of the instruction
67 Relative a The address of the operand is the next word of the instruction added to the PC
77 Relative deferred @a The address of the address of the operand is the next word of the instruction added to PC

The only common use of absolute mode, whose syntax combines immediate and deferred mode, is to specify input/output registers, as the registers for each device have specific memory addresses. Relative mode has a simpler syntax and is more typical for referring to program variables and jump destinations. A program that uses relative mode (and relative deferred mode) exclusively for internal references is position-independent; it contains no assumptions about its own location, so it can be loaded into an arbitrary memory location, or even moved, with no need for its addresses to be adjusted to reflect its location (relocated). In computing such addresses relative to the current location, the processor performed relocation on the fly.

Immediate and absolute modes are merely autoincrement and autoincrement deferred mode, respectively, applied to PC. When the auxiliary word is "in the instruction" as the above table says, the PC for the next instruction is automatically incremented past the auxiliary word. As PC always points to words, the autoincrement operation is always by 2.

Stack addressing modesEdit

R6, also written SP, is used as a hardware stack for traps and interrupts. A convention enforced by the set of modes the PDP-11 provides is that a stack grows downward—toward lower addresses—as items are pushed onto it. When a mode is applied to SP, or to any register the programmer elects to use as a software stack, the addressing modes have the following effects:

Code Name Example Description
16 Deferred (SP) The operand is on the top of the stack
26 Autoincrement (SP)+ The operand is on the top of the stack, then pop it off
36 Autoincrement deferred @(SP)+ A pointer to the operand is on top of the stack; pop the pointer off
46 Autodecrement −(SP) Push a value onto the stack
66 Indexed X(SP) This refers to any item on the stack by its positive distance from the top
76 Indexed deferred @X(SP) This refers to a value to which a pointer is at the specified location on the stack

Although software stacks can contain bytes, SP is always a stack of words. Autoincrement and autodecrement operations on SP is always by 2.

Instruction setEdit

The PDP-11 operates on bytes and words. Bytes are specified by a register number—identifying the register's low-order byte—or by a memory location. Words are specified by a register number or by the memory location of the low-order byte, which must be an even number. In most instructions that take operands, bit 15 is set to specify byte addressing, or clear to specify word addressing. In the lists in the following two sections, the assembly-language programmer appended B to the instruction symbol to specify a byte operation; for example, MOV became MOVB.

A few instructions, for example MARK and SOB, were not implemented on some PDP-11 models.

Double-operand instructionsEdit

The high-order four bits specify the operation to be performed (with bit 15 generally selecting word versus byte addressing). Two groups of six bits specify the source operand addressing mode and the destination operand addressing mode, as defined above.

15 12 11 9 8 6 5 3 2 0
Opcode Src Register Dest Register
Opcode Mnemonic Operation
01 MOV Move: Dest ← Src

Note: Moving byte to a register sign-extends into bits 8-15

11 MOVB
02 CMP Compare: Set-flags(Src − Dest)
12 CMPB
03 BIT Bit test: Set-flags(Src ∧ Dest)
13 BITB
04 BIC Bit clear: Dest ← Dest ∧ Ones-complement(Src)
14 BICB
05 BIS Bit set: Dest ← Dest ∨ Src
15 BISB
06 ADD Add: Dest ← Dest + Src
16 SUB Subtract: Dest ← Dest − Src

The ADD and SUB instructions use word addressing, and have no byte-oriented variations.

Some two-operand instructions utilize an addressing mode operand and an additional register operand:

15 9 8 6 5 3 2 0
Opcode Reg Src/Dest Register

Where a register pair is used (written below as "(Reg, Reg+1)", the first register contains the low-order portion of the operand and must be an even numbered register. The next higher numbered register contains the high-order portion of the operand (or the remainder). An exception is the multiply instruction; Reg may be odd, but if it is, the high 16 bits of the result are not stored.

Opcode Mnemonic Operation
070 MUL Multiply: (Reg, Reg+1) ← Reg × Src
071 DIV Divide: Compute (Reg, Reg+1) ÷ Src; Reg ← quotient; Reg+1 ← remainder
072 ASH Arithmetic shift: if Src<5:0> < 0 then Reg ← Shift-right(Reg, -Src<5:0>) else Reg ← Shift-left(Reg, Src<5:0>)
073 ASHC Arithmetic shift combined: if Src<5:0> < 0 then (Reg, Reg+1) ← Shift-right((Reg, Reg+1), -Src<5:0>)

else (Reg, Reg+1) ← Shift-left((Reg, Reg+1), Src<5:0>)

074 XOR Exclusive or: Dest ← Dest ⊻ Reg

Single-operand instructionsEdit

The high-order ten bits specify the operation to be performed, with bit 15 generally selecting byte versus word addressing. A single group of six bits specifies the operand as defined above.

15 6 5 3 2 0
Opcode Src/Dest Register
Opcode Mnemonic Operation
0001 JMP Jump: PC ← Src
0003 SWAB Swap bytes of word: Dest ← Swap-bytes(Dest)
0050 CLR Clear: Dest ← 0
1050 CLRB
0051 COM Complement: Dest ← Ones-complement(Dest)
1051 COMB
0052 INC Increment: Dest ← Dest + 1
1052 INCB
0053 DEC Decrement: Dest ← Dest − 1
1053 DECB
0054 NEG Negate: Dest ← Twos-complement(Dest)
1054 NEGB
0055 ADC Add carry: Dest ← Dest + C flag
1055 ADCB
0056 SBC Subtract carry: Dest ← Dest - C flag
1056 SBCB
0057 TST Test: Set-flags(Src)
1057 TSTB
0060 ROR Rotate right: Dest ← Rotate-right(Dest, 1)
1060 RORB
0061 ROL Rotate left: Dest ← Rotate-left(Dest, 1)
1061 ROLB
0062 ASR Arithmetic shift right: Dest ← Shift-right(Dest, 1)
1062 ASRB
0063 ASL Arithmetic shift left: Dest ← Shift-left(Dest, 1)
1063 ASLB
1064 MTPS Move to PSW: PSW ← Src
0065 MFPI Move from previous I space: −(SP) ← Src
1065 MFPD Move from previous D space: −(SP) ← Src
0066 MTPI Move to previous I space: Dest ← (SP)+
1066 MTPD Move to previous D space: Dest ← (SP)+
0067 SXT Sign extend: if N flag ≠ 0 then Dest ← -1 else Dest ← 0
1067 MFPS Move from PSW: Dest ← PSW

Branch instructionsEdit

In most branch instructions, whether the branch is taken is based on the state of the condition codes. A branch instruction is typically preceded by a two-operand CMP (compare) or BIT (bit test) or a one-operand TST (test) instruction. Arithmetic and logic instructions also set the condition codes. In contrast to Intel processors in the x86 architecture, MOV instructions set them too, so a branch instruction could be used to branch depending on whether the value moved was zero or negative.

The high-order byte of the instruction specifies the operation. Bits 9 through 15 are the op-code, and bit 8 is the value of the condition code calculation which results in the branch being taken. The low-order byte is a signed word offset relative to the current location of the program counter. This allows for forward and reverse branches in code.

15 9 8 7 0
Opcode C Offset
Opcode C Mnemonic Condition or Operation
000 1 BR Branch always PC ← PC + 2 × Sign-extend(Offset)
001 0 BNE Branch if not equal Z = 0
001 1 BEQ Branch if equal Z = 1
002 0 BGE Branch if greater than or equal (N ⊻ V) = 0
002 1 BLT Branch if less than (N ⊻ V) = 1
003 0 BGT Branch if greater than (Z ∨ (N ⊻ V)) = 0
003 1 BLE Branch if less than or equal (Z ∨ (N ⊻ V)) = 1
100 0 BPL Branch if plus N = 0
100 1 BMI Branch if minus N = 1
101 0 BHI Branch if higher (C ∨ Z) = 0
101 1 BLOS Branch if lower or same (C ∨ Z) = 1
102 0 BVC Branch if overflow clear V = 0
102 1 BVS Branch if overflow set V = 1
103 0 BCC or BHIS Branch if carry clear, or Branch if higher or same C = 0
103 1 BCS or BLO Branch if carry set, or Branch if lower C = 1

The limited range of the branch instructions meant that, as code grew, the target addresses of some branches would become unreachable. The programmer would change the one-word BR to the two-word JMP instruction from the next group. As JMP has no conditional forms, the programmer would change BEQ to a BNE that branched around a JMP.

SOB (Subtract One and Branch) is another conditional branch instruction. The specified register is decremented by 1, and if the result is not zero, a reverse branch is taken based on the 6 bit word offset.

15 9 8 6 5 0
Opcode Reg Offset
Opcode Mnemonic Operation
077 SOB Subtract One and Branch: Reg ← Reg - 1; if Reg ≠ 0 then PC ← PC - 2 × Offset

Subroutine instructionsEdit

The JSR instruction could save any register on the stack. Programs that did not need this feature specified PC as the register (JSR PC,address) and the routine returned using RTS PC. If a routine were called with, for instance, "JSR R4, address", then the old value of R4 would be on the top of the stack and the return address (just after JSR) would be in R4. This let the routine gain access to values coded in-line by specifying (R4)+, or to in-line pointers by specifying @(R4)+. The autoincrementation moved past these data, to the point at which the caller's code resumed. Such a routine would have to specify RTS R4 to return to its caller.

15 9 8 6 5 3 2 0
Opcode Reg Src Register
Opcode Mnemonic Operation
004 JSR Jump to subroutine: -(SP) ← Reg; Reg ← PC; PC ← Src
15 3 2 0
Opcode Reg
Opcode Mnemonic Operation
00020 RTS Return from subroutine: PC ← Reg; Reg ← (SP)+

Trap instructionsEdit

15 9 8 7 0
Opcode S Operation Code
Opcode S Mnemonic Operation
104 0 EMT Emulator trap: -(SP) ← PS; -(SP) ← PC; PC ← (30); PS ← (32)
104 1 TRAP General trap: -(SP) ← PS; -(SP) ← PC; PC ← (34); PS ← (36)
15 0
Opcode
Opcode Mnemonic Operation
000002 RTI Return from interrupt: PC ← (SP)+; PS ← (SP)+
000003 BPT Breakpoint trap: -(SP) ← PS; -(SP) ← PC; PC ← (14); PS ← (16)
000004 IOT I/O trap: -(SP) ← PS; -(SP) ← PC; PC ← (20); PS ← (22)
000006 RTT Return from trap: PC ← (SP)+; PS ← (SP)+

Trap and Exception Vector Address AssignmentsEdit

Vector Condition
000000 (Reserved)
000004 Illegal instruction, bus error, stack limit
000010 Reserved instruction
000014 BPT instruction, trace trap
000020 IOT instruction
000030 EMT instruction
000034 TRAP instruction
000244 Floating point exception
000250 Memory management fault

Miscellaneous instructionsEdit

15 0
Opcode
Opcode Mnemonic Operation
000000 HALT Halt processor: Halt execution before next instruction
000001 WAIT Wait for interrupt: Halt execution before next instruction; Resume execution at next interrupt handler
000005 RESET Reset UNIBUS: Assert INIT on UNIBUS for 10 ms; All other devices reset to power up state

Condition-code operationsEdit

15 6 5 4 3 2 1 0
Opcode 1 S N Z V C
Opcode S Mnemonic Operation
0002 0 Ccc Clear condition codes: Clear codes according to N, Z, V, C bits
0002 1 Scc Set condition codes: Set codes according to N, Z, V, C bits

The four condition codes in the processor status word (PSW) are

  • N indicating a negative value
  • Z indicating a zero (equal) condition
  • V indicating an overflow condition, and
  • C indicating a carry condition.

Instructions in this group were what Digital called "micro-programmed": A single bit in the instruction word referenced a single condition code. The assembler did not define syntax to specify every combination, but the symbols SCC and CCC assembled an instruction that set or cleared, respectively, all four condition codes.

Clearing or setting none of the condition codes (opcodes 000240 and 000260, respectively) could effectively be considered as no-operation instructions. In fact, the NOP mnemonic assembled into 000240.

Optional instruction setsEdit

Extended Instruction Set (EIS)

The EIS was an option for 11/35/40 and 11/03, and was standard on newer processors.

  • MUL, DIV multiply and divide integer operand to register pair
  • ASH, ASHC arithmetic - shift a register or a register pair. For a positive number it will shift left, and right for a negative one.
Floating Instruction Set (FIS)

The FIS instruction set was an option for the PDP-11/35/40 and 11/03

  • FADD, FSUB, FMUL, FDIV only for single-precision operating on stack addressed by register operand
Floating Point Processor (FPP)

This was the optional floating point processor option for 11/45 and most subsequent models.

  • full floating point operations on single- or double-precision operands, selected by single/double bit in Floating Point Status Register
  • single-precision floating point data format predecessor of IEEE 754 format: sign bit, 8-bit exponent, 23-bit mantissa with hidden bit 24
Commercial Instruction Set (CIS)

The CIS was implemented by optional microcode in the 11/23/24, and by an add-in module in the 11/44 and in one version of the 11/74. It provided string and decimal instructions used by COBOL and Dibol.

Access to Processor Status Word (PSW)

The PSW was mapped to memory address 177 776, but instructions found on all but the earliest PDP-11s gave programs more direct access to the register.

  • SPL (set priority level)
  • MTPS (move to Processor Status)
  • MFPS (move from Processor Status)
Access to other memory spaces

On PDP-11s that provided multiple instruction spaces and data spaces, a set of non-orthogonal Move instructions gave access to other spaces. For example, routines in the operating system that handled run-time service calls would use these instructions to exchange information with the caller.

  • MTPD (move to previous data space)
  • MTPI (move to previous instruction space)
  • MFPD (move from previous data space)
  • MFPI (move from previous instruction space)

Inconsistent instructionsEdit

Over the life of the PDP-11, subtle differences arose in the implementation of instructions and combinations of addressing modes, though no implementation was regarded as correct. The inconsistencies did not affect ordinary use of the PDP-11.

SpeedEdit

PDP-11 processor speed varied by model, memory configuration, op code, and addressing modes. Instruction timing had up to three components, execute/fetch of the instruction itself and access time for the source and the destination. The last two components depended on the addressing mode. For example, on the PDP-11/70 (circa 1975), an instruction of the form ADD x(Rm),y(Rn) had a fetch/execute time of 1.35 microseconds plus source and destination times of 0.6 microseconds each, for a total instruction time of 2.55 microseconds. Any case where addressed memory was not in the cache added 1.02 microseconds. The register-to-register ADD Rm,Rn could execute from the cache in 0.3 microseconds. Floating point was even more complex, since there was some overlap between the CPU and the floating-point processor, but in general, floating point was significantly slower. A single-precision floating add instruction could range from 2.4 to 5.5 microseconds plus time to fetch the operands.[4]

InterruptsEdit

The PDP-11 operated at a priority level from 0 through 7, declared by three bits in the Processor Status Word (PSW), and high-end models could operate in a choice of modes, Kernel (privileged), User (application), and sometimes Supervisor, according to two bits in the PSW.

To request an interrupt, a bus device would assert one of four common bus lines, BR4 through BR7, until the processor responded. Higher numbers indicated greater urgency, perhaps that data might be lost or a desired sector might rotate out of contact with the read/write heads unless the processor responded quickly. The printer's readiness for another character was the lowest priority (BR4), as it would remain ready indefinitely. If the processor were operating at level 5, then BR6 and BR7 would be in order. If the processor were operating at 3 or lower, it would grant any interrupt; if at 7, it would grant none. Bus requests that were not granted were not lost but merely deferred. The device needing service would continue to assert its bus request.

Whenever an interrupt exceeded the processor's priority level, the processor asserted the corresponding bus grant, BG4 through BG7. The bus-grant lines were not common lines but were a daisy chain: The input of each gate was the output of the previous gate in the chain. A gate was on each bus device, and a device physically closer to the processor was earlier in the daisy chain. If the device had made a request, then on sensing its bus-grant input, it could conclude it was in control of the bus, and did not pass the grant signal to the next device on the bus. If the device had not made a request, it propagated its bus-grant input to its bus-grant output, giving the next closest device the chance to reply. (If devices did not occupy adjacent slots to the processor board, "grant continuity cards" inserted into the empty slots propagated the bus-grant line.)

Once in control of the bus, the device dropped its bus request and placed on the bus the memory address of its two-word vector. The processor saved the program counter (PC) and PSW, entered Kernel mode, and loaded new values from the specified vector. For a device at BR6, the new PSW in its vector would typically specify 6 as the new processor priority, so the processor would honor more urgent requests (BR7) during the service routine, but defer requests of the same or lower priority. With the new PC, the processor jumped to the service routine for the interrupting device. That routine operated the device, at least removing the condition that caused the interrupt. The routine ended with the RTI (ReTurn from Interrupt) instruction, which restored PC and PSW as of just before the processor granted the interrupt.

If a bus request were made in error and no device responded to the bus grant, the processor timed out and performed a trap that would suggest bad hardware.

MACRO-11 assembly languageEdit

 
Punched tape used for PDP-11

MACRO-11 is the assembly language for the PDP-11. It is the successor to PAL-11 (Program Assembler Loader), an earlier version of the PDP-11 assembly language without macro facilities. MACRO-11 was supported on all DEC PDP-11 operating systems. PDP-11 Unix systems also include an assembler (called "as"), structurally similar to MACRO-11, but with different syntax and fewer features.

Myth of PDP-11 influence on programming languagesEdit

A folk myth is that the instruction set architecture of the PDP-11 influenced the idiomatic use of the B programming language. The PDP-11's increment and decrement addressing modes correspond to the −−i and i++ constructs in C. If i and j were both register variables, an expression such as *(−−i) = *(j++) could be compiled to a single machine instruction. Dennis Ritchie says this folk myth is historically impossible.[5] However, the C programming language did take advantage of several low-level programming features of the PDP-11, resulting in their inclusion into new processors.[6]

NotesEdit

  1. ^ "PDP-11 Processor Handbook" (PDF). DEC. Retrieved 13 November 2015.
  2. ^ pdp11/05/10/35/40, Chapter 7.
  3. ^ pdp11/04/34a/44/60/70, page 421.
  4. ^ DEC PDP-11/70 Processor Handbook, 1975, Appendix C, Instruction Timing
  5. ^ Dennis M. Ritchie (March 1993). "The Development of the C Language". ACM SIGPLAN Notices. 28 (3): 201–208. doi:10.1145/155360.155580. People often guess that they were created to use the auto-increment and auto-decrement address modes provided by the DEC PDP-11 on which C and Unix first became popular. This is historically impossible, since there was no PDP-11 when B was developed. The PDP-7, however, did have a few `auto-increment' memory cells, with the property that an indirect memory reference through them incremented the cell. This feature probably suggested such operators to Thompson; the generalization to make them both prefix and postfix was his own. Indeed, the auto-increment cells were not used directly in implementation of the operators, and a stronger motivation for the innovation was probably his observation that the translation of ++x was smaller than that of x=x+1.
  6. ^ Bakyo, John. "DEC PDP-11, benchmark for the first 16/32 bit generation. (1970)" in Great Microprocessors of the Past and Present (V 13.4.0), Section Three, Part I. Accessed 2011-03-04

ReferencesEdit

  • pdp11 processor handbook - pdp11/05/10/35/40. Digital Equipment Corporation. 1973.
  • pdp11 processor handbook - pdp11/04/34a/44/60/70. Digital Equipment Corporation. 1979.

Further readingEdit

  • Eckhouse, jr., Richard H.; Morris, L. Robert (1979). Microcomputer Systems Organization, Programming and Applications (PDP-11). Englewood Cliffs, New Jersey: Prentice-Hall. ISBN 0-13-583914-9.
  • Michael Singer, PDP-11. Assembler Language Programming and Machine Organization, John Wiley & Sons, NY: 1980.

External linksEdit