\ vandys \ cons.f \ VGA text console driver in Forth \ only drivers definitions \ Stash all this in driver namespace also os NSCREEN constant NSCREEN \ # virtual screens supported CONS_COLS constant CONS_COLS \ Columns on display CONS_COLS 1- constant CONS_COLS-1 CONS_ROWS constant CONS_ROWS \ Rows on display RAM_SIZE constant RAM_SIZE \ Words on display RAM_BYTES constant RAM_BYTES \ Bytes on display 3 constant CHAR_INTR \ Interrupt char (^C) $3D4 constant GDC_REG \ I/O ports to control cursor hardware $3D5 constant GDC_VAL $B8000 constant TVRAM \ Mapped screen memory \ vandys create cur_attr 7 8 lshift , $0720 constant BLWORD variable cur_col variable cur_row variable cursor_moved variable scrollCount 80 dup constant #TTYQ create ttyq allot create nttyq 0 , SCRMEM constant SCRMEM \ # bytes of state per screen create screens \ Per-screen state SCRMEM NSCREEN * allot \ 0: Current display pointer (either virtual or HW address) \ 4: row \ 8: col \ 12: attr \ 16: scroll count \ 20: \ 24: RAM_BYTES bytes of screen image storage \ vandys \ Get pointer to screen state : >scrptr ( u -- a ) SCRMEM * screens + ; \ Convert pointer to screen state into pointer to hardware buffer memory : >scrhw ( a -- a' ) 6 cells + ; \ Point to TTY channel USER variable : >ttchan ttchan up @ - + ; variable SCR \ Base address of screen memory variable SCRrow1 \ ...address of 2nd line of screen variable SCRrow24 \ ...of start of last line variable SCRrow25 \ ...of last line variable cur_hw \ Screen # displayed on physical screen variable cur_chan \ Screen # currently set on SCR \ Amount of memory to scroll up with move CONS_ROWS 1- dup constant CONS_ROWS-1 CONS_COLS * 2* constant SCRscrollsize \ vandys : set_screenmem ( a -- ) dup CONS_COLS 2* + SCRrow1 ! dup SCRscrollsize + dup SCRrow24 ! CONS_COLS 2* + SCRrow25 ! SCR ! ; : gdc! ( val gdcreg -- ) GDC_REG outb GDC_VAL outb ; : cursor_pos ( -- ) cursor_moved off cur_row @ CONS_COLS * cur_col @ + dup 8 rshift $E gdc! $F gdc! ; : on_hw? ( -- ? ) ttchan @ cur_hw @ = ; \ vandys : (scroll_up) ( -- ) SCRrow1 @ SCR @ SCRscrollsize move SCRrow25 @ SCRrow24 @ do BLWORD i w! 2 +loop ; : check_intr ( -- ) nttyq @ if ttyq c@ CHAR_INTR = if handler @ if nttyq off 1 abort" Interrupt" then then then ; : scroll_up ( -- ) scrollCount @ CONS_ROWS < if (scroll_up) exit then nttyq @ if (scroll_up) exit then CONS_COLS-1 cur_col ! begin pause on_hw? dup if cursor_pos then nttyq @ 0<> and until (scroll_up) cur_col off cursor_moved on scrollCount off check_intr nttyq off ; : consput ( c -- ) cur_attr @ + SCR @ cur_row @ CONS_COLS * cur_col @ + 2* + w! ; \ vandys : (cons_fwd) ( -- ) cur_col inc cur_col @ CONS_COLS < if exit then cur_col off cur_row inc scrollCount inc cur_row @ CONS_ROWS < if exit then cur_row dec scroll_up ; : (cons_putc) ( c -- ) consput (cons_fwd) ; : cons_putc ( c -- ) on_hw? if cursor_moved on then dup 31 > over 128 < and if (cons_putc) exit then \ vandys dup 9 = if drop begin 32 recurse cur_col @ 8 mod 0= until exit then dup 13 = if drop 0 cur_col ! exit then dup 10 = if drop cur_row inc scrollCount inc cur_row @ CONS_ROWS >= if cur_row dec scroll_up then exit then \ vandys dup 8 = if drop cur_col @ 0 > if cur_col dec else cur_row @ if cur_row dec CONS_COLS 1- cur_col ! then then exit then \ Unknown control char drop ; \ vandys : blank_page ( a -- ) RAM_SIZE 0 do BLWORD over i 2* + w! loop drop ; : cons_page ( -- ) SCR @ blank_page cur_col off cur_row off cursor_moved on ; : cons_xy ( row col -- ) cur_col ! cur_row ! scrollCount off cursor_moved on ; : cons_attr ( ? -- ) if $7000 else $700 then cur_attr ! ; : cons_blot ( -- ) SCR @ cur_row @ CONS_COLS * cur_col @ + 2* + CONS_COLS cur_col @ - 0 do BLWORD over w! 2 + loop drop ; : cons_putpage ( a -- ) SCR @ RAM_SIZE 0 do over c@ $700 + over w! 2+ swap 1+ swap loop 2drop ; \ vandys \ Ports for PC keyboard $61 constant KBD_CTL $60 constant KBD_DATA $64 constant KBD_STATUS \ vandys \ Mapping from key position to ASCII \ Un-shifted mapping of PC scancodes to ASCII create key_map 0 c, 27 c, ,chars 1234567890-= 8 c, 9 c, ,chars qwertyuiop[] 13 c, $80 c, ,chars asdfghjkl; 39 c, 96 c, $80 c, 92 c, ,chars zxcvbnm,./ $80 c, char * c, $80 c, 32 c, 23 pad80 char 0 c, 127 c, \ Shifted mapping of PC scancodes to ASCII create shift_map 0 c, 27 c, ,chars !@#$%^&*()_+ 8 c, 9 c, ,chars QWERTYUIOP{} 13 c, $80 c, ,chars ASDFGHJKL: 34 c, char ~ c, $80 c, ,chars |ZXCVBNM<>? $80 c, 42 c, $80 c, 32 c, 13 pad80 ,chars 789 $80 c, ,chars 456 $80 c, ,chars 1230 127 c, align \ vandys variable conshift variable conctrl : set_chan ( u -- ) cur_chan @ 2dup = if 2drop exit then >scrptr SCR @ over ! cell+ cur_row @ over ! cell+ cur_col @ over ! cell+ cur_attr @ over ! cell+ scrollCount @ swap ! dup cur_chan ! >scrptr dup @ set_screenmem cell+ dup @ cur_row ! cell+ dup @ cur_col ! cell+ dup @ cur_attr ! cell+ @ scrollCount ! ; \ vandys : set_hw ( u-newchan -- ) dup NSCREEN u< not if drop exit then dup cur_hw @ = if drop exit then 'pause @ 0= if drop exit then dup set_chan TVRAM cur_hw @ >scrptr dup >r >scrhw RAM_BYTES cmove r> dup >scrhw swap ! ( newchan ) \ vandys ( newchan ) dup cur_hw ! >scrptr dup >r >scrhw TVRAM RAM_BYTES cmove r> TVRAM swap ! TVRAM set_screenmem cursor_moved on ; \ vandys \ Get next character typed on PC keyboard : (cons_getc) ( -- c T | F ) \ vandys 0 begin drop \ Char from previous time around \ Strobe enable on keyboard KBD_CTL inb dup $7F and KBD_CTL outb dup $80 or KBD_CTL outb $7F and KBD_CTL outb \ Return FALSE if no data available KBD_STATUS inb 1 and 0= if false exit then \ Read next byte of data KBD_DATA inb \ F1..F10 select screens (TBD... require ALT-Fx?) dup 59 >= over 68 <= and if 59 - set_hw false exit then \ Shift pressed? dup $36 = over $2A = or if 1 conshift ! drop $80 then \ vandys \ Shift released? dup $B6 = over $AA = or if 0 conshift ! drop $80 then \ Ctrl pressed? dup $1D = if 1 conctrl ! drop $80 then \ Ctrl released? dup $9D = if 0 conctrl ! drop $80 then \ Iterate until actual data key dup 58 < until \ Trim to 7-bit ASCII, look up character in keyboard map $7F and conshift @ if shift_map else key_map then + c@ \ Control key? conctrl @ if $1F and then true \ Return flag that we have the data ; \ vandys : bad_cons_op 1 abort" Bad console operation" ; : cons_q ( c -- ) nttyq @ #TTYQ >= if drop exit then nttyq @ ttyq + c! nttyq inc ; : cons_deq ( -- c ) ttyq c@ nttyq @ dup 0= abort" Empty" 1- nttyq ! ttyq dup 1+ swap nttyq @ move ; : cons_watcher ( -- ) begin (cons_getc) if dup CHAR_INTR = if ttyq c! 1 nttyq ! else cons_q then scrollCount off then pause again ; : cons_getc ( -- c T | F ) on_hw? not if false exit then cursor_moved @ if cursor_pos then nttyq @ 0= if false exit then check_intr cons_deq true ; : cons_op ( op -- ... ) dup 2 = if drop pause cons_getc exit then ttchan @ cur_chan @ <> if ttchan @ set_chan then \ vandys \ Dispatch request (exec:) ( 0: ) bad_cons_op ( 1: ) cons_putc ( 2: ) nop ( cons_getc is handled above as a special case ) ( 3: ) cons_page ( 4: ) cons_xy ( 5: ) cons_blot ( 6: ) cons_attr ( 7: ) nop ( was initialize--obsolete ) ( 8: ) cons_putpage ; \ vandys initialize definitions os : boot-cons ( ? -- n | ) 0= if 400 exit then ['] cons_op 'ttyops ! $4D 10 gdc! $0F 11 gdc! 0 dup cur_chan ! cur_hw ! cold? if fork ?dup 0= if cons_watcher else setrun then then NSCREEN 0 do i >scrptr \ vandys i 0= if TVRAM else dup >scrhw then over ! i if cold? if fork ?dup 0= if drop quit then i over >ttchan ! setrun then then \ vandys cell+ CONS_ROWS 1- over ! cell+ 0 over ! cell+ cur_attr @ over ! cell+ 0 over ! cell+ 0 over ! cell+ blank_page loop TVRAM set_screenmem CONS_ROWS 1- cur_row ! 0 cur_col ! NSCREEN 1 do i ttchan ! ." Task" i . cr loop 0 ttchan ! ; \ Support for TTY integration into tasking edisms vandys \ : (key-edisms) ( ttchan -- ? ) cur_hw @ - if false exit then \ TBD: need ttchan/vector combo to be pollable from any context. only