======================================
   Lec-LC3-project-2.html
======================================
   Linking LC3 C code and assembly code
======================================

This assignment has to do with writing C code that can call
code written in assembly language, and writing that assembly code
so that it can be called by C code. We will use lcc to both compile
our C code and to link our assembly code with our C code. The
result will be a .asm file that lc3as assembles into an LC3 
load object, a .obj file. We will implement our OS in C 
and assembly this way.

What to turn in:

1. A cover sheet w/ the usual info (name, course, date). Also
include notes about what you worked on, and where the files are in
your branch. Attached to the coversheet or on it, include your 
answers to any questions.

======================================

------------------------
-- Get source code
------------------------

In src/ you will find a directory, src/C-linking/. It contains
some program skeletons you can use to get started on your OS:

   os.c              (base C code for the OS)
   asm-utils.asm     (assembly utilities)
   asm-utils.h       (C prototypes for utilities)
   Makefile          (commands for assembling, compiling, and linking)

Copy that directory to your src2/, and add it to your branch.

Note that C function prototypes are needed for any externally
defined routines called by C code. These are included in 
asm-utils.h for functions in asm-utils.asm.

NB--Make sure you have an up-to-date src/. Just to be sure,
do,
    cd src/
    svn info

and check that your src/ is checked out from projects/LC3trunk/src/.
Then do,

   svn up

in src/ to make sure it is up to date. If this is a problem, just
use a browser and go to projects/LC3trunk/src/ and get the source
code mentioned above.

------------------------------------------------
-- Build os.obj, load it to PennSim, 
-- and trace its execution.
------------------------------------------------

Look at os.c. It is a skeleton of a potential OS. Do this to build it,

  make os.obj

Now, start PennSim.jar, and load os.obj. Use "step" to execute the code
one instruction at a time.

Q. Because lcc sets ".Orig x3000" by default, how is that PennSim.jar
loaded os.obj to x0200? Hint, see the Makefile, and look at a.asm
and os.asm. Those are the outputs from 1) lcc and 2) the processing done
by Makefile.

In PennSim.jar, step through the program up to the first JSSR.

Q. What is the stack pointer, SP aka R6, initially set to by the PREAMBLE?
What is the base pointer, BP aka R5, set to? What is the Global Data
Pointer, GDP aka R4, set to?

Now, step through the first JSSR.

Q. What function did it jump to? Where is the source code for that function?
At what address does this function begin?

The next 6 instructions are lcc's C protocol for entering a function
and setting up its call frame. R7 is pushed, and BP/R5 is pushed.
Next, space is allocated for local variables on the stack.
The BP is set to the first local variable and SP/R6 is set to the 
last local variable (which might be the same location if there are none
or only one local variable, one word is always allocated).

Q. Draw a picture of the stack. Show the current words pointed to
by SP and BP. What addresses to they contain? How many local variables 
were allocated?

Immediately after that, a value is fetched from the Global Data table 
(GD) addressed via R4 (the Global Data Pointer, GDP).
There are two instructions associated with that access of the GD. The
first just gets something into R0. 

Q. What is it? Look at the content of R0 and explain what that value is.
Is it a memory address? 

Q. What is the label associated with that address? You can figure this
out by looking at the address in R4, and the offset added to it. Find
that address, and look at what label is found there. NOTE: in a real
machine, no symbolic information is availabe, only machine code. PennSim
uses a.sym to figure out the labels associated with addresses.

The next instruction actually does the data fetch, using R0's content
as an address and storing what is fetched into R0.

Q. What label is associated with the content of R0 after the data fetch?
Look at the memory location now in R0 and find what label is associated 
with that address. What instruction is at that address?

The next instruction is JSSR R0. This is a C call.

Q. Where in the source code is this call (which file, which line)?
Where is the source code for the function jumped to? Is that a C
routine or an ASM routine?

Continue stepping through the program until you come to the next JSSR.
Look at the content of R0 just before the jump is executed. 

Q. What function is being jumped to? Where in the source code is the 
jump? Is this a C call? In what file is the source code for the function
being jumped to?

You will see some unfamiliar syntax in that source code. These are lcc
linking directives, similar to assembler directives such as ".END" and
the like. They declare labels that will be associated with GD. Look
in the assembler's output, os.asm, and find the GD (it is at the bottom).

Q. What label is associated with the GD entry for this function?

Q. What content is in that location in the GD? Explain what effect 
execution of this code would have at this point,

    ldr r3, r4, 5
    ldr r0, r3, 0
    jssr r0

That is, what gets loaded into R3? What gets loaded into R0? And what
function is jumped to?

Continuing stepping through the function you are in until you see R0 loaded
with data from the stack. This is an argument. (R1 is also loaded with
an argument later.) 

Q. What is loaded into R0? What is at that address? 

