----------------------------- -- Lec-1-HW-3-OSbase.html ----------------------------- What to turn in: Check in your source code to your branch. Bring a written summary of your progress and difficulties to class on the due date, with the usual information (Name, Course Title, HW Title, date). Included in this document (see below) are source code text for two assembly language programs: os.asm -- The starting base for you OS. usr.asm -- A user program the OS jumps to, and provides services for. Cut and paste these into files in your /src2, and svn add them to your branch. The task is to get the PUTC trap routine working, and have the user program use it to display a character. In the interests of simplicity, I have changed the base code to be all in one file, and the macros are reduced to just a couple. The macros are included in the source .asm code to simplify processing. You can, of course, rearrange these as you like, and define new macros following the pattern of the macros in os.asm. Be warned that editing the macros can be very mysterious. I had a bug which could not be seen in the text. The only way I got it working was to copy/paste from another macro definition, and carefully change one character at at time, testing each time to see if it still worked. We will be using PennSim.jar for both assembly and simulation. The command line in PennSim is the narrow window just below the "Next" button. The two commands we will use are "as", assemble, and "ld", load. We will pre-process our source code w/ m4. So, we will do the following after editing our source code: cat os.asm | m4 > oss.asm cat usr.asm | m4 > usrr.asm which expands all the macros in os.asm. You might want to put a few lines in your Makefile for this: all: make oss.asm make usrr.asm oss.asm: os.asm cat os.asm | m4 > oss.asm usrr.asm: usr.asm cat usr.asm | m4 > usrr.asm Then, do "make all" to do the pre-processing. Next, we will assemble and load using PennSim's command line. Start PennSim in the directory where you have os.asm and usr.asm. You will have to copy PennSim.jar to that directory and double click it (or java -jar). Using PennSim's command line window (just below the "Next" button) do, as oss.asm ld oss.obj as usrr.asm ld usrr.obj Setting PennSim's PC = x0200, we execute our program using "Step". The OS starts booting. When that is done, the OS jumps to the user program. When the user program is finished, it returns to the OS via TRAP x25 (HALT). The HALT routine simply reboots the OS. If you want the program to run without Step'ing through it, place a breakpoint at the start of HALT, for instance, and use "Continue." You may use any LC3 instructions you care to. There is no restriction on using LD, LDI, ST, STI, JSR, JSRR, or TRAP. However, it is probably a good idea to comform to the convention of using the DATA table to call subroutines and store all data constants and variables. Refering to the DATA table's offsets, the macros for these have been placed at the top of the source code files and the DATA segment has been placed as it normally would be, at the bottom. Add to the offset macros as you add new items to the data segments. The macros for the user program and the OS will be different as the two data segments are in different memory locations and contain different information. The stack segments are also not the same. Therefore, the user must, as a first step, reset the stack and data pointers to its own areas. WHAT PUTC DOES PUTC (i.e., TRAP x21, aka "OUT") receives as its argument an ASCII character code in the low byte of R0 (the upper byte is ignored). PUTC then polls the display's status register, DSR (at address xFE04) to see if its ready bit (DSR[15]) is 1. If it is, the display is ready to receive a character to display, and the character is written to the data register, DDR (xFE06). The caller has provided a return address in R7; so, PUTC simply does JMP R7 (aka, RET) to exit. The user progam does the following: -- loads R0 with a character code -- TRAP x21 The character code would be stored in the user's data segment. For instance, DATA: ... .FILL x0061 ;-- 'a' ... and loaded into a register, e.g., R0: ldr R0, GDP__, #char_a__ where char_a__ has been defined in a macro as the table offset to that data table entry for 'a'. REFERENCES: LC3trunk/docs/LC3-3-PP-Append-A.pdf LC3trunk/docs/LC3-4-Assembly-Manual.pdf LC3trunk/docs/LC3-4-Assembly-CheatSheet LC3trunk/docs/LC3-4-Assembly-ASCII.html LC3tools/PennSim_Manual.pdf SOURCE CODE: ################################################################## ### os.asm (begins on next line) ################################# changecom(`;',) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; os.asm ;; ;; This code uses m4 macro definitions. ;; You must pre-preocess this w/ m4, e.g.: ;; ;; cat os.asm | m4 > os_pre.asm ;; ;; The m4 definitions follow this header. The "changecom" at the ;; top tells m4 we are using ";" as our comment delimiter. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;; BEGIN Macro Defs ;;;;;;;;;;;;;;;;;;;;;;;;;;;; define(`GDP__',`R4')dnl define(`BP__',`R5')dnl define(`SP__',`R6')dnl define(`push__',` ADD SP__, SP__, #-1 STR $1, SP__, #0')dnl define(`pop__',` LDR $1, SP__, #0 ADD SP__, SP__, #1')dnl ;------ DATA table offset definitions. define(`CODE__', `0')dnl define(`STACK__', `1')dnl define(`HALT_vect__', `2')dnl define(`HALT_init__', `3')dnl define(`HALT_begin__', `4')dnl define(`USR_CODE__', `5')dnl ;;;;;;;;;;; END Macro Defs ;;;;;;;;;;;;;;;;;;;;;;;;;;;; .ORIG x0200 ;================================================ ; Code Segment ;================================================ CODE: ;------------------------------------------- ;-- OS initialization ---------------------- ;------------------------------------------- ;--------------------------------- ; Set up GDP ;--------------------------------- LEA GDP__, DATA_PTR ;-- GDP gets address of pointer. LDR GDP__, GDP__, #0 ;-- GDP gets pointer to DATA. BR L1 ;-- Jump over local data. DATA_PTR: .FILL DATA ;-- L1: ;--------------------------------------- ; Set up statck. ;--------------------------------------- LDR SP__, GDP__, #STACK__ LDR BP__, GDP__, #STACK__ ;--------------------------------------- ; Set up Vector Table ;--------------------------------------- JSR HALT_init ;------------------------------------------- ;-- OS main -------------------------------- ;------------------------------------------- main: LDR R7, GDP__, #USR_CODE__ ;-- get user's code address, JMP R7 ;-- go to user's code (returns via HALT) ;---------------------------------------- ;-- Service Routines -------------------- ;---------------------------------------- ;---------------------------------------- ;-- HALT_init ;---------------------------------------- HALT_init: LDR R0, GDP__, #HALT_vect__ ;-- Get VT slot address. LDR R1, GDP__, #HALT_begin__ ;-- Get HALT's address. STR R1, R0, #0 ;-- Load the VT slot. JMP R7 ;---------------------------------------- ;-- HALT, TRAP x25 ;-- User program's exit and return to OS. ;-- Restarts the OS. Cannot trust the values of ;-- GDP, SP, or BP. User may have altered them. ;---------------------------------------- HALT_begin: LEA R7, HALT_data ;-- get pointer LDR R7, R7, #0 ;-- get data JMP R7 ;-- jump (reboot) HALT_data: .FILL CODE ;================================================ ; Data Segment ; NOTE: m4 macros define table offsets. The definitions ; cannot be used above where they are defined. That's why ; They are defined at the top of this file. ;================================================ DATA: ;--- content ------------------ offset name .FILL CODE ;-- CODE__ .FILL x3000 ;-- STACK__ .FILL x0025 ;-- HALT_vect__ .FILL HALT_init ;-- HALT_init__ .FILL HALT_begin ;-- HALT_begin__ .FILL x3000 ;-- USR_CODE__ .END ## END of os.asm (ends on line above) ########################## ################################################################ ################################################################## ### usr.asm ( begins next line) ################################## changecom(`;',) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; usr.asm ;; ;; This looks initially just like os.asm, however ;; it is assembled separately. Labels turn into addresses. ;; The .ORIG is x3000. The addresses will be different. ;; It has its own CODE and DATA and STACK segments. They are ;; not shared with the OS code. The user has to initialize the ;; GDP, SP, and BP to point to its own segments. ;; The user uses the OS services by jumping via TRAP. The user ;; code does not know what the OS service routine's addresses ;; are at runtime. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;; BEGIN Macro Defs ;;;;;;;;;;;;;;;;;;;;;;;;;;;; define(`GDP__',`R4')dnl define(`BP__',`R5')dnl define(`SP__',`R6')dnl define(`push__',` ADD SP__, SP__, #-1 STR $1, SP__, #0')dnl define(`pop__',` LDR $1, SP__, #0 ADD SP__, SP__, #1')dnl ;------ DATA table offset definitions. define(`CODE__', `0')dnl define(`STACK__', `1')dnl ;;;;;;;;;;; END Macro Defs ;;;;;;;;;;;;;;;;;;;;;;;;;;;; .ORIG x3000 ;================================================ ; Code Segment ;================================================ CODE: ;--------------------------------- ; Set up GDP ;--------------------------------- LEA GDP__, DATA_PTR ;-- GDP gets address of pointer. LDR GDP__, GDP__, #0 ;-- GDP gets pointer to DATA. BR L1 ;-- Jump over local data. DATA_PTR: .FILL DATA ;-- L1: ;--------------------------------------- ; Set up statck. ;--------------------------------------- LDR SP__, GDP__, #STACK__ LDR BP__, GDP__, #STACK__ ;------------------------------------------- ;-- main -------------------------------- ;------------------------------------------- main: TRAP x25 ; HALT, return to OS ;================================================ ; Data Segment ; NOTE: m4 macros define table offsets. The definitions ; cannot be used above where they are defined. That's why ; They are defined at the top of this file. ;================================================ DATA: ;--- content ------------------ offset name .FILL CODE ;-- CODE__ .FILL xFE00 ;-- STACK__ .END ## END of usr.asm (ends on line above) ######################### ################################################################