# CSE 30 -- Lecture 3 -- Oct 6

In this lecture, I talked about two's complement representation of negative numbers, and the one-instruction computer.

## Two's complement arithmetic

Important points:
• Bits are bits, and we interpret them differently to ``get'' different numbers,
• two's complement representation is one way to interpret bits such that unsigned addition and subtraction just ``works'' for negative numbers as well -- this means that no additional hardware is needed to process negative numbers.
The computers that are used today have either 32 bit words or 64 bit words. The MIPS instruction set that we will use later will be 32-bits. In our examples, we will mostly use 16-bit words.

For a 32-bit machine, the smallest unsigned integer that can be represented is 0, and the largest unsigned integer that can be represented is 232-1. Additions that result in a ``too large'' number results in an overflow: adding 1 to 232-1 gives 0 -- the ``carry'' off the end of the word just disappears. For some machines / languages, arithmetic overflow causes an ``exception'', which if not handled will cause the program to abort. In C overflows are always ignored.

In 2's complement representation, negative numbers are bit patterns that have a leading 1 bit; this is called the ``sign bit''. The value of the bit pattern is determined by figuring out the corresponding positive number to which it can be added to result in a zero result due to overflow. The way we add is the same in unsigned arithmetic and in two's complement arithmetic: this is intentional, since we wish to use the same circuits on the chip to do addition for both number representations.

Using 16-bit registers, -3 is the binary number 1111 1111 1111 11012 or FFFD16, since

1111 1111 1111 1101
+ 0000 0000 0000 0011
---------------------
1 0000 0000 0000 0000
is zero (with an overflow, which is intentionally ignored). Because addition and subtraction of 2's complement representation of numbers (signed integers) are done the same way as unsigned integers, the same ALU circuits -- and machine language instruction -- may be used. On some machines, there will be separate signed and unsigned arithmetic instructions; the only difference is whether overflows will cause exceptions, or what are considered to be overflow conditions.

To figure out the two's complement representation of a negative number, first write down the binary representation of the absolute value, complement all the bits (flip zero for ones and vice versa), then add one to the result. This is the two's complement representation of the number. For example, to find -6, we first write

0000 0000 0000 0110
then complement to get
1111 1111 1111 1001
and add 1 to get
1111 1111 1111 1010

We can verify that this is -6 by adding 6 to it:

1111 1111 1111 1010
+ 0000 0000 0000 0110
---------------------
1 0000 0000 0000 0000

The complement-all-bits-then-add-one procedure is actually what you do to negate a number in general. Try negating -6 above and verifying that you get 6.

In both the unsigned integer interpretation and two's complement interpretation of bit patterns, the number of different numbers that can be represented (in a 32-bit machine) is the same: 232. Above, we said that unsigned integers can take on the values [0,232-1] (0 through 232-1 inclusive). What are the values for two's complement notation? Are there more positive numbers than negative numbers in the set of numbers that can be represented in two's complement?

Consider the number (again using 16-bit registers now):

1000 0000 0000 0000
It is negative, since the ``sign bit'' is set. What happens when you negate it using the complement-all-bits-then-add-one procedure? Do you get a positive number?

Consider the bit pattern

0111 1111 1111 1111
as a two's complement representation of a number. This is the largest positive number that can be represented. What happens when you add 1 to it?

## One-Instruction Computer

The single instruction in the one-instruction computer is the subz instruction. The instruction
subz a,b,c
has the same ``meaning'' as this C fragment:
mem[a] = mem[a] - mem[b];
if (mem[a] == 0) PC = c;
else PC = PC + 1;
where PC is the program counter, which is a register that contains the address of the current instruction.

In class, I went over the instruction sequence for adding two numbers, and the instruction sequence to implement a loop. You should look at the files ~/../public/add.oic and ~/../public/mult.oic to see how this is done. These files are commented the way I would expect your homework to be commented.

There is a one-instruction computer simulator. To try it out, run it on the input files:

% oic -v ~/../public/add.oic
which gives verbose, instruction-by-instruction output as the program runs, or
% oic -s 6 -c 3 ~/../public/add.oic
to run the program and printout 3 memory words starting at location 6. Similarly, if you run the multiplication program via the simulator as
% oic -s 0x100 -c 3 ~/../public/mult.oic ~/../public/mult.inp.oic
you'll just see the inputs and the result at addresses 0x100 through 0x102. The of the ``machine language'' input files are as follows: anything after a semicolon is ignored; the first non-comment line should contain the starting address into which the file is loaded into memory; all other non-comment lines should contain three numbers, each of which is a 16-bit number, separated by spaces, specifying the contents of a memory word.

If you had a macro assembler, you might define an add macro thus:

subz t,t,next
subz t,a,next
subz t,b,next
subz c,c,next
subz c,t,next
endm
After this definition, occurrences of the line
would be replaced with the body of the macro definition, with appropriate textual substitutions for the arguments a,b,c,t. For example, if you had
subz x,t,next	; x = x - t.
add x,y,z,temp	; z = x + y, using temp as scratch
subz q,z,next	; q = q - z
the macro would be expanded, and the code would be treated as if the input was
subz x,t,next	; x = x - t
subz temp,temp,next
subz temp,x,next
subz temp,y,next
subz z,z,next
subz z,temp,next
subz q,z,next	; q = q -z

We are not using a macro assembler in this class. For the one-instruction computer simulator, there is no assembler at all! You must ``hand assemble'' your code into the simulator's input .

The loop example that I gave in class was

subz i,i,next			; i = 0;
subz negmax,negmax,next		; do {
subz negmax,max,next
loop:	... 				;    loop body
...
subz i,neg1,next		;    i = i + 1;
subz t,t,next			; } while (i != max);
subz t,i,next
subz t,negmax,done
subz t,t,loop
done:	...				; code that follows loop
The loop in the mult.oic example is different than that given in class. Why?
[ CSE home | CSE talks | bsy's home page | webster i/f | yahoo | lycos | altavista | pgp key svr | spam | commerce ]

bsy@cse.ucsd.edu, last updated Sun Oct 26 23:14:21 PST 1997.

email bsy