Benutzer-Werkzeuge

Webseiten-Werkzeuge


papierkorb:4th_lesson_11

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

papierkorb:4th_lesson_11 [2025-08-16 19:10] – ↷ Seite von projects:4th_lesson_11 nach papierkorb:4th_lesson_11 verschoben mkapapierkorb:4th_lesson_11 [Unbekanntes Datum] (aktuell) – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1
Zeile 1: Zeile 1:
-=== Lesson 11 === 
  
-<code> 
-\       Lesson 11 - Terminal Program Using Interrupts 
-\       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 
- 
-                11.2  THE 8250 ACE CHIP                  11-3 
- 
-                11.3  A QUEUE DATA STRUCTURE             11-5 
- 
-                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-12 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
-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.  We 
-        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.  The main 
-        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.  The DOS functions 25H (set interrupt 
-        vector) and 35H (get interrupt vector) can be used for this purpose. 
-        The following Forth words make this easy. 
-comment; 
- 
-PREFIX  HEX 
-\       Get interrupt vector 
-CODE get.int.vector   ( int# -- seg offset ) 
-        POP AX 
-        PUSH ES 
-        PUSH BX                 \ AL = interrupt number 
-        MOV AH, # 35            \ DOS service 35H 
-        INT 21                  \ ES:BX = segment:offset 
-        MOV DX, ES              \  of interrupt handler 
-        MOV AX, BX 
-        POP BX 
-        POP ES 
-        2PUSH 
-        END-CODE 
- 
-\       Set interrupt vector 
-CODE set.int.vector   ( segment offset int# -- ) 
-        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      ( addr int# -- ) 
-        ?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     CONSTANT        COM1            \ base address for COM1 
-200     CONSTANT        COM2            \ base address for COM2 
-0C      CONSTANT        INT#1           \ interrupt number for COM1 
-0B      CONSTANT        INT#2           \ interrupt number for COM2 
-EF      CONSTANT        ENABLE4         \ interrupt 4 enable mask 
-10      CONSTANT        DISABLE4        \ interrupt 4 disable mask 
-F7      CONSTANT        ENABLE3         \ interrupt 3 enable mask 
-08      CONSTANT        DISABLE3        \ interrupt 3 disable mask 
-\       Default COM1 
-COM1    VALUE   COM                     \ current COM base address 
-INT#1   VALUE   INT#                    \ interrupt # for current COM 
-ENABLE4 VALUE   ENABLE                  \ enable mask for current COM 
-DISABLE4 VALUE  DISABLE                 \ disable mask for current COM 
- 
-\       The following values are added to the base COM address to obtain 
-\       the corresponding register addresses: 
-F8      CONSTANT        txdata          \ transmit data reg (write only) 
-F8      CONSTANT        recdat          \ receive data reg (read only) 
-FC      CONSTANT        mcr             \ modem control reg 
-F9      CONSTANT        ier             \ interrupt enable reg 
-FD      CONSTANT        lsr             \ line status reg 
-21      CONSTANT        imask           \ mask reg in PIC 
-20      CONSTANT        eoi             \ end of int value 
-20      CONSTANT        ocw2            \ PIC ocw2 
- 
-VARIABLE        int.vec.addr            \ save int vector offset address 
-VARIABLE        int.vec.seg             \ save int vector segment address 
-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 
-\       before the modem control register bits are set to enable interrupts 
-\       because the INT 14H call will undo them! 
- 
-\       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  67 , 131 , 163 , 195 , 227 , 
-\       Index   Baud rate 
-\                 300 
-\                1200 
-\                2400 
-\                4800 
-\                9600 
- 
-CODE INIT-COM   ( mask -- ) 
-                POP     AX 
-                MOV     AH, # 0 
-                MOV     DX, # 0 
-                INT     20 
-                NEXT 
-                END-CODE 
- 
-\       Default 9600 baud 
-\       Modify this word if you want to change the baud rate from the screen. 
-: get.baud#     ( -- n ) 
-                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   qbuff.seg    \ segment of queue 
-10000   CONSTANT qsize  \ size of queue in bytes 
- 
-\       Initialize queue 
-: 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        ( -- n tf | ff ) 
-                front @ rear @ <>               \ if front = rear 
-                IF                              \ then empty 
-                   INLINE 
-                      CLI                       \ disable interrupts 
-                      NEXT 
-                   END-INLINE 
-                   1 front +!                   \ inc front 
-                   front @ qmax @ >             \ if front > qmax 
-                   IF 
-                      qmin @ front !            \ then front = qmin 
-                   THEN 
-                   qbuff.seg @ front @ C@L      \ get byte 
-                   TRUE                         \ set true flag 
-                   INLINE 
-                      STI                       \ enable interrupts 
-                      NEXT 
-                   END-INLINE 
-                ELSE 
-                   FALSE                        \ set false flag 
-                THEN ; 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
-\       Store byte in AL in queue 
-LABEL   qstore 
-                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     SI                      \    dec rear 
-                CMP     SI, qmin                \    if rear < qmin 
-                JAE     3 $                        then rear = qmax 
-                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 
- 
-\       Interrupt service routine 
-\       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               \ save old int vector 
-                int.vec.addr !  int.vec.seg ! 
-                INT.SRV INT# store.int.vector ;   \ set new int vector 
- 
-\       Terminal initialization routine 
-: init.term             ( -- ) 
-                initq                           \ initialize queue 
-                int.setup                       \ set up interrupts 
-                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   VALUE   ?>disk          \ flag to "send to disk" 
-0       VALUE   col.at          \ saved cursor position 
-0       VALUE   row.at 
- 
-VARIABLE t_handle               \ terminal file handle 
-CREATE edit_buff  70 ALLOT      \ temporary edit buffer 
- 
-: $HCREATE      ( addr -- f )   \ create file for counted string at addr 
-                SEQHANDLE HCLOSE DROP 
-                SEQHANDLE $>HANDLE 
-                SEQHANDLE HCREATE ; 
- 
-: file.open.error       ( -- ) 
-                33 12 65 14 box&fill 
-                ." 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.  Data coming in 
-\       the serial port will be sent to this file.  This word will be 
-\       called by pressing function key F1. 
- 
-: select.nil.file       ( -- ) 
-                20 4 60 7 box&fill 
-                ." Enter a filename" 
-                "  " ">$ 
-                edit_buff OVER C@ 1+ CMOVE 
-                21 6 edit_buff 30 lineeditor 
-                IF 
-                   edit_buff $HCREATE 
-                   IF 
-                      file.open.error 
-                   ELSE 
-                      SEQHANDLE >HNDLE @ 
-                      DUP handl ! t_handle ! 
-                      TRUE !> ?>disk 
-                   THEN 
-                THEN ; 
- 
-: >term         ( -- ) 
-                t_handle @ handl ! ; 
- 
-\       Pressing function key F1 will turn 'data capture' on 
-: disk.on.nil       ( -- ) 
-                IBM-AT? !> row.at !> col.at 
-                SAVESCR 
-                select.nil.file 
-                RESTSCR 
-                col.at row.at AT ; 
- 
-\       Pressing function key F2 will turn 'data capture' off 
-: disk.off      ( -- ) 
-                t_handle @ ?DUP 
-                IF 
-                   close.file 
-                   0 t_handle ! 
-                THEN 
-                FALSE !> ?>disk ; 
- 
-\       Transmit ascii code out serial port 
-: 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 
- 
-\       Pressing CTRL P will toggle the printer on and off 
-: ?PRINT        ( -- ) 
-                PRINTING C@ NOT PRINTING C! ; 
- 
-\       Send character to the screen 
-: do.emit       ( n -- ) 
-                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 
-                   ?>disk                       \ if data capture on 
-                   IF 
-                      DUP >term send.byte          send to disk 
-                   THEN 
-                   do.emit                      \ send to screen 
-                ELSE 
-                   DROP 
-                THEN ; 
- 
-comment: 
- 
- 
- 
-11.5  DOWNLOADING FILES 
- 
-        The following words can be used to download a file containing 
-        MaxForth code to the 68HC11.  MaxForth will load a line at a 
-        time, compiling the words in the dictionary.  After loading a 
-        line it will send a line-feed (ASCII 10) back to the PC. 
-comment; 
- 
-VARIABLE        wait.count 
- 
-\       Transmit a string given its address and length 
- 
-: xmt.str       ( addr cnt -- )    \ XMT string + CR 
-                0 DO 
-                   DUP I + C@ 
-                   XMT 
-                LOOP 
-                DROP 
-                13 XMT ; 
- 
-\       Wait for a particular character to be received 
- 
-: wait.for      ( ascii -- ) 
-                0 wait.count ! 
-                BEGIN 
-                   checkq                       \ char n tf | char ff 
-                   IF                           \ char n    | char 
-                      DUP ?EMIT                 \ char n 
-                      OVER =                    \ char f 
-                      0 wait.count ! 
-                   ELSE 
-                      1 wait.count +! FALSE                 char ff 
-                   THEN 
-                   wait.count @ 32000 =         \ char f f 
-                   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 ; 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
-\       Download a file to the 68HC11 
- 
-: file.download         ( -- ) 
-                GETFILE 
-                DARK 
-                IF 
-                   $HOPEN 
-                   IF 
-                      file.open.error 
-                   ELSE 
-                      ." File: " .SEQHANDLE CR 
-                      BEGIN 
-                         LINEREAD COUNT 2-              \ addr cnt 
-                         OVER C@ 26 = NOT               \ while not EOF 
-                      WHILE 
-                         xmt.str                        \ send line 
-                         10 wait.for                    \ wait for LF 
-                      REPEAT 
-                      CLOSE 
-                   THEN 
-                ELSE 
-                   2R> 2DROP 
-                   EXIT                                 \ exit DO-KEY 
-                THEN ; 
- 
-comment: 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
-11.6  MAIN TERMINAL PROGRAM 
- 
-        Pressing the ESC key will exit the terminal word HOST 
-comment; 
- 
-: ESC.HOST      ( -- ) 
-                disable.term                    \ disable all interrupts 
-                disk.off                        \ close file if necessary 
-                qbuff.seg @ release.mem         \ release queue buffer 
-                DARK 
-                ABORT ; 
- 
-\       This is the jump table for all key pressings 
- 
-EXEC.TABLE DO-KEY 
-        CONTROL P | ?PRINT     ( PRINTER ON/OFF ) 
-              27  | ESC.HOST        ( ESCAPE KEY ) 
-              187 | disk.on.nil     ( F1 )     188 | disk.off     ( F2 ) 
-              189 | file.download   ( F3 )     190 | UNUSED       ( F4 ) 
-              191 | UNUSED          ( F5 )     192 | UNUSED       ( F6 ) 
-              193 | UNUSED          ( F7 )     194 | UNUSED       ( F8 ) 
-              195 | UNUSED          ( F9 )     196 | UNUSED       ( F10 ) 
- 
-              199 | UNUSED      ( HOME )   200 | UNUSED       ( UP ) 
-              201 | UNUSED      ( PUP )    203 | UNUSED       ( LEFT ) 
-              205 | UNUSED      ( RIGHT )  207 | UNUSED       ( END ) 
-              208 | UNUSED      ( DOWN )   209 | UNUSED       ( PGDN ) 
-              210 | UNUSED      ( INS  )   211 | UNUSED       ( DEL  ) 
-           DEFAULT|  XMT 
- 
- 
-: T-LINK        ( -- ) 
-                set.baud.rate 
-                CURSOR-ON 
-                FALSE !> ?>disk 
-                DARK 
-                ." 4thterm is on-line..." CR CR 
-                init.term ; 
- 
-\       To run the terminal program, type HOST 
- 
-: HOST          T-LINK 
-                BEGIN 
-                   KEY? 
-                   IF 
-                      KEY DO-KEY 
-                   THEN 
-                   checkq 
-                   IF 
-                      ?EMIT 
-                   THEN 
-                AGAIN ; 
- 
- 
-</code> 
papierkorb/4th_lesson_11.1755364236.txt.gz · Zuletzt geändert: 2025-08-16 19:10 von mka