Let us begin with the calling operations. Our first machine will be the MC68000, one of the classical and widely available CISC processors. It or one of its progeny is found in many machines and forms the heart of the Macintosh(not the Power Mac)and the early Sun workstations. Programmatically, the 68000 family shares a great deal with the very popular VAX family of processors. Both of these CISC designs derive in rather linear fashion from DEC's PDP-11 machines that were so widely used in the 1970s. Comparisons to that style of machine will be done with the SPARC, a RISC processor found in Sun, Solbourne, and other workstations Memory and Registers All computers will have data stored in memory and <H Little endian some space in the CPU for manipulating data Memory can be considered to be a long list of bytes(8-bit data Big endian-D 00 011011 blocks)with addresses(locations in the list)spanning 000xx ome large range of numbers from 0 to typically 4 billion(4 GB). The memory is constructed physically 100xx by grouping chips so that they appear to form enor wn in Fig. 87. Since each column can deliver one byte on each request, the number of adjacent columns determines the number of bytes which may be obtained from a gle request. Machines today have 1, 2, 4, or 8 sucl columns.(Some machines, the 68000 being our cur- FIGURE 87. 1 Memory arranged as 4 columns of bytes. The rent example, have only 2 columns but arrange to have binary addresses are shown in the two formats widely used the CPU ask for two successive transfers to get a total in computers. The illustration shows only 32 bytes in a 4 of 4 bytes. In general, the CPU may manipulate 38 array, but a more realistic span would be 4 3 1,000,000 gle step a datum as wide as the memory. For all of or 4 3 4,000,000(4 MB to 16 MB) the machines which we will consider that maximum datum size is 32 bits or 4 bytes. While convention would have us call this biggest datum a word, historical reason has led both the vAX and MC68000 to call it a longword. Then, 2 bytes is either a halfword or a word. We will use the VAX/68000 notation(longword, word, and byte) wherever possible to simplify the reading. To load data from memory, the CPU sends the address and the datum size to the memory and gets the datum as the reply. To store data, the address is sent and then the datum and datum size. Some machines require that the datum be properly aligned with the stacking order of the memory columns in Fig. 87. 1. Thus, on the SPARC, a longword must have an address ending in 00(xxx00 in Fig. 87. 1), and a word address must end in 0. The programmer who arranges to violate this rule will be greeted with an address error. Since the MC68000 has only two columns, it complains only if you ask for words or longwords with odd addresses. Successor models of that chip(68020, 30, and 40), like the VAX, accept any address and have the CPU read two longwords and do the proper repacking The instruction explicitly specifies the size and indicates how the CPu should calculate the address. An instruction to load a byte, for example, is LB, MOVE. B, or MOVB on the SPARC, MC68000, and VAX, e pectively. These are followed immediately by an expression which specifies an address. We will discuss how pecify an address later. First, we must introduce the concept of a register The space for holding data and working on it in the CPU is the register set. Registers are a very important esource. Bringing data in from memory is quite separate from any operations on that data. Data in memory must first be fetched, then acted upon. Data in registers can be acted on immediately. Thus, the availability of registers to store very active variables and intermediate results makes a processor inherently faster. In some nachines, most or all of the registers are tied to specific uses. The most prevalent example would be Intels 80x86 processors, which power the ubiquitous PC. Such architectures, however, are considered quite old fashioned. All of the machines that we are considering are of a type called general register machines in that they have a large group of registers which may be used for any purpose. The machines that we include have either 16or32 Table 87.1 shows the general register resources in the three machines. The SPARC is a little strange. The machine provides eight global registers and then a window blind of 128 registers which sits behind a frame e 2000 by CRC Press LLC
© 2000 by CRC Press LLC Let us begin with the calling operations. Our first machine will be the MC68000, one of the classical and widely available CISC processors. It or one of its progeny is found in many machines and forms the heart of the Macintosh (not the PowerMac) and the early Sun workstations. Programmatically, the 68000 family shares a great deal with the very popular VAX family of processors. Both of these CISC designs derive in rather linear fashion from DEC’s PDP-11 machines that were so widely used in the 1970s. Comparisons to that style of machine will be done with the SPARC, a RISC processor found in Sun, Solbourne, and other workstations. Memory and Registers All computers will have data stored in memory and some space in the CPU for manipulating data. Memory can be considered to be a long list of bytes (8-bit data blocks) with addresses (locations in the list) spanning some large range of numbers from 0 to typically 4 billion (4 GB). The memory is constructed physically by grouping chips so that they appear to form enormously deep columns of bytes, as shown in Fig. 87.1. Since each column can deliver one byte on each request, the number of adjacent columns determines the number of bytes which may be obtained from a single request. Machines today have 1, 2, 4, or 8 such columns. (Some machines, the 68000 being our current example, have only 2 columns but arrange to have the CPU ask for two successive transfers to get a total of 4 bytes.) In general, the CPU may manipulate in a single step a datum as wide as the memory. For all of the machines which we will consider, that maximum datum size is 32 bits or 4 bytes. While convention would have us call this biggest datum a word, historical reason has led both the VAX and MC68000 to call it a longword. Then, 2 bytes is either a halfword or a word. We will use the VAX/68000 notation (longword, word, and byte) wherever possible to simplify the reading. To load data from memory, the CPU sends the address and the datum size to the memory and gets the datum as the reply. To store data, the address is sent and then the datum and datum size. Some machines require that the datum be properly aligned with the stacking order of the memory columns in Fig. 87.1. Thus, on the SPARC, a longword must have an address ending in 00 (xxx00 in Fig. 87.1), and a word address must end in 0. The programmer who arranges to violate this rule will be greeted with an address error. Since the MC68000 has only two columns, it complains only if you ask for words or longwords with odd addresses. Successor models of that chip (68020, 30, and 40), like the VAX, accept any address and have the CPU read two longwords and do the proper repacking. The instruction explicitly specifies the size and indicates how the CPU should calculate the address. An instruction to load a byte, for example, is LB, MOVE.B, or MOVB on the SPARC, MC68000, and VAX, respectively. These are followed immediately by an expression which specifies an address. We will discuss how to specify an address later. First, we must introduce the concept of a register. The space for holding data and working on it in the CPU is the register set. Registers are a very important resource. Bringing data in from memory is quite separate from any operations on that data. Data in memory must first be fetched, then acted upon. Data in registers can be acted on immediately. Thus, the availability of registers to store very active variables and intermediate results makes a processor inherently faster. In some machines, most or all of the registers are tied to specific uses. The most prevalent example would be Intel’s 80x86 processors, which power the ubiquitous PC. Such architectures, however, are considered quite oldfashioned. All of the machines that we are considering are of a type called general register machines in that they have a large group of registers which may be used for any purpose. The machines that we include have either 16 or 32 registers, with only a few tied to specific machine operations. Table 87.1 shows the general register resources in the three machines. The SPARC is a little strange. The machine provides eight global registers and then a window blind of 128 registers which sits behind a frame FIGURE 87.1 Memory arranged as 4 columns of bytes. The binary addresses are shown in the two formats widely used in computers. The illustration shows only 32 bytes in a 4 3 8 array, but a more realistic span would be 4 3 1,000,000 or 4 3 4,000,000 (4 MB to 16 MB)
TABLE 87.1 General Registers in the Three Machines Reg Special Names Comments AC6800016 ress)register operations are 32 bits wide. Address ge gisters as bases. D(data) registers allow byte, word, and AP, FP,SP and PC hold the addresses of the argument block, the frame, the stack AP, FP, SR, PC and the current place in the program, respectively. All data instructions car use any register. gl. g7, The 4 groups of eight registers comprise: global (g), incoming parameters (i), 10.15, FR, RA, local (l) and outgoing parameters(o). go i 10.l7,00.05, wastebasket as a destination. The registers are arranged as a window bl (see text)with the gs always visible and the others moveable in multiple overlapping frames of 24. ithin the set of general registers. Where a PC is not listed, it exists as a special register and can be used as an address when the program uses program-relative addressing. which exposes 24 of the 128. A program can ask the machine to raise or lower the blind by 16 registers. That leaves an overlap of eight between successive yanks or rewinds. This arrangement is called a multiple overlapping register set(MORS). If you think of starting with register r8 at the bottom and r31 at the top, a yank of 16 on the blind will now have r49 at the top and r24 at the bottom r24 to r31 are shared between the old set and the new. To avoid having to keep track of which registers are showing, the set of 24 are divided into what came in from the last set, those that are only local, and those that will go out to the next set. These names apply to going toward increasing numbers. In going the other direction, the ins of the current set will become the outs of the next set. Almost all other machines keep their registers screwed down to the local masonry, but you will see in a moment how useful a MORS can be ( Like other useful but expensive accessories, the debate is always on whether it is worth it[Patterson and Hennessy, 1989].) Stack. Most subroutines define a number of local variables Number Count in C, for example, defines 10 local variables. While these local variables will often be created and kept in register, there is always some need for a bit of for each invocation of (call to)a subroutine In the" good old days, this local storage was often tied to the block of code comprising the subroutine. However, such a fixed block means that a subroutine could never call itself or be called by something that it called. To avoid that problem(and for other purposes)a memory structure called a stack was invented which got its name because it behaved like the spring-loaded plate stack in a restaurant. Basically, it is a last-in-first-out(LiFO) structure whose top is defined by a pointer (address)which resides in a register commonly called the stack pointer or SP Heap. When a subroutine needs space to store local variables, it acquires that space on the stack. When the subroutine finishes, it returns that stack space for use by other routines. Thus, local variable allocations live and die with their subroutines. It is often necessary to create a data structure which is passed to other routines whose lives are independent of the creating routine. This kind of storage must be independent of the creator To meet this need, the heap was invented. This is an expandable storage area managed by the system. You get an allocation by asking for it [malloc(structure_ size)in C]. You get back a pointer to the allocation and the routine can pass that pointer to any other routine and then go away. When it comes time to dispose of the allocation--that is, return the space for other usesthe program must do that actively by a deallocation call the memory for other uses, all by passing the pointer to the structure from one to another er one can return Free(pointer) in C]. Thus, one function can create a structure, several may use it, and anothe Both heap and stack provide a mechanism to obtain large(or small) amounts of storage dynamically. Thus, large structures which are created only at run time need not have static space stored for them in programs that are stored on disk nor need they occupy great chunks of memory when the program does not need them Dynamic allocation is very useful and all modern HLLs provide for it. Since there are two types of dynamic storage, there must be some way to lay out memory so that unpredictable needs in either stack or heap can be met at all times. The mechanism is simplicity itself. The program is stuffed into low addresses in memory along with any static storage(e.g, globals)which are declared in the program. The entire remaining space is then devoted to dynamic storage. The heap starts right after the program and e 2000 by CRC Press LLC
© 2000 by CRC Press LLC which exposes 24 of the 128. A program can ask the machine to raise or lower the blind by 16 registers. That leaves an overlap of eight between successive yanks or rewinds. This arrangement is called a multiple overlapping register set (MORS). If you think of starting with register r8 at the bottom and r31 at the top, a yank of 16 on the blind will now have r49 at the top and r24 at the bottom. r24 to r31 are shared between the old set and the new. To avoid having to keep track of which registers are showing, the set of 24 are divided into what came in from the last set, those that are only local, and those that will go out to the next set. These names apply to going toward increasing numbers. In going the other direction, the ins of the current set will become the outs of the next set. Almost all other machines keep their registers screwed down to the local masonry, but you will see in a moment how useful a MORS can be. (Like other useful but expensive accessories, the debate is always on whether it is worth it [Patterson and Hennessy, 1989].) Stack. Most subroutines define a number of local variables. NumberCount in C, for example, defines 10 local variables. While these local variables will often be created and kept in register, there is always some need for a bit of memory for each invocation of (call to) a subroutine. In the “good old days,” this local storage was often tied to the block of code comprising the subroutine. However, such a fixed block means that a subroutine could never call itself or be called by something that it called. To avoid that problem (and for other purposes) a memory structure called a stack was invented which got its name because it behaved like the spring-loaded plate stack in a restaurant. Basically, it is a last-in-first-out (LIFO) structure whose top is defined by a pointer (address) which resides in a register commonly called the stack pointer or SP. Heap. When a subroutine needs space to store local variables, it acquires that space on the stack. When the subroutine finishes, it returns that stack space for use by other routines. Thus, local variable allocations live and die with their subroutines. It is often necessary to create a data structure which is passed to other routines whose lives are independent of the creating routine. This kind of storage must be independent of the creator. To meet this need, the heap was invented. This is an expandable storage area managed by the system. You get an allocation by asking for it [malloc (structure_size) in C]. You get back a pointer to the allocation and the routine can pass that pointer to any other routine and then go away. When it comes time to dispose of the allocation—that is, return the space for other uses—the program must do that actively by a deallocation call [free(pointer) in C]. Thus, one function can create a structure, several may use it, and another one can return the memory for other uses, all by passing the pointer to the structure from one to another. Both heap and stack provide a mechanism to obtain large (or small) amounts of storage dynamically. Thus, large structures which are created only at run time need not have static space stored for them in programs that are stored on disk nor need they occupy great chunks of memory when the program does not need them. Dynamic allocation is very useful and all modern HLLs provide for it. Since there are two types of dynamic storage, there must be some way to lay out memory so that unpredictable needs in either stack or heap can be met at all times. The mechanism is simplicity itself. The program is stuffed into low addresses in memory along with any static storage (e.g., globals) which are declared in the program. The entire remaining space is then devoted to dynamic storage. The heap starts right after the program and TABLE 87.1 General Registers in the Three Machines Reg Special Names Comments MC68000 16 1 D0..D7 A0..A7 A(ddress) register operations are 32 bits wide. Address generation uses A registers as bases. D (data) registers allow byte, word, and longword operations. A7 is SP. VAX 16 4 r0..r11 AP, FP, SP, PC AP,FP,SP and PC hold the addresses of the argument block, the frame, the stack and the current place in the program, respectively. All data instructions can use any register. SPARC 32 (136) 4 zero, g1..g7, i0..i5, FP, RA, l0..l7, o0..o5, SP, o7 The 4 groups of eight registers comprise: global (g), incoming parameters (i), local (l) and outgoing parameters (o). g0 is a hardwired 0 as a data source and a wastebasket as a destination. The registers are arranged as a window blind (see text) with the g’s always visible and the others moveable in multiple overlapping frames of 24. The special registers are within the set of general registers. Where a PC is not listed, it exists as a special register and can be used as an address when the program uses program-relative addressing
grows toward higher addresses; the stack goes in at the top of memory and grows down. The system is responsible to see that they never collide(a stack crash). When it all goes together, it looks like Fig. 87. 2 [Aho et al., 1986] There is one last tidbit that an assembly programmer must be aware of in looking at memory. Just as some human alphabets are written left to right and some right to left(not to mention top to bottom), computer manufacturers have chosen to disagree on how to arrange words in memory. The two schemes are called big-endian and little-endian(after which end of a number goes in the program lowest-numbered byte and also after a marvelous episode in Gulliver's Travels) The easiest way to perceive how it is done in the two systems is to think of all numbers as being written in conventional order(left to right), but for big-endian you start counting on the upper left of the page and on little-endian you start counting on the upy,l byte, thIs easy description makes big-endian text read er right(see Fig 87.1). Since each character in a text block is a number of length mal order(left to right)but little-endian text reads from right to left. Figure 87.3 shows the sentence This is a sentence " followed by the two hexadecimal HEX)numbers 01020304 and OAOBOCOD written to consecutive bytes in the two systems. Why must we bring this up? Because anyone working in assembly language must know how the bytes are arranged. Furthermore, two of the systems we are considering are big-endian and one(the VAX) is little-endian. which is the better system? Either one. It is having both of them that is a nuisance Onhs you look at Fig. 87.3, undoubtedly you will prefer big-endian, but that is because it appeals to your prejudices. In truth, either works well. what is FIGURE 87.2 Layout of a important is that you be able to direct your program to go fetch the item of dynamic storage in memory. choice. In both systems, you use the lowest-numbered byte to indicate the item of choice. Thus, for the number 01020304, the address will be 13. For the big-endian system, 13 will point to ne byte containing 04 and for the little-endian system, it will point at the byte containing o1 Figure 87.3 contains a problem for some computers which we alluded to in the discussion of Fig. 87.1.We have arranged the bytes to be four in a row as in Fig. 87. 1. That is the way that the memory is arranged in two of our three machines. (In the 68000, there are only two columns. )A good way to look at the fetch operation is that the memory always delivers a whole row and then the processor must acquire the parts that it wants and then properly arrange them. (This is the effect if not always the method. )Some processors--the VAX being a conspicuous example-are willing to undertake getting a longword by fetching two longwords and then iecing together the parts that it wants. Others(in our case, the 68000 and the SPARC) are not so accommo- dating. Those machines opt for simplicity and speed and require that the program keep its data aligned. To use one of those machines, you(or the compiler or assembler)must rearrange Fig 87.3 by inserting a null byt into Fig. 87. 2. This modification is shown in Fig. 87.4. With this modification, all three machines could fetch the two numbers in one operation without rearrangement. Look closely at the numbers 01020304 and OAOBOCOD in Fig. 87. 4. Notice that for both configurations, the numbers read from left to right and that(visually) they appear to be in the same place. Furthermore, as pointed out in the discussion of Fig. 87.3, the"beginning "or address of each of the numbers is identical. However, the byte that is pointed at by the address is not the same and the internal bytes do not have the same addresses. Getting big-endian and little-endian machines in a conversation is not easy. It proves to be even more muddled than these figures suggest a delightful and cogent discussion of the whole issue is found in Cohen [1981 The principal objective in this whole section has been accomplished if looking at Fig. 87. 4 and given the command to load a byte from location 0000 0019, you get the number OB in the big-endian machine and oC in the little-endian machine If you are not already familiar with storing structures in memory, look at the string(sentence)and ask how those letters get in memory. To begin with, every typeable symbol and all of the unprintable actions such as tabbing and carriage returns have been assigned a numerical value from the aSciI code. Each assignment is a byte-long number. What"This"really looks like(HEX, left to right) is 54 68 69 73. The spaces are HEX 20 the period 2E. With the alignment null byte at the end, this list of characters forms a proper C string. It is a structure of 20 bytes. A structure of any number of bytes can be stored, but from the assembly point of view, e 2000 by CRC Press LLC
© 2000 by CRC Press LLC grows toward higher addresses; the stack goes in at the top of memory and grows down. The system is responsible to see that they never collide (a stack crash). When it all goes together, it looks like Fig. 87.2 [Aho et al., 1986]. There is one last tidbit that an assembly programmer must be aware of in looking at memory. Just as some human alphabets are written left to right and some right to left (not to mention top to bottom), computer manufacturers have chosen to disagree on how to arrange words in memory. The two schemes are called big-endian and little-endian (after which end of a number goes in the lowest-numbered byte and also after a marvelous episode in Gulliver’s Travels). The easiest way to perceive how it is done in the two systems is to think of all numbers as being written in conventional order (left to right), but for big-endian you start counting on the upper left of the page and on little-endian you start counting on the upper right (see Fig. 87.1). Since each character in a text block is a number of length 1 byte, this easy description makes big-endian text read in normal order (left to right) but little-endian text reads from right to left. Figure 87.3 shows the sentence “This is a sentence” followed by the two hexadecimal (HEX) numbers 01020304 and 0A0B0C0D written to consecutive bytes in the two systems. Why must we bring this up? Because anyone working in assembly language must know how the bytes are arranged. Furthermore, two of the systems we are considering are big-endian and one (the VAX) is little-endian. Which is the better system? Either one. It is having both of them that is a nuisance. As you look at Fig. 87.3, undoubtedly you will prefer big-endian, but that is only because it appeals to your prejudices. In truth, either works well. What is important is that you be able to direct your program to go fetch the item of choice. In both systems, you use the lowest-numbered byte to indicate the item of choice. Thus, for the number 01020304, the address will be 13. For the big-endian system, 13 will point to the byte containing 04 and for the little-endian system, it will point at the byte containing 01. Figure 87.3 contains a problem for some computers which we alluded to in the discussion of Fig. 87.1. We have arranged the bytes to be four in a row as in Fig. 87.1. That is the way that the memory is arranged in two of our three machines. (In the 68000, there are only two columns.) A good way to look at the fetch operation is that the memory always delivers a whole row and then the processor must acquire the parts that it wants and then properly arrange them. (This is the effect if not always the method.) Some processors—the VAX being a conspicuous example—are willing to undertake getting a longword by fetching two longwords and then piecing together the parts that it wants. Others (in our case, the 68000 and the SPARC) are not so accommodating. Those machines opt for simplicity and speed and require that the program keep its data aligned. To use one of those machines, you (or the compiler or assembler) must rearrange Fig. 87.3 by inserting a null byte into Fig. 87.2. This modification is shown in Fig. 87.4. With this modification, all three machines could fetch the two numbers in one operation without rearrangement. Look closely at the numbers 01020304 and 0A0B0C0D in Fig. 87.4. Notice that for both configurations, the numbers read from left to right and that (visually) they appear to be in the same place. Furthermore, as pointed out in the discussion of Fig. 87.3, the “beginning” or address of each of the numbers is identical. However, the byte that is pointed at by the address is not the same and the internal bytes do not have the same addresses. Getting big-endian and little-endian machines in a conversation is not easy. It proves to be even more muddled than these figures suggest. A delightful and cogent discussion of the whole issue is found in Cohen [1981]. The principal objective in this whole section has been accomplished if looking at Fig. 87.4 and given the command to load a byte from location 0000 0019, you get the number 0B in the big-endian machine and 0C in the little-endian machine. If you are not already familiar with storing structures in memory, look at the string (sentence) and ask how those letters get in memory. To begin with, every typeable symbol and all of the unprintable actions such as tabbing and carriage returns have been assigned a numerical value from the ASCII code. Each assignment is a byte-long number. What “This” really looks like (HEX, left to right) is 54 68 69 73. The spaces are HEX 20; the period 2E. With the alignment null byte at the end, this list of characters forms a proper C string. It is a structure of 20 bytes. A structure of any number of bytes can be stored, but from the assembly point of view, FIGURE 87.2 Layout of a program, static storage, and dynamic storage in memory
T 18 Little Endian (SPARC, MC68000) FIGURE 87.3 Byte numbering and number placement for big- and little-endian systems. Hexadecimal numbers are used memory addresses 0 01020304 18 1B Big Endian Little Endian (SPARC, MC68000) (VAX) FIGURE 87.4 The same items as in Fig. 87.3, but with justification of the long integers to begin on a longword bound it is all just a list of bytes. You may access them two at a time, four at a time, or one at a time. Any interpretation of those bytes is entirely up to the program. Unlike the HLL which requires that you tell it what each named variable is, assembly language knows only bytes and groups of bytes. In assembly language, the"T"can be thought of as a letter or the number 54(HEX). Your choice. Or, more importantly, your programs choice Addressing Now that we have both memory and addresses, we should next consider how these processors require that programmers specify the data that is to be acted upon by the instructions All of these machines have multiple modes of address. The VAX has the biggest vocabulary; the SPARC the smallest. Yet all can accomplish the same tasks. Four general types of address specification are quite common mong assembly languages. These are shown in Table 87. 2. They are spelled out in words in the table, but their usage is really developed in the examples which follow in this and the succeeding sections. In Table 87. 2, formats 1.4 and 1.5 and the entries in 4 require some expansion. The others will be clear in ne examples we will present. Base-index addressing is the mechanism for dealing with subscripts. The base ints at the starting point of a data structure, such as a string or a vector; the index measures the offset from the start of the structure to the element in question. For most machines, the index is simply a separate regist which counts the bytes from the base to the item in question. If the items in the list are 4 bytes long, then to increment the index, you add 4. While that is not hard to remember, the vax does its multiplication by the item length for you. Furthermore, it allows you to index any form of address that you can write. To show you what that means, consider expanding numbers stored in words into numbers stored in longwords. The extension is to preserve sign. The VAX provides specific instructions for conversions. If we were moving these words in one array to longwords in another array, we would write: e 2000 by CRC Press LLC
© 2000 by CRC Press LLC it is all just a list of bytes. You may access them two at a time, four at a time, or one at a time. Any interpretation of those bytes is entirely up to the program. Unlike the HLL which requires that you tell it what each named variable is, assembly language knows only bytes and groups of bytes. In assembly language, the “T” can be thought of as a letter or the number 54 (HEX). Your choice. Or, more importantly, your program’s choice. Addressing Now that we have both memory and addresses, we should next consider how these processors require that programmers specify the data that is to be acted upon by the instructions. All of these machines have multiple modes of address. The VAX has the biggest vocabulary; the SPARC the smallest. Yet all can accomplish the same tasks. Four general types of address specification are quite common among assembly languages. These are shown in Table 87.2. They are spelled out in words in the table, but their usage is really developed in the examples which follow in this and the succeeding sections. In Table 87.2, formats 1.4 and 1.5 and the entries in 4 require some expansion. The others will be clear in the examples we will present. Base-index addressing is the mechanism for dealing with subscripts. The base points at the starting point of a data structure, such as a string or a vector; the index measures the offset from the start of the structure to the element in question. For most machines, the index is simply a separate register which counts the bytes from the base to the item in question. If the items in the list are 4 bytes long, then to increment the index, you add 4. While that is not hard to remember, the VAX does its multiplication by the item length for you. Furthermore, it allows you to index any form of address that you can write. To show you what that means, consider expanding numbers stored in words into numbers stored in longwords. The extension is to preserve sign. The VAX provides specific instructions for conversions. If we were moving these words in one array to longwords in another array, we would write: FIGURE 87.3 Byte numbering and number placement for big- and little-endian systems. Hexadecimal numbers are used for the memory addresses. FIGURE 87.4 The same items as in Fig. 87.3, but with justification of the long integers to begin on a longword boundary
TABLE 87.2 Addressing Modes 1. Explicit addresses Example 1. 1. Absolute addressing 765 The actual address written into the instruction 1. 2. Register indirect 3) Meaning"the address is in register 3. 1.3. Base-displacement -12(r3) Meaning"12 bytes before the address in register 3. 14. Baseindex (r3, r4) Meaning make an address by adding the contents of r3 and r4. This mode has many riations which are discussed below 1.5. Double indirect @5(r4) Very uncommon! Means calculate an address as in 1.3, then fetch the longword there, and then use it as the address of what you really want. 2. Direct data specification 2.1. Immediate/literal 6 or 6 Meaning"use 6 as the datum. "In machines which use #6, 6 without# means address 6. This is called"absolute addressing. 3. Program-relative 3.1. Labels loop: The label (typically an alphanumeric ending in a colon)is a marker in the program which the assembler and linker keep track of. The common uses are to jump to a labeled spot or to load labeled constants stored with the program. 4. Address-modifying form 4. 1. Postincrement (sp) Same as 1. 2 except that, after the address is used, it is incremented by the size of the datum in bytes and returned to the register from which it came. 4.2. Predecrement -(sp) The value in SP is decremented by the size of the datum in bytes, used as the address and returned to the register from which it came CVTWL (r4)[r5], (r6)r5] i convert the words starting at(r4)to longwords starting at(r6) Note that the same index, [r5], is used for both arrays. On the left, the contents of r5 are multiplied by 2 and added to r4 to get the address; on the right, the address is r5*4+r6. You would be saying: Convert the 4th word to the 4th longword. This is undoubtedly compact and sometimes convenient. It is also unique to the VAX. For the 68000, the designers folded both base-displacement and base- index into one mode and made room for word or longword indices. It looks like dress =(A3+64)+sign-extended(D2) The 68000 limits the displacement to a signed byte, but other than that, it is indeed a rather general indexing format. If you do not want the displacement, set it to O For the powerful but simple SPARC, the simple base-index form shown in 1. 4 is all that you have (or need The double- indirect format, 1.5, is so rarely used that it has been left out of almost all designs but the VAX. What makes it occasionally useful is that subroutines get pointers to"pass by pointer"variables. Thus, if you want to get the variable, first you must load the address and then the variable. The vaX allows you to do this one instruction. While that sounds compact, it is expensive in memory cycles. If you want to use that pointer again, it pays to have it in register. The two items under heading 4 are strange at first. Their principal function is adding items to and removing them from a dynamic stack, or for C, to execute the operation *X++ or*(X). The action may be viewed with the code below and the illustration of memory in Fig. 87.2 movl r4,-(sp) make room on the stack(subtract 4 from SP)and put movl(sp)+, r4 stake a longword off the stack, shorten the stack by 4 bytes, and put the longword in r4 RISCs abhor instructions which do two unrelated things. Instead of using a dynamic stack, they use a quasi static stack. If a subroutine needs 12 bytes of stack space, it explicitly subtracts 12 from SP. Then it works from there with the base-displacement format(1.3)to reference any place in the block of bytes just defined. If you want to use a pointer and then increment the pointer, RISCs will do that as two independent instructions. Let us consider one short section of MC68000 code from our sample program in C to see how these modes work and to sample some of the flavor of the language e 2000 by CRC Press LLC
© 2000 by CRC Press LLC CVTWL (r4)[r5],(r6)[r5] ;convert the words starting at (r4) to longwords starting at (r6) Note that the same index, [r5], is used for both arrays. On the left, the contents of r5 are multiplied by 2 and added to r4 to get the address; on the right, the address is r5*4+r6. You would be saying: “Convert the 4th word to the 4th longword.” This is undoubtedly compact and sometimes convenient. It is also unique to the VAX. For the 68000, the designers folded both base-displacement and base-index into one mode and made room for word or longword indices. It looks like: add.1 64(A3,D2.w),D3 ;address = (A3+64) +sign-extended(D2) The 68000 limits the displacement to a signed byte, but other than that, it is indeed a rather general indexing format. If you do not want the displacement, set it to 0. For the powerful but simple SPARC, the simple base-index form shown in 1.4 is all that you have (or need). The double-indirect format, 1.5, is so rarely used that it has been left out of almost all designs but the VAX. What makes it occasionally useful is that subroutines get pointers to “pass by pointer” variables. Thus, if you want to get the variable, first you must load the address and then the variable. The VAX allows you to do this in one instruction. While that sounds compact, it is expensive in memory cycles. If you want to use that pointer again, it pays to have it in register. The two items under heading 4 are strange at first. Their principal function is adding items to and removing them from a dynamic stack, or for C, to execute the operation *X++ or *(– –X). The action may be viewed with the code below and the illustration of memory in Fig. 87.2: movl r4, –(sp) ;make room on the stack (subtract 4 from SP) and put the contents of r4 in that spot movl (sp)+, r4 ;take a longword off the stack, shorten the stack by 4 bytes, and put the longword in r4 RISCs abhor instructions which do two unrelated things. Instead of using a dynamic stack, they use a quasistatic stack. If a subroutine needs 12 bytes of stack space, it explicitly subtracts 12 from SP. Then it works from there with the base-displacement format (1.3) to reference any place in the block of bytes just defined. If you want to use a pointer and then increment the pointer, RISCs will do that as two independent instructions. Let us consider one short section of MC68000 code from our sample program in C to see how these modes work and to sample some of the flavor of the language: TABLE 87.2 Addressing Modes 1. Explicit addresses Example 1.1. Absolute addressing 765 The actual address written into the instruction. 1.2. Register indirect (r3) Meaning “the address is in register 3.” 1.3. Base-displacement –12(r3) Meaning “12 bytes before the address in register 3.” 1.4. Base-index (r3,r4) Meaning make an address by adding the contents of r3 and r4. This mode has many variations which are discussed below. 1.5. Double indirect @5(r4) Very uncommon! Means calculate an address as in 1.3, then fetch the longword there, and then use it as the address of what you really want. 2. Direct data specification 2.1. Immediate/literal #6 or 6 Meaning “use 6 as the datum.” In machines which use #6, 6 without # means address 6. This is called “absolute addressing.” 3. Program-relative 3.1. Labels loop: The label (typically an alphanumeric ending in a colon) is a marker in the program which the assembler and linker keep track of. The common uses are to jump to a labeled spot or to load labeled constants stored with the program. 4. Address-modifying forms (CISC only) 4.1. Postincrement (sp)+ Same as 1.2 except that, after the address is used, it is incremented by the size of the datum in bytes and returned to the register from which it came. 4.2. Predecrement –(sp) The value in SP is decremented by the size of the datum in bytes, used as the address and returned to the register from which it came