; VT100 demo started Sunday 01:43:50 am 14/04/91 ; ; ACAL Application V1.10 Friday 17/01/95 ; ACAL&GEC Application V1.20 Tuesday 30/05/95 ; Shrunk GEC Application V1.20 Monday 27/11/95 ;Enable_PS equ true ; If exists, trap- ;Start_Msg equ true ; If exists, show this GEC_Version equ true ; If exists, GEC variant Pio_AD equ %1 1 0 1 1 1 00 Pio_BD equ %1 1 0 1 1 1 01 Pio_AK equ %1 1 0 1 1 1 10 Pio_BK equ %1 1 0 1 1 1 11 Lcd_D equ %0 1 1 1 1 11 1 Lcd_K equ %0 1 1 1 1 11 0 Ctc_A equ %1 1 1 0 1 1 00 Ctc_B equ %1 1 1 0 1 1 01 Ctc_C equ %1 1 1 0 1 1 10 Ctc_D equ %1 1 1 0 1 1 11 VT100_Chars equ #18000 ; The VT100 char set TV914_Chars equ #10000 ; The TV914 char sets ; Memory stuff SAR0L equ #60 ; DMA Src SAR0H equ #61 ; SAR0B equ #62 ; DAR0L equ #63 ; DMA Dst DAR0H equ #64 ; DAR0B equ #65 ; BCR0L equ #66 ; DMA Cnt BCR0H equ #67 ; DSTAT equ #70 ; DMA status DMODE equ #71 ; DMA mode DMAWAIT equ #72 RCA equ #76 ; Refresh control CBR equ #78 BBR equ #79 CBAR equ #7A IL equ #73 ; ITC equ #74 ; ICR equ #3F ; ICR in reset posn OUT_0 equ #00 ; Watchdog port IN_0 equ #01 ; Input port IN_1 equ #02 ; Input port ; System equates RAM_Start equ #1000 ; The start of RAM Vars equ #3000 ; Variables ; Video equates Mem_Off equ #8000 ; Offset the vdu start lVLU_Base equ #6000 ; The window table area lVDU_Base equ #6000 + (2048) ; The window data area lCHR_Base equ #0 ; The character-cell data area lVID equ #7FF0 ; The registers lTOP equ #6FFF ; The registers base aVLU_Base equ lVLU_Base + Mem_Off ; The window table area aVDU_Blank equ lVDU_Base + Mem_Off ; A blank line aVDU_Base equ aVDU_Blank + 80*2 ; The window data area aCHR_Base equ lCHR_Base + Mem_Off ; The character-cell data area aVID equ lVID + Mem_Off ; The registers aTOP equ lTOP + Mem_Off ; The registers base Vid_Attr equ aVID + 0 ; Attributes Vid_IntClr equ aVID + 7 ; Clear the interrupt ; Serial equates CNTLA0 equ #40 ; ASC Ctrl Reg A (0) CNTLB0 equ #42 ; ASC Ctrl Reg B (0) STAT0 equ #44 ; ASC Status Reg (0) TDR0 equ #46 ; ASC TxD (0) RDR0 equ #48 ; ASC RxD (0) CNTLA1 equ #41 ; ASC Ctrl Reg A (1) CNTLB1 equ #43 ; ASC Ctrl Reg B (1) STAT1 equ #45 ; ASC Status Reg (1) TDR1 equ #47 ; ASC TxD (1) RDR1 equ #49 ; ASC RxD (1) Rx_TO equ 0 ; Receiver time-out value ; VT100 stuff cEsc equ #1B ; Escape char bCurEnable equ 0 ; Use in BIT ops bCurShown equ 1 ; Use in BIT ops VT_CFT equ 2000 ; Cursor flash rate iFl_0 equ 1 ; Flash 0 rate iFl_1 equ 15 ; Flash 1 rate ; TV914 stuff TV9_CFT equ 2000 ; Cursor flash rate ; Key matrix stuff SMS_Cnt equ 3 ; This many frames for debounce ; IBM Keyboard stuff cUp equ #80 ; Extended keys cDn equ #81 ; cLt equ #82 ; cRt equ #83 ; cPU equ #84 ; cPD equ #85 ; cCN equ #90 ; Configuration key cEC equ #91 ; Edit the chars ; Serial stuff cXON equ #11 ; Xon cXOFF equ #13 ; Xoff ; The character editing stuff EC_CS_TL equ aVDU_Base + (0 * 2) + (0 * 160) ; The char set window EC_C_TL equ aVDU_Base + (64 * 2) + (0 * 160) ; The char window ; Code org #1000 jp Start ; Start-up vFrame_Int jp 0;Frame_Int ; Vector to frame int AFTER reset jp 0 ; NMI = Reset ; Plant the version, etc db "VT100/TV914 version 1.40 " db timestr ; Start here . . . Start ld sp,#8000 ; Stack at top of RAM call Setup_Z180 ; Setup the memory mapping, etc call Clear_Vars ; Clear the variables ; Get the default options call Read_Options ; Read the defaults call Setup_Timing_25 ; Display timing call VT_Setup_Chars ; Character set bitmaps call Setup_IBM_Keys ; Setup the IBM keyboard manager call Enable_Ints ; Setup the interrupt structures call Read_Options ; Read the defaults (again ;) call Setup_VT100 ; Setup the display driver call Setup_Serial ; Setup the serial port ; Enable Para-Sys if required if def Enable_PS call Setup_PS endif ; Show a string if required if def Start_Msg ld hl,sStart_Msg call VT_String ld a,#08 ld (#E801),a ld (#E89F),a ld (#F701),a ld (#F79F),a endif ; Change to TV914 mode if required ld a,(opMode) ; 1 = VT100 dec a ; call nz Setup_TV914 ; Use the TV914 mode ; Drive the terminal Main_Lp call Kick_Watchdog ; Kick the dog ; Trap out if Para-Sys if def Enable_PS ld bc,STAT1 ; Char waiting ? in a,(c) ; bit 7,a ; Rx full ? jp nz #9C ; Yes, exit to PS endif ; Any chars waiting ? call Read_Rx ; Get a char from the serial port ? jr c Main_NoRx ; No, skip ; Show this char Main_Show call Show_Char ; Show the char using the VT100/TV914 ; Now, is there a kbd char ? Main_NoRx ld hl,Kbd_Buff ; Point at the buffer ld ix,Kbd_Ptr ; And the ptrs call Remove_Byte ; Get a key ? jr c Main_Lp ; No, loop ; We have a char, is it a CONFIGURATION request ? cp cCN ; Conf ? jr z Do_Configure ; Yes, skip ; We have a char, is it a CHAR EDIT request ? cp cEC ; Edit chars ? jp z Do_EditChars ; Yes, skip ; Send the char call Write_Tx ; Send it ; Now, should we echo locally ? ld b,a ; Save char ld a,(opEcho) ; = 1 ? dec a ; jr nz Main_Lp ; No, loop ; Echo it ld a,b ; Get the char jr Main_Show ; Show it ; Show a string VT_String ld a,(hl) ; Get next inc hl ; Skip or a ; ret z ; End, exit push hl call VT_Show_Char ; Write it pop hl jr VT_String ; Loop ; Show a character, using either the VT100 or the TV914 display driver Show_Char ld b,a ; Save the char ; VT100 ? ld a,(opMode) ; 1 = VT100 dec a ; ld a,b ; Restore char jp z VT_Show_Char ; VT100 ; This is a TV914 jp TV9_Show_Char ; VT914 ? if def Enable_PS ; Setup the serial-port 57600 baud Setup_PS ld a,%0 1 1 0 0 100 ; Rx en, Tx en, Clk out,clr err, 8N1 ld bc,CNTLA1 ; out (c),a ; ld a,%00 0 0 0 000 ; /10 ld bc,CNTLB1 ; out (c),a ; ld a,%0000 0 1 0 0 ; CTS1 en, int di ld bc,STAT1 ; out (c),a ; ret ; Done endif ; Setup the options Do_Configure call Setup_VT100_NC ; Make us a VT100 terminal call Read_Options ; Read the defaults ; Fire-up the Setup page call Configure_Term ; Configure it ; Should we write them back ? ld a,(Opt_Exit) ; 1 = write-back cp 1 ; 1 ? jr nz DC_X ; No, skip ; Yes, warn the user ld hl,sFlash_Update ; String call VT_String ; Show it ; Write the options call Write_Options ; Write them ; Restart the unit DC_X jp Start ; Fire-up ; Edit the character-set Do_EditChars ld hl,#0100 ; Set 0 (Was 1) ld (EC_X),hl ; Cursor (Char) ld (EC_Y),hl ; ld (EC_PX),hl ; Cursor (Pixel) ld (EC_PY),hl ; ld a,-1 ; Force a redraw ld (ECO_Set),a ; ; Clear the display EC_Setup ld a,-1 ; Force redraws ld (ECO_X),a ; ld (ECO_PX),a ; ld (ECO_Set),a ; call Setup_VT100_NC ; Everything except the chars ; Now, draw display EC_Redraw call EC_Draw ; Show the character-set call EC_Get_Key ; Giz a key ; Now, check for cursors call EC_CursorCheck ; Is it a cursor ? jr nc ECR_C ; Yes, skip ; No, try something else cp " " ; Toggle ? jp z EC_Toggle ; Yes, skip ; Underline set ? cp "U" ; Underline ? jr z ECR_Underline ; Yes, skip cp "u" ; Underline ? jr z ECR_Underline ; Yes, skip ; VT100 / TV914 ? cp "T" ; Change mode ? jr z ECR_Mode ; Yes, skip cp "t" ; Change mode ? jr z ECR_Mode ; Yes, skip ; Save ? cp "S" ; Save edits ? jr z ECR_Save ; Yes, skip cp "s" ; Change mode ? jr z ECR_Save ; Yes, skip ; Escape ? cp #1B ; Esc ? jr nz EC_Redraw ; No, loop ; Exit back to terminal ld a,(opMode) ; VT100/TV914 ? dec a ; push af ; Save call z Setup_VT100_NC ; VT100 pop af ; call nz Setup_TV914_NC ; TV914 jp Main_Lp ; As before ; We have a save request ECR_Save ld hl,sFlash_Update ; String call VT_String ; Show it ; Now write them call Write_CS ; Write the character set back jp EC_Setup ; As above ; We have an underline select ECR_Underline ld a,(EC_Set) ; Flip the underline bit xor #01 ; ld (EC_Set),a ; Set it jp EC_Redraw ; Show it ; We have a VT100/TV914 change request ECR_Mode ld a,(EC_Set) ; Flip the mode bit xor #02 ; ld (EC_Set),a ; Set it ; Select one and #02 ; Cleared again ? jr z ECRM_VT100 ; Yes call TV9_Setup_Chars ; Get them jp EC_Redraw ; Show it ; Restore VT100 ECRM_VT100 call VT_Setup_Chars ; Get them jp EC_Redraw ; Show it ; We have a cursor move ECR_C ld hl,IB_Shift_L ; Left shift ld a,(hl) ; inc hl ; Right shift or (hl) ; jr z ECR_Pixel ; No, pixel move ; Character move, do it ld a,(EC_X) ; Step X add a,e ; and #1F ; 0 .. 31 ld (EC_X),a ; ld a,(EC_Y) ; Step Y add a,d ; and #0F ; 0 .. 15 ld (EC_Y),a ; jp EC_Redraw ; Show it ; Pixel cursor move ECR_Pixel ld a,(EC_PX) ; Step X add a,e ; and #0F ; 0 .. 15 ld (EC_PX),a ; ld a,(EC_PY) ; Step Y add a,d ; and #0F ; 0 .. 15 ld (EC_PY),a ; jp EC_Redraw ; Show it ; Write the character set back Write_CS ld a,(EC_Set) ; Get the char set bit 1,a ; 0 or 1 ? (Reversed) ld hl,VT100_Chars and #FFFF ; Assume VT100 (Set 0) ld a,VT100_Chars / #10000 ; jr z WCS_1 ; ld hl,TV914_Chars and #FFFF ; Is TV914 (Set 1) ld a,TV914_Chars / #10000 ; ; Now, save the address WCS_1 ld (Fl_Dst),hl ; Save the address ld (Fl_Dst2),a ; ; Erase 2 sectors call Flash_Erase ; Erase it jr c Write_CS ; Failed, try again ; And the next sector ld hl,(Fl_Dst) ; Step the address ld de,#4000 ; add hl,de ; ld a,(Fl_Dst2) ; call Flash_Erase ; Erase it jr c Write_CS ; Failed, try again ; Calc the address again ld a,(EC_Set) ; Get the char set bit 1,a ; 0 or 1 ? (Reversed) ld hl,VT100_Chars and #FFFF ; Assume VT100 (Set 0) ld a,VT100_Chars / #10000 ; jr z WCS_2 ; ld hl,TV914_Chars and #FFFF ; Is TV914 (Set 1) ld a,TV914_Chars / #10000 ; ; Now, save the address WCS_2 ld (Fl_Dst),hl ; Save the address ld (Fl_Dst2),a ; ; Now, we must write the new character set back ld hl,aCHR_Base ; The RAM address ld (Fl_Src),hl ; Set it ; Length ld hl,#6000 ; This many ld (Fl_Cnt),hl ; Set it ; Write to FLASH call Flash_Copy ; Do it jr c Write_CS ; Failed, try again ; Ok, exit ret ; Done ; Clear the screen EC_CLS ld hl,aVDU_Base ; Point at it ld bc,80*25 ; This many ECC_Lp ld (hl)," " ; " " inc hl ; ld (hl),#10 ; Attr cpi ; Loop jp v ECC_Lp ; ret ; Done ; Toggle the current bit EC_Toggle call EC_Calc_Addr ; HL/A ld c,(HL) ; XOR xor c ; ld (hl),a ; ; Force a char redraw ld a,-1 ; Force a char redraw ld (ECO_PX),a ; ; Do it jp EC_Redraw ; Show it ; Calc the pixel address EC_Calc_Addr ld a,(EC_X) ; Char - X and #0F ; ld l,a ; Save LSN ld a,(EC_Y) ; MSN rlca ; << 4 rlca ; rlca ; rlca ; or l ; Merge ld l,a ; Char ; Now, we calc the char-set ld h,#80 ; Normal ld a,(EC_Set) ; UL ? bit 0,a ; jr z ECCA_NU ; No, skip ld h,#90 ; UL ; Now, add pixel Y ECCA_NU ld a,(EC_PY) ; Y add a,h ; ld h,a ; ; We have a ptr to the byte, except for 16-bit ld a,(EC_X) ; 8 or 16 bit ? cp 16 ; 8 ? jr c ECCA_8 ; Yes, skip ld a,#20 ; LHS add a,h ; ld h,a ; ; Now, see if we are in the RHS ld a,(EC_PX) ; RHS ? cp 8 ; jr c ECCA_8 ; No, skip ld a,#20 ; RHS add a,h ; ld h,a ; ; Now, the bit position ECCA_8 push hl ; Save addr ld a,(EC_PX) ; X and #07 ; 0 .. 7 ld hl,EC_Bit_Tab ; Table call Index_It ; Look-it up ld a,l ; Point at it pop hl ; Restore ret ; Done ; Check if A is a cursor key EC_CursorCheck ld de,1 ; Assume Rt cp cRt ; Rt ? ret z ; Yes ld e,-1 ; Assume Lt cp cLt ; Lt ? ret z ; Yes ld de,#0100 ; Assume Dn cp cDn ; Dn ? ret z ; Yes ld d,-1 ; Assume Up cp cUp ; Up ? ret z ; Yes ld d,0 ; 0,0 scf ; Not a cursor ret ; ; Draw the character-set editing page EC_Draw call EC_Show_CS ; Show the character-set call EC_Show_Char ; Show the character ret ; Done ; Show a character EC_Show_Char ld a,(EC_PX) ; Has the cursor moved ? ld b,a ; ld a,(ECO_PX) ; cp b ; Same ? jr nz ECSC_1 ; No, show it ld a,(EC_PY) ; Has the cursor moved ? ld b,a ; ld a,(ECO_PY) ; cp b ; Same ? ret z ; Yes, exit ; Changed, show it ECSC_1 ld a,(EC_PX) ; X ld (ECO_PX),a ; ld a,(EC_PY) ; Y ld (ECO_PY),a ; ; Now, draw this char ; 8 or 16 bits wide ? ld a,(EC_X) ; Char - X cp 16 ; 0 .. 15 ? jr nc ECSC_16 ; No, double width ; We have a single-width char, show it ld l,a ; Save LSN ld a,(EC_Y) ; MSN rlca ; << 4 rlca ; rlca ; rlca ; or l ; Merge ld l,a ; Char ; Now, we calc the char-set ld h,#80 ; Normal ld a,(EC_Set) ; UL ? bit 0,a ; jr z ECSC_NU ; No, skip ld h,#90 ; UL ; We have a ptr to the char, show it ECSC_NU push hl ; IX := HL pop ix ; ld hl,EC_C_TL ; Here call ECSC_One ; Show 8.16 ; Now, show the cursor ld a,(EC_PY) ; 0 .. 15 ld hl,Cur_Y_Tab ; Index call Index_It ; ld de,EC_C_TL + 1 ; Point at the disp (Attr) add hl,de ; ld a,(EC_PX) ; 0 .. 7 and #07 ; ld (EC_PX),a ; Save clipped state add a,a ; * 2 ld e,a ; hl + a ld d,0 ; add hl,de ; ; Write it call ECSCS_Cur ; Show it ; Clear the unused char ld hl,EC_C_TL + 8*2 ; Clear the other half jp ECSC_Clear ; ; We have a double-width char, show it ECSC_16 sub 16 ; 0 .. 15 ld l,a ; Save LSN ld a,(EC_Y) ; MSN rlca ; << 4 rlca ; rlca ; rlca ; or l ; Merge ld l,a ; Char ; Now, we calc the char-set ld h,#A0 ; Normal ld a,(EC_Set) ; UL ? bit 0,a ; jr z ECSC_W_NU ; No, skip ld h,#B0 ; UL ; We have a ptr to the char, show it ECSC_W_NU push hl ; Save push hl ; IX=HL pop ix ; ld hl,EC_C_TL ; Here call ECSC_One ; Show 8.16 pop ix ; IX=HL ld de,#2000 ; RHS add ix,de ; ld hl,EC_C_TL + 8*2 ; Here call ECSC_One ; Show 8.16 ; Now, show the cursor ld a,(EC_PY) ; 0 .. 15 ld hl,Cur_Y_Tab ; Index call Index_It ; ld de,EC_C_TL + 1 ; Point at the disp (Attr) add hl,de ; ld a,(EC_PX) ; 0 .. 15 and #0F ; add a,a ; * 2 ld e,a ; hl + a ld d,0 ; add hl,de ; ; Write it jp ECSCS_Cur ; Show it ; Show one char ECSC_One ld c,16 ; 16 lines ECSC_LpY ld a,(ix) ; Next byte ld de,#100 ; Move down add ix,de ; ld de,#302E ; "0" or "." ld b,8 ; This wide ECSC_LpX rlca ; Top-bit jr c ECSC_Set ; Set ld (hl),e ; Not-set jr ECSC_Next ; Skip ECSC_Set ld (hl),d ; Set ECSC_Next inc hl ; Step ld (hl),#10 ; Attr inc hl ; djnz ECSC_LpX ; X-loop ld de,80*2 - 8*2 ; Down add hl,de ; dec c ; Y-loop jr nz ECSC_LpY ; ret ; Done ; Clear the area ECSC_Clear ld c,16 ; 16 lines ld a," " ; Clear ECSCC_LpY ld b,8 ; This wide ECSCC_LpX ld (hl),a ; Not-set inc hl ; Step ld (hl),#10 ; Attr inc hl ; djnz ECSCC_LpX ; X-loop ld de,80*2 - 8*2 ; Down add hl,de ; dec c ; Y-loop jr nz ECSCC_LpY ; ret ; Done ; Show the entire character-set EC_Show_CS ld a,(EC_Set) ; Has the set changed ? ld b,a ; ld a,(ECO_Set) ; cp b ; Same ? jr nz ECSCS_1 ; No, show it ld a,(EC_X) ; Has the cursor moved ? ld b,a ; ld a,(ECO_X) ; cp b ; Same ? jr nz ECSCS_1 ; No, show it ld a,(EC_Y) ; Has the cursor moved ? ld b,a ; ld a,(ECO_Y) ; cp b ; Same ? ret z ; Yes, exit ; Something has changed, save params ECSCS_1 ld a,(EC_Set) ; Set ld (ECO_Set),a ; ld a,(EC_X) ; X ld (ECO_X),a ; ld a,(EC_Y) ; Y ld (ECO_Y),a ; ld a,-1 ; Force a char redraw ld (ECO_PX),a ; ; Draw it ld hl,EC_CS_TL ; The screen-address ; Now, get the UL flag ld a,(EC_Set) ; Bit 0 = UL and #01 ; UL or #10 ; Normal attr ld c,a ; Save the attr add a,2 ; LHS attr ld d,a ; add a,2 ; RHS attr ld e,a ; xor a ; Char ECSCS_Lp ld b,16 ; This many ECSCS_Lp1 ld (hl),a ; The char inc hl ; inc a ; Step it ld (hl),c ; The attr inc hl ; djnz ECSCS_Lp1 ; Show the normal chars sub 16 ; Restore char ; Now the double-width inc hl ; One blank char inc hl ; ld b,16 ; This many ECSCS_Lp2 ld (hl),a ; The char inc hl ; ld (hl),d ; LHS attr inc hl ; ld (hl),a ; The char inc hl ; ld (hl),e ; RHS attr inc hl ; inc a ; Char++ djnz ECSCS_Lp2 ; Show the normal chars ; Now, move down push de ; Save ld de,80*2 - 49*2 ; Offset add hl,de ; pop de ; Restore or a ; All done ? jr nz ECSCS_Lp ; Loop ; Now, we must show the cursor ld a,(EC_X) ; 0 .. 15 ld hl,Cur_X_Tab ; Index call Index_It ; push hl ; Save the offset ld a,(EC_Y) ; 0 .. 15 ld hl,Cur_Y_Tab ; Index call Index_It ; pop de ; Restore add hl,de ; Calc address ld de,EC_CS_TL + 1 ; The screen-address add hl,de ; ; One or two chars ? ld a,(EC_X) ; > 16 ? cp 16 ; jr nc ECSCS_W ; Yes, skip ; Show the cursor here ECSCS_Cur ld a,(hl) ; Current attr and %00000 111 ; Preserve CS or %01110 000 ; Flash ld (hl),a ; Show it ret ; Done ; Wider ECSCS_W call ECSCS_Cur ; LHS inc hl ; Step inc hl ; jr ECSCS_Cur ; RHS ; Add A*2 to HL, then look-up HL Index_It add a,a ; * 2 add a,l ; HL := HL+A ld l,a ; adc a,h ; sub l ; ld h,a ; ld a,(hl) ; HL := (HL) inc hl ; ld h,(hl) ; ld l,a ; ret ; Done ; The bit-position table EC_Bit_Tab dw #80,#40,#20,#10,#08,#04,#02,#01 ; Bit posns ; The char-cursor X convert Cur_X_Tab dw 0,2,4,6,8,10,12,14 ; 0 .. 7 dw 16,18,20,22,24,26,28,30 ; 8 .. 15 dw 34,38,42,46,50,54,58,62 ; 16 .. 23 dw 66,70,74,78,82,86,90,94 ; 24 .. 31 ; dw 32,36,40,44,48,52,56,60 ; 16 .. 23 ; dw 64,68,72,76,80,84,88,92 ; 24 .. 31 ; The char-cursor Y convert Cur_Y_Tab dw 0 * 160 ; 0 dw 1 * 160 ; 1 dw 2 * 160 ; 2 dw 3 * 160 ; 3 dw 4 * 160 ; 4 dw 5 * 160 ; 5 dw 6 * 160 ; 6 dw 7 * 160 ; 7 dw 8 * 160 ; 8 dw 9 * 160 ; 9 dw 10 * 160 ; 10 dw 11 * 160 ; 11 dw 12 * 160 ; 12 dw 13 * 160 ; 13 dw 14 * 160 ; 14 dw 15 * 160 ; 15 ; Get a key-stroke EC_Get_Key push ix ; Save push hl ; ECGK_Lp ld hl,Kbd_Buff ; Point at the buffer ld ix,Kbd_Ptr ; And the ptrs call Remove_Byte ; Get a key ? jr c ECGK_Lp ; No, loop pop hl ; Restore pop ix ; ret ; Done ; Clear the Vars Clear_Vars ld hl,Var_Start ; Point at the start ld de,Var_Start+1 ; ld bc,+(Var_End-Var_Start)-1 ; Length ld (hl),0 ; Clear it ldir ; ret ; Done ; Setup the serial-port as a fn. of the options Setup_Serial ld c,%0 1 1 0 0 101 ; Rx en, Tx en, Clk out,clr err, 8N2 ; Now, clear the 8-bit if the opData = 2 ld a,(opData) ; 2 = 7 bit cp 2 ; jr nz SS_1 ; No, skip res 2,c ; Clear the 8-bit flag ; Now, clear the 2 stop-bits flag if required SS_1 ld a,(opStop) ; 2 = 1 bit cp 2 ; jr nz SS_2 ; No, skip res 0,c ; Clear the 2-stops flag ; Now, set the parity bit if required SS_2 ld a,(opParity) ; 3 = NONE cp 3 ; jr z SS_3 ; Yes, skip set 1,c ; Set the parity bit flag ; Now, write this SS_3 ld a,c ; Get the mode ld bc,CNTLA0 ; out (c),a ; ld (Rx_0_Ctrl),a ; Save it ; Now, set the baud-rate ld a,(opBaud) ; 1 .. 8 dec a ; add a,Baud_Tab and #FF ; Index into table ld l,a ; adc a,Baud_Tab/256 ; sub l ; ld h,a ; ld c,(hl) ; Get the baud-rate byte ; Now, we have to determine the parity bit ld a,(opParity) ; Set it if ODD cp 1 ; Odd ? jr nz SS_4 ; No, skip set 4,c ; Set PEO ; Write it SS_4 ld a,c ; Get the baud rate/parity etc ld bc,CNTLB0 ; out (c),a ; ; Enable CTS, etc ld a,%0000 1 1 0 0 ; CTS1 en, int Rx ei ld bc,STAT0 ; out (c),a ; xor a ; We haven't sent an XOFF ld (Rx_Stopped),a ; xor a ; Clear it ld (Tx_Fast_Send),a ; ret ; Done ; The baud-rate table Baud_Tab db %0 0 0 0 0 000 ; 57600 Baud db %0 0 1 0 0 000 ; 19200 Baud db %0 0 1 0 0 001 ; 9600 Baud db %0 0 1 0 0 010 ; 4800 Baud db %0 0 1 0 0 011 ; 2400 Baud db %0 0 1 0 0 100 ; 1200 Baud db %0 0 1 0 0 101 ; 600 Baud db %0 0 1 0 0 110 ; 300 Baud ; Send a character Write_Tx push ix ; Save push hl ; push bc ; push af ; ; Add it to the Tx buffer ld hl,Tx_0_Buff ; ld ix,Tx_0_Ptr ; call Insert_Byte ; Add it to the buffer ; Set the TIE flag ld bc,STAT0 ; STAT reg di ; Don't interrupt in a,(c) ; Get it or %0000000 1 ; Enable the Tx out (c),a ; ei ; ; Done, exit pop af ; Restore pop bc ; pop hl ; pop ix ; ret ; Done ; Receive a character (CF = None) Read_Rx push ix ; Save push hl ; ; Get it from the Rx buffer ld hl,Rx_0_Buff ; ld ix,Rx_0_Ptr ; call Remove_Byte ; Get it from the buffer push af ; Save byte and flag ; See if we should drive RTS call Get_Buff_Cnt ; No. of chars remaining ; If < 60 enable RTS cp 60 ; < 60 jr nc RR_X ; No, ignore ; Stopped ? ld a,(Rx_Stopped) ; Have we sent an XOFF ? or a ; jr z RR_X ; No, skip ; If yes, we MUST send an XON ; Clear Stopped xor a ; Not any more ld (Rx_Stopped),a ; ; Send an Xon ld a,cXON ; Send the stop call Tx_Pri ; ; Enable RTS ld a,(Rx_0_Ctrl) ; Get the setup or %0000 1 000 ; Don't clear the errors ld c,CNTLA0 ; Point at the reg out (c),a ; Clear /RTS ; Done RR_X pop af ; Restore ; Done, exit pop hl ; Restore pop ix ; ret ; Done ; Read the default options Read_Options ld hl,#C000 ; The Options data ld a,0 ; call DMA_SetSrc ; ; The dest ld hl,opMode-RAM_Start ; The address in RAM ld a,#04 ; call DMA_SetDst ; Dest ; The length ld hl,defEnd-defOptions ; This many call DMA_SetCnt ; Set it call DMA_DoIt ; Do it ; Default ptr for options ld hl,ocU_2 ; "NO" ld (op_pCur),hl ; ; Convert the Shrunk selection to the appropriate values ; Assume 16 lines per char ld hl,nLPC ; Set the number of lines per char ld (hl),16 ; Assume 16 ld hl,0 ; Offset ld (VTY_Offset),hl ; ld a,(opShrunk) ; Are we shrunk ? cp 2 ; Yes ? ret nz ; No, exit ; Actually 12 LPC ld hl,nLPC ; Set the number of lines per char ld (hl),12 ; Actually 12 ld hl,VT_Line_Ys_S - VT_Line_Ys_NS ; Offset ld (VTY_Offset),hl ; ret ; Done ; Write the options back to FLASH Write_Options ld hl,#C000 ; Sector address ld a,#00 ; call Flash_Erase ; Erase it ret c ; Failed, skip ; Now, write the options ld hl,opMode ; The RAM address ld (Fl_Src),hl ; Set it ; Dst ld hl,#C000 ; The dest ld a,#00 ; ld (Fl_Dst),hl ; ld (Fl_Dst2),a ; ; Length ld hl,defEnd-defOptions ; This many ld (Fl_Cnt),hl ; Set it ; Write to FLASH call Flash_Copy ; Do it ret nc ; Ok ; Failed ret ; Done ; Write a block of memory to FLASH (SRC:Only the lower 64K !!) Flash_Copy ld hl,(Fl_Src) ; Read the byte ld a,(hl) ; Get it inc hl ; Skip ld (Fl_Src),hl ; Save the new address ld (Fl_Byte),a ; Save the byte ; From here on in we don't want interrupts ! di ; No ints here please, we're British ! ; Now, send the write command to the Flash ld hl,#5555 ; AA to 05555 ld c,0 ; ld a,#AA ; call Long_Write ; Write it ; ld hl,#2AAA ; 55 to 02AAA ld c,0 ; ld a,#55 ; call Long_Write ; Write it ; ld hl,#5555 ; A0 to 05555 ld c,0 ; ld a,#A0 ; call Long_Write ; Write it ; Write the byte ld hl,(Fl_Dst) ; ld a,(Fl_Dst2) ; ld c,a ; ld a,(Fl_Byte) ; Get it call Long_Write ; Write it ; Now, we read it until it is OK FC_Lp ld hl,(Fl_Dst) ; Read this address ld a,(Fl_Dst2) ; call Long_Read ; Read it ld c,a ; Save ld a,(Fl_Byte) ; This is what we want cp c ; Same jr nz FC_Lp ; No, loop ; We have written this byte, get the next ei ; Enable ints in case ; Step the dstn address ld hl,(Fl_Dst) ; 24-bit addr ld a,(Fl_Dst2) ; ld de,1 ; Step it add hl,de ; adc a,0 ; ld (Fl_Dst),hl ; ld (Fl_Dst2),a ; ; Now, any more ? ld hl,(Fl_Cnt) ; This many dec hl ; ld (Fl_Cnt),hl ; ld a,l ; Loop or h ; jr nz Flash_Copy ; ; Done, exit or a ; Ok ret ; Done ; Erase a sector of FLASH (using DMA, urgh !) Flash_Erase di ; No interrupts !! ld (Fl_HL),hl ; Save the address ld (Fl_A),a ; ; Now, write the erase command to the Flash ld hl,#5555 ; AA to 05555 ld c,0 ; ld a,#AA ; call Long_Write ; Write it ; ld hl,#2AAA ; 55 to 02AAA ld c,0 ; ld a,#55 ; call Long_Write ; Write it ; ld hl,#5555 ; 80 to 05555 ld c,0 ; ld a,#80 ; call Long_Write ; Write it ; ld hl,#5555 ; AA to 05555 ld c,0 ; ld a,#AA ; call Long_Write ; Write it ; ld hl,#2AAA ; 55 to 02AAA ld c,0 ; ld a,#55 ; call Long_Write ; Write it ; Sector address ld hl,(Fl_HL) ; 30 to address ld a,(Fl_A) ; ld c,a ; ld a,#30 ; call Long_Write ; Write it ; Now, we read it until it is OK FE_Lp ld hl,(Fl_HL) ; Read this address ld a,(Fl_A) ; call Long_Read ; Read it bit 7,a ; Ok ? jr nz FE_Ok ; Yes, exit bit 5,a ; Failed ? jr z FE_Lp ; No, loop ; Failed, reset the FLASH ld hl,#5555 ; AA to 05555 ld c,0 ; ld a,#AA ; call Long_Write ; Write it ld hl,#2AAA ; 55 to 02AAA ld c,0 ; ld a,#55 ; call Long_Write ; Write it ld hl,#5555 ; F0 to 05555 ld c,0 ; ld a,#F0 ; call Long_Write ; Write it ; Assert fail ei ; Allow ints again scf ; CF ret ; Done ; Ok FE_Ok ei ; Allow ints again or a ; NC ret ; Done ; Write the byte in A to the address in CHL Long_Write ld (Flash_Byte),a ; Write it ld a,c ; Addr call DMA_SetDst ; Set the address ; Src byte ld hl,Flash_Byte-RAM_Start ; Address in RAM ld a,#04 ; call DMA_SetSrc ; Src ; Length ld hl,1 ; Length = 1 call DMA_SetCnt ; call DMA_DoIt ; Do it jp Kick_Watchdog_NI ; Not here ; Read the byte at address in AHL to Flash_Byte (and A) Long_Read call DMA_SetSrc ; Set the address ; Dst byte ld hl,Flash_Byte-RAM_Start ; Address in RAM ld a,#04 ; call DMA_SetDst ; Dst ; Length ld hl,1 ; Length = 1 call DMA_SetCnt ; call DMA_DoIt ; Do it call Kick_Watchdog_NI ; Not here ; Return the byte ld a,(Flash_Byte) ; Get it ret ; Done ; Drive the configuration page about Configure_Term ld hl,sConf_1 ; Draw the background, etc call VT_String ; Show it ; Clear the exit flag xor a ; 0 ld (Opt_Exit),a ; ; Now, draw the data CT_Update ld ix,opt_Def ; Point at the option data ld hl,(op_pCur) ; Point at the current option ld e,(hl) ; X inc hl ; ld d,(hl) ; Y call Show_Options ; Show it ; Exit yet ? ld a,(Opt_Exit) ; Get the exit case or a ; 0 ? jr nz CT_GotEm ; No, exit ; Now, get a key CT_Key call Get_IBM_Key ; Giz a key ; Perform the operation call Option_Key ; Do it jr c CT_Update ; Moved, show them again ; Not an option key, loop jr CT_Key ; Next key ; We have the new options, CT_GotEm call Setup_VT100 ; Reset the display driver ret ; Done ; Show the options Show_Options ld l,(ix) ; Point at the selection ld h,(ix+1) ; ld a,l ; End ? or h ; ret z ; Yes, exit ld c,(hl) ; Get the flag ld l,(ix+2) ; Point at the options definition ld h,(ix+3) ; dec d ; Option count ld b,e ; Option select call SO_Show ; Show this set inc ix ; Step it inc ix ; inc ix ; inc ix ; jr Show_Options ; Loop ; Show one set of options SO_Show ld a,(hl) ; X inc hl ; or a ; 0 ? ret z ; Yes, exit ld (cCur_X),a ; ld a,(hl) ; Y inc hl ; ld (cCur_Y),a ; ; Clear highlight ld a,%0 1 0 0 0 000 ; Normal ld (cAttr),a ; ; Now, do we highlight this one ? dec c ; This one ? jr nz SOS_1 ; No, skip ld a,%0 0 0 1 0 001 ; Inverse ld (cAttr),a ; ; Is this the cursor ? SOS_1 dec b ; Opt cnt jr nz SOS_2 ; No, skip inc d ; d = 0 ? dec d ; jr nz SOS_2 ; No, skip ; Flag this as the cursor ld a,(cAttr) ; Flag cursor and %0 0 0 0 0 001 ; Preserve underline or %0 1 1 1 0 000 ; Flashing ld (cAttr),a ; ; Write text SOS_2 call VT_String ; Show it ; Done, next jr SO_Show ; Loop ; Drive a keystroke about, as an option Option_Key ld ix,(op_pCur) ; Point at the menu defn. ; Select ? cp #0D ; Cret ? jr z OK_Sel ; Yes, skip cp #20 ; Space jr z OK_Sel ; Yes, skip ; Escape ? cp #1B ; Esc ? jr z OK_Esc ; Yes, skip ; Move ? ld de,4 ; Left ptr cp cLt ; Left ? jr z OK_M ; Yes, skip cp #08 ; BS ? jr z OK_M ; Yes, skip ld e,6 ; Right ptr cp cRt ; Right ? jr z OK_M ; Yes, skip ld e,8 ; Up ptr cp cUp ; Up ? jr z OK_M ; Yes, skip ld e,10 ; Down ptr cp cDn ; Down ? jr z OK_M ; Yes, skip ; Ignore this key or a ; NC ret ; ; Esc, move to exit OK_Esc call Read_Options ; Get the default ones ; Point at the No ld hl,ocU_2 ; Update (NO) ld (op_pCur),hl ; scf ; Update ret ; Done ; Select this OK_Sel ld l,(ix+2) ; Point at the var ld h,(ix+3) ; ld a,(ix) ; Number ld (hl),a ; Change selection ; Now, check for exit case ld a,(ix+1) ; Get the Y cp 9 ; Update line ? jr nz OKS_X ; No, exit ; Update line, flag exit ld a,(ix) ; 1/2 ld (Opt_Exit),a ; Save it ; Done, update OKS_X scf ; Flag redraw ret ; Done ; Move as appropriate OK_M add ix,de ; Point at the vector ld l,(ix) ; Get the new menu ptr ld h,(ix+1) ; ld (op_pCur),hl ; Save scf ; Flag to redraw ret ; Done ; Get an IBM Keystroke Get_IBM_Key push ix ; Save push hl ; push bc ; ; Get an IBM-key GIK_Lp ld hl,Kbd_Buff ; Point at the buffer ld ix,Kbd_Ptr ; And the vars call Remove_Byte ; Get a kbd char jr c GIK_Lp ; None, loop ; Done, exit pop bc ; Restore pop hl ; pop ix ; ret ; Done ; Setup the IBM keyboard driver Setup_IBM_Keys xor a ; Clear the flag ld (IBM_Mode),a ; Mode := Idle ld (IB_Mode),a ; Not expecting release ld (IB_Curr_Key),a ; No current key ld (IB_Shift_L),a ; ld (IB_Shift_R),a ; ld (IB_Ctrl),a ; ld (IB_Alt),a ; ld (IB_Caps),a ; ld (IB_Alt),a ; ld (IB_Num),a ; ret ; Done ; Setup the TV914 driver Setup_TV914 call TV9_Setup_Chars ; Draw the character-sets ; Set the Flashing mode Setup_TV914_NC ld a,1 ; Flash as a TV914 ld (Flash_Mode),a ; ; Now we do everything except the chars jp TV9_Set80x24 ; 24 lines of 80 chars ; Set the TV914 to 80 by 24 ; TV9_Set80x24 ld a,1 ; Set 80.24 mode ld (TV9_80_F),a ; ; Cls ld c," " ; CLS call TV9_CLS ; ; Reset the video logic call Setup_Timing_24 ; Reset the VDU timing ; Now, setup the cursor jr TV9_SetCur ; Setup the cursor ; Set the TV914 to 40 by 12 ; TV9_Set40x12 ld a,0 ; Set 40.12 mode ld (TV9_80_F),a ; ; Cls ld c," " ; CLS call TV9_CLS ; ; Reset the video timing call Setup_Timing_12 ; Reset the VDU timing ; Now, setup the cursor TV9_SetCur ld a,%0 0 0 1 0 000 ; Normal on Black ld (cAttr),a ; ld a,1 ; 01 ld (cCur_X),a ; X ld (cCur_Y),a ; X ld (cCur_F),a ; 01 (Enabled, not shown) ld a,%0 1 1 1 0 000 ; Flashing rectangle cursor ld (TV9_CurAttr),a ; xor a ; Ready for a char ld (TV9_Mode),a ; if def GEC_Version ld (TV9_SemiF),a ; Not in semi graphic mode endif ld a,"?" ; Dummy char for repeats ld (TV9_Rpt),a ; ; Ignore char set flags call TV9_Show_Cursor ; Show the cursor ; Clear the frame number ld hl,0 ; Clear the frame count ld (Frame_No),hl ; ; Setup flash rates ld a,iFl_0 ; 0 ld (Flash_0),a ; ld a,iFl_1 ; 1 ld (Flash_1),a ; ; Done ret ; Done ; The main TV914 show char routine TV9_Show_Char push hl ; Save push de ; push bc ; push af ; ; Esc ? cp cEsc ; Escape ? jr z TV9SC_Esc ; Yes, skip ld d,a ; Save the char ; What mode are we in ? ld a,(TV9_Mode) ; Giz the mode ld e,a ; Save or a ; jr z TV9SC_Char ; Not waiting, skip ; We are waiting, restore char ld a,d ; Char ; Check the mode dec e ; Mode = 1 ? jr z TV9SC_HaveList ; Yes, skip dec e ; Mode = 2 ? (R) jr z TV9_Mode_R ; Yes, skip dec e ; Mode = 3 ? (C) jr z TV9_Mode_C ; Yes, skip dec e ; Mode = 4 ? jr z TV9_RptMode ; Yes, skip ; Reset back to expecting char TV9SC_ExitChar xor a ; Mode := 0 ld (TV9_Mode),a ; ; Exit TV9SC_Exit pop af ; Restore pop bc ; pop de ; pop hl ; ret ; Done ; Deal with an "R" TV9_Mode_R sub 31 ; Calc X call TV9_Clip_Y ; Clip it ld (TV9_Temp),a ; Save it ld a,3 ; Mode := 3 ld (TV9_Mode),a ; jr TV9SC_Exit ; Done ; Deal with an "C" TV9_Mode_C sub 31 ; Calc Y call TV9_Clip_X ; Clip it call TV9_Hide_Cursor ; Hide it ld (cCur_X),a ; Move Y ld a,(TV9_Temp) ; Move X ld (cCur_Y),a ; call TV9_Show_Cursor ; Show it jr TV9SC_ExitChar ; Done ; Deal with a repeat mode TV9_RptMode sub 31 ; Calc count jr z TV9SC_ExitChar ; Done ld b,a ; Save the number xor a ; Make normal mode ld (TV9_Mode),a ; TV9_RM_Lp push bc ; Save count ld a,(TV9_Rpt) ; Giz the char call TV9_Show_Char ; Show it pop bc ; Restore djnz TV9_RM_Lp ; Loop ; Done, exit jr TV9SC_Exit ; Done ; Normal character handler TV9SC_Char ld a,d ; Giz char cp #20 ; 00 .. 1F Ctrl ? jr nc TV9SC_Show ; No, show it ; Yes ld hl,TV9_CTRL_Tab ; Point at the table call FindChar ; Look for this char in the list jr c TV9SC_Show ; Not found, show it as it is ; Now jr TV9SCEC_DoIt ; Drive it ; We have an ESC, setup mode TV9SC_Esc ld a,1 ; Mode := 1 ld (TV9_Mode),a ; ld hl,TV9_ESC_Tab ; Point at the ESC table ld (TV9_pList),hl ; Save it jp TV9SC_Exit ; Exit ; We have a list of possible chars TV9SC_HaveList ld hl,(TV9_pList) ; Get the ptr ; Look it up TV9SC_ExecChar call FindChar ; Look for this char in the list jr c TV9SC_ExitChar ; Not found, exit ; Found, call the driver routine TV9SCEC_DoIt call CallHL ; Call the driver ; Done, exit jp TV9SC_Exit ; Exit ; Show this character (in D) TV9SC_Show call TV9_Hide_Cursor ; Remove the cursor ; Show the char ld a,d ; Store the char in case of repeats ld (TV9_Rpt),a ; ld b,d ; Save the char call VT_Get_pCurs ; Point at it ; Now, if we are in semi-graphic mode we change this if def GEC_Version ld a,(TV9_SemiF) ; Semi graphic mode ? or a ; jr z TV9SCS_Write ; No, skip ; Convert the char ld a,b ; Get the char cp #40 ; In range ? jr c TV9SCS_Write ; No, skip cp #80 ; In range ? jr nc TV9SCS_Write ; No, skip ; This needs translating, so translate it... add a,#40 ; Offset to the graphics chars ld b,a ; Save the new char endif ; Write to the buffer TV9SCS_Write ld (hl),b ; Save the char inc hl ; Step ld a,(cAttr) ; Get the attribute ld (hl),a ; Save the attr ld c,a ; Save it ; Setup the Char/Attr ld d,b ; Char ld e,c ; Attr ; Write the character call TV9_Update_Curs ; Write this char ; Now step the cursor ; Are we at the RHS ? ld a,(cCur_X) ; X call TV9_RHS_Check ; jr nc TV9SCS_0 ; Yes, skip ; Move right ld a,(cCur_X) ; +1 inc a ; ld (cCur_X),a ; ; Enable the cursor again TV9SCS_1 call TV9_Show_Cursor ; Show it again ; Done, exit jp TV9SC_Exit ; Done ; Yes, move to start of next TV9SCS_0 push de ; Save char call TV9_MC_DHS ; Down, Home and Scroll if necc. pop de ; Restore jr TV9SCS_1 ; Show it ; Given A = X, check if we have hit the RHS yet (nc = RHS) TV9_RHS_Check ld b,a ; Save ld a,(TV9_80_F) ; 80 columns ? or a ; ld a,b ; Restore X jr nz TV9RC_80 ; Yes, skip ; 40 columns cp 40 ; NC = RHS ret ; TV9RC_80 cp 80 ; NC = RHS ret ; ; Given A = Y, check if we have hit the bottom yet (NC = bottom) TV9_BOTT_Check ld b,a ; Save ld a,(TV9_80_F) ; 80 columns ? or a ; ld a,b ; Restore Y jr nz TV9RC_24 ; Yes, skip ; 12 lines cp 12 ; NC = BOTTOM ret ; TV9RC_24 cp 24 ; NC = BOTTOM ret ; ; Show the TV914 cursor TV9_Show_Cursor push af ; Save ld a,(cCur_F) ; Giz the flags ; Visible ? bit bCurShown,a ; Shown ? jr nz TV9SC_X ; Yes, skip ; Should we see it ? bit bCurEnable,a ; Enabled ? jr z TV9SC_X ; No, skip ; Show it set bCurShown,a ; Assert shown ld (cCur_F),a ; ; Draw it, etc push hl ; Save push de ; push bc ; call TV9_Get_pCurs ; hl = pChar ; Get the char ld d,(hl) ; Get it inc hl ; ; Use the cursor attribute ld e,(hl) ; Attr ld a,(TV9_CurAttr) ; Get the cursor attribute xor e ; Merge the attr and %1 1 1 1 1 001 ; Use the cursor attribute xor e ; ld e,a ; Save it ; Update the screen call TV9_Update_Curs ; Show it ; Done, restore things pop bc ; Restore pop de ; pop hl ; TV9SC_X pop af ; Done, exit ret ; ; Hide the TV914 cursor TV9_Hide_Cursor push af ; Save ld a,(cCur_F) ; Giz the flags ; Visible ? bit bCurShown,a ; Shown ? jr z TV9HC_X ; No, skip res bCurShown,a ; Clear shown ld (cCur_F),a ; ; Remove it, etc push hl ; Save push de ; push bc ; ; Reset the flash time ld hl,TV9_CFT ; Reset the cursor flash time ld (Cur_F_Cnt),hl ; ; Remove the cursor call TV9_Get_pCurs ; hl = pChar ; Get the char and attr ld d,(hl) ; Get it inc hl ; ld e,(hl) ; ; Update the screen call TV9_Update_Curs ; Show it ; Done, restore things pop bc ; Restore pop de ; pop hl ; TV9HC_X pop af ; Done, exit ret ; ; Flash the TV914 cursor TV9_Flash_Cursor push hl ; Save ld hl,(Cur_F_Cnt) ; Get it dec hl ; ld (Cur_F_Cnt),hl ; ld a,l ; Z ? or h ; pop hl ; Restore jr nz TV9FC_X ; No, exit ; Is it on ? ld a,(cCur_F) ; Is it shown ? bit bCurShown,a ; jr nz TV9FC_Hide ; Yes, hide it ; It is not shown, show it pop af ; Restore jp TV9_Show_Cursor ; Show it ; Hide it TV9FC_Hide pop af ; Restore jp TV9_Hide_Cursor ; Show it ; Exit TV9FC_X pop af ; Restore ret ; Done ; Set the cursor, show iff a <> 0 TV9_Set_Cursor or a ; Set flags jp nz TV9_Show_Cursor ; NZ = Show it jp TV9_Hide_Cursor ; Z = Hide it ; Update the TV914 cursor (or any other char) given DE = Char/Attr TV9_Update_Curs ld hl,(cCur_X) ; L := X, H := Y ld a,(TV9_80_F) ; 80 columns ? or a ; jr z TV9UC_DW ; Skip if double-width jp TV9_Char ; Just write one char ; Double-width TV9UC_DW sla l ; X * 2 dec l ; X - 1 inc e ; E := E+2 (LHS) inc e ; call TV9_Char ; Write the LHS inc l ; X + 1 inc e ; E := E+2 (RHS) inc e ; jp TV9_Char ; Write the RHS ; Write a character to the display given L = X, H = Y, D= Char E = Attr TV9_Char push hl ; Save push de ; push bc ; push af ; ; Check X/Y dec l ; X = 0 .. 79 dec h ; Y = 0 .. 23 ld a,h ; Y In range ? cp 24 ; 0 .. 23 ? jr nc TV9_Fail ; No, exit ld a,l ; X In range ? cp 80 ; 0 .. 79 ? jr nc TV9_Fail ; No, exit ; Calc the screen-position ld l,h ; Get Y ld h,0 ; add hl,hl ; * 2 ld bc,VT_Y_Table_S ; Add base add hl,bc ; add a,a ; X * 2 add a,(hl) ; Add Y ld c,a ; Save it ld a,0 ; inc hl ; adc a,(hl) ; Y ld h,a ; HL := pChar ld l,c ; ; Now write char/attr ld (hl),d ; Char inc hl ; ld (hl),e ; Attr ; Done, exit TV9_Fail pop af ; Restore pop bc ; pop de ; pop hl ; ret ; Done ; Get the cursor position, HL := pChar TV9_Get_pCurs push af ; Save ; Get X/Y ld de,(cCur_X) ; E := X D := Y ; Check X/Y dec e ; X = 0 .. 79 dec d ; Y = 0 .. 23 ld a,d ; Y In range ? cp 24 ; 0 .. 23 ? jr nc TV9GpC_Fail ; No, exit ld a,e ; X In range ? cp 80 ; 0 .. 79 ? jr nc TV9GpC_Fail ; No, exit ; Calc the buffer-position ld l,d ; Get Y ld h,0 ; add hl,hl ; * 2 ld de,VT_Y_Table_B ; Add base add hl,de ; ld e,(hl) ; Get pLine inc hl ; ld d,(hl) ; add a,a ; HL := X * 2 ld l,a ; ld h,0 ; add hl,de ; Point at the char inc hl ; TV9GpC_Fail pop af ; Restore dwRet ret ; Done ; Move down and home left scrolling if required TV9_MC_DHS ld a,1 ; X = 1 ld (cCur_X),a ; ; Fall into ; Move down and scroll if required TV9_MC_DS ld a,(cCur_Y) ; At bottom ? call TV9_BOTT_Check ; jp nc TV9_SU ; Yes, scroll up ; No, move down inc a ; Down one ld (cCur_Y),a ; Save it ; Done ret ; Done ; Move up and scroll if neccessary TV9_MC_US ld a,(cCur_Y) ; Y cp 2 ; Top of display ? jp c TV9_SD ; 0,1 = top ; No, move up dec a ; -1 ld (cCur_Y),a ; Y := Y - 1 ; Done ret ; Done ; Move the cursor left to the LHS, and up if possible TV9_pcMC_L ld a,(cCur_X) ; X cp 2 ; 0 or 1 -> done jr c TV9_pcMC_L_1 ; LHS, can we move up ? call TV9_Hide_Cursor ; Hide it ld hl,cCur_X ; Dec it dec (hl) ; call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Done ; Try to move up TV9_pcMC_L_1 ld a,(cCur_Y) ; Y cp 2 ; 0/1 ? jp c TV9_pcExit ; Yes, stuck at top-left ; Move up call TV9_Hide_Cursor ; Hide it ld hl,cCur_Y ; Dec it dec (hl) ; ; Move to RHS ld a,90 ; RHS call TV9_Clip_X ; ld (cCur_X),a ; call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Exit ; Move the cursor right to the RHS, and down if possible TV9_pcMC_R ld a,(cCur_X) ; X call TV9_RHS_Check ; Hit it ? jr nc TV9_pcMC_R_1 ; RHS, can we move down ? call TV9_Hide_Cursor ; Hide it ld hl,cCur_X ; Inc it inc (hl) ; call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Done ; Try to move down TV9_pcMC_R_1 ld a,(cCur_Y) ; Y call TV9_BOTT_Check ; Hit it ? jp nc TV9_pcExit ; Yes, stuck at bottom-right ; Move down call TV9_Hide_Cursor ; Hide it ld hl,cCur_Y ; Dec it inc (hl) ; ; Move to LHS ld a,1 ; LHS ld (cCur_X),a ; call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Exit ; Perform Home TV9_pcHOME call TV9_Hide_Cursor ; Hide it ld a,1 ; Top-left ld (cCur_X),a ; ld (cCur_Y),a ; call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Exit ; Perform Cret TV9_pcCRET call TV9_Hide_Cursor ; Hide it call TV9_MC_DHS ; Do a Cret call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Exit ; Perform an LF TV9_pcLF call TV9_Hide_Cursor ; Hide it call TV9_MC_DS ; Do a down & scroll call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Exit ; Perform an Up & scroll TV9_pcUS call TV9_Hide_Cursor ; Hide it call TV9_MC_US ; Do a up & scroll call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Exit ; Move down TV9_pcMC_D ld a,(cCur_Y) ; Y call TV9_BOTT_Check ; Hit it ? jr nc TV9_pcExit ; Yes, stuck at bottom ; Move down call TV9_Hide_Cursor ; Hide it ld hl,cCur_Y ; Dec it inc (hl) ; call TV9_Show_Cursor ; Show it jp TV9_pcExit ; Exit ; Setup for a move cur string TV9_SetMoveCur ld a,2 ; Expect R&C ld (TV9_Mode),a ; ret ; Done ; Repeat char TV9_SetRepeat ld a,4 ; Mode = 4 ld (TV9_Mode),a ; ret ; Done ; Set the serial XON mode TV9_SetXON ld a,c ; Get the parameter ld (opHand),a ; Set it ret ; if def GEC_Version ; Set the semi-graphic mode TV9_SetSemiG ld a,1 ; Set it TV9_SG ld (TV9_SemiF),a ; ret ; Done ; Clr the semi-graphic mode TV9_ClrSemiG xor a ; Clear it jr TV9_SG ; As above endif ; Perform TAB operation TV9_pcTAB call TV9_Hide_Cursor ; Hide it ld a,(cCur_X) ; X dec a ; 0 .. n and #F8 ; Clip to 8 add a,9 ; Move 8 (+1) call TV9_Clip_X ; Clip the cursor ld (cCur_X),a ; Save it call TV9_Show_Cursor ; Show it jr TV9_pcExit ; Done ; Perform a CR TV9_pcLHS call TV9_Hide_Cursor ; Hide it ld a,1 ; Home ld (cCur_X),a ; call TV9_Show_Cursor ; Show it TV9_pcExit xor a ; Clear the mode ld (TV9_Mode),a ; ret ; Done ; Set the ESC "*" table TV9_SetClrTab ld hl,TV9_CLR_Tab ; Point at the escape table ld (TV9_pList),hl ; ret ; Done ; Set the ESC "." table TV9_SetCurTab ld hl,TV9_CUR_Tab ; Point at the escape table ld (TV9_pList),hl ; ret ; Done ; Set the ESC "G" table TV9_SetAttrTab ld hl,TV9_ATTR_Tab ; Point at the escape table ld (TV9_pList),hl ; ret ; Done ; Set the ESC "J" table TV9_SetCharsetTab ld hl,TV9_CHAR_Tab ; Point at the escape table ld (TV9_pList),hl ; ret ; Done ; Set the cursor shape TV9_SetCursor call TV9_Hide_Cursor ; Hide it ld a,c ; Get the parameter or a ; Kill the cursor ? jr z TV9SC_Kill ; Yes, skip ; Save the attr ld (TV9_CurAttr),a ; Save the attribute ; No, enable it ld a,%01 ; Enabled, but not shown ld (cCur_F),a ; ; Now, show the cursor call TV9_Show_Cursor ; Show it ; Exit jp TV9_pcExit ; Done ; Kill the cursor TV9SC_Kill xor a ; Kill the cursor ld (cCur_F),a ; jp TV9_pcExit ; Done ; Set the text attribute TV9_SetAttr ld a,c ; Get the attribute ld (cAttr),a ; Save it jp TV9_pcExit ; Done ; Clear the display TV9_dwCLS call TV9_Hide_Cursor ; Hide it ; Clear the display call TV9_CLS ; Clear it ; Show the cursor again call TV9_Show_Cursor ; Show the cursor ; Exit jp TV9_pcExit ; Done ; Clear it ; TV9_CLS push bc ; Save the char ld a,(TV9_80_F) ; 80 or 40 ? or a ; jr z TV9_CLS_40 ; 40, skip ; 80 by 24 ld hl,aVDU_Base ; Point at the display ld (hl),c ; Write the NULL/SPACE inc hl ; ld (hl),%0 0 0 1 0 000 ; Attr inc hl ; ex de,hl ; Into DE ld hl,aVDU_Base ; Base ld bc,80*2*24 - 2 ; Small chars ldir ; Clear it pop bc ; Restore the char ; Now clear the buffer ld hl,VDU_Buffer ; Point at the buffer ld b,24 ; Small chars ; Clear one line at a time TV9_CLS80_Lp push bc ; Save cnt ld (hl),0 ; SOL inc hl ; ld d,h ; Save ptr ld e,l ; ld (hl),c ; Write the NULL/SPACE inc hl ; ld (hl),%0 0 0 1 0 000 ; Attr inc hl ; ex de,hl ; Into DE ld bc,80*2 - 2 ; Clear one line ldir ; Clear it ex de,hl ; Point at the next pop bc ; Loop djnz TV9_CLS80_Lp ; Loop ; Restore the cursor ld a,1 ; TL ld (cCur_X),a ; ld (cCur_Y),a ; ret ; Done ; 40 by 12 TV9_CLS_40 ld hl,aVDU_Base ; Point at the display ld (hl),c ; Write the NULL/SPACE inc hl ; ld (hl),%0 0 0 1 0 010 ; Attr inc hl ; ld (hl),c ; Write the NULL/SPACE inc hl ; ld (hl),%0 0 0 1 0 100 ; Attr inc hl ; ex de,hl ; Into DE ld hl,aVDU_Base ; Base ld bc,80*2*24 - 4 ; Small chars ldir ; Clear it pop bc ; Restore the char ; Now clear the buffer ld hl,VDU_Buffer ; Point at the buffer ld b,12 ; Small chars jr TV9_CLS80_Lp ; As above ; Clip A into the range 1 .. Width TV9_Clip_X ld b,a ; Save X ld a,(TV9_80_F) ; 80 columns ? or a ; ld a,b ; Restore X jr nz TV9_CX_80 ; Yes, skip cp 40 ; 0 .. 40 ? ret c ; Yes, exit ld a,40 ; Clip it ret ; TV9_CX_80 cp 80 ; 0 .. 80 ? ret c ; ld a,80 ; Clip it ret ; ; Clip A into the range 1 .. Height TV9_Clip_Y ld b,a ; Save Y ld a,(TV9_80_F) ; 24 lines ? or a ; ld a,b ; Restore Y jr nz TV9_CX_24 ; Yes, skip cp 12 ; 0 .. 12 ? ret c ; Yes, exit ld a,12 ; Clip it ret ; TV9_CX_24 cp 24 ; 0 .. 24 ? ret c ; ld a,24 ; Clip it ret ; ; Scroll the TV914 display down TV9_SD ld h,1 ; Top-line ld a,30 ; Find bottom line call TV9_Clip_Y ; ld l,a ; Bottom line call VT_Scroll_Lines ; Scroll the display ret ; ; Scroll the TV914 display up TV9_SU ld l,1 ; Top-line ld a,30 ; Find bottom line call TV9_Clip_Y ; ld h,a ; Bottom line call VT_Scroll_Lines ; Scroll the display ret ; ; Setup the VT100 driver Setup_VT100 call VT_Setup_Chars ; Draw the character-sets ; Now we do everything except the chars Setup_VT100_NC ld hl,VDU_Buffer ; Point at the screen map ld c,25 ; This many lines SVT_Lp ld (hl),0 ; Clear the size inc hl ; ld b,80 ; This many chars SVT_Lp2 ld (hl)," " ; Char inc hl ; ld (hl),%0 0 0 1 0 000 ; Attr inc hl ; djnz SVT_Lp2 ; Loop dec c ; Loop jr nz SVT_Lp ; ; Now clear the physical screen ld hl,aVDU_Base ; ld de,aVDU_Base+2 ; ld bc,80*2*25-2 ; ld (hl)," " ; Blank inc hl ; ld (hl),%0 0 0 1 0 000 ; dec hl ; ldir ; Clear it ; Reset everything else call Setup_Timing_25 ; Reset the VDU timing ; Set the Flashing mode ld a,0 ; Flash as a VT100 ld (Flash_Mode),a ; ; Now, setup the cursor ld a,%0 0 0 1 0 000 ; Normal on Black ld (cAttr),a ; ld a,1 ; 01 ld (cCur_X),a ; X ld (cCur_Y),a ; X ld (cCur_F),a ; 01 (Enabled, not shown) ; Margins ld a,1 ; Whole screen ld (cTop_M),a ; ld a,25 ; ld (cBott_M),a ; ; Vars xor a ; 00 ld (Hack_RHS),a ; ld (VT_Mode),a ; ; Ignore char set flags call VT_Show_Cursor ; Show the cursor ; Clear the frame number ld hl,0 ; Clear the frame count ld (Frame_No),hl ; ; Setup flash rates ld a,iFl_0 ; 0 ld (Flash_0),a ; ld a,iFl_1 ; 1 ld (Flash_1),a ; ; Done ret ; Done ; The main VT100 show char routine VT_Show_Char push hl ; Save push de ; push bc ; push af ; ; Esc ? cp cEsc ; Escape ? jr z VTSC_Esc ; Yes, skip ld d,a ; Save the char ; What mode are we in ? ld a,(VT_Mode) ; Giz the mode ld e,a ; Save or a ; jr z VTSC_Char ; Not waiting, skip ; We are waiting, have we got a cancel ? ld a,d ; Char cp #18 ; CANCEL ? jr z VTSC_ExitChar ; Yes cp #1A ; CANCEL ? jr z VTSC_ExitChar ; Yes ; Check the mode dec e ; Mode = 1 ? jr z VTSC_HaveList ; Yes, skip ; Reset back to expecting char VTSC_ExitChar xor a ; Mode := 0 ld (VT_Mode),a ; ; Exit VTSC_Exit pop af ; Restore pop bc ; pop de ; pop hl ; ret ; Done ; Normal character handler VTSC_Char ld a,d ; Giz char cp #20 ; 00 .. 1F Ctrl ? jr nc VTSC_Show ; No, show it ; Yes ld hl,VT_CTRL_Tab ; Point at the table call FindChar ; Look for this char in the list jr c VTSC_Show ; Not found, show it as it is ; Now jr VTSCEC_DoIt ; Drive it ; We have an ESC, setup mode VTSC_Esc ld a,1 ; Mode := 1 ld (VT_Mode),a ; ld hl,VT_ESC_Tab ; Point at the ESC table ld (VT_pList),hl ; Save it jp VTSC_Exit ; Exit ; We have a list of possible chars VTSC_HaveList ld hl,(VT_pList) ; Get the ptr ; Look it up VTSC_ExecChar call FindChar ; Look for this char in the list jr c VTSC_ExitChar ; Not found, exit ; Found, call the driver routine VTSCEC_DoIt call CallHL ; Call the driver ; Clear the RHS hack xor a ; Clear the RHS hack flag ld (Hack_RHS),a ; ; Done, exit jp VTSC_Exit ; Exit ; Show this character (in D) VTSC_Show call VT_Hide_Cursor ; Remove the cursor ; Is the cursor at the RHS ? call VT_Get_Cur_LW ; Get the width of this line ld b,a ; Save ld a,(cCur_X) ; Get the Cur X cp b ; RHS ? jr nz VTSCS_0c ; No, clear the flag we are not RHS ; Was it at the RHS last time ? (Isn't this crappy !) ld a,(Hack_RHS) ; Flag or a ; jr z VTSCS_0s ; No, set flag and print here ; Yes, move to start of next push de ; Save char call VT_MC_DHS ; Down, Home and Scroll if necc. pop de ; Restore jp VTSCS_0c ; Skip ; We are at the RHS for the first time, set flag and print here VTSCS_0s ld a,1 ; Set the flag ld (Hack_RHS),a ; jp VTSCS_1 ; Skip ; Clear the flag, we are not at the RHS VTSCS_0c xor a ; Clear ld (Hack_RHS),a ; ; Show the char VTSCS_1 ld b,d ; Save the char call VT_Get_pCurs ; Point at it ; Write to the buffer ld (hl),b ; Save the char inc hl ; Step ld a,(cAttr) ; Get the attribute ld (hl),a ; Save the attr ld c,a ; Save it ; Now, get the size info ld a,(de) ; Get the line-size ; Setup the Char/Attr ld d,b ; Char ld e,c ; Attr ld c,a ; Size ; Write the character call VT_Update_Curs ; Write this char ; Now step the cursor ld a,(Hack_RHS) ; RHS ? or a ; jr nz VTSCS_RHS ; Yes, skip ; Move right ld a,(cCur_X) ; +1 inc a ; ld (cCur_X),a ; ; Enable the cursor again VTSCS_RHS call VT_Show_Cursor ; Show it again ; Done, exit jp VTSC_Exit ; Done ; Move down and home left scrolling if required VT_MC_DHS ld a,1 ; X = 1 ld (cCur_X),a ; ; Fall into ; Move down and scroll if required VT_MC_DS ld a,(cBott_M) ; Bottom Y ld c,a ; Save ; Bottom margin ? ld a,(cCur_Y) ; Current Y cp c ; At bottom ? jr z VT_MCDS_SU ; Yes, scroll up ; Bottom of screen ? cp 25 ; Bottom of screen jr z VT_MCDS_X ; Yes, skip ; No, move down inc a ; Down one ld (cCur_Y),a ; Save it ; Clip X ld a,(cCur_X) ; Get ze X call VT_Clip_X ; ld (cCur_X),a ; ; Done VT_MCDS_X ret ; Done ; Scroll up the scrolling region VT_MCDS_SU ld hl,(cTop_M) ; L = Top H = Bottom jp VT_Scroll_Lines ; Scroll them ; Move up and scroll if neccessary VT_MC_US ld a,(cCur_Y) ; Y cp 2 ; Top of display ? jr c VT_MCUS_SD ; 0,1 = top ; Top margin ? ld c,a ; Save Y ld a,(cTop_M) ; Top cp c ; Hit it ? jr z VT_MCUS_SD ; Top, scroll ; No, move up ld a,c ; Y dec a ; -1 ld (cCur_Y),a ; Y := Y - 1 ; Clip X ld a,(cCur_X) ; Get ze X call VT_Clip_X ; ld (cCur_X),a ; ; Done ret ; Done ; Scroll down the scrolling region VT_MCUS_SD ld hl,(cTop_M) ; L = Top H = Bottom ld a,l ; Swap them ld l,h ; ld h,a ; jp VT_Scroll_Lines ; Scroll them ; Change character sets (ignored for now) VT_pcSetCS equ VT_pcExit VT_pcCharSet equ VT_pcExit ; Move the cursor left to the LHS VT_pcMC_L ld a,(cCur_X) ; X cp 2 ; 0 or 1 -> done jr c VT_pcExit ; Done call VT_Hide_Cursor ; Hide it ld hl,cCur_X ; Dec it dec (hl) ; call VT_Show_Cursor ; Show it jr VT_pcExit ; Done ; Perform TAB operation VT_pcTAB call VT_Hide_Cursor ; Hide it ld a,(cCur_X) ; X dec a ; 0 .. n and #F8 ; Clip to 8 add a,9 ; Move 8 (+1) call VT_Clip_X ; Clip the cursor ld (cCur_X),a ; Save it call VT_Show_Cursor ; Show it jr VT_pcExit ; Done ; Perform a Cret VT_pcCRET call VT_Hide_Cursor ; Hide it call VT_MC_DHS ; Down, Home, Scroll call VT_Show_Cursor ; Show it VT_pcExit xor a ; Clear the mode ld (VT_Mode),a ; ret ; Done ; Perform a LHS VT_pcLHS call VT_Hide_Cursor ; Hide it ld a,1 ; Home ld (cCur_X),a ; call VT_Show_Cursor ; Show it xor a ; Clear the mode ld (VT_Mode),a ; ret ; Done ; Set the ESC mode VT_pcSetESC ld hl,VT_ESC_Tab ; Point at the escape table ld (VT_pList),hl ; ret ; Done ; Set the CMD mode VT_pcSetCMD ld hl,VT_CMD_Tab ; Point at the command table jr VT_Set_Param ; Set it ; Extended CMD mode "ESC [ ?" VT_pcSet_EXT_Q ld hl,VT_EXT_Q_Tab ; Point at another one VT_Set_Param ld (VT_pList),hl ; ; Now point at the parameter list ld hl,Parameters ; Point at them ld (VT_pParam),hl ; Set the ptr VT_Clear_Param ld a,#ff ; -1 ld (hl),a ; -1 inc hl ; ld (hl),a ; inc hl ; ld (hl),a ; -1 (Term) inc hl ; ld (hl),a ; ; Done ret ; Done ; Set the CHARS mode VT_pcSetCHARS ld hl,VT_CHARS_Tab ; Point at the chars table ld (VT_pList),hl ; ; ld a,c ; Save the ; ld (blah),a ; G0 or G1 ret ; Done ; Set the SIZE mode VT_pcSetSIZE ld hl,VT_SIZE_Tab ; Point at the size table ld (VT_pList),hl ; ret ; Done ; ; Move down/scroll VT_pcDS call VT_Hide_Cursor ; Hide it call VT_MC_DS ; Down, Scroll call VT_Show_Cursor ; Show it jp VT_pcExit ; Reset mode ; Move up/scroll VT_pcUS call VT_Hide_Cursor ; Hide it call VT_MC_US ; Up, Scroll call VT_Show_Cursor ; Show it jp VT_pcExit ; Reset mode ; Save cursor and attr VT_pcSave ld hl,(cCur_X) ; Save pos ld (sCur_X),hl ; ld a,(Hack_RHS) ; Hack ld (sHack_RHS),a ; ld a,(cAttr) ; Attr ld (sAttr),a ; jp VT_pcExit ; Reset mode ; Restore from a saved state VT_pcRestore call VT_Hide_Cursor ; Hide it ld a,(sCur_Y) ; Restore the Y ld (cCur_Y),a ; ld a,(sCur_X) ; Clip the X call VT_Clip_X ; ld (cCur_X),a ; ld a,(sHack_RHS) ; This isn't right if clipped !! ld (Hack_RHS),a ; ld a,(sAttr) ; Attribute ld (cAttr),A ; call VT_Show_Cursor ; Show it jp VT_pcExit ; Clear mode ; Now we have the ESC [ x codes ; We have a digit, drive the current parameter VT_pcP_Digit ld hl,(VT_pParam) ; Point at the current parameter ld b,0 ; bc = new ld e,(hl) ; Get the current value inc hl ; ld d,(hl) ; dec hl ; ; Used yet ? ld a,e ; -1 ? and d ; inc a ; jr z VT_pcPD_1 ; No, it needs starting ; It is started ex de,hl ; Save ld a,c ; Save new no. ld c,l ; Dup ld b,h ; add hl,hl ; * 2 add hl,hl ; * 4 add hl,bc ; * 5 add hl,hl ; * 10 ld c,a ; Next digit ld b,0 ; add hl,bc ; Add it ex de,hl ; Swap ld c,e ; Into bc ld b,d ; ; Write it VT_pcPD_1 ld (hl),c ; Save it inc hl ; ld (hl),b ; ; Done ret ; Done ; Skip parameter VT_pcP_NextP ld de,(VT_pParam) ; Point at it ld hl,Last_Param ; Point at the end or a ; End ? sbc hl,de ; ret z ; Yes, exit ; No, skip this one ex de,hl ; hl := ptr inc hl ; Skip it inc hl ; ld (VT_pParam),hl ; Save the ptr jp VT_Clear_Param ; Clear it ; Move the cursor to a given position VT_pcP_YX push ix ; Save call VT_Hide_Cursor ; Hide it ld hl,1 ; Assume 1 call VT_Read_Param_F ; Get the first parameter ld a,l ; Get Y call VT_Clip_Y ; Clip it ld (cCur_Y),a ; Save it ld hl,1 ; Assume 1 call VT_Read_Param ; Get the next parameter ld a,l ; Get X call VT_Clip_X ; Clip it ld (cCur_X),a ; Save it call VT_Show_Cursor ; Show it pop ix ; Done jp VT_pcExit ; Exit ; Move up (clip) VT_MC_U ld a,(cCur_Y) ; Y cp 1 ; Top ? ret z ; Yes, exit ld c,a ; Save ld a,(cTop_M) ; Top of scrollable area cp c ; Top ? ret z ; Yes, exit ld a,c ; Y dec a ; Y - 1 VT_MC_U_1 ld (cCur_Y),a ; Y := Y - 1 ; Clip X ld a,(cCur_X) ; Get ze X call VT_Clip_X ; ld (cCur_X),a ; ; Done ret ; Done ; Move down (clip) VT_MC_D ld a,(cCur_Y) ; Y cp 25 ; Top ? ret z ; Yes, exit ld c,a ; Save ld a,(cBott_M) ; Top of scrollable area cp c ; Top ? ret z ; Yes, exit ld a,c ; Y inc a ; Y + 1 jr VT_MC_U_1 ; As above ; Move left (clip) VT_MC_L ld a,(cCur_X) ; X cp 1 ; LHS ? ret z ; Yes, exit dec a ; - 1 ld (cCur_X),a ; ret ; Done ; Move right (clip) VT_MC_R call VT_Get_Cur_LW ; A := Width ld c,a ; Save ; RHS ? ld a,(cCur_X) ; X cp c ; RHS ? ret z ; Yes, exit inc a ; + 1 ld (cCur_X),a ; ret ; Done ; Move up n times VT_pcP_U ld hl,VT_MC_U ; Point at the routine jr VT_pcP_Perform ; Do it ; Move down n times VT_pcP_D ld hl,VT_MC_D ; Point at the routine jr VT_pcP_Perform ; Do it ; Move left n times VT_pcP_L ld hl,VT_MC_L ; Point at the routine jr VT_pcP_Perform ; Do it ; Move right n times VT_pcP_R ld hl,VT_MC_R ; Point at the routine ; Fall into VT_pcP_Perform push ix ; Save ptr push hl ; Save the ptr call VT_Hide_Cursor ; Hide the cursor ; Get the repeat count call VT_Get_Param_Cnt ; Giz the number ld c,l ; BC := HL ld b,h ; pop hl ; Restore ptr ; Repeat this fn n times VT_pcPP_Lp push hl ; Save push bc ; call CallHL ; Call the routine pop bc ; Restore pop hl ; dec bc ; Loop ld a,c ; or b ; jr nz VT_pcPP_Lp ; ; Replace cursor call VT_Show_Cursor ; Show it ; Done pop ix ; Restore jp VT_pcExit ; Clear mode ; Set the attribute VT_pcP_Attr push ix ; Save ld hl,0 ; Assume 0 call VT_Read_Param_F ; Get the first one call VT_Drive_Attr ; Drive it ; Now, process as many as there are VT_pcPA_Lp ld hl,0 ; Assume 0 call VT_Read_Param ; Get the next one jr c VT_pcPA_X ; No more, exit call VT_Drive_Attr ; Do it jr VT_pcPA_Lp ; Loop VT_pcPA_X pop ix ; Restore jp VT_pcExit ; Exit ; Drive the attribute (in HL) VT_Drive_Attr ld a,(cAttr) ; Get the current state ld h,a ; Save ld a,l ; Giz the # cp 0 ; 0 ? jr z VTDA_0 ; cp 1 ; 1 ? jr z VTDA_1 ; cp 2 ; 2 ? jr z VTDA_2 ; cp 4 ; 4 ? jr z VTDA_4 ; cp 5 ; 5 ? jr z VTDA_5 ; cp 7 ; 7 ? ret nz ; No, exit ; Inverse ld a,h ; Current rlca ; Shift and %0 1 0 1 0 000 ; New foreground ld l,a ; Save ld a,h ; Current rrca ; Shift and %0 0 1 0 1 000 ; New background or l ; Merge xor h ; Combine with old and %1 1 1 1 1 000 ; Get the bottom 3 bits from old xor h ; ld (cAttr),a ; Set it ret ; Done ; 0 ( clear attrs ) VTDA_0 ld a,%0 0 0 1 0 000 ; Normal ld (cAttr),a ; ret ; Done ; 1 ( Bold (F1) ) VTDA_1 ld a,h ; Get them and %0 0 1 0 1 111 ; Clip out foreground or %0 1 0 0 0 000 ; Foreground = F1 ld (cAttr),a ; Save it ret ; Done ; 2 ( Normal ) VTDA_2 ld a,h ; Get them and %0 0 1 0 1 111 ; Clip out foreground or %0 0 0 1 0 000 ; Foreground = Normal ld (cAttr),a ; Save it ret ; Done ; 4 ( underline ) VTDA_4 ld a,h ; Get them or %0 0 0 0 0 001 ; Set underline ld (cAttr),a ; Save it ret ; Done ; 5 ( Flash) VTDA_5 ld a,h ; Get them and %0 0 1 0 1 111 ; Clip out foreground or %0 1 0 1 0 000 ; Foreground = F2 ld (cAttr),a ; Save it ret ; Done ; Set the scroll region VT_pcP_Scroll push ix ; Save ; Top ld hl,1 ; Assume 1 call VT_Read_Param_F ; Get a parameter ld a,l ; Clip it call VT_Clip_Y ; push af ; Save it ; Bottom ld hl,25 ; Assume 25 call VT_Read_Param ; Get a parameter ld a,l ; Clip it call VT_Clip_Y ; pop hl ; Restore ; Are these valid ? cp h ; Bottom < Top ? jr z VT_pcPS_Fail ; No, exit jr c VT_pcPS_Fail ; No, exit ; They are valid, use them ld (cBott_M),a ; Save Bottom ld a,h ; ld (cTop_M),a ; Top ; Home the cursor call VT_Hide_Cursor ; Hide it ld a,1 ; Top-left ld (cCur_X),a ; ld (cCur_Y),a ; call VT_Show_Cursor ; Show it ; Exit VT_pcPS_Fail pop ix ; Restore jp VT_pcExit ; Done ; Drive the cursor on VT_pcCur_On push ix ; Save call VT_Get_Param_Cnt ; Giz the first parameter ; The parameter MUST BE 25 ld de,25 ; 25 or a ; sbc hl,de ; Is it ? jr nz VT_pcCO_X ; No, skip ; Turn it on ld a,(cCur_F) ; Set the enable set bCurEnable,a ; ld (cCur_F),a ; ; Show it call VT_Show_Cursor ; Show it ; Exit VT_pcCO_X pop ix ; Done jp VT_pcExit ; ; Drive the cursor off VT_pcCur_Off push ix ; Save call VT_Get_Param_Cnt ; Giz the first parameter ; The parameter MUST BE 25 ld de,25 ; 25 or a ; sbc hl,de ; Is it ? jr nz VT_pcCO_X ; No, skip ; Turn it off ld a,(cCur_F) ; Set the enable res bCurEnable,a ; ld (cCur_F),a ; ; Hide it call VT_Hide_Cursor ; Hide it ; Exit pop ix ; Done jp VT_pcExit ; ; Erase in line VT_pcP_Er_Line push ix ; Save call VT_Get_Param_Er ; Get 0,1,2 ; Erase in the cursor line call VT_Er_In_Cur_L ; To start/end of line jr VT_pcPED_X ; Exit ; Erase in display VT_pcP_Er_Disp push ix ; Save call VT_Get_Param_Er ; Get 0,1,2 cp 2 ; Whole screen ? jr z VT_pcPED_2 ; Yes, skip ; Erase in the cursor line call VT_Er_In_Cur_L ; To start/end of line ; Now erase whole lines or a ; 0 ? (To End) jr z VT_pcPED_0 ; Yes, skip ; Erase whole lines from Y-1 to top ld a,(cCur_Y) ; Get the current line ld c,a ; Save ld a,1 ; Top line VT_pcPED_Lp1 cp c ; Cursor line ? jr z VT_pcPED_X ; Yes, done, exit call VT_Clear_Line ; Clear it inc a ; Step down jr VT_pcPED_Lp1 ; Loop ; End VT_pcPED_X pop ix ; Done jp VT_pcExit ; Exit ; To end VT_pcPED_0 ld a,(cCur_Y) ; Get the current line VT_pcPED_Lp0 cp 25 ; End ? jr z VT_pcPED_X ; Yes, done, exit inc a ; Move down call VT_Clear_Line ; Clear it jr VT_pcPED_Lp0 ; Loop ; Whole screen VT_pcPED_2 call VT_Hide_Cursor ; Hide it ld a,1 ; Top line VT_pcPED_Lp2 call VT_Clear_Line ; Clear it inc a ; Move down cp 26 ; Off bottom ? jr nz VT_pcPED_Lp2 ; No, loop call VT_Show_Cursor ; Show it jr VT_pcPED_X ; Exit ; Erase in a line VT_Er_In_Cur_L push af ; Save call VT_Get_pCurs ; Point at the cursor inc de ; From the start pop af ; Restore type push af ; or a ; 0 = to end jr z VTEIC_0 ; Yes, skip dec a ; 1 = To beginning jr z VTEIC_1 ; Yes ; Erase the whole line ld h,d ; Dup ld l,e ; ld (hl)," " ; Blank inc hl ; ld (hl),%0 0 0 1 0 000 ; inc hl ; ex de,hl ; ld bc,79*2 ; This many ldir ; Clear it ; Show this line VTEIC_Done call VT_Hide_Cursor ; Hide it ; Redraw screen line ld a,(cCur_Y) ; Get the Y call VT_Redraw_Line ; Redraw this line call VT_Show_Cursor ; Show it pop af ; Restore ret ; Done ; From the beginning VTEIC_1 ex de,hl ; hl points at the SOL ld a,(cCur_X) ; How many chars ? ld b,a ; VTEIC_Lp1 ld (hl)," " ; Clear one inc hl ; ld (hl),%0 0 0 1 0 000 ; inc hl ; djnz VTEIC_Lp1 ; Loop jr VTEIC_Done ; Exit ; To the end VTEIC_0 ld a,(cCur_X) ; Posn ld b,a ; Save ld a,81 ; RHS+1 sub b ; Length to RHS + 1 ld b,a ; Into B jr VTEIC_Lp1 ; As above ; Redraw a line from the buffer to the screen, given A=Y VT_Redraw_Line dec a ; 0 .. 24 cp 25 ; In range ? ret nc ; ; Calc ptrs add a,a ; * 2 add a,a ; * 4 add a,VT_Line_Tab and #FF ; Add base ld l,a ; adc a,VT_Line_Tab/256 ; sub l ; ld h,a ; ; Get ptr to VDU ld e,(hl) ; DE := pVDU inc hl ; ld d,(hl) ; inc hl ; ld a,(hl) ; HL := pBuffer inc hl ; ld h,(hl) ; ld l,a ; ; Get line size ld a,(hl) ; Size inc hl ; bit 0,a ; NZ = 40 chars jr nz VTRL_40 ; Yes, skip ; 80 chars, just copy the line ld bc,80*2 ; This many ldir ; Copy ret ; Done ; Double-width line VTRL_40 ld b,40 ; This many chars ex de,hl ; de := src VTRL_Lp ld a,(de) ; Get the char inc de ; ld (hl),a ; Save char inc hl ; ld c,a ; Save ld a,(de) ; Giz attr inc de ; or %0 0 0 0 0 0 1 0 ; LHS ld (hl),a ; Save attr inc hl ; ld (hl),c ; Char inc hl ; add a,2 ; RHS ld (hl),a ; Save attr inc hl ; djnz VTRL_Lp ; Loop ret ; Done ; Set the size of the cursor line VT_pcSetSize ld a,c ; Get the parameter jp VT_Set_Size ; Set the line size ; Set the character size of the cursor line given a = flags VT_Set_Size push af ; Save the flags call VT_Hide_Cursor ; Hide it call VT_Get_pCurs ; Point at it pop af ; Restore ex de,hl ; HL := pSize ; Change size flag ld c,a ; Save the new size xor (hl) ; Same ? jr z VTSS_X ; Yes, exit ; Different, we must change the flag ld (hl),c ; Write the new flag ; Now, did the Y change ? push af ; Save the changed bits and %11 0 ; Has the Y changed ? jr z VTSS_Do_X ; No, skip ; Now, drive the Y change ; Calc addresses to change ld a,(cCur_Y) ; Y dec a ; 0 .. 24 add a,a ; * 2 add a,VT_Line_Ys_NS and #FF; Add base ld l,a ; adc a,VT_Line_Ys_NS / 256 ; sub l ; ld h,a ; ; Now, we must move onto the next table if shrunk ld de,(VTY_Offset) ; Move if required add hl,de ; ; Look-up the line address ld a,(hl) ; inc hl ; ld h,(hl) ; ld l,a ; ; Now, skip if we're in the shrunk mode ld a,(opShrunk) ; Shrunk ? cp 2 ; jr z VTSS_Shrunk ; Yes, skip ; Now see what type of change ld a,c ; Get the size and %11 0 ; Y's only jr z VTSS_S ; Single, skip ld c,%0 1 0 0 0000 ; Assume top cp %10 0 ; Top ? jr z VTSS_D ; Yes, skip ld c,%0 1 0 0 1000 ; Line 8 .. 15 doubled VTSS_D ld b,8 ; 8 pairs of lines ld de,3 ; Offset VTSS_D_Lp ld (hl),c ; Write it add hl,de ; ld (hl),c ; add hl,de ; inc c ; next line djnz VTSS_D_Lp ; Loop ; Drive the X changed VTSS_Do_X pop af ; Restore and %00 1 ; Width changed ? jr z VTSS_X ; No, skip ; Width changed, redraw screen ld a,(cCur_Y) ; Get the Y call VT_Redraw_Line ; Show it ; Done VTSS_X ld a,(cCur_X) ; Clip the X call VT_Clip_X ; ld (cCur_X),a ; call VT_Show_Cursor ; Show it jp VT_pcExit ; Done ; Set single line mode VTSS_S ld b,16 ; 16 Lines ld de,3 ; Offset ld a,%0 1 0 0 0000 ; Line 0 VTSS_S_Lp ld (hl),a ; Write it add hl,de ; inc a ; next line djnz VTSS_S_Lp ; Loop jr VTSS_Do_X ; Drive the X ; ; Now we have it all again in shrunk mode VTSS_Shrunk ld a,c ; Get the size and %11 0 ; Y's only jr z VTSS_12_S ; Single, skip ld c,%0 1 0 0 0000 ; Assume top cp %10 0 ; Top ? jr z VTSS_12_D ; Yes, skip ld c,%0 1 0 0 0110 ; Line 6 .. 11 doubled VTSS_12_D ld b,6 ; 6 pairs of lines ld de,3 ; Offset VTSS_12_D_Lp ld (hl),c ; Write it add hl,de ; ld (hl),c ; add hl,de ; inc c ; next line djnz VTSS_12_D_Lp ; Loop ; Drive the X changed jr VTSS_Do_X ; Restore, as above ; Set single line mode VTSS_12_S ld b,12 ; 12 Lines ld de,3 ; Offset ld a,%0 1 0 0 0000 ; Line 0 jr VTSS_S_Lp ; Write it, as above ; ; Get a count parameter VT_Get_Param_Cnt ld hl,1 ; Assume 1 if default call VT_Read_Param_F ; Get the first param ld a,l ; 0 ? or h ; ret nz ; No, exit ld hl,1 ; Should be 1 ret ; Done ; Get an erase parameter VT_Get_Param_Er ld hl,0 ; Assume 0 if default call VT_Read_Param_F ; Get the first param ld a,l ; 0 ? cp 3 ; 0,1,2 ? ret c ; Yes, exit xor a ; Else 0 ret ; Done ; Read the first parameter into HL (or leave default untouched) CF = End VT_Read_Param_F ld ix,Parameters ; Point at the first ; Fall into VT_Read_Param push hl ; Save the default ld hl,(VT_pParam) ; The last one written inc hl ; The term inc hl ; push ix ; cp hl,ix pop de ; or a ; sbc hl,de ; jr z VT_RP_End ; End, use default ; Not at the end, get it ld l,(ix) ; Get the next parameter inc ix ; ld h,(ix) ; inc ix ; ; Is this a default value ? ld a,l ; -1 and h ; inc a ; jr z VT_RP_Def ; Yes, use default pop af ; Dump the default or a ; NC ret ; Done ; Use the default value VT_RP_Def pop hl ; Restore default or a ; NC ret ; Done VT_RP_End pop hl ; Restore default scf ; Flag end ret ; Done ; Clip A into the current line width VT_Clip_X cp 2 ; 0,1 return 1 jr c VTCX_r1 ; 1 ; Is it <= 40 ? cp 41 ; 1 .. 40 must be ok ret c ; Yes, exit ; Now, check against the current linewidth ld c,a ; Save the X call VT_Get_Cur_LW ; Giz the width cp c ; Valid ? ret c ; No, return width ld a,c ; Invalid, return RHS ret ; Done ; Return 1 VTCX_r1 ld a,1 ; 1 ret ; Done ; Clip A into 1 .. 25 VT_Clip_Y cp 2 ; 0,1 return 1 jr c VTCX_r1 ; 1 ; Is it <= 25 ? cp 26 ; 1 .. 25 must be ok ret c ; Yes, exit ld a,25 ; Return bottom ret ; Done ; Scroll from line H to line L VT_Scroll_Lines ld a,l ; One line ? cp h ; jr z VT_Clear_Line ; Yes, clear line A ; Now scroll from L to H jr nc VTSL_D_Lp ; Scroll down ; Scrolling up from H to L VTSL_U_Lp ld b,a ; b = next inc b ; Move down call VT_Copy_Line ; Copy b to a ld a,b ; Point at the scr cp h ; End line ? jr nz VTSL_U_Lp ; No, loop ; End, clear it jp VT_Clear_Line ; Clear it ; Scrolling down from H to L VTSL_D_Lp ld b,a ; b = next dec b ; Move up call VT_Copy_Line ; Copy b to a ld a,b ; Point at the scr cp h ; End line ? jr nz VTSL_D_Lp ; No, loop ; End, clear it jp VT_Clear_Line ; Clear it ; Clear a line, given A = Y VT_Clear_Line push hl ; Save push de ; push bc ; push af ; ; Calc ptrs dec a ; 0 .. 24 cp 25 ; jr nc VTCL_X ; No, exit ; Calc ptrs add a,a ; * 2 ld e,a ; Save add a,a ; * 4 add a,VT_Line_Tab and #FF ; Add base ld l,a ; adc a,VT_Line_Tab/256 ; sub l ; ld h,a ; ; Now, clear them ld c,(hl) ; Get the ptrs inc hl ; ld b,(hl) ; inc hl ; push bc ; Save ld a,(hl) ; inc hl ; ld h,(hl) ; ld l,a ; HL = pBuffer ld a,(hl) ; Check if the Y is non-std and %11 0 ; Mask jr z VTCL_1 ; Ok, skip ; This line needs converting push hl ; Save ld a,e ; Y * 2 add a,VT_Line_Ys_NS and #FF; Add base ld l,a ; adc a,VT_Line_Ys_NS / 256 ; sub l ; ld h,a ; ; Now, we must move onto the next table if shrunk ld de,(VTY_Offset) ; Move if required add hl,de ; ld a,(hl) ; inc hl ; ld h,(hl) ; ld l,a ; ; Set single line mode ld a,(nLPC) ; This many lines ld b,a ; Per char ld de,3 ; Offset ld a,%0 1 0 0 0000 ; Line 0 VTCL_S_Lp ld (hl),a ; Write it add hl,de ; inc a ; next line djnz VTCL_S_Lp ; Loop pop hl ; Restore ; Clear the buffer VTCL_1 ld (hl),0 ; Clear the size inc hl ; ld a," " ; Blank ld c,%0 0 0 1 0 000 ; ld b,80/4 VTCL_Lp1 ld (hl),a ; Clear inc hl ; ld (hl),c ; inc hl ; ld (hl),a ; Clear inc hl ; ld (hl),c ; inc hl ; ld (hl),a ; Clear inc hl ; ld (hl),c ; inc hl ; ld (hl),a ; Clear inc hl ; ld (hl),c ; inc hl ; djnz VTCL_Lp1 ; Loop ; Now clear the display pop hl ; Restore ptr ; HL = pVDU ld a," " ; Blank ld c,%0 0 0 1 0 000 ; ld b,80/4 VTCL_Lp2 ld (hl),a ; Clear inc hl ; ld (hl),c ; inc hl ; ld (hl),a ; Clear inc hl ; ld (hl),c ; inc hl ; ld (hl),a ; Clear inc hl ; ld (hl),c ; inc hl ; ld (hl),a ; Clear inc hl ; ld (hl),c ; inc hl ; djnz VTCL_Lp2 ; Loop ; Done, exit VTCL_X pop af ; Restore pop bc ; pop de ; pop hl ; ret ; Done ; Copy a line B = Src A = Dst VT_Copy_Line push hl ; Save push de ; push bc ; ld c,a ; Save Dst push bc ; ; Calc ptrs dec a ; 0 .. 24 cp 25 ; jr nc VTCpL_X ; No, exit ; Calc ptrs add a,a ; * 2 add a,a ; * 4 add a,VT_Line_Tab and #FF ; Add base ld l,a ; adc a,VT_Line_Tab/256 ; sub l ; ld h,a ; ; Now, get the ptrs ld e,(hl) ; Get the ptrs inc hl ; ld d,(hl) ; inc hl ; push de ; Save ptr VDU ld a,(hl) ; inc hl ; ld h,(hl) ; ld l,a push hl ; Save ptr Buffer ; Calc ptrs ld a,b ; Src dec a ; 0 .. 24 cp 25 ; jr nc VTCpL_X ; No, exit ; Calc ptrs add a,a ; * 2 add a,a ; * 4 add a,VT_Line_Tab and #FF ; Add base ld l,a ; adc a,VT_Line_Tab/256 ; sub l ; ld h,a ; ; Now, get ptrs ld c,(hl) ; Get the ptrs inc hl ; ld b,(hl) ; inc hl ; ld a,(hl) ; inc hl ; ld h,(hl) ; ld l,a ; HL = sB BC = sV Stack = dB dV pop de ; := dB push bc ; Stack := sV dV ; Do the two lines have the same Y-Mapping ? ld a,(de) ; Size xor (hl) ; Difference in size ; Copy buffer ld bc,161 ; This many ldir ; Copy the line ; Now the screen pop hl ; Src pop de ; Dst ld bc,160 ; Screen length ldir ; Copy the line ; Copy Y mapping if different and %11 0 ; Mask the difference jr z VTCpL_X ; None, done ; We must copy the Y-mapping too pop bc ; B := Src C := Dst push bc ; dec b ; 0 .. 24 dec c ; 0 .. 24 ; Point at the src ld a,b ; Y add a,a ; * 2 add a,VT_Line_Ys_NS and #FF; Add base ld l,a ; adc a,VT_Line_Ys_NS / 256 ; sub l ; ld h,a ; ; Now, we must move onto the next table if shrunk ld de,(VTY_Offset) ; Move if required add hl,de ; ; Lookup the address ld e,(hl) ; inc hl ; ld d,(hl) ; ; Point at the dest ld a,c add a,a ; * 2 add a,VT_Line_Ys_NS and #FF; Add base ld l,a ; adc a,VT_Line_Ys_NS / 256 ; sub l ; ld h,a ; ; Now, we must move onto the next table if shrunk ld bc,(VTY_Offset) ; Move if required add hl,bc ; ld a,(hl) ; inc hl ; ld h,(hl) ; ld l,a ; ; de = pSrc hl = pDst ld a,(nLPC) ; 12 or 16 ld b,a ; lines VTCpL_Lp ld a,(de) ; Copy inc de ; inc de ; inc de ; ld (hl),a ; inc hl ; inc hl ; inc hl ; djnz VTCpL_Lp ; Loop ; Done, exit VTCpL_X pop bc ; Restore pop bc ; pop de ; pop hl ; ret ; Done ; Find if a char is in a list given HL = pLIST, A = Char ; If found, return HL,C,A C = Parameter FindChar ld d,a ; Save char ld bc,4 ; Offset jr FiC_1 ; Skip FiC_Lp add hl,bc ; Skip entry FiC_1 ld a,(hl) ; Giz next or a ; jr z FiC_Fail ; EOL, failed cp d ; This one ? jr nz FiC_Lp ; No, try next inc hl ; Skip char ld c,(hl) ; Get param inc hl ; ld a,(hl) ; Get ptr inc hl ; ld h,(hl) ; ld l,a ; or a ; NC ret ; Done FiC_Fail ld a,d ; Return the failed char scf ; Fail ret ; ; Vector to HL CallHL jp (HL) ; Vector to HL ; Show the VT100 cursor VT_Show_Cursor push af ; Save ld a,(cCur_F) ; Giz the flags ; Visible ? bit bCurShown,a ; Shown ? jr nz VTSC_X ; Yes, skip ; Should we see it ? bit bCurEnable,a ; Enabled ? jr z VTSC_X ; No, skip ; Show it set bCurShown,a ; Assert shown ld (cCur_F),a ; ; Draw it, etc push hl ; Save push de ; push bc ; call VT_Get_pCurs ; hl = pChar, de = pLine ld a,(de) ; Get the size info ld c,a ; Save the size ; Get the char ld d,(hl) ; Get it inc hl ; ; Get the attribute and swap fore/back ld a,(hl) ; Attr rlca ; Align background and %0 1 0 1 0 000 ; Mask ld e,a ; Save ld a,(hl) ; Attr rrca ; Align background and %0 0 1 0 1 000 ; Mask or e ; Merge ld e,a ; ld a,(hl) ; Attr and %0 0 0 0 0 111 ; or e ; Merge ld e,a ; Save ; Update the screen call VT_Update_Curs ; Show it ; Done, restore things pop bc ; Restore pop de ; pop hl ; VTSC_X pop af ; Done, exit ret ; ; Hide the VT100 cursor VT_Hide_Cursor push af ; Save ld a,(cCur_F) ; Giz the flags ; Visible ? bit bCurShown,a ; Shown ? jr z VTHC_X ; No, skip res bCurShown,a ; Clear shown ld (cCur_F),a ; ; Remove it, etc push hl ; Save push de ; push bc ; ; Reset the flash time ld hl,VT_CFT ; Reset the cursor flash time ld (Cur_F_Cnt),hl ; ; Remove the cursor call VT_Get_pCurs ; hl = pChar, de = pLine ld a,(de) ; Get the size info ld c,a ; Save the size ; Get the char and attr ld d,(hl) ; Get it inc hl ; ld e,(hl) ; ; Update the screen call VT_Update_Curs ; Show it ; Done, restore things pop bc ; Restore pop de ; pop hl ; VTHC_X pop af ; Done, exit ret ; ; Flash the cursor VT_Flash_Cursor push hl ; Save ld hl,(Cur_F_Cnt) ; Get it dec hl ; ld (Cur_F_Cnt),hl ; ld a,l ; Z ? or h ; pop hl ; Restore jr nz VTFC_X ; No, exit ; Is it on ? ld a,(cCur_F) ; Is it shown ? bit bCurShown,a ; jr nz VTFC_Hide ; Yes, hide it ; It is not shown, show it pop af ; Restore jp VT_Show_Cursor ; Show it ; Hide it VTFC_Hide pop af ; Restore jp VT_Hide_Cursor ; Show it ; Exit VTFC_X pop af ; Restore ret ; Done ; Set the cursor, show iff a <> 0 VT_Set_Cursor or a ; Set flags jp nz VT_Show_Cursor ; NZ = Show it jp VT_Hide_Cursor ; Z = Hide it ; Update the cursor (or any other char) given DE = Char/Attr, C = Size VT_Update_Curs ld hl,(cCur_X) ; L := X, H := Y bit 0,c ; Size = Double width ? jr nz VTUC_DW ; Yes, skip jp VT_Char ; Just write one char ; Double-width VTUC_DW sla l ; X * 2 dec l ; X - 1 inc e ; E := E+2 (LHS) inc e ; call VT_Char ; Write the LHS inc l ; X + 1 inc e ; E := E+2 (RHS) inc e ; jp VT_Char ; Write the RHS ; Write a character to the display given L = X, H = Y, D= Char E = Attr VT_Char push hl ; Save push de ; push bc ; push af ; ; Check X/Y dec l ; X = 0 .. 79 dec h ; Y = 0 .. 24 ld a,h ; Y In range ? cp 25 ; 0 .. 24 ? jr nc VTC_Fail ; No, exit ld a,l ; X In range ? cp 80 ; 0 .. 79 ? jr nc VTC_Fail ; No, exit ; Calc the screen-position ld l,h ; Get Y ld h,0 ; add hl,hl ; * 2 ld bc,VT_Y_Table_S ; Add base add hl,bc ; add a,a ; X * 2 add a,(hl) ; Add Y ld c,a ; Save it ld a,0 ; inc hl ; adc a,(hl) ; Y ld h,a ; HL := pChar ld l,c ; ; Now write char/attr ld (hl),d ; Char inc hl ; ld (hl),e ; Attr ; Done, exit VTC_Fail pop af ; Restore pop bc ; pop de ; pop hl ; ret ; Done ; Get the cursor position, HL := pChar DE := pLine VT_Get_pCurs push af ; Save ; Get X/Y ld de,(cCur_X) ; E := X D := Y ; Check X/Y dec e ; X = 0 .. 79 dec d ; Y = 0 .. 24 ld a,d ; Y In range ? cp 25 ; 0 .. 24 ? jr nc VTGpC_Fail ; No, exit ld a,e ; X In range ? cp 80 ; 0 .. 79 ? jr nc VTGpC_Fail ; No, exit ; Calc the buffer-position ld l,d ; Get Y ld h,0 ; add hl,hl ; * 2 ld de,VT_Y_Table_B ; Add base add hl,de ; ld e,(hl) ; Get pLine inc hl ; ld d,(hl) ; add a,a ; HL := X * 2 ld l,a ; ld h,0 ; add hl,de ; Point at the char inc hl ; VTGpC_Fail pop af ; Restore ret ; Done ; Return the length of the line on the line containing the cursor VT_Get_Cur_LW push hl ; Save ld a,(cCur_Y) ; A := Y ; Check X/Y dec a ; Y = 0 .. 24 cp 25 ; 0 .. 24 ? jr nc VTGCL_80 ; No, assume 80 ; Calc the buffer-position add a,a ; * 2 add a,VT_Y_Table_B and #FF ; Add base ld l,a ; Get Y ld a,0 ; 0 adc a,VT_Y_Table_B/256 ; ld h,a ; ld a,(hl) ; Get pLine inc hl ; ld h,(hl) ; ld l,a ; ld a,(hl) ; Get size bit 0,a ; NZ = 40 jr nz VTGCL_40 ; Skip if 40 VTGCL_80 ld a,80 ; Must be 80 pop hl ; ret ; Done ; Return 40 VTGCL_40 ld a,40 ; Must be 40 pop hl ; ret ; Done ; Set the Z180 up to something sensible Setup_Z180 ld a,#40 ; 1 wait on memory ld bc,DMAWAIT ; out (c),a ; ld a,#00 ; NO refresh ld bc,RCA ; out (c),a ; ; Now, setup the memory-map to access the RAM ld a,#81 ; $1000 .. $8000 ld bc,CBAR ; out (c),a ; ld a,#40-#01 ; Start at $40000 ld bc,BBR ; out (c),a ; ld a,#60-#08 ; Start at $60000 ld bc,CBR ; out (c),a ; ; Drive the outputs ld a,%0 1 0000 00 ; Setup outputs ld (OUT_Cpy),a ; out (OUT_0),a ; Setup the port ret ; Done ; Kick the watchdog Kick_Watchdog push af ; Save di ; No ints ld a,(OUT_Cpy) ; The RAM copy xor #80 ; Flip the bit ld (OUT_Cpy),a ; out (OUT_0),a ; Write it ei ; Ok, again pop af ; Restore ret ; Done ; For use when ints aren't enabled Kick_Watchdog_NI push af ; Save ld a,(OUT_Cpy) ; The RAM copy xor #80 ; Flip the bit ld (OUT_Cpy),a ; out (OUT_0),a ; Write it pop af ; Restore ret ; Done ; Enable interrupt 2 Enable_Ints ld hl,vFrame_Int ; Write the vector into RAM ld (hl),#C3 ; JP inc l ; ld (hl),Frame_Int and #FF ; Low byte inc l ; ld (hl),Frame_Int / 256 ; High byte ; Now, setup the vectored interrupts ld hl,Int_Vects ; Point at the table ld a,l ; Low word ld bc,IL ; out (c),a ; ld a,h ; High word ld i,a ; ld a,%0 0 111 0 1 1 ; Enable video int, IBM keyboard int ld bc,ITC ; out (c),a ; ld (Vid_IntClr),a ; Clear it im 1 ; Mode ei ; Allow them vRETI reti ; Start it align 32 ; Bound it Int_Vects dw Kbd_Int ; IBM Keyboard interrupt dw vRETI ; Ignore INT2 dw vRETI ; Ignore PRT 0 dw vRETI ; Ignore PRT 1 dw vRETI ; Ignore DMA 0 dw vRETI ; Ignore DMA 1 dw vRETI ; Ignore CSI/O dw ASC_0_Int ; ASC 0 Interrupt dw vRETI ; Ignore ASC 1 ; The serial port interrupt ASC_0_Int push af ; Save push bc ; ; Get the status ld bc,STAT0 ; Point at the status register in a,(c) ; Get the status ; Is there a byte to read ? bit 7,a ; Rx full ? jr nz A0I_Rx ; Yes, skip ; Is DCD High ? bit 2,a ; DCD ? jr nz A0I_DCD ; Yes, skip ; Is the transmitter empty ? bit 1,a ; Tx empty ? jp nz A0I_Tx ; ; God knows why were interrupted, read the status and exit A0I_DCD in a,(c) ; DCD0 wants two reads in a,(c) ; ; Ignore this . . . ; Done A0I_X pop bc ; Restore pop af ; ei ; Enable them reti ; Exit ; Try receiving summat A0I_Rx and %0 1 1 1 0 0 0 0 ; Any errors ? jr nz A0I_RxErr ; Yes, skip ; Ok, this byte is valid, get it ld c,RDR0 ; Point at it in a,(c) ; Get the byte ; Stuff this into the buffer push ix ; Save push hl ; ld hl,Rx_0_Buff ; Point at the buffer ld ix,Rx_0_Ptr ; And the ptrs call Insert_Byte ; Add it ; Now, check the length of the buffer call Get_Buff_Cnt ; Get the number of chars pop hl ; Restore pop ix ; ; If > 100 we need to send an XOFF cp 80 ; > 100 jr nc A0I_Rx_Stop ; Yes, skip ; Enable CTS A0I_Rx_1 ld a,(Rx_0_Ctrl) ; Get the setup or %0000 1 000 ; Don't clear the errors ld c,CNTLA0 ; Point at the reg ; out (c),a ; Clear /RTS ; Done, exit jp A0I_X ; As above ; We must stop the transmission A0I_Rx_Stop ld a,(opHand) ; XON/XOFF enabled ? cp 2 ; jr nz A0I_Rx_1 ; No, exit ; Send an XOFF ld a,(Rx_Stopped) ; Already ? or a ; jr nz A0I_Rx_1 ; Yes, skip ld a,1 ; Flag that we tried ld (Rx_Stopped),a ; ld a,cXOFF ; Send the stop call Tx_Pri ; jr A0I_Rx_1 ; Done ; Disable CTS A0I_Clr_RTS ld a,(Rx_0_Ctrl) ; Get the setup or %000 1 1 000 ; Don't clear the errors, Set /RTS ld c,CNTLA0 ; Point at the reg out (c),a ; Set /RTS ; Done, exit jp A0I_X ; As above ; Rx errors, clear them A0I_RxErr ld c,RDR0 ; Read the char in a,(c) ; ld a,(Rx_0_Ctrl) ; Get the setup ld c,CNTLA0 ; Point at the reg out (c),a ; Clear the error flags ; Done, exit jp A0I_X ; As above Tx_Pri push bc ld (Tx_Fast_Send),a ; Store it ; Set the TIE flag ld bc,STAT0 ; STAT reg in a,(c) ; Get it or %0000000 1 ; Enable the Tx out (c),a ; pop bc ; Restore ret ; Done ; Send a TX byte Send_Tx push ix ; Save push hl ; ; Add it to the Tx buffer ld hl,Tx_0_Buff ; ld ix,Tx_0_Ptr ; call Insert_Byte ; Add it to the buffer ; Set the TIE flag ld bc,STAT0 ; STAT reg in a,(c) ; Get it or %0000000 1 ; Enable the Tx out (c),a ; pop hl ; pop ix ; ret ; ; Transmitter empty, see if there is a byte to Tx A0I_Tx push ix ; Save push hl ; ; Fast one ? ld a,(Tx_Fast_Send) ; XON/XOFF ? or a ; jr nz A0I_Tx_1 ; Yes, skip ; Try in the buffer ld hl,Tx_0_Buff ; Point at the buffer ld ix,Tx_0_Ptr ; Point at the ptr call Remove_Byte ; Giz a byte jr c A0I_KillTx ; No, none there, skip ; We have a byte, send it ld c,TDR0 ; Point at the register out (c),a ; Send it ; Done pop hl ; Restore pop ix ; jp A0I_X ; Exit ; We have a fast byte, send it A0I_Tx_1 ld c,TDR0 ; Point at the register out (c),a ; Send it xor a ; Clear it ld (Tx_Fast_Send),a ; ; Done pop hl ; Restore pop ix ; jp A0I_X ; Exit ; We don't have a byte to transmit, kill the Tx interrupt A0I_KillTx ld c,STAT0 ; Get the enables in a,(c) ; and %1111111 0 ; Clear the TIE out (c),a ; ; Done pop hl ; Restore pop ix ; jp A0I_X ; Exit ; Set the video timing (80.25) ; These now cater for the opShrunk flag Setup_Timing_25 ld hl,Timing_Data ; Point at it ld de,aVID ; Into memory ld bc,8 ; 8 locations ldir ; Write them ; Init the blank-line call ST_InitBlank ; Clear it ; Now, build the display list ld ix,aVLU_Base ; Point at the start ld hl,lVDU_Base + 80*2 ; Point at the data area ; Now, if we're shrunk we need to put 50 blank lines here ld a,(opShrunk) ; Shrunk ? cp 2 ; call z ST_Blank_50 ; 50 blank lines ; Active display lines here ld b,25 ; 25 lines ST25_Lp1 call ST25_Line ; Do one ld de,160 add hl,de djnz ST25_Lp1 ; Loop ; Now, if we're shrunk we need to put another 50 blanks here ld a,(opShrunk) ; Shrunk ? cp 2 ; call z ST_Blank_50 ; 50 blank lines ; Now, add the rest ld b,1 ; Blank bits ST25_Lp2 call ST_Blank ; djnz ST25_Lp2 ; ; Terminate it ld (ix+1),#80 ; Clear the counter ; Add the vertical sync ld hl,401 ; Start ld de,1 ; Number ld a,%00100000 ; SYNC bit call ST_VSet ; Set it ; Add the vertical active ld hl,0 ; Start ld de,400 ; Number ld a,%01000000 ; ACTIVE bit call ST_VSet ; Set it ; Add the vertical interrupt ld hl,400 ; Start ld de,1 ; Number ld a,%10000000 ; SYNC bit call ST_VSet ; Set it ; Done ret ; Done ; Set the video timing (80.24) Setup_Timing_24 ld hl,Timing_Data ; Point at it ld de,aVID ; Into memory ld bc,8 ; 8 locations ldir ; Write them ; Init the blank-line call ST_InitBlank ; Clear it ; Now, build the display list ld ix,aVLU_Base ; Point at the start ld hl,lVDU_Base + 80*2 ; Point at the data area ; Now, if we're shrunk we need to put another 48 blanks here ld a,(opShrunk) ; Shrunk ? cp 2 ; call z ST_Blank_48 ; 48 blank lines ld b,8 ; Blank bits ST24_Lp0 call ST_Blank ; djnz ST24_Lp0 ; ld b,24 ; 24 lines ST24_Lp1 call ST25_Line ; Do one ld de,160 add hl,de djnz ST24_Lp1 ; Loop ; Now, if we're shrunk we need to put another 48 blanks here ld a,(opShrunk) ; Shrunk ? cp 2 ; call z ST_Blank_48 ; 48 blank lines ; Now, add the rest ld b,9 ; Blank bits jr ST25_Lp2 ; As above ; Set the video timing (40.12) Setup_Timing_12 ld hl,Timing_Data ; Point at it ld de,aVID ; Into memory ld bc,8 ; 8 locations ldir ; Write them ; Init the blank-line call ST_InitBlank ; Clear it ; Now, build the display list ld ix,aVLU_Base ; Point at the start ld hl,lVDU_Base + 80*2 ; Point at the data area ; Now, if we're shrunk we need to put another 48 blanks here ld a,(opShrunk) ; Shrunk ? cp 2 ; call z ST_Blank_48 ; 50 blank lines ; 8 blank lines ld b,8 ; Blank bits ST12_Lp0 call ST_Blank ; djnz ST12_Lp0 ; ; 12 char lines ld b,12 ; 12 lines ST12_Lp1 call ST12_Line ; Do one ld de,160 ; Skip this line add hl,de ; djnz ST12_Lp1 ; Loop ; Now, if we're shrunk we need to put another 48 blanks here ld a,(opShrunk) ; Shrunk ? cp 2 ; call z ST_Blank_48 ; 48 blank lines ; Now, add the rest ld b,9 ; Blank bits jp ST25_Lp2 ; As above ; Add a character-line HL = ptr, C = line count ST25_Line ld c,0 ; Pixel-line 0 ST25L_Lp ld (ix+0),l ; Ptr ld (ix+1),h ; ld (ix+2),c ; inc ix ; Skip inc ix ; inc ix ; inc c ; Next ld a,(nLPC) ; End ? cp c ; jr nz ST25L_Lp ; Loop ret ; Done ; Add a character-line HL = ptr, C = line count ST12_Line ld c,0 ; Pixel-line 0 ST12L_Lp ld (ix+0),l ; Ptr ld (ix+1),h ; ld (ix+2),c ; inc ix ; Skip inc ix ; inc ix ; ; Same again ld (ix+0),l ; Ptr ld (ix+1),h ; ld (ix+2),c ; inc ix ; Skip inc ix ; inc ix ; inc c ; Next ld a,(nLPC) ; End ? cp c ; jr nz ST12L_Lp ; Loop ret ; Done ; Clear the blank line ST_InitBlank ld hl,aVDU_Blank ; Point at the buffer ld de,aVDU_Blank+2 ; ld bc,79*2 ; ld (hl)," " ; Blank inc hl ; ld (hl),0 ; dec hl ; ldir ; Clear it ret ; Done ; Add 50 blank lines ST_Blank_50 ld b,50 ; 50 blank lines ST_B50_Lp call ST_Blank ; One blank djnz ST_B50_Lp ; Loop ret ; Done ; Add 48 blank lines ST_Blank_48 ld b,48 ; 48 blank lines jr ST_B50_Lp ; As above ; Add a blank pixel line ST_Blank ld (ix+0),lVDU_Base and #FF ; Blank line ld (ix+1),lVDU_Base /256 ; ld (ix+2),0 ; #00 ST_Skip inc ix ; Skip definition inc ix ; inc ix ; ret ; Done ; ; Set a bit in a range of vertical lines ST_VSet push hl ; Save pop bc ; add hl,hl ; * 3 add hl,bc ; ld bc,aVLU_Base+2 ; Offset add hl,bc ; ; Set it for a range of lines ld c,a ; Save bit STVS_Lp ld a,(hl) ; Set it or c ; ld (hl),a ; inc hl ; Skip inc hl ; inc hl ; dec de ; Loop ld a,d ; or e ; jr nz STVS_Lp ; ret ; Done ; Set the character set for the TV914 TV9_Setup_Chars ld a,(EC_Set) ; Force to TV914 set or %000000 1 0 ; ld (EC_Set),a ; ; Copy them in from FLASH ld hl,TV914_Chars and #FFFF ; Point at them ld a,TV914_Chars/65536 ; jr DMA_Chars ; Copy them ; Set the character set for the VT100 VT_Setup_Chars ld a,(EC_Set) ; Force to VT100 set and %111111 0 1 ; ld (EC_Set),a ; ; Copy them in from flash ld hl,VT100_Chars and #FFFF ; Point at them ld a,VT100_Chars/65536 ; DMA_Chars call DMA_SetSrc ; Set it ; Now the destination ld hl,0 ; Point at the display ld a,#06 ; call DMA_SetDst ; Set it ; Now the length ld hl,#6000 ; The VT100 chars length call DMA_SetCnt ; This many ; Now copy them call DMA_DoIt ; Do it ; Done, exit ret ; Done ; Set the DMA src register DMA_SetSrc ld bc,SAR0L ; Ports DSS_1 out (c),l ; inc c ; out (c),h ; inc c ; out (c),a ; ret ; Done ; Set the DMA dst register DMA_SetDst ld bc,DAR0L ; Ports jr DSS_1 ; As above ; Set the DMA transfer length DMA_SetCnt ld bc,DMODE ; Mode port ld a,%00 00 00 1 0 ; Burst mode out (c),a ; ; Now set the count ld bc,BCR0L ; Ports out (c),l ; Low inc c ; out (c),h ; High ret ; Done ; Start the DMA transfer DMA_DoIt ld bc,DSTAT ; Status reg ld a,%0 1 1 0 0 0 0 0 ; Enable channel 0 out (c),a ; Do it ret ; Done ; The video interrupt Frame_Int push af ; Save push hl ; Save push de ; push bc ; ; Trap out if Para-Sys if def Enable_PS ld bc,STAT1 ; Char waiting ? in a,(c) ; bit 7,a ; Rx full ? jp nz #9C ; Yes, exit endif ; Perform the flashing ld a,(Flash_Mode) ; VT100 / TV914 ? or a ; jr nz FI_TV9_Flash ; TV914 mode, skip ; VT100 ld hl,Flash_0 ; Point at it dec (hl) ; jr nz FI_1 ; Skip ld (hl),iFl_0 ; Reset count ; Flip the bit ld a,(Vid_Attr) ; Change the state xor %0 0 0 1 0 0 0 0 ; ld (Vid_Attr),a ; ; Other flash FI_1 inc hl ; Point at next flash dec (hl) ; jr nz FI_2 ; Skip ld (hl),iFl_1 ; Reset count ; Flip the bit ld a,(Vid_Attr) ; Change the state xor %0 1 0 0 0 0 0 0 ; ld (Vid_Attr),a ; ; Frame count FI_2 ld hl,(Frame_No) ; Step the frame no inc hl ; ld (Frame_No),hl ; ; The IBM keyboard timer value ld hl,IBM_TO ; The kbd timer ld a,(hl) ; 0 ? or a ; jr z FI_SM ; Yes, skip dec (hl) ; Dec it ; Allow ints again FI_SM ld b,20 ; Small delay djnz . ; ld (Vid_IntClr),a ; Kill the int ei ; Allow ints ; Now, scan the matrix keyboard call Scan_Matrix ; Scan the kbd FI_End pop bc ; Restore pop de ; pop hl ; pop af ; ret ; ; Now the TV914 flashing mode, (Flash_1) only FI_TV9_Flash ld hl,Flash_1 ; Point at it dec (hl) ; jr nz FI_2 ; Skip ld (hl),iFl_1 ; Reset count ; Flip the bit ld a,(Vid_Attr) ; Change the state xor %0 0 0 1 0 0 0 0 ; ld l,a ; Save it rlca ; Align with the other bit rlca ; xor %0 1 0 0 0 0 0 0 ; Flip it xor l ; Merge the bit and %0 1 0 0 0 0 0 0 ; xor l ; ld (Vid_Attr),a ; jp FI_2 ; As above ; Scan the external matrix keyboard Scan_Matrix ld hl,Mat_Buff ; Point at the buffer ld c,%00 0001 00 ; Drive the first line ld d,0 ; Nothing reported yet SM_Y di ; No ints ld a,(OUT_Cpy) ; Get the port and %11 0000 11 ; Mask xor %10 0000 00 ; Flip the watchdog or c ; Merge ld (OUT_Cpy),a ; ei ; Ints valid again out (OUT_0),a ; Drive it ; Now, wait a bit then read the port. call SM_Del ; Wait in a,(IN_0) ; Get the LSB rrca ; Miss the two LSB's rrca ; ld b,6 ; Do 6 of them call SM_Scan ; Scan it in a,(IN_1) ; Get the MSB ld b,5 ; Do 5 of them call SM_Scan ; Scan it ; Now, next line rlc c ; Shift bit bit 6,c ; End ? jr z SM_Y ; No, loop ; Done, were there any keys ? ld a,d ; Giz the key or a ; Any ? ret z ; Exit if not ; We have a key, report it add a,KM_Map and #FF ; Look it up ld l,a ; adc a,KM_Map/256 ; sub l ; ld h,a ; ld a,(hl) ; Get the key or a ; Ignore it ? ret z ; ; Put it in the buffer push ix ; Save ld hl,Kbd_Buff ; Buffer ld ix,Kbd_Ptr ; call Insert_Byte ; pop ix ; Restore ; Done, exit ret ; Done ; Scan A for keys SM_Scan ld e,a ; Save the bits SMS_Lp rr e ; Get the next bit jr nc SMS_Pressed ; Skip if pressed ; This key is released, drive it ld a,(hl) ; Get the key-counts and %0000 1111 ; Count clear ? jr z SMS_Next ; Yes, skip cp 1 ; Will be 0 ? jr z SMS_Clr ; Yes, skip ; reduce the count dec (hl) ; cnt = cnt - 1 ; Next key SMS_Next inc hl ; Point at the next key djnz SMS_Lp ; Loop ret ; Done ; Clear this keydef SMS_Clr ld (hl),0 ; Clear it jr SMS_Next ; Next key ; This one is pressed SMS_Pressed ld a,(hl) ; Get the key-counts and %0000 1111 ; Count = pressed ? cp SMS_Cnt ; jr z SMS_Valid ; Yes, skip ; increase the count inc (hl) ; cnt = cnt + 1 jr SMS_Next ; Next key ; This key has been pressed long enough, report it ? SMS_Valid inc d ; Any reported key yet ? dec d ; jr nz SMS_Next ; Yes, ignore this one ; Has this key been reported ? ld a,(hl) ; get the flag or a ; jp m SMS_Next ; Bit 7 = 1, reported, skip ; Right, report it or %1 000 0000 ; Set the flag ld (hl),a ; ; Return this key ld a,l ; Get key offset sub (Mat_Buff-1) and #FF; ld d,a ; ; Done, next jp SMS_Next ; Next ; The key settle delay SM_Del push bc ; Save ld b,255 ; Pause djnz . ; pop bc ; Restore ret ; Done ; The IBM keyboard has clocked, read it Kbd_Int push af ; Save in a,(IN_0) ; Get the input state push bc ; ld c,a ; Save state ; Have we timed-out ? ld a,(IBM_TO) ; Timed-out ? or a ; jr nz KI_1 ; No, skip xor a ; Clear the mode ld (IBM_Mode),a ; KI_1 ld a,2 ; This many frames ld (IBM_TO),a ; Reset the TO value ; Now, are we expecting kbd clocks ? ld a,(IBM_Mode) ; 0 = Idle, 1 = Expecting input or a ; Idle ? jr z IKI_Idle ; Yes, is this a start ? dec a ; Receiving ? jr z IKI_Rx ; Yes, skip dec a ; Parity ? jr z IKI_Parity ; Yes, skip dec a ; Stop-bit ? jr z IKI_StopBit ; Yes, skip ; Dunno. Ignore it IKI_Reset xor a ; Mode := 0 (Idle) ld (IBM_Mode),a ; IKI_X pop bc ; Restore ; We must wait here until this clock has finished IKI_X_Wait in a,(IN_0) ; Get the input state bit 0,a ; Clock still low ? jr z IKI_X_Wait ; Yes, pause pop af ; Restore ei ; Enable them again reti ; Done ; Idle, is this a valid start bit ? IKI_Idle bit 1,c ; 0 ? jr nz IKI_X ; No, ignore it ; This is a start-bit, setup Rx ld a,1 ; Mode := 1 ld (IBM_Mode),a ; ld a,8 ; Bits/byte ld (IBM_Cnt),a ; jr IKI_X ; Done, exit ; Receiving IKI_Rx ld a,(IBM_Rx) ; Current rr c ; Get cf := bit rr c ; Get cf := bit rra ; Into bit 7 ld (IBM_Rx),a ; Save it ; Dec count ld a,(IBM_Cnt) ; Count - dec a ; ld (IBM_Cnt),a ; jr nz IKI_X ; Not finished, skip ; We have the byte, get the parity ld a,2 ; Get_Parity_Flag ld (IBM_Mode),a ; jr IKI_X ; Exit ; Drive the parity bit IKI_Parity ld a,(IBM_Rx) ; Get the char or a ; Assert parity ld a,c ; Get the parity bit jp pe IKI_PO ; Even, skip xor %1 0 ; Flip it IKI_PO bit 1,a ; Overall = Odd ? jr z IKI_Reset ; No, ignore it ; The parity = odd, get the stop bit ld a,3 ; Set stop bit mode ld (IBM_Mode),a ; jr IKI_X ; Exit ; Drive the stop-bit IKI_StopBit bit 1,c ; NZ ? jr z IKI_Reset ; No, reset ; The Rx byte is valid, drive it ld a,(IBM_Rx) ; Giz the byte cp #AA ; BAT Ok ? call nz IKI_Byte ; We have a byte, convert it ; Done, exit jr IKI_Reset ; Done, exit ; We have a scan-code in A, convert it to ASCII IKI_Byte push hl ; Save push de ; ; Save the code ld c,a ; The Rx byte ; Are we expecting a release ? ld a,(IB_Mode) ; Release expected ? or a ; jr nz IB_Rel ; Yes, skip ; Is this a release code ? ld a,c ; Get the scan-code cp #F0 ; Release ? jr z IB_SetRel ; Yes, skip ; This is a press, is it a shiftish key ? call IB_Find_Shift ; Look for shift keys jr z IB_Shift ; Yes, skip ; It is not a shift key, is it a repeat ? ld a,(IB_Curr_Key) ; The current one cp c ; Same ? jr z IB_X ; Yes, ignore it ; No, it is different, a new current-key ld a,c ; Get it ld (IB_Curr_Key),a ; Set it ; Now, convert this scan-code to ASCII call IB_Conv ; Convert it jr c IB_X ; Fail ; Save it push ix ; Save ld hl,Kbd_Buff ; Point at the buffer ld ix,Kbd_Ptr ; And the vars call Insert_Byte ; Add it pop ix ; Done ; Done, exit IB_X pop de ; Restore pop hl ; ret ; Done ; This is a shift-key, flag it IB_Shift dec b ; xxxx-lock ? jr z IBS_Lock ; Yes, skip ld (hl),1 ; Flag pressed jr IB_X ; Done ; The xxx-lock keys toggle IBS_Lock ld a,(hl) ; Flip it xor 1 ; ld (hl),a ; jr IB_X ; Done, exit ; This is a release code IB_Rel xor a ; Clear the expected flag ld (IB_Mode),a ; ; Is this a shift-key ? call IB_Find_Shift ; Look for shift keys jr z IB_Rel_Shift ; Yes, skip ; This is a released key, is it the current one ? ld a,(IB_Curr_Key) ; Is it this one ? cp c ; jr nz IB_X ; No, exit ; Yes, we have released the current key. xor a ; Kill it ld (IB_Curr_Key),a ; jr IB_X ; Done ; This is a shift-key, flag it IB_Rel_Shift dec b ; xxx-lock ? jr z IB_X ; Yes, ignore release ; Clear it ld (hl),0 ; Flag released jr IB_X ; Done ; Set release expected IB_SetRel ld a,1 ; Flag that we expect a key-release ld (IB_Mode),a ; jr IB_X ; Done ; Given a key scancode in C, return HL ptr to its shift flag ZF set ; B = 1 for a xxxx-lock IB_Find_Shift ld a,c ; Giz the scan-code ld b,0 ; Assume not a 'lock' key ld hl,IB_Shift_L ; Assume ls cp #12 ; sc for left shift ret z ; Yes ld hl,IB_Shift_R ; Assume rs cp #59 ; ret z ; ld hl,IB_Ctrl ; Assume ctrl cp #14 ; ret z ; ld hl,IB_Alt ; Assume alt cp #11 ; ret z ; ld b,1 ; Oh well, assume caps-lock, etc ld hl,IB_Caps ; Assume caps cp #58 ; ret z ; ld hl,IB_Num ; Assume num cp #77 ; ret z ; ld hl,IB_Scroll ; Assume scroll cp #7E ; ret ; ; Given an IBM scan-code in A, convert it to ASCII in A (CF = Failed) IB_Conv and #7F ; 00 .. 7F add a,IB_Tab and #FF ; Add base ld l,a ; adc a,IB_Tab / 256 ; sub l ; ld h,a ; ; Now, calc the shift-state ld a,(IB_Shift_L) ; Merge the shift-keys ld b,a ; ld a,(IB_Shift_R) ; or b ; jr z IBC_NS ; No shift, skip ; Shifted, change table ld bc,#80 ; Move to the shifted-table add hl,bc ; ; Now caps-lock it IBC_NS ld c,(hl) ; Get the char inc c ; OK ? dec c ; jr z IBC_Fail ; No, exit ; Caps-lock pressed ? ld a,(IB_Caps) ; Caps-lock ? or a ; jr z IBC_NCaps ; No, skip ; It is caps-locked, is it a..z or A..Z ? ld a,c ; Get it call Test_Alpha ; a..z or A..Z ? jr nc IBC_NCaps ; No, skip ; Yes, flip the shift-state ld a,c ; Get it xor %00 1 00000 ; Flip case ld c,a ; ; Now the ctrl IBC_NCaps ld a,(IB_Ctrl) ; Ctrl ? or a ; jr z IBC_NC ; No, skip ; Yes, and with #1F ld a,%000 11111 ; Perform a ctrl-fn and c ; ld c,a ; ; Ctrl done, exit IBC_NC ld a,c ; Get it or a ; Flag OK ret ; Done IBC_Fail scf ret ; Fail ; Return CF set if A is a..z or A..Z Test_Alpha cp "A" ; below A ? jr c TA_No ; No, exit false cp "Z"+1 ; above Z ? jr c TA_Yes ; No, exit true cp "a" ; below a ? jr c TA_No ; No, exit false cp "z"+1 ; above z ? jr c TA_Yes ; No, exit true TA_No or a ; NC ret ; TA_Yes scf ; C ret ; ; Insert a byte into a buffer given A = byte IX = pVars, HL = buffer addr Insert_Byte ld c,a ; Save the byte ld a,(ix+2) ; Length in buffer cp 128 ; Full ? jr z IB_Fail ; Yes, skip ; We can add this one ld a,(ix) ; Src ptr and %0 1111111 ; 0 .. 127 or l ; Into ptr ld l,a ; ld (hl),c ; Write this byte inc (ix) ; Step the ptr inc (ix+2) ; Flag one more in buffer or a ; Done ret ; IB_Fail scf ; Fail ret ; ; Remove a byte from a buffer given IX = pVars, HL = buffer addr Remove_Byte ld a,(ix+2) ; Length in buffer or a ; Empty ? jr z RB_Fail ; Yes, skip ; We can remove one ld a,(ix+1) ; Dst ptr and %0 1111111 ; Mask or l ; Into ptr ld l,a ; ld a,(hl) ; Read this byte inc (ix+1) ; Step the dst ptr dec (ix+2) ; Flag one less in buffer or a ; Done ret ; RB_Fail scf ; Fail ret ; ; Get the number of bytes in the buffer Get_Buff_Cnt ld a,(ix+2) ; This many used ret ; ; Get the free space in the buffer Get_Buff_Free ld a,128 ; Max size sub (ix+2) ; This many used ret ; ; Constants here ; ; The IBM-keyboard scancode convert table ; Unshifted IB_Tab db #00,#00,#00,#00,#00,#00,#00,cCN ; 00 .. 07 db #00,#00,#00,#00,#00,#09,#7C,#00 ; 08 .. 0F db #00,#00,#00,#00,#00,"q","1",#00 ; 10 .. 17 db #00,#00,"z","s","a","w","2",#00 ; 18 .. 1F db #00,"c","x","d","e","4","3",#00 ; 20 .. 27 db #00," ","v","f","t","r","5",#00 ; 28 .. 2F db #00,"n","b","h","g","y","6",#00 ; 30 .. 37 db #00,#00,"m","j","u","7","8",#00 ; 38 .. 3F db #00,",","k","i","o","0","9",#00 ; 40 .. 47 db #00,".","/","l",";","p","-",#00 ; 48 .. 4F db #00,#00,"'",#00,"[","=",#00,#00 ; 50 .. 57 db #00,#00,#0D,"]",#00,"#",#00,#00 ; 58 .. 5F db #00,#5C,#00,#00,#00,#00,#08,#00; 60 .. 67 db #00,#00,#00,cLt,#00,#00,#00,#00 ; 68 .. 6F db #00,#00,cDn,#00,cRt,cUp,#1B,#00 ; 70 .. 77 db cEC,"+",cPD,"-","*",cPU,#00,#00 ; 78 .. 7F ; Now shifted db #00,#00,#00,#00,#00,#00,#00,cCN ; 00 .. 07 db #00,#00,#00,#00,#00,#09,#7C,#00 ; 08 .. 0F db #00,#00,#00,#00,#00,"Q","!",#00 ; 10 .. 17 db #00,#00,"Z","S","A","W",#22,#00 ; 18 .. 1F db #00,"C","X","D","E","$","[9C]",#00 ; 20 .. 27 db #00," ","V","F","T","R","%",#00 ; 28 .. 2F db #00,"N","B","H","G","Y","^",#00 ; 30 .. 37 db #00,#00,"M","J","U","&","*",#00 ; 38 .. 3F db #00,"<","K","I","O",")","(",#00 ; 40 .. 47 db #00,">","?","L",":","P","_",#00 ; 48 .. 4F db #00,#00,"@",#00,"{","+",#00,#00 ; 50 .. 57 db #00,#00,#0D,"}",#00,"~",#00,#00 ; 58 .. 5F db #00,"|",#00,#00,#00,#00,#08,#00 ; 60 .. 67 db #00,#00,#00,cLt,#00,#00,#00,#00 ; 68 .. 6F db #00,#00,cDn,#00,cRt,cUp,#1B,#00 ; 70 .. 77 db cEC,"+",cPD,"-","*",cPU,#00,#00 ; 78 .. 7F ; The VT100 tables VT_CTRL_Tab db #08,0 ; Move LEFT dw VT_pcMC_L ; db #09,0 ; Perform TAB dw VT_pcTAB ; db #0A,0 ; Perform CRET dw VT_pcCRET ; db #0B,0 ; Perform CRET dw VT_pcCRET ; db #0C,0 ; Perform CRET dw VT_pcCRET ; db #0D,0 ; Perform a LHS dw VT_pcLHS ; db #0E,1 ; Select G1 dw VT_pcSetCS ; db #0F,0 ; Select G2 dw VT_pcSetCS ; db #1B,0 ; ESC dw VT_pcSetESC ; db 0 ; End VT_ESC_Tab db "[",0 ; Command ? dw VT_pcSetCMD ; db "c",0 ; Total daa dw Start ; db "D",0 ; Move down and scroll dw VT_pcDS ; db "E",0 ; CRET dw VT_pcCRET ; db "M",0 ; Move up and scroll dw VT_pcUS ; db "7",0 ; Save Cur+Attr dw VT_pcSave ; db "8",0 ; Load Cur+Attr dw VT_pcRestore ; db "#",0 ; Preset size dw VT_pcSetSIZE ; db "(",0 ; Preset G0 dw VT_pcSetCHARS ; db ")",1 ; Preset G1 dw VT_pcSetCHARS ; db 0 ; End ; Table for size setting VT_SIZE_Tab db "5",%00 0 ; Setup Sizes (Normal) dw VT_pcSetSize ; db "6",%00 1 ; DW dw VT_pcSetSize ; db "3",%10 1 ; DW DH Top dw VT_pcSetSize ; db "4",%11 1 ; DW DH Bottom dw VT_pcSetSize ; db 0 ; End VT_CHARS_Tab db "A",0 ; UK set dw VT_pcCharSet ; db "B",0 ; ASCII dw VT_pcCharSet ; db "0",1 ; Graphics dw VT_pcCharSet ; db "1",1 ; dw VT_pcCharSet ; db "2",1 ; dw VT_pcCharSet ; db 0 ; End ; ESC [ Table VT_CMD_Tab db "0",0 ; "0" dw VT_pcP_Digit ; db "1",1 ; "1" dw VT_pcP_Digit ; db "2",2 ; "2" dw VT_pcP_Digit ; db "3",3 ; "3" dw VT_pcP_Digit ; db "4",4 ; "4" dw VT_pcP_Digit ; db "5",5 ; "5" dw VT_pcP_Digit ; db "6",6 ; "6" dw VT_pcP_Digit ; db "7",7 ; "7" dw VT_pcP_Digit ; db "8",8 ; "8" dw VT_pcP_Digit ; db "9",9 ; "9" dw VT_pcP_Digit ; db ";",0 ; Separator dw VT_pcP_NextP ; ; Cursors db "A",0 ; Move Up dw VT_pcP_U ; db "B",0 ; Move Down dw VT_pcP_D ; db "C",0 ; Move Right dw VT_pcP_R ; db "D",0 ; Move Left dw VT_pcP_L ; ; Y,X db "H",0 ; Move to Y,X dw VT_pcP_YX ; db "f",0 ; Move to Y,X dw VT_pcP_YX ; ; Set scroll region db "r",0 ; Scroll region dw VT_pcP_Scroll ; ; Erase db "J",0 ; Erase in display dw VT_pcP_Er_Disp ; db "K",0 ; Erase in line dw VT_pcP_Er_Line ; ; Select attributes db "m",0 ; Attributes dw VT_pcP_Attr ; ; Extended commands "ESC [ ?" db "?",0 ; "ESC [ ? nn X" dw VT_pcSet_EXT_Q ; Use extended table db 0 ; End ; ESC [ ? Table VT_EXT_Q_Tab db "0",0 ; "0" dw VT_pcP_Digit ; db "1",1 ; "1" dw VT_pcP_Digit ; db "2",2 ; "2" dw VT_pcP_Digit ; db "3",3 ; "3" dw VT_pcP_Digit ; db "4",4 ; "4" dw VT_pcP_Digit ; db "5",5 ; "5" dw VT_pcP_Digit ; db "6",6 ; "6" dw VT_pcP_Digit ; db "7",7 ; "7" dw VT_pcP_Digit ; db "8",8 ; "8" dw VT_pcP_Digit ; db "9",9 ; "9" dw VT_pcP_Digit ; db ";",0 ; Separator dw VT_pcP_NextP ; ; Only the cursor on / off uses this disgusting format db "h",0 ; ESC [ ? nn h dw VT_pcCur_On ; db "l",0 ; ESC [ ? nn l dw VT_pcCur_Off ; db 0 ; ; Table for converting to screen addresses VT_Y_Table_S dw aVDU_Base ; Convert to screen addresses dw aVDU_Base + 160 ; dw aVDU_Base + 160 * 2 ; dw aVDU_Base + 160 * 3 ; dw aVDU_Base + 160 * 4 ; dw aVDU_Base + 160 * 5 ; dw aVDU_Base + 160 * 6 ; dw aVDU_Base + 160 * 7 ; dw aVDU_Base + 160 * 8 ; dw aVDU_Base + 160 * 9 ; dw aVDU_Base + 160 * 10 ; dw aVDU_Base + 160 * 11 ; dw aVDU_Base + 160 * 12 ; dw aVDU_Base + 160 * 13 ; dw aVDU_Base + 160 * 14 ; dw aVDU_Base + 160 * 15 ; dw aVDU_Base + 160 * 16 ; dw aVDU_Base + 160 * 17 ; dw aVDU_Base + 160 * 18 ; dw aVDU_Base + 160 * 19 ; dw aVDU_Base + 160 * 20 ; dw aVDU_Base + 160 * 21 ; dw aVDU_Base + 160 * 22 ; dw aVDU_Base + 160 * 23 ; dw aVDU_Base + 160 * 24 ; ; Table for converting to buffer addresses VT_Y_Table_B dw VDU_Buffer ; Convert to screen addresses dw VDU_Buffer + 161 ; dw VDU_Buffer + 161 * 2 ; dw VDU_Buffer + 161 * 3 ; dw VDU_Buffer + 161 * 4 ; dw VDU_Buffer + 161 * 5 ; dw VDU_Buffer + 161 * 6 ; dw VDU_Buffer + 161 * 7 ; dw VDU_Buffer + 161 * 8 ; dw VDU_Buffer + 161 * 9 ; dw VDU_Buffer + 161 * 10 ; dw VDU_Buffer + 161 * 11 ; dw VDU_Buffer + 161 * 12 ; dw VDU_Buffer + 161 * 13 ; dw VDU_Buffer + 161 * 14 ; dw VDU_Buffer + 161 * 15 ; dw VDU_Buffer + 161 * 16 ; dw VDU_Buffer + 161 * 17 ; dw VDU_Buffer + 161 * 18 ; dw VDU_Buffer + 161 * 19 ; dw VDU_Buffer + 161 * 20 ; dw VDU_Buffer + 161 * 21 ; dw VDU_Buffer + 161 * 22 ; dw VDU_Buffer + 161 * 23 ; dw VDU_Buffer + 161 * 24 ; ; Table for clearing and copying lines VT_Line_Tab dw aVDU_Base + 160 * 0 ; dw VDU_Buffer + 161 * 0 ; dw aVDU_Base + 160 * 1 ; dw VDU_Buffer + 161 * 1 ; dw aVDU_Base + 160 * 2 ; dw VDU_Buffer + 161 * 2 ; dw aVDU_Base + 160 * 3 ; dw VDU_Buffer + 161 * 3 ; dw aVDU_Base + 160 * 4 ; dw VDU_Buffer + 161 * 4 ; dw aVDU_Base + 160 * 5 ; dw VDU_Buffer + 161 * 5 ; dw aVDU_Base + 160 * 6 ; dw VDU_Buffer + 161 * 6 ; dw aVDU_Base + 160 * 7 ; dw VDU_Buffer + 161 * 7 ; dw aVDU_Base + 160 * 8 ; dw VDU_Buffer + 161 * 8 ; dw aVDU_Base + 160 * 9 ; dw VDU_Buffer + 161 * 9 ; dw aVDU_Base + 160 * 10 ; dw VDU_Buffer + 161 * 10 ; dw aVDU_Base + 160 * 11 ; dw VDU_Buffer + 161 * 11 ; dw aVDU_Base + 160 * 12 ; dw VDU_Buffer + 161 * 12 ; dw aVDU_Base + 160 * 13 ; dw VDU_Buffer + 161 * 13 ; dw aVDU_Base + 160 * 14 ; dw VDU_Buffer + 161 * 14 ; dw aVDU_Base + 160 * 15 ; dw VDU_Buffer + 161 * 15 ; dw aVDU_Base + 160 * 16 ; dw VDU_Buffer + 161 * 16 ; dw aVDU_Base + 160 * 17 ; dw VDU_Buffer + 161 * 17 ; dw aVDU_Base + 160 * 18 ; dw VDU_Buffer + 161 * 18 ; dw aVDU_Base + 160 * 19 ; dw VDU_Buffer + 161 * 19 ; dw aVDU_Base + 160 * 20 ; dw VDU_Buffer + 161 * 20 ; dw aVDU_Base + 160 * 21 ; dw VDU_Buffer + 161 * 21 ; dw aVDU_Base + 160 * 22 ; dw VDU_Buffer + 161 * 22 ; dw aVDU_Base + 160 * 23 ; dw VDU_Buffer + 161 * 23 ; dw aVDU_Base + 160 * 24 ; dw VDU_Buffer + 161 * 24 ; ; Table for Y-tab data VT_Line_Ys_NS dw aVLU_Base + 2 + 48 * 0 ; dw aVLU_Base + 2 + 48 * 1 ; dw aVLU_Base + 2 + 48 * 2 ; dw aVLU_Base + 2 + 48 * 3 ; dw aVLU_Base + 2 + 48 * 4 ; dw aVLU_Base + 2 + 48 * 5 ; dw aVLU_Base + 2 + 48 * 6 ; dw aVLU_Base + 2 + 48 * 7 ; dw aVLU_Base + 2 + 48 * 8 ; dw aVLU_Base + 2 + 48 * 9 ; dw aVLU_Base + 2 + 48 * 10 ; dw aVLU_Base + 2 + 48 * 11 ; dw aVLU_Base + 2 + 48 * 12 ; dw aVLU_Base + 2 + 48 * 13 ; dw aVLU_Base + 2 + 48 * 14 ; dw aVLU_Base + 2 + 48 * 15 ; dw aVLU_Base + 2 + 48 * 16 ; dw aVLU_Base + 2 + 48 * 17 ; dw aVLU_Base + 2 + 48 * 18 ; dw aVLU_Base + 2 + 48 * 19 ; dw aVLU_Base + 2 + 48 * 20 ; dw aVLU_Base + 2 + 48 * 21 ; dw aVLU_Base + 2 + 48 * 22 ; dw aVLU_Base + 2 + 48 * 23 ; dw aVLU_Base + 2 + 48 * 24 ; ; Now, the shrunk version VT_Line_Ys_S dw aVLU_Base + 152 + 36 * 0 ; dw aVLU_Base + 152 + 36 * 1 ; dw aVLU_Base + 152 + 36 * 2 ; dw aVLU_Base + 152 + 36 * 3 ; dw aVLU_Base + 152 + 36 * 4 ; dw aVLU_Base + 152 + 36 * 5 ; dw aVLU_Base + 152 + 36 * 6 ; dw aVLU_Base + 152 + 36 * 7 ; dw aVLU_Base + 152 + 36 * 8 ; dw aVLU_Base + 152 + 36 * 9 ; dw aVLU_Base + 152 + 36 * 10 ; dw aVLU_Base + 152 + 36 * 11 ; dw aVLU_Base + 152 + 36 * 12 ; dw aVLU_Base + 152 + 36 * 13 ; dw aVLU_Base + 152 + 36 * 14 ; dw aVLU_Base + 152 + 36 * 15 ; dw aVLU_Base + 152 + 36 * 16 ; dw aVLU_Base + 152 + 36 * 17 ; dw aVLU_Base + 152 + 36 * 18 ; dw aVLU_Base + 152 + 36 * 19 ; dw aVLU_Base + 152 + 36 * 20 ; dw aVLU_Base + 152 + 36 * 21 ; dw aVLU_Base + 152 + 36 * 22 ; dw aVLU_Base + 152 + 36 * 23 ; dw aVLU_Base + 152 + 36 * 24 ; ; TV914 Tables TV9_CTRL_Tab db #08,0 ; Left dw TV9_pcMC_L ; db #09,0 ; Tab dw TV9_pcTAB ; db #0A,0 ; LF dw TV9_pcLF ; db #0B,0 ; US dw TV9_pcUS ; db #0C,0 ; Right dw TV9_pcMC_R ; db #0D,0 ; LHS dw TV9_pcLHS ; db #0E,1 ; Disable XON/XOFF dw TV9_SetXON ; db #0F,2 ; Enable XON/XOFF dw TV9_SetXON ; db #10,0 ; Repeat dw TV9_SetRepeat ; db #16,0 ; MD dw TV9_pcMC_D ; db #1A," " ; Clear screen with spaces dw TV9_dwCLS ; db #1E,0 ; HOME dw TV9_pcHOME ; db #1F,0 ; CRET dw TV9_pcCRET ; db 0,0 ; Move LEFT dw dwRet ; ; The TV914 ESC table TV9_ESC_Tab db "O",0 ; Set 80 by 24 dw TV9_Set80x24 ; db "o",0 ; Set 40 by 12 dw TV9_Set40x12 ; db "*",0 ; Set clear table dw TV9_SetClrTab ; db ".",0 ; Set cursor mode dw TV9_SetCurTab ; db "G",0 ; Set attribute dw TV9_SetAttrTab ; db "J",0 ; Char set selection dw TV9_SetCharsetTab ; db "=",0 ; Move cursor dw TV9_SetMoveCur ; if def GEC_Version db "$",0 ; Enable graphic mode dw TV9_SetSemiG ; db "%",0 ; Disable graphic mode dw TV9_ClrSemiG ; endif db 0,0 ; dw dwRet ; ; The cursor table TV9_CUR_Tab db "0",0 ; Invisible dw TV9_SetCursor ; db "1",%0 1 1 1 0 000 ; Flashing rectangle dw TV9_SetCursor ; db "2",%0 0 0 0 1 000 ; Fixed rectangle dw TV9_SetCursor ; db "3",%0 1 1 1 0 001 ; Flashing + underline dw TV9_SetCursor ; db "4",%0 0 0 1 0 001 ; Underline dw TV9_SetCursor ; db 0,0 ; EOL ; The attribute table TV9_ATTR_Tab db "@",%0 0 0 1 0 000 ; Normal dw TV9_SetAttr ; db "0",%0 0 0 1 0 000 ; Normal dw TV9_SetAttr ; db "2",%0 1 0 1 0 000 ; Flashing dw TV9_SetAttr ; db "4",%0 0 0 0 1 000 ; Inverse dw TV9_SetAttr ; db "6",%0 1 1 1 0 000 ; Flashing inverse dw TV9_SetAttr ; db "8",%0 0 0 1 0 001 ; Underline dw TV9_SetAttr ; db ":",%0 1 0 1 0 001 ; Flashing/Underline dw TV9_SetAttr ; db "(",%0 0 0 0 1 001 ; Underline / Inverse dw TV9_SetAttr ; db ")",%0 1 1 0 1 001 ; Flashing Underline Inverse dw TV9_SetAttr ; db 0,0 ; EOL ; The char set table TV9_CHAR_Tab db 0,0 ; NULL ; The CLS table TV9_CLR_Tab db "0",0 ; CLS/null dw TV9_dwCLS ; db "2",0 ; CLS/null dw TV9_dwCLS ; db "1"," " ; CLS dw TV9_dwCLS ; db "3"," " ; CLS dw TV9_dwCLS ; db 0,0 ; EOL Timing_Data db #AB ; Palette db lVLU_Base/2048 ; LU base (Any 1K boundary) db 0,0,0,0 ; NC db %1 ; EI db 0 ; Clear int flag ; The default options defOptions db 1 ; VT100 db 2 ; 19200 db 1 ; 8 db 3 ; NONE db 1 ; 2 db 1 ; Dont echo db 1 db 2 ; Dont defEnd equ . ; End ; The option definition opt_Def dw opMode,opt_Term ; The terminal mode dw opBaud,opt_Baud ; The baud rate dw opData,opt_Data ; The number of bits dw opParity,opt_Parity ; Parity dw opStop,opt_Stop ; Stop dw opHand,opt_Hand ; Handshake dw opEcho,opt_Echo ; Echo dw opShrunk,opt_Shrunk ; Shrunk Flag dw opUpdate,opt_Update ; Update flag dw 0 ; End ; Left,Right,Up,Down opt_Cur equ ocT_1 ; Term_1 ocT_1 db 1,1:dw opMode,ocT_2,ocT_2,ocU_1,ocB_1 ; Term 1 ocT_2 db 2,1:dw opMode,ocT_1,ocT_1,ocU_2,ocB_2 ; Term 2 ocB_1 db 1,2:dw opBaud,ocB_8,ocB_2,ocT_1,ocD_1 ; Baud 1 ocB_2 db 2,2:dw opBaud,ocB_1,ocB_3,ocT_2,ocD_2 ; Baud 2 ocB_3 db 3,2:dw opBaud,ocB_2,ocB_4,ocT_2,ocD_2 ; Baud 3 ocB_4 db 4,2:dw opBaud,ocB_3,ocB_5,ocT_2,ocD_2 ; Baud 4 ocB_5 db 5,2:dw opBaud,ocB_4,ocB_6,ocT_2,ocD_2 ; Baud 5 ocB_6 db 6,2:dw opBaud,ocB_5,ocB_7,ocT_2,ocD_2 ; Baud 6 ocB_7 db 7,2:dw opBaud,ocB_6,ocB_8,ocT_2,ocD_2 ; Baud 7 ocB_8 db 8,2:dw opBaud,ocB_7,ocB_1,ocT_2,ocD_2 ; Baud 8 ocD_1 db 1,3:dw opData,ocD_2,ocD_2,ocB_1,ocP_1 ; Data 1 ocD_2 db 2,3:dw opData,ocD_1,ocD_1,ocB_2,ocP_2 ; Data 2 ocP_1 db 1,4:dw opParity,ocP_3,ocP_2,ocD_1,ocS_1 ; Parity 1 ocP_2 db 2,4:dw opParity,ocP_1,ocP_3,ocD_2,ocS_2 ; Parity 2 ocP_3 db 3,4:dw opParity,ocP_2,ocP_1,ocD_2,ocS_2 ; Parity 3 ocS_1 db 1,5:dw opStop,ocS_2,ocS_2,ocP_1,ocH_1 ; Stop 1 ocS_2 db 2,5:dw opStop,ocS_1,ocS_1,ocP_2,ocH_2 ; Stop 2 ocH_1 db 1,6:dw opHand,ocH_2,ocH_2,ocS_1,ocE_1 ; Hand 1 ocH_2 db 2,6:dw opHand,ocH_1,ocH_1,ocS_2,ocE_2 ; Hand 2 ocE_1 db 1,7:dw opEcho,ocE_2,ocE_2,ocH_1,ocSh_1 ; Echo 1 ocE_2 db 2,7:dw opEcho,ocE_1,ocE_1,ocH_2,ocSh_2 ; Echo 2 ocSh_1 db 1,8:dw opShrunk,ocSh_2,ocSh_2,ocE_1,ocU_1 ; Shrunk 1 ocSh_2 db 2,8:dw opShrunk,ocSh_1,ocSh_1,ocE_2,ocU_2 ; Shrunk 2 ocU_1 db 1,9:dw opUpdate,ocU_2,ocU_2,ocSh_1,ocT_1 ; Update 1 ocU_2 db 2,9:dw opUpdate,ocU_1,ocU_1,ocSh_2,ocT_2 ; Update 2 ; The terminal mode opt_Term db 16,4,"VT100",0 ; 0 db 24,4,"TV914",0 ; 1 db 0 ; ; The baud rate opt_Baud db 16,6,"57600",0 ; 0 db 24,6,"19200",0 ; 1 db 32,6,"9600",0 ; 2 db 40,6,"4800",0 ; 3 db 48,6,"2400",0 ; 4 db 56,6,"1200",0 ; 5 db 64,6,"600",0 ; 6 db 72,6,"300",0 ; 7 db 0 ; ; Data bits opt_Data db 16,8,"8",0 ; 0 db 24,8,"7",0 ; 1 db 0 ; ; Parity bits opt_Parity db 16,10,"ODD",0 ; 0 db 24,10,"EVEN",0 ; 1 db 32,10,"NONE",0 ; 2 db 0 ; ; Stop bits opt_Stop db 16,12,"2",0 ; 0 db 24,12,"1",0 ; 1 db 0 ; ; Serial Mode opt_Hand db 16,14,"No Handshake",0 ; 0 db 29,14,"XON/XOFF",0 ; 1 db 0 ; ; Local Echo Mode opt_Echo db 16,16,"ON",0 ; 0 db 24,16,"OFF",0 ; 1 db 0 ; ; Shrunk Flag opt_Shrunk db 16,18,"No",0 ; 0 db 24,18,"Yes",0 ; 1 db 0 ; ; Update opt_Update db 16,25,"YES",0 ; 0 db 24,25,"NO",0 ; 1 db 0 ; ; The configuration string sConf_1 db cEsc,"[0m" ; Clear the attributes db cEsc,"[2J" ; Clear the display db cEsc,"[1;1H" ; Home db "Terminal Setup Page"; Title db cEsc,"#3",#0C ; Top double db "Terminal Setup Page"; Title db cEsc,"#4",#0C ; Bottom double db #0C ; Blank line db "Terminal Mode" ; db #0C,#0C ; db "Baud Rate" ; db #0C,#0C ; db "Data Bits" ; db #0C,#0C ; db "Parity" ; db #0C,#0C ; db "Stop Bits" ; db #0C,#0C ; db "Handshake Mode" ; db #0C,#0C ; db "Local Echo" ; db #0C,#0C ; db "Shrunk" ; db #0C,#0C ; ; db "Flash Rate 1" ; ; db #0C,#0C ; ; db "Flash Rate 2" ; ; db #0C,#0C ; db #0C,#0C ; db #0C,#0C ; db #0C ; db "Update Setup" ; db cEsc,"[?25l" ; Cursor Off ; Version if not def GEC_Version db cEsc,"[1m" ; Dim db cEsc,"[24;51H" ; Home db "(Software version 1.40)" ; db cEsc,"[25;51H" ; Home time$ ; else db cEsc,"[1m" ; Dim db cEsc,"[24;51H" ; Home db "( GEC Software version 1.40 )" ; db cEsc,"[25;51H" ; Home db timestr ; endif db 0 ; Done ; The FLASH update string sFlash_Update db cEsc,"[0m" ; Clear the attributes db cEsc,"[2J" ; Clear the display db cEsc,"[11;1H" ; Middle of the display db cEsc,"[?25l" ; Cursor Off db " Storing the new options, please wait"; Title db cEsc,"#3",#0C ; Top double db " Storing the new options, please wait"; Title db cEsc,"#4",#0C ; Bottom double db 0 ; Done ; The key matrix mapping if not def GEC_Version KM_Map db 0 ; Null ; c9 c6 c2 c8 c10 c1 c3 c4 c5 c7 c11 db #20,#0B,#57,#30,#0D,#56,#00,#00,#00,#16,#00 ; L4 db #35,#00,#49,#34,#36,#48,#00,#00,#00,#00,#08 ; L2 db #38,#00,#00,#37,#39,#00,#00,#00,#00,#00,#00 ; L3 db #32,#46,#42,#31,#33,#41,#43,#44,#45,#47,#00 ; L1 else KM_Map db 0 ; Null ; c9 c6 c2 c8 c10 c1 c3 c4 c5 c7 c11 db #20,#0B,#57,#30,#0D,#56,#58,#59,#5A,#16,#00 ; L4 db #35,#4D,#49,#34,#36,#48,#4A,#4B,#4C,#4E,#08 ; L2 db #38,#54,#50,#37,#39,#4F,#51,#52,#53,#55,#00 ; L3 db #32,#46,#42,#31,#33,#41,#43,#44,#45,#47,#1B ; L1 endif ; Optional bits if def Start_Msg sStart_Msg db #0D,#0C,#0C,#09 db "F12 for setup screen" db #0D,#0C,#09 db "F11 for character editor" db #0D,#0C,#0C,#09 db "You need to set the links on the EL as follows !" db #0D,#0C,#09 db "The pattern of links should be :-" db #0D,#0C,#0C,#09 db ":|:|||| |||: (ie 8 links fitted.)" db #0D,#0C,#0C,#09 db "This assumes you look at the links from the back of the" db " EL" db #0D,#0C,#09 db "with the 'Planar International Ltd' at the bottom." db #0D,#0C,#0C,#09 db "When you get it right there will be an equal block in each" db #0D,#0C,#09 db "corner of the screen." db #0D,#0C,#0C,#09 db "The character editor won't save yet but you'll get the idea" db #0D,#0C,#09 db "The numeric cursors PLUS shift = select character" db #0D,#0C,#09 db "Either cursors WITHOUT shift = select pixel" db #0D,#0C,#09 db "SPACE = toggle pixel, ESC = Exit, U = toggle between normal" db #0D,#0C,#09 db "and underline sets. T toggles between VT100/TV914 sets." db #0D,#0C,#0C,#09 db "ALL EDITS ARE LOST WHEN YOU PRESS T ! ! !" db #0D,#0C,#09 db "(You can switch in and out with ESC & F11 safely, though.)" db 0 endif ; Variables ; org Vars align 128 ; Align it Var_Start equ . ; Clear from here ; Buffer vars Kbd_Buff ds 128 ; The keyboard buffer Rx_0_Buff ds 128 ; Port 0 Rx buffer Tx_0_Buff ds 128 ; Etc Rx_1_Buff ds 128 ; Tx_1_Buff ds 128 ; Kbd_Ptr ds 3 ; Point at the output Rx_0_Ptr ds 3 ; Point at the output Tx_0_Ptr ds 3 ; Point at the output Rx_1_Ptr ds 3 ; Point at the output Tx_1_Ptr ds 3 ; Point at the output ; Vars OUT_Cpy ds 1 ; The output-port state Rx_Stopped ds 1 ; NZ = XOFF sent Tx_Fast_Send ds 1 ; NZ = send this NOW !! Rx_0_Ctrl ds 1 ; The serial setup CNTLA0 value Flash_Byte ds 1 ; The transfer byte for Flash commands Fl_HL ds 2 ; Hold the address Fl_A ds 1 ; Fl_Src ds 2 ; Src address Fl_Dst ds 2 ; Src address Fl_Dst2 ds 1 ; Fl_Cnt ds 2 ; The length Fl_Byte ds 1 ; The byte ; Key matrix vars Mat_Buff ds 4 * 11 ; This many keys ; Character editor EC_Set ds 1 ; The charset being edited ECO_Set ds 1 ; The charset being edited EC_X ds 1 ; Cursor X ECO_X ds 1 ; Cursor X EC_Y ds 1 ; Cursor Y ECO_Y ds 1 ; Cursor Y EC_PX ds 1 ; Pixel Cursor X ECO_PX ds 1 ; Pixel Cursor X EC_PY ds 1 ; Pixel Cursor Y ECO_PY ds 1 ; Pixel Cursor Y ; Setups opMode ds 1 ; opBaud ds 1 ; opData ds 1 ; opParity ds 1 ; opStop ds 1 ; opHand ds 1 ; 1 = NONE 2 = XON/XOFF opEcho ds 1 ; opShrunk ds 1 ; opUpdate ds 1 ; op_pCur ds 2 ; Point at the data struct Opt_Exit ds 1 ; NZ = exit IBM_Mode ds 1 ; The IBM Kbd int mode IBM_TO ds 1 ; The timer count IBM_Cnt ds 1 ; The Rx byte count IBM_Rx ds 1 ; The Rx byte IBM_Parity ds 1 ; The parity byte IB_Mode ds 1 ; NZ = release code expected IB_Curr_Key ds 1 ; The current keys' scan code IB_Shift_L ds 1 ; The left shift key IB_Shift_R ds 1 ; The right shift key IB_Ctrl ds 1 ; Ctrl IB_Alt ds 1 ; Alt IB_Caps ds 1 ; Caps-Lock IB_Num ds 1 ; Num-Lock IB_Scroll ds 1 ; Scroll-Lock Flash_0 ds 1 ; The count for BOLD Flash_1 ds 1 ; The count for FLASH cAttr ds 1 ; The current attribute cCur_X ds 1 ; Cursor X These MUST be together ! cCur_Y ds 1 ; Cursor Y " " " cCur_F ds 1 ; Cursor flags 0 = Shown, 1 = Enable Cur_F_Cnt ds 2 ; Cursor Flash count cTop_M ds 1 ; Top margin cBott_M ds 1 ; Bottom margin Hack_RHS ds 1 ; NZ = hack the RHS VT_Mode ds 1 ; Chars expected mode VT_pList ds 2 ; Ptr to the list of possible chars Frame_No ds 2 ; The frame number sCur_X ds 1 ; Saved cursor posn sCur_Y ds 1 ; sHack_RHS ds 1 ; Saved Urgh ! sAttr ds 1 ; Saved attribute VT_pParam ds 2 ; Ptr to the current param Parameters ds 4*2 ; Allow for 4 of the damn things Last_Param ds 2*2 ; End Flash_Mode ds 1 ; NZ = TV914 flashing nLPC ds 1 ; Lines per char, either 12 or 16 VTY_Offset ds 2 ; Offset to the YTable ; TV914 vars TV9_Mode ds 1 ; State variable for char decode TV9_Temp ds 1 ; Hold a char TV9_Rpt ds 1 ; Hold a char for repeats TV9_80_F ds 1 ; NZ = 80 column mode TV9_pList ds 2 ; Point at the possible chars list TV9_CurAttr ds 1 ; Cursor attribute if def GEC_Version TV9_SemiF ds 1 ; NZ = Semi graphic mode endif VDU_Buffer ds 25 * (1 + 2*80) ; The display buffer Var_End equ . ; Clear to here zeusprinthex . if . > #8000 zeuserror "Out of memory!" endif