papierkorb:4th_lesson_11
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| papierkorb:4th_lesson_11 [2025-08-16 19:10] – ↷ Seite von projects:4th_lesson_11 nach papierkorb:4th_lesson_11 verschoben mka | papierkorb:4th_lesson_11 [Unbekanntes Datum] (aktuell) – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1 | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | === Lesson 11 === | ||
| - | < | ||
| - | \ | ||
| - | \ The Forth Course | ||
| - | \ by Richard E. Haskell | ||
| - | \ Dept. of Computer Science and Engineering | ||
| - | \ Oakland University, Rochester, MI 48309 | ||
| - | |||
| - | comment: | ||
| - | |||
| - | |||
| - | |||
| - | Lesson 11 | ||
| - | |||
| - | TERMINAL PROGRAM USING INTERRUPTS | ||
| - | |||
| - | |||
| - | 11.1 8086/8088 INTERRUPTS | ||
| - | |||
| - | 11.2 THE 8250 ACE CHIP 11-3 | ||
| - | |||
| - | 11.3 A QUEUE DATA STRUCTURE | ||
| - | |||
| - | 11.4 SENDING CHARACTERS TO THE SCREEN | ||
| - | AND/OR TO DISK 11-8 | ||
| - | |||
| - | 11.5 DOWNLOADING FILES 11-10 | ||
| - | |||
| - | 11.6 MAIN TERMINAL PROGRAM | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | 11.1 8086/8088 INTERRUPTS | ||
| - | |||
| - | In this lesson we will write a terminal program using interrupts | ||
| - | that we can use to communicate with other computers or to | ||
| - | download Forth code to Forth chips such as the 68HC11 single-chip | ||
| - | microcomputer that contains Max-Forth. | ||
| - | |||
| - | We will want to communicate at baud rates up to 9600 baud. This | ||
| - | means that we will need to use interrupts to store incoming | ||
| - | characters without losing them while scrolling the screen. | ||
| - | will write an interrupt service routine that is called every time | ||
| - | a character is received in the serial port. This interrupt service | ||
| - | routine will read the character and store it in a queue. | ||
| - | terminal program will then alternate between checking the keyboard | ||
| - | for key pressings and checking the queue for received characters. | ||
| - | When a key is pressed the character will be transmitted out the | ||
| - | serial port. When a character is in the queue (i.e. has been | ||
| - | received in the serial port) it will be displayed on the screen | ||
| - | and, optionally, stored on disk. | ||
| - | |||
| - | The segment and offset addresses of the interrupt service routine | ||
| - | must be stored in the interrupt vector table at the beginning of | ||
| - | segment zero in memory. | ||
| - | vector) and 35H (get interrupt vector) can be used for this purpose. | ||
| - | The following Forth words make this easy. | ||
| - | comment; | ||
| - | |||
| - | PREFIX | ||
| - | \ Get interrupt vector | ||
| - | CODE get.int.vector | ||
| - | POP AX | ||
| - | PUSH ES | ||
| - | PUSH BX \ AL = interrupt number | ||
| - | MOV AH, # 35 \ DOS service 35H | ||
| - | INT 21 \ ES:BX = segment: | ||
| - | MOV DX, ES \ of interrupt handler | ||
| - | MOV AX, BX | ||
| - | POP BX | ||
| - | POP ES | ||
| - | 2PUSH | ||
| - | END-CODE | ||
| - | |||
| - | \ Set interrupt vector | ||
| - | CODE set.int.vector | ||
| - | POP AX \ AL = interrupt number | ||
| - | POP DX \ DX = offset addr | ||
| - | POP BX \ BX = segment addr | ||
| - | MOV AH, # 25 \ DOS service 25H | ||
| - | PUSH DS \ save DS | ||
| - | MOV DS, BX \ DS:DX -> int handler | ||
| - | INT 21 \ DOS INT 21H | ||
| - | POP DS \ restore DS | ||
| - | NEXT | ||
| - | END-CODE | ||
| - | |||
| - | \ Store interrupt vector of routine at addr | ||
| - | : store.int.vector | ||
| - | ?CS: -ROT set.int.vector ; | ||
| - | |||
| - | \ We will need words from Lessons 7, 8 and 10. Therefore, | ||
| - | \ we will FLOAD these files. | ||
| - | DECIMAL | ||
| - | |||
| - | fload lesson7 | ||
| - | fload lesson8 | ||
| - | fload lesson10 | ||
| - | |||
| - | comment: | ||
| - | |||
| - | 11.2 THE 8250 ACE CHIP | ||
| - | Serial communication is handled by the 8250 Asynchronous | ||
| - | Communication Element (ACE) chip. The interrupt line from | ||
| - | this chip goes to IRQ4 of the Priority Interrupt Controller (PIC) | ||
| - | chip for COM1 and to IRQ3 of the PIC for COM2. OUT2 of the modem | ||
| - | control register of the 8250 must be set to enable the output | ||
| - | buffer of the 8250 IRQ line. | ||
| - | comment; | ||
| - | |||
| - | HEX | ||
| - | 300 | ||
| - | 200 | ||
| - | 0C CONSTANT | ||
| - | 0B CONSTANT | ||
| - | EF CONSTANT | ||
| - | 10 CONSTANT | ||
| - | F7 CONSTANT | ||
| - | 08 CONSTANT | ||
| - | \ | ||
| - | COM1 VALUE | ||
| - | INT#1 | ||
| - | ENABLE4 VALUE | ||
| - | DISABLE4 VALUE DISABLE | ||
| - | |||
| - | \ The following values are added to the base COM address to obtain | ||
| - | \ the corresponding register addresses: | ||
| - | F8 CONSTANT | ||
| - | F8 CONSTANT | ||
| - | FC CONSTANT | ||
| - | F9 CONSTANT | ||
| - | FD CONSTANT | ||
| - | 21 CONSTANT | ||
| - | 20 CONSTANT | ||
| - | 20 CONSTANT | ||
| - | |||
| - | VARIABLE | ||
| - | VARIABLE | ||
| - | DECIMAL | ||
| - | |||
| - | |||
| - | |||
| - | \ We will use the BIOS INT 14H (20 decimal) initialize communications | ||
| - | \ port routine (AH = 0) to set the baud rate. This MUST be done | ||
| - | \ | ||
| - | \ | ||
| - | |||
| - | \ The following table contains the control register masks | ||
| - | \ for baud rates of 300, 1200, 2400, 4800 and 9600 | ||
| - | \ with no parity, 8 data bits and 1 stop bit. | ||
| - | |||
| - | CREATE baud.table | ||
| - | \ | ||
| - | \ | ||
| - | \ | ||
| - | \ | ||
| - | \ | ||
| - | \ | ||
| - | |||
| - | CODE INIT-COM | ||
| - | POP AX | ||
| - | MOV AH, # 0 | ||
| - | MOV DX, # 0 | ||
| - | INT 20 | ||
| - | NEXT | ||
| - | END-CODE | ||
| - | |||
| - | \ | ||
| - | \ | ||
| - | : get.baud# | ||
| - | 4 ; | ||
| - | |||
| - | : set.baud.rate | ||
| - | get.baud# 2* | ||
| - | baud.table + @ | ||
| - | INIT-COM ; | ||
| - | |||
| - | comment: | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | 11.3 A QUEUE DATA STRUCTURE | ||
| - | A circular queue will be used to store the received characters | ||
| - | in an interrupt service routine | ||
| - | |||
| - | The following pointers are used to define the queue | ||
| - | comment; | ||
| - | |||
| - | VARIABLE front \ pointer to front of queue (oldest data at front+1) | ||
| - | VARIABLE rear \ pointer to rear of queue (most recent data at rear) | ||
| - | VARIABLE qmin \ pointer to first byte in queue | ||
| - | VARIABLE qmax \ pointer to last byte in queue | ||
| - | VARIABLE | ||
| - | 10000 | ||
| - | |||
| - | \ | ||
| - | : initq ( -- ) | ||
| - | qsize alloc.mem qbuff.seg ! \ allocate memory for queue | ||
| - | 0 front ! \ front = 0 | ||
| - | 0 rear ! \ rear = 0 | ||
| - | 0 qmin ! \ qmin = 0 | ||
| - | qsize 1- qmax ! ; \ qmax = qsize - 1 | ||
| - | |||
| - | \ Check queue | ||
| - | : checkq | ||
| - | front @ rear @ <> | ||
| - | IF \ then empty | ||
| - | | ||
| - | CLI \ disable interrupts | ||
| - | NEXT | ||
| - | | ||
| - | 1 front +! \ inc front | ||
| - | front @ qmax @ > \ if front > qmax | ||
| - | IF | ||
| - | qmin @ front ! \ then front = qmin | ||
| - | THEN | ||
| - | | ||
| - | | ||
| - | | ||
| - | STI \ enable interrupts | ||
| - | NEXT | ||
| - | | ||
| - | ELSE | ||
| - | | ||
| - | THEN ; | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | \ Store byte in AL in queue | ||
| - | LABEL | ||
| - | PUSH SI | ||
| - | PUSH ES | ||
| - | MOV SI, qbuff.seg | ||
| - | MOV ES, SI \ ES = qbuff.seg | ||
| - | INC rear WORD \ inc rear | ||
| - | MOV SI, rear \ if rear > qmax | ||
| - | CMP SI, qmax | ||
| - | JBE 2 $ | ||
| - | MOV SI, qmin \ then rear = qmin | ||
| - | MOV rear SI | ||
| - | 2 $: CMP SI, front \ if front = rear | ||
| - | JNE 4 $ \ then full | ||
| - | DEC | ||
| - | CMP SI, qmin \ if rear < qmin | ||
| - | JAE 3 $ | ||
| - | MOV SI, qmax | ||
| - | MOV rear SI | ||
| - | 3 $: POP ES | ||
| - | POP SI | ||
| - | RET | ||
| - | 4 $: MOV ES: 0 [SI], AL \ else store at rear | ||
| - | POP ES | ||
| - | POP SI | ||
| - | RET | ||
| - | END-CODE | ||
| - | |||
| - | \ | ||
| - | \ This routine gets data from the receive serial port | ||
| - | \ and stores it in the queue. | ||
| - | LABEL INT.SRV | ||
| - | PUSH AX | ||
| - | PUSH DX | ||
| - | PUSH DS | ||
| - | MOV AX, CS | ||
| - | MOV DS, AX \ DS = CS | ||
| - | MOV DX, # COM \ if data is ready | ||
| - | ADD DX, # lsr | ||
| - | IN AL, DX | ||
| - | TEST AL, # 1 | ||
| - | JE 1 $ | ||
| - | MOV DX, # COM | ||
| - | ADD DX, # recdat | ||
| - | IN AL, DX \ read it | ||
| - | CALL qstore | ||
| - | 1 $: MOV AL, # eoi | ||
| - | MOV DX, # ocw2 | ||
| - | OUT DX, AL \ clear eoi | ||
| - | POP DS | ||
| - | POP DX | ||
| - | POP AX | ||
| - | IRET | ||
| - | END-CODE | ||
| - | |||
| - | \ Set up interrupts | ||
| - | : int.setup | ||
| - | 12 COM mcr + PC! \ modem cr out2 lo | ||
| - | 1 COM ier + PC! \ enable recv int | ||
| - | INT# get.int.vector | ||
| - | int.vec.addr ! int.vec.seg ! | ||
| - | INT.SRV INT# store.int.vector ; \ set new int vector | ||
| - | |||
| - | \ | ||
| - | : init.term | ||
| - | initq \ initialize queue | ||
| - | int.setup | ||
| - | imask PC@ | ||
| - | ENABLE AND \ enable irq4 (COM1 default) | ||
| - | imask PC! ; | ||
| - | |||
| - | : disable.term | ||
| - | imask PC@ | ||
| - | DISABLE OR \ disable irq4 (COM1 default) | ||
| - | imask PC! | ||
| - | 0 COM mcr + PC! \ 0 -> modem control reg | ||
| - | int.vec.seg @ \ restore original | ||
| - | int.vec.addr @ \ interrupt vector | ||
| - | INT# set.int.vector ; | ||
| - | comment: | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | 11.4 SENDING CHARACTERS TO THE SCREEN AND/OR TO DISK | ||
| - | Characters in the queue will be displayed on the screen and, | ||
| - | optionally, sent to a disk file. | ||
| - | comment; | ||
| - | |||
| - | FALSE | ||
| - | 0 | ||
| - | 0 | ||
| - | |||
| - | VARIABLE t_handle | ||
| - | CREATE edit_buff | ||
| - | |||
| - | : $HCREATE | ||
| - | SEQHANDLE HCLOSE DROP | ||
| - | SEQHANDLE $>HANDLE | ||
| - | SEQHANDLE HCREATE ; | ||
| - | |||
| - | : file.open.error | ||
| - | 33 12 65 14 box& | ||
| - | ." Could not open file!!" | ||
| - | KEY DROP ; | ||
| - | |||
| - | \ The following word will display a window on the screen in which | ||
| - | \ to enter a filename, which will then be opened. | ||
| - | \ the serial port will be sent to this file. This word will be | ||
| - | \ | ||
| - | |||
| - | : select.nil.file | ||
| - | 20 4 60 7 box& | ||
| - | ." Enter a filename" | ||
| - | " | ||
| - | edit_buff OVER C@ 1+ CMOVE | ||
| - | 21 6 edit_buff 30 lineeditor | ||
| - | IF | ||
| - | | ||
| - | IF | ||
| - | file.open.error | ||
| - | ELSE | ||
| - | SEQHANDLE >HNDLE @ | ||
| - | DUP handl ! t_handle ! | ||
| - | TRUE !> ?>disk | ||
| - | THEN | ||
| - | THEN ; | ||
| - | |||
| - | : > | ||
| - | t_handle @ handl ! ; | ||
| - | |||
| - | \ | ||
| - | : disk.on.nil | ||
| - | IBM-AT? !> row.at !> col.at | ||
| - | SAVESCR | ||
| - | select.nil.file | ||
| - | RESTSCR | ||
| - | col.at row.at AT ; | ||
| - | |||
| - | \ | ||
| - | : disk.off | ||
| - | t_handle @ ?DUP | ||
| - | IF | ||
| - | | ||
| - | 0 t_handle ! | ||
| - | THEN | ||
| - | FALSE !> ?>disk ; | ||
| - | |||
| - | \ | ||
| - | : XMT ( ascii -- ) | ||
| - | COM \ use base address in COM | ||
| - | BEGIN | ||
| - | DUP lsr + \ wait for bit 5 in line status | ||
| - | PC@ 32 AND \ register (TDRE) to be set | ||
| - | UNTIL | ||
| - | txdata + PC! ; \ send data | ||
| - | |||
| - | \ | ||
| - | : ? | ||
| - | PRINTING C@ NOT PRINTING C! ; | ||
| - | |||
| - | \ Send character to the screen | ||
| - | : do.emit | ||
| - | DUP 13 = \ if CR | ||
| - | IF | ||
| - | DROP CR \ do a carriage return | ||
| - | ELSE | ||
| - | DUP 32 >= \ ignore other control characters | ||
| - | IF | ||
| - | EMIT | ||
| - | ELSE | ||
| - | DROP | ||
| - | THEN | ||
| - | THEN ; | ||
| - | |||
| - | : ?EMIT ( n -- ) | ||
| - | 127 AND \ mask parity bit | ||
| - | DUP 13 = \ ignore control char | ||
| - | OVER 10 = OR \ other than CR and LF | ||
| - | OVER 32 >= OR | ||
| - | IF | ||
| - | ?> | ||
| - | IF | ||
| - | DUP >term send.byte | ||
| - | THEN | ||
| - | | ||
| - | ELSE | ||
| - | DROP | ||
| - | THEN ; | ||
| - | |||
| - | comment: | ||
| - | |||
| - | |||
| - | |||
| - | 11.5 DOWNLOADING FILES | ||
| - | |||
| - | The following words can be used to download a file containing | ||
| - | MaxForth code to the 68HC11. | ||
| - | time, compiling the words in the dictionary. | ||
| - | line it will send a line-feed (ASCII 10) back to the PC. | ||
| - | comment; | ||
| - | |||
| - | VARIABLE | ||
| - | |||
| - | \ | ||
| - | |||
| - | : xmt.str | ||
| - | 0 DO | ||
| - | DUP I + C@ | ||
| - | XMT | ||
| - | LOOP | ||
| - | DROP | ||
| - | 13 XMT ; | ||
| - | |||
| - | \ Wait for a particular character to be received | ||
| - | |||
| - | : wait.for | ||
| - | 0 wait.count ! | ||
| - | BEGIN | ||
| - | | ||
| - | | ||
| - | DUP ?EMIT \ char n | ||
| - | OVER = \ char f | ||
| - | 0 wait.count ! | ||
| - | ELSE | ||
| - | 1 wait.count +! FALSE | ||
| - | THEN | ||
| - | | ||
| - | IF | ||
| - | CONTROL G EMIT 2DROP \ beep -- no response | ||
| - | CR ." No response..." | ||
| - | KEY DROP | ||
| - | 2R> 2DROP \ exit wait.for | ||
| - | 2R> 2DROP \ exit file.download | ||
| - | EXIT \ exit DO-KEY | ||
| - | THEN | ||
| - | UNTIL | ||
| - | DROP ; | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | \ | ||
| - | |||
| - | : file.download | ||
| - | GETFILE | ||
| - | DARK | ||
| - | IF | ||
| - | | ||
| - | IF | ||
| - | file.open.error | ||
| - | ELSE | ||
| - | ." File: " .SEQHANDLE CR | ||
| - | BEGIN | ||
| - | | ||
| - | OVER C@ 26 = NOT \ while not EOF | ||
| - | WHILE | ||
| - | | ||
| - | 10 wait.for | ||
| - | REPEAT | ||
| - | CLOSE | ||
| - | THEN | ||
| - | ELSE | ||
| - | | ||
| - | | ||
| - | THEN ; | ||
| - | |||
| - | comment: | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | 11.6 MAIN TERMINAL PROGRAM | ||
| - | |||
| - | Pressing the ESC key will exit the terminal word HOST | ||
| - | comment; | ||
| - | |||
| - | : ESC.HOST | ||
| - | disable.term | ||
| - | disk.off | ||
| - | qbuff.seg @ release.mem | ||
| - | DARK | ||
| - | ABORT ; | ||
| - | |||
| - | \ This is the jump table for all key pressings | ||
| - | |||
| - | EXEC.TABLE DO-KEY | ||
| - | CONTROL P | ? | ||
| - | 27 | ESC.HOST | ||
| - | 187 | disk.on.nil | ||
| - | 189 | file.download | ||
| - | 191 | UNUSED | ||
| - | 193 | UNUSED | ||
| - | 195 | UNUSED | ||
| - | |||
| - | 199 | UNUSED | ||
| - | 201 | UNUSED | ||
| - | 205 | UNUSED | ||
| - | 208 | UNUSED | ||
| - | 210 | UNUSED | ||
| - | | ||
| - | |||
| - | |||
| - | : T-LINK | ||
| - | set.baud.rate | ||
| - | CURSOR-ON | ||
| - | FALSE !> ?>disk | ||
| - | DARK | ||
| - | ." 4thterm is on-line..." | ||
| - | init.term ; | ||
| - | |||
| - | \ To run the terminal program, type HOST | ||
| - | |||
| - | : HOST T-LINK | ||
| - | BEGIN | ||
| - | KEY? | ||
| - | IF | ||
| - | KEY DO-KEY | ||
| - | THEN | ||
| - | | ||
| - | IF | ||
| - | ?EMIT | ||
| - | THEN | ||
| - | AGAIN ; | ||
| - | |||
| - | |||
| - | </ | ||
papierkorb/4th_lesson_11.1755364236.txt.gz · Zuletzt geändert: 2025-08-16 19:10 von mka