I/O Port Examples This file contains four examples using I/O Ports Example 1: Keyboard Input Example This example shows fragments of a program that gets input from the keyboard. Fragment 1: Indicate that interrupts are not allowed (just done once near the beginning of the program). …. ; set Keyboard Control Port to indicate interrupts ; not allowed MOV DX,0000H MOV AL,0b OUT [DX],AL …. Fragment 2: Wait until input is ready and then read it in (done every time input is needed), and process it. …. ; wait for input (polling with busy waiting loop) using ; Keyboard Status Port MOV DX,0001H PollLoop: IN AL,[DX] AND AL,010b ; result of AND will be 1 if data is ready JZ PollLoop ; we have input, so get it (Keyboard Data Port) MOV DX,0002H IN AL,[DX] ; process AL (ASCII character) … Example 2: Display I/O Example This example shows an ISR, MoveChar, that reads in the character just before the current cursor position and prints it in the upper left hand corner of the otherwise blank screen. It returns 0 if it cannot access the position before the current cursor position (i.e. cursor at 0,0), and otherwise it returns 1. ; boolean MoveChar ( ) [ISR] ; read character just before current cursor position and print ; in upper left corner of otherwise blank screen ; return 0 if cannot access position before cursor ; (i.e. cursor at 0, 0); return 1 otherwise Outline: MoveChar: PUSH MOV ; PUSH …. BP BP,SP To add later ; these two lines are optional ; as MoveChar has no parameters ; 1. get current cursor row and column ; 2. move to previous position (if possible) ; 3. get character ; 4. clear screen (which also homes cursor) ; 5. write character at (0, 0) ; 6. set return value Done: ; POP …. POP IRET To add later BP ; required if the first two lines present ; 1. get current cursor row and column MOV DX,04EAH ; column IN AL,[DX] MOV CL,AL ; column in CL MOV DX,04EBH ; row IN AL,[DX] ; row in AL ; used CX, DX ; 2. move to previous position (if possible) CMP CL,0 ; are we at the start of a row? JE MoveToPrevRow SUB CL,1 JMP HavePosn MoveToPrevRow: CMP AL,0 ; are we at (0, 0)? JE Problem SUB AL,1 ; move to end of prev row MOV CL,39 ; column is now 39 JMP HavePosn Problem: MOV AL,0 ; return value JMP Done ; 3. get character ; (calculate port 0100H + 40 * row + col) MOV DX,0100H MOV CH,40 MUL CH ; AX = 40*AL (AL = row) ADD DX,AX MOV CH,0 ADD DX,CX ; add on col (CL) IN AL,[DX] ; get character at that position MOV CL,AL ; store character in CL ; (as AL will be overwritten by clear screen) ; 4. clear screen (which homes cursor) MOV DX,04E8H MOV AL,0001b ; clear screen is bit 0 OUT [DX],AL ; 5. write character at current cursor position (0,0) ; (and advance cursor) ; Note that if we use port 0100H it will write to position (0,0) but ; the cursor will remain on top, so the value is not visible MOV DX,04E9H MOV AL,CL ; character to display OUT [DX],AL ; 6. set return value MOV AL,1 ; everything ok Updated Stack Frame for MoveChar: Note: registers to PUSH and POP are: CX and DX (only) MoveChar: PUSH MOV PUSH PUSH BP BP,SP CX DX ; code for 1. to 6. above goes here Done: POP POP POP IRET DX CX BP Example 3: Display I/O Example This example shows a subroutine (not an ISR), MoveCharTo (similar to MoveChar) that reads in the character just before the current cursor position and prints it at the Row, Col indicated. It returns 0 if it cannot access the position before the current cursor position (i.e. cursor at 0,0) or if Row and/or Col are not valid, and otherwise it returns 1. ; boolean MoveCharTo ( byte Row, byte Col ) [regular subroutine] ; read character just before current cursor position and print ; in position indicated of otherwise blank screen ; return 0 if cannot access position previous to cursor ; (i.e. cursor at 0, 0), or if Row not in range 0-24, ; or if Column not in range 0-39; return 1 otherwise Uses: ; word GetCursorPosn ( ) [regular subroutine] ; returns the row and column of the current cursor position ; (row is in AH, column in AL) And: ; word ReturnPort (byte Row, byte Col) [regular subroutine] ; returns the display Port corresponding to the given ; Row and Column; returns –1 if Row >24 or Column >39 Outline: MoveCharTo: PUSH MOV ; PUSH …. BP BP,SP To add later ; required as there are parameters ; get parameters MOV MOV BH,[BP+4] BL,[BP+6] ; row ; col (used BX) ; 1. get current cursor row and column ; 2. calculate port ; 3. subtract 1 from port (if possible) ; 4. get character ; 5. clear screen ; 6. get port for desired screen location (if possible) ; 7. write character and move cursor if it’s on top ; 8. set return value Done2: ; POP …. POP RET To add later BP ; regular subroutine ; 1. get current cursor row and column Call GetCursorPosn MOV CL,AL ; column MOV AL,AH ; row ; used CX ; 2. calculate port PUSH PUSH CALL ADD MOV CMP JE ; used DX CX AX ReturnPort SP,4 DX,AX DX,-1 Problem2 ; column ; row ; port returned in AX ; see if there was a problem ; 3. subtract 1 (if possible) CMP DX,0100H JE Problem2 SUB DX,1 JMP HavePosn2 Problem2: MOV AX,0 JMP Done2 ; are we at 0, 0? ; decrement port ; return value ; 4. get character (already have port) HavePosn2: IN AL,[DX] ; get character at that position MOV CL,AL ; store character in CL ; 5. clear screen (which will home the cursor, too) MOV DX,04E8H MOV AL,0001b ; clear screen is bit 0 OUT [DX],AL ; 6. get port for desired screen location (if possible) PUSH BX ; col (BL) MOV AL,BH PUSH AX ; row (BH) CALL ReturnPort ADD SP,4 MOV DX,AX ; port returned in AX CMP DX,-1 ; see if there was a problem JE Problem2 ; 7. write character (move cursor forward if writing to 0,0) CMP DX,0100H JNE WriteChar ; if we are writing to 0,0 MOV DX,04E9H ; use non-mapped port ; which will advance cursor WriteChar: MOV AL,CL ; character to display OUT [DX],AL ; 8. set return value MOV AL,1 ; everything ok Updated Stack Frame for MoveCharTo: Used registers BX, CX, and DX (only) MoveCharTo: PUSH MOV PUSH PUSH PUSH BP BP,SP BX CX DX ; code for 1. to 6. above goes here Done2: POP POP POP POP RET DX CX BX BP ; regular subroutine Sub-subroutines: ; word GetCursorPosn ( ) [regular subroutine] ; returns the row and column of the current cursor position ; (row is in AH, column in AL) GetCursorPosn: PUSH MOV PUSH BP BP,SP DX MOV IN MOV MOV IN DX,04EBH AL,[DX] AH,AL DX,04EAH AL,[DX] POP POP RET DX BP ; only register used ; row ; row now in AH ; column ; column in AL ; word ReturnPort (byte Row, byte Col) [regular subroutine] ; returns the display Port corresponding to the given ; Row and Column; returns –1 if Row >24 or Column >39 ReturnPort: PUSH MOV PUSH PUSH MOV MOV BP BP,SP BX CX BL,[BP+4] ; row CL,[BP+6] ; column ; check parameters CMP BL,24 JBE RowOK MOV AX,-1 JMP RetPortDone RowOK: CMP CL,39 JBE ColOK MOV AX,-1 JMP RetPortDone ColOK: ; calculate port MOV MUL MOV ADD ADD RetPortDone: POP POP POP RET ; parms are ok AL,40 BL CH,0 AX,CX AX,0100H CX BX BP ; AX = 40*BL (BL = row) ; add on col (CL) ; add on offset to first port Example 4: A/D Converter Example Suppose that we want to collect temperature readings every 5 seconds and these readings are converted to binary via an A/D converter as studied in the class slides. Assume that the A/D converter has 1. an 8-bit Control port at 1000H (bit 7 =1 => take a reading, all other bits unused), 2. an 8 bit Status port at 1001H (bit 7 = 1 => data is ready, bit 0 = 1 => A/D converter is enabled, all other bits unused), and 3. an 8 bit Data port at 1002H where the digital temperature reading is presented. Fragment 0: Initialize timer to expire after “delta t” time == [WAITTIME] ticks. MOV MOV OUT DX, 10H ;TIMER: control port AL, 1010B ;stop timing, clear count done, ;disable interrupt [DX], AL MOV MOV OUT AX, [WAITTIME] ;number of ticks DX, 12H ;TIMER: reload value lsB [DX], AL MOV MOV OUT DX, 13H AL, AH [DX], AL ;TIMER: reload value msB Fragment 1: Start timer. RETIME: MOV MOV OUT DX, 10H ;TIMER: control port AL, 0100B ;copy reload value and start timer [DX], AL Fragment 2: Ask the A/D converter to take a reading. MOV IN AND JZ DX, 1001H AL,[DX] AL,1B DisabledError ;Converter status port ;Get status ;enabled bit ;Not functional ; should we also check if data is already ‘ready’? MOV MOV OUT DX, 1000H AL, 80H [DX], AL ;Converter control port ;Ask to take a reading Fragment 3: Get a temperature reading from converter MOV DX, 1001H ;Converter status port WAITFORDATA: IN AL,[DX] ;Get status AND AL,80H ;data ready bit JZ WAITFORDATA ;poll until data ready MOV IN DX,1002H AL, [DX] ;Converter data port ;get temperature value Fragment 4: Application specific processing – suppose temperature is stored in a byte array pointed to by BX, and whose size is in ArraySize. SI is array index. INC CMP JE MOV SI ;bump array index SI, Word Ptr[ArraySize] TooManyError ;error: array is full [BX+SI],AL ;store temp in next byte Fragment 5: Delay for rest of delta t MOV DELAYMORE: IN AND JZ DX, 11H ;Timer status port AL, [DX] AL,10B DELAYMORE ;count done?