name ('loader') title LOADER ROUTINE FOR ATHENA 1.2 .z80 .tfcond .comment ~ ********************************************************************************** ********************************************************************************** *** ******** ******** ********** ************ *********** *** ********** ********** *********** ************ ************ *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ******* ************ *** *** *** ************ *** *** ******* *********** *** *** *** ************ *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ************ ********** *** *** *********** ************ *** *** ************ ******** *** *** ********** ************ *** *** ********************************************************************************** ********************************************************************************** L O A D E R . M A C Version 1.20 Creation Date: 17 August 1982 MODULE: 0.10 Date Last Revised: 7 October 1983 Loader Module for ATHENA operating system modules Edit History: 17 Aug 82 - Created by Mike Pinkston. 21 Dec 82 - Modified to solve the SIO/DART Reset Channel problem. 24 Dec 82 - Modified labeling done for clarity and continuity of programming style. 7 Jan 83 - Modified by moving the FCB's forward. 12 Jan 83 - Modified by adding a search for string module (I did this out of desperation). 18 Jan 83 - Set up for the ATHENA.SPR file. 7 Oct 83 - Modified for use with the ZCPR2 system. ~ subttl Global/External points of entry and reference page 60 GLOBAL Loader GLOBAL ATHLNG, ATHSTR, TOPAGE, MESAG8 EXTERNAL SETMEM EXTERNAL LDOS subttl MODULE EQUATE STATEMENTS page FCB.Buffer EQU 005CH ; Default FCB. DMA.Buffer EQU 0080H ; Default DMA buffer address. Buffer.Area EQU 2800H ; Starting address of the File Buffer. Character.Out EQU 2 ; Output Character system call. Print.String EQU 9 ; Print String system call. Reset.Disk EQU 13 ; Reset Disk System system call. Open.File EQU 15 ; Open File system call. Read.a.Record EQU 20 ; Read a Record system call. Set.DMA.Address EQU 26 ; Set DMA Address system call. Null EQU 000H ; ASCII Null Code. Carriage.Return EQU 00DH ; ASCII Carriage Return. Line.Feed EQU 00AH ; ASCII Line Feed. Escape EQU 01BH ; ASCII Escape character. Lead.In EQU Escape ; Lead in character for clearing the screen. Clear.Screen EQU 'v' ; Clear screen character. subttl START OF MODULE AND DATA AREAS page aseg org 0100H Loader:: ; Jump to beginning of program. JP Beginning ; Top.Page.of.Memory: DEFB 0E3H ; Address of the top page in memory to ; be used by ATHENA. This means that ; starting from this location DOWN is ; available to be used for ATHENA.SPR. Stop.Test.Page: DEFB 0EFH ; Page address of the last page in ; memory to be cleared and tested. ; In most cases this page address will ; be greater than Top.Page.of.Memory ; to insure that all of the reserved ; buffer areas are cleared and tested. FCB.1: DEFB 0,'ATHENA SPR' DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 Signon.Message: DEFB Lead.In, Clear.Screen DEFB '******************************' DEFB Carriage.Return, Line.Feed DEFB '* ATHENA/ZCPR2 System Loader *' DEFB Carriage.Return, Line.Feed DEFB '* Version: 1.2 *' DEFB Carriage.Return, Line.Feed DEFB '* by Black Hole Systems *' DEFB Carriage.Return, Line.Feed DEFB '* Current as of: 7 Oct 1983 *' DEFB Carriage.Return, Line.Feed DEFB '* for: Mike Pinkston *' DEFB Carriage.Return, Line.Feed DEFB '* Z80 STD Bus Development *' DEFB Carriage.Return, Line.Feed DEFB '* System *' DEFB Carriage.Return, Line.Feed DEFB '******************************' DEFB Carriage.Return, Line.Feed, '$' Message.1: DEFB Carriage.Return, Line.Feed DEFB 'Top of memory = $' Message.2: DEFB Carriage.Return, Line.Feed, Carriage.Return, Line.Feed DEFB 'Memory Segment Table:$' page Message.3: DEFB Carriage.Return, Line.Feed DEFB '******************************' DEFB Carriage.Return, Line.Feed, Line.Feed DEFB Null, Null DEFB '$' Message.4: DEFB ' $' Message.6: DEFB ' This file is not present in the directory of this disk.$' Message.7: DEFB Carriage.Return, Line.Feed DEFB 'There does not appear to be enough memory to load the operating system.$' Mesag8:: DEFB 'k ATHENA/ZCPR2 Version$' page ; Storage for variables to be used. ATHLNG:: ; Program.Length: ; DEFW 0000H ; Program length. Bit.Map.Pointer: ; DEFW 0000H ; Bit Map address pointer. ATHSTR:: ; Top.Page.Address: ; DEFW 0000H ; Location of Top Memory address. TOPAGE:: ; DEFB 00H ; High Byte of Top Page of memory. subttl Start of the Loader program page Beginning: ; DI ; Disable interrupts. LD SP,Stack.Area ; LD C,Reset.Disk ; Reset the Disk System. CALL LDOS ; LD DE,Signon.Message ; Display the Signon message. CALL Display.Message ; LD A,(Stop.Test.Page) ; Set memory from the Buffer.Area up to LD H,A ; Stop.Test.Page to zeros. LD L,0 ; LD DE,Buffer.Area ; OR A ; SBC HL,DE ; LD B,H ; LD C,L ; LD HL,Buffer.Area ; Loop.1: ; Keep looping until done. XOR A ; LD (HL),A ; INC HL ; DEC BC ; LD A,B ; OR C ; JR NZ,Loop.1 ; LD A,(Top.Page.of.Memory) ; Get the value of the top page of memory. If.1: ; If (the value = 00) OR A ; LD H,A ; JR NZ,Endif.1 ; ; Then.1: ; Then (the value = 00) LD HL,Buffer.Area ; Start at the file buffer and go up. ; This routine tests for the top of memory ; by getting a byte, complementing the ; byte, storing it back, and then seeing ; if the written byte is the same as the ; previous value. If so, then the top of memory ; has been found. Otherwise the byte is ; restored to its previous value and the next ; byte is looked at. ; Do.Until.1: ; Do until (the end of memory) LD A,(HL) ; CPL ; LD (HL),A ; CP (HL) ; If.2: ; If (the values are equal) JR NZ,Endif.2 ; ; Then.2: ; Then (the values are equal) CPL ; Try the next byte. LD (HL),A ; INC HL ; LD A,(Stop.Test.Page) ; CP H ; JR NZ,Do.Until.1 ; Loop for next byte. ; Endif.2: ; Endif (the values are equal) Enddo.until.1: ; Enddo until (the end of memory) Endif.1: ; Endif (the value = 00) subttl Display top memory address and get files loaded page LD L,00 ; Set up Top Memory Address. LD (Top.Page.Address),HL ; LD A,H ; LD (TOPAGE),A ; LD DE,Message.1 ; Display the "Top of memory = " message. CALL Display.Message ; LD HL,(Top.Page.Address) ; Get Top Memory Address. DEC HL ; Get corrected address. CALL ASCII.Value.Prnt ; Output the address as "XXXXH". ; LD DE,Message.2 ; Display the "Memory Segment Table:" message. CALL Display.Message ; LD DE,FCB.1 ; Load the "ATHENA.SPR" file. CALL Get.the.File ; ; LD DE,Message.3 ; Display the seperator line. CALL Display.Message ; ; CALL SETMEM## ; Set the Memory Size string in the AIOS. LD HL,(ATHSTR) ; JP (HL) ; subttl VARIOUS SUPPORT ROUTINES page Set.the.DMA.Addr: ; Set DMA address to 0080H. LD DE,DMA.Buffer ; LD C,Set.DMA.Address ; JP LDOS ; CRLF: ; Output a CR,LF to the console. LD A,Carriage.Return ; CALL Print.Character ; LD A,Line.Feed ; JP Print.Character ; ASCII.Value.Prnt: ; Output the ASCII string "XXXXH", where LD A,H ; XXXX is the ASCII Hex value of "HL". CALL Print.Digit ; LD A,L ; CALL Print.Digit ; LD A,'H' ; JP Print.Character ; Print.Digit: ; Output the value of "A" as an ASCII PUSH AF ; Hex number. RRCA ; RRCA ; RRCA ; RRCA ; CALL Print.Digit.1 ; POP AF ; Print.Digit.1: ; AND 0FH ; ADD A,90H ; DAA ; ADC A,40H ; DAA ; Print.Character: ; Send the character in "A" to console. PUSH BC ; PUSH DE ; PUSH HL ; LD E,A ; LD C,Character.Out ; CALL LDOS ; POP HL ; POP DE ; POP BC ; RET ; Space.Print: ; Print " " on console. LD DE,Message.4 ; Display.Message: ; LD C,Print.String ; Print string on console. JP LDOS ; page Print.File.Name: ; Print the File name pointed to be "DE" LD B,0BH ; on the console. Do.Until.2: ; Do until (end of the file name) INC DE ; LD A,(DE) ; CALL Print.Character ; DEC B ; JR NZ,Do.Until.2 ; RET ; Enddo.until.2: ; Enddo until (end of the file name) Mem.Error.Message: ; Print the Insufficient memory error LD DE,Message.7 ; message on the console. CALL Display.Message ; Eternal.Loop: ; Eternal wait loop. JR Eternal.Loop ; subttl GET THE FILE LOADED AND CONVERTED page Get.the.File: ; PUSH DE ; CALL Set.the.DMA.Addr ; POP DE ; PUSH DE ; Open file systen call. LD C,Open.File ; CALL LDOS ; POP DE ; INC A ; If.4: ; If (the file is not present) JR NZ,Endif.4 ; Then.4: ; Then (the file is not present) CALL CRLF ; CALL Print.File.Name ; LD DE,Message.6 ; Print file not present in directory CALL Display.Message ; message on console. JR Eternal.Loop ; Endif.4: ; Endif (the file is not present) LD HL,Buffer.Area ; Start loading the file into the buffer. Do.Until.3: ; Do until (the file is loaded) PUSH HL ; PUSH DE ; EX DE,HL ; LD C,Set.DMA.Address ; Set the DMA address to the buffer. CALL LDOS ; POP DE ; PUSH DE ; LD C,Read.a.Record ; Read a record into the buffer. CALL LDOS ; POP DE ; POP HL ; LD BC,0080H ; ADD HL,BC ; OR A ; JR Z,Do.Until.3 ; ; Enddo.until.3: ; Enddo.until (the file is loaded) PUSH DE ; Save the FCB address. PUSH HL ; Save the pointer to the last byte of the file. LD HL,(Buffer.Area + 1) ; Get the program length value. LD A,L ; Set the program length to a 256 byte OR A ; boundary. If.5: ; If (the boundary is not 256 multiple) JR Z,Endif.5 ; Then.5: ; Then (the boundary is not 256 multiple) LD L,00 ; INC H ; Endif.5: ; Endif (the boundary is not 256 multiple) page LD (Program.Length),HL ; Compute the necessary base address for EX DE,HL ; the module to be loaded. LD HL,(Top.Page.Address) ; OR A ; SBC HL,DE ; LD (Top.Page.Address),HL ; Save the new base address for later use. POP DE ; Compute the length of the available memory. OR A ; SBC HL,DE ; If there is not enough memory to load JP C,Mem.Error.Message ; the module then, jump memory error message. CALL CRLF ; Otherwise, output a CR,LF to console. POP DE ; Display the filename on the console. CALL Print.File.Name ; CALL Space.Print ; Display spaces. LD HL,(Top.Page.Address) ; CALL ASCII.Value.Prnt ; Display the Starting address of the module. CALL Space.Print ; Display spaces. LD HL,(Program.Length) ; CALL ASCII.Value.Prnt ; Display the Length of the module. LD HL,(Buffer.Area + 1) ; Get the length of the program. LD DE,Buffer.Area + 100H ; Get the starting address of the program. ADD HL,DE ; Compute the start of the relocation bit map. LD (Bit.Map.Pointer),HL ; Save bit map pointer address. LD HL,(Top.Page.Address) ; Set up offset value for relocation. LD A,H ; LD (Offset.Value),A ; page Do.Until.4: ; Do until (Bitmap area is exhausted) ; Set up to work on 8 bytes at a time. LD B,08H ; (1 bitmap byte = 8 program bytes.) PUSH HL ; LD HL,(Bit.Map.Pointer) ; Get a byte from the bit map. LD C,(HL) ; INC HL ; Increment the bitmap pointer. LD (Bit.Map.Pointer),HL ; Save it off again. POP HL ; Get destination byte pointer. Do.Until.5: ; Do until (Bitmap byte is exhausted) LD A,C ; Rotate the byte from the bitmap, one bit RLCA ; left into the Carry bit. If the bit is LD C,A ; set, then add the offset to the program LD A,(DE) ; byte. Otherwise leave alone. In either If.6: ; If (byte is relocatable) JR NC,Endif.6 ; case, transport the program byte to the Then.6: ; Then (byte is relocatable) ADD A,00 ; destination address. Offset.Value EQU $-1 ; Endif.6: ; Endif (byte is relocatable) LD (HL),A ; INC HL ; INC DE ; PUSH HL ; LD HL,(Buffer.Area + 1) ; Decrement the program length count. DEC HL ; LD (Buffer.Area + 1),HL ; LD A,L ; Check to see if count = 0. OR H ; POP HL ; RET Z ; If count = 0, then return. DJNZ Do.Until.5 ; Otherwise decrement bit count and loop. Enddo.until.5: ; Enddo until (Bitmap byte is exhausted) JR Do.Until.4 ; Cycle for another bitmap byte. Enddo.Until.4: ; Enddo until (Bitmap area is exhausted) subttl Stack Data Area page DS 30H Stack.Area EQU $ ; Stack area used by loader. END Loader