title 'MOKE Monitor' ;---------------------------------------------------------------- ; Monitor Program For Tony's MOKE Board ; ; Written by Richard Holmes 22-07-87 ; Last Update by Richard Holmes 17-03-89 ; ; Added hooks for external interrupt handlers 20-02-88 ; Started timer 1 (second) at 50ms ticks 15-03-88 ; Setup push/pop of registers for int1 and int2 16-03-88 ; Make 'Q' command halt CPU to generate a RESET wdog 12-05-88 ; Make into "moke" version 17-03-89 ;---------------------------------------------------------------- ; maclib hdz80 maclib mokemap ; extrn exec ; Executive interface extrn con$hdlr, aux$hdlr extrn tmr0$hdlr,tmr1$hdlr extrn int0$hdlr,int1$hdlr extrn int2$hdlr,csio$hdlr ; extrn ext$ldr ; External code loader ; public reset,caps extrn con$inp,con$out,con$ist ; extrn aux$ist extrn aux$out,aux$inp extrn aux$ird,aux$iwr, aux$ost extrn prn$out ; ram$siz equ 2048 ; Bytes in ram rom$siz equ 8192 ; Bytes in rom cks$siz equ rom$siz - 4 ; Bytes to checksum cks$loc equ rom$siz - 4 ; Location of stored checksum ; pgm equ 02000h ; Base of "in-rom" programs ; ; true equ 0ffffh false equ not true ; hd64180 equ true ; t0$cnt equ 3072 ; 10 ms ticks. t1$cnt equ 3072 * 5 ; 50 ms ticks. ; cpos1 equ 01bh ; Cursor positioning lead in code cpos2 equ '=' offset equ 020h ; Offset for vdu cursor positioioning cscrn equ 01ah ; Clear screen code stk$siz equ 256 ; Size of stack area in levels ; cr equ 0dh lf equ 0ah esc equ 01bh ; ;---------------------------------------------------------------- ; ---- Start of program ---- ; ; Location 0. ;---------------------------------------------------------------- ; reset: jmp monitor ; jmp warm ; Warm start system here ; ;---------------------------------------------------------------- ; This is the main restart entry point to allow software to ; call the exec processor with just a restart 1 instruction. ;---------------------------------------------------------------- ; org 8 ; Restart 1 jmp exec ; To the exec procedure ; org 010h ; Restart 2 mvi a,'2' call coe ret ; org 018h ; Restart 3 mvi a,'3' call coe ret ; org 020h ; Restart 4 mvi a,'4' call coe ret ; org 028h ; Restart 5 mvi a,'5' call coe ret ; org 030h ; Restart 6 mvi a,'6' call coe ret ; org 038h ; Restart 7 mvi a,'7' call coe ret ; org 040h ; Restart 8 mvi a,'8' call coe ret ; ;---------------------------------------------------------------- ; Non-maskable interrupt handler. Reset the processor so that ; the MLU will know about it. ;---------------------------------------------------------------- ; org 66h in wdt ; Stop the watchdog. ; ; Delay while power drops a little more mvi b,0 hl$lp: in wdt djnz hl$lp ; ; Stop cpu dead in tracks. hlt ; page ;================================================================ ; Internal Interrupt table. This is used for all internal ; interrupts and contains the address of all the drivers. ;================================================================ ; org 100h ; Requires 100h byte (=1 page) boundaries ; int$tbl: dw drv$int1 ; 0. Driver. INT1 pin dw drv$int2 ; 2. Driver. INT2 pin dw drv$tmr0 ; 4. Driver. Timer 0 dw drv$tmr1 ; 6. Driver. Timer 1 dw drv$dma0 ; 8. Driver. DMA Channel 0 dw drv$dma1 ; 10. Driver. DMA Channel 1 dw drv$csio ; 12. Driver. Clocked serial I/O dw drv$asci0 ; 14. Driver. Serial I/O channel 0 dw drv$asci1 ; 16. Driver. Serial I/O channel 1 ; ; ---- Driver code for these interrupts. ---- ; drv$int1: ; 0. Driver. INT1 pin push psw push h push b push d ; call int1$hdlr ; Use EXEC handler for this ei ; Re-allow interrupts NOW ; pop d pop b pop h pop psw ret ; ; drv$int2: ; 2. Driver. INT2 pin push psw push h push b push d ; call int2$hdlr ei ; pop d pop b pop h pop psw ret ; ; Timer 0 interrupt serivce routine. ; drv$tmr0: ; 4. Driver. Timer 0 push psw ; Re-enable interrupts here to allow others in. ino a,tcr ; Clear internal TIFO ino a,tmdr0l ei ; This is a low priority task. Allow others in. ; ; push h push b push d ; call tmr0$hdlr ; Invoke exec handler ; pop d pop b pop h pop psw ret ; drv$tmr1: ; 6. Driver. Timer 1 push psw ; Re-enable interrupts here to allow others in. ino a,tcr ; Clear internal TIFO ino a,tmdr1l ei push h push b push d ; call tmr1$hdlr ; pop d pop b pop h ; pop psw ret ; drv$dma0: ; 8. Driver. DMA Channel 0 ei ret ; drv$dma1: ; 10. Driver. DMA Channel 1 ei ret ; drv$csio: ; 12. Driver. Clocked serial I/O jmp csio$hdlr ; drv$asci0: ; 14. Driver. Serial I/O channel 0 jmp aux$hdlr ; This is the AUX channel handler ; drv$asci1: ; 16. Driver. Serial I/O channel 1 jmp con$hdlr ; The CONsole handler ; ;---------------------------------------------------------------- ; Enable internal interrupts by setting the itc and interrupt ; vector table up. ;---------------------------------------------------------------- ; enable$int: di ; ; Setup vector table pointers lxi h,int$tbl ; -> interrupt table mov a,h stai ; Setup HIGH address of table ; mov a,l ; Table low 8 bits of address ani 1110$0000b ; Mask off grunge. Not really needed. outo il,a ; To interrupt low vector register ; ; Setup trap control register to allow int1 and int2 ; mvi a,0000$0110b ; Allow only INT1 and INT2 outo itc,a ; Send to register ; ei ret ; ;---------------------------------------------------------------- ; -- Start PRT0 ---- ;---------------------------------------------------------------- ; start$prt0: push h ; ; 1. Stop timer ino a,tcr ani 1111$1110b ; Stop timer 0 outo tcr,a ; ; 2. Load Reload and down count registers lxi h,t0$cnt ; timer 0 count value outo tmdr0l,l ; To decrement register low outo rldr0l,l ; To reload register low ; outo tmdr0h,h ; To decrement register high outo rldr0h,h ; To reload register high ; ; 3. Start timer ; ; Bit 4 = Enable interrupts ; 0 = Start counting ; ino a,tcr ; Read existing value ori 0001$0001b ; Re-start timer 0 outo tcr,a ; pop h ei ret ; ;---------------------------------------------------------------- ; ---- Read the first counter. Result in HL ---- ;---------------------------------------------------------------- ; read$prt0: ino l,tmdr0l ino h,tmdr0h ; Decrement register high ret ; ; ---- Stop the first counter ---- ; stop$prt0: di ino a,tcr ani 1110$1110b ; Stop the down counter. Interrupts off outo tcr,a ei ret ; ;---------------------------------------------------------------- ; ---- Start the second timer. ---- ;---------------------------------------------------------------- ; start$prt1: push h ; ; 1. Stop timer ino a,tcr ; Timer control register ani 1111$1101b ; Stop timer 1 outo tcr,a ; ; 2. Load Reload and down count registers lxi h,t1$cnt ; timer 0 count value outo tmdr1l,l ; To decrement register low outo rldr1l,l ; To reload register low ; outo tmdr1h,h ; To decrement register high outo rldr1h,h ; To reload register high ; ; 3. Start timer ; ; Bit 5 = Enable interrupts ; 1 = Start counting ; ino a,tcr ; Read existing value ori 0010$0010b ; Re-start timer 1 outo tcr,a ; pop h ret ; ;---------------------------------------------------------------- ; ---- Read the first counter. Result in HL ---- ;---------------------------------------------------------------- ; read$prt1: ino l,tmdr1l ; Decrement register low ino h,tmdr1h ; Decrement register high ret ; ; ---- Stop the second counter ---- ; stop$prt1: ino a,tcr ; Timer control register ani 1101$1101b ; Stop the down counter. Interrupts off outo tcr,a ret ; ;---------------------------------------------------------------- ; A Monitor program for the DINOS Keyboard ; ;---------------------------------------------------------------- ; monitor: in wdt ; ; lxi sp,stack ; lxi h,0 shld dump$lst ; xra a sta trp$flg ; Turn off trap flag in ram ; ; Check the trap. ino a,itc ; Interrupt trap control register ani 1000$0000b ; SET bit = a trap interrupt jrz not$trap ; ; Clear trap interrupt xra a out itc inr a sta trp$flg ; Flag a trap interrupt. ; ; not$trap: mvi c,0 ; Hardware reset rst 1 ; ...all hardware via the exec rom ; lda trp$flg ; Did we get a trap interrupt ? ora a ; 00 = not jrz not$trap1 ; and skip the message ; mvi c,9 ; Else on a tap, print the message rst 1 db 07,'Illegal Interrupt Trap',07,0 ; xra a sta trp$flg ; not$trap1: call clr$wdt lxi d,signon ; Go print the message call ptxt ; call clr$wdt ; call enable$int call start$prt0 ; Start timer 0 call start$prt1 ; Start timer 1 ; call clr$wdt ; ; Else check for a program at "pgm" and run it if there. lda pgm ; Get 1st byte of a program then cpi 0ffh ; There ? jnz pgm ; Jump to program if not 0ffh ; ; Warm1 is the restart address after all routines are finished. ; warm: lxi sp,stack call crlf ; lxi d,signon2 call ptxt ; Print the M> message call echo ; Get character and echo it ; cpi '@' ; Start of a CODE LOAD command ? jz code$load ; Process the command then ; cpi cr jrz warm cpi lf jrz warm cpi ' ' jrz warm cpi esc jrz warm ; ; Control A to reset cpu cpi 'A' and 01fh jz reset ; Reset ; mov c,a push b ; Save character call space ; Space across 1 call gaddr ; Get operands pop b mov a,c ; Restore first command lxi h,warm ; Save address of re-entry push h ; On stack lded opr1 ; Operand 1 ; ;**************************************************************** ;* Check key against table * ;**************************************************************** ; sui 'A' jc erdisp ; Incorrect command cpi 'Z'-'A'+1 ; Only A to Z allowed. jnc erdisp add a ; *2 push d ; Save it mov e,a mvi d,0 ; Index into table lxi h,jmptbl ; Table of routines dad d ; Point to it mov e,m inx h mov d,m xchg pop d ; Restore push h ; Load stack with routine address lhld opr2 ret ; To the routine ; page ; page ;---------------------------------------------------------------- ; Load code from an external machine into this one. ;---------------------------------------------------------------- ; code$load: call ext$ldr ; Call the external code loader jmp warm ; ;**************************************************************** ;* Display a ? for an error prompt * ;**************************************************************** ; erdisp: mvi a,'?' ; ? = illegal data call coe jmp warm ; Re-enter monitor ; ; ;******************************************************* ; Inline help screen. Pressing a '?' displays this lot * ;******************************************************* ; help: jmp warm ; ;**************************************************************** ; Display memory as if it were a page of text. Hex data is not * ; displayed, it is converted into a '.' to be comaptible with * ; the dump command. * ;**************************************************************** ; adump: lda opcnt ora a jz erdisp ; No operands cause an error cpi 1 ; 1 operand gives a screen full jrz scrnful ; Display from start to a finish. Start is in de, finish in hl call rngchk ; Check end is after the start lhld opr2 ; Re-load ending address if ok. adump1: push h ; Save ending address ldax d ; Get the character call makasc ; make it ascii into C call coe inx d ; Bump memory source address ora a ; Clear carry dsbc d ; Subtract current address from end pop h ; Restore the ending address jrnz adump1 ; When equal, next page is asked for ; ; Here we read the console for an escape or a space adwait: ; Wait for a legitimate ascii dump command call cie cpi esc jz warm cpi ' ' ; next K ? jrz adump2 cpi '^' ; Previous K ? jrz adump3 cpi '?' ; Do you want to know the address ?? jrnz adwait ; If not this then keep on waiting call prhl ; Print the current ending address jr adwait ; Wait on Norelle, all things come.... ; adump2: ; Add the standard screen display amount to the end address lxi b,1024 ; Dsiplay the next 1k dad b ; End address is now 1k on call crlf jr adump1 ; adump3: ; Display the previous k to the one on the screen ora a ; Clear carry lxi b,2048 ; A sort of double back up is required dsbc b ; HL & DE point to 2 k back push h pop d ; Copy end into start jr adump2 ; Load the new end address ; ; Here the user entered only one operand so he wants a standard screenfull scrnful: push d pop h ; Copy start address into end jr adump2 ; ;**************************************************************** ; Execute a program at an optional address * ;**************************************************************** ; go: lda opcnt ; See if operands entered ana a jrz go1 ; Use last given address sded temp8 go1: lhld temp8 pchl ; Start execution at the address ; ;**************************************************************** ;* Block move memory routine * ;**************************************************************** ; move: call rngchk ; See that end > start mov b,h mov c,l ; Bc = count of bytes xchg lded opr3 ; Get destination ora a dsbc d ; Check no everlay jrnc move2 ; Skip if likely lhld opr3 ; Get back dest dad b ; Add to byte count dcx h ; Less 1 mov d,h mov e,l ; Copy to de lhld opr2 ; Get end call clr$wdt lddr ; Fill backwards ret ; move2: lhld opr1 ; Forward block move ldir move1: ret ; ;**************************************************************** ;* This is the hexadecimal calculator * ;**************************************************************** ; hexad: push h dad d ; Add opr1 and opr2 mvi a,'+' ; Display sum call coe call prhl ; Display contents hl call space ; Space pop h ; Restore opr2 xchg ; Swap opr1 and opr2 ora a ; Clear flags dsbc d ; Subtract other way mvi a,'-' call coe ; Display difference jmp prhl ; ;**************************************************************** ;* Exam port contents * ;* cmd => i pp (x) where x means forever * ;**************************************************************** ; portin: ; Get the port number into C lda opr1 cpi 6 ; Aux port ? jz pin$aux ; mov c,a ; Save port number ; mvi b,0 ; Upper low to read internal/external inp a ; Read port cma mov e,a ; Ensure impossible value in E 1st time mvi d,0 ; Load count before a CR,LF ; lxi h,1 ; Default count into HL lda opcnt ; How many operands ; Specified opcode count ? cpi 2 ; 2 ? jrc porti1 ; Skip if less lhld opr2 ; Get operand 2 (no.Displays) ; ; First time round we need a heading porti1: call crlf mov a,c call phacc ; Display port no.+ space call space mvi a,'-' call coe ; ;---------------------------------------------------------------- ; Port input loop. Wait for a port change then display it. If ; decremented number of displays required = 0 then exit. ; ; -- Use registers as -- ; HL = count of items printed total ; D = count of items printed on a line 0..7 ; E = the previous port image ; C = port number ;---------------------------------------------------------------- ; portin$loop: call clr$wdt ; Clear watchdog mvi b,0 inp a ; cmp e jrz porti3 ; ; Else if not equal, display the new value ; mov e,a ; Save new value port image call space mov a,e call phacc ; Go display value inr d ; One more displayed mov a,d cpi 8 jrnz porti2 ; End of line, cr/lf and port address mvi d,0 call crlf mov a,c ; Port number call phacc ; Display port no.+ space call space mvi a,'-' call coe ; ; Decrement the HL count and if 0 then exit. porti2: dcx h mov a,l ora h ; Does H = L = 0 ???? rz ; Exit if end ; ; If port is same as previous image then come to this routine ; and check for an escape key. ; porti3: call cst jrz portin$loop call cie cpi esc jrnz portin$loop ret ; ;---------------------------------------------------------------- ; Read the aux port the required number of times. ;---------------------------------------------------------------- ; pin$aux: call aux$ird lbcd opr2 ; Loops pin$loop: call clr$wdt call aux$ist ; Input status jrnz pin$rd call cst jrz pin$loop call cie cpi esc jrnz pin$loop ret ; pin$rd: call aux$inp ; Read aux call coe ; Write console dcx b mov a,b ora c jrnz pin$loop ; lbcd opr2 mov a,b ora c jz pin$loop ; ret ; ;**************************************************************** ;* Output a value to a port * ;* cmd => o pp (xx) (yy) * ;* xx= data yy = optional count, 0 = forever * ;* ;* OPR3 = count ;**************************************************************** ; portout: ; ; Detect if the AUX port and if so, handle specially ; lda opr1 cpi 6 ; Port 6 = AUX port of device jz pout$aux ; lda opr2 ; Get data mov d,a ; Into d ; lxi b,1 ; Default count = 1 lda opcnt ; See how many operands cpi 3 jrc pout0 ; Skip if < 3 lbcd opr3 ; Get loop count pout0: sbcd opr3 ; Load. pout1: push b call clr$wdt ; Stop the watchdog lda opr1 ; Get port no. mov c,a ; To port C mvi b,0 ; Top port address must be 0 outp d ; Send data in D to port in A pop b call chkabrt ; See if abort wanted dcx b mov a,c ora b jrnz pout1 ; Counter - 1 ; lbcd opr3 ; Get loop count mov a,b ora c jz pout1 ; BC = 0 so repeat indefinite ret ; ; -- Aux port write -- ; pout$aux: call aux$iwr ; Initialize to write mode lbcd opr3 ; Repeat counter paux$loop: call clr$wdt lda opr2 ; Data to send call aux$out call cst jrz paux$1 call cie cpi esc jrnz paux$end paux$1: dcx b mov a,b ora c jrnz paux$loop ; Repeat aux write loop ; lbcd opr3 mov a,b ora c jrz paux$loop ; paux$end: call aux$ird ret ; ;**************************************************************** ;* Fill memory with data * ;* cmd => f ssss ffff dd * ;**************************************************************** ; fill: lda opr3 ; Get data to fill with push h ; Save hl call rngchk ; Check de < hl pop h fill1: call clr$wdt stax d ; Save data push h ora a ; Clear flags leave acc. dsbc d ; See if address match pop h ; Restore end address inx d ; Next location jrnz fill1 ; Skip if no match ret ; ;**************************************************************** ;* Locate a string in memory * ;* cmd => l ssss ffff b1 b2 b3... B5 * ;**************************************************************** ; locat: call rngchk ; Make sure end > start lda opcnt ; How many operands sui 3 ; Subtract 3 jc erdisp ; Error 3 minimum mov b,a ; Save difference inr a ; Add 1 sta opcnt ; Save operand count lxi h,opr4-1 lxi d,opr4 locat1: ldax d ; Get data mov m,a ; Save it inx h ; Next location inx d inx d djnz locat1 ; Loop till all operands crushed locat2: lda opcnt mov b,a ; Save opcount lhld opr1 ; Get start address lxi d,opr3 locat3: ldax d ; Get operand cmp m ; Compare to memory jrnz locat4 ; Skip if no match inx h ; Next memory location inx d ; Next operand djnz locat3 ; Opcount - 1 lhld opr1 call prhl ; Memory address call crlf ; New line call chkabrt ; See if abort wanted locat4: lhld opr2 ; Get end address lded opr1 ; Get start address ora a dsbc d ; Compare them rz ; If same, exit inx d ; Next location sded opr1 ; Update start address jr locat2 ; Loop around ; ;**************************************************************** ;* Verify 2 blocks of memory * ;* cmd => v ssss ffff ssss * ;**************************************************************** ; verify: call rngchk ; Check start and end address push h ; Save difference pop b ; Count into bc xchg ; Swap start and end lded opr3 ; Get destination block verif1: ldax d ; Byte from dest cci ; Block compare with increment inx d ; Next locat for test jrnz verif2 ; If no match skip rpo ; End of compare, exit jr verif1 ; Loop ; verif2: push psw ; No match push b push d ; Save all regs dcx h ; Go back one location call prhl ; Display pointer mov a,m ; Get contents inx h ; Increment pointer call pracc ; Print value pop d push d push h xchg ; Get dest block dcx h ; Back one call prhl ; Print pointer mov a,m ; Get data call phacc ; Display it also call crlf ; New line pop h pop d pop b pop psw ; Restore regs rpo call chkabrt ; Test for abort key jr verif1 ; Then loop ; ;**************************************************************** ;* Test memory for errors * ;* cmd => t ssss ffff * ;**************************************************************** ; mtest: xchg ; Swap start and end inx d ; De = start+1 mvi b,0 ; Count = 256 mtest1: lhld opr1 ; Get start address ; mtest2: call clr$wdt mov a,l xra h ; Compare to h xra b ; Then count mov m,a ; Save in memory (auto change) inx h ; Next location push h ; Save pointer ora a ; Clear flags dsbc d ; Start - dest pop h ; Restore pointer jrnz mtest2 ; Loop if not finished lhld opr1 ; Get back start address ; mtest3: call clr$wdt mov a,l xra h xra b ; Reconstruct data to test cmp m cnz mtest4 ; If no match, display error inx h ; Next loc push h ; Save it ora a dsbc d ; See if end of test pop h jrnz mtest3 ; Skip if not inr b ; Bit count done call chkabrt ; See if abort wanted mvi a,'P' ; Indicate 1 pass call coe call clr$wdt jr mtest1 ; Loop to restart ; mtest4: push psw ; Save test byte call clr$wdt call prhl ; Print address pop psw call pracc ; Print test byte mov a,m ; Get invalid data call pracc ; Print it also jmp crlf ; Display crlf, then return ; ;**************************************************************** ;* Dump memory contents * ;* cmd => d ssss * ;**************************************************************** ; dump: lda opcnt ; Get count ora a jrz dump$again ; cpi 1 ; See if < 2 jnz erdisp ; One operand = start address ONLY lded opr1 ; Get the start address sded dump$lst ; dump$again: lded dump$lst ; ; 16 lines to dispplay ; dsp$mem: call crlf mvi b,16 ; Lines to display dsp$mem$loop: call dsp$line call crlf call cst jrz dml1 call cie cpi esc rz ; Exit if an escape call bell ; Else bell the key. dml1: djnz dsp$mem$loop ; call cie cpi 01bh rz cpi cr jrz dsp$mem ; Display the next page a CR cpi ' ' jrz dsp$mem ; Display next page if a space cpi lf jrz dsp$mem ; Next page if a lf cpi '+' jrz next$k cpi '-' jrz lst$k ret ; next$k: lxi h,1024 ; 1k dad d xchg jr dsp$mem ; lst$k: xchg lxi d,1024 ora a dsbc d xchg jr dsp$mem ; ;------------------------------------ ; ---- Display a line of memory ---- ;------------------------------------ ; dsp$line: push b ; Save external counters ; Now the address from DE call phde ; Print as hex call space ; push d ; Save the address also mvi b,16 ; 16 bytes dl1: ldax d inx d call phacc ; Print as hex inx h call space ; Separator ; Middle ? mov a,b cpi 9 jnz dl11 mvi a,'-' call coe call space dl11: call clr$wdt ; Stop the dog djnz dl1 ; call space2 pop d ; Restore the memory address mvi b,16 dl2: ldax d inx d call makasc call coe call clr$wdt djnz dl2 ; pop b ; Restore counters ret ; ;**************************************************************** ;* Examine / alter memory locations * ;* cmd => e llll (xx) * ;**************************************************************** ; exmem: xchg ; Hl gets start exmem1: call prhl ; Display pointer mov a,m ; Get byte call phacc ; Print hex value mvi a,'-' call coe ; Then marker push h call gaddr ; Get data from user pop h lda opcnt ; Get bytes entered ani 3 jrz exmem3 ; If none, skip lda opr1 ; Get data mov m,a ; Copy to memory inx h ; Next location lda lastchr cpi 00dh ; Was it a carriage ret ? jrz exmem1 ; Skip if so exmem2: dcx h ; Restore pointer jr exmem1 ; Loop ; exmem3: lda lastchr ; Get back last char cpi '^' ; Was it an up-carrot jrz exmem2 ; If so, stay on this location inx h ; Else next location jr exmem1 ; Loop around ; ;**************************************************************** ;* Port examine / modify command * ;* cmd => p pp * ;**************************************************************** ; port: ; See if display whole port space lda lastchr ; Get the character cpi '^' ; Carrot causes whole page jrz pmap cpi '&' jrnz porta ; Do a repeated port map display with cursor positioning. An escape ends it. cport: mvi a,cscrn ; Erase screen code call coe cport1: ; DO a cursor position to line 5 column 1 mvi a,cpos1 ; First cursor position code call coe mvi a,cpos2 ; Second cursor position code call coe mvi a,3+offset ; Row + offset first call coe mvi a,1+offset ; Column next call coe call pmap ; Display the port map jr cport1 ; pmap: ; This section causes the whole port address space to be displayed mvi e,16 ; Number of 16 port lines mvi c,00 ; Start at port 00 pm1: call clr$wdt mvi b,16 ; 16 ports per line displayed mov l,c ; Get start port # mvi h,00 push b call crlf ; Space apart call prhl2 ; Print port # pop b pm2: call clr$wdt inp a ; Get the port from (c) push b ; Save the counters call pracc ; Print a port & a space call prsep ; Check if we need a line separator call chkabrt ; Detect if we need to quit-a-motto pop b inr c ; Next port next time djnz pm2 ; ; Detect if all lines have been sent to screen ( = all ports done) dcr e ; Decrement line counter mov a,e ora a ; End of the lines ? jrnz pm1 ret ; porta: lda opr1 ; Get port no mov c,a ; Into c port1: mov a,c ; Get back port no call pracc ; Display it inp a ; Get contents call pracc ; Print also push b call gaddr ; See if data to be altered pop b lda lastchr ; Get character entered mov h,a lda opcnt ; Get opcount ana a jrz port3 ; If none, skip lda opr1 outp a ; Send data out mvi a,'^' ; Test for carrot cmp h jrz port1 ; Skip if so port2: inr c ; Next port number jr port1 ; Loop ; port3: mvi a,'^' cmp h jrnz port2 ; Skip if not carrot dcr c ; Port no.- 1 jr port1 ; ;**************************************************************** ; ; Quit the monitor * ; * ;**************************************************************** ; exit: hlt ; Generates a reset pulse jmp 0 ; = reset ; ;**************************************************************** ; Enter a string into memory at opr1 till an escape. * ;**************************************************************** ; string: lda opcnt cpi 1 jnz warm ; Only one operand allowed xchg ; Put the destination address in hl ; Do a crlf then enter text till a control Z lxi d,00 ; Set up a character counter string1: call cie ; Get a character cpi 01ah ; Control Z jrz string2 ; End of the command. cpi esc cnz coe ; No echo of control codes. mov m,a ; Put into memory inx h inx d ; Bump pointers jr string1 string2: ; Here when the user has had enough and entered a control Z call crlf xchg ; Put character counter into hl mvi a,'>' call coe call prhl ; Print the number of characters jmp warm ; Process next command ; ; ; chkabrt: ; Detect if the user wanted to quit or not call cst ; See if abort pressed rz ; Return if no character pending call cie ; Get the character, conin handles esc cpi esc jz warm cpi '.' jz warm ret ; ;**************************************************************** ;* See if de less than hl * ;**************************************************************** ; rngchk: ora a ; Clear flags dsbc d jc erdisp inx h ret ; pracc: call phacc jmp space ; ; makhex: sui '0' ; Remove ascii bias cpi 10 ; If 0 - 9, return rm sui 7 ; Else make a - f = 10 - 15 ret ; valnum: cpi '0' jrc valbad ; Check = '0' - '9' cpi '9'+1 jrc valnok cpi 'A'-1 ; Check = 'A' - 'F' jrc valbad cpi 'G' jrnc valbad valnok: xra a ; Set zero flag for good exit ret ; valbad: xra a ; Set acc = 1 inr a ret ; ;**************************************************************** ;* Checks for end of numeric entry * ;**************************************************************** ; valdm: cpi ' ' ; valid delim rz cpi '^' ; Alternate code for cr (*) jrz valdm1 cpi '&' ; This is allowed for cont' commands jrz valdm1 cpi cr ; End of command rnz ; Exit if not a one of these ; valdm1: call crlf ; Issue a carriage return xra a ; Set zero flag = valid delim ret ; ghex: lxi h,00 mov b,l ghex1: call echo inr b call valdm rz call valnum rnz mov a,c call makhex dad h dad h dad h dad h add l ; add in lower digit mov l,a ; put back in jr ghex1 ; echo: call cie ani 07fh cpi 'a' ; Ensure in upper case jrc noconv cpi 'z'+1 jrnc noconv ani 05fh noconv: mov c,a ; save cpi esc jnz coe ret ; ;**************************************************************** ;* Collect up to 9 bytes of numeric data * ;* separated by spaces if entered * ;**************************************************************** ; gaddr: xra a lxi h,opr1 push h popix mov m,a lxi b,13 lxi d,opr1+1 ldir ; Clear 13 bytes of ram sta opcnt ; ; gaddr1: call ghex jnz erdisp mov a,c sta lastchr cpi ' ' jrz gaddr2 dcr b rz ; ; gaddr2: stx l,000h stx h,001h lda opcnt inr a sta opcnt inxix inxix mov a,c cpi ' ' jrz gaddr1 ret ; prhl: mov a,h call phacc mov a,l jmp pracc ; prhl2: ; Print contents of hl and also extra spaces call prhl jr prsep2 ; Send an additional space ; prsep: ; If b = 8 then print a '- ' else return mov a,b cpi 9 ; Already done 8 characters ?? rnz ; Return if not at exact match mvi a,'-' call coe prsep2: jmp space ; Print a space ; ;**************************************************************** ;* Printer output routine * ;**************************************************************** ; poe: ret ; ;---------------------------------------------------------------- ; Do a checksum of memory and report it to the user. This allows ; the user to generate a checksum from a modified rom and then ; put it into the rom. ; Display both. ;---------------------------------------------------------------- ; cks$test: lxi d,rom$ckm ; Stored eprom message call ptxt lda cks$loc ; Stored checksum call phacc ; Print it. ; lxi d,cal$ckm ; Calculated message call ptxt ; lxi d,00000h ; base of eprom lxi b,cks$siz ; Size ; ; mvi l,00 ; Cumulative seed. cks$loop: in wdt ; Stop watchdog. ldax d add l ; Add without carry. mov l,a ; Save inx d ; -> next byte dcx b mov a,b ora c jrnz cks$loop ; ZERO if B = C = 0 mov a,l ; Fetch cma ; Compliment accumulator ; call phacc jmp crlf ; Exit via a line feed / return. ; rom$ckm: db cr,lf,'Rom Stored Checksum = ',0 cal$ckm: db cr,lf,'Calculated checksum = ',0 ; ;---------------------------------------------------------------- ; Read the AUX port till the user hits any key. ;---------------------------------------------------------------- ; aux$r: call aux$ird ; Select read mode ; aux$r$loop: call clr$wdt call cst jrnz aux$r$end ; call aux$ist jrz aux$r$loop call aux$inp ; Read character call con$out ; Display to screen jr aux$r$loop ; ; aux$r$end: call cie ret ; ;---------------------------------------------------------------- ; Write to the AUX port the user hits an escape. ;---------------------------------------------------------------- ; aux$w: call aux$iwr ; Select write mode lda opcnt ora a jz aux$w$loop ; No operands = echo mode lded opr2 ; Get the count of bytes to be sent ; ; Else get the byte and send it and decrement the counter in DE ; aux$send: call clr$wdt call cst ; Get console status jrz aux$send1 call con$inp cpi esc ; End ? jz aux$w$end ; Exit on escape aux$send1: lda opr1 call aux$out dcx d mov a,e ora d jrnz aux$send ; DE = 0. lded opr2 ; Get the size again mov a,e ora d jrz aux$send jmp aux$w$end ; Exit if > 0 initially ; ; Here, no operands = echo console to the aux port. ; aux$w$loop: call clr$wdt call cst jrz aux$w$loop ; call con$inp ; Read character cpi esc jrz aux$w$end ; ; No escape. Send to aux port call aux$out call con$out jr aux$w$loop ; aux$w$end: call aux$ird ; Always exit in read mode. ret ; ;---------------------------------------------------------------- ; Do a restart test. ;---------------------------------------------------------------- ; rst$test: rst 1 ; Do it. rst 2 rst 3 rst 4 rst 5 rst 6 rst 7 ret ; ; Small I/O Deiver interfaces ; phde: push b mvi c,19 ; HEX DE Print code rst 1 pop b ret ; pdde: push b mvi c,20 ; Decimal DE Print code rst 1 pop b ret ; phacc: push b mvi c,17 ; HEX Psw Print code rst 1 pop b ret ; pptxt: ldax d ora a rz cpi '$' rz call prn$out inx d jr pptxt ; ptxt: ldax d ora a rz cpi '$' rz call coe inx d jr ptxt ; ; bell: mvi a,7 jmp coe space2: call space space: mvi a,' ' jmp coe ; crlf: mvi a,cr call coe mvi a,lf jmp coe ; caps: push b mvi c,55 ; CAPS code rst 1 pop b ret ; ClrWdt: push b push psw mvi c,40 ; Watchdog clear rst 1 pop psw pop b ret ; makasc: ani 07fh ; Make in the range cpi 020h ; Lower than a space is illegal jrc noasc ; Not ascii cpi 07bh ; Higher than upper case is illegal too rc ; return with ascii character in C noasc: mvi A,02eh ; Replace with a '.' ret ; coe: jmp con$out cie: jmp con$inp cst: jmp con$ist ; ; ;************************************************ ;* Table of routines addresses * ;************************************************ ; jmptbl: dw adump ; A Ascii display of memory dw erdisp ; B dw cks$test ; C Checksum test dw dump ; D display memory dw exmem ; E examine memory dw fill ; F fill memory dw go ; G go to program dw hexad ; H hex sum and difference dw portin ; I input from port dw erdisp ; J dw erdisp ; K dw locat ; L locate string dw move ; M move memory dw erdisp ; N dw portout ; O output to a port dw port ; P examine port dw exit ; Q quit this monitor dw aux$r ; R Read channel dw exmem ; S Examine memory dw mtest ; T test ram dw string ; U Use console for writing to ram dw verify ; V verify ram dw aux$w ; W Write to aux device (RS-485) dw erdisp ; X dw rst$test ; Y Restart instruction test dw cks$test ; Z Checksum test ; ; signon: db cr,lf signon1: db cr,lf,'SME Systems MOKE Monitor' db cr,lf,'Version 1.3 17/03/1989' db cr,lf,0 signon2: db 'M>' db 0 ; dseg ; ; trp$flg ds 1 led$cnt ds 1 ; LED timer to toggle. bel$cnt ds 1 dump$lst ds 2 ; Last dump address opcnt db 00 lastchr db 00 opr1 db 00,00 opr2 db 00,00 opr3 db 00,00 opr4 db 00,00 opr5 db 00,00 opr6 db 00,00 opr7 db 00,00 temp2 db 00,00 temp6 db 00,00 temp8 db 00,00 ; usr$stk db 00,00 ds stk$siz * 2 stack: ; end ; ; ---- End of module ---- ;