If you look at the comments in asm-utils.asm for this function, you
will see a C prototype declaration. The first argument is a pointer
to a function whose type is "void f( void )". The function pointer,
in an argument list defined in the definition of a C routine,
would look like this,

int foo (   void (*f_ptr)( void )  ) { ... }

and from that we would assume the formal argument, f_ptr, is a pointer
variable that when deferenced provides the address of a function. We 
would invoke or jump to that function using this syntax in the body of
foo:

    (*f_ptr)();

which says, find the memory location associated with the variable f_ptr, 
get its content, and use that as a jump address.

Step through the next instruction in which R0 gets loaded again
using R0's content as an address. 

Q. What is that value fetched into R0? What does that value refer to?

If you look at the C source that is made the call to the function we
are currently stepping through, you will see the current function's 
argument list. 

Q. What is being passed in to this function as its first argument?

By C convention, the name of a function refers to a pointer variable
that contains the address of the function. Look as os.asm, find the
GD.

Q. What is the name of the pointer variable that was passed as an
argument? It contains the address of a function. Looking in os.asm,
and the DG, what function's address is in that pointer variable?

Q. Looking at PennSim, what is the address of the pointer variable?

Stepping execution a bit more, the content of R0 is written to memory.

Q. What memory location is written into? What value is written to that
location? What have we just accomplished?

Continuing stepping through two RETs to get out of the two nested
function calls we have made. Execution is back in main. Look at os.c
to see what function will be called next. Step execution in PennSim
until you enter this function via JSSR.

Q. What is the address of the function you have just entered?

The function you have entered has its source code in asm-utils.asm.
It is a wrapper for the putc trap routine. Trap routines are entered
via a TRAP instruction. How can you make a TRAP in C code? You can't.
So, this do_putc allows us to call it from C code, and it does the
TRAP in assembly language. This is the simplest routine in asm-utils.asm.
The C code pushes one argument, which by convention is pointed to
by SP. We just put the argument in R0 and TRAP x21 to putc.

Note that registers are saved on the stack, but this do_putc does not
set up its call frame. Any C function it might call would assume the 
SP was set before the call, so the callee can push and pop as it desires.
That is not the case here. Our do_putc is counting on putc to not
mess up the stack so that its stored register values will still be there
after putc returns. In fact, we wrote putc with that in mind, so it
does not use the stack at all. To be safe, we could have simply set
SP above where we stored our register values, and moved it back
after putc returned.

-----------------------------
-- Project development
-----------------------------

Typically, do_putc and any C routines that call it would be part of
a system library that users would link into their programs. The user
would call the C routines as system utilities, which would make
the actual system calls via things like do_putc. Printf is a good
example. The C conventions we have to abide by are listed in 
asm-utils.asm.

Actually, lcc's version of printf is written in assembly and calls 
PUTS to display a string. lcc's library includes (see bin/lcc-1.3/lc3lib),
printf.asm, stdio.asm, getchar.asm, putchar.asm, and scanf.asm.
These use the following traps: GETC (trap x20), OUT (trap x21), and
PUTS (trap x22). (Note, we call OUT's code, putc.) These are needed
for C code compiled by lcc for the LC3.

You now have template code for building other OS routines.
Start with PUTS. This is a TRAP routine: it is entered by
TRAP x22; it is not jumped to from C code. It writes a string to the
display. Its argument is in R0, the same as putc's, but R0 contains 
the address of a memory location, which contains an ASCII character 
code in its low byte and zero in its high byte, the same data that 
putc expects. The subsequent memory locations also contain ASCII, 
and PUTS writes these to the display until it finds a word 
containing ASCII NUL in the low byte, i.e., x0000. It calls,
i.e., via TRAP x21, PUTS/putc to display the characters.

We can initialize its VT slot the same as we did putc's. It's trap
number is x22. Since we can't use the word "puts" or "PUTS" in our
assembly language, let's name our TRAP x22 routine, "puts_trap".

We could have a companion routine,  do_puts, that C code can use, just
as we did for putc. However, since the lc3lib already implements
printf() and scanf(), we don't really need to.

The C convention for strings is the same as TRAP x22 expects. 
So, this, 
    char message[] = "Hello World!\n"

generates a succession of memory locations with a NUL at the end,
each location holding a single ASCII character. Printf would pass
the first address to PUTS in R0, then TRAP x22.

Using the existing asm-utils.asm as a template, write puts_trap.
Also, as was done w/ putc in os.c, call setVTentry( puts_trap, 0x0022) 
to initialize. C code the executes after that call can then use
printf().

You already have puts.asm as a starting point. It needs just a little
fixing up to work. You can drop its code into asm-utils.asm,  and
add the ".global" stuff around it. Don't use our lc3pre macro extensions
though: lcc won't give them a chance to be pre-processed.
Also, don't use the stack: you can't be certain how it's being
used when the trap occurs. Usually, you can use the stack, but
it's less of a headache not to.