1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
|
TITLE Hercules graphics module
; Michael Gordon - 8-Dec-86
;
; Certain routines were taken from the Hercules BIOS of Dave Tutelman - 8/86
; Others came from pcgraph.asm included in GNUPLOT by Colin Kelley
;
; modified slightly by Colin Kelley - 22-Dec-86
; added header.mac, parameterized declarations
; added dgroup: in HVmodem to reach HCh_Parms and HGr_Parms - 30-Jan-87
; modified by Russell Lang 3 Jun 1988
; added H_init
include header.mac
if1
include lineproc.mac
endif
GPg1_Base equ 0B800h ; Graphics page 1 base address
_text segment
public _H_line, _H_color, _H_mask, _HVmode, _H_puts
public _H_init
HCfg_Switch equ 03BFH ; Configuration Switch - software switch
; to select graphics card memory map
beginproc _H_init
mov al, 03H ; allow graphics in b8000:bffff
mov dx, HCfg_Switch
out dx, al
ret
_H_init endp
hpixel proc near
ror word ptr bmask,1
jc cont
ret
cont:
push ax
push bx
push cx
push dx
push si
mov cx,ax ; x
mov dx,bx ; y
;
; [couldn't this be done faster with a lookup table? -cdk]
;
; first compute the address of byte to be modified
; = 90*[row/4] + [col/8] + 2^D*[row/4] + 2^F*page
mov bh,cl ; col (low order) in BH
mov bl,dl ; row (low order) in BL
and bx,0703H ; mask the col & row remainders
IFDEF iAPX286
shr cx,3 ; col / 8
shr dx,2 ; row / 4
mov al,90
mul dx ; AX = 90*[ row/4 ]
add ax,cx ; ... + col/8
shl bl,5 ; align row remainder
ELSE ; same as above, obscure but fast for 8086
shr cx,1 ; divide col by 8
shr cx,1
shr cx,1
shr dx,1 ; divide row by 4
shr dx,1
shl dx,1 ; begin fast multiply by 90 (1011010 B)
mov ax,dx
shl dx,1
shl dx,1
add ax,dx
shl dx,1
add ax,dx
shl dx,1
shl dx,1
add ax,dx ; end fast multiply by 90
add ax,cx ; add on the col/8
shl bl,1 ; align row remainder
shl bl,1
shl bl,1
shl bl,1
shl bl,1
ENDIF
add ah,bl ; use aligned row remainder
end_adr_calc: ; address of byte is now in AX
mov dx,GPg1_Base ; base of pixel display to DX
mov es,dx ; ...and thence to segment reg
mov si,ax ; address of byte w/ pixel to index reg
mov cl,bh ; bit addr in byte
mov al,80H ; '1000 0000' in AL
shr al,cl ; shift mask to line up with bit to read/write
set_pix: ; set the pixel
or es:[si],al ; or the mask with the right byte
pop si
pop dx
pop cx
pop bx
pop ax
ret
hpixel endp
lineproc _H_line, hpixel
;
; clear - clear page 1 of the screen buffer to zero (effectively, blank
; the screen)
;
clear proc near
push es
push ax
push cx
push di
mov ax, GPg1_Base
mov es, ax
xor di, di
mov cx, 4000h
xor ax, ax
cld
rep stosw ; zero out screen page
pop di
pop cx
pop ax
pop es
ret
clear endp
beginproc _H_color
push bp
mov bp,sp
mov al,[bp+X] ; color
mov byte ptr color,al
pop bp
ret
_H_color endp
beginproc _H_mask
push bp
mov bp,sp
mov ax,[bp+X] ; mask
mov word ptr bmask,ax
pop bp
ret
_H_mask endp
HCtrl_Port equ 03B8H ; Hercules 6845 control port IO addr
HIndx_Port equ 03B4H ; Hercules 6845 index port IO addr
HScrn_Enable equ 008h ; Control port bit to enable video
HCh_Mode equ 020h ; Character output mode
HGr_Mode equ 082h ; Graphics output mode page 1
parm_count equ 12
beginproc _HVmode
push bp
mov bp, sp
push si
mov ax, [bp+X]
or ah, al
mov al, HCh_Mode ; Assume character mode is wanted
mov si, offset dgroup:HCh_Parms
cmp ah, 0 ; nonzero means switch to graphics
jz vmode_ok
call near ptr clear ; clear the graphics page
mov al, HGr_Mode
mov si, offset dgroup:HGr_Parms
vmode_ok:
mov dx, HCtrl_Port
out dx, al ; Set Hercules board to proper mode
call near ptr setParms ; Set the 6845 parameters
or al, HScrn_Enable ; Enable the video output
out dx, al
pop si
pop bp
ret
_HVmode endp
setParms proc near ; Send 6845 parms to Hercules board
push ax
push dx
push si
mov dx, HIndx_Port ; Index port addr -> DX
mov ah, 0 ; 0 -> parameter counter
sp_loop:
mov al, ah
out dx, al ; output to 6845 addr register
inc dx ; next output to data register
mov al, [si] ; next control byte -> al
inc si
out dx, al ; output control byte
dec dx ; 6845 index addr -> dx
inc ah ; bump addr
cmp ah, parm_count
jnz sp_loop
pop si
pop dx
pop ax
ret
setParms endp
; H_puts - print text in graphics mode
;
; cx = row
; bx = column
; si = address of string (null terminated) to print
beginproc _H_puts
push bp
mov bp, sp
push si
push ds
mov si, [bp+X] ; string offset
ifdef LARGE_DATA
mov ds, [bp+X+2] ; string segment
mov cx, [bp+X+4] ; row
mov bx, [bp+X+6] ; col
else
mov cx, [bp+X+2] ; row
mov bx, [bp+X+4] ; col
endif
ploop: lodsb ; get next char
or al, al ; end of display?
je pdone
call near ptr display
inc bx ; bump to next column
jmp ploop
pdone: pop ds
pop si
pop bp
ret
_H_puts endp
;
; display - output an 8x8 character from the IBM ROM to the Herc board
;
; AX = char, BX = column (0-89), CX = row(0-42) ** all preserved **
;
CON8 db 8
CON180 db 180
IBMROM equ 0F000h
CHARTAB equ 0FA6Eh
display proc near
push ds ; save the lot
push es
push ax
push bx
push cx
push dx
push si
push di
; setup ds -> IBM ROM, and si -> index into IBM ROM character table located
; at 0fa6eh in the ROM
and ax, 07fh
mul cs:CON8 ; mult by 8 bytes of table per char
mov si, ax
mov ax, IBMROM
mov ds, ax
assume ds:nothing
add si, CHARTAB ; add offset of character table
; compute index into Hercules screen memory for scan line 0. The remaining
; seven scan lines are all at fixed offsets from the first.
;
; Since graphics mode treats the screen as sets of 16x4 "characters",
; we need to map an 8x8 real character onto the front or back of
; a pair of graphics "characters". The first four scan lines of our
; 8x8 character will map to the top graphics "character", and the second
; four scan lines map to the graphics character on the "line" (4 scan
; lines high) below it.
;
; For some exotic hardware reason (probably speed), all scan line 0
; bits (i.e. every fourth scan line) are stored in memory locations
; 0-2000h in the screen buffer. All scan line 1 bits are stored
; 2000h-4000h. Within these banks, they are stored by rows. The first
; scan line on the screen (scan line 0 of graphics character row 0)
; is the first 45 words of memory in the screen buffer. The next 45
; words are the first scan line graphics row 1, and since graphics
; "characters" are 4 bits high, this second scan line is physically
; the fifth scan line displayed on the screen.
;
; SO, to display an 8x8 character, the 1st and 5th rows of dots are
; both scan line 0 of the graphics "character", the 2nd and 6th are
; scan line 1, and so on.
;
; The column (0-89) tells which byte in a scan line we need to load.
; Since it takes two rows of graphics characters to hold one row of
; our characters, column+90 is a index to scan line 4 rows of pixels
; higher (n+4). Thus 180 bytes of screen memory in any bank (0h, 2000h,
; 4000h, 6000h) represent a row of 8x8 characters.
;
; The starting location in screen memory for the first scan line of
; a character to be displayed will be: (row*180)+column
; The 5th scan line will be at: (row*180)+column+90
;
; The second and 6th scan lines will be at the above offsets plus
; the bank offset of 2000h. The third and 7th, add 4000h and finally
; the 4th and 8th, add 6000h.
;
mov ax, GPg1_Base
mov es, ax ; es = hercules page 0
mov ax, cx ; get row
mul cs:CON180 ; mult by 180(10)
mov di, ax ; di = index reg
cld ; insure right direction
;output 8 segments of character to video ram
lodsb ; line 0
mov es:[di+bx], al
lodsb
mov es:[di+bx+2000h], al ; line 1
lodsb
mov es:[di+bx+4000h], al ; line 2
lodsb
mov es:[di+bx+6000h], al ; line 3
lodsb
mov es:[di+bx+90], al ; line 4
lodsb
mov es:[di+bx+2000h+90], al ; line 5
lodsb
mov es:[di+bx+4000h+90], al ; line 6
lodsb
mov es:[di+bx+6000h+90], al ; line 7
pop di
pop si
pop dx
pop cx
pop bx
pop ax
pop es
pop ds
ret
display endp
_text ends
_data segment
bmask dw -1
color db 1
_data ends
const segment
HCh_Parms db 61H, 50H, 52H, 0FH, 19H, 06H, 19H, 19H, 02H, 0DH, 0BH, 0CH
HGr_Parms db 35H, 2DH, 2EH, 07H, 5BH, 02H, 57H, 57H, 02H, 03H, 00H, 00H
const ends
end
|