; TOON12.ASM ;A screen dump program: puts a watchdog between ;the conin jmp and CONIN itself, which simply passes ;along normal chars, but writes the screen to disk ;when it detects ^_. The screen is written by ;bank-switching to video memory through rdvid, ;which alters the bank switch bit from the system ;port to read bank 1 memory (video memory + prom) ;directly. If TOON, the carTOON file for screens, ;already exists, the new screen is added on the end. ; ;In version 1.1, the sub-CCP address in high memory ;where TOON goes is hard coded, but the BDOS jump ;is altered by TOON to point to TOON's lowest addr. ;The TOON watchdog's first location is then a jump ;to the original entry point in the BDOS. Therefore, ;load TOON first, and later programs can adjust ;their use of the TPA using the altered BDOS addr. ; ;Version 1.2 adds the deletion of space chars in ;the 80th column to clean up display on 80 char ;screens, and other minor changes. ; v1.2 ;(c)June, 1985 ;Mike Yarus * 2231 16th Street * Boulder, CO 80302 ; ;TOON.ASM, TOON.COM, and TOON.DOC are released into ;the public domain, and may be used freely for any ;non-commercial purpose. They may not be sold or ;used to enhance the value of another product ;without the permission of the author. ; ; bdos equ 0005h wmboot equ 0000h cr equ 0Dh lf equ 0Ah eof equ 1Ah ; ;the following equate is for the conin bios addr ;and the original bdos jump address ; ;a dummy address (= 0000) dmmy$ad equ wmboot ;to hold a place for real ;address written at run time ; ;equates for the move into high memory ; offs equ 280h ;distance below ccp to load ccp equ 0E400h ;bios-1600h=ccp start, std 64k newstrt equ ccp-offs;new start, offs-et below ccp ; org 0100h ; ;get the bdos address and store it at bottom of dump ; lhld 0006h ;load bdos jmp addr shld bds$trgt+1 ;store at new site lxi h,newstrt ;get bottom of dump shld 0006h ;redirect bdos jmp to dump ; ;get the address of the bios ; lhld 0001h ;load bios + 3 dcx h dcx h dcx h ;hl -> bios address shld bios ;store start of bios jumps ; ;find the phrase "Warm Boot" ; lxi d,0004h ;offset to warm boot address dad d ;hl points to warmst addr call getwd ;warmst routine addr -> hl ; mvi c,'W' ;search for 'W' call find0 ;begin at warmbt routine ; lxi d,newmsg;address in hl from find call fill0 ;overwrite "Warm Boot" ; ;redirect the conin jump in the bios ; lhld bios ;load addr of bios lxi d,000ah ;offset to conin addr addr dad d ;addr of conin routine addr shld cinadd ;store it, must overwrite call getwd ;conin address into hl shld conin ;store address of conin routine ; lhld cinadd ;addr of conin addr lxi d,dump ;addr of dump in de call putwd ;alter conout addr to dump addr ; ;write in the calculated address of the conin routine ; lhld conin ;load conin addr xchg ;conin addr-> de lxi h,cin$trgt+1 ;addr for call to conin call putwd ;write addr in de to hl ; jmp launch0 ;move the business end under ccp ; ;fills memory at h with string stored at d, term by $ ;used to fill open memory at fixed, dedicated location ; fill0 mvi c,'$' ldax d ;get char into a cmp c ;is the new char the end char? rz ;if so, have done string mov m,a ;if not, store next char ; inx d inx h ;increment both string counters jmp fill0 ; ;find the character in c after the address supplied in h ;returns the address of the char in h ; find0 mov a,m ;get char in a cmp c ;is it the target char? rz ;char found, address in h inx h ;inc address and jmp find0 ;get the next char ; ;get word at addr in hl into hl: orig addr + 1 -> de ; getwd mov a,m ;get low order byte mov e,a ;move to e inx h ;reset for high order byte mov a,m ;get it in a mov d,a ;put high order byte in d xchg ;exchange number and address ret ; ;put word in de to address in hl ; putwd mov a,e ;lsb to a mov m,a ;lsb to address in hl inx h ;address for msb mov a,d ;msb to a mov m,a ;msb to address ret ; ;the routine to move the code below it to high memory ; launch0 lxi b,endmv-begin+1 ;bytes to move lxi d,begin ;start addr for move lxi h,newstrt ;new start after move ; launch ldax d ;get a char from lo mem mov m,a ;put char in high mem inx d ;increment lo addr inx h ;increment hi mem addr dcx b ;decrement # bytes to move ; mov a,b ;test if b&c = 0 ora c ;a&c = 0? jnz launch ;no, get another byte ; ret ;done, back to cpm ; newmsg db 'Toon = ^_$' bios ds 2 ;addr of bios jump table cinadd ds 2 ;addr of conout jmp addr conin ds 2 ;addr of the conout routine ; ;***************** all below is moved ***************** begin equ $ ; distnce equ newstrt-begin ;hi mem addr - lo mem ; ;redirect the bdos jmp to its original address ; bds$trgt jmp dmmy$ad ;bdos addr at run time ; ;and now, the dump routine,... ; dump equ $+distnce ;<<< entry, high mem cin$trgt ;conin address target call dmmy$ad ;addr put in at run time mvi c,1fh ;ctrl underline, ^_ cmp c ;compare to char in c jz dmpfl ;if ^_, go to routine ret ;otherwise just return ; ;open a file, put something in it after the end of the ;last entry, then close it, OK? ; ;row and col must be initialized for each screen written ; dmpfl equ $+distnce mvi a,1 sta col ;col = 1 sta row ;row = 1 ; ;set up a local stack ; lxi h,0 ;clear hl dad sp ;sp -> hl shld cpmstk ;store original stack pointer lxi sp,locstk ;new top of stack ; ;define new dma ; mvi c,1ah lxi d,dma ;use the equate call bdos ; ;initialize address for next write to dma ; lxi h,dma ;start of dma shld dmaddr ;start at first addr in dma ; ;prepare the filename in the FCB ; lxi h,fcb+1 ;destination, for fill lxi d,flnm ;string address, for fill call fill ;put filename in fcb ; ;open or make file, go to end of a previous file ; openf equ $+distnce mvi c,0fh ;open file lxi d,fcb call bdos ;A = 0,1,2,3, or ffh cpi 0ffh jnz empty ;is a file, test & find end makef equ $+distnce ;req'd for era'd Toon lxi d,filler ;string of 0's lxi h,fcb+0Ch ;put them after fname call fill ;zero the fcb ; mvi c,16h ;make file via bdos lxi d,fcb call bdos jmp scrloop ;skip search to end of file ; ;find end record of file ; fend equ $+distnce mvi c,14h ;read sequential lxi d,fcb call bdos ;a=0 if read successful ori 0 jz fend ;not at end, read again ; ;reset the record number, delete the ^Z at eof ; deleof equ $+distnce lda fcb+20h ;the current record number dcr a ;back to last record sta fcb+20h ;put decremented cr back call rdseq ;last rec-> dma: advances rec #! lda fcb+20h ;the current record number dcr a ;back to last record sta fcb+20h ;decremented cr, can rewrite ; ;find the eof and overwrite it ; mvi c,1ah ;eof in c lxi h,dma ;address for search call find ;returns addr of char in c in h shld dmaddr ;store active address in dma jmp scrloop ;append new text to end of file ; ;measure out a screenfull, write byte by byte from video ; scrloop equ $+distnce ; lda col ;get col, set up to read video mov c,a ;col into c mvi b,0 ;zero out b push b ;onto stack lda row ;get row mov c,a ;row into c mvi b,0 ;zero b push b ;onto stack call rdvid ;return onto stack, get char! ; ;process the char from video memory, returned in c ; lhld dmaddr call dmaout ;char in c, dmaddr in hl lda col ;get current column inr a ;increment col, note col -> 81 sta col ;restore col mvi d,81 ;test, last col? cmp d ;compare to col jnz scrloop ;if 80th not written, next col ; lda row ;row -> a mov d,a ;row -> d lda col ;col -> a add d ;col + row in a cpi 105 ;done? col + row = 105 jz endf ;yes, done with screen ; inr d ;no, increment row mov a,d ;row + 1 -> a sta row ;restore row call eoln ;put in crlf mvi a,1 sta col ;col -> 1 for new row jmp scrloop ;fill next col ; ;read the next record ; rdseq equ $+distnce mvi c,14h ;read sequential lxi d,fcb call bdos ret ;done, go back ; ;write the dma to current record ; wrtseq equ $+distnce mvi c,15h ;write sequential lxi d,fcb call bdos ret ;end ; ;close file ; clsfl equ $+distnce mvi c,10h ;close file lxi d,fcb call bdos ret ;done ; ;test to see if ex=rc=0, eg, empty Toon ; empty equ $+distnce ;test for empty Toon ;and delete, if so lda fcb+0Fh ;load the # rec in extent mov b,a ;curr record to b lda fcb+0Ch ;locd curr extent to a ora b ;rec & extent 0? jnz fend ;not empty, find end ; ;erase file ; erafl equ $+distnce ;erase empty file mvi c,13h ;bdos erase file lxi d,fcb call bdos jmp makef ;now make new file ; ;fills memory at h with string stored at d, term by $ ;used to fill open memory at fixed, dedicated location ; fill equ $+distnce mvi c,'$' ldax d ;get char into a cmp c ;is the new char the end char? rz ;if so, have done string mov m,a ;if not, store next char ; inx d inx h ;increment both string counters jmp fill ; ;find the character in c after the address supplied in h ;returns the address of the char in h ; find equ $+distnce mov a,m ;get char in a cmp c ;is it the target char? rz ;char found, address in h inx h ;inc address and jmp find ;get the next char ; ;write to dma from c, which has char ;dmaddr is in hl ; dmaout equ $+distnce call ckdma ;decides to write when dma full mov m,c ;byte -> dma call incr ;increment dmaddr ret ;done ; ;dma full? yes->reset and restart dma ;gets and returns current char in c, dmaddr in hl ; ckdma equ $+distnce lxi d,dma+80h ;get dma end+1 mov a,e ;lsb of dma end in a cmp l ;at end of dma? rnz ;ret if not done yet ; push b ;save char call wrtseq ;full dma, write it pop b ;get char back lxi h,dma ;reset dmaddr shld dmaddr ;store dmaddr ret ;done ; ;increment the address for current write to dma ; incr equ $+distnce lhld dmaddr ;load next write addr inx h ;+ 1 shld dmaddr ;restore incr addr ret ;done ; ;writes crlf after every 80 screen chars ;deletes blank at eoln to make 79 char lines ;in order to inprove screen appearance ; eoln equ $+distnce lhld dmaddr ;get next location dcx h ;last written char mov a,m ;get the char cpi 20h ;was it a blank? jnz eoln1 ;no, terminate line shld dmaddr ;yes, update address jmp eoln2 ;cr & lf ; eoln1 equ $+distnce inx h ;skip non-blank eoln2 equ $+distnce mvi c,cr call dmaout ;check address in hl mvi c,lf call dmaout ;check address in hl ret ; ;puts in last section of file, eof,...Note that ;in general, would have to worry about hitting ;record end during eorec, but a screenful will ;usually end within a record ; endf equ $+distnce call eoln ;cr & lf lxi d,eorec ;addr of string for fill lhld dmaddr ;fill here call fill ;with some eof's call wrtseq ;write the last dma call clsfl ;close file ; lhld cpmstk ;replace the orig stack ptr sphl ;hl -> sp ret ; ;################ MACHINE DEPENDENT ################# ; vvvvvvv vvvvvvvvv ; ;this routine switches from normal memory (bank 0) to ;video memory and prom (bank 1). it reads one char at ;the address calculated for the screen col and row ;supplied on the stack when rdvid is called, then ;returns that char in register c ; ;reset for input from bank 1, video memory and prom ; rdvid equ $+distnce in 1Ch ;get system byte from the Z80 ori 80h ;force msb -> 1 for bank one out 1Ch ;set port ; ;stack on entry: rtn addr,row,col ; pop h ;get rtn addr pop b ;row in BC pop d ;column in DE push h ;restore rtn addr ; ;calculate the address in video mem ; lxi h,3000h ;set up hl mov a,c ;move row -> A mvi c,80h ;BC = 0080, note B=00 assumed ; ;multiplication routine to get (row-1)*80h ; rowx equ $+distnce dcr a ;row-1 jz donex ;through multiplying ? dad b ;addr + 80h jnz rowx ;not yet HL=3000h+(row-1)*80h ;uses flag from dcr ; donex equ $+distnce dcx d ;col-1 dad d ;addr+(col-1) in HL ; mov c,m ;get the byte from memory in c ; ;reset for bank 0 memory ; in 1Ch ;get system byte xri 80h ;msb -> 0, bank zero out 1Ch ;set it ; ret ;end of rdvid ; ; ^^^^^^^ ^^^^^^^^^ ;################ MACHINE DEPENDENT ################ ; flnm equ $+distnce db 'TOON $' eorec equ $+distnce db eof,eof,eof,eof,'$' dmaddr equ $+distnce ds 2 ;address of next write to dma row equ $+distnce ds 1 ;current screen column, 1->80 col equ $+distnce ds 1 ;current screen row,1->24 filler equ $+distnce db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,'$' ;used to reinit fcb fcb equ $+distnce db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;36 bytes init to 0 dma equ $+distnce ds 128 ;space for sector buffer ds 32 ;local stack locstk equ $+distnce-1 ;top of stack cpmstk equ $+distnce ds 2 ;cpm's stack pointer on entry ; endmv equ $