Page 1 of 1

Hardware Cursor in Text Mode 80*25 with CRTC (Solved)

Posted: Mon Mar 19, 2007 3:09 am
by XCHG
I have written an Update Cursor procedure that allows the Row and the Column to be specified as parameters and then attempts to show the Hardware Cursor at the specified position. The problem is that the procedure works on Rows and Columns that already have a character written to them. If, for example, position(ROW, COLUMN) (0x0A, 0x0B) does not have a character printed at it, the Hardware Cursor is not shown. Below is the code if it helps spotting the problem:

Code: Select all

__UpdateHardwareCursor:
  ; void __UpdateHardwareCursor (DWORD Column, DWORD Row); StdCall;
  PUSH    EAX                          ; Push the accumulator onto the stack
  PUSH    EBX                          ; Push the base index onto the stack
  PUSH    EDX                          ; Push the data register onto the stack
  PUSH    EBP                          ; Push the base pointer onto the stack
  MOV     EBP , ESP                    ; Move the stack pointer to the base pointer
  MOV     EAX , DWORD PTR [EBP + 0x18] ; Accumulator now holds the [Row] parameter
  MOV     EBX , DWORD PTR [EBP + 0x14] ; Base Index now holds the [Column] parameter
  SHL     EAX , 0x00000004             ; Multiply the row by 80, Step 1
  LEA     EAX , [EAX + 0x04*EAX]       ; Multiply the row by 80, Step 2
  ADD     EBX , EAX                    ; Add the Column to the Row, Keep in the EBX
  MOV     EDX , 0x000003D4             ; CRTC Address Register
  MOV     EAX , 0x0000000F             ; Cursor Location Low Register
  OUT     DX , AL                      ; Tell the CRTC Address Register the Index
  MOV     EAX , EBX                    ; Get the calculated location in EAX
  INC     EDX                          ; EDX = CRTC Data Register (0x03D5)
  OUT     DX , AL                      ; Put the Cursor Location Low Address
  DEC     EDX                          ; EDX = CRTC Address Register (0x03D4)
  MOV     AL , 0x0000000E              ; Cursor Location High Register
  OUT     DX , AL                      ; Tell the CRTC Address Register the Index
  INC     EDX                          ; EDX = CRTC Data Register (0x03D5)
  MOV     EAX , EBX                    ; Get the Calculated Location again
  SHR     EAX , 0x00000008             ; Get the High Byte in AL
  OUT     DX , AL                      ; Tell the CRTC Data Register the Index
  POP     EBP                          ; Restore the base pointer
  POP     EDX                          ; Restore the data register
  POP     EBX                          ; Restore the base index
  POP     EAX                          ; Restore the accumulator
  RET     0x08                         ; Return to the calling procedure
                                       ; And sweep 4 parameters off the stack

Posted: Mon Mar 19, 2007 3:27 am
by Combuster
meh

in essence its just a pair of writes to the CRTC controller. The reason why you wont see a cursor where there's no text is because you apparently set the foreground to black, which happens to be taken as the cursor's color

which is a direct consequence of a zeromemory() call :roll:

Posted: Mon Mar 19, 2007 11:17 am
by salil_bhagurkar
Talking of the hardware cursor i had a hardware cursor in the early versions of my os. When GRUB loaded it from the menu it showed up nicely but when i used to boot my kernel through the GRUB commandline there used to be no cursor... What could be the reason?

Later on i made a virtual cursor with an 'unsigned int cursor' declaration and i only displayed it on getch()

Posted: Tue Mar 20, 2007 5:28 am
by XCHG
Combuster,

Thank you so much. The problem was exactly what you said. The foreground color.

Posted: Wed Mar 21, 2007 5:18 am
by XCHG
I coded this little procedure that works on Text Mode of 80*25. It puts a character at an absolute position on the screen. I used this procedure to put a blank character with the foreground of white on the screen, before I updated the Hardware video cursor. Hope it will help someone, someday.

Code: Select all

VIDEOSEGMENT            EQU             0x000B8000
__WriteCharPos:
  ; void __WriteCharPos (DWORD X, DWORD Y, DWORD Character); StdCall;
  PUSH    EAX                                    ; Push the accumulator onto the stack
  PUSH    EDX                                    ; Push the data register onto the stack
  PUSH    EBP                                    ; Push the base pointer onto the stack
  MOV     EBP , ESP                              ; Move the stack pointer to the base pointer
  MOV     EAX , DWORD PTR [EBP + 0x14]           ; *EAX = The [Y] parameter
  SHL     EAX , 0x00000005                       ; Multiply EAX by 160 (160 bytes per Row), Step 1
  LEA     EAX , [EAX + 0x04*EAX + VIDEOSEGMENT]  ; Multiply EAX by 160, Step 2, Add the video segment
  MOV     EDX , DWORD PTR [EBP + 0x10]           ; *EDX = [X] (Each Column must be multiplied by 2)
  LEA     EAX , [EAX + 0x02*EDX]                 ; Multiply Column by 2 and add it to the Row
  MOV     EDX , DWORD PTR [EBP + 0x18]           ; *EDX = The [Character] parameter
  MOV     DH , 0x0F                              ; Set the foreground color to White
  MOV     WORD PTR [EAX] , DX                    ; Put the character and color
  POP     EBP                                    ; Restore the base pointer
  POP     EDX                                    ; Restore the data register
  POP     EAX                                    ; Restore the accumulator
  RET     0x0C                                   ; Return to the calling procedure
                                                 ; And sweep 3 parameter off the stack