CS225, Fall 2006, LC2 architecture
Unfortunately, the LC2 simulator will not run
on the Windows XP machines (the editor and assembler sort of will, but
the simulator just doesn't). As far as I know it was never
available for Macintosh... It might be amusing to simulate the
simulator and read/guess what it looks like anyhow, but not as much fun
as writing programs that actually run!.
LC2, a Load-Store, general-purpose register
architecture.
Handout 1
Get handout 2, formats of instructions, from me. All instructions
are in appendix A of Patt&Patel.
Direct addressing: LD DR,
Label ST SR, Label Just
like PEP, acts on contents of memory at location Label.
Immediate mode: Only in ADD and AND; actual numbers,
signed binary, 5 bits. (Sign extended to 16 bits in
computation) ADD R2, R3,
#7 R2<-- R3+7.
What do these do? AND R2, R2,
#0 ADD R2, R2, # -1
AND R2, R2, #0
AND R2, R2, #0
ADD R2, R2,
R5
ADD R2, R2, #5
and, the only Immediate memory operation
Load Effective Address LEA DR, Label LEA R4,
FOO: R4 <-- address which FOO represents
Equivalent to LOADB Label, i
Indexed addressing is a little different here: "Base + Offset"
LDR DR, BaseR, index6
STR SR, BaseR, index6
LDR R4, R2, #10: R4<-- mem[R2 +10] STR
R4, R2, #10: mem[R2 +10] <--R4
R2 is the Base and 10 is the
offset.
But this instruction has a fixed offset, so can't
be used like the PEP Indexed,
where LdA Base,x : A<--mem[Base+X] Base stays fixed and
X
changes like the index of an array.
Most commonly used in this form:
LEA R2, ArrayBase
Loop LDR R0, R2,
#0 ; Get element from
memory at address in R2
;output (or whatever ) R0
ADD R2, R2, #1 ; Move pointer
R2 to next element in array
BRxx Loop
; Loop to get another one
(So the offset is usually 0 for traversing an array, and the "base"
register changes.)
When might you use the fixed offset? How about in a stack frame
for locating internal variables, relative to stack pointer.
Example:
; = = = = = = = = = = == = = = = = = = = = = = = = = =
;asctobin.asm
; Gets a digit from the keyboard and changes it to binary.
; Stores it in array. Repeats for 5 digits
.orig x3000
LEA R3,Binary ; Initialize to first
location
LD R6,ASCII ; Template to
strip ascii
LD R1,COUNT ; Initialize to 5
AGAIN
IN
; Get keyboard input
ADD R0,R0,R6 ; Strip ASCII template
STR R0,R3,#0 ; Store binary digit
ADD R3,R3,#1 ; Increment array
pointer
ADD R1,R1,#-1 ; Decrement COUNT.
BRp AGAIN ; More
characters?
halt
ASCII .FILL
xFFD0 ; Negative of x0030.
COUNT .FILL
#5 ;
Binary .BLKW
#5 ; Array space for 5
digits.
.end
= = = = = = = = = = = = = = = = = = = = = = = = = = =
;outputstring.asm
; Outputs a string, stored in C form in array String.
;Follows with Linefeed
.orig x3000
LEA R1,
String ; Initialize to first
location
Loop
LDR R0, R1, #0 ;
Retrieve the character(s)
BRz
Nomore ; If it is
0, done
OUT
; Write the character
ADD R1, R1, #1 ;
Increment pointer
BR
Loop
; Do it all over again
Nomore
LD R0, Linefeed
OUT
Halt
;
String .Stringz "Hello
world"
Linefeed .Fill x0A
.end
= = = = = = = = = = = = = = = = = = = = = = = = = = = =
All Registers are interchangeable EXCEPT
R0 is used for I/0
R7 is used by Traps and Subroutines to store Return
address. Watch after IN or OUT
(R6 is used by other Interrupts to store Return address)
How to protect? Save and restore in a convenient memory
location, call it SaveR7
;asctobinwrong.asm
; Gets a digit from the keyboard and changes it to binary.
; Stores it in array. Repeats for 5 digits
.orig x3000
LEA R3,Binary ; Initialize to first
location
LD R6,ASCII ; Template for
stripping ASCII
LD R7,COUNT ; Initialize to 5
AGAIN
IN
; Get keyboard input
ADD R0,R0,R6 ; Strip ASCII template
STR R0,R3,#0 ; Store binary digit
ADD R3,R3,#1 ; Increment array
pointer
ADD R7,R7,#-1 ; Decrement COUNT.
BRp AGAIN ; More
characters?
halt
ASCII .FILL
xFFD0 ; Negative of x0030.
COUNT .FILL
#5 ;
Binary .BLKW
#5 ; Array space for 5
digits.
.end
- - - - - - - - - -
This doesn't work.
Insert these lines in the 3 appropriate places to make it work.
(Careful!!)
SaveR7 .BLKW #1 ; space to store R7
ST R7, SaveR7 ;
contents of R7 to memory
LD R7, SaveR7 ;
restore contents of R7 from memory
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = =
Procedures: How do they return, how do we pass/protect
things?
JSR label As you're used to. Puts return address
into R7.
RET Return from subroutine. Copies R7 to PC.
How do we: Pass by reference: value in R3.
Just use R3 in the subroutine.
How do we: Pass by value. Leave other registers untouched
by subroutine. Have local variables.
At beginning of subroutine, save all the
registers not passing by reference to local memory; restore before
exiting subroutine. Example next time.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = =
HW:
A) What are the largest negative and the largest positive numbers you
can use in immediate addressing with ADD & AND?
B) a) Run asctobin. b) Change it so that it just stores the 5
characters in memory (Doesn't strip the ASCII off). Hand in
the .asm listing.
C) a) Run outputstring. b) Check the format of the ascii string
in memory, making sure it really is null-terminated. Note that
this is a wasteful way to store a string, taking up a whole 16 bits per
character.
c) Modify the program so it prints out every other character! (
Hl..etc. ) There could be a problem with the end of string, so
add a space filled with 0 at the end. Hand in the .asm
listing, and write what the output is. (I don't see a way
to print the console window.)
D) Write a short program which will take a number and find its 2's
complement negative. Get the number from a memory location, and
store the negative back to another memory location. Run it with 3
numbers, hand in the .asm file and the results for your 3 numbers ( hex
and dec for the number and for the negative. You can get the dec
off the register values as you step the program.)
E) Run asctobinwrong. Note that R7 is the problem; it has
the wrong value and doesn't decrement, because IN overwrites it.
(To halt a running program, use Execute>Stop)
Subroutines:
PC is passed in R7. Pass parameters in other
registers.
Example:
;subsimple.asm
; Main Calls subroutine S. Character is in R1.
; S adds 1 to Character (Parameter passed by reference).
; Main outputs the new Character
.orig x3000
main
LD R1,
String ; Loads "M" into R1
JSR S
AND R0, R0, #0 ;
Move new character to
Add R0, R0, R1 ;
R0
OUT
; Output new Character
Halt
;- - - - - S- - - - - - - - - - -
S
ADD R1, R1, #1 ;
Increment character
RET
;- - - - - - - - - - - - - - -
; Main variable
String .Stringz "M"
.end
= = = = = = = = = ==== = = = = = = = = = = = =
Protection: Specify a memory location, in main
SaveR7, in procedure SaveR0, R1, etc. Use ST and LD to save and
restore these values.
Example: Outputstring as a subroutine.
Address of first entry of string passed in R0. We can pass the address
by value. But we aren't passing the string by value.
= = = = = = = = =
;stringassubrou.asm
; Main Calls subroutine outstring. Pointer to string is in
R1.
; outstring Outputs a string, stored in C form.
; Main follows with Linefeed
.orig x3000
main
LEA R1,
String ; R1 points to string
ST R7, SaveR7
JSR
Stringout
LD R7,
SaveR7 ;Does this work?
LD R0,
Linefeed
OUT
Halt
;
;- - - - - Stringout- - - - - - - - - - -
Stringout ST
R0, SaveR0
; Save registers used by
ST R1,
SaveR1 ; this procedure,
ST R7,
SaveR7 ;INCLUDING .R7
Loop
LDR R0, R1, #0 ;
Retrieve the character(s)
BRz
Nomore ; If it is
0, done
OUT
; Write the character
ADD R1, R1,
#1 ; Increment pointer
BR
Loop
; Do it all over again
Nomore LD
R7, SaveR7
; Restore registers used by
LD R1,
SaveR1
LD R0,
SaveR0 ; this procedure
RET
; Outstring variables
SaveR0 .blkw 1
SaveR1 .blkw 1
SaveR7 .blkw 1
;- - - - - - - - - - - - - - -
; Main variables
String .Stringz "Hi"
Linefeed .Fill x0A
.end
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = =
Passing parameters in registers (vs.Passing parameters
purely on the stack ):
--Simple to program.
--Much faster, especially if you don't have to protect too much.
(Register windowing: "New" chips have many many
registers (say 100). Some are organized into smaller "windows"--each
contains private registers, registers for passing out and passing
in. Hardware has a way of hooking up the passing registers).
Registers: m m m m m m m m s s s s s s s s t t t t t t t t
m m m m m m m
m
Main's window
s s s s s s s
s Subroutine1's window
(what it feels like)
t t t t t t t t Subroutine of Sub1's window (what it feels
like)
--Save/restore in local memory: Can't do
recursion. Usually we save and restore registers to a stack.
If you have too many parameters to pass in registers, rest
go on stack.
Calling conventions:
--Who should preserve registers?
(A compiler wants to have register use clear up front: Optimally
will minimize load-store, maximize register use.)
Scratch registers: expect it to be
trashed. Use locally only. All PEP's registers.
Caller-saved registers
Callee-saved registers
Forbidden registers (like PC, SP)
Agreement between caller and subroutine(s). Sometimes above is a
formal assigment by op. sys. or ISA.
Caller saves:
Caller's responsibility to save all
registers it wants to still be there (maybe all--overkill?)
Callee saves:
Subroutine's responsibility to save all registers that it uses, (that
the caller might want.)
IT MUST GET DONE!
Who decides: Compiler writer, subject to op.sys or ISA
req'ts.
(Appleworks Pascal and
Metrowerks Pascal for old Macs--incompatible codes--different calling
conventions)
Assembly level: Your specs better
make it clear!
How you pass:
On the stack: Caller always pushes
arguments onto stack. Caller or callee pops them when done.
(Which? Pep: caller)
Return value allocated in caller's stack space? Or callee's stack
space?
(PEP: caller; along with arguments)
In register(s): Parameters--Often
first few (3) pass in registers, rest on stack. Function Return
value--a specific register?
Which registers?
Conventional to use first few registers (e.g. R0 for I /O)
Return address--usually on stack. LC2--you'd need to
put it on a stack yourself for potential deeper subs.)
= = = = = = = = = = = = = = = = = = = = = = = = = = = = =
HW: A) Run asctobinwrong (above). Note that
R7 is the problem. Fix it,
with the code given at the bottom.
B) Rewrite subsimple.asm so it gets a character from the keyboard
(instead of memory), passes it to the subroutine, and outputs the next
character.
C) Fix the error in stringassubrou that means R7 is not properly
restored in the main program.
This page belongs to Sally Sievers who is solely
responsible
for its content. Please see our statement
of responsibility.