home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-06-06 | 35.5 KB | 1,700 lines |
- ;************************************************************************
- ;* History: *
- ;* 28.08.1987 Grundversion *
- ;* 28.02.1989 Cmd-Line Parser verbessert: L|schte Bildschirm *
- ;* bei Eingabe von lfw:Dateiname *
- ;* Au~erdem werden Dateinamen mit mehr als 8 Zei- *
- ;* chen jetzt akzeptiert (Rest ignoriert!) und *
- ;* '_'-Zeichen im Dateinamen auch. *
- ;* lfw: wird jetzt richtig ausgewertet *
- ;* l|scht den Speicher jetzt vor dem Linken! *
- ;* verschiedene Special-Link-Items werden jetzt *
- ;* erkannt (high(addr), low(addr)). *
- ;* *
- ;************************************************************************
-
- .z80 ;
- tab equ 9 ;
- lf equ 10 ;
- cr equ 13 ;
- maclib BDOSCALL.MLB ;
-
- print macro text ;
- local txtaddr ;
- dseg ;
- txtaddr: db text,0 ;
- cseg ;
- ld hl,txtaddr ;
- call txtout ;
- endm ;
-
-
- clear_mem: ld hl,(6) ; BDOS - Start
- ld de,($MEMRY) ;
- scf ;
- sbc hl,de ; free mem length - 1
- ld c,l ;
- ld b,h ; BC := length - 1
- ld l,e ;
- ld h,d ; HL := ($MEMRY)
- ld (hl),0 ;
- inc de ;
- ldir ;
- ret ;
-
- public $MEMRY ;
-
- entry: print <cr,lf,"Z80-Linker Ver. 1.1 written Aug-1987 by M.Bischoff", cr, lf, lf>
- do_reset: ld sp,stack ;
- call clear_mem ;
- call cmd_line_init ;
- ld hl,1100h ;
- $MEMRY equ $-2 ;
- ld (prog_buf),hl ;
- call reset ;
- main_loop: ld sp,stack ;
- call get_cmd ;
- check_option: ld (txt_ptr),hl ; store pointer
- or a ; end of line => load module
- jr z,load_relfile ;
- cp ',' ; terminated with comma => load module
- jr z,load_relfile ;
- cp '/' ;
- jr z,option ;
- inc hl ;
- ld a,(hl) ;
- call is_delim_2 ; blank, comma or slash
- jr z,check_option ;
-
- cmd_error: print "Bad Command: " ;
- ld hl,(txt_ptr) ;
- call txtout ;
- call crlf_out ;
- abbruch: ld hl,(txt_ptr) ;
- ld (hl),0 ;
- jr main_loop ;
-
- option: inc hl ; steht auf Zeichen
- inc hl ; steht auf 1 weiter!
- ld a,(hl) ;
- call is_delim_2 ; darf nur ',' oder '/' folgen
- jp nz,cmd_error ;
- dec hl ;
- ld a,(hl) ;
- inc hl ;
- and 0dfh ; to upper
- cp 'N' ;
- jp z,name_outfile ;
- cp 'S' ;
- jp z,search_library ;
- cp 'R' ;
- jp z,do_reset ; reset, don't load file before
- ld e,a ;
- ld a,(user_fcb+1) ; any file to load?
- cp ' ' ; any filename?
- jr nz,load_relfile ; then skip option, do it later
- ld a,e ; resume other commands
- cp 'U' ;
- jp z,list_undefineds ;
- cp 'M' ;
- jp z,list_defineds ;
- cp 'E' ;
- jp z,save_object ;
- cp 'O' ; set to octal?
- jr z,set_oct_hex ;
- cp 'H' ; set to hexadecimal?
- jr z,set_oct_hex ;
- jp cmd_error ;
-
- load_relfile: call open_relfile ;
- load_loop.1: call load_module ;
- or a ;
- jr z,load_loop.1 ;
- cp 1 ;
- jp z,main_loop ; end of file
- jp abbruch ;
-
- open_relfile: ld hl,user_fcb ;
- ld de,rel_fcb ;
- ld bc,24h ;
- ldir ;
- ld hl,rel_fcb+9 ;
- ld a,(hl) ;
- or a ;
- jr nz,has_rel_ext ;
- ld (hl),'R' ;
- inc hl ;
- ld (hl),'E' ;
- inc hl ;
- ld (hl),'L' ;
- has_rel_ext: ld a,80h ;
- ld (bytecnt),a ; set Buffer to beginning
-
- bdos open_file,rel_fcb ;
- cp 4 ;
- ret c ;
- print "Cannot open file "
- xor a ;
- ld (rel_fcb+13),a ;
- ld hl,rel_fcb+1 ;
- call txtout ;
- call crlf_out ;
- jp abbruch ;
-
- dseg ;
- blank_fcb: db 0,' ',0,' ' ; 1. Byte der Extension ist 0
- ds 24h-12,0 ;
- user_fcb: ds 24h,0 ;
-
- txt_ptr: dw 0 ;
- cseg ;
-
- set_oct_hex: ld (txt_ptr),hl ; store new address
- dec hl ;
- ld a,(hl) ; extension of numbers
- ld (number_ext),a ;
- res 5,a ; make lower to upper
- sub 'H' ; hex is
- ld (octal_flag),a ;
- jp main_loop ;
-
- cmd_line_init: ld hl,80h ;
- ld e,(hl) ;
- ld d,0 ;
- inc hl ;
- ld (txt_ptr),hl ;
- add hl,de ;
- ld (hl),d ;
- ret ;
-
- is_alnum: cp '_' ; underscore erlaubt!
- jr z,.isalnum1 ;
- sub '0' ;
- cp 10 ;
- ret c ; disgit
- sub 'A'-'0' ;
- cp 26 ;
- ret c ; Gro~buchstabe
- sub 20h ;
- cp 26 ;
- ret nc ; kein alnum
- res 5,(hl) ; toupper!
- .isalnum1: scf ; true!
- ret
-
- is_delim_2: cp '/' ;
- ret z ;
- is_delim_1: cp ',' ;
- ret z ;
- is_blank: cp ' ' ;
- ret z ;
- cp tab ;
- ret z ;
- or a ;
- ret ;
-
- get_cmd: ld hl,(txt_ptr) ;
- skip: ld a,(hl) ;
- call is_delim_1 ; blank or comma skipped
- jr nz,has_text ;
- inc hl ; Zeiger auf n{chstes Zeichen!
- or a ;
- jr nz,skip ; any spaces, tabs, commas
-
- ld a,'*' ; read more commands from console
- call akku_out ;
- ld de,80h ;
- ld a,7ch ;
- ld (de),a ;
- bdos inline ;
- ld a,lf ;
- call crlf_out ;
- ld hl,80h ;
- xor a ;
- ld (hl),a ;
- inc hl ;
- ld e,(hl) ;
- ld d,a ;
- inc hl ;
- ld (txt_ptr),hl ;
- add hl,de ;
- ld (hl),d ; 0
- jr get_cmd ;
-
- has_text: exx ;
- ld hl,blank_fcb ;
- ld de,user_fcb ;
- ld bc,24h ;
- ldir ;
- exx ;
- cp '/' ; im Akku noch Zeichen!
- ret z ; HL steht auf n{chstem Zeichen
- ; HL steht auf 1. Zeichen des Dateinamens!
- after_lfw: and 0dfh ; must be character
- sub 'A' ;
- cp 26 ;
- jp nc,cmd_error ;
- res 5,(hl) ; wandele (HL) in Gro~buchstaben um!
- inc hl ;
- ld c,a ; speichern!
- ld a,(hl) ;
- cp ':' ; Laufwerksangabe?
- ld a,c ;
- jr nz,no_lfw ;
- cp 16 ;
- jp nc,cmd_error ; Cp/M kennt nur A..P
- ld a,(user_fcb) ; hat schon Laufwerk?
- or a ;
- jp nz,cmd_error ; dann Fehler melden
- ld a,c ;
- inc a ;
- ld (user_fcb),a ;
- inc hl ; noch einen weiter => 1. Zeichen nach ':'
- ld a,(hl) ;
- jr after_lfw ; zweiter Versuch!
-
- no_lfw: add a,'A' ;
- ld de,user_fcb+1 ;
- ld bc,8*256 ; C=0: no extension yet
- init_user_fcb: ld (de),a ;
- inc de ;
- after_ext: ld a,(hl) ;
- call is_delim_2 ; blank, comma or slash
- ret z ;
- cp '.' ; Filename extension?
- jr z,get_extension ;
- call is_alnum ;
- jp nc,cmd_error ;
- ld a,(hl) ;
- inc hl ;
- djnz init_user_fcb ;
- jr after_ext ;nicht so nerv|s werden, Rest ignorieren
- jp cmd_error ;
-
- get_extension: bit 0,c ; extension ?
- jp nz,cmd_error ; 2. nicht erlaubt
- ld de,user_fcb+9 ; beg. of extension
- ld b,4 ; 3 Zeichen erlaubt (last = error)
- inc hl ;
- inc c ; set extension
- ld a,' ' ; bis jetzt keine Extension
- ld (de),a ; nur, um Default-Extension zu vermei-
- jr after_ext ; den
-
- dseg ;
- ds 200,0 ;
- stack: ;
- cseg ;
-
- reset: ld hl,(6) ;
- dec hl ; letzte benutzbare Speicherzelle
- ld (top_of_mem),hl ;
-
- ld hl,103h ; Default load addresses
- ld (start_cseg),hl ;
- ld (start_dseg),hl ;
- ld (start_common),hl ;
-
- ld hl,(prog_buf) ; no Entry Point defined
- ld (hl),0 ;
- inc hl ;
- ld (hl),0 ;
- inc hl ;
- ld (hl),0 ;
- inc hl ;
- ld (top_load),hl ; hoechste Ladeadresse
-
- ld hl,0 ; no Globals yet
- ld (list_globals),hl ;
- ld (list_commons),hl ;
- ld (list_requests),hl ;
- ld hl,upn_stack
- ld (upn_ptr),hl
- ret ;
-
-
- dseg ;
- base: dw 0 ; true zero
- start_cseg: dw 103h ; cseg orign ; USER addresses
- start_dseg: dw 103h ; dseg orign
- start_common: dw 103h ; common orign
-
- size_cseg: dw 103h ; cseg size
- size_dseg: dw 103h ; dseg size
- size_common: dw 103h ; common size
- start_cseg_real:dw 103h ; cseg orign ; REAL addresses
- start_dseg_real:dw 103h ; dseg orign ; unused
- start_common_real:dw 103h ; common orign
-
- top_load: dw 0 ; ; REAL addresses
- top_of_mem: dw 0 ;
- curr_mem: dw 0 ;
-
- list_globals: dw 0 ; Pointer auf Anfang von verketteter
- list_commons: dw 0 ; Liste alphabetisch sortierter
- list_requests: dw 0 ; Globals, COMMONs, Requests
- list_explus: dw 0 ;
-
- prog_buf: dw 0 ; begin of Program Buffer
- undefd_name: db 0 ;
- db '(undefined)',0 ;
- program_name: db 0 ;
- ds 16,0 ; for later!
- commonblock: db 0 ;
- ds 16,0 ;
-
- searchfield: dw 0 ; next-address
- db 0 ; typebyte
- B_field: db 0 ;
- ds 16,0 ;
- cseg ;
-
- ;************************************************************************
- ;* *
- ;* load_file: File is open and FCB on correct position *
- ;* *
- ;************************************************************************
-
- load_module: ld (saved_sp),sp ; f}r den Fehlerfall...
- ld a,0ffh ; Beginne bei einer Bytegrenze
- ld (relcnt),a ;
-
- ld hl,undefd_name ;
- ld de,program_name ; no Name defined
- ld bc,17 ;
- ldir ;
-
- ld hl,0 ; no address specified
- ld (start_cseg),hl ; fuer's erste
- jr load_loop ;
-
- load_gethl: ld hl,(curr_mem) ;
- load_loop: call getbit ;
- jr nc,absolute_byte ;
- ld a,2 ;
- call get_abits ;
- jr z,special_item ;
- push hl ; load 16 Bit with offset
- call read_16 ; read A-field is same
- ex de,hl ;
- pop hl ;
- ld a,l ; address OK?
- or h ;
- jp z,e_no_addr ; no!
- ld (hl),e ;
- inc hl ;
- ld (hl),d ;
- inc hl ;
- jp pruef_mem ;
-
- absolute_byte: ld a,l ; address OK?
- or h ;
- jp z,e_no_addr ; no!
- call get_byte ;
- ld (hl),a ; save in memory
- inc hl ;
-
- pruef_mem: ex de,hl ;
- ld hl,(top_load) ;
- or a ;
- sbc hl,de ;
- ex de,hl ;
- jr nc,load_loop ;
-
- e_nomem: ld hl,txt_no_mem ;
- jp rel_fehler ;
-
- special_item: ld (curr_mem),hl ;
- ld a,4 ;
- call get_abits ;
- ld hl,jp_table ;
- add hl,bc ;
- add hl,bc ;
- ld a,(hl) ;
- inc hl ;
- ld h,(hl) ;
- ld l,a ;
- jp (hl) ;
-
- jp_table: dw get_entry_symbol ;
- dw sel_common ;
- dw store_name ;
- dw request_search ;
- dw reserved_B ;
-
- dw def_common_size ;
- dw chain_external ;
- dw define_entry ;
- dw reserved_A ;
-
- dw external_offset ;
- dw def_dseg_size ;
- dw set_loc_counter ;
- dw chain_address ;
- dw def_cseg_size ;
- dw end_program ;
-
- dw end_file ;
-
- ;************************************************************************
- ;* *
- ;* verschiedene Programme, die Special Link *
- ;* Items ausfuehren *
- ;* *
- ;************************************************************************
-
- get_entry_symbol:call get_B_field ; LINK item 0
- jp load_gethl ; ignore so far
-
- sel_common: call get_B_field ; LINK item 1
- call search_common ;
- jp nz,undefd_common ;
- ld (start_common),de ;
- jp load_gethl ;
-
- store_name: call get_B_field ; LINK item 2
- ld hl,B_field ;
- ld de,program_name ;
- ld bc,17 ;
- ldir ;
- jp load_gethl ;
-
- request_search: call get_B_field ; LINK item 3
- call find_request ;
- jp load_gethl ;
-
-
- pushde: ld hl,(upn_ptr)
- dec hl
- ld (hl),d
- dec hl
- ld (hl),e
- ld (upn_ptr),hl
- ret
- popde: ld hl,(upn_ptr)
- ld e,(hl)
- inc hl
- ld d,(hl)
- inc hl
- ld (upn_ptr),hl
- ret
-
- dseg
- ds 20 ; Stack f}r special Link-items
- upn_stack:
- upn_ptr: dw upn_stack
- cseg
-
- push_upn: ld a,(hl)
- ex de,hl
- and 3 ; abs/cseg/dseg/common
- add a,a
- ld c,a
- ld b,0
- ld hl,base
- add hl,bc ; hl is offset
- ld c,(hl)
- inc hl
- ld b,(hl) ; BC is USER-Address
- ex de,hl
- inc hl
- ld a,(hl)
- add a,c ; low byte (USER address)
- ld e,a
- inc hl
- ld a,(hl)
- adc a,b
- ld d,a ; high byte
- call pushde
- jp load_gethl
-
- dseg
- txt_abs_ex: db 'FATAL: exp. abs. byte after L.I. 4', 0
- cseg
-
- fatal_absex: ld hl,txt_abs_ex
- call txtout
- rst 0
-
- sp4_A01: call getbit
- jr c,fatal_absex
- call get_byte
- call popde
- ld hl,(curr_mem)
- ld (hl),e
- inc hl
- jp pruef_mem
- sp4_A02: call getbit
- jr c,fatal_absex
- call get_byte
- call getbit
- jr c,fatal_absex
- call get_byte
- call popde
- ld hl,(curr_mem)
- ld (hl),e
- inc hl
- ld (hl),d
- inc hl
- jp pruef_mem
- sp4_A03: call popde
- ld e,d
- ld d,0
- upn_back: call pushde
- jp load_gethl
- sp4_A04: call popde
- ld d,0
- jr upn_back
- sp4_A05: call popde
- ld a,e
- cpl
- ld e,a
- ld a,d
- cpl
- ld d,a
- jr upn_back
- sp4_A06: call popde
- ld hl,0
- sub_back: or a
- sbc hl,de
- ex de,hl
- jr upn_back
- sp4_A07: call popde
- push de
- call popde
- pop hl
- ex de,hl ; HL is now 2nd
- jr sub_back
- sp4_A08: call popde
- push de
- call popde
- pop hl
- add hl,de
- ex de,hl
- jr upn_back
-
- do_ari: ld a,(hl)
- or a
- jr z,sp4_unknown
- dec a
- jr z,sp4_A01
- dec a
- jr z,sp4_A02
- dec a
- jr z,sp4_A03
- dec a
- jr z,sp4_A04
- dec a
- jr z,sp4_A05
- dec a
- jr z,sp4_A06
- dec a
- jr z,sp4_A07
- dec a
- jr z,sp4_A08
- jr sp4_unknown
-
- push_external: ld de,0
- call pushde ; um Stack-Konflikte zu vermeiden
- jr sp4_unknown
-
- reserved_B: call get_B_field ; LINK item 4
- ld hl,B_field+1
- ld a,(hl)
- inc hl
- cp 'A' ; arithmetic?
- jr z,do_ari
- cp 'B'
- jr z,push_external
- cp 'C'
- jp z,push_upn
- sp4_unknown: ld hl,txt_special_4 ;
- call txtout ;
- ld hl,(curr_mem) ; derzeitige Ladeadresse
- ld de,(prog_buf)
- dec d
- or a
- sbc hl,de
- ex de,hl
- call hexout_de
- ld hl,txt_special4a
- call txtout
- call prt_B_field ;
- jp load_gethl ;
-
- prt_B_field: ld hl,B_field ;
- ld b,(hl) ; > 0!
- B_prt_loop: push bc
- inc hl
- ld a,(hl)
- sub ' '
- cp 5fh
- jr c,.B_prt1
- ld a,'/'
- call akku_out
- ld a,(hl)
- call hexout_a
- jr .B_prt2
- .B_prt1: ld a,(hl)
- call akku_out
- .B_prt2: pop bc
- djnz B_prt_loop
- ld a,'>'
- call akku_out
- call crlf_out
- ret
-
- def_common_size:call get_A_field ; LINK item 5
- push hl ;
- call get_B_field ;
- call find_common ;
- jr z,has_common ;
-
- pop bc ; size
- ld (hl),b ;
- dec hl ;
- ld (hl),c ;
- dec hl ;
- push hl ;
- ld hl,(top_load) ;
- ld de,(prog_buf) ; make USER address
- dec d ;
- or a ;
- sbc hl,de ;
- ex de,hl ;
- pop hl ;
- ld (hl),d ;
- dec hl ;
- ld (hl),e ;
- ld hl,(top_load) ;
- add hl,bc ;
- jp c,e_nomem ; ERROR: Overflow total
- ld (top_load),hl ;
- ld de,(top_of_mem) ;
- sbc hl,de ;
- jp c,load_gethl ;
- jp e_nomem ; ERROR: Speicher voll
-
- has_common: ld a,(B_field) ;
- add a,5 ;
- ld c,a ; B is 0
- add hl,bc ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- pop hl ; new size
- scf ;
- sbc hl,de ; must be C
- jp c,load_gethl ;
-
- ld hl,txt_2nd_larger ;
- call txtout ;
- ld hl,B_field+1 ;
- call txtout ;
- ld hl,txt_2nd_2 ;
- call txtout ;
- jp load_gethl ;
-
- chain_external: call get_A_field ; LINK item 6
- push hl ; head of address chain
- call get_B_field ; name
- call find_global ; search or create name in list
- jr z,has_external ;
-
- pop bc ; head of chain
- ld (hl),b ;
- dec hl ;
- ld (hl),c ; store it
- ex de,hl ; HL= begin
- inc hl ;
- inc hl ; size/type - field
- set 7,(hl) ; mark as undefined
- jp load_gethl ;
-
- has_external: inc hl ;
- inc hl ;
- bit 7,(hl) ; also undefined?
- jr z,value_known ;
- dec hl ; concatenate two undefineds
- dec hl ;
- ld bc,(prog_buf) ; start area
- dec b ; for offset 100h
- search_end: ex de,hl ; HL := value (head of old chain)
- add hl,bc ; REAL address
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ; DE := USER address
- ld a,d ;
- or e ;
- jr nz,search_end ;
-
- pop de ;
- ld (hl),d ;
- dec hl ;
- ld (hl),e ;
- jp load_gethl ;
-
- value_known: ld c,e ; DE is value (from search)
- ld b,d ; BC := value of Global
- pop de ; USER address of first in chain
- jr define_it ;
-
- define_entry: call get_A_field ; LINK item 7
- push hl ; value
- call get_B_field ;
- call find_global ;
- jr z,had_global ;
-
- pop de ; value
- ld (hl),d ;
- dec hl ;
- ld (hl),e ;
- jp load_gethl ;
-
- had_global: inc hl ;
- inc hl ;
- bit 7,(hl) ;
- jr z,redefinition ;
- res 7,(hl) ;
- ld c,(hl) ;
- inc hl ;
- add hl,bc ;
- pop bc ; Value of now defined
- ; BC = USER value, HL points to chain
- replace_loop: ld e,(hl) ; Chain of undefineds
- ld (hl),c ;
- inc hl ;
- ld d,(hl) ;
- ld (hl),b ;
- define_it: ld a,d ;
- or e ;
- jp z,load_gethl ; all done, exit
- ld hl,(prog_buf) ;
- dec h ;
- add hl,de ; HL := REAL address of new
- jp replace_loop ;
-
- redefinition: push hl ;
- print "**** Warning! Global "
- ld hl,B_field+1 ;
- call txtout ;
- print <" redefined ****",cr,lf,"(Old value = ">
- pop hl ;
- ld c,(hl) ;
- ld b,0 ;
- add hl,bc ;
- inc hl ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- call hexout_de ;
- print ", new value = " ;
- pop de ;
- call hexout_de ;
- print <") Error ignored",cr,lf>
- jp load_gethl ;
-
- reserved_A: call get_A_field ; LINK item 8
- ld hl,txt_special_8 ;
- call txtout ;
- jp load_gethl ;
-
- external_offset:call get_A_field ; LINK item 9
- push hl ;
-
- ld hl,(top_of_mem) ;
- ld de,-6 ;
- add hl,de ;
- ld (top_of_mem),hl ;
- ex de,hl ;
- ld hl,(top_load) ;
- or a ;
- sbc hl,de ; NC!!!
- jp nc,e_nomem ;
- inc de ;
- ld hl,(list_explus) ;
- ld (list_explus),de ; zeigt auf neuen
- ex de,hl ; HL := &new
- pop bc ;
-
- ld (hl),e ; store next-ptr
- inc hl ;
- ld (hl),d ;
- inc hl ;
- ld de,(curr_mem) ; REAL address
- ld (hl),e ;
- inc hl ;
- ld (hl),d ;
- inc hl ;
- ld (hl),c ; store address field (offset)
- inc hl ;
- ld (hl),b ;
- jp load_gethl ;
-
- def_dseg_size: call get_A_field ; LINK item 10
- ld (size_dseg),hl ;
- ld de,(top_load) ;
- ld (start_dseg_real),de ;
- add hl,de ;
- ld (top_load),hl ;
- ld de,(top_of_mem) ;
- or a ;
- sbc hl,de ;
- jp nc,e_nomem ;
- ld hl,(start_dseg_real) ;
- ld bc,(prog_buf) ;
- dec b ;
- or a ;
- sbc hl,bc ; "NULL" abziehen
- ld (start_dseg),hl ;
- jp load_gethl ;
-
- set_loc_counter:call get_A_field ; LINK item 11
- ld de,(prog_buf) ;
- dec d ; get correct offset
- add hl,de ;
- jp load_loop ;
-
- chain_address: call get_A_field ; LINK item 12
- ld bc,(curr_mem) ;
- jp replace_loop ;
-
- def_cseg_size: call get_A_field ; LINK item 13
- ld (size_cseg),hl ;
- ld de,(top_load) ;
- ld (start_cseg_real),de ;
- add hl,de ;
- ld (top_load),hl ;
- ld de,(top_of_mem) ;
- or a ;
- sbc hl,de ;
- jp nc,e_nomem ;
- ld hl,(start_cseg_real) ;
- ld bc,(curr_mem) ;
- ld a,b ;
- or c ;
- jr nz,already_defined ;
- ld (curr_mem),hl ;
- already_defined:ld bc,(prog_buf) ;
- dec b ;
- or a ;
- sbc hl,bc ; "NULL" abziehen
- ld (start_cseg),hl ;
- jp load_gethl ;
-
- end_program: call get_A_field ; LINK item 14
- ld a,0ffh ; force Byte Boundary
- ld (relcnt),a ;
- ld a,h ;
- or l ;
- ret z ; done!
- ex de,hl ;
- ld hl,(prog_buf) ;
- ld (hl),0c3h ; JP
- inc hl ;
- ld (hl),e ;
- inc hl ;
- ld (hl),d ;
- xor a ; return 0: END OF MODULE
- ret ;
-
- end_file: ld a,1 ; LINK item 15
- or a ; return 1: END OF FILE
- ret ;
-
- ;************************************************************************
- ;* *
- ;* Unterprogramm zum Einlesen einzelner Felder *
- ;* *
- ;************************************************************************
-
- get_A_field: ld a,2 ; to HL
- call get_abits ;
- read_16: ld hl,base ;
- add hl,bc ;
- add hl,bc ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ; DE = offset
- push de ;
- call get_byte ;
- ld l,a ;
- call get_byte ;
- ld h,a ;
- pop de ;
- add hl,de ; true address
- ret ;
-
- get_B_field: ld hl,B_field ;
- ld a,3 ;
- call get_abits ;
- jr z,no_text ;
- ld (hl),a ;
- inc hl ;
- ld b,a ;
- loop_get_B: push bc ;
- call get_byte ;
- pop bc ;
- ld (hl),a ;
- inc hl ;
- djnz loop_get_B ;
- ld (hl),b ; terminate with 0
- ret ;
-
- no_text: inc a ; change empty to space!
- ld (hl),a ;
- inc hl ;
- ld (hl),' ' ;
- inc hl ;
- xor a ;
- ld (hl),a ;
- ret ;
-
- ;************************************************************************
- ;* *
- ;* REL-file I/O *
- ;* *
- ;************************************************************************
-
- get_byte: ld a,8 ; HL saved, DE, BC not A,C result
- get_abits: ld c,0 ; return B=0
- ld b,a ;
- loop: call getbit ;
- rl c ;
- djnz loop ;
- ld a,c ; NC, Z akkording to akku
- ret ;
-
- getbit: ld a,0 ; reg HL is saved, DE not
- relbyte equ $-1 ; reg BC if read_sector saves it (ok)
- ld d,0ffh ;
- relcnt equ $-1 ;
- inc d ;
- jp nz,has_bit ;
- push hl ;
-
- ld a,080h ;
- bytecnt equ $-1 ;
- or a ;
- call m,read_sector ; must return A=0 & D=0!!!
- ld e,a ;
- inc a ;
- ld (bytecnt),a ;
- ld hl,read_buffer ;
- add hl,de ;
- ld a,(hl) ;
- ld d,0f8h ;
-
- pop hl ;
- has_bit: add a,a ;
- ld (relbyte),a ;
- ld a,d ;
- ld (relcnt),a ;
- ret ;
-
-
- read_sector: push bc ; BC saved
- bdos set_dma_addr,read_buffer
- bdos read_seq,rel_fcb ;
- pop bc ;
- or a ;
- ld d,a ;
- ret z ; hat geklappt
- ld hl,txt_unex_eof ;
- jp rel_fehler ;
-
- dseg ;
- rel_fcb: db 0,' REL' ;
- ds 24h-12,0 ;
- read_buffer: ds 128,0 ;
- cseg ;
-
- ;************************************************************************
- ;* *
- ;* Error managing: *
- ;* *
- ;************************************************************************
-
- ;************************************************************************
- ;* I) non-FATAL errors *
- ;************************************************************************
-
- txt_special_4: db 'Special Link-item (4) received at PC = 0x',0
- txt_special4a: db ': <',0
- txt_special_8: db 'Special Link-item (8) received',cr,lf,0
-
- txt_2nd_larger: db '**** Warning! 2nd COMMON larger: /',0
- txt_2nd_2: db '/ ****',cr,lf,0 ;
-
- ;************************************************************************
- ;* II) FATAL errors *
- ;************************************************************************
-
- txt_no_mem: db 'Not enough memory', 0;
- txt_unex_eof: db 'Unexpected EOF', 0
- txt_no_addr: db 'No loading address specified!', 0
- saved_sp: dw 0 ;
- txt_undef_comm: db 'Undefined COMMON selected: ',0
-
- undefd_common: ld hl,txt_undef_comm ;
- error_in_B: call txtout ;
- ld hl,B_field+1 ;
- jr rel_fehler ;
-
- e_no_addr: ld hl,txt_no_addr ;
- rel_fehler: call txtout ;
- print <cr,lf,"Module "> ;
- ld hl,program_name+1 ;
- call txtout ;
- call crlf_out ;
- ld sp,(saved_sp) ;
- or 0ffh ; return 0ffh on error
- ret ;
-
- ;************************************************************************
- ;* *
- ;* Ausgabe-Funktionen *
- ;* *
- ;************************************************************************
-
- txtout: ld a,(hl) ;
- or a ;
- ret z ;
- call akku_out ;
- inc hl ;
- jr txtout ;
-
- print_octal: ex de,hl ; shift HL
- ld bc,0106h ; first digit has one bit only
- jr .octal2 ;
-
- .octal1: ld b,3 ;
- .octal2: xor a ;
- .octal3: add hl,hl ; shift bit
- rla ; into akku
- djnz .octal3 ;
- add a,'0' ; make it digit
- push bc ; c is counter
- call akku_out ;
- pop bc ;
- dec c ; another digit?
- jr nz,.octal1 ;
- ex de,hl ;
- jr trailer ;
-
- hexout_de: ld a,0 ; initially HEX
- octal_flag equ $-1 ;
- or a ;
- jr nz,print_octal ;
- ld a,d ;
- call hexout_a ;
- ld a,e ;
- call hexout_a ;
- trailer: ld a,'h' ;
- number_ext equ $-1 ; initially 'h'
- jr akku_out ;
-
- hexout_a: push af ;
- rra ;
- rra ;
- rra ;
- rra ;
- call nib_out ;
- pop af ;
- nib_out: and 0fh ;
- add a,'0' ;
- cp '9'+1 ;
- jr c,akku_out ;
- add a,7 ;
- akku_out: push de ;
- push hl ;
- ld e,a ;
- bdos console_out ;
- pop hl ;
- pop de ;
- ret ;
-
- crlf_out: ld a,cr ; HL, DE gerettet
- call akku_out ;
- ld a,lf ;
- jr akku_out ;
-
- tab_out: ld a,tab ; HL, DE gerettet
- jr akku_out ;
-
- ;******************************************************************************
- ;* *
- ;* Verwaltung der GLOBAL-Listen *
- ;* *
- ;******************************************************************************
-
- ;******************************************************************************
- ;* *
- ;* Format der Listen im Speicher: *
- ;* *
- ;* 1) Globals/Undefineds: *
- ;* +-----------+------------+-------------+------------------------+ *
- ;* ! next (16) ! length (8) ! name (var.) ! USERvalue or list (16) ! *
- ;* +-----------+------------+-------------+------------------------+ *
- ;* *
- ;* 2) COMMONs: *
- ;* +-----------+------------+-------------+------------+-----------+ *
- ;* ! next (16) ! length (8) ! name (var.) ! Start (16) ! Size (16) ! *
- ;* +-----------+------------+-------------+------------+-----------+ *
- ;* *
- ;* 3) REQUESTs *
- ;* +-----------+------------+-------------+ *
- ;* ! next (16) ! length (8) ! name (var.) ! *
- ;* +-----------+------------+-------------+ *
- ;* *
- ;* 4) External + Offsets *
- ;* +-----------+--------------------+-------------+ *
- ;* ! next (16) ! REAL location (16) ! offset (16) ! *
- ;* +-----------+--------------------+-------------+ *
- ;* *
- ;******************************************************************************
-
- search_common: ld hl,list_commons ;
- jr search.1 ;
- search_request: ld hl,list_requests ;
- jr search.1 ;
- search_global: ld hl,list_globals ;
- jr search.1 ;
-
- try_next.1: pop hl ;
- search.1: ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- ld a,d ;
- or e ;
- jr z,append_name.1 ;
- push de ; address of new
- inc de ;
- inc de ;
- ld a,(de) ; type of new
- ld c,a ;
- and 0fh ; length ausmaskieren
- ld hl,B_field ;
- cp (hl) ; length same?
- jr nz,try_next.1 ;
- ld b,a ;
- inc de ;
- compare.1: inc hl ;
- ld a,(de) ;
- sub (hl) ;
- jr c,try_next.1 ;
- jr nz,insert_name.1 ;
- inc de ;
- djnz compare.1 ;
- ex de,hl ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- pop hl ; HL = addr, DE = value
- ret ; Z-Flag, A=00, B=00, C=type, HL=address,
- ; DE=value
- insert_name.1: pop hl ;
- db 3eh ; ld a,..
- append_name.1: dec hl ; zeigt auf &0
- or 0ffh ;
- ret ;
-
- ;
-
- get_end: ld e,(hl)
- inc hl
- ld d,(hl)
- ld a,d
- or e
- ret z
- ex de,hl
- jr get_end
-
- find_request: call search_request ;
- ret z ;
- call get_end ;
- dec hl ;
- xor a ;
- ld (offset),a ;
- push hl ; & new
- push de ; 0
- jp append_name.2 ;
- ;
-
- find_global: ld hl,list_globals ;
- ld a,2 ;
- ld (offset),a ;
- jr search.2 ;
- find_common: ld hl,list_commons ;
- ld a,4 ;
- ld (offset),a ;
- jr search.2 ;
-
- try_next.2: pop hl ;
- pop de ;
- search.2: push hl ; address of old field
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- ld a,d ;
- or e ;
- push de ; address of new
- jr z,append_name.2 ;
- inc de ;
- inc de ;
- ld a,(de) ; type of new
- ld c,a ;
- and 0fh ; length ausmaskieren
- ld hl,B_field+1 ;
- ld b,a ;
- inc de ;
- compare.2: ld a,(de) ;
- sub (hl) ;
- jr c,try_next.2 ;
- jr nz,insert_name.2 ;
- inc hl ;
- inc de ;
- djnz compare.2 ;
- cp (hl) ; Ende?
- jr nz,try_next.2 ; der in der Liste ist k}rzer
- ex de,hl ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- pop hl ;
- ex af,af' ;
- pop af ;
- ex af,af' ;
- ret ; Z-Flag, A=00, B=00, C=type, HL=address,
- ; DE=value
- insert_name.2: ;
- append_name.2: ; ld a,(B_field)
- ; add a,5 ; NC, I suppose
- ; ld c,a
- ; ld b,0
- ; ld hl,(top_of_mem)
- ; sbc hl,bc
- ; ld (top_of_mem),hl
- ; ex de,hl
- ; ld hl,searchfield
- ; ldir
- ld hl,B_field ;
- ld a,(hl) ;
- add a,2 ;
- offset equ $-1 ; weil COMMON 2 mehr braucht,
- ld c,a ; REQUEST gar keinen
- ld b,0 ;
- add hl,bc ;
- add a,3 ;
- ld c,a ;
- ld de,(top_of_mem) ;
- ld (later),de ;
- lddr ;
- ld (top_of_mem),de ;
- ld hl,(top_load) ;
- sbc hl,de ; NC!!!
- jp nc,e_nomem ;
- ex de,hl ; HL := top of mem
- pop de ; new (first too big)
- inc hl ;
- ld (hl),e ;
- inc hl ;
- ld (hl),d ; store pointer to next
- dec hl ;
- ex de,hl ; DE := pointer to new
- pop hl ; HL := pointer to old
- ld (hl),e ;
- inc hl ;
- ld (hl),d ; BC = 0
- or 0ffh ; mark as new inserted
- ld hl,0 ; points to last byte of new entry
- later equ $-2 ; DE points to FIRST memory cell
- ret ; HL points to LAST memory cell
- ; of new element in list
-
- ;************************************************************************
- ;* ENDE Speicherverwaltung *
- ;************************************************************************
-
- ;************************************************************************
- ;* ANFANG Ausgaberoutinen *
- ;************************************************************************
-
- print_name: ld a,(hl) ;
- and 0fh ; nur L{nge nehmen
- ld e,a ; Z{hler 1
- ld d,a ; Z{hler 2
- l001: inc hl ;
- ld a,(hl) ;
- call akku_out ;
- dec d ;
- jr nz,l001 ;
- inc hl ;
- call tab_out ;
- ret ;
-
- print_mem_usage:print <cr,lf,"Memory usage:",cr,lf,"Program Start: ">
- ld de,103h ;
- call hexout_de ;
- print <cr,lf,"Program End: ">
- ld hl,(top_load) ;
- ld de,(prog_buf) ;
- dec d ;
- or a ;
- sbc hl,de ;
- ex de,hl ;
- call hexout_de ;
- ld hl,(prog_buf) ;
- ld a,(hl) ;
- or a ;
- jr z,end_info ;
- inc hl ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- print <cr,lf,"Entry Point: ">
- call hexout_de ;
- end_info: jp crlf_out ;
-
- print_requests: ld hl,list_requests ;
- rq_loop: ld e,(hl)
- inc hl
- ld d,(hl)
- ld a,d
- or e
- ret z
- print "REQUEST "
- ex de,hl
- push hl
- inc hl
- inc hl
- call print_name
- call crlf_out
- pop hl
- jr rq_loop
-
- print_commons: ld hl,list_commons ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- ld a,d ;
- or e ;
- ret z ; no commons => auch keine Titelzeile
-
- print <cr,lf,"Common block name",tab,"Start",tab,"Size",cr,lf>
- ex de,hl ;
-
- pr_commons_loop:ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- push de ; next (if exists)
- inc hl ; zeigt jetzt auf L{nge des Namens
- call print_name ;
- call tab_out ;
- call tab_out ;
-
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- call hexout_de ;
- call tab_out ;
-
- inc hl ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- call hexout_de ;
- call crlf_out ;
- pop hl ; n{chster COMMON
- ld a,h ;
- or l ;
- jr nz,pr_commons_loop ;
- ret ;
-
- text_globals: db cr,lf,'Defined Globals:',0
- text_undefineds:db cr,lf,'Undefined Globals:',0;
-
- advance: ld a,0 ;
- spalten_counter equ $-1 ;
- or a ;
- jr nz,not_first ;
- push hl ;
- ld hl,0 ;
- text_1 equ $-2 ;
- call txtout ;
- pop hl ;
- ld a,1 ;
- not_first: dec a ;
- jr nz,tab_only ;
- call crlf_out ;
- ld a,3 ;
- ld (spalten_counter),a ;
- ret ;
-
- tab_only: ld (spalten_counter),a ;
- jp tab_out ;
-
- print_undefds: ld hl,text_undefineds ;
- ld a,80h ;
- jr intro.1 ;
- print_globals: ld hl,text_globals ;
- xor a ;
- intro.1: ld (text_1),hl ;
- ld (modebyte),a ;
- ld hl,(list_globals) ;
- xor a ;
- ld (spalten_counter),a ;
- ex de,hl ;
-
- next_global: ex de,hl ;
- ld a,h ;
- or l ;
- jr z,ende_globals ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- inc hl ;
- ld a,(hl) ;
- xor 0 ;
- modebyte equ $-1 ;
- jp m,next_global ; weil falscher Typ
- push de ; next Global
- call advance ;
- call print_name ;
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- call hexout_de ;
- pop de ;
- jr next_global ;
-
- ende_globals: call crlf_out ;
- ret ;
-
- list_defineds: ld (txt_ptr),hl ;
- call print_mem_usage ;
- call print_commons ;
- call print_globals ;
- .intro: call print_undefds ;
- call print_requests ;
- call crlf_out ;
- jp main_loop ;
-
- list_undefineds:ld (txt_ptr),hl ;
- call print_mem_usage ;
- jr .intro ;
-
- name_outfile: ld (txt_ptr),hl ;
- ld hl,user_fcb ;
- ld de,out_fcb ;
- ld bc,24h ;
- ldir ;
- ld hl,out_fcb+9 ;
- ld a,(hl) ;
- or a ; Extent given?
- jr nz,has_out_ext ;
- ld (hl),'C' ;
- inc hl ;
- ld (hl),'O' ;
- inc hl ;
- ld (hl),'M' ;
-
- has_out_ext: jp main_loop ;
-
- dseg ;
- out_fcb: db 0,' ' ;
- ds 24h-12,0 ;
- cseg ;
-
- save_object: ld a,(out_fcb+1) ;
- cp ' ' ;
- jr z,no_name_err ;
- call satisfy_request ; any requests?
- call set_offsets ;
- call set_$memry ;
- call print_undefds ;
- call print_mem_usage ;
-
- write_file: bdos delete_file,out_fcb;
- bdos make_file,out_fcb ;
- cp 4 ;
- jr nc,creation_err ;
- ld de,(prog_buf) ;
- write_loop: push de ;
- bdos set_dma_addr ;
- bdos write_seq,out_fcb ;
- or a ;
- jr nz,write_err ;
- pop de ;
- ld hl,80h ;
- add hl,de ;
- ex de,hl ;
- ld hl,(top_load) ;
- scf ;
- sbc hl,de ;
- jr nc,write_loop ;
- bdos close_file,out_fcb ;
- jp 0 ;
- write_err: print <"Disk full",cr,lf>
- jp abbruch ;
- creation_err: print <"Can't create object file",cr,lf>
- jp abbruch ;
- no_name_err: print <"No filename to save.",cr,lf,"Exiting without saving.",cr,lf>
- jp 0 ;
-
- set_offsets: ld hl,(list_explus) ;
-
- set_offsets_loop:ld a,h ;
- or l ;
- ret z ; Ende der Liste
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ;
- inc hl ;
- push de ;
-
- ld e,(hl) ;
- inc hl ;
- ld d,(hl) ; DE := REAL address
- inc hl ;
- ld a,(de) ;
- add a,(hl) ; correct lowbyte
- ld (de),a ;
- inc hl ;
- inc de ;
- ld a,(de) ;
- adc a,(hl) ; correct highbyte
- ld (de),a ;
-
- pop hl ;
- jr set_offsets_loop ;
-
- dseg ;
- memry_global: db 6,'$MEMRY',0 ;
- cseg ;
-
- set_$memry: ld hl,memry_global ;
- ld de,B_field ;
- ld bc,8 ;
- ldir ;
- call search_global ;
- ret nz ; not found
- inc hl ;
- inc hl ;
- bit 7,(hl) ; undefined?
- ret nz ;
- ld bc,(prog_buf) ;
- dec b ; BC := REAL(0000h)
- ld hl,(top_load) ;
- or a ;
- sbc hl,bc ; minus NULL = USER top_load
- ex de,hl ; HL := USER address
- add hl,bc ; HL := REAL address
- ld (hl),e ;
- inc hl ;
- ld (hl),d ;
- ret ;
-
- search_library: ld (txt_ptr),hl ;
- call search_lib ;
- jp main_loop ;
-
- search_lib: call open_relfile ;
-
- check_module: ld a,(bytecnt) ; save position in file
- ld de,save_fcb ;
- ld hl,rel_fcb ;
- ld bc,24h+80h ;
- ldir ;
- ld (de),a ;
- ld a,0ffh ;
- ld (relcnt),a ; setze auf Byte-Grenze
- skip_loop: call getbit ;
- jr nc,skip_8 ;
- ld a,2 ;
- call get_abits ;
- jr nz,skip_16 ;
- ld a,4 ;
- call get_abits ;
- cp 15 ; End of file?
- ret z ;
- push af ; type
- sub 5 ; 5 - 14 hat A-field
- cp 10 ;
- call c,get_A_field ;
- pop af ;
- push af ;
- cp 9 ;
- call c,get_B_field ;
- pop af ;
- cp 14 ; end of module?
- jr z,check_module ; (the next one)
- or a ; Entry symbol?
- jr nz,skip_loop ;
- call search_global ;
- jr nz,skip_loop ; Name nicht bekannt
- inc hl ;
- inc hl ;
- bit 7,(hl) ; defined?
- jr z,skip_loop ; yes!
- jr load_this ;
- skip_16: ld a,8 ;
- call get_abits ;
- skip_8: ld a,8 ;
- call get_abits ;
- jr skip_loop ;
-
- load_this: ld hl,save_fcb ; restore old position in FCB
- ld de,rel_fcb ;
- ld bc,24h+80h ;
- ldir ;
- ld a,(hl) ; bytecnt
- ld (bytecnt),a ;
- call load_module ;
- or a ;
- jp nz,abbruch ;
- jr check_module ;
-
- dseg ;
- save_fcb: ds 25h+080h,0 ; and save Buffer
- cseg ;
-
- satisfy_request:ld hl,(list_requests) ;
- ld a,l
- or h ; no request?
- ret z
- ld hl,(list_globals) ;
- try_if_undef: ld a,l
- or h
- ret z ; no undefined global found, don't search
- ld e,(hl)
- inc hl
- ld d,(hl)
- inc hl
- bit 7,(hl)
- ex de,hl
- jr z,try_if_undef ; dieser ist definiert
-
- print "Searching "
- ld hl,blank_fcb ; found undefined global
- ld de,user_fcb
- ld bc,24h
- ldir
- ld hl,(list_requests) ;
- ld e,(hl)
- inc hl
- ld d,(hl)
- ld (list_requests),de ; next request
- inc hl
- push hl
- ld c,(hl)
- inc hl
- ld de,user_fcb+1
- ldir
- pop hl
- call print_name
- call crlf_out
- call search_lib
- jr satisfy_request
- end entry ;