;//--------------------------------------------------------------- ;// arrows.s ;// ;// This example shows how to directly program the cursor's ;// location and height while in standard text display-mode ;// Here the keyboard is "polled" for new input rather than ;// being "interrupt-driven" as is customary. ;// ;// assemble with: $ as86 arrows.s -b arrows.b ;// install using: $ dd if=arrows.b of=/dev/fd0 seek=1 ;// ;// NOTE: This code begins executing with CS:IP = 1000:0002. ;// ;// programmer: ALLAN CRUSE ;// date begun: 13 MAR 2004 ;// completion: 22 MAR 2004 ;//--------------------------------------------------------------- .SECT .TEXT ;----------------------------------------------------------------- .WORD 0xABCD ; programming signature ;----------------------------------------------------------------- main: mov ax, cs ; address this segment mov ds, ax ; with DS register pop dword return_address ; store return-address mov ss, ax ; adjust SS register lea esp, tos0 ; and set new stacktop call initialize_video_ram call initialize_cursor_ht call exec_arrow_keys_demo push dword return_address ; recover our exit-address retf ; exit to program launcher ;----------------------------------------------------------------- return_address: .LONG 0 ; to store exit-address ;----------------------------------------------------------------- ; EQUATES for keyboard scancodes KEYPAD_MIN EQU 0x47 ; scancode for -key KEYPAD_MAX EQU 0x51 ; scancode for -key KEY_ESCAPE EQU 0x01 ; scancode for ;----------------------------------------------------------------- ; storage for cursor-location coordinates page: .BYTE 0 ; video page-number row: .BYTE 0 ; cursor row-number col: .BYTE 0 ; cursor col-number ;----------------------------------------------------------------- initialize_cursor_ht: mov dx, #0x03D4 ; CRTC port-address mov ax, #0x020A ; cursor_start: line 2 out dx, ax ; write to CRTC register mov ax, #0x0C0B ; cursor_end: line 12 out dx, ax ; write to CRTC register ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- initialize_video_ram: ; reset display_mode for standard 80-column text mov ah, #0x00 ; set_display_mode mov al, #0x03 ; standard 80x25 text int 0x10 ; request BIOS service ; fill each vram page with that page's page-number mov ax, #0xB800 ; address video memory mov es, ax ; with ES register xor di, di ; initial vram offset cld ; do forward processing mov ah, #0x07 ; normal color-attribute mov al, #0x30 ; ascii page-number '0' mov dx, #8 ; number of vram pages .L0: mov cx, #2048 ; characters-per-page rep ; string repeat-prefix stosw ; store char and color inc al ; set next page-number dec dx ; decrement loop-count jnz .L0 ; initialize next page ret ;----------------------------------------------------------------- exec_arrow_keys_demo: ; mask the keyboard interrupt in al, #0x21 ; master-8259A mask or al, #0x02 ; set mask for IRQ1 out #0x21, al ; write the new mask await: ; wait for keyboard controller's input-buffer full in al, #0x64 ; kb_controller's status test al, #1 ; output buffer full? jz await ; no, continue waiting ; read the new keyboard scancode into register AL in al, #0x60 ; get keyboard scancode ; check for exit-condition cmp al, #KEY_ESCAPE ; -key? je finis ; yes, exit this loop ; otherwise process the new scancode call move_cursor ; perform cursor action jmp await ; then get next scancode finis: ; unmask keyboard interrupts in al, #0x21 ; master-8259A mask and al, #0xFD ; clear mask for IRQ1 out #0x21, al ; write the new mask ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- jump_table: .WORD do_home_key, do_arrow_up, do_page_up, ignore .WORD do_arrow_left, ignore, do_arrow_right, ignore .WORD do_end_key, do_arrow_down, do_page_down ;----------------------------------------------------------------- move_cursor: cmp al, #KEYPAD_MIN ; scancode below minimum? jb movxx ; yes, take no action cmp al, #KEYPAD_MAX ; scancode above maximum? ja movxx ; yes, take no action sub al, #KEYPAD_MIN ; subtract table minimum movzx eax, al ; then extend to 32-bits call word jump_table[eax*2] ; perform cursor movement call set_crt_cursor ; and adjust the cursor movxx: ret ; return to the caller ;---------------------------------------------------------------- ignore: ret ; no cursor movement ;---------------------------------------------------------------- do_home_key: mov byte row, #0 mov byte col, #0 mov byte page, #0 ret ;---------------------------------------------------------------- do_end_key: mov byte row, #24 mov byte col, #79 ret ;---------------------------------------------------------------- do_arrow_up: sub byte row, #1 jge upok mov byte row, #24 sub byte page, #1 and byte page, #0x07 upok: ret ;----------------------------------------------------------------- do_arrow_down: add byte row, #1 cmp byte row, #24 jle dnok mov byte row, #0 add byte page, #1 and byte page, #0x07 dnok: ret ;----------------------------------------------------------------- do_arrow_left: sub byte col, #1 jge lfok mov byte col, #79 sub byte row, #1 jge lfok mov byte row, #24 sub byte page, #1 and byte page, #0x07 lfok: ret ;----------------------------------------------------------------- do_arrow_right: add byte col, #1 cmp byte col, #79 jle rtok mov byte col, #0 add byte row, #1 cmp byte row, #24 jle rtok add byte page, #1 and byte page, #0x07 rtok: ret ;----------------------------------------------------------------- do_page_up: sub byte page, #1 and byte page, #0x07 ret ;----------------------------------------------------------------- do_page_down: add byte page, #1 and byte page, #0x07 ret ;----------------------------------------------------------------- set_crt_cursor: ; compute the cursor's page-offset in BX mov bl, page ; get vram page-number and bx, #0x0007 ; extended to 16-bits shl bx, #11 ; multiply by 2048 ; reprogram the CRTC start_address mov dx, #0x3D4 ; CRTC port-address mov al, #0x0D ; index for start_addr_lo mov ah, bl ; value for start_addr_lo out dx, ax ; write new start_addr_lo mov al, #0x0C ; index for start_addr_hi mov ah, bh ; value for start_addr_hi out dx, ax ; write new start_addr_hi ; compute the cursor's cell-offset in BX mov al, #80 ; setup cells-per-line mul byte row ; times cursor row-number add bx, ax ; add offset to BX add bl, col ; plus column's lobyte adc bh, #0 ; also column's hibyte ; reprogram the cursor-position and start_address mov dx, #0x3D4 ; CRTC port-address mov al, #0x0F ; index for cursor_lo mov ah, bl ; value for cursor_lo out dx, ax ; write new cursor_lo mov al, #0x0E ; index for cursor_hi mov ah, bh ; value for cursor_hi out dx, ax ; write new cursor_hi ret ;----------------------------------------------------------------- .ALIGN 16 ; alignment at paragraph .SPACE 512 ; reserved for stack use tos0: ; label fop top-of-stack ;----------------------------------------------------------------- END