; OSBORNE EXECUTIVE - Screen Dump Utility ; ; - written Dec'84 by Mark Steinbrecher ; (with help from Dave Mabry) ; ; This is an RSX to print the screen on an Osborne Executive rsx equ 60 ; BDOS RSX function call cr equ 0dh ; ASCII carriage return character lf equ 0ah ; ASCII line feed character freeram equ 0fb20h ; Address of unused common memory ; for new conin serial: ds 6 ; Initialized by loader start: jmp begin ; Start of RSX code next: db 0c3h ; Jump instruction ds 2 ; Initialized by loader prev: ds 2 ; Initialized by loader remove: db 0 ; Don't remove nonbank: db 0 ; Load in all systems db 'dump ' ; Name field loader: ds 1 ; Loader flag ds 2 ; Reserved ; Here starts the code that is executed by a call to BDOS with ; RSX function number in C. begin: mov a,c ; Get BDOS function number cpi rsx ; Is it for an RSX ? jnz next ; No, pass it on ldax d ; Get RSX function number cpi 53 ; Is it for this RSX ? jnz next ; No, pass it on ; Must save calling program's stack and use our owm lxi h,0 dad sp shld stack lxi sp,stack ; Does calling program want us to remove ourself ? mov h,d mov l,e ;HL point to rsxpb inx h inx h ;Point to param1 mov a,m ;Fetch it ora a ;Nonzero means remove jz beg05 ;Zero means initialize call next ;In case there is another DUMP RSX jmp die ;Suicide ; Check to see if we are the only DUMP RSX in memory beg05: call next ;As if we are calling DUMP ora a ;Returns zero if there is another jz die05 ;Suicide if another exists xchg ;HL point to RSX parameter block inx h inx h ;Point to parameter 1 mov a,m ;Get low byte ora a ;Check for zero jnz die ;If not binary 0, then suicide inx h ;Point to trigger passed in mov a,m sta trigger ; At this point, we have to initialize the RSX code to intercept ; all console input calls. ; But only if we haven't done it before. lda modified ora a jnz return ;Bypass vector modification if done lhld 1 ;Get warm boot vector lxi d,7 dad d ;Point to console in vector address shld conin$adr ;Save for die also push h ;save temporarily mov a,m ;get low byte of conin vector address inx h ;point to high byte mov h,m ;get high byte of conin vector address mov l,a ;hl reg now has conin address shld old$conin ;store locally call patch ;move patch code into unused BIOS ram lxi d,freeram ;new console address to DE pop h ;again point to conin vector in BIOS mov m,e ;move low byte of unused BIOS ram address inx h ;point to high byte of vector mov m,d ;conin in vector is now patched ! ; Now get the list out routine address in case application program ; modifies location 1 (warm boot vector). SuperCalc does this ; and maybe others. lhld 1 ;Address of BIOS jump table lxi d,13 ;Offset to address of list output dad d mov a,m ;Low byte of list out address inx h mov h,m ;High byte mov l,a shld l$out ;save address ; Indicate that the console in has been modified. mvi a,0ffh ;Set modified flag sta modified return: lhld stack ;get old stack address sphl ;restore mvi a,0 ;Indicate success ret ;rsx initialization complete die: lda modified ;Have we modified the BIOS jump table ? ora a jz die05 ;No, then just die lhld old$conin ;Get original address of CONIN xchg ; to DE lhld conin$adr ;Point to address field in jump table mov m,e ;Restore original jump address inx h mov m,d die05: mvi a,0ffh ;True flag sta remove ;Flag removal at next warm boot jmp return patch: mvi b,length ;setup loop counter lxi h,freeram ;setup address pointer for relocated code lxi d,st$code ;setup address pointer for local code loop: ldax d mov m,a inx h inx d dcr b jnz loop ret ; ; The code that follows is relocated to address in common ; memory by . Address is patched into the conin ; vector in the BIOS jump table so that all further console inputs ; pass through this routine. st$code: in 0 ;get current bank push psw ;save temporarily mvi a,41h ;setup bank 1 (TPA bank) out 0 ;enable TPA call new$conin ;vector to console input patch mov b,a ;move console char. to B temporarily pop psw ;get old bank back out 0 ;enable old bank mov a,b ;put console char. back in A ret ;ret with console character in A ; length equ $-st$code ; old: lhld old$conin pchl ; new$conin: push h lxi h,0 ;Use a local stack dad sp shld stack lxi sp,stack call old ;Go get character push psw ;Save status lxi h,trigger ;Compare with the trigger character cmp m ;Is it the same ? cz doit ;Go dump screen if yes pop psw ;Else pass it by lhld stack sphl pop h ret doit: lxi h,0c000h ;point to start of screen ram lxi b,5018h ;set up row and column counters next$row: push b ;save row and column counts next$col: mov a,m ;get next char. from screen ani 7fh ;strip attribute bit cpi 20h ;check for valid ASCII character cm bad mov c,a push h ;save pointer push b call list$out ;print character pop b pop h inx h ;point to next character dcr b ;decrement column counter jnz next$col ;if not zero continue mvi c,lf ;row finished so print a crlf push h call list$out mvi c,cr call list$out pop h ;recall screen ram pointer pop b ;recall row count & reset col. counter dcr c ;decrement row counter rz ;if row count=0, we're done lxi d,30h ;row to row address offset dad d ;not done so point to next row jmp next$row ; bad: mvi a,20h ;replace nonprintable char. with space ret ; list$out: lhld l$out ;Get address of list out routine pchl ;Go do it modified: db 0 ;True -> BIOS jump table modified trigger: ds 1 ;Place to store trigger character l$out: ds 2 ;Place to store address of list out old$conin: ds 2 ;Place to store address of old conin conin$adr: ds 2 ;Place to store address of jump vector ; of CONIN in BIOS jump table ds 30 stack: ds 2 ;Place to save original stack end