CLASS 23

Format 1 Instructions

There is only one Format 1 instruction -- the call instruction. The call instruction has a single argument, which is the address of the subroutine. Addresses are 32 bits in the SPARC architecture, and the call instruction needs to be able to specify a subroutine anywhere in the address space. So the remaining 30 bits in the instruction wouldn't be enough space to hold the subroutine address, but for a trick. The trick is that subroutine addresses always start on word boundaries. That is, the address of a subroutine is always divisible by 4. Therefore the last two bits of a subroutine address are always zero and don't need to be stored. So the execution unit takes the 30 bits of address from the instruction, puts two zero bits on the end, and uses the result as the subroutine address.

The Format 1 instruction is also PC-relative.

So stored by shifting right 2 bits. Address after the call is :

npc = (instruction<29:0> << 2) + pc.

But the problem is that programs are frequently moved around in memory, and hence the calling addresses and the called addresses keep changing. The relative address remains fixed, and is used. e.g.

       .global _main

       _main: call _main    ! strange??
              nop

The call instruction will have the following representation:

 0x40000000 
i.e. It will have 01 followed by 30 zero's (as the offset is zero.)

External Data And Text

Static Data

So far the data structure that we've used to organize memory is the stack, which is natural for variables local to a subroutine ("automatic" variables in C) since subroutines need to allocate a bunch of memory when they start, and throw it away when they're done. The LIFO characteristics of the stack are natural for this.

However, stack variables are constrained in two ways: they have limited scope, and limited extent.

Scope and extent. Scope refers to the part of the code in which a variable can be referenced. Extent is the length of time that the variable exists. Scope is an issue that is mainly dealt with at compile-time -- it refers to a program's source code, and in what parts of the source code it is legal to refer to a variable. Extent is an issue that is resolved at run-time -- it refers to the allocation and deallocation of memory as the program runs.

Now, stack variables have both scope and extent limited to an individual subroutine. Stack variables can only be referenced within their subroutine; and stack variables are created and destroyed with their subroutine begins and ends. In order to have other kinds of variables, we need to separate these two characteristics.

Why would we want to modify just scope, or extent, without affecting the other?

Widening scope with limited extent - An example would be languages in which a called subroutine is allowed to use variables declared in the caller. Languages that allow this are some dialects of Lisp, such as Scheme. C doesn't allow this though.

Lengthening extent with limited scope - An example would be, say, a variable that is only accessible within a subroutine, but whose value we wish to preserve across subroutine calls. That is, we want the local variable to have the same value on entry to the subroutine that it had when the subroutine last exited.

The task of widening scope is a job for the compiler and we won't discuss it any more here. However, the task of allowing lengthened extent is a question of memory allocation. We'll discuss the most common form of wider extent that can be provided: to cause the variable to exist for the entire execution of the program. To do this we obviously need a new data structure other than the stack.

The solution is to allocate a portion of memory when the program starts that is used for so-called "static" data. This chunk of memory is called a segment. In fact, the program itself is a chunk of memory that is managed in this way -- it's called the text segment. The memory used for static data is called the data segment.

The reason for using two segments comes from the support that the operating system provides for segments. Later on we'll discuss how the operating system implements segments. For now, we'll note that the OS creates segments when the program starts executing, and it has the ability to make a segment either read-only (R/O) or readable and writeable (R/W). The two segments exist because we typically want our program code to be read/only, while our data must of course be read/write. Making program code (the text segment) R/O is intended to be a help to the programmer, to prevent errors in which program code is accidentally overwritten by an erroneous program. However, it of course means that if a program wants to modify its own code, or generate new code during execution, it must do so in the data segment.

For class 24 notes, click here

For more information, contact me at tvohra@mtu.edu