=== Examples for Lecture Number 11 === Screen 0 not modified 0 \ Examples for Lecture Number 11 20:27JWB12/07/85 1 \ Last change: Screen 007 11:12jwb11/22/87 2 3 4 5 USER VARIABLES 6 7 MULTI TASKING 8 9 10 11 12 13 14 15 Screen 2 not modified 0 \ BLOCK 16:03JWB11/29/85 1 2 3 BLOCK ( n adr ) Given the block number n, BLOCK returns 4 the in address, adr, of the assigned block buffer. The 5 buffer address, adr, is the location of the first data 6 storage cell of the buffer, which consists of 1024 bytes 7 8 9 UPDATE ( -- -- ) Mark most recently referenced block as 10 modified. Then if its block buffer is required it will 11 automatically be transfered back to mass storage. 12 13 14 15 Screen 3 not modified 0 BUFFER 16:50JWB11/29/85 1 BUFFER ( n adr ) Assign block n the buffer storage area at 2 adr . The function is the same as for BLOCK except 3 that the contents of the data storage area are undefined 4 That is . . . The buffer is assigned only and the 5 if the block is not already in memory its contents might 6 not be transfered from mass storage. Not often used. 7 8 EMPTY-BUFFERS ( -- -- ) Erase all data in block buffers, 9 initialize buffer pointers and mark buffers as empty. 10 11 SAVE-BUFFERS ( -- -- ) Transfer all buffers marked as 12 updated to mass storage and then mark them as unmodified 13 14 FLUSH ( -- -- ) Same effect as SAVE-BUFFERS followed 15 by EMPTY-BUFFERS . Screen 4 not modified 0 \ Virtual vector arrays-1 11:26jwb11/22/87 1 BLK @ 2+ ( 6 ) CONSTANT FIRST-BLOCK 2 BLK @ 4 + ( 8 ) CONSTANT LAST-BLOCK 3 CREATE POINTER 0 , \ Keeps track of amount allocated. 4 VARIABLE STORE? \ Fetch store flag 5 : => STORE? ON ; \ Assignment operator. 6 \ Allot some virtual memory cells. 7 : B-ALLOT ( n -- ) 8 DUP POINTER @ + 9 LAST-BLOCK FIRST-BLOCK - 1+ 1024 * > 10 ABORT" Allocated virtual memory exausted" 11 POINTER +! ; 12 \ Compile time routine. 13 : COMPILE-VVECTOR ( n -- ) 14 POINTER @ OVER 2* B-ALLOT 15 , , ; \ pfa: pointer : array-size : Screen 5 not modified 0 \ Virtual vector arrays-2 11:26jwb11/22/87 1 \ Runtime for virtual vector. ?? may be data item to be stored 2 : RUN-VVECTOR ( ?? pfa ??? ) \ ??? may be data fetched. 3 2DUP 2+ @ < NOT \ ?? pfa flag 4 IF STORE? OFF -1 ABORT" Subscript out of range." THEN 5 @ SWAP 2* \ ?? pointer index 6 + B/BUF /MOD \ ?? offset block-offset 7 FIRST-BLOCK + BLOCK + \ ?? data-storage-address 8 STORE? @ STORE? OFF 9 IF ! UPDATE ELSE @ THEN ; 10 11 : VVECTOR 12 CREATE COMPILE-VVECTOR 13 DOES> RUN-VVECTOR ; 14 15 500 VVECTOR XX 500 VVECTOR YY 500 VVECTOR ZZ Screen 9 not modified 0 \ Multitasking. 21:01JWB12/07/85 1 Multitasking allows one computer to appear to do several things 2 at the same time. Most of the time a single user computer sits 3 in an idle loop waiting for the operator to press the keyboard. 4 5 The idea is to utilize this waiting time to perform other useful 6 tasks. Typical background tasks would be watching over 7 instruments in a lab, printing a long file, updating a clock etc 8 9 F83 uses a very simple yet effective round-robin scheduling 10 technique. Task switching is extremly fast because each task 11 maintains its own parameter and return stacks and its own set 12 of critical variables ( called USER variables ). 13 14 The task switcher just changes the pointer to the correct list 15 of USER variables. Screen 10 not modified 0 \ Task dependent user variables. 20:44JWB12/07/85 1 \ The following USER variables are needed in every task. 2 TOS Saved during Task switching. 3 ENTRY Jumped to during multitasking. 4 LINK Points to next task in the circular queue 5 SP0 Empty parameter stack for this task. 6 RP0 Empty return stack for this task. 7 DP Size of dictionary. Next available location. 8 #OUT Number of characters sent since last CR. 9 #LINE Number of CR's sent since last page. 10 OFFSET Added to all block references. 11 BASE The current numeric base for number input output. 12 HLD Points to a converted character during numeric output. 13 FILE Allows printing of one file while editing another. 14 IN-FILE Allows printing of one file while editing another. 15 PRINTING indicates whether printing is enabled. Screen 11 not modified 0 \ PAUSE RESTART 21:13JWB12/07/85 1 2 PAUSE When multitasking PAUSE stops the current task and 3 passes control to the next task in the round-robin loop. 4 5 When singletasking PAUSE is equivalent to a NOOP. 6 7 RESTART When multitasking RESTART does the reverse of PAUSE. 8 It restores critical information stored in tasks user 9 variables and starts executing the task left asleep 10 during the last pass. 11 12 13 14 15 Screen 12 not modified 0 \ SLEEP WAKE STOP MULTI SINGLE 21:20JWB12/07/85 1 SLEEP ( adr -- ) Used in the form: {taskname} SLEEP 2 Make the addressed task pause indefinitely. 3 4 WAKE ( adr -- ) Used in the form: {taskname} WAKE 5 Wake up task so that it will execute next time round. 6 7 STOP ( -- -- ) Make the current task pause indefinitely. 8 9 MULTI ( -- -- ) Start the multitasker. This is done by 10 installing the scheduler/dispatcher loop and activating 11 PAUSE. 12 13 SINGLE ( -- -- ) Stop multitasking. This is done by 14 removing the scheduler/dispatcher loop and restoring 15 PAUSE to its NOOP function. Screen 13 not modified 0 \ Task Definition. 22:54JWB12/07/85 1 2 TASK: {taskname} ( size -- ) Creates a named task. A task 3 must frist be defined as a word in the dictionary. 4 Space must also be allocated for: 5 1) Its USER variable area. 6 2) Two stacks ( parameter stack and return stack). 7 3) Extra dictionary space for its I/O buffers at PAD 8 The parameter size abover is the amount of dictionary 9 space for this task. 10 11 In addition to alloting space the new task must be 12 installed in the round-robin loop. 13 Example: 14 400 TASK: MYTASK \ Creates a task called MYTASK with 400 15 \ bytes of dictionary space. Screen 14 not modified 0 \ SET-TASK 20:28JWB12/07/85 1 2 SET-TASK ( ip.adr task.adr -- ) Assign an existing task to 3 execute the code pointed to by ip.adr. This word is 4 used in ACTIVATE which is the end-user word. 5 6 ACTIVATE ( task.adr -- ) Assign the invoked task to execute 7 the following code and wake up the task makine it ready 8 to execute. 9 10 BACKGROUND: {taskname} ( -- -- ) Create a new task with 400 11 bytes of dictionary space and initialize it to execute 12 the code which follows up to the semi-colon . 13 14 15 Screen 15 not modified 0 \ Multitasking Examples. 20:28JWB12/07/85 1 ONLY EDITOR ALSO FORTH DEFINITIONS ALSO 2 2VARIABLE TCOUNT 3 : TT TCOUNT 2@ D. ; 4 5 : COUNTER 6 10000. TCOUNT 2! 7 BEGIN PAUSE 8 TCOUNT 2@ 1. D- TCOUNT 2! 9 TCOUNT 2@ D0= 10 UNTIL 11 CR " COUNTER IS DONE" VTYPE STOP ; 12 13 14 BACKGROUND: TASK1 COUNTER ; 15 Screen 16 not modified 0 \ TASK-COUNT 1 2 : TASK-COUNT 3 0. TCOUNT 2! 4 BEGIN PAUSE 5 TCOUNT 2@ 1. D+ TCOUNT 2! 6 AGAIN ; 7 8 TASK1 SLEEP 9 ' TASK-COUNT >BODY TASK1 SET-TASK 10 TASK1 WAKE 11 12 \ TASK1 SLEEP 13 \ ' COUNTER >BODY TASK1 SET-TASK 14 \ TASK1 WAKE 15 Screen 17 not modified 0 \ S.ON S.OFF TONE 13:22JWB12/08/95 1 HEX 2 : S.ON ( -- -- ) \ Turn speaker on. 3 61 PC@ 3 OR 61 PC! ; 4 : S.OFF ( -- -- ) \ Turn speaker off. 5 61 PC@ FFFC AND 61 PC! ; DECIMAL 6 7 : TONE ( freq -- ) \ Make tone of specified frequency. 8 21 MAX \ Lowest frequency. 9 1.190000 ROT \ Get divisor for timer. 10 MU/MOD \ 16bit.rem 32bit.quot 11 DROP NIP [ HEX ] \ Keep 16-bit quotient only. 12 0B6 043 PC! \ Write to timer mode register. 13 100 /MOD SWAP \ Split into hi and low byte. 14 42 PC! 42 PC! \ Store low and high byte in timer. 15 S.ON ; DECIMAL Screen 18 not modified 0 \ PIPPING 13:23JWB12/08/95 1 2 : PIPPING 3 21 TONE 4 BEGIN S.ON S.OFF 5 PAUSE 6 AGAIN ; 7 8 BACKGROUND: TASK2 PIPPING ; 9 10 11 12 13 14 15 Screen 19 not modified 0 \ VIEW-REG 10:43 12/08/85 1 ONLY EDITOR ALSO FORTH DEFINITIONS ALSO 2 VARIABLE VADR \ Holds adr of 16 bit cell 3 VARIABLE VOLD \ Holds old value. 4 : #'S 0 ?DO PAUSE # LOOP ; 5 TCOUNT 2+ VADR ! 6 : VIEWREG ( -- -- ) 15 ATRIB ! 7 BEGIN PAUSE VADR @ @ VOLD @ - 8 IF 2 BASE ! VADR @ @ DUP VOLD ! 9 0 <# ASCII ] HOLD BL HOLD 8 #'S BL HOLD 10 8 #'S BL HOLD ASCII [ HOLD #> 11 CUR@ >R 40 2 AT 12 VTYPE R> CUR! DECIMAL THEN 13 AGAIN ; 14 BACKGROUND: TASK3 VIEWREG ; 15 Screen 20 not modified 0 \ CLOCK task 1 2 : CLOCK 3 BEGIN PAUSE 4 (.TIME) PAUSE 5 CUR@ >R 6 20 2 AT VTYPE 7 R> CUR! 8 AGAIN ; 9 10 BACKGROUND: TASK4 CLOCK ; 11 12 13 14 15 Screen 21 not modified 0 \ MARQUEE 1 2 CREATE SPEED 50 , \ 1 IS FAST 1000 IS GLACIAL 3 : PAWS SPEED @ -1 ?DO PAUSE LOOP ; 4 5 CREATE TEXTB 24 , \ Beginning block for display 6 CREATE #TEXTB 2 , \ How many blocks for display 7 CREATE #T 0 , \ Offset in bytes, from TEXTB 8 \ in virtual memory. 9 10 : VTEXT ( -- adr ) \ Leave virtual address relative to TEXTB 11 #T @ 1024 /MOD TEXTB @ + BLOCK + ; 12 13 CREATE MQ? -1 , \ Flag read by MARQUEE 14 : HO MQ? OFF ; \ Halt the MARQUEE 15 : HUM MQ? ON ; \ Resume the MARQUEE Screen 22 not modified 0 \ HUH BUMP MARQ 16:02JWB12/08/85 1 CREATE RD? 0 , \ Flag read by MARQUEE 2 : HUH -1 RD? +! ; \ Back up the MARQUEE and redisplay 3 4 4 CONSTANT #BUMP \ Positions to bump to the left. 5 \ only use powers of 2. 6 7 : BUMP ( -- -- ) 8 PAD #BUMP + PAD 80 #BUMP - CMOVE ; 9 10 \ Display PAD and then bump characters to the left. 11 : MARQ ( -- -- ) 12 PAWS CUR@ 0 0 AT PAD 80 VTYPE CUR! 13 MQ? @ IF BUMP THEN ; 14 : TAIL ( -- adr count ) 15 80 #BUMP - PAD + #BUMP ; Screen 23 not modified 0 \ MARQUEE 16:12JWB12/08/85 1 2 : MARQUEE ( -- -- ) 3 BEGIN 4 CUR@ 0 0 79 0 ATRIB @ INIT-WINDOW CUR! 5 PAD 80 BLANK #T OFF 6 #TEXTB @ 1024 * 0 7 DO VTEXT TAIL CMOVE MARQ MQ? @ 8 IF #BUMP #T +! THEN RD? @ 9 IF 1 RD? +! PAD 80 BLANK -160 DUP #T +! 10 ELSE 0 THEN 11 MQ? @ IF #BUMP ELSE 0 THEN + 12 +LOOP TAIL BLANK 80 #BUMP / 0 13 DO MARQ LOOP 14 AGAIN ; 15 BACKGROUND: TASK5 MARQUEE ; Screen 24 not modified 0 WELCOME TO THE WONDERFUL WORLD OF 8086 MULTI-TASKING FORTH. 1 Multitasking allows one computer to appear to do several things 2 at the same time. Most of the time a single user computer sits 3 in an idle loop waiting for the operator to press the keyboard. 4 5 The idea is to utilize this waiting time to perform other useful 6 tasks. Typical background tasks would be watching over 7 instruments in a lab, printing a long file, updating a clock etc 8 9 F83 uses a very simple yet effective round-robin scheduling 10 technique. Task switching is extremly fast because each task 11 maintains its own parameter and return stacks and its own set 12 of critical variables ( called USER variables ). 13 14 The task switcher just changes the pointer to the correct list 15 of USER variables. Screen 25 not modified 0 WELCOME TO THE WONDERFUL WORLD OF 8086 MULTI-TASKING FORTH. 1 Now you can read your FORTH screens while you continue to hack 2 away at you FORTH system. Things to remember. SINGLE . . . 3 puts the system in the singletasking mode. MULTI . . . puts 4 the system in the multitasking mode. {taskname} WAKE . . . 5 wakes up a task. {taskname} SLEEP . . . puts task to sleep. 6 DO NOT use STOP from the terminal. It will put the forgroun 7 d task to sleep. To create a new task use the format: . . 8 BACKGROUND: {taskname} {runtime routine code} ; 9 Tasknames can be assigned new jobs using SET-TASK and 10 ACTIVATE. But be very careful. It is easy to crash if you 11 do something wrong!! First you should practice with MULTI 12 SINGLE WAKE & SLEEP using the 5 tasks that I have provided 13 then if your brave. write your own task. WARNING WARNING 14 Background tasks that output to the screen can mess up the 15 cursor. Study my examples to see how to save the cursor. Screen 26 not modified 0 \ How to use ACTIVATE reassign a taskname 1 2 3 : COUNTDOWN ( -- -- ) 4 TASK1 ACTIVATE 5 1000. TCOUNT 2! 6 BEGIN PAUSE 7 TCOUNT 2@ 1. D- TCOUNT 2! 8 TCOUNT 2@ (UD.) 9 CUR@ >R 0 2 AT VTYPE R> CUR! 10 TCOUNT 2@ D0= 11 UNTIL 12 CR " COUNTER IS DONE" VTYPE 13 STOP ; 14 15