The /tests/pc folder is now /tests/pcx86 (to be consistent with the associated emulator)
This commit is contained in:
parent
51b50382fb
commit
663343a1ad
68 changed files with 24 additions and 16 deletions
9
tests/pcx86/.gitignore
vendored
Normal file
9
tests/pcx86/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
*.com
|
||||
*.COM
|
||||
*.lst
|
||||
*.LST
|
||||
*.obj
|
||||
*.OBJ
|
||||
*.exe
|
||||
*.EXE
|
||||
80186/
|
||||
12
tests/pcx86/80386/README.md
Normal file
12
tests/pcx86/80386/README.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
layout: page
|
||||
title: 80386 Tests
|
||||
permalink: /tests/pcx86/80386/
|
||||
redirect_from:
|
||||
- /tests/pc/80386/
|
||||
---
|
||||
|
||||
Overview
|
||||
---
|
||||
|
||||
See [test386.asm](test386.asm).
|
||||
10
tests/pcx86/80386/makefile
Normal file
10
tests/pcx86/80386/makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
all: test386.json test386.img
|
||||
|
||||
test386.com: test386.asm ../inc/dos.inc ../inc/misc.inc ../inc/x86.inc
|
||||
nasm -i../inc/ -f bin test386.asm -l test386.lst -o test386.com
|
||||
|
||||
test386.json: test386.com
|
||||
node ../../../modules/filedump/bin/filedump --file=test386.com --output=test386.json --overwrite
|
||||
|
||||
test386.img: test386.com
|
||||
node ../../../modules/diskdump/bin/diskdump --path=test386.com --output=test386.img --format=img --overwrite
|
||||
1001
tests/pcx86/80386/test386.asm
Normal file
1001
tests/pcx86/80386/test386.asm
Normal file
File diff suppressed because it is too large
Load diff
1022
tests/pcx86/80386/test386.json
Normal file
1022
tests/pcx86/80386/test386.json
Normal file
File diff suppressed because it is too large
Load diff
28764
tests/pcx86/80386/test386.txt
Normal file
28764
tests/pcx86/80386/test386.txt
Normal file
File diff suppressed because it is too large
Load diff
14
tests/pcx86/README.md
Normal file
14
tests/pcx86/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
layout: page
|
||||
title: PC Test Resources
|
||||
permalink: /tests/pcx86/
|
||||
redirect_from:
|
||||
- /tests/pc/
|
||||
---
|
||||
|
||||
PCx86 Test Resources
|
||||
--------------------
|
||||
|
||||
* [80386 Tests](80386/)
|
||||
* [Trace Utility](trace/)
|
||||
* [VGA "Black Book" Tests](vga/)
|
||||
645
tests/pcx86/cpu/cpuid.asm
Normal file
645
tests/pcx86/cpu/cpuid.asm
Normal file
|
|
@ -0,0 +1,645 @@
|
|||
; Posted in comp.sys.ibm.pc by Michael A. Shiels 8/16/89
|
||||
; From https://groups.google.com/forum/#!searchin/comp.sys.ibm.pc/single-step$20interrupt/comp.sys.ibm.pc/irWPIdzmCHQ/SyqEtq9mqCEJ
|
||||
|
||||
title CPUID - Determine CPU & NDP Type
|
||||
page 58,122
|
||||
name CPUID
|
||||
|
||||
;
|
||||
; CPUID uniquely identifies each NEC & Intel CPU & NDP.
|
||||
;
|
||||
; Notes on program structure:
|
||||
;
|
||||
; This program uses four segments, two classes, and one group.
|
||||
; It demonstrates a useful technique for programmers who generate
|
||||
; .COM programs. In particular, it shows how to use segment
|
||||
; classes to re-order segments, and how to eliminate the linker's
|
||||
; warning message about the absence of a stack segment.
|
||||
;
|
||||
; The correspondence between segments and classes is as follows:
|
||||
;
|
||||
; Segment Class
|
||||
; ------- -----
|
||||
; STACK prog
|
||||
; DATA data
|
||||
; MDATA data
|
||||
; CODE prog
|
||||
;
|
||||
; The segments apprear in the above order in the program source
|
||||
; to avoid forward references in the CODE segment to labels in
|
||||
; the DATA/MDATA segments. However, because the STACK segment
|
||||
; appears first in the file, it and all segments in the same
|
||||
; class are made contiguous by the linker. Thus they precede
|
||||
; the DATA/MDATA segments in the resulting .COM file because
|
||||
; the latter are in a different class. In this manner, although
|
||||
; DATA and MDATA precede CODE in the source file, their order
|
||||
; is swapped in the .COM file. That way there is no need for
|
||||
; an initial skip over the data areas to get to the CODE
|
||||
; segment. As a side benefit, declaring a STACK segment (as
|
||||
; the first segment in the source) also eliminates the linker's
|
||||
; warning about that segment missing. Finally, all segments
|
||||
; are declared to be in the same group so the linker can properly
|
||||
; resolve offsets.
|
||||
;
|
||||
; Note that if you re-assemble the code for any reason, it is
|
||||
; important to use an assembler later than the IBM version 1.0.
|
||||
; That version has a number of bugs including an annoying habit
|
||||
; of alphabetizing segment names in the .OBJ file. If you use
|
||||
; IBM MASM 2.0, be sure to specify /S to order the segments
|
||||
; properly.
|
||||
;
|
||||
; If the program reports results at variance with your knowledge
|
||||
; of the system, please contact the author.
|
||||
;
|
||||
; Environments tested in:
|
||||
;
|
||||
; CPU Speed
|
||||
; System in MHz CPU NDP
|
||||
; ------ --------- --- ---
|
||||
; IBM PC AT 6 Intel 80286 Intel 80287
|
||||
; IBM PC AT 9 Intel 80286 Intel 80287
|
||||
; IBM PC AT 6 Intel 80286 none
|
||||
; IBM PC AT 8.5 Intel 80286 none
|
||||
; IBM PC 4.77 Intel 8088 Intel 8087-3
|
||||
; IBM PC 4.77 Intel 8088* Intel 8087-3
|
||||
; IBM PC XT 4.77 Intel 8088 none
|
||||
; IBM PC XT 4.77 Intel 8088 Intel 8087-3
|
||||
; IBM PC Portable 4.77 NEC V20 none
|
||||
; COMPAQ 4.77 Intel 8088 none
|
||||
; COMPAQ 4.77 NEC V20 none
|
||||
; AT&T PC 6300 8 Intel 8086 Intel 8087-2
|
||||
; AT&T PC 6300 8 NEC V30 Intel 8087-2
|
||||
; Tandy 2000 8 Intel 80186 none
|
||||
;
|
||||
; * = faulty CPU
|
||||
;
|
||||
; Program structure:
|
||||
;
|
||||
; Group PGROUP:
|
||||
; Stack segment STACK, byte-aligned, stack, class 'prog'
|
||||
; Program segment CODE, byte-aligned, public, class 'prog'
|
||||
; Data segment DATA, byte-aligned, public, class 'data'
|
||||
; Data segment MDATA, byte-aligned, public, class 'data'
|
||||
;
|
||||
; Assembly requirements:
|
||||
;
|
||||
; Use MASM 1.25 or later.
|
||||
; With IBM's MASM 2.0 only, use /S to avoid alphabetizing the segment names.
|
||||
; Use /r option to generate real NDP code.
|
||||
;
|
||||
; MASM CPUID/r; to convert .ASM to .OBJ
|
||||
; LINK CPUID; to convert .OBJ to .EXE
|
||||
; EXE2BIN CPUID CPUID.COM to convert .EXE to .COM
|
||||
; ERASE CPUID.EXE to avoid executing .EXE
|
||||
;
|
||||
; Note that the linker doesn't warn about a missing stack segment.
|
||||
;
|
||||
; Author:
|
||||
;
|
||||
; Original code by:
|
||||
;
|
||||
; Bob Smith May 1985
|
||||
; Qualitas, Inc.
|
||||
; 8314 Thoreau Dr.
|
||||
; Bethesda, MD 20817
|
||||
;
|
||||
; Arthur Zachai suggested the technique to distinguish within the
|
||||
; 808x and 8018x families by exploiting the difference in the
|
||||
; length of their pre-fetch instruction queues.
|
||||
;
|
||||
; Published in PC Tech Journal - April 1986 - Vol 4 No 4
|
||||
;
|
||||
subttl Structures, Records, Equates, & Macros
|
||||
page
|
||||
|
||||
ARG_STR struct
|
||||
ARG_BP dw ? ; caller's BP
|
||||
ARG_OFF dw ? ; caller's offset
|
||||
ARG_SEG dw ? ; segment
|
||||
ARG_FLG dw ? ; flags
|
||||
ARG_STR ends
|
||||
|
||||
; Record to define bits in the CPU's & NDP's flags' registers
|
||||
|
||||
CPUFLAGS record RO:1,NT:1,IOPL:2,OF:1,_DF:1,_IF:1,TF:1,SF:1,ZF:1,R1:1,AF:1,R2:1,PF:1,R3:1,CF:1
|
||||
|
||||
NDPFLAGS record R4:3,IC:1,RC:2,PC:2,IEM:1,R5:1,PM:1,UM:1,OM:1,ZM:1,DM:1,IM:1
|
||||
|
||||
; FLG_PIQL Pre-fetch instruction queue length, 0 => 4-byte, 1 => 6-byte
|
||||
; FLG_08 Intel 808x
|
||||
; FLG_NEC NEC V20 or V30
|
||||
; FLG_18 Intel 8018x
|
||||
; FLG_28 Intel 8028x
|
||||
; FLG_87 Intel 8087
|
||||
; FLG_287 Intel 80287
|
||||
;
|
||||
; FLG_CERR Faulty CPU
|
||||
; FLG_NERR Faulty NDP switch setting
|
||||
|
||||
FLG record RSVD:9,FLG_NERR:1,FLG_CERR:1,FLG_NDP:2,FLG_CPU:3
|
||||
|
||||
; CPU-related flags
|
||||
|
||||
FLG_PIQL equ 001b shl FLG_CPU
|
||||
FLG_08 equ 000b shl FLG_CPU
|
||||
FLG_NEC equ 010b shl FLG_CPU
|
||||
FLG_18 equ 100b shl FLG_CPU
|
||||
FLG_28 equ 110b shl FLG_CPU
|
||||
|
||||
FLG_8088 equ FLG_08
|
||||
FLG_8086 equ FLG_08 or FLG_PIQL
|
||||
FLG_V20 equ FLG_NEC
|
||||
FLG_v30 equ FLG_NEC or FLG_PIQL
|
||||
FLG_80188 equ FLG_18
|
||||
FLG_80186 equ FLG_18 or FLG_PIQL
|
||||
FLG_80286 equ FLG_28 or FLG_PIQL
|
||||
|
||||
; NDP-related flags
|
||||
|
||||
; 00b shl FLG_NDP Not Present
|
||||
FLG_87 equ 01b shl FLG_NDP
|
||||
FLG_287 equ 10b shl FLG_NDP
|
||||
BEL equ 07h
|
||||
LF equ 0ah
|
||||
CR equ 0dh
|
||||
EOS equ '$'
|
||||
|
||||
POPFF macro
|
||||
local L1,L2
|
||||
jmp short L2 ; skip over IRET
|
||||
L1:
|
||||
iret ; pop the CP & IP pushed below along
|
||||
; with the flags, our original purpose
|
||||
L2:
|
||||
push cs ; prepare for IRET by pushing CS
|
||||
call L1 ; push IP, jump to IRET
|
||||
endm ; POPFF macro
|
||||
|
||||
TAB macro TYP
|
||||
push bx ; save for a moment
|
||||
and bx,mask FLG_&TYP ; isolate flags
|
||||
mov cl,FLG_&TYP ; shift amount
|
||||
shr bx,cl ; shift to low-order
|
||||
shl bx,1 ; times two to index table of words
|
||||
mov dx,TYP&MSG_TAB[bx] ; ds:dx => descriptive message
|
||||
pop bx ; restore
|
||||
mov ah,09h ; function code to display string
|
||||
int 21h ; request dos service
|
||||
endm ; TAB macro
|
||||
|
||||
page
|
||||
|
||||
INT_VEC segment at 0 ; start INT_VEC segment
|
||||
dd ? ; pointer to INT 00h
|
||||
INT01_OFF dw ? ; pointer to INT 01h
|
||||
INT01_SEG dw ?
|
||||
INT_VEC ends ; end INT_VEC segment
|
||||
|
||||
PGROUP group STACK,CODE,DATA,MDATA
|
||||
|
||||
; The following segment both positions class 'prog' segments lower in
|
||||
; memory than others so the first byte of the resulting .COM file is
|
||||
; in the CODE segment, as well as satisfies the LINKer's need to have
|
||||
; a stack segment.
|
||||
|
||||
STACK segment byte stack 'prog' ; start STACK segment
|
||||
STACK ends ; end STACK segment
|
||||
|
||||
I11_REC record I11_PRN:2,I11_RSV1:2,I11_COM:3,I11_RSV2:1,I11_DISK:2,I11_VID:2,I11_RSV3:2,I11_NDP:1,I11_IPL:1
|
||||
|
||||
DATA segment byte public 'data' ; start DATA segment
|
||||
|
||||
assume ds:PGROUP
|
||||
|
||||
OLDINT01_VEC label dword ; save area for original INT 01h handler
|
||||
OLDINT01_OFF dw ?
|
||||
OLDINT01_SEG dw ?
|
||||
|
||||
NDP_CW label word ; save area for NDP control word
|
||||
db ?
|
||||
NDP_CW_HI db 0 ; high byte of control word
|
||||
NDP_ENV dw 7 dup(?) ; save area for NDP environment
|
||||
|
||||
DATA ends
|
||||
subttl Message Data Area
|
||||
page
|
||||
|
||||
MDATA segment byte public 'data' ; start MDATA segment
|
||||
|
||||
assume ds:PGROUP
|
||||
|
||||
MSG_START db 'CPUID -- Version 1.0'
|
||||
db CR,LF,CR,LF,EOS
|
||||
MSG_8088 db 'CPU is an Intel 8088.'
|
||||
db CR,LF,EOS
|
||||
MSG_8086 db 'CPU is an Intel 8086.'
|
||||
db CR,LF,EOS
|
||||
MSG_V20 db 'CPU is an NEC V20.'
|
||||
db CR,LF,EOS
|
||||
MSG_V30 db 'CPU is an NEC V30.'
|
||||
db CR,LF,EOS
|
||||
MSG_80188 db 'CPU is an Intel 80188.'
|
||||
db CR,LF,EOS
|
||||
MSG_80186 db 'CPU is an Intel 80186.'
|
||||
db CR,LF,EOS
|
||||
MSG_UNK db 'CPU is a maverick -- 80288??.'
|
||||
db CR,LF,EOS
|
||||
MSG_80286 db 'CPU is an Intel 80286.'
|
||||
db CR,LF,EOS
|
||||
|
||||
CPUMSG_TAB dw PGROUP:MSG_8088 ; 000 = Intel 8088
|
||||
dw PGROUP:MSG_8086 ; 001 = Intel 8086
|
||||
dw PGROUP:MSG_V20 ; 010 = NEC V20
|
||||
dw PGROUP:MSG_V30 ; 011 = NEC V30
|
||||
dw PGROUP:MSG_80188 ; 100 = Intel 80188
|
||||
dw PGROUP:MSG_80186 ; 101 = Intel 80186
|
||||
dw PGROUP:MSG_UNK ; 110 = ?
|
||||
dw PGROUP:MSG_80286 ; 111 = Intel 80286
|
||||
|
||||
NDPMSG_TAB dw PGROUP:MSG_NDPX ; 00 = No NDP
|
||||
dw PGROUP:MSG_8087 ; 01 = Intel 8087
|
||||
dw PGROUP:MSG_80287 ; 10 = Intel 80287
|
||||
|
||||
MSG_NDPX db 'NDP is not present.'
|
||||
db CR,LF,EOS
|
||||
MSG_8087 db 'NDP is an Intel 8087.'
|
||||
db CR,LF,EOS
|
||||
MSG_80287 db 'NDP is an Intel 80287.'
|
||||
db CR,LF,EOS
|
||||
|
||||
CERRMSG_TAB dw PGROUP:MSG_CPUOK ; 0 = CPU healthy
|
||||
dw PGROUP:MSG_CPUBAD ; 1 = CPU faulty
|
||||
|
||||
MSG_CPUOK db 'CPU appears to be healthy.'
|
||||
db CR,LF,EOS
|
||||
MSG_CPUBAD db BEL,'*** CPU incorrectly allows interrupts '
|
||||
db 'after a change to SS ***',CR,LF
|
||||
db 'It should be replaced with a more recent '
|
||||
db 'version as it could crash the',CR,LF
|
||||
db 'system at seemingly random times.',CR,LF,EOS
|
||||
|
||||
NERRMSG_TAB dw PGROUP:MSG_NDPSWOK ; 0 = NDP switch set correctly
|
||||
dw PGROUP:MSG_NDPSWERR ; 1 = NDP switch set incorrectly
|
||||
|
||||
MSG_NDPSWOK db EOS ; no message
|
||||
MSG_NDPSWERR db '*** Although there is an NDP installed '
|
||||
db 'on this sytem, the corresponding',CR,LF
|
||||
db 'system board switch is not properly set. '
|
||||
db 'To correct this, flip switch 2 of',CR,LF
|
||||
db 'switch block 1 on the system board.',CR,LF,EOS
|
||||
|
||||
MDATA ends ; end MDATA segment
|
||||
|
||||
subttl Main Routine
|
||||
page
|
||||
|
||||
CODE segment byte public 'prog' ; start CODE segment
|
||||
|
||||
assume cs:PGROUP,ds:PGROUP,es:PGROUP
|
||||
|
||||
org 100h ; skip over PSP
|
||||
|
||||
INITIAL proc near
|
||||
mov dx,offset ds:MSG_START ; starting message
|
||||
mov ah,09h ; function code to display string
|
||||
int 21h ; request DOS service
|
||||
|
||||
call CPU_ID ; check the CPU's identity
|
||||
|
||||
TAB CPU ; display CPU results
|
||||
TAB NDP ; display NDP results
|
||||
TAB CERR ; display CPU ERR results
|
||||
TAB NERR ; display NDP ERR results
|
||||
|
||||
ret ; return to DOS
|
||||
INITIAL endp ; end INITIAL procedure
|
||||
|
||||
subttl CPU_ID Procedure
|
||||
page
|
||||
|
||||
CPU_ID proc near ; start CPU_ID procedure
|
||||
|
||||
assume cs:PGROUP,ds:PGROUP,es:PGROUP
|
||||
|
||||
; This procedure determines the type of CPU and NDP (if any) in use.
|
||||
;
|
||||
; The possibilities include:
|
||||
;
|
||||
; Intel 8086
|
||||
; Intel 8088
|
||||
; NEC V20
|
||||
; NEC V30
|
||||
; Intel 80186
|
||||
; Intel 80188
|
||||
; Intel 80286
|
||||
; Intel 8087
|
||||
; Intel 80287
|
||||
;
|
||||
; Also checked is whether or not the CPU allows interrupts after
|
||||
; changing the SS register segment. If the CPU does, it is faulty
|
||||
; and should be replaced.
|
||||
;
|
||||
; Further, if an NDP is installed, non-AT machines should have a
|
||||
; system board switch set. Such a discrepancy is reported.
|
||||
;
|
||||
; On exit, BX contains flag settings (as defined in FLG record) which
|
||||
; the caller can check. For example, to test for an Intel 80286, use
|
||||
;
|
||||
; and bx,mask FLAG_CPU
|
||||
; cmp bx,FLG_80286
|
||||
; je ITSA286
|
||||
|
||||
irp XX,<ax,cx,di,ds,es> ; save registers
|
||||
push XX
|
||||
endm
|
||||
|
||||
; test for 80286 -- this CPU executes PUSH SP by first storing SP on
|
||||
; stack, then decrementing it. earlier CPU's decrement, THEN store.
|
||||
|
||||
mov bx,FLG_28 ; assume it's a 286
|
||||
push sp ; only 286 pushes pre-push SP
|
||||
pop ax ; get it back
|
||||
cmp ax,sp ; check for same
|
||||
je CHECK_PIQL ; they are, so it's a 286
|
||||
|
||||
; test for 80186/80188 -- 18xx and 286 CPU's mask shift/rotate
|
||||
; operations mod 32; earlier CPUs use all 8 bits of CL.
|
||||
|
||||
mov bx,FLG_18 ; assume it's an 8018x
|
||||
mov cl,32+1 ; 18x masks shift counts mod 32
|
||||
; note we can't use just 32 in CL
|
||||
mov al,0ffh ; start with all bits set
|
||||
|
||||
shl al,cl ; shift one position if 18x
|
||||
jnz CHECK_PIQL ; some bits still on,
|
||||
; so its a 18x, check PIQL
|
||||
; test for V20
|
||||
|
||||
mov bx,FLG_NEC ; assume it's an NEC V-series CPU
|
||||
call CHECK_NEC ; see if it's an NEC chip
|
||||
jcxz CHECK_PIQL ; good guess, check PIQL
|
||||
|
||||
mov bx,FLG_08 ; it's an 808x
|
||||
|
||||
subttl Check Length of Pre-Fetch Instruction Queue
|
||||
page
|
||||
|
||||
; Check the length of the pre-fetch instruction queue (PIQ).
|
||||
;
|
||||
; xxxx6 CPUs have a PIQ length of 6 bytes,
|
||||
; xxxx8 CPUs have a PIQ length of 4 bytes
|
||||
;
|
||||
; Self-modifying code is used to distinguish the two PIQ lengths.
|
||||
|
||||
CHECK_PIQL:
|
||||
call PIQL_SUB ; handle via subroutine
|
||||
jcxz CHECK_ERR ; if CX is 0, INC was not executed,
|
||||
; hence PIQ length is 4
|
||||
or bx,FLG_PIQL ; PIQ length is 6
|
||||
|
||||
subttl Check for Allowing Interrupts After POP SS
|
||||
page
|
||||
|
||||
; Test for faulty chip (allows interrupts after change to SS register)
|
||||
|
||||
CHECK_ERR:
|
||||
xor ax,ax ; prepare to address
|
||||
; interrupt vector segment
|
||||
mov ds,ax ; DS points to segment 0
|
||||
|
||||
assume ds:INT_VEC ; tell the assembler
|
||||
|
||||
cli ; nobody move while we swap
|
||||
|
||||
mov ax,offset cs:INT01 ; point to our own handler
|
||||
xchg ax,INT01_OFF ; get and swap offset
|
||||
mov OLDINT01_OFF,ax ; save to restore later
|
||||
|
||||
mov ax,cs ; our handler's segment
|
||||
xchg ax,INT01_SEG ; get and swap segment
|
||||
mov OLDINT01_SEG,ax ; save to restore later
|
||||
|
||||
; note we continue with interrupts disabled to avoid
|
||||
; an external interrupt occuring during this test
|
||||
|
||||
mov cx,1 ; initialize a register
|
||||
push ss ; save ss to store back into itself
|
||||
pushf ; move flags
|
||||
pop ax ; ... into ax
|
||||
or ax,mask TF ; set trap flag
|
||||
push ax ; place onto stack
|
||||
POPFF ; ... and then into effect
|
||||
; some CPUs affect the trap flag
|
||||
; immediately, some
|
||||
; wait one instruction
|
||||
nop ; allow interrupt to take effect
|
||||
|
||||
POST_NOP:
|
||||
pop ss ; change the stack segment register
|
||||
; (to itself)
|
||||
dec cx ; normal cpu's execute this instruction
|
||||
; before recognizing the single-step
|
||||
; interrupt
|
||||
hlt ; we never get here
|
||||
|
||||
INT01:
|
||||
|
||||
; Note: IF=TF=0
|
||||
; If we're stopped at or before POST_NOP, continue on
|
||||
|
||||
push bp ; prepare to address the stack
|
||||
mov bp,sp ; hello, Mr. stack
|
||||
|
||||
cmp [bp].ARG_STR.ARG_OFF,offset cs:POST_NOP ; check offset
|
||||
pop bp ; restore
|
||||
ja INTO1_DONE ; we're done
|
||||
|
||||
iret ; return to caller
|
||||
|
||||
INTO1_DONE:
|
||||
|
||||
; restore old INT 01h handler
|
||||
|
||||
les ax,OLDINT01_VEC ; ES:AX ==> old INT 01h handler
|
||||
assume es:nothing ; tell the assembler
|
||||
mov INT01_OFF,ax ; restore offset
|
||||
mov INT01_SEG,es ; ... and segment
|
||||
sti ; allow interrupts again (IF=1)
|
||||
|
||||
add sp,3*2 ; strip IP, CS, and flags from stack
|
||||
|
||||
push cs ; setup DS for code below
|
||||
pop ds
|
||||
assume ds:PGROUP ; tell the assembler
|
||||
|
||||
jcxz CHECK_NDP ; if cx is 0, the dec cx was executed,
|
||||
; and the cpu is ok
|
||||
or bx,mask FLG_CERR ; it's a faulty chip
|
||||
|
||||
subttl Check For Numeric Data Processor
|
||||
page
|
||||
|
||||
; Test for a Numeric Data Processor -- Intel 8087 or 80287. The
|
||||
; technique used is passive -- it leaves the NDP in the same state in
|
||||
; which it is found.
|
||||
|
||||
CHECK_NDP:
|
||||
cli ; protect FNSTENV
|
||||
fnstenv NDP_ENV ; if NDP present, save
|
||||
; current environment,
|
||||
; otherwise, this instruction
|
||||
; is ignored
|
||||
mov cx,50/7 ; cycle this many times
|
||||
loop $ ; wait for result to be stored
|
||||
sti ; allow interrupts
|
||||
fninit ; initialize processor to known state
|
||||
jmp short $+2 ; wait for initialization
|
||||
|
||||
fnstcw NDP_CW ; save control word
|
||||
jmp short $+2 ; wait for result to be stored
|
||||
jmp short $+2
|
||||
cmp NDP_CW_HI,03h ; check for NDP initial control word
|
||||
jne CPUID_EXIT ; no NDP installed
|
||||
int 11h ; get equipment flags into ax
|
||||
test ax,mask I11_NDP ; check NDP-installed bit
|
||||
jnz CHECK_NDP1 ; it's correctly set
|
||||
or bx,mask FLG_NERR ; mark as in error
|
||||
|
||||
CHECK_NDP1:
|
||||
and NDP_CW,not mask IEM ; enable interrupts
|
||||
; (IEM=0, 8087 only)
|
||||
fldcw NDP_CW ; reload control word
|
||||
fdisi ; disable interrupts (IEM=1) on 8087,
|
||||
; ignored by 80287
|
||||
fstcw NDP_CW ; save control word
|
||||
fldenv NDP_ENV ; restore original NDP environment
|
||||
; no need to wait
|
||||
; for environment to be loaded
|
||||
test NDP_CW,mask IEM ; check interrupt enable mask
|
||||
; (8087 only)
|
||||
jnz CPUID_8087 ; it changed, hence NDP is an 8087
|
||||
or bx,FLG_287 ; NDP is an 80287
|
||||
jmp short CPUID_EXIT ; exit with falgs in BX
|
||||
|
||||
CPUID_8087:
|
||||
or bx,FLG_87 ; NDP is an 8087
|
||||
|
||||
CPUID_EXIT:
|
||||
irp XX,<es,ds,di,cx,ax> ; restore registers
|
||||
pop XX
|
||||
endm
|
||||
|
||||
assume ds:nothing,es:nothing
|
||||
ret ; return to caller
|
||||
CPU_ID endp ; end CPU_ID procedure
|
||||
|
||||
subttl Check For NEC V20/V30
|
||||
page
|
||||
|
||||
CHECK_NEC proc near
|
||||
|
||||
; The NEC V20/V30 are very compatible with the Intel 8086/8088.
|
||||
; The only point of "incompatibility" is that they do not contain
|
||||
; a bug found in the Intel CPU's. Specifically, the NEC CPU's
|
||||
; correctly restart an interrupted multi-prefix string instruction
|
||||
; at the start of the instruction. The Intel CPU's incorrectly
|
||||
; restart in the middle of the instruction. This routine tests
|
||||
; for that situation by executing such an instruction for a
|
||||
; sufficiently long period of time for a timer interrupt to occur.
|
||||
; If at the end of the instruction, CX is zero, it must be an NEC
|
||||
; CPU; if not, it's an Intel CPU.
|
||||
;
|
||||
; Note that we're counting on the timer interrupt to do its thing
|
||||
; every 18.2 times per second.
|
||||
;
|
||||
; Here's a worst case analysis: An Intel 8088/8086 executes 65535
|
||||
; iterations of LODSB ES[SI] in 2+9+13*65535 = 851,966 clock ticks.
|
||||
; If the Intel 8088/8086 is running at 10 MHz, each clock tick is
|
||||
; 100 nanoseconds, hence the entire operation takes 85 milliseconds.
|
||||
; If the timer is running at normal speed, it interrupts the CPU every
|
||||
; 55ms and so should interrupt the repeated string instruction at least
|
||||
; once.
|
||||
|
||||
mov cx,0ffffh ; move a lot of data
|
||||
sti ; ensure timer enabled
|
||||
|
||||
; execute multi-prefix instruction. note that the value of ES as
|
||||
; well as the direction flag setting is irrelevant.
|
||||
|
||||
push ax ; save registers
|
||||
push si
|
||||
rep lods byte ptr es:[si]
|
||||
pop si ; restore
|
||||
pop ax
|
||||
|
||||
; on exit: if cx is zero, it's an NEC CPU, otherwise it's an Intel CPU
|
||||
|
||||
ret ; return to caller
|
||||
CHECK_NEC endp
|
||||
|
||||
subttl Pre-Fetch Instruction Queue Subroutine
|
||||
page
|
||||
|
||||
PIQL_SUB proc near
|
||||
|
||||
; This subroutine discerns the length of the CPU's pre-fetch
|
||||
; instruction queue (PIQ).
|
||||
;
|
||||
; The technique used is to first ensure that the PIQ is full, then
|
||||
; change an instruction which should be in a 6-byte PIQ but not in a
|
||||
; 4-byte PIQ. Then, if the original instruction is executed, the PIQ
|
||||
; is 6-bytes long; if the new instruction is executed, PIQ length is 4.
|
||||
;
|
||||
; We ensure the PIQ is full be executing an instruction which takes
|
||||
; long enough so that the Bus Interface Unit (BIU) can fill the PIQ
|
||||
; while the instruction is executing.
|
||||
;
|
||||
; Specifically, for all byt the last STOSB, we're simple marking time
|
||||
; waiting for the BIU to fill the PIQ. The last STOSB actually changes
|
||||
; the instruction. By that time, the orignial instruction should be in
|
||||
; a six-byte PIQ byt not a four-byte PIQ.
|
||||
|
||||
assume cs:PGROUP,es:PGROUP
|
||||
@REP equ 3 ; repeat the store this many times
|
||||
std ; store backwards
|
||||
mov di,offset es:LAB_INC+@REP-1 ; change the instructions
|
||||
; at ES:DI
|
||||
; and preceding
|
||||
mov al,ds:LAB_STI ; change to a sti
|
||||
mov cx,@REP ; give the BIU time
|
||||
; to pre-fetch instructions
|
||||
cli ; ensure interrupts are disabled,
|
||||
; otherwise a timer tick
|
||||
; could change the PIQ filling
|
||||
rep stosb ; change the instruction
|
||||
; during execution of this instruction
|
||||
; the BIU is refilling the PIQ. The
|
||||
; current instruction is no longer
|
||||
; in the PIQ.
|
||||
; Note at end, CX is 0.
|
||||
; The PIQ begins filling here
|
||||
|
||||
cld ; restore direction flag
|
||||
nop ; PIQ fillers
|
||||
nop
|
||||
nop
|
||||
|
||||
; The following instruction is beyond a four-byte-PIQ CPU's reach,
|
||||
; but within that of a six-byte-PIQ CPU.
|
||||
|
||||
LAB_INC label byte
|
||||
inc cx ; executed only if PIQ length is 6
|
||||
|
||||
LAB_STI label byte
|
||||
rept @REP-1
|
||||
sti ; restore interrupts
|
||||
endm
|
||||
|
||||
ret ; return to caller
|
||||
|
||||
assume ds:nothing,es:nothing
|
||||
PIQL_SUB endp ; end PIQL_SUB procedure
|
||||
|
||||
CODE ends ; end code segment
|
||||
|
||||
end INITIAL ; end CPU_ID module
|
||||
58
tests/pcx86/exec/exec.asm
Normal file
58
tests/pcx86/exec/exec.asm
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
.model tiny
|
||||
.code
|
||||
|
||||
ExecBlk Struc
|
||||
Psp dw ?
|
||||
Cmdline dw ?
|
||||
CmdSeg dw ?
|
||||
FCB1 dw ?
|
||||
FCB1seg dw ?
|
||||
FCB2 dw ?
|
||||
FCB2seg dw ?
|
||||
ExecBlk ends
|
||||
|
||||
org 100h
|
||||
|
||||
main proc
|
||||
lea bx,pspblk
|
||||
mov sp,bx
|
||||
call resize
|
||||
|
||||
mov execb.psp,0 ; copy our environment
|
||||
mov execb.cmdline,80h ; pass command line as is
|
||||
mov execb.FCB1,5ch
|
||||
mov execb.FCB2,6ch
|
||||
mov execb.cmdseg,cs
|
||||
mov execb.FCB1seg,cs
|
||||
mov execb.FCB2seg,cs
|
||||
lea dx,execf
|
||||
push ds
|
||||
pop es
|
||||
lea bx,execb
|
||||
mov ax,4b00h
|
||||
int 21h
|
||||
merr:
|
||||
mov ax,4c00h
|
||||
int 21h
|
||||
main endp
|
||||
resize proc
|
||||
add bx,15
|
||||
mov cl,4
|
||||
shr bx,cl
|
||||
mov ax,cs
|
||||
add bx,ax
|
||||
mov ah,4ah
|
||||
int 21h
|
||||
jc merr
|
||||
ret
|
||||
resize endp
|
||||
|
||||
|
||||
execf db "123.EXE",0 ; ASCIIZ pathname of file to be
|
||||
execd
|
||||
execb ExecBlk <>
|
||||
_stack dw 1000h dup(?)
|
||||
|
||||
pspblk label byte
|
||||
|
||||
end main
|
||||
141
tests/pcx86/inc/dos.inc
Normal file
141
tests/pcx86/inc/dos.inc
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
INT_DOSEXIT EQU 20H
|
||||
INT_DOS EQU 21H
|
||||
DOS_ABORT EQU 00H
|
||||
DOS_STD_CON_INPUT EQU 01H
|
||||
DOS_STD_CON_OUTPUT EQU 02H
|
||||
DOS_STD_AUX_INPUT EQU 03H
|
||||
DOS_STD_AUX_OUTPUT EQU 04H
|
||||
DOS_STD_PRINTER_OUTPUT EQU 05H
|
||||
DOS_RAW_CON_IO EQU 06H
|
||||
DOS_RAW_CON_INPUT EQU 07H
|
||||
DOS_STD_CON_INPUT_NO_ECHO EQU 08H
|
||||
DOS_STD_CON_STRING_OUTPUT EQU 09H
|
||||
DOS_STD_CON_STRING_INPUT EQU 0AH
|
||||
DOS_STD_CON_INPUT_STATUS EQU 0BH
|
||||
DOS_STD_CON_INPUT_FLUSH EQU 0CH
|
||||
DOS_DISK_RESET EQU 0DH
|
||||
DOS_SET_DEFAULT_DRIVE EQU 0EH
|
||||
DOS_FCB_OPEN EQU 0FH
|
||||
DOS_FCB_CLOSE EQU 10H
|
||||
DOS_DIR_SEARCH_FIRST EQU 11H
|
||||
DOS_DIR_SEARCH_NEXT EQU 12H
|
||||
DOS_FCB_DELETE EQU 13H
|
||||
DOS_FCB_SEQ_READ EQU 14H
|
||||
DOS_FCB_SEQ_WRITE EQU 15H
|
||||
DOS_FCB_CREATE EQU 16H
|
||||
DOS_FCB_RENAME EQU 17H
|
||||
DOS_RESERVED18 EQU 18H
|
||||
DOS_GET_DEFAULT_DRIVE EQU 19H
|
||||
DOS_SET_DMA EQU 1AH
|
||||
DOS_RESERVED1B EQU 1BH
|
||||
DOS_RESERVED1C EQU 1CH
|
||||
DOS_RESERVED1D EQU 1DH
|
||||
DOS_RESERVED1E EQU 1EH
|
||||
DOS_GET_DEFAULT_DPB EQU 1FH
|
||||
DOS_RESERVED20 EQU 20H
|
||||
DOS_FCB_RANDOM_READ EQU 21H
|
||||
DOS_FCB_RANDOM_WRITE EQU 22H
|
||||
DOS_GET_FCB_FILE_LENGTH EQU 23H
|
||||
DOS_GET_FCB_POSITION EQU 24H
|
||||
DOS_SET_INTERRUPT_VECTOR EQU 25H
|
||||
DOS_CREATE_PDB EQU 26H
|
||||
DOS_FCB_RANDOM_READ_BLOCK EQU 27H
|
||||
DOS_FCB_RANDOM_WRITE_BLOCK EQU 28H
|
||||
DOS_PARSE_FILE_DESCRIPTOR EQU 29H
|
||||
DOS_GET_DATE EQU 2AH
|
||||
DOS_SET_DATE EQU 2BH
|
||||
DOS_GET_TIME EQU 2CH
|
||||
DOS_SET_TIME EQU 2DH
|
||||
DOS_SET_VERIFY_ON_WRITE EQU 2EH
|
||||
DOS_GET_DMA EQU 2FH
|
||||
DOS_GET_VERSION EQU 30H
|
||||
DOS_KEEP_PROCESS EQU 31H
|
||||
DOS_GET_DPB EQU 32H
|
||||
DOS_SET_CTRL_C_TRAPPING EQU 33H
|
||||
DOS_GET_INDOS_FLAG EQU 34H
|
||||
DOS_GET_INTERRUPT_VECTOR EQU 35H
|
||||
DOS_GET_DRIVE_FREESPACE EQU 36H
|
||||
DOS_CHAR_OPER EQU 37H
|
||||
DOS_INTERNATIONAL_SUPPORT EQU 38H
|
||||
DOS_MKDIR EQU 39H
|
||||
DOS_RMDIR EQU 3AH
|
||||
DOS_CHDIR EQU 3BH
|
||||
DOS_CREAT EQU 3CH
|
||||
DOS_OPEN EQU 3DH
|
||||
DOS_CLOSE EQU 3EH
|
||||
DOS_READ EQU 3FH
|
||||
DOS_WRITE EQU 40H
|
||||
DOS_UNLINK EQU 41H
|
||||
DOS_LSEEK EQU 42H
|
||||
DOS_CHMOD EQU 43H
|
||||
DOS_IOCTL EQU 44H
|
||||
DOS_XDUP EQU 45H
|
||||
DOS_XDUP2 EQU 46H
|
||||
DOS_GETDIR EQU 47H
|
||||
DOS_ALLOC EQU 48H
|
||||
DOS_DEALLOC EQU 49H
|
||||
DOS_SETBLOCK EQU 4AH
|
||||
DOS_EXEC EQU 4BH
|
||||
DOS_EXIT EQU 4CH
|
||||
DOS_WAIT EQU 4DH
|
||||
DOS_FIND_FIRST EQU 4EH
|
||||
DOS_FIND_NEXT EQU 4FH
|
||||
DOS_SET_CURRENT_PDB EQU 50H
|
||||
DOS_GET_CURRENT_PDB EQU 51H
|
||||
DOS_GET_SYSINIT_VARS EQU 52H
|
||||
DOS_SET_DPB EQU 53H
|
||||
DOS_GET_VERIFY_ON_WRITE EQU 54H
|
||||
DOS_DUP_PDB EQU 55H
|
||||
DOS_RENAME EQU 56H
|
||||
DOS_FILE_TIMES EQU 57H
|
||||
DOS_RESERVED58 EQU 58H
|
||||
DOS_GET_EXTENDED_ERROR EQU 59H
|
||||
DOS_CREATE_TEMP_FILE EQU 5AH
|
||||
DOS_CREATE_NEW_FILE EQU 5BH
|
||||
DOS_LOCK_OPER EQU 5CH
|
||||
DOS_SERVER_CALL EQU 5DH
|
||||
DOS_USER_OPER EQU 5EH
|
||||
DOS_ASSIGN_OPER EQU 5FH
|
||||
DOS_XNAMETRANS EQU 60H
|
||||
DOS_JSA EQU 61H
|
||||
DOS_GET_CURRENT_PSP EQU 62H
|
||||
DOS_HONGEUL EQU 63H
|
||||
DOS_SYSINITSLEAZE EQU 64H
|
||||
DOSERR_NONE EQU 00H
|
||||
DOSERR_BADFUNCTION EQU 01H
|
||||
DOSERR_NOFILE EQU 02H
|
||||
DOSERR_NOPATH EQU 03H
|
||||
DOSERR_NOHANDLES EQU 04H
|
||||
DOSERR_NOACCESS EQU 05H
|
||||
DOSERR_BADHANDLE EQU 06H
|
||||
DOSERR_BADARENA EQU 07H
|
||||
DOSERR_NOMEMORY EQU 08H
|
||||
DOSERR_BADADDRESS EQU 09H
|
||||
DOSERR_BADENVIRONMENT EQU 0AH
|
||||
DOSERR_BADFORMAT EQU 0BH
|
||||
DOSERR_BADACCESS EQU 0CH
|
||||
DOSERR_BADDATA EQU 0DH
|
||||
DOSERR_BADUNIT EQU 0EH
|
||||
DOSERR_BADDISK EQU 0FH
|
||||
DOSERR_DELETECURDIR EQU 10H
|
||||
DOSERR_NOTSAMEDEVICE EQU 11H
|
||||
DOSERR_NOMOREFILES EQU 12H
|
||||
DOSERR_WRITEPROTECT EQU 13H
|
||||
DOSERR_UNKNOWNUNIT EQU 14H
|
||||
DOSERR_DRIVENOTREADY EQU 15H
|
||||
DOSERR_BADCOMMAND EQU 16H
|
||||
DOSERR_DATA EQU 17H
|
||||
DOSERR_BADREQUEST EQU 18H
|
||||
DOSERR_SEEK EQU 19H
|
||||
DOSERR_UNKNOWNMEDIA EQU 1AH
|
||||
DOSERR_BADSECTOR EQU 1BH
|
||||
DOSERR_NOPAPER EQU 1CH
|
||||
DOSERR_WRITEFAULT EQU 1DH
|
||||
DOSERR_READFAULT EQU 1EH
|
||||
DOSERR_GENERALFAILURE EQU 1FH
|
||||
DOSERR_NOTSHARED EQU 20H
|
||||
DOSERR_LOCKED EQU 21H
|
||||
DOSERR_DISKCHANGE EQU 22H
|
||||
SEEK_SET EQU 00H
|
||||
SEEK_CUR EQU 01H
|
||||
SEEK_END EQU 02H
|
||||
17
tests/pcx86/inc/misc.inc
Normal file
17
tests/pcx86/inc/misc.inc
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
CR equ 0x0d
|
||||
LF equ 0x0a
|
||||
|
||||
;
|
||||
; The "set" macro initializes a register to the specified value (eg, "set eax,0")
|
||||
;
|
||||
%macro set 2
|
||||
%ifnum %2
|
||||
%if %2 = 0
|
||||
xor %1,%1
|
||||
%else
|
||||
mov %1,%2
|
||||
%endif
|
||||
%else
|
||||
mov %1,%2
|
||||
%endif
|
||||
%endmacro
|
||||
39
tests/pcx86/inc/x86.inc
Normal file
39
tests/pcx86/inc/x86.inc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
;
|
||||
; X86.DESC defines (see x86.js)
|
||||
;
|
||||
PS_CF equ 0x0001
|
||||
PS_PF equ 0x0004
|
||||
PS_AF equ 0x0010
|
||||
PS_ZF equ 0x0040
|
||||
PS_SF equ 0x0080
|
||||
PS_TF equ 0x0100
|
||||
PS_IF equ 0x0200
|
||||
PS_DF equ 0x0400
|
||||
PS_OF equ 0x0800
|
||||
PS_ARITH equ (PS_CF | PS_PF | PS_AF | PS_ZF | PS_SF | PS_OF)
|
||||
PS_LOGIC equ (PS_CF | PS_PF | PS_ZF | PS_SF | PS_OF)
|
||||
PS_MULTIPLY equ (PS_CF | PS_OF) ; only CF and OF are "defined" following MUL or IMUL
|
||||
PS_DIVIDE equ 0 ; none of the Processor Status flags are "defined" following DIV or IDIV
|
||||
|
||||
CR0_MSW_PE equ 0x0001
|
||||
CR0_PG equ 0x80000000 ; set if paging enabled
|
||||
|
||||
ACC_TYPE_GATE386_INT equ 0x0E00
|
||||
ACC_TYPE_SEG equ 0x1000
|
||||
ACC_PRESENT equ 0x8000
|
||||
ACC_TYPE_CODE equ 0x0800
|
||||
ACC_TYPE_READABLE equ 0x0200
|
||||
ACC_TYPE_WRITABLE equ 0x0200
|
||||
ACC_TYPE_CODE_READABLE equ 0x1a00
|
||||
ACC_TYPE_DATA_WRITABLE equ 0x1200
|
||||
|
||||
|
||||
EXT_NONE equ 0x0000
|
||||
EXT_BIG equ 0x0040
|
||||
|
||||
PTE_FRAME equ 0xfffff000
|
||||
PTE_DIRTY equ 0x00000040 ; page has been modified
|
||||
PTE_ACCESSED equ 0x00000020 ; page has been accessed
|
||||
PTE_USER equ 0x00000004 ; set for user level (CPL 3), clear for supervisor level (CPL 0-2)
|
||||
PTE_READWRITE equ 0x00000002 ; set for read/write, clear for read-only (affects CPL 3 only)
|
||||
PTE_PRESENT equ 0x00000001 ; set for present page, clear for not-present page
|
||||
59
tests/pcx86/trace/README.md
Normal file
59
tests/pcx86/trace/README.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
layout: page
|
||||
title: PC Trace Utility
|
||||
permalink: /tests/pcx86/trace/
|
||||
redirect_from:
|
||||
- /tests/pc/trace/
|
||||
---
|
||||
|
||||
WARNING: This utility is obsolete. It has been superseded by [test386](/tests/pcx86/80386/),
|
||||
which, going forward, serves as our new model for instruction-level testing. As a result,
|
||||
the **traceLog()** functionality mentioned below has been removed from the PCjs source code
|
||||
(but you can always dig it back up if you really want it).
|
||||
|
||||
Overview
|
||||
---
|
||||
|
||||
TRACE.COM takes an instruction log, as recorded by the PCjs Debugger's traceLog() function, and
|
||||
"plays" the instructions back on another machine DOS-compatible 8086 machine, verifying that:
|
||||
|
||||
1. Results match the recorded results;
|
||||
2. Any "modified" flags match the recorded flags; and
|
||||
3. Any "unmodified" flags remain unmodified
|
||||
|
||||
The format of an instruction log entry is a series of lines (ASCII characters terminated by an LF),
|
||||
where each line looks like:
|
||||
|
||||
F000:EEFF SHL(0480,0002,F006) 1200,F006
|
||||
|
||||
specifically:
|
||||
|
||||
address, space, instruction, parenthesis, dst operand, comma, src operand, comma,
|
||||
input flags, parenthesis, space, result, comma, and output flags
|
||||
|
||||
WARNING: For the shift and rotate tests to pass on a real x86 CPU, we either have to distinguish
|
||||
between single-bit shifts and multi-bit shifts (because the latter leaves PS_OF in an "undefined"
|
||||
state), or we have to ignore PS_OF altogether. For now, I'm specifying PS_ALL_BUT_OF for those
|
||||
instructions, even though we'll be missing OVERFLOW validation for all single-bit shifts and rotates.
|
||||
|
||||
Operation
|
||||
---
|
||||
|
||||
To load TRACE.COM and TRACE.TXT onto a virtual disk image that PCjs can access, you can add an
|
||||
"automount" setting to your PCjs <fdc> configuration that will dynamically generate a fresh disk image
|
||||
every time the machine is loaded, via the DiskDump API. This is useful when you're constantly
|
||||
generating new test results:
|
||||
|
||||
```xml
|
||||
<fdc id="fdcNEC" automount='{B:{name:"Trace Tests",path:"/tests/pcx86/trace/trace.com;trace.txt"}}'/>
|
||||
```
|
||||
|
||||
Alternatively, if you want to run the tests in another virtual PC environment (eg, VMware Fusion),
|
||||
you can create an IMG disk image from a directory using DiskDump's command-line interface:
|
||||
|
||||
cd tests/pcx86
|
||||
node ../../modules/diskdump/bin/diskdump --dir=trace --format=img --output=trace.img
|
||||
|
||||
OS X users can also create an ISO image like so:
|
||||
|
||||
hdiutil makehybrid -o tests/pcx86/trace.iso tests/pcx86/trace -iso -joliet
|
||||
4
tests/pcx86/trace/makefile
Normal file
4
tests/pcx86/trace/makefile
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
all: trace.com
|
||||
|
||||
trace.com: trace.nasm
|
||||
nasm -f bin trace.nasm -l trace.lst -o trace.com
|
||||
710
tests/pcx86/trace/trace.nasm
Normal file
710
tests/pcx86/trace/trace.nasm
Normal file
|
|
@ -0,0 +1,710 @@
|
|||
;
|
||||
; trace.nasm
|
||||
; Copyright © 2012-2015 Jeff Parsons <Jeff@pcjs.org>
|
||||
;
|
||||
; This file is part of PCjs, which is part of the JavaScript Machines Project (aka JSMachines)
|
||||
; at <http://jsmachines.net/> and <http://pcjs.org/>.
|
||||
;
|
||||
; PCjs is free software: you can redistribute it and/or modify it under the terms of the
|
||||
; GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
; of the License, or (at your option) any later version.
|
||||
;
|
||||
; PCjs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License along with PCjs. If not,
|
||||
; see <http://www.gnu.org/licenses/gpl.html>.
|
||||
;
|
||||
; You are required to include the above copyright notice in every source code file of every
|
||||
; copy or modified version of this work, and to display that copyright notice on every screen
|
||||
; that loads or runs any version of this software (see Computer.sCopyright).
|
||||
;
|
||||
; Some PCjs files also attempt to load external resource files, such as character-image files,
|
||||
; ROM files, and disk image files. Those external resource files are not considered part of the
|
||||
; PCjs program for purposes of the GNU General Public License, and the author does not claim
|
||||
; any copyright as to their contents.
|
||||
;
|
||||
; Overview
|
||||
; --------
|
||||
; Takes an instruction log, as recorded by the Debugger's traceLog() function, and
|
||||
; "plays" the instructions back on another machine DOS-compatible 8086 machine, verifying that:
|
||||
;
|
||||
; 1) results match the recorded results
|
||||
; 2) any "modified" flags match the recorded flags
|
||||
; 3) any "unmodified" flags remain unmodified
|
||||
;
|
||||
; The format of an instruction log entry is a series of lines (ASCII characters terminated by an LF),
|
||||
; where each line looks like:
|
||||
;
|
||||
; F000:EEFF SHL(0480,0002,F006) 1200,F006
|
||||
;
|
||||
; ie, address, space, instruction, parenthesis, dst operand, comma, src operand, comma,
|
||||
; input flags, parenthesis, space, result, comma, and output flags.
|
||||
;
|
||||
; WARNING: For the shift and rotate tests to pass on a real x86 CPU, we either have to distinguish
|
||||
; between single-bit shifts and multi-bit shifts (because the latter leaves PS_OF in an "undefined"
|
||||
; state), or we have to ignore PS_OF altogether. For now, I'm specifying PS_ALL_BUT_OF for those
|
||||
; instructions, even though we'll be missing OVERFLOW validation for all single-bit shifts and rotates.
|
||||
;
|
||||
CPU 8086
|
||||
;
|
||||
; Bit masks for all the arithmetic flags we care about
|
||||
;
|
||||
PS_NONE equ 0x0000
|
||||
PS_CF equ 0x0001 ; bit 0: Carry flag
|
||||
PS_PF equ 0x0004 ; bit 2: Parity flag
|
||||
PS_AF equ 0x0010 ; bit 4: Auxiliary Carry flag (aka Arithmetic flag)
|
||||
PS_ZF equ 0x0040 ; bit 6: Zero flag
|
||||
PS_SF equ 0x0080 ; bit 7: Sign flag
|
||||
PS_OF equ 0x0800 ; bit 11: Overflow flag
|
||||
PS_ALL equ PS_CF | PS_PF | PS_AF | PS_ZF | PS_SF | PS_OF
|
||||
PS_ALL_BUT_AF equ PS_CF | PS_PF | PS_ZF | PS_SF | PS_OF
|
||||
PS_ALL_BUT_OF equ PS_CF | PS_PF | PS_AF | PS_ZF | PS_SF
|
||||
|
||||
%macro openF 1
|
||||
section .data
|
||||
%%name: db %1,0
|
||||
section .text
|
||||
mov dx,%%name
|
||||
mov ax,0x3D00
|
||||
int 0x21
|
||||
%endmacro
|
||||
|
||||
%macro readF 3
|
||||
%ifnidni %1,bx
|
||||
mov bx,%1
|
||||
%endif
|
||||
%ifnidni %2,dx
|
||||
mov dx,%2
|
||||
%endif
|
||||
%ifnidni %3,cx
|
||||
mov cx,%3
|
||||
%endif
|
||||
mov ah,0x3F
|
||||
int 0x21
|
||||
%endmacro
|
||||
|
||||
%macro print 1
|
||||
%ifidni %1,line
|
||||
push ax
|
||||
push cx
|
||||
push dx
|
||||
push si
|
||||
mov dx,si
|
||||
dec cx
|
||||
add si,cx
|
||||
mov byte [si],'$'
|
||||
mov ah,0x09
|
||||
int 0x21
|
||||
mov dx,strCRLF
|
||||
mov ah,0x09
|
||||
int 0x21
|
||||
pop si
|
||||
pop dx
|
||||
pop cx
|
||||
pop ax
|
||||
%else
|
||||
%ifstr %1
|
||||
section .data
|
||||
%%str: db %1,'$'
|
||||
section .text
|
||||
push dx
|
||||
mov dx,%%str
|
||||
%elifnidni %1,dx
|
||||
push dx
|
||||
mov dx,%1
|
||||
%endif
|
||||
push ax
|
||||
mov ah,0x09
|
||||
int 0x21
|
||||
pop ax
|
||||
%ifnidni %1,dx
|
||||
pop dx
|
||||
%endif
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%macro exit 0-2
|
||||
%ifstr %1
|
||||
section .data
|
||||
%%msg: db %1,'$'
|
||||
section .text
|
||||
%ifidni %2,oncarry
|
||||
jnc %%ok
|
||||
%endif
|
||||
mov dx,%%msg
|
||||
mov ah,0x09
|
||||
int 0x21
|
||||
%endif
|
||||
int 0x20
|
||||
%%ok:
|
||||
%endmacro
|
||||
|
||||
%macro break 0
|
||||
;
|
||||
; "int3" generates the 1-byte breakpoint instruction; "int 3" generates a 2-byte software interrupt
|
||||
;
|
||||
int3
|
||||
%endmacro
|
||||
|
||||
org 0x100
|
||||
section .text
|
||||
|
||||
openF "TRACE.TXT"
|
||||
exit "unable to open file",oncarry
|
||||
|
||||
mov di,file_buffer
|
||||
readF ax,di,file_buffer_len
|
||||
|
||||
m1: exit "unable to read file",oncarry
|
||||
|
||||
test ax,ax ; AX contains how many bytes were actually read
|
||||
jnz m2
|
||||
exit "processing complete"
|
||||
|
||||
m2: cld
|
||||
mov si,file_buffer
|
||||
add di,ax
|
||||
;
|
||||
; At this point, DS:SI is the current line pointer, and DI is the end-of-buffer
|
||||
; position. getLine() will update CX to the length of the current line (including
|
||||
; the terminating LF).
|
||||
;
|
||||
m3: call getLine
|
||||
jnc m4
|
||||
;
|
||||
; Oops, carry is set, so we're missing part or all of the next line. Move the
|
||||
; partial line to the top of the file buffer and then fill the rest of the buffer.
|
||||
;
|
||||
mov di,file_buffer
|
||||
rep movsb
|
||||
mov cx,file_buffer_end
|
||||
sub cx,di
|
||||
readF bx,di,cx
|
||||
jmp m1
|
||||
;
|
||||
; OK, we now have a complete line at DS:SI, guaranteed to end with an LF, with a
|
||||
; length of CX (although CX will soon be overwritten by calls to getHex).
|
||||
;
|
||||
m4:
|
||||
; print line
|
||||
|
||||
mov ah,' '
|
||||
call skipTo
|
||||
m4err: exit "missing space",oncarry
|
||||
inc si
|
||||
push di
|
||||
mov di,ins_name
|
||||
m5: lodsb
|
||||
cmp al,'('
|
||||
je m6
|
||||
stosb
|
||||
jmp m5
|
||||
m6: mov al,'$'
|
||||
stosb
|
||||
pop di
|
||||
|
||||
print ins_name
|
||||
print strColon
|
||||
|
||||
call getHex
|
||||
mov [dst_operand],ax
|
||||
mov [dst_operand+2],dx
|
||||
mov [dst_size],cx
|
||||
call printHex
|
||||
print strComma
|
||||
|
||||
inc si
|
||||
call getHex
|
||||
mov [src_operand],ax
|
||||
mov [src_operand+2],dx
|
||||
mov [src_size],cx
|
||||
call printHex
|
||||
|
||||
inc si
|
||||
call getHex
|
||||
and ax,PS_ALL
|
||||
mov [operand_flags],ax
|
||||
jcxz m6b
|
||||
print strComma
|
||||
call printHex
|
||||
|
||||
m6b: mov ah,' '
|
||||
call skipTo
|
||||
jc m4err
|
||||
inc si
|
||||
call getHex
|
||||
mov [result_operand],ax
|
||||
mov [result_operand+2],dx
|
||||
mov [result_size],cx
|
||||
print strEquals
|
||||
call printHex
|
||||
print strComma
|
||||
|
||||
inc si
|
||||
call getHex
|
||||
and ax,PS_ALL
|
||||
mov [result_flags],ax
|
||||
call printHex
|
||||
print strCRLF
|
||||
;
|
||||
; Now that we know operand sizes, it's time to look up the instruction function
|
||||
;
|
||||
push si
|
||||
mov si,ins_table
|
||||
push di
|
||||
m7a: mov di,ins_name
|
||||
m7b: lodsb
|
||||
test al,al
|
||||
jz m8
|
||||
mov ah,[es:di]
|
||||
inc di
|
||||
cmp al,ah
|
||||
je m7b
|
||||
m7c: lodsb
|
||||
test al,al
|
||||
jnz m7c
|
||||
add si,8 ; after then name, each ins_table entry is 4 words long
|
||||
cmp byte [si],0
|
||||
jne m7a
|
||||
print "missing function: "
|
||||
print ins_name
|
||||
exit
|
||||
|
||||
m8: mov ax,[si]
|
||||
mov cx,[result_size]
|
||||
mov dx,compare8
|
||||
cmp cl,4
|
||||
jb m8a
|
||||
mov ax,[si+2]
|
||||
mov dx,compare16
|
||||
cmp cl,8
|
||||
jb m8a
|
||||
mov ax,[si+4]
|
||||
mov dx,compare32
|
||||
m8a: test ax,ax
|
||||
jnz m8b
|
||||
print "missing "
|
||||
print ins_name
|
||||
xchg ax,cx
|
||||
call printHex
|
||||
exit
|
||||
m8b: mov [ins_function],ax
|
||||
mov [ins_compare],dx
|
||||
mov ax,[si+6]
|
||||
mov [relevant_flags],ax
|
||||
;
|
||||
; Let's call the instruction function now, loading the PS_ALL flags with the same values
|
||||
; that the emulator recorded (operand_flags).
|
||||
;
|
||||
pushf
|
||||
pop cx ; CX == current flags
|
||||
mov ax,PS_ALL
|
||||
not ax
|
||||
and cx,ax ; CX == current flags, with PS_ALL flags cleared
|
||||
or cx,[operand_flags]
|
||||
push cx ; CX == current flags, with PS_ALL flags from operand_flags included
|
||||
popf
|
||||
call [ins_function]
|
||||
pushf
|
||||
pop cx
|
||||
call [ins_compare]
|
||||
;
|
||||
; If we're still here, the instruction passed, so restore the line pointer and move to the next line
|
||||
;
|
||||
pop di
|
||||
pop si
|
||||
;
|
||||
; When we finished reading the current line, DS:SI should have been left pointing at the terminating LF;
|
||||
; however, if we used "print" to display it, that LF would have replaced with a '$'. In any case, we don't
|
||||
; really need to call skipTo, if we know we're at the end of the current line.
|
||||
;
|
||||
; mov ah,0x0A
|
||||
; call skipTo
|
||||
inc si ; step over the LF (or '$', in case we printed the line before processing it)
|
||||
jmp m3
|
||||
|
||||
compare8:
|
||||
mov ah,[result_operand]
|
||||
cmp al,ah
|
||||
jne c8err
|
||||
jmp compareFlags
|
||||
c8err: print "byte mismatch:"
|
||||
print strActual
|
||||
mov cx,2
|
||||
call printHex
|
||||
print strRecorded
|
||||
mov al,ah
|
||||
call printHex
|
||||
print strCRLF
|
||||
exit
|
||||
|
||||
compare16:
|
||||
mov dx,[result_operand]
|
||||
cmp ax,dx
|
||||
jne c16err
|
||||
jmp compareFlags
|
||||
c16err: print "word mismatch:"
|
||||
print strActual
|
||||
mov cx,4
|
||||
call printHex
|
||||
print strRecorded
|
||||
xchg ax,dx
|
||||
call printHex
|
||||
print strCRLF
|
||||
exit
|
||||
|
||||
compare32:
|
||||
cmp ax,[result_operand]
|
||||
jne c32err
|
||||
cmp dx,[result_operand+2]
|
||||
je compareFlags
|
||||
c32err: print "dword mismatch:"
|
||||
print strActual
|
||||
mov cx,8
|
||||
call printHex
|
||||
print strRecorded
|
||||
mov ax,[result_operand]
|
||||
mov dx,[result_operand+2]
|
||||
call printHex
|
||||
print strCRLF
|
||||
exit
|
||||
|
||||
compareFlags:
|
||||
mov dx,[result_flags]
|
||||
and cx,[relevant_flags]
|
||||
and dx,[relevant_flags]
|
||||
cmp cx,dx
|
||||
je cfret
|
||||
print "flag mismatch:"
|
||||
print strActual
|
||||
xchg ax,cx
|
||||
mov cx,4
|
||||
call printHex
|
||||
print strRecorded
|
||||
xchg ax,dx
|
||||
call printHex
|
||||
print strCRLF
|
||||
exit
|
||||
cfret: ret
|
||||
|
||||
testROL8:
|
||||
mov al,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
rol al,cl
|
||||
ret
|
||||
|
||||
testROL16:
|
||||
mov ax,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
rol ax,cl
|
||||
ret
|
||||
|
||||
testROR8:
|
||||
mov al,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
ror al,cl
|
||||
ret
|
||||
|
||||
testROR16:
|
||||
mov ax,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
ror ax,cl
|
||||
ret
|
||||
|
||||
testRCL8:
|
||||
mov al,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
rcl al,cl
|
||||
ret
|
||||
|
||||
testRCL16:
|
||||
mov ax,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
rcl ax,cl
|
||||
ret
|
||||
|
||||
testRCR8:
|
||||
mov al,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
rcr al,cl
|
||||
ret
|
||||
|
||||
testRCR16:
|
||||
mov ax,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
rcr ax,cl
|
||||
ret
|
||||
|
||||
testSHL8:
|
||||
mov al,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
shl al,cl
|
||||
ret
|
||||
|
||||
testSHL16:
|
||||
mov ax,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
shl ax,cl
|
||||
ret
|
||||
|
||||
testMUL16:
|
||||
mov al,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
mul cl
|
||||
ret
|
||||
|
||||
testMUL32:
|
||||
mov ax,[dst_operand]
|
||||
mov cx,[src_operand]
|
||||
mul cx
|
||||
ret
|
||||
|
||||
testIMUL16:
|
||||
mov al,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
imul cl
|
||||
ret
|
||||
|
||||
testIMUL32:
|
||||
mov ax,[dst_operand]
|
||||
mov cx,[src_operand]
|
||||
imul cx
|
||||
ret
|
||||
|
||||
testDIV16:
|
||||
mov ax,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
div cl
|
||||
ret
|
||||
|
||||
testDIV32:
|
||||
mov ax,[dst_operand]
|
||||
mov dx,[dst_operand+2]
|
||||
mov cx,[src_operand]
|
||||
div cx
|
||||
ret
|
||||
|
||||
testIDIV16:
|
||||
mov ax,[dst_operand]
|
||||
mov cl,[src_operand]
|
||||
idiv cl
|
||||
ret
|
||||
|
||||
testIDIV32:
|
||||
mov ax,[dst_operand]
|
||||
mov dx,[dst_operand+2]
|
||||
mov cx,[src_operand]
|
||||
idiv cx
|
||||
ret
|
||||
|
||||
;
|
||||
; getHex: get value of hex string
|
||||
;
|
||||
; Inputs
|
||||
; DS:SI -> hex string
|
||||
;
|
||||
; Outputs
|
||||
; CX == number of characters
|
||||
; DX:AX == corresponding value
|
||||
; DS:SI -> next non-hex character
|
||||
;
|
||||
; Uses
|
||||
; AX, CX, DX, SI, Flags
|
||||
;
|
||||
; Notes
|
||||
; Supports upper-case alpha chars only, with no prefixes (eg, "0x") or suffixes (eg, "h");
|
||||
; if there are more than 8 hex characters, the value will represent only the last 8 characters.
|
||||
;
|
||||
getHex:
|
||||
push bx
|
||||
sub bx,bx ; BX holds the low 16 bits
|
||||
sub dx,dx ; DX holds the high 16 bits
|
||||
sub cx,cx ; CX holds the character count
|
||||
gh1: lodsb
|
||||
cmp al,'0'
|
||||
jb gh9
|
||||
cmp al,'9'
|
||||
ja gh3
|
||||
sub al,'0'
|
||||
gh2: shl bx,1
|
||||
rcl dx,1
|
||||
shl bx,1
|
||||
rcl dx,1
|
||||
shl bx,1
|
||||
rcl dx,1
|
||||
shl bx,1
|
||||
rcl dx,1
|
||||
or bl,al
|
||||
inc cx
|
||||
jmp gh1
|
||||
gh3: cmp al,'A'
|
||||
jb gh9
|
||||
cmp al,'F'
|
||||
ja gh9
|
||||
sub al,'A'-10
|
||||
jmp gh2
|
||||
gh9: dec si
|
||||
xchg ax,bx ; DX:AX now holds the final 32-bit result
|
||||
pop bx
|
||||
ret
|
||||
|
||||
;
|
||||
; printHex: print value in hex
|
||||
;
|
||||
; Inputs
|
||||
; DX:AX == value
|
||||
; CX == # of characters
|
||||
;
|
||||
; Outputs
|
||||
; None
|
||||
;
|
||||
; Uses
|
||||
; Flags
|
||||
;
|
||||
printHex:
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
mov bx,ax ; DX:BX now holds the value to print
|
||||
mov di,hex_buffer_end - 1
|
||||
mov al,'$'
|
||||
std
|
||||
stosb
|
||||
ph1: jcxz ph3
|
||||
mov al,bl
|
||||
and al,0x0F
|
||||
add al,'0'
|
||||
cmp al,'9'
|
||||
jbe ph2
|
||||
add al,'A'-'0'-10
|
||||
ph2: stosb
|
||||
dec cx
|
||||
shr dx,1
|
||||
rcr bx,1
|
||||
shr dx,1
|
||||
rcr bx,1
|
||||
shr dx,1
|
||||
rcr bx,1
|
||||
shr dx,1
|
||||
rcr bx,1
|
||||
jmp ph1
|
||||
ph3: cld
|
||||
inc di
|
||||
print di
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
;
|
||||
; getLine: find the length of the current line
|
||||
;
|
||||
; Inputs
|
||||
; DS:SI -> start of line
|
||||
; DS:DI -> first byte past end of line buffer
|
||||
;
|
||||
; Outputs
|
||||
; CX == length of line, including the terminating LF (or partial length)
|
||||
; Carry clear if line complete, carry set if line incomplete (SI reached DI)
|
||||
;
|
||||
; Uses
|
||||
; AL, CX, Flags
|
||||
;
|
||||
getLine:
|
||||
push si
|
||||
sub cx,cx
|
||||
gl1: cmp si,di
|
||||
jb gl2
|
||||
stc
|
||||
jmp gl9
|
||||
gl2: lodsb
|
||||
inc cx
|
||||
cmp al,0x0A
|
||||
jne gl1
|
||||
gl9: pop si
|
||||
ret
|
||||
|
||||
;
|
||||
; skipTo: skip to the character in AH
|
||||
;
|
||||
; Inputs
|
||||
; AH == specified character
|
||||
; DS:SI -> LF-terminated line
|
||||
;
|
||||
; Outputs
|
||||
; DS:SI -> specified character if carry clear, or LF if carry set
|
||||
;
|
||||
; Uses
|
||||
; AL, SI, Flags
|
||||
;
|
||||
skipTo:
|
||||
lodsb
|
||||
cmp al,ah
|
||||
je st9
|
||||
cmp al,0x0A
|
||||
jne skipTo
|
||||
stc
|
||||
st9: dec si
|
||||
ret
|
||||
|
||||
;
|
||||
; The following is "const" (read-only) data...
|
||||
;
|
||||
section .data
|
||||
ins_table db "ROL",0
|
||||
dw testROL8, testROL16, 0, PS_ALL_BUT_OF
|
||||
db "ROR",0
|
||||
dw testROR8, testROR16, 0, PS_ALL_BUT_OF
|
||||
db "RCL",0
|
||||
dw testRCL8, testRCL16, 0, PS_ALL_BUT_OF
|
||||
db "RCR",0
|
||||
dw testRCR8, testRCR16, 0, PS_ALL_BUT_OF
|
||||
db "SHL",0
|
||||
dw testSHL8, testSHL16, 0, PS_ALL_BUT_AF
|
||||
db "MUL",0
|
||||
dw 0, testMUL16, testMUL32, PS_CF | PS_OF
|
||||
db "IMUL",0
|
||||
dw 0, testIMUL16, testIMUL32, PS_CF | PS_OF
|
||||
db "DIV",0
|
||||
dw 0, testDIV16, testDIV32, PS_NONE
|
||||
db "IMUL",0
|
||||
dw 0, testIDIV16, testIDIV32, PS_NONE
|
||||
db 0 ; end of instruction table
|
||||
|
||||
strCRLF db 0x0D,0x0A,'$'
|
||||
strColon db ":$"
|
||||
strEquals db "=$"
|
||||
strComma db ",$"
|
||||
strActual db " actual=$"
|
||||
strRecorded db " recorded=$"
|
||||
|
||||
;
|
||||
; We end with all the unitialized data (ie, data that doesn't need to be stored in the binary)
|
||||
;
|
||||
section .bss
|
||||
ins_name resb 6
|
||||
ins_function resw 1
|
||||
ins_compare resw 1
|
||||
dst_operand resw 2
|
||||
dst_size resw 1
|
||||
src_operand resw 2
|
||||
src_size resw 1
|
||||
operand_flags resw 1
|
||||
relevant_flags resw 1
|
||||
result_operand resw 2
|
||||
result_size resw 1
|
||||
result_flags resw 1
|
||||
|
||||
hex_buffer resb 9
|
||||
hex_buffer_end equ $
|
||||
hex_buffer_len equ hex_buffer_end - hex_buffer
|
||||
|
||||
file_buffer resb 0x1000
|
||||
file_buffer_end equ $
|
||||
file_buffer_len equ file_buffer_end - file_buffer
|
||||
1353
tests/pcx86/trace/trace.txt
Normal file
1353
tests/pcx86/trace/trace.txt
Normal file
File diff suppressed because it is too large
Load diff
555
tests/pcx86/vga/L23-1.ASM
Normal file
555
tests/pcx86/vga/L23-1.ASM
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
; Sample VGA program.
|
||||
; Animates four balls bouncing around a playfield by using
|
||||
; page flipping. Playfield is panned smoothly both horizontally
|
||||
; and vertically.
|
||||
; By Michael Abrash.
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup(?)
|
||||
stack ends
|
||||
;
|
||||
MEDRES_VIDEO_MODE equ 0 ;define for 640x350 video mode
|
||||
; comment out for 640x200 mode
|
||||
VIDEO_SEGMENT equ 0a000h ;display memory segment for
|
||||
; true VGA graphics modes
|
||||
LOGICAL_SCREEN_WIDTH equ 672/8 ;width in bytes and height in scan
|
||||
LOGICAL_SCREEN_HEIGHT equ 384 ; lines of the virtual screen
|
||||
; we'll work with
|
||||
PAGE0 equ 0 ;flag for page 0 when page flipping
|
||||
PAGE1 equ 1 ;flag for page 1 when page flipping
|
||||
PAGE0_OFFSET equ 0 ;start offset of page 0 in VGA memory
|
||||
PAGE1_OFFSET equ LOGICAL_SCREEN_WIDTH * LOGICAL_SCREEN_HEIGHT
|
||||
;start offset of page 1 (both pages
|
||||
; are 672x384 virtual screens)
|
||||
BALL_WIDTH equ 24/8 ;width of ball in display memory bytes
|
||||
BALL_HEIGHT equ 24 ;height of ball in scan lines
|
||||
BLANK_OFFSET equ PAGE1_OFFSET * 2;start of blank image
|
||||
; in VGA memory
|
||||
BALL_OFFSET equ BLANK_OFFSET + (BALL_WIDTH * BALL_HEIGHT)
|
||||
;start offset of ball image in VGA memory
|
||||
NUM_BALLS equ 4 ;number of balls to animate
|
||||
;
|
||||
; VGA register equates.
|
||||
;
|
||||
SC_INDEX equ 3c4h ;SC index register
|
||||
MAP_MASK equ 2 ;SC map mask register
|
||||
GC_INDEX equ 3ceh ;GC index register
|
||||
GC_MODE equ 5 ;GC mode register
|
||||
CRTC_INDEX equ 03d4h ;CRTC index register
|
||||
START_ADDRESS_HIGH equ 0ch ;CRTC start address high byte
|
||||
START_ADDRESS_LOW equ 0dh ;CRTC start address low byte
|
||||
CRTC_OFFSET equ 13h ;CRTC offset register
|
||||
INPUT_STATUS_1 equ 03dah ;VGA status register
|
||||
VSYNC_MASK equ 08h ;vertical sync bit in status register 1
|
||||
DE_MASK equ 01h ;display enable bit in status register 1
|
||||
AC_INDEX equ 03c0h ;AC index register
|
||||
HPELPAN equ 20h OR 13h ;AC horizontal pel panning register
|
||||
; (bit 7 is high to keep palette RAM
|
||||
; addressing on)
|
||||
dseg segment para common 'DATA'
|
||||
CurrentPage db PAGE1 ;page to draw to
|
||||
CurrentPageOffset dw PAGE1_OFFSET
|
||||
;
|
||||
; Four plane's worth of multicolored ball image.
|
||||
;
|
||||
BallPlane0Image label byte ;blue plane image
|
||||
db 000h, 03ch, 000h, 001h, 0ffh, 080h
|
||||
db 007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h
|
||||
db 4 * 3 dup(000h)
|
||||
db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
|
||||
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
|
||||
db 4 * 3 dup(000h)
|
||||
db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
|
||||
db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
|
||||
db 4 * 3 dup(000h)
|
||||
BallPlane1Image label byte ;green plane image
|
||||
db 4 * 3 dup(000h)
|
||||
db 01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch
|
||||
db 03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh
|
||||
db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
|
||||
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
|
||||
db 8 * 3 dup(000h)
|
||||
db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
|
||||
db 001h, 0ffh, 080h, 000h, 03ch, 000h
|
||||
BallPlane2Image label byte ;red plane image
|
||||
db 12 * 3 dup(000h)
|
||||
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
|
||||
db 0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh
|
||||
db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
|
||||
db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
|
||||
db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
|
||||
db 001h, 0ffh, 080h, 000h, 03ch, 000h
|
||||
BallPlane3Image label byte ;intensity on for all planes,
|
||||
; to produce high-intensity colors
|
||||
db 000h, 03ch, 000h, 001h, 0ffh, 080h
|
||||
db 007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h
|
||||
db 01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch
|
||||
db 03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh
|
||||
db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
|
||||
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
|
||||
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
|
||||
db 0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh
|
||||
db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
|
||||
db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
|
||||
db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
|
||||
db 001h, 0ffh, 080h, 000h, 03ch, 000h
|
||||
;
|
||||
BallX dw 15, 50, 40, 70 ;array of ball x coords
|
||||
BallY dw 40, 200, 110, 300 ;array of ball y coords
|
||||
LastBallX dw 15, 50, 40, 70 ;previous ball x coords
|
||||
LastBallY dw 40, 100, 160, 30 ;previous ball y coords
|
||||
BallXInc dw 1, 1, 1, 1 ;x move factors for ball
|
||||
BallYInc dw 8, 8, 8, 8 ;y move factors for ball
|
||||
BallRep dw 1, 1, 1, 1 ;# times to keep moving
|
||||
; ball according to current
|
||||
; increments
|
||||
BallControl dw Ball0Control, Ball1Control ;pointers to current
|
||||
dw Ball2Control, Ball3Control ; locations in ball
|
||||
; control strings
|
||||
BallControlString dw Ball0Control, Ball1Control ;pointers to
|
||||
dw Ball2Control, Ball3Control ; start of ball
|
||||
; control strings
|
||||
;
|
||||
; Ball control strings.
|
||||
;
|
||||
Ball0Control label word
|
||||
dw 10, 1, 4, 10, -1, 4, 10, -1, -4, 10, 1, -4, 0
|
||||
Ball1Control label word
|
||||
dw 12, -1, 1, 28, -1, -1, 12, 1, -1, 28, 1, 1, 0
|
||||
Ball2Control label word
|
||||
dw 20, 0, -1, 40, 0, 1, 20, 0, -1, 0
|
||||
Ball3Control label word
|
||||
dw 8, 1, 0, 52, -1, 0, 44, 1, 0, 0
|
||||
;
|
||||
; Panning control string.
|
||||
;
|
||||
ifdef MEDRES_VIDEO_MODE
|
||||
PanningControlString dw 32, 1, 0, 34, 0, 1, 32, -1, 0, 34, 0, -1, 0
|
||||
else
|
||||
PanningControlString dw 32, 1, 0, 184, 0, 1, 32, -1, 0, 184, 0, -1, 0
|
||||
endif
|
||||
PanningControl dw PanningControlString ;pointer to current location
|
||||
; in panning control string
|
||||
PanningRep dw 1 ;# times to pan according to current
|
||||
; panning increments
|
||||
PanningXInc dw 1 ;x panning factor
|
||||
PanningYInc dw 0 ;y panning factor
|
||||
HPan db 0 ;horizontal pel panning setting
|
||||
PanningStartOffset dw 0 ;start offset adjustment to produce vertical
|
||||
; panning & coarse horizontal panning
|
||||
dseg ends
|
||||
;
|
||||
; Macro to set indexed register P2 of chip with index register
|
||||
; at P1 to AL.
|
||||
;
|
||||
SETREG macro P1, P2
|
||||
mov dx,P1
|
||||
mov ah,al
|
||||
mov al,P2
|
||||
out dx,ax
|
||||
endm
|
||||
;
|
||||
cseg segment para public 'CODE'
|
||||
assume cs:cseg, ds:dseg
|
||||
start proc near
|
||||
mov ax,dseg
|
||||
mov ds,ax
|
||||
;
|
||||
; Select graphics mode.
|
||||
;
|
||||
ifdef MEDRES_VIDEO_MODE
|
||||
mov ax,010h
|
||||
else
|
||||
mov ax,0eh
|
||||
endif
|
||||
int 10h
|
||||
;
|
||||
; ES always points to VGA memory.
|
||||
;
|
||||
mov ax,VIDEO_SEGMENT
|
||||
mov es,ax
|
||||
;
|
||||
; Draw border around playfield in both pages.
|
||||
;
|
||||
mov di,PAGE0_OFFSET
|
||||
call DrawBorder ;page 0 border
|
||||
mov di,PAGE1_OFFSET
|
||||
call DrawBorder ;page 1 border
|
||||
;
|
||||
; Draw all four plane's worth of the ball to undisplayed VGA memory.
|
||||
;
|
||||
mov al,01h ;enable plane 0
|
||||
SETREG SC_INDEX, MAP_MASK
|
||||
mov si,offset BallPlane0Image
|
||||
mov di,BALL_OFFSET
|
||||
mov cx,BALL_WIDTH * BALL_HEIGHT
|
||||
rep movsb
|
||||
mov al,02h ;enable plane 1
|
||||
SETREG SC_INDEX, MAP_MASK
|
||||
mov si,offset BallPlane1Image
|
||||
mov di,BALL_OFFSET
|
||||
mov cx,BALL_WIDTH * BALL_HEIGHT
|
||||
rep movsb
|
||||
mov al,04h ;enable plane 2
|
||||
SETREG SC_INDEX, MAP_MASK
|
||||
mov si,offset BallPlane2Image
|
||||
mov di,BALL_OFFSET
|
||||
mov cx,BALL_WIDTH * BALL_HEIGHT
|
||||
rep movsb
|
||||
mov al,08h ;enable plane 3
|
||||
SETREG SC_INDEX, MAP_MASK
|
||||
mov si,offset BallPlane3Image
|
||||
mov di,BALL_OFFSET
|
||||
mov cx,BALL_WIDTH * BALL_HEIGHT
|
||||
rep movsb
|
||||
;
|
||||
; Draw a blank image the size of the ball to undisplayed VGA memory.
|
||||
;
|
||||
mov al,0fh ;enable all memory planes, since the
|
||||
SETREG SC_INDEX, MAP_MASK ; blank has to erase all planes
|
||||
mov di,BLANK_OFFSET
|
||||
mov cx,BALL_WIDTH * BALL_HEIGHT
|
||||
sub al,al
|
||||
rep stosb
|
||||
;
|
||||
; Set VGA to write mode 1, for block copying ball and blank images.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_MODE
|
||||
out dx,al ;point GC Index to GC Mode register
|
||||
inc dx ;point to GC Data register
|
||||
jmp $+2 ;delay to let bus settle
|
||||
in al,dx ;get current state of GC Mode
|
||||
and al,not 3 ;clear the write mode bits
|
||||
or al,1 ;set the write mode field to 1
|
||||
jmp $+2 ;delay to let bus settle
|
||||
out dx,al
|
||||
;
|
||||
; Set VGA offset register in words to define logical screen width.
|
||||
;
|
||||
mov al,LOGICAL_SCREEN_WIDTH / 2
|
||||
SETREG CRTC_INDEX, CRTC_OFFSET
|
||||
;
|
||||
; Move the balls by erasing each ball, moving it, and
|
||||
; redrawing it, then switching pages when they're all moved.
|
||||
;
|
||||
BallAnimationLoop:
|
||||
mov bx,( NUM_BALLS * 2 ) - 2
|
||||
EachBallLoop:
|
||||
;
|
||||
; Erase old image of ball in this page (at location from one more earlier).
|
||||
;
|
||||
mov si,BLANK_OFFSET ;point to blank image
|
||||
mov cx,[LastBallX+bx]
|
||||
mov dx,[LastBallY+bx]
|
||||
call DrawBall
|
||||
;
|
||||
; Set new last ball location.
|
||||
;
|
||||
mov ax,[BallX+bx]
|
||||
mov [LastballX+bx],ax
|
||||
mov ax,[BallY+bx]
|
||||
mov [LastballY+bx],ax
|
||||
;
|
||||
; Change the ball movement values if it's time to do so.
|
||||
;
|
||||
dec [BallRep+bx] ;has current repeat factor run out?
|
||||
jnz MoveBall
|
||||
mov si,[BallControl+bx] ;it's time to change movement values
|
||||
lodsw ;get new repeat factor from
|
||||
; control string
|
||||
and ax,ax ;at end of control string?
|
||||
jnz SetNewMove
|
||||
mov si,[BallControlString+bx] ;reset control string
|
||||
lodsw ;get new repeat factor
|
||||
SetNewMove:
|
||||
mov [BallRep+bx],ax ;set new movement repeat factor
|
||||
lodsw ;set new x movement increment
|
||||
mov [BallXInc+bx],ax
|
||||
lodsw ;set new y movement increment
|
||||
mov [BallYInc+bx],ax
|
||||
mov [BallControl+bx],si ;save new control string pointer
|
||||
;
|
||||
; Move the ball.
|
||||
;
|
||||
MoveBall:
|
||||
mov ax,[BallXInc+bx]
|
||||
add [BallX+bx],ax ;move in x direction
|
||||
mov ax,[BallYInc+bx]
|
||||
add [BallY+bx],ax ;move in y direction
|
||||
;
|
||||
; Draw ball at new location.
|
||||
;
|
||||
mov si,BALL_OFFSET ;point to ball's image
|
||||
mov cx,[BallX+bx]
|
||||
mov dx,[BallY+bx]
|
||||
call DrawBall
|
||||
;
|
||||
dec bx
|
||||
dec bx
|
||||
jns EachBallLoop
|
||||
|
||||
;
|
||||
; Set up the next panning state (but don't program it into the
|
||||
; VGA yet).
|
||||
;
|
||||
call AdjustPanning
|
||||
|
||||
;
|
||||
; Wait for display enable (pixel data being displayed) so we know
|
||||
; we're nowhere near vertical sync, where the start address gets
|
||||
; latched and used.
|
||||
;
|
||||
call WaitDisplayEnable
|
||||
;
|
||||
; Flip to the new page by changing the start address.
|
||||
;
|
||||
mov ax,[CurrentPageOffset]
|
||||
add ax,[PanningStartOffset]
|
||||
push ax
|
||||
SETREG CRTC_INDEX, START_ADDRESS_LOW
|
||||
mov al,byte ptr [CurrentPageOffset+1]
|
||||
pop ax
|
||||
mov al,ah
|
||||
SETREG CRTC_INDEX, START_ADDRESS_HIGH
|
||||
;
|
||||
; Wait for vertical sync so the new start address has a chance
|
||||
; to take effect.
|
||||
;
|
||||
call WaitVSync
|
||||
;
|
||||
; Set horizontal panning now, just as new start address takes effect.
|
||||
;
|
||||
mov al,[HPan]
|
||||
mov dx,INPUT_STATUS_1
|
||||
in al,dx ;reset AC addressing to index reg
|
||||
mov dx,AC_INDEX
|
||||
mov al,HPELPAN
|
||||
out dx,al ;set AC index to pel pan reg
|
||||
mov al,[HPan]
|
||||
out dx,al ;set new pel panning
|
||||
;
|
||||
; Flip the page to draw to the undisplayed page.
|
||||
;
|
||||
xor [CurrentPage],1
|
||||
jnz IsPage1
|
||||
mov [CurrentPageOffset],PAGE0_OFFSET
|
||||
jmp short EndFlipPage
|
||||
IsPage1:
|
||||
mov [CurrentPageOffset],PAGE1_OFFSET
|
||||
EndFlipPage:
|
||||
;
|
||||
; Exit if a key's been hit.
|
||||
;
|
||||
mov ah,1
|
||||
int 16h
|
||||
jnz Done
|
||||
jmp BallAnimationLoop
|
||||
;
|
||||
; Finished, clear key, reset screen mode and exit.
|
||||
;
|
||||
Done:
|
||||
mov ah,0 ;clear key
|
||||
int 16h
|
||||
;
|
||||
mov ax,3 ;reset to text mode
|
||||
int 10h
|
||||
;
|
||||
mov ah,4ch ;exit to DOS
|
||||
int 21h
|
||||
;
|
||||
start endp
|
||||
;
|
||||
; Routine to draw a ball-sized image to all planes, copying from
|
||||
; offset SI in VGA memory to offset CX,DX (x,y) in VGA memory in
|
||||
; the current page.
|
||||
;
|
||||
DrawBall proc near
|
||||
mov ax,LOGICAL_SCREEN_WIDTH
|
||||
mul dx ;offset of start of top image scan line
|
||||
add ax,cx ;offset of upper left of image
|
||||
add ax,[CurrentPageOffset] ;offset of start of page
|
||||
mov di,ax
|
||||
mov bp,BALL_HEIGHT
|
||||
push ds
|
||||
push es
|
||||
pop ds ;move from VGA memory to VGA memory
|
||||
DrawBallLoop:
|
||||
push di
|
||||
mov cx,BALL_WIDTH
|
||||
rep movsb ;draw a scan line of image
|
||||
pop di
|
||||
add di,LOGICAL_SCREEN_WIDTH ;point to next destination scan line
|
||||
dec bp
|
||||
jnz DrawBallLoop
|
||||
pop ds
|
||||
ret
|
||||
DrawBall endp
|
||||
;
|
||||
; Wait for the leading edge of vertical sync pulse.
|
||||
;
|
||||
WaitVSync proc near
|
||||
mov dx,INPUT_STATUS_1
|
||||
WaitNotVSyncLoop:
|
||||
in al,dx
|
||||
and al,VSYNC_MASK
|
||||
jnz WaitNotVSyncLoop
|
||||
WaitVSyncLoop:
|
||||
in al,dx
|
||||
and al,VSYNC_MASK
|
||||
jz WaitVSyncLoop
|
||||
ret
|
||||
WaitVSync endp
|
||||
|
||||
;
|
||||
; Wait for display enable to happen (pixels to be scanned to
|
||||
; the screen, indicating we're in the middle of displaying a frame).
|
||||
;
|
||||
WaitDisplayEnable proc near
|
||||
mov dx,INPUT_STATUS_1
|
||||
WaitDELoop:
|
||||
in al,dx
|
||||
and al,DE_MASK
|
||||
jnz WaitDELoop
|
||||
ret
|
||||
WaitDisplayEnable endp
|
||||
|
||||
;
|
||||
; Perform horizontal/vertical panning.
|
||||
;
|
||||
AdjustPanning proc near
|
||||
dec [PanningRep] ;time to get new panning values?
|
||||
jnz DoPan
|
||||
mov si,[PanningControl] ;point to current location in
|
||||
; panning control string
|
||||
lodsw ;get panning repeat factor
|
||||
and ax,ax ;at end of panning control string?
|
||||
jnz SetnewPanValues
|
||||
mov si,offset PanningControlString ;reset to start of string
|
||||
lodsw ;get panning repeat factor
|
||||
SetNewPanValues:
|
||||
mov [PanningRep],ax ;set new panning repeat value
|
||||
lodsw
|
||||
mov [PanningXInc],ax ;horizontal panning value
|
||||
lodsw
|
||||
mov [PanningYInc],ax ;vertical panning value
|
||||
mov [PanningControl],si ;save current location in panning
|
||||
; control string
|
||||
;
|
||||
; Pan according to panning values.
|
||||
;
|
||||
DoPan:
|
||||
mov ax,[PanningXInc] ;horizontal panning
|
||||
and ax,ax
|
||||
js PanLeft ;negative means pan left
|
||||
jz CheckVerticalPan
|
||||
mov al,[HPan]
|
||||
inc al ;pan right; if pel pan reaches
|
||||
cmp al,8 ; 8, it's time to move to the
|
||||
jb SetHPan ; next byte with a pel pan of 0
|
||||
sub al,al ; and a start offset that's one
|
||||
inc [PanningStartOffset] ; higher
|
||||
jmp short SetHPan
|
||||
PanLeft:
|
||||
mov al,[HPan]
|
||||
dec al ;pan left; if pel pan reaches -1,
|
||||
jns SetHPan ; it's time to move to the next
|
||||
mov al,7 ; byte with a pel pan of 7 and a
|
||||
dec [PanningStartOffset] ; start offset that's one lower
|
||||
SetHPan:
|
||||
mov [HPan],al ;save new pel pan value
|
||||
CheckVerticalPan:
|
||||
mov ax,[PanningYInc] ;vertical panning
|
||||
and ax,ax
|
||||
js PanUp ;negative means pan up
|
||||
jz EndPan
|
||||
add [PanningStartOffset],LOGICAL_SCREEN_WIDTH
|
||||
;pan down by advancing the start
|
||||
; address by a scan line
|
||||
jmp short EndPan
|
||||
PanUp:
|
||||
sub [PanningStartOffset],LOGICAL_SCREEN_WIDTH
|
||||
;pan up by retarding the start
|
||||
; address by a scan line
|
||||
EndPan:
|
||||
ret
|
||||
;
|
||||
; Draw textured border around playfield that starts at DI.
|
||||
;
|
||||
DrawBorder proc near
|
||||
;
|
||||
; Draw the left border.
|
||||
;
|
||||
push di
|
||||
mov cx,LOGICAL_SCREEN_HEIGHT / 16
|
||||
DrawLeftBorderLoop:
|
||||
mov al,0ch ;select red color for block
|
||||
call DrawBorderBlock
|
||||
add di,LOGICAL_SCREEN_WIDTH * 8
|
||||
mov al,0eh ;select yellow color for block
|
||||
call DrawBorderBlock
|
||||
add di,LOGICAL_SCREEN_WIDTH * 8
|
||||
loop DrawLeftBorderLoop
|
||||
pop di
|
||||
;
|
||||
; Draw the right border.
|
||||
;
|
||||
push di
|
||||
add di,LOGICAL_SCREEN_WIDTH - 1
|
||||
mov cx,LOGICAL_SCREEN_HEIGHT / 16
|
||||
DrawRightBorderLoop:
|
||||
mov al,0eh ;select yellow color for block
|
||||
call DrawBorderBlock
|
||||
add di,LOGICAL_SCREEN_WIDTH * 8
|
||||
mov al,0ch ;select red color for block
|
||||
call DrawBorderBlock
|
||||
add di,LOGICAL_SCREEN_WIDTH * 8
|
||||
loop DrawRightBorderLoop
|
||||
pop di
|
||||
;
|
||||
; Draw the top border.
|
||||
;
|
||||
push di
|
||||
mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
|
||||
DrawTopBorderLoop:
|
||||
inc di
|
||||
mov al,0eh ;select yellow color for block
|
||||
call DrawBorderBlock
|
||||
inc di
|
||||
mov al,0ch ;select red color for block
|
||||
call DrawBorderBlock
|
||||
loop DrawTopBorderLoop
|
||||
pop di
|
||||
;
|
||||
; Draw the bottom border.
|
||||
;
|
||||
add di,(LOGICAL_SCREEN_HEIGHT - 8) * LOGICAL_SCREEN_WIDTH
|
||||
mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
|
||||
DrawBottomBorderLoop:
|
||||
inc di
|
||||
mov al,0ch ;select red color for block
|
||||
call DrawBorderBlock
|
||||
inc di
|
||||
mov al,0eh ;select yellow color for block
|
||||
call DrawBorderBlock
|
||||
loop DrawBottomBorderLoop
|
||||
ret
|
||||
DrawBorder endp
|
||||
;
|
||||
; Draws an 8x8 border block in color in AL at location DI.
|
||||
; DI preserved.
|
||||
;
|
||||
DrawBorderBlock proc near
|
||||
push di
|
||||
SETREG SC_INDEX, MAP_MASK
|
||||
mov al,0ffh
|
||||
rept 8
|
||||
stosb
|
||||
add di,LOGICAL_SCREEN_WIDTH - 1
|
||||
endm
|
||||
pop di
|
||||
ret
|
||||
DrawBorderBlock endp
|
||||
AdjustPanning endp
|
||||
cseg ends
|
||||
end start
|
||||
254
tests/pcx86/vga/L24-1.ASM
Normal file
254
tests/pcx86/vga/L24-1.ASM
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
; Program to illustrate operation of ALUs and latches of the VGA's
|
||||
; Graphics Controller. Draws a variety of patterns against
|
||||
; a horizontally striped background, using each of the 4 available
|
||||
; logical functions (data unmodified, AND, OR, XOR) in turn to combine
|
||||
; the images with the background.
|
||||
; By Michael Abrash.
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup(?)
|
||||
stack ends
|
||||
;
|
||||
VGA_VIDEO_SEGMENT equ 0a000h ;VGA display memory segment
|
||||
SCREEN_HEIGHT equ 350
|
||||
SCREEN_WIDTH_IN_BYTES equ 80
|
||||
DEMO_AREA_HEIGHT equ 336 ;# of scan lines in area
|
||||
; logical function operation
|
||||
; is demonstrated in
|
||||
DEMO_AREA_WIDTH_IN_BYTES equ 40 ;width in bytes of area
|
||||
; logical function operation
|
||||
; is demonstrated in
|
||||
VERTICAL_BOX_WIDTH_IN_BYTES equ 10 ;width in bytes of the box used to
|
||||
; demonstrate each logical function
|
||||
;
|
||||
; VGA register equates.
|
||||
;
|
||||
GC_INDEX equ 3ceh ;GC index register
|
||||
GC_ROTATE equ 3 ;GC data rotate/logical function
|
||||
; register index
|
||||
GC_MODE equ 5 ;GC mode register index
|
||||
;
|
||||
dseg segment para common 'DATA'
|
||||
;
|
||||
; String used to label logical functions.
|
||||
;
|
||||
LabelString label byte
|
||||
db 'UNMODIFIED AND OR XOR '
|
||||
LABEL_STRING_LENGTH equ $-LabelString
|
||||
;
|
||||
; Strings used to label fill patterns.
|
||||
;
|
||||
FillPatternFF db 'Fill Pattern: 0FFh'
|
||||
FILL_PATTERN_FF_LENGTH equ $ - FillPatternFF
|
||||
|
||||
FillPattern00 db 'Fill Pattern: 000h'
|
||||
FILL_PATTERN_00_LENGTH equ $ - FillPattern00
|
||||
|
||||
FillPatternVert db 'Fill Pattern: Vertical Bar'
|
||||
FILL_PATTERN_VERT_LENGTH equ $ - FillPatternVert
|
||||
|
||||
FillPatternHorz db 'Fill Pattern: Horizontal Bar'
|
||||
FILL_PATTERN_HORZ_LENGTH equ $ - FillPatternHorz
|
||||
;
|
||||
dseg ends
|
||||
;
|
||||
; Macro to set indexed register INDEX of GC chip to SETTING.
|
||||
;
|
||||
SETGC macro INDEX, SETTING
|
||||
mov dx,GC_INDEX
|
||||
mov ax,(SETTING SHL 8) OR INDEX
|
||||
out dx,ax
|
||||
endm
|
||||
;
|
||||
;
|
||||
; Macro to call BIOS write string function to display text string
|
||||
; TEXT_STRING, of length TEXT_LENGTH, at location ROW,COLUMN.
|
||||
;
|
||||
TEXT_UP macro TEXT_STRING, TEXT_LENGTH, ROW, COLUMN
|
||||
mov ah,13h ;BIOS write string function
|
||||
mov bp,offset TEXT_STRING ;ES:BP points to string
|
||||
mov cx,TEXT_LENGTH
|
||||
mov dx,(ROW SHL 8) OR COLUMN;position
|
||||
sub al,al ;string is chars only, cursor not moved
|
||||
mov bl,7 ;text attribute is white (light gray)
|
||||
int 10h
|
||||
endm
|
||||
;
|
||||
cseg segment para public 'CODE'
|
||||
assume cs:cseg, ds:dseg
|
||||
start proc near
|
||||
mov ax,dseg
|
||||
mov ds,ax
|
||||
;
|
||||
; Select 640x350 graphics mode.
|
||||
;
|
||||
mov ax,010h
|
||||
int 10h
|
||||
;
|
||||
; ES points to VGA memory.
|
||||
;
|
||||
mov ax,VGA_VIDEO_SEGMENT
|
||||
mov es,ax
|
||||
;
|
||||
; Draw background of horizontal bars.
|
||||
;
|
||||
mov dx,SCREEN_HEIGHT/4
|
||||
;# of bars to draw (each 4 pixels high)
|
||||
sub di,di ;start at offset 0 in display memory
|
||||
mov ax,0ffffh ;fill pattern for light areas of bars
|
||||
mov bx,DEMO_AREA_WIDTH_IN_BYTES / 2 ;length of each bar
|
||||
mov si,SCREEN_WIDTH_IN_BYTES - DEMO_AREA_WIDTH_IN_BYTES
|
||||
mov bp,(SCREEN_WIDTH_IN_BYTES * 3) - DEMO_AREA_WIDTH_IN_BYTES
|
||||
BackgroundLoop:
|
||||
mov cx,bx ;length of bar
|
||||
rep stosw ;draw top half of bar
|
||||
add di,si ;point to start of bottom half of bar
|
||||
mov cx,bx ;length of bar
|
||||
rep stosw ;draw bottom half of bar
|
||||
add di,bp ;point to start of top of next bar
|
||||
dec dx
|
||||
jnz BackgroundLoop
|
||||
;
|
||||
; Draw vertical boxes filled with a variety of fill patterns
|
||||
; using each of the 4 logical functions in turn.
|
||||
;
|
||||
SETGC GC_ROTATE, 0 ;select data unmodified
|
||||
; logical function...
|
||||
mov di,0
|
||||
call DrawVerticalBox ;...and draw box
|
||||
;
|
||||
SETGC GC_ROTATE, 08h ;select AND logical function...
|
||||
mov di,10
|
||||
call DrawVerticalBox ;...and draw box
|
||||
;
|
||||
SETGC GC_ROTATE, 10h ;select OR logical function...
|
||||
mov di,20
|
||||
call DrawVerticalBox ;...and draw box
|
||||
;
|
||||
SETGC GC_ROTATE, 18h ;select XOR logical function...
|
||||
mov di,30
|
||||
call DrawVerticalBox ;...and draw box
|
||||
;
|
||||
; Reset the logical function to data unmodified, the default state.
|
||||
;
|
||||
SETGC GC_ROTATE, 0
|
||||
;
|
||||
; Label the screen.
|
||||
;
|
||||
push ds
|
||||
pop es ;strings we'll display are passed to BIOS
|
||||
; by pointing ES:BP to them
|
||||
;
|
||||
; Label the logical functions, using the VGA BIOS's
|
||||
; write string function.
|
||||
;
|
||||
TEXT_UP LabelString, LABEL_STRING_LENGTH, 24, 0
|
||||
;
|
||||
; Label the fill patterns, using the VGA BIOS's
|
||||
; write string function.
|
||||
;
|
||||
TEXT_UP FillPatternFF, FILL_PATTERN_FF_LENGTH, 3, 42
|
||||
TEXT_UP FillPattern00, FILL_PATTERN_00_LENGTH, 9, 42
|
||||
TEXT_UP FillPatternVert, FILL_PATTERN_VERT_LENGTH, 15, 42
|
||||
TEXT_UP FillPatternHorz, FILL_PATTERN_HORZ_LENGTH, 21, 42
|
||||
;
|
||||
; Wait until a key's been hit to reset screen mode & exit.
|
||||
;
|
||||
WaitForKey:
|
||||
mov ah,1
|
||||
int 16h
|
||||
jz WaitForKey
|
||||
;
|
||||
; Finished. Clear key, reset screen mode and exit.
|
||||
;
|
||||
Done:
|
||||
mov ah,0 ;clear key that we just detected
|
||||
int 16h
|
||||
;
|
||||
mov ax,3 ;reset to text mode
|
||||
int 10h
|
||||
;
|
||||
mov ah,4ch ;exit to DOS
|
||||
int 21h
|
||||
;
|
||||
start endp
|
||||
;
|
||||
; Subroutine to draw a box 80x336 in size, using currently selected
|
||||
; logical function, with upper left corner at the display memory offset
|
||||
; in DI. Box is filled with four patterns. Top quarter of area is
|
||||
; filled with 0FFh (solid) pattern, next quarter is filled with 00h
|
||||
; (empty) pattern, next quarter is filled with 33h (double pixel wide
|
||||
; vertical bar) pattern, and bottom quarter is filled with double pixel
|
||||
; high horizontal bar pattern.
|
||||
;
|
||||
; Macro to draw a column of the specified width in bytes, one-quarter
|
||||
; of the height of the box, with the specified fill pattern.
|
||||
;
|
||||
DRAW_BOX_QUARTER macro FILL, WIDTH
|
||||
local RowLoop, ColumnLoop
|
||||
mov al,FILL ;fill pattern
|
||||
mov dx,DEMO_AREA_HEIGHT / 4 ;1/4 of the full box height
|
||||
RowLoop:
|
||||
mov cx,WIDTH
|
||||
ColumnLoop:
|
||||
mov ah,es:[di] ;load display memory contents into
|
||||
; GC latches (we don't actually care
|
||||
; about value read into AH)
|
||||
stosb ;write pattern, which is logically
|
||||
; combined with latch contents for each
|
||||
; plane and then written to display
|
||||
; memory
|
||||
loop ColumnLoop
|
||||
add di,SCREEN_WIDTH_IN_BYTES - WIDTH
|
||||
;point to start of next line down in box
|
||||
dec dx
|
||||
jnz RowLoop
|
||||
endm
|
||||
;
|
||||
DrawVerticalBox proc near
|
||||
DRAW_BOX_QUARTER 0ffh, VERTICAL_BOX_WIDTH_IN_BYTES
|
||||
;first fill pattern: solid fill
|
||||
DRAW_BOX_QUARTER 0, VERTICAL_BOX_WIDTH_IN_BYTES
|
||||
;second fill pattern: empty fill
|
||||
DRAW_BOX_QUARTER 033h, VERTICAL_BOX_WIDTH_IN_BYTES
|
||||
;third fill pattern: double-pixel
|
||||
; wide vertical bars
|
||||
mov dx,DEMO_AREA_HEIGHT / 4 / 4
|
||||
;fourth fill pattern: horizontal bars in
|
||||
; sets of 4 scan lines
|
||||
sub ax,ax
|
||||
mov si,VERTICAL_BOX_WIDTH_IN_BYTES ;width of fill area
|
||||
HorzBarLoop:
|
||||
dec ax ;0ffh fill (smaller to do word than byte DEC)
|
||||
mov cx,si ;width to fill
|
||||
HBLoop1:
|
||||
mov bl,es:[di] ;load latches (don't care about value)
|
||||
stosb ;write solid pattern, through ALUs
|
||||
loop HBLoop1
|
||||
add di,SCREEN_WIDTH_IN_BYTES - VERTICAL_BOX_WIDTH_IN_BYTES
|
||||
mov cx,si ;width to fill
|
||||
HBLoop2:
|
||||
mov bl,es:[di] ;load latches
|
||||
stosb ;write solid pattern, through ALUs
|
||||
loop HBLoop2
|
||||
add di,SCREEN_WIDTH_IN_BYTES - VERTICAL_BOX_WIDTH_IN_BYTES
|
||||
inc ax ;0 fill (smaller to do word than byte DEC)
|
||||
mov cx,si ;width to fill
|
||||
HBLoop3:
|
||||
mov bl,es:[di] ;load latches
|
||||
stosb ;write empty pattern, through ALUs
|
||||
loop HBLoop3
|
||||
add di,SCREEN_WIDTH_IN_BYTES - VERTICAL_BOX_WIDTH_IN_BYTES
|
||||
mov cx,si ;width to fill
|
||||
HBLoop4:
|
||||
mov bl,es:[di] ;load latches
|
||||
stosb ;write empty pattern, through ALUs
|
||||
loop HBLoop4
|
||||
add di,SCREEN_WIDTH_IN_BYTES - VERTICAL_BOX_WIDTH_IN_BYTES
|
||||
dec dx
|
||||
jnz HorzBarLoop
|
||||
;
|
||||
ret
|
||||
DrawVerticalBox endp
|
||||
cseg ends
|
||||
end start
|
||||
230
tests/pcx86/vga/L25-1.ASM
Normal file
230
tests/pcx86/vga/L25-1.ASM
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
; Program to illustrate operation of data rotate and bit mask
|
||||
; features of Graphics Controller. Draws 8x8 character at
|
||||
; specified location, using VGA's 8x8 ROM font. Designed
|
||||
; for use with modes 0Dh, 0Eh, 0Fh, 10h, and 12h.
|
||||
; By Michael Abrash.
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup(?)
|
||||
stack ends
|
||||
;
|
||||
VGA_VIDEO_SEGMENT equ 0a000h ;VGA display memory segment
|
||||
SCREEN_WIDTH_IN_BYTES equ 044ah ;offset of BIOS variable
|
||||
FONT_CHARACTER_SIZE equ 8 ;# bytes in each font char
|
||||
;
|
||||
; VGA register equates.
|
||||
;
|
||||
GC_INDEX equ 3ceh ;GC index register
|
||||
GC_ROTATE equ 3 ;GC data rotate/logical function
|
||||
; register index
|
||||
GC_BIT_MASK equ 8 ;GC bit mask register index
|
||||
;
|
||||
dseg segment para common 'DATA'
|
||||
TEST_TEXT_ROW equ 69 ;row to display test text at
|
||||
TEST_TEXT_COL equ 17 ;column to display test text at
|
||||
TEST_TEXT_WIDTH equ 8 ;width of a character in pixels
|
||||
|
||||
TestString label byte
|
||||
db 'Hello, world!',0 ;test string to print.
|
||||
FontPointer dd ? ;font offset
|
||||
dseg ends
|
||||
;
|
||||
; Macro to set indexed register INDEX of GC chip to SETTING.
|
||||
;
|
||||
SETGC macro INDEX, SETTING
|
||||
mov dx,GC_INDEX
|
||||
mov ax,(SETTING SHL 8) OR INDEX
|
||||
out dx,ax
|
||||
endm
|
||||
;
|
||||
cseg segment para public 'CODE'
|
||||
assume cs:cseg, ds:dseg
|
||||
start proc near
|
||||
mov ax,dseg
|
||||
mov ds,ax
|
||||
;
|
||||
; Select 640x480 graphics mode.
|
||||
;
|
||||
mov ax,012h
|
||||
int 10h
|
||||
;
|
||||
; Set driver to use the 8x8 font.
|
||||
;
|
||||
mov ah,11h ;VGA BIOS character generator function,
|
||||
mov al,30h ; return info subfunction
|
||||
mov bh,3 ;get 8x8 font pointer
|
||||
int 10h
|
||||
call SelectFont
|
||||
;
|
||||
; Print the test string.
|
||||
;
|
||||
mov si,offset TestString
|
||||
mov bx,TEST_TEXT_ROW
|
||||
mov cx,TEST_TEXT_COL
|
||||
StringOutLoop:
|
||||
lodsb
|
||||
and al,al
|
||||
jz StringOutDone
|
||||
call DrawChar
|
||||
add cx,TEST_TEXT_WIDTH
|
||||
jmp StringOutLoop
|
||||
StringOutDone:
|
||||
;
|
||||
; Reset the data rotate and bit mask registers.
|
||||
;
|
||||
SETGC GC_ROTATE, 0
|
||||
SETGC GC_BIT_MASK, 0ffh
|
||||
;
|
||||
; Wait for a keystroke.
|
||||
;
|
||||
mov ah,1
|
||||
int 21h
|
||||
;
|
||||
; Return to text mode.
|
||||
;
|
||||
mov ax,03h
|
||||
int 10h
|
||||
;
|
||||
; Exit to DOS.
|
||||
;
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
Start endp
|
||||
;
|
||||
; Subroutine to draw a text character in a linear graphics mode
|
||||
; (0Dh, 0Eh, 0Fh, 010h, 012h).
|
||||
; Font used should be pointed to by FontPointer.
|
||||
;
|
||||
; Input:
|
||||
; AL = character to draw
|
||||
; BX = row to draw text character at
|
||||
; CX = column to draw text character at
|
||||
;
|
||||
; Forces ALU function to "move".
|
||||
;
|
||||
DrawChar proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push si
|
||||
push di
|
||||
push bp
|
||||
push ds
|
||||
;
|
||||
; Set DS:SI to point to font and ES to point to display memory.
|
||||
;
|
||||
lds si,[FontPointer] ;point to font
|
||||
mov dx,VGA_VIDEO_SEGMENT
|
||||
mov es,dx ;point to display memory
|
||||
;
|
||||
; Calculate screen address of byte character starts in.
|
||||
;
|
||||
push ds ;point to BIOS data segment
|
||||
sub dx,dx
|
||||
mov ds,dx
|
||||
xchg ax,bx
|
||||
mov di,ds:[SCREEN_WIDTH_IN_BYTES] ;retrieve BIOS
|
||||
; screen width
|
||||
pop ds
|
||||
mul di ;calculate offset of start of row
|
||||
push di ;set aside screen width
|
||||
mov di,cx ;set aside the column
|
||||
and cl,0111b;keep only the column in-byte address
|
||||
shr di,1
|
||||
shr di,1
|
||||
shr di,1 ;divide column by 8 to make a byte address
|
||||
add di,ax ;and point to byte
|
||||
;
|
||||
; Calculate font address of character.
|
||||
;
|
||||
sub bh,bh
|
||||
shl bx,1 ;assumes 8 bytes per character; use
|
||||
shl bx,1 ; a multiply otherwise
|
||||
shl bx,1 ;offset in font of character
|
||||
add si,bx ;offset in font segment of character
|
||||
;
|
||||
; Set up the GC rotation.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_ROTATE
|
||||
mov ah,cl
|
||||
out dx,ax
|
||||
;
|
||||
; Set up BH as bit mask for left half,
|
||||
; BL as rotation for right half.
|
||||
;
|
||||
mov bx,0ffffh
|
||||
shr bh,cl
|
||||
neg cl
|
||||
add cl,8
|
||||
shl bl,cl
|
||||
;
|
||||
; Draw the character, left half first, then right half in the
|
||||
; succeeding byte, using the data rotation to position the character
|
||||
; across the byte boundary and then using the bit mask to get the
|
||||
; proper portion of the character into each byte.
|
||||
; Does not check for case where character is byte-aligned and
|
||||
; no rotation and only one write is required.
|
||||
;
|
||||
mov bp,FONT_CHARACTER_SIZE
|
||||
mov dx,GC_INDEX
|
||||
pop cx ;get back screen width
|
||||
dec cx
|
||||
dec cx ; -2 because do two bytes for each char
|
||||
CharacterLoop:
|
||||
;
|
||||
; Set the bit mask for the left half of the character.
|
||||
;
|
||||
mov al,GC_BIT_MASK
|
||||
mov ah,bh
|
||||
out dx,ax
|
||||
;
|
||||
; Get the next character byte & write it to display memory.
|
||||
; (Left half of character.)
|
||||
;
|
||||
mov al,[si] ;get character byte
|
||||
mov ah,es:[di] ;load latches
|
||||
stosb ;write character byte
|
||||
;
|
||||
; Set the bit mask for the right half of the character.
|
||||
;
|
||||
mov al,GC_BIT_MASK
|
||||
mov ah,bl
|
||||
out dx,ax
|
||||
;
|
||||
; Get the character byte again & write it to display memory.
|
||||
; (Right half of character.)
|
||||
;
|
||||
lodsb ;get character byte
|
||||
mov ah,es:[di] ;load latches
|
||||
stosb ;write character byte
|
||||
;
|
||||
; Point to next line of character in display memory.
|
||||
;
|
||||
add di,cx
|
||||
;
|
||||
dec bp
|
||||
jnz CharacterLoop
|
||||
;
|
||||
pop ds
|
||||
pop bp
|
||||
pop di
|
||||
pop si
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
DrawChar endp
|
||||
;
|
||||
; Set the pointer to the font to draw from to ES:BP.
|
||||
;
|
||||
SelectFont proc near
|
||||
mov word ptr [FontPointer],bp ;save pointer
|
||||
mov word ptr [FontPointer+2],es
|
||||
ret
|
||||
SelectFont endp
|
||||
;
|
||||
cseg ends
|
||||
end start
|
||||
81
tests/pcx86/vga/L25-2.ASM
Normal file
81
tests/pcx86/vga/L25-2.ASM
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
; Program to illustrate operation of Map Mask register when drawing
|
||||
; to memory that already contains data.
|
||||
; By Michael Abrash.
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup(?)
|
||||
stack ends
|
||||
;
|
||||
EGA_VIDEO_SEGMENT equ 0a000h ;EGA display memory segment
|
||||
;
|
||||
; EGA register equates.
|
||||
;
|
||||
SC_INDEX equ 3c4h ;SC index register
|
||||
SC_MAP_MASK equ 2 ;SC map mask register
|
||||
;
|
||||
; Macro to set indexed register INDEX of SC chip to SETTING.
|
||||
;
|
||||
SETSC macro INDEX, SETTING
|
||||
mov dx,SC_INDEX
|
||||
mov al,INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,SETTING
|
||||
out dx,al
|
||||
dec dx
|
||||
endm
|
||||
;
|
||||
cseg segment para public 'CODE'
|
||||
assume cs:cseg
|
||||
start proc near
|
||||
;
|
||||
; Select 640x480 graphics mode.
|
||||
;
|
||||
mov ax,012h
|
||||
int 10h
|
||||
;
|
||||
mov ax,EGA_VIDEO_SEGMENT
|
||||
mov es,ax ;point to video memory
|
||||
;
|
||||
; Draw 24 10-scan-line high horizontal bars in green, 10 scan lines apart.
|
||||
;
|
||||
SETSC SC_MAP_MASK,02h ;map mask setting enables only
|
||||
; plane 1, the green plane
|
||||
sub di,di ;start at beginning of video memory
|
||||
mov al,0ffh
|
||||
mov bp,24 ;# bars to draw
|
||||
HorzBarLoop:
|
||||
mov cx,80*10 ;# bytes per horizontal bar
|
||||
rep stosb ;draw bar
|
||||
add di,80*10 ;point to start of next bar
|
||||
dec bp
|
||||
jnz HorzBarLoop
|
||||
;
|
||||
; Fill screen with blue, using Map Mask register to enable writes
|
||||
; to blue plane only.
|
||||
;
|
||||
SETSC SC_MAP_MASK,01h ;map mask setting enables only
|
||||
; plane 0, the blue plane
|
||||
sub di,di
|
||||
mov cx,80*480 ;# bytes per screen
|
||||
mov al,0ffh
|
||||
rep stosb ;perform fill (affects only
|
||||
; plane 0, the blue plane)
|
||||
;
|
||||
; Wait for a keystroke.
|
||||
;
|
||||
mov ah,1
|
||||
int 21h
|
||||
;
|
||||
; Restore text mode.
|
||||
;
|
||||
mov ax,03h
|
||||
int 10h
|
||||
;
|
||||
; Exit to DOS.
|
||||
;
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
start endp
|
||||
cseg ends
|
||||
end start
|
||||
108
tests/pcx86/vga/L25-3.ASM
Normal file
108
tests/pcx86/vga/L25-3.ASM
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
; Program to illustrate operation of set/reset circuitry to force
|
||||
; setting of memory that already contains data.
|
||||
; By Michael Abrash.
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup(?)
|
||||
stack ends
|
||||
;
|
||||
EGA_VIDEO_SEGMENT equ 0a000h ;EGA display memory segment
|
||||
;
|
||||
; EGA register equates.
|
||||
;
|
||||
SC_INDEX equ 3c4h ;SC index register
|
||||
SC_MAP_MASK equ 2 ;SC map mask register
|
||||
GC_INDEX equ 3ceh ;GC index register
|
||||
GC_SET_RESET equ 0 ;GC set/reset register
|
||||
GC_ENABLE_SET_RESET equ 1 ;GC enable set/reset register
|
||||
;
|
||||
; Macro to set indexed register INDEX of SC chip to SETTING.
|
||||
;
|
||||
SETSC macro INDEX, SETTING
|
||||
mov dx,SC_INDEX
|
||||
mov al,INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,SETTING
|
||||
out dx,al
|
||||
dec dx
|
||||
endm
|
||||
;
|
||||
; Macro to set indexed register INDEX of GC chip to SETTING.
|
||||
;
|
||||
SETGC macro INDEX, SETTING
|
||||
mov dx,GC_INDEX
|
||||
mov al,INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,SETTING
|
||||
out dx,al
|
||||
dec dx
|
||||
endm
|
||||
;
|
||||
cseg segment para public 'CODE'
|
||||
assume cs:cseg
|
||||
start proc near
|
||||
;
|
||||
; Select 640x480 graphics mode.
|
||||
;
|
||||
mov ax,012h
|
||||
int 10h
|
||||
;
|
||||
mov ax,EGA_VIDEO_SEGMENT
|
||||
mov es,ax ;point to video memory
|
||||
;
|
||||
; Draw 24 10-scan-line high horizontal bars in green, 10 scan lines apart.
|
||||
;
|
||||
SETSC SC_MAP_MASK,02h ;map mask setting enables only
|
||||
; plane 1, the green plane
|
||||
sub di,di ;start at beginning of video memory
|
||||
mov al,0ffh
|
||||
mov bp,24 ;# bars to draw
|
||||
HorzBarLoop:
|
||||
mov cx,80*10 ;# bytes per horizontal bar
|
||||
rep stosb ;draw bar
|
||||
add di,80*10 ;point to start of next bar
|
||||
dec bp
|
||||
jnz HorzBarLoop
|
||||
;
|
||||
; Fill screen with blue, using set/reset to force plane 0 to 1's and all
|
||||
; other plane to 0's.
|
||||
;
|
||||
SETSC SC_MAP_MASK,0fh ;must set map mask to enable all
|
||||
; planes, so set/reset values can
|
||||
; be written to memory
|
||||
SETGC GC_ENABLE_SET_RESET,0fh ;CPU data to all planes will be
|
||||
; replaced by set/reset value
|
||||
SETGC GC_SET_RESET,01h ;set/reset value is 0ffh for plane 0
|
||||
; (the blue plane) and 0 for other
|
||||
; planes
|
||||
sub di,di
|
||||
mov cx,80*480 ;# bytes per screen
|
||||
mov al,0ffh ;since set/reset is enabled for all
|
||||
; planes, the CPU data is ignored-
|
||||
; only the act of writing is
|
||||
; important
|
||||
rep stosb ;perform fill (affects all planes)
|
||||
;
|
||||
; Turn off set/reset.
|
||||
;
|
||||
SETGC GC_ENABLE_SET_RESET,0
|
||||
;
|
||||
; Wait for a keystroke.
|
||||
;
|
||||
mov ah,1
|
||||
int 21h
|
||||
;
|
||||
; Restore text mode.
|
||||
;
|
||||
mov ax,03h
|
||||
int 10h
|
||||
;
|
||||
; Exit to DOS.
|
||||
;
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
start endp
|
||||
cseg ends
|
||||
end start
|
||||
108
tests/pcx86/vga/L25-4.ASM
Normal file
108
tests/pcx86/vga/L25-4.ASM
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
; Program to illustrate operation of set/reset circuitry in conjunction
|
||||
; with CPU data to modify setting of memory that already contains data.
|
||||
; By Michael Abrash.
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup(?)
|
||||
stack ends
|
||||
;
|
||||
EGA_VIDEO_SEGMENT equ 0a000h ;EGA display memory segment
|
||||
;
|
||||
; EGA register equates.
|
||||
;
|
||||
SC_INDEX equ 3c4h ;SC index register
|
||||
SC_MAP_MASK equ 2 ;SC map mask register
|
||||
GC_INDEX equ 3ceh ;GC index register
|
||||
GC_SET_RESET equ 0 ;GC set/reset register
|
||||
GC_ENABLE_SET_RESET equ 1 ;GC enable set/reset register
|
||||
;
|
||||
; Macro to set indexed register INDEX of SC chip to SETTING.
|
||||
;
|
||||
SETSC macro INDEX, SETTING
|
||||
mov dx,SC_INDEX
|
||||
mov al,INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,SETTING
|
||||
out dx,al
|
||||
dec dx
|
||||
endm
|
||||
;
|
||||
; Macro to set indexed register INDEX of GC chip to SETTING.
|
||||
;
|
||||
SETGC macro INDEX, SETTING
|
||||
mov dx,GC_INDEX
|
||||
mov al,INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,SETTING
|
||||
out dx,al
|
||||
dec dx
|
||||
endm
|
||||
;
|
||||
cseg segment para public 'CODE'
|
||||
assume cs:cseg
|
||||
start proc near
|
||||
;
|
||||
; Select 640x350 graphics mode.
|
||||
;
|
||||
mov ax,010h
|
||||
int 10h
|
||||
;
|
||||
mov ax,EGA_VIDEO_SEGMENT
|
||||
mov es,ax ;point to video memory
|
||||
;
|
||||
; Draw 18 10-scan-line high horizontal bars in green, 10 scan lines apart.
|
||||
;
|
||||
SETSC SC_MAP_MASK,02h ;map mask setting enables only
|
||||
; plane 1, the green plane
|
||||
sub di,di ;start at beginning of video memory
|
||||
mov al,0ffh
|
||||
mov bp,18 ;# bars to draw
|
||||
HorzBarLoop:
|
||||
mov cx,80*10 ;# bytes per horizontal bar
|
||||
rep stosb ;draw bar
|
||||
add di,80*10 ;point to start of next bar
|
||||
dec bp
|
||||
jnz HorzBarLoop
|
||||
;
|
||||
; Fill screen with alternating bars of red and brown, using CPU data
|
||||
; to set plane 1 and set/reset to set planes 0, 2 & 3.
|
||||
;
|
||||
SETSC SC_MAP_MASK,0fh ;must set map mask to enable all
|
||||
; planes, so set/reset values can
|
||||
; be written to planes 0, 2 & 3
|
||||
; and CPU data can be written to
|
||||
; plane 1 (the green plane)
|
||||
SETGC GC_ENABLE_SET_RESET,0dh ;CPU data to planes 0, 2 & 3 will be
|
||||
; replaced by set/reset value
|
||||
SETGC GC_SET_RESET,04h ;set/reset value is 0ffh for plane 2
|
||||
; (the red plane) and 0 for other
|
||||
; planes
|
||||
sub di,di
|
||||
mov cx,80*350/2 ;# words per screen
|
||||
mov ax,07e0h ;CPU data controls only plane 1;
|
||||
; set/reset controls other planes
|
||||
rep stosw ;perform fill (affects all planes)
|
||||
;
|
||||
; Turn off set/reset.
|
||||
;
|
||||
SETGC GC_ENABLE_SET_RESET,0
|
||||
;
|
||||
; Wait for a keystroke.
|
||||
;
|
||||
mov ah,1
|
||||
int 21h
|
||||
;
|
||||
; Restore text mode.
|
||||
;
|
||||
mov ax,03h
|
||||
int 10h
|
||||
;
|
||||
; Exit to DOS.
|
||||
;
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
start endp
|
||||
cseg ends
|
||||
end start
|
||||
293
tests/pcx86/vga/L26-1.ASM
Normal file
293
tests/pcx86/vga/L26-1.ASM
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
; Program to illustrate operation of write mode 3 of the VGA.
|
||||
; Draws 8x8 characters at arbitrary locations without disturbing
|
||||
; the background, using VGA's 8x8 ROM font. Designed
|
||||
; for use with modes 0Dh, 0Eh, 0Fh, 10h, and 12h.
|
||||
; Runs only on VGAs (in Models 50 & up and IBM Display Adapter
|
||||
; and 100% compatibles).
|
||||
; Assembled with MASM
|
||||
; By Michael Abrash
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup(?)
|
||||
stack ends
|
||||
;
|
||||
VGA_VIDEO_SEGMENT equ 0a000h ;VGA display memory segment
|
||||
SCREEN_WIDTH_IN_BYTES equ 044ah ;offset of BIOS variable
|
||||
FONT_CHARACTER_SIZE equ 8 ;# bytes in each font char
|
||||
;
|
||||
; VGA register equates.
|
||||
;
|
||||
SC_INDEX equ 3c4h ;SC index register
|
||||
SC_MAP_MASK equ 2 ;SC map mask register index
|
||||
GC_INDEX equ 3ceh ;GC index register
|
||||
GC_SET_RESET equ 0 ;GC set/reset register index
|
||||
GC_ENABLE_SET_RESET equ 1 ;GC enable set/reset register index
|
||||
GC_ROTATE equ 3 ;GC data rotate/logical function
|
||||
; register index
|
||||
GC_MODE equ 5 ;GC Mode register
|
||||
GC_BIT_MASK equ 8 ;GC bit mask register index
|
||||
;
|
||||
dseg segment para common 'DATA'
|
||||
TEST_TEXT_ROW equ 69 ;row to display test text at
|
||||
TEST_TEXT_COL equ 17 ;column to display test text at
|
||||
TEST_TEXT_WIDTH equ 8 ;width of a character in pixels
|
||||
TestString label byte
|
||||
db 'Hello, world!',0 ;test string to print.
|
||||
FontPointer dd ? ;font offset
|
||||
dseg ends
|
||||
;
|
||||
cseg segment para public 'CODE'
|
||||
assume cs:cseg, ds:dseg
|
||||
start proc near
|
||||
mov ax,dseg
|
||||
mov ds,ax
|
||||
;
|
||||
; Select 640x480 graphics mode.
|
||||
;
|
||||
mov ax,012h
|
||||
int 10h
|
||||
;
|
||||
; Set the screen to all blue, using the readability of VGA registers
|
||||
; to preserve reserved bits.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_SET_RESET
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,0f0h
|
||||
or al,1 ;blue plane only set, others reset
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,GC_ENABLE_SET_RESET
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,0f0h
|
||||
or al,0fh ;enable set/reset for all planes
|
||||
out dx,al
|
||||
mov dx,VGA_VIDEO_SEGMENT
|
||||
mov es,dx ;point to display memory
|
||||
mov di,0
|
||||
mov cx,8000h ;fill all 32k words
|
||||
mov ax,0ffffh ;because of set/reset, the value
|
||||
; written actually doesn't matter
|
||||
rep stosw ;fill with blue
|
||||
;
|
||||
; Set driver to use the 8x8 font.
|
||||
;
|
||||
mov ah,11h ;VGA BIOS character generator function,
|
||||
mov al,30h ; return info subfunction
|
||||
mov bh,3 ;get 8x8 font pointer
|
||||
int 10h
|
||||
call SelectFont
|
||||
;
|
||||
; Print the test string, cycling through colors.
|
||||
;
|
||||
mov si,offset TestString
|
||||
mov bx,TEST_TEXT_ROW
|
||||
mov cx,TEST_TEXT_COL
|
||||
mov ah,0 ;start with color 0
|
||||
StringOutLoop:
|
||||
lodsb
|
||||
and al,al
|
||||
jz StringOutDone
|
||||
push ax ;preserve color
|
||||
call DrawChar
|
||||
pop ax ;restore color
|
||||
inc ah ;next color
|
||||
and ah,0fh ;colors range from 0 to 15
|
||||
add cx,TEST_TEXT_WIDTH
|
||||
jmp StringOutLoop
|
||||
StringOutDone:
|
||||
;
|
||||
; Wait for a key, then set to text mode & end.
|
||||
;
|
||||
mov ah,1
|
||||
int 21h ;wait for a key
|
||||
mov ax,3
|
||||
int 10h ;restore text mode
|
||||
;
|
||||
; Exit to DOS.
|
||||
;
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
Start endp
|
||||
;
|
||||
; Subroutine to draw a text character in a linear graphics mode
|
||||
; (0Dh, 0Eh, 0Fh, 010h, 012h). Background around the pixels that
|
||||
; make up the character is preserved.
|
||||
; Font used should be pointed to by FontPointer.
|
||||
;
|
||||
; Input:
|
||||
; AL = character to draw
|
||||
; AH = color to draw character in (0-15)
|
||||
; BX = row to draw text character at
|
||||
; CX = column to draw text character at
|
||||
;
|
||||
; Forces ALU function to "move".
|
||||
; Forces write mode 3.
|
||||
;
|
||||
DrawChar proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push si
|
||||
push di
|
||||
push bp
|
||||
push ds
|
||||
push ax ;preserve character to draw in AL
|
||||
;
|
||||
; Set up set/reset to produce character color, using the readability
|
||||
; of VGA register to preserve the setting of reserved bits 7-4.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_SET_RESET
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,0f0h
|
||||
and ah,0fh
|
||||
or al,ah
|
||||
out dx,al
|
||||
;
|
||||
; Select write mode 3, using the readability of VGA registers
|
||||
; to leave bits other than the write mode bits unchanged.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
or al,3
|
||||
out dx,al
|
||||
;
|
||||
; Set DS:SI to point to font and ES to point to display memory.
|
||||
;
|
||||
lds si,[FontPointer] ;point to font
|
||||
mov dx,VGA_VIDEO_SEGMENT
|
||||
mov es,dx ;point to display memory
|
||||
;
|
||||
; Calculate screen address of byte character starts in.
|
||||
;
|
||||
pop ax ;get back character to draw in AL
|
||||
|
||||
push ds ;point to BIOS data segment
|
||||
sub dx,dx
|
||||
mov ds,dx
|
||||
xchg ax,bx
|
||||
mov di,ds:[SCREEN_WIDTH_IN_BYTES] ;retrieve BIOS
|
||||
; screen width
|
||||
pop ds
|
||||
mul di ;calculate offset of start of row
|
||||
push di ;set aside screen width
|
||||
mov di,cx ;set aside the column
|
||||
and cl,0111b ;keep only the column in-byte address
|
||||
shr di,1
|
||||
shr di,1
|
||||
shr di,1 ;divide column by 8 to make a byte address
|
||||
add di,ax ;and point to byte
|
||||
;
|
||||
; Calculate font address of character.
|
||||
;
|
||||
sub bh,bh
|
||||
shl bx,1 ;assumes 8 bytes per character; use
|
||||
shl bx,1 ; a multiply otherwise
|
||||
shl bx,1 ;offset in font of character
|
||||
add si,bx ;offset in font segment of character
|
||||
;
|
||||
; Set up the GC rotation. In write mode 3, this is the rotation
|
||||
; of CPU data before it is ANDed with the Bit Mask register to
|
||||
; form the bit mask. Force the ALU function to "move". Uses the
|
||||
; readability of VGA registers to leave reserved bits unchanged.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_ROTATE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,0e0h
|
||||
or al,cl
|
||||
out dx,al
|
||||
;
|
||||
; Set up BH as bit mask for left half, BL as rotation for right half.
|
||||
;
|
||||
mov bx,0ffffh
|
||||
shr bh,cl
|
||||
neg cl
|
||||
add cl,8
|
||||
shl bl,cl
|
||||
;
|
||||
; Draw the character, left half first, then right half in the
|
||||
; succeeding byte, using the data rotation to position the character
|
||||
; across the byte boundary and then using write mode 3 to combine the
|
||||
; character data with the bit mask to allow the set/reset value (the
|
||||
; character color) through only for the proper portion (where the
|
||||
; font bits for the character are 1) of the character for each byte.
|
||||
; Wherever the font bits for the character are 0, the background
|
||||
; color is preserved.
|
||||
; Does not check for case where character is byte-aligned and
|
||||
; no rotation and only one write is required.
|
||||
;
|
||||
mov bp,FONT_CHARACTER_SIZE
|
||||
mov dx,GC_INDEX
|
||||
pop cx ;get back screen width
|
||||
dec cx
|
||||
dec cx ; -2 because do two bytes for each char
|
||||
CharacterLoop:
|
||||
;
|
||||
; Set the bit mask for the left half of the character.
|
||||
;
|
||||
mov al,GC_BIT_MASK
|
||||
mov ah,bh
|
||||
out dx,ax
|
||||
;
|
||||
; Get the next character byte & write it to display memory.
|
||||
; (Left half of character.)
|
||||
;
|
||||
mov al,[si] ;get character byte
|
||||
mov ah,es:[di] ;load latches
|
||||
stosb ;write character byte
|
||||
;
|
||||
; Set the bit mask for the right half of the character.
|
||||
;
|
||||
mov al,GC_BIT_MASK
|
||||
mov ah,bl
|
||||
out dx,ax
|
||||
;
|
||||
; Get the character byte again & write it to display memory.
|
||||
; (Right half of character.)
|
||||
;
|
||||
lodsb ;get character byte
|
||||
mov ah,es:[di] ;load latches
|
||||
stosb ;write character byte
|
||||
;
|
||||
; Point to next line of character in display memory.
|
||||
;
|
||||
add di,cx
|
||||
;
|
||||
dec bp
|
||||
jnz CharacterLoop
|
||||
;
|
||||
pop ds
|
||||
pop bp
|
||||
pop di
|
||||
pop si
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
DrawChar endp
|
||||
;
|
||||
; Set the pointer to the font to draw from to ES:BP.
|
||||
;
|
||||
SelectFont proc near
|
||||
mov word ptr [FontPointer],bp ;save pointer
|
||||
mov word ptr [FontPointer+2],es
|
||||
ret
|
||||
SelectFont endp
|
||||
;
|
||||
cseg ends
|
||||
end start
|
||||
318
tests/pcx86/vga/L26-2.ASM
Normal file
318
tests/pcx86/vga/L26-2.ASM
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
; Program to illustrate high-speed text-drawing operation of
|
||||
; write mode 3 of the VGA.
|
||||
; Draws a string of 8x14 characters at arbitrary locations
|
||||
; without disturbing the background, using VGA's 8x14 ROM font.
|
||||
; Designed for use with modes 0Dh, 0Eh, 0Fh, 10h, and 12h.
|
||||
; Runs only on VGAs (in Models 50 & up and IBM Display Adapter
|
||||
; and 100% compatibles).
|
||||
; Assembled with MASM
|
||||
; By Michael Abrash
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup(?)
|
||||
stack ends
|
||||
;
|
||||
VGA_VIDEO_SEGMENT equ 0a000h ;VGA display memory segment
|
||||
SCREEN_WIDTH_IN_BYTES equ 044ah ;offset of BIOS variable
|
||||
FONT_CHARACTER_SIZE equ 14 ;# bytes in each font char
|
||||
;
|
||||
; VGA register equates.
|
||||
;
|
||||
SC_INDEX equ 3c4h ;SC index register
|
||||
SC_MAP_MASK equ 2 ;SC map mask register index
|
||||
GC_INDEX equ 3ceh ;GC index register
|
||||
GC_SET_RESET equ 0 ;GC set/reset register index
|
||||
GC_ENABLE_SET_RESET equ 1 ;GC enable set/reset register index
|
||||
GC_ROTATE equ 3 ;GC data rotate/logical function
|
||||
; register index
|
||||
GC_MODE equ 5 ;GC Mode register
|
||||
GC_BIT_MASK equ 8 ;GC bit mask register index
|
||||
;
|
||||
dseg segment para common 'DATA'
|
||||
TEST_TEXT_ROW equ 69 ;row to display test text at
|
||||
TEST_TEXT_COL equ 17 ;column to display test text at
|
||||
TEST_TEXT_COLOR equ 0fh ;high intensity white
|
||||
TestString label byte
|
||||
db 'Hello, world!',0 ;test string to print.
|
||||
FontPointer dd ? ;font offset
|
||||
dseg ends
|
||||
;
|
||||
cseg segment para public 'CODE'
|
||||
assume cs:cseg, ds:dseg
|
||||
start proc near
|
||||
mov ax,dseg
|
||||
mov ds,ax
|
||||
;
|
||||
; Select 640x480 graphics mode.
|
||||
;
|
||||
mov ax,012h
|
||||
int 10h
|
||||
;
|
||||
; Set the screen to all blue, using the readability of VGA registers
|
||||
; to preserve reserved bits.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_SET_RESET
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,0f0h
|
||||
or al,1 ;blue plane only set, others reset
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,GC_ENABLE_SET_RESET
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,0f0h
|
||||
or al,0fh ;enable set/reset for all planes
|
||||
out dx,al
|
||||
mov dx,VGA_VIDEO_SEGMENT
|
||||
mov es,dx ;point to display memory
|
||||
mov di,0
|
||||
mov cx,8000h ;fill all 32k words
|
||||
mov ax,0ffffh ;because of set/reset, the value
|
||||
; written actually doesn't matter
|
||||
rep stosw ;fill with blue
|
||||
;
|
||||
; Set driver to use the 8x14 font.
|
||||
;
|
||||
mov ah,11h ;VGA BIOS character generator function,
|
||||
mov al,30h ; return info subfunction
|
||||
mov bh,2 ;get 8x14 font pointer
|
||||
int 10h
|
||||
call SelectFont
|
||||
;
|
||||
; Print the test string.
|
||||
;
|
||||
mov si,offset TestString
|
||||
mov bx,TEST_TEXT_ROW
|
||||
mov cx,TEST_TEXT_COL
|
||||
mov ah,TEST_TEXT_COLOR
|
||||
call DrawString
|
||||
;
|
||||
; Wait for a key, then set to text mode & end.
|
||||
;
|
||||
mov ah,1
|
||||
int 21h ;wait for a key
|
||||
mov ax,3
|
||||
int 10h ;restore text mode
|
||||
;
|
||||
; Exit to DOS.
|
||||
;
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
Start endp
|
||||
;
|
||||
; Subroutine to draw a text string left-to-right in a linear
|
||||
; graphics mode (0Dh, 0Eh, 0Fh, 010h, 012h) with 8-dot-wide
|
||||
; characters. Background around the pixels that make up the
|
||||
; characters is preserved.
|
||||
; Font used should be pointed to by FontPointer.
|
||||
;
|
||||
; Input:
|
||||
; AH = color to draw string in
|
||||
; BX = row to draw string on
|
||||
; CX = column to start string at
|
||||
; DS:SI = string to draw
|
||||
;
|
||||
; Forces ALU function to "move".
|
||||
; Forces write mode 3.
|
||||
;
|
||||
DrawString proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push si
|
||||
push di
|
||||
push bp
|
||||
push ds
|
||||
;
|
||||
; Set up set/reset to produce character color, using the readability
|
||||
; of VGA register to preserve the setting of reserved bits 7-4.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_SET_RESET
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,0f0h
|
||||
and ah,0fh
|
||||
or al,ah
|
||||
out dx,al
|
||||
;
|
||||
; Select write mode 3, using the readability of VGA registers
|
||||
; to leave bits other than the write mode bits unchanged.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
or al,3
|
||||
out dx,al
|
||||
mov dx,VGA_VIDEO_SEGMENT
|
||||
mov es,dx ;point to display memory
|
||||
;
|
||||
; Calculate screen address of byte character starts in.
|
||||
;
|
||||
push ds ;point to BIOS data segment
|
||||
sub dx,dx
|
||||
mov ds,dx
|
||||
mov di,ds:[SCREEN_WIDTH_IN_BYTES] ;retrieve BIOS
|
||||
; screen width
|
||||
pop ds
|
||||
mov ax,bx ;row
|
||||
mul di ;calculate offset of start of row
|
||||
push di ;set aside screen width
|
||||
mov di,cx ;set aside the column
|
||||
and cl,0111b ;keep only the column in-byte address
|
||||
shr di,1
|
||||
shr di,1
|
||||
shr di,1 ;divide column by 8 to make a byte address
|
||||
add di,ax ;and point to byte
|
||||
;
|
||||
; Set up the GC rotation. In write mode 3, this is the rotation
|
||||
; of CPU data before it is ANDed with the Bit Mask register to
|
||||
; form the bit mask. Force the ALU function to "move". Uses the
|
||||
; readability of VGA registers to leave reserved bits unchanged.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_ROTATE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,0e0h
|
||||
or al,cl
|
||||
out dx,al
|
||||
;
|
||||
; Set up BH as bit mask for left half, BL as rotation for right half.
|
||||
;
|
||||
mov bx,0ffffh
|
||||
shr bh,cl
|
||||
neg cl
|
||||
add cl,8
|
||||
shl bl,cl
|
||||
;
|
||||
; Draw all characters, left portion first, then right portion in the
|
||||
; succeeding byte, using the data rotation to position the character
|
||||
; across the byte boundary and then using write mode 3 to combine the
|
||||
; character data with the bit mask to allow the set/reset value (the
|
||||
; character color) through only for the proper portion (where the
|
||||
; font bits for the character are 1) of the character for each byte.
|
||||
; Wherever the font bits for the character are 0, the background
|
||||
; color is preserved.
|
||||
; Does not check for case where character is byte-aligned and
|
||||
; no rotation and only one write is required.
|
||||
;
|
||||
; Draw the left portion of each character in the string.
|
||||
;
|
||||
pop cx ;get back screen width
|
||||
push si
|
||||
push di
|
||||
push bx
|
||||
;
|
||||
; Set the bit mask for the left half of the character.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_BIT_MASK
|
||||
mov ah,bh
|
||||
out dx,ax
|
||||
LeftHalfLoop:
|
||||
lodsb
|
||||
and al,al
|
||||
jz LeftHalfLoopDone
|
||||
call CharacterUp
|
||||
inc di ;point to next character location
|
||||
jmp LeftHalfLoop
|
||||
LeftHalfLoopDone:
|
||||
pop bx
|
||||
pop di
|
||||
pop si
|
||||
;
|
||||
; Draw the right portion of each character in the string.
|
||||
;
|
||||
inc di ;right portion of each character is across
|
||||
; byte boundary
|
||||
;
|
||||
; Set the bit mask for the right half of the character.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GC_BIT_MASK
|
||||
mov ah,bl
|
||||
out dx,ax
|
||||
RightHalfLoop:
|
||||
lodsb
|
||||
and al,al
|
||||
jz RightHalfLoopDone
|
||||
call CharacterUp
|
||||
inc di ;point to next character location
|
||||
jmp RightHalfLoop
|
||||
RightHalfLoopDone:
|
||||
;
|
||||
pop ds
|
||||
pop bp
|
||||
pop di
|
||||
pop si
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
DrawString endp
|
||||
;
|
||||
; Draw a character.
|
||||
;
|
||||
; Input:
|
||||
; AL = character
|
||||
; CX = screen width
|
||||
; ES:DI = address to draw character at
|
||||
;
|
||||
CharacterUp proc near
|
||||
push cx
|
||||
push si
|
||||
push di
|
||||
push ds
|
||||
;
|
||||
; Set DS:SI to point to font and ES to point to display memory.
|
||||
;
|
||||
lds si,[FontPointer] ;point to font
|
||||
;
|
||||
; Calculate font address of character.
|
||||
;
|
||||
mov bl,14 ;14 bytes per character
|
||||
mul bl
|
||||
add si,ax ;offset in font segment of character
|
||||
|
||||
mov bp,FONT_CHARACTER_SIZE
|
||||
dec cx ; -1 because one byte per char
|
||||
CharacterLoop:
|
||||
lodsb ;get character byte
|
||||
mov ah,es:[di] ;load latches
|
||||
stosb ;write character byte
|
||||
;
|
||||
; Point to next line of character in display memory.
|
||||
;
|
||||
add di,cx
|
||||
;
|
||||
dec bp
|
||||
jnz CharacterLoop
|
||||
;
|
||||
pop ds
|
||||
pop di
|
||||
pop si
|
||||
pop cx
|
||||
ret
|
||||
CharacterUp endp
|
||||
;
|
||||
; Set the pointer to the font to draw from to ES:BP.
|
||||
;
|
||||
SelectFont proc near
|
||||
mov word ptr [FontPointer],bp ;save pointer
|
||||
mov word ptr [FontPointer+2],es
|
||||
ret
|
||||
SelectFont endp
|
||||
;
|
||||
cseg ends
|
||||
end start
|
||||
218
tests/pcx86/vga/L27-1.ASM
Normal file
218
tests/pcx86/vga/L27-1.ASM
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
; Program to illustrate one use of write mode 2 of the VGA and EGA by
|
||||
; animating the image of an "A" drawn by copying it from a chunky
|
||||
; bit-map in system memory to a planar bit-map in VGA or EGA memory.
|
||||
;
|
||||
; Assemble with MASM or TASM
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
Stack segment para stack 'STACK'
|
||||
db 512 dup(0)
|
||||
Stack ends
|
||||
|
||||
SCREEN_WIDTH_IN_BYTES equ 80
|
||||
DISPLAY_MEMORY_SEGMENT equ 0a000h
|
||||
|
||||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||||
MAP_MASK equ 2 ;index of Map Mask register
|
||||
GC_INDEX equ 03ceh ;Graphics Controller Index reg
|
||||
GRAPHICS_MODE equ 5 ;index of Graphics Mode reg
|
||||
BIT_MASK equ 8 ;index of Bit Mask reg
|
||||
|
||||
Data segment para common 'DATA'
|
||||
;
|
||||
; Current location of "A" as it is animated across the screen.
|
||||
;
|
||||
CurrentX dw ?
|
||||
CurrentY dw ?
|
||||
RemainingLength dw ?
|
||||
;
|
||||
; Chunky bit-map image of a yellow "A" on a bright blue background
|
||||
;
|
||||
AImage label byte
|
||||
dw 13, 13 ;width, height in pixels
|
||||
db 000h, 000h, 000h, 000h, 000h, 000h, 000h
|
||||
db 009h, 099h, 099h, 099h, 099h, 099h, 000h
|
||||
db 009h, 099h, 099h, 099h, 099h, 099h, 000h
|
||||
db 009h, 099h, 099h, 0e9h, 099h, 099h, 000h
|
||||
db 009h, 099h, 09eh, 0eeh, 099h, 099h, 000h
|
||||
db 009h, 099h, 0eeh, 09eh, 0e9h, 099h, 000h
|
||||
db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
|
||||
db 009h, 09eh, 0eeh, 0eeh, 0eeh, 099h, 000h
|
||||
db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
|
||||
db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
|
||||
db 009h, 099h, 099h, 099h, 099h, 099h, 000h
|
||||
db 009h, 099h, 099h, 099h, 099h, 099h, 000h
|
||||
db 000h, 000h, 000h, 000h, 000h, 000h, 000h
|
||||
Data ends
|
||||
|
||||
Code segment para public 'CODE'
|
||||
assume cs:Code, ds:Data
|
||||
Start proc near
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
mov ax,10h
|
||||
int 10h ;select video mode 10h (640x350)
|
||||
;
|
||||
; Prepare for animation.
|
||||
;
|
||||
mov [CurrentX],0
|
||||
mov [CurrentY],200
|
||||
mov [RemainingLength],600 ;move 600 times
|
||||
;
|
||||
; Animate, repeating RemainingLength times. It's unnecessary to erase
|
||||
; the old image, since the one pixel of blank fringe around the image
|
||||
; erases the part of the old image not overlapped by the new image.
|
||||
;
|
||||
AnimationLoop:
|
||||
mov bx,[CurrentX]
|
||||
mov cx,[CurrentY]
|
||||
mov si,offset AImage
|
||||
call DrawFromChunkyBitmap ;draw the "A" image
|
||||
inc [CurrentX] ;move one pixel to the right
|
||||
|
||||
mov cx,0 ;delay so we don't move the
|
||||
DelayLoop: ; image too fast; adjust as
|
||||
; needed
|
||||
loop DelayLoop
|
||||
|
||||
dec [RemainingLength]
|
||||
jnz AnimationLoop
|
||||
;
|
||||
; Wait for a key before returning to text mode and ending.
|
||||
;
|
||||
mov ah,01h
|
||||
int 21h
|
||||
mov ax,03h
|
||||
int 10h
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
Start endp
|
||||
;
|
||||
; Draw an image stored in a chunky-bit map into planar VGA/EGA memory
|
||||
; at the specified location.
|
||||
;
|
||||
; Input:
|
||||
; BX = X screen location at which to draw the upper-left corner
|
||||
; of the image
|
||||
; CX = Y screen location at which to draw the upper-left corner
|
||||
; of the image
|
||||
; DS:SI = pointer to chunky image to draw, as follows:
|
||||
; word at 0: width of image, in pixels
|
||||
; word at 2: height of image, in pixels
|
||||
; byte at 4: msb/lsb = first & second chunky pixels,
|
||||
; repeating for the remainder of the scan line
|
||||
; of the image, then for all scan lines. Images
|
||||
; with odd widths have an unused null nibble
|
||||
; padding each scan line out to a byte width
|
||||
;
|
||||
; AX, BX, CX, DX, SI, DI, ES destroyed.
|
||||
;
|
||||
DrawFromChunkyBitmap proc near
|
||||
cld
|
||||
;
|
||||
; Select write mode 2.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GRAPHICS_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,02h
|
||||
out dx,al
|
||||
;
|
||||
; Enable writes to all 4 planes.
|
||||
;
|
||||
mov dx,SC_INDEX
|
||||
mov al,MAP_MASK
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,0fh
|
||||
out dx,al
|
||||
;
|
||||
; Point ES:DI to the display memory byte in which the first pixel
|
||||
; of the image goes, with AH set up as the bit mask to access that
|
||||
; pixel within the addressed byte.
|
||||
;
|
||||
mov ax,SCREEN_WIDTH_IN_BYTES
|
||||
mul cx ;offset of start of top scan line
|
||||
mov di,ax
|
||||
mov cl,bl
|
||||
and cl,111b
|
||||
mov ah,80h ;set AH to the bit mask for the
|
||||
shr ah,cl ; initial pixel
|
||||
shr bx,1
|
||||
shr bx,1
|
||||
shr bx,1 ;X in bytes
|
||||
add di,bx ;offset of upper-left byte of image
|
||||
mov bx,DISPLAY_MEMORY_SEGMENT
|
||||
mov es,bx ;ES:DI points to the byte at which the
|
||||
; upper left of the image goes
|
||||
;
|
||||
; Get the width and height of the image.
|
||||
;
|
||||
mov cx,[si] ;get the width
|
||||
inc si
|
||||
inc si
|
||||
mov bx,[si] ;get the height
|
||||
inc si
|
||||
inc si
|
||||
mov dx,GC_INDEX
|
||||
mov al,BIT_MASK
|
||||
out dx,al ;leave the GC Index register pointing
|
||||
inc dx ; to the Bit Mask register
|
||||
RowLoop:
|
||||
|
||||
push ax ;preserve the left column's bit mask
|
||||
push cx ;preserve the width
|
||||
push di ;preserve the destination offset
|
||||
|
||||
ColumnLoop:
|
||||
mov al,ah
|
||||
out dx,al ;set the bit mask to draw this pixel
|
||||
mov al,es:[di] ;load the latches
|
||||
mov al,[si] ;get the next two chunky pixels
|
||||
shr al,1
|
||||
shr al,1
|
||||
shr al,1
|
||||
shr al,1 ;move the first pixel into the lsb
|
||||
stosb ;draw the first pixel
|
||||
ror ah,1 ;move mask to next pixel position
|
||||
jc CheckMorePixels ;is next pixel in the adjacent byte?
|
||||
dec di ;no
|
||||
|
||||
CheckMorePixels:
|
||||
dec cx ;see if there are any more pixels
|
||||
jz AdvanceToNextScanLine ; across in image
|
||||
mov al,ah
|
||||
out dx,al ;set the bit mask to draw this pixel
|
||||
mov al,es:[di] ;load the latches
|
||||
lodsb ;get the same two chunky pixels again
|
||||
; and advance pointer to the next
|
||||
; two pixels
|
||||
stosb ;draw the second of the two pixels
|
||||
ror ah,1 ;move mask to next pixel position
|
||||
jc CheckMorePixels2;is next pixel in the adjacent byte?
|
||||
dec di ;no
|
||||
|
||||
CheckMorePixels2:
|
||||
loop ColumnLoop ;see if there are any more pixels
|
||||
; across in the image
|
||||
jmp short CheckMoreScanLines
|
||||
|
||||
AdvanceToNextScanLine:
|
||||
inc si ;advance to the start of the next
|
||||
; scan line in the image
|
||||
|
||||
CheckMoreScanLines:
|
||||
pop di ;get back the destination offset
|
||||
pop cx ;get back the width
|
||||
pop ax ;get back the left column's bit mask
|
||||
add di,SCREEN_WIDTH_IN_BYTES
|
||||
;point to the start of the next scan
|
||||
; line of the image
|
||||
dec bx ;see if there are any more scan lines
|
||||
jnz RowLoop ; in the image
|
||||
ret
|
||||
DrawFromChunkyBitmap endp
|
||||
Code ends
|
||||
end Start
|
||||
327
tests/pcx86/vga/L27-2.ASM
Normal file
327
tests/pcx86/vga/L27-2.ASM
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
; Program to illustrate one use of write mode 2 of the VGA and EGA by
|
||||
; drawing lines in color patterns.
|
||||
;
|
||||
; Assemble with MASM or TASM
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
Stack segment para stack 'STACK'
|
||||
db 512 dup(0)
|
||||
Stack ends
|
||||
|
||||
SCREEN_WIDTH_IN_BYTES equ 80
|
||||
GRAPHICS_SEGMENT equ 0a000h ;mode 10 bit-map segment
|
||||
|
||||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||||
MAP_MASK equ 2 ;index of Map Mask register
|
||||
GC_INDEX equ 03ceh ;Graphics Controller Index reg
|
||||
GRAPHICS_MODE equ 5 ;index of Graphics Mode reg
|
||||
BIT_MASK equ 8 ;index of Bit Mask reg
|
||||
|
||||
Data segment para common 'DATA'
|
||||
Pattern0 db 16
|
||||
db 0, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
db 9, 10, 11, 12, 13, 14, 15
|
||||
Pattern1 db 6
|
||||
db 2, 2, 2, 10, 10, 10
|
||||
Pattern2 db 8
|
||||
db 15, 15, 15, 0, 0, 15, 0, 0
|
||||
Pattern3 db 9
|
||||
db 1, 1, 1, 2, 2, 2, 4, 4, 4
|
||||
Data ends
|
||||
|
||||
Code segment para public 'CODE'
|
||||
assume cs:Code, ds:Data
|
||||
Start proc near
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
mov ax,10h
|
||||
int 10h ;select video mode 10h (640x350)
|
||||
;
|
||||
; Draw 8 radial lines in upper-left quadrant in pattern 0.
|
||||
;
|
||||
mov bx,0
|
||||
mov cx,0
|
||||
mov si,offset Pattern0
|
||||
call QuadrantUp
|
||||
;
|
||||
; Draw 8 radial lines in upper-right quadrant in pattern 1.
|
||||
;
|
||||
mov bx,320
|
||||
mov cx,0
|
||||
mov si,offset Pattern1
|
||||
call QuadrantUp
|
||||
;
|
||||
; Draw 8 radial lines in lower-left quadrant in pattern 2.
|
||||
;
|
||||
mov bx,0
|
||||
mov cx,175
|
||||
mov si,offset Pattern2
|
||||
call QuadrantUp
|
||||
;
|
||||
; Draw 8 radial lines in lower-right quadrant in pattern 3.
|
||||
;
|
||||
mov bx,320
|
||||
mov cx,175
|
||||
mov si,offset Pattern3
|
||||
call QuadrantUp
|
||||
;
|
||||
; Wait for a key before returning to text mode and ending.
|
||||
;
|
||||
mov ah,01h
|
||||
int 21h
|
||||
mov ax,03h
|
||||
int 10h
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
;
|
||||
; Draws 8 radial lines with specified pattern in specified mode 10h
|
||||
; quadrant.
|
||||
;
|
||||
; Input:
|
||||
; BX = X coordinate of upper left corner of quadrant
|
||||
; CX = Y coordinate of upper left corner of quadrant
|
||||
; SI = pointer to pattern, in following form:
|
||||
; Byte 0: Length of pattern
|
||||
; Byte 1: Start of pattern, one color per byte
|
||||
;
|
||||
; AX, BX, CX, DX destroyed
|
||||
;
|
||||
QuadrantUp proc near
|
||||
add bx,160
|
||||
add cx,87 ;point to the center of the quadrant
|
||||
mov ax,0
|
||||
mov dx,160
|
||||
call LineUp ;draw horizontal line to right edge
|
||||
mov ax,1
|
||||
mov dx,88
|
||||
call LineUp ;draw diagonal line to upper right
|
||||
mov ax,2
|
||||
mov dx,88
|
||||
call LineUp ;draw vertical line to top edge
|
||||
mov ax,3
|
||||
mov dx,88
|
||||
call LineUp ;draw diagonal line to upper left
|
||||
mov ax,4
|
||||
mov dx,161
|
||||
call LineUp ;draw horizontal line to left edge
|
||||
mov ax,5
|
||||
mov dx,88
|
||||
call LineUp ;draw diagonal line to lower left
|
||||
mov ax,6
|
||||
mov dx,88
|
||||
call LineUp ;draw vertical line to bottom edge
|
||||
mov ax,7
|
||||
mov dx,88
|
||||
call LineUp ;draw diagonal line to bottom right
|
||||
ret
|
||||
QuadrantUp endp
|
||||
;
|
||||
; Draws a horizontal, vertical, or diagonal line (one of the eight
|
||||
; possible radial lines) of the specified length from the specified
|
||||
; starting point.
|
||||
;
|
||||
; Input:
|
||||
; AX = line direction, as follows:
|
||||
; 3 2 1
|
||||
; 4 * 0
|
||||
; 5 6 7
|
||||
; BX = X coordinate of starting point
|
||||
; CX = Y coordinate of starting point
|
||||
; DX = length of line (number of pixels drawn)
|
||||
;
|
||||
; All registers preserved.
|
||||
;
|
||||
; Table of vectors to routines for each of the 8 possible lines.
|
||||
;
|
||||
LineUpVectors label word
|
||||
dw LineUp0, LineUp1, LineUp2, LineUp3
|
||||
dw LineUp4, LineUp5, LineUp6, LineUp7
|
||||
|
||||
;
|
||||
; Macro to draw horizontal, vertical, or diagonal line.
|
||||
;
|
||||
; Input:
|
||||
; XParm = 1 to draw right, -1 to draw left, 0 to not move horz.
|
||||
; YParm = 1 to draw up, -1 to draw down, 0 to not move vert.
|
||||
; BX = X start location
|
||||
; CX = Y start location
|
||||
; DX = number of pixels to draw
|
||||
; DS:SI = line pattern
|
||||
;
|
||||
MLineUp macro XParm, YParm
|
||||
local LineUpLoop, CheckMoreLine
|
||||
mov di,si ;set aside start offset of pattern
|
||||
lodsb ;get length of pattern
|
||||
mov ah,al
|
||||
|
||||
LineUpLoop:
|
||||
lodsb ;get color of this pixel...
|
||||
call DotUpInColor ;...and draw it
|
||||
if XParm EQ 1
|
||||
inc bx
|
||||
endif
|
||||
if XParm EQ -1
|
||||
dec bx
|
||||
endif
|
||||
if YParm EQ 1
|
||||
inc cx
|
||||
endif
|
||||
if YParm EQ -1
|
||||
dec cx
|
||||
endif
|
||||
dec ah ;at end of pattern?
|
||||
jnz CheckMoreLine
|
||||
mov si,di ;get back start of pattern
|
||||
lodsb
|
||||
mov ah,al ;reset pattern count
|
||||
|
||||
CheckMoreLine:
|
||||
dec dx
|
||||
jnz LineUpLoop
|
||||
jmp LineUpEnd
|
||||
endm
|
||||
|
||||
LineUp proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push si
|
||||
push di
|
||||
push es
|
||||
|
||||
mov di,ax
|
||||
|
||||
mov ax,GRAPHICS_SEGMENT
|
||||
mov es,ax
|
||||
|
||||
push dx ;save line length
|
||||
;
|
||||
; Enable writes to all planes.
|
||||
;
|
||||
mov dx,SC_INDEX
|
||||
mov al,MAP_MASK
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,0fh
|
||||
out dx,al
|
||||
;
|
||||
; Select write mode 2.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GRAPHICS_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,02h
|
||||
out dx,al
|
||||
;
|
||||
; Vector to proper routine.
|
||||
;
|
||||
pop dx ;get back line length
|
||||
|
||||
shl di,1
|
||||
jmp cs:[LineUpVectors+di]
|
||||
;
|
||||
; Horizontal line to right.
|
||||
;
|
||||
LineUp0:
|
||||
MLineUp 1, 0
|
||||
;
|
||||
; Diagonal line to upper right.
|
||||
;
|
||||
LineUp1:
|
||||
MLineUp 1, -1
|
||||
;
|
||||
; Vertical line to top.
|
||||
;
|
||||
LineUp2:
|
||||
MLineUp 0, -1
|
||||
;
|
||||
; Diagonal line to upper left.
|
||||
;
|
||||
LineUp3:
|
||||
MLineUp -1, -1
|
||||
;
|
||||
; Horizontal line to left.
|
||||
;
|
||||
LineUp4:
|
||||
MLineUp -1, 0
|
||||
;
|
||||
; Diagonal line to bottom left.
|
||||
;
|
||||
LineUp5:
|
||||
MLineUp -1, 1
|
||||
;
|
||||
; Vertical line to bottom.
|
||||
;
|
||||
LineUp6:
|
||||
MLineUp 0, 1
|
||||
;
|
||||
; Diagonal line to bottom right.
|
||||
;
|
||||
LineUp7:
|
||||
MLineUp 1, 1
|
||||
|
||||
LineUpEnd:
|
||||
pop es
|
||||
pop di
|
||||
pop si
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
LineUp endp
|
||||
;
|
||||
; Draws a dot in the specified color at the specified location.
|
||||
; Assumes that the VGA is in write mode 2 with writes to all planes
|
||||
; enabled and that ES points to display memory.
|
||||
;
|
||||
; Input:
|
||||
; AL = dot color
|
||||
; BX = X coordinate of dot
|
||||
; CX = Y coordinate of dot
|
||||
; ES = display memory segment
|
||||
;
|
||||
; All registers preserved.
|
||||
;
|
||||
DotUpInColor proc near
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
;
|
||||
; Point ES:DI to the display memory byte in which the pixel goes, with
|
||||
; the bit mask set up to access that pixel within the addressed byte.
|
||||
;
|
||||
push ax ;preserve dot color
|
||||
mov ax,SCREEN_WIDTH_IN_BYTES
|
||||
mul cx ;offset of start of top scan line
|
||||
mov di,ax
|
||||
mov cl,bl
|
||||
and cl,111b
|
||||
mov dx,GC_INDEX
|
||||
mov al,BIT_MASK
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,80h
|
||||
shr al,cl
|
||||
out dx,al ;set the bit mask for the pixel
|
||||
shr bx,1
|
||||
shr bx,1
|
||||
shr bx,1 ;X in bytes
|
||||
add di,bx ;offset of byte pixel is in
|
||||
mov al,es:[di] ;load latches
|
||||
pop ax ;get back dot color
|
||||
stosb ;write dot in desired color
|
||||
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
ret
|
||||
DotUpInColor endp
|
||||
Start endp
|
||||
Code ends
|
||||
end Start
|
||||
192
tests/pcx86/vga/L27-3.ASM
Normal file
192
tests/pcx86/vga/L27-3.ASM
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
; Program to illustrate flipping from bit-mapped graphics mode to
|
||||
; text mode and back without losing any of the graphics bit-map.
|
||||
;
|
||||
; Assemble with MASM or TASM
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
Stack segment para stack 'STACK'
|
||||
db 512 dup(0)
|
||||
Stack ends
|
||||
|
||||
GRAPHICS_SEGMENT equ 0a000h ;mode 10 bit-map segment
|
||||
TEXT_SEGMENT equ 0b800h ;mode 3 bit-map segment
|
||||
|
||||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||||
MAP_MASK equ 2 ;index of Map Mask register
|
||||
GC_INDEX equ 3ceh ;Graphics Controller Index register
|
||||
READ_MAP equ 4 ;index of Read Map register
|
||||
|
||||
Data segment para common 'DATA'
|
||||
|
||||
GStrikeAnyKeyMsg0 label byte
|
||||
db 0dh, 0ah, 'Graphics mode', 0dh, 0ah
|
||||
db 'Strike any key to continue...', 0dh, 0ah, '$'
|
||||
|
||||
GStrikeAnyKeyMsg1 label byte
|
||||
db 0dh, 0ah, 'Graphics mode again', 0dh, 0ah
|
||||
db 'Strike any key to continue...', 0dh, 0ah, '$'
|
||||
|
||||
TStrikeAnyKeyMsg label byte
|
||||
db 0dh, 0ah, 'Text mode', 0dh, 0ah
|
||||
db 'Strike any key to continue...', 0dh, 0ah, '$'
|
||||
|
||||
Plane2Save db 2000h dup (?) ;save area for plane 2 data
|
||||
; where font gets loaded
|
||||
CharAttSave db 4000 dup (?) ;save area for memory wiped
|
||||
; out by character/attribute
|
||||
; data in text mode
|
||||
Data ends
|
||||
|
||||
Code segment para public 'CODE'
|
||||
assume cs:Code, ds:Data
|
||||
Start proc near
|
||||
mov ax,10h
|
||||
int 10h ;select video mode 10h (640x350)
|
||||
;
|
||||
; Fill the graphics bit-map with a colored pattern.
|
||||
;
|
||||
cld
|
||||
mov ax,GRAPHICS_SEGMENT
|
||||
mov es,ax
|
||||
mov ah,3 ;initial fill pattern
|
||||
mov cx,4 ;four planes to fill
|
||||
mov dx,SC_INDEX
|
||||
mov al,MAP_MASK
|
||||
out dx,al ;leave the SC Index pointing to the
|
||||
inc dx ; Map Mask register
|
||||
|
||||
FillBitMap:
|
||||
mov al,10h
|
||||
shr al,cl ;generate map mask for this plane
|
||||
out dx,al ;set map mask for this plane
|
||||
sub di,di ;start at offset 0
|
||||
mov al,ah ;get the fill pattern
|
||||
push cx ;preserve plane count
|
||||
mov cx,8000h ;fill 32K words
|
||||
rep stosw ;do fill for this plane
|
||||
pop cx ;get back plane count
|
||||
shl ah,1
|
||||
shl ah,1
|
||||
loop FillBitMap
|
||||
;
|
||||
; Put up "strike any key" message.
|
||||
;
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
mov dx,offset GStrikeAnyKeyMsg0
|
||||
mov ah,9
|
||||
int 21h
|
||||
;
|
||||
; Wait for a key.
|
||||
;
|
||||
mov ah,01h
|
||||
int 21h
|
||||
;
|
||||
; Save the 8K of plane 2 that will be used by the font.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,READ_MAP
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,2
|
||||
out dx,al ;set up to read from plane 2
|
||||
mov ax,Data
|
||||
mov es,ax
|
||||
mov ax,GRAPHICS_SEGMENT
|
||||
mov ds,ax
|
||||
sub si,si
|
||||
mov di,offset Plane2Save
|
||||
mov cx,2000h/2 ;save 8K (length of default font)
|
||||
rep movsw
|
||||
;
|
||||
; Go to text mode without clearing display memory.
|
||||
;
|
||||
mov ax,083h
|
||||
int 10h
|
||||
;
|
||||
; Save the text mode bit-map.
|
||||
;
|
||||
mov ax,Data
|
||||
mov es,ax
|
||||
mov ax,TEXT_SEGMENT
|
||||
mov ds,ax
|
||||
sub si,si
|
||||
mov di,offset CharAttSave
|
||||
mov cx,4000/2 ;length of one text screen in words
|
||||
rep movsw
|
||||
;
|
||||
; Fill the text mode screen with dots and put up "strike any key"
|
||||
; message.
|
||||
;
|
||||
mov ax,TEXT_SEGMENT
|
||||
mov es,ax
|
||||
sub di,di
|
||||
mov al,'.' ;fill character
|
||||
mov ah,7 ;fill attribute
|
||||
mov cx,4000/2 ;length of one text screen in words
|
||||
rep stosw
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
mov dx,offset TStrikeAnyKeyMsg
|
||||
mov ah,9
|
||||
int 21h
|
||||
;
|
||||
; Wait for a key.
|
||||
;
|
||||
mov ah,01h
|
||||
int 21h
|
||||
;
|
||||
; Restore the text mode screen to the state it was in on entering
|
||||
; text mode.
|
||||
;
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
mov ax,TEXT_SEGMENT
|
||||
mov es,ax
|
||||
mov si,offset CharAttSave
|
||||
sub di,di
|
||||
mov cx,4000/2 ;length of one text screen in words
|
||||
rep movsw
|
||||
;
|
||||
; Return to mode 10h without clearing display memory.
|
||||
;
|
||||
mov ax,90h
|
||||
int 10h
|
||||
;
|
||||
; Restore the portion of plane 2 that was wiped out by the font.
|
||||
;
|
||||
mov dx,SC_INDEX
|
||||
mov al,MAP_MASK
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,4
|
||||
out dx,al ;set up to write to plane 2
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
mov ax,GRAPHICS_SEGMENT
|
||||
mov es,ax
|
||||
mov si,offset Plane2Save
|
||||
sub di,di
|
||||
mov cx,2000h/2 ;restore 8K (length of default font)
|
||||
rep movsw
|
||||
;
|
||||
; Put up "strike any key" message.
|
||||
;
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
mov dx,offset GStrikeAnyKeyMsg1
|
||||
mov ah,9
|
||||
int 21h
|
||||
;
|
||||
; Wait for a key before returning to text mode and ending.
|
||||
;
|
||||
mov ah,01h
|
||||
int 21h
|
||||
mov ax,03h
|
||||
int 10h
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
Start endp
|
||||
Code ends
|
||||
end Start
|
||||
235
tests/pcx86/vga/L28-1.ASM
Normal file
235
tests/pcx86/vga/L28-1.ASM
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
; Program to illustrate the use of the Read Map register in read mode 0.
|
||||
; Animates by copying a 16-color image from VGA memory to system memory,
|
||||
; one plane at a time, then copying the image back to a new location
|
||||
; in VGA memory.
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
stack segment word stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
data segment word 'DATA'
|
||||
IMAGE_WIDTH EQU 4 ;in bytes
|
||||
IMAGE_HEIGHT EQU 32 ;in pixels
|
||||
LEFT_BOUND EQU 10 ;in bytes
|
||||
RIGHT_BOUND EQU 66 ;in bytes
|
||||
VGA_SEGMENT EQU 0a000h
|
||||
SCREEN_WIDTH EQU 80 ;in bytes
|
||||
SC_INDEX EQU 3c4h ;Sequence Controller Index register
|
||||
GC_INDEX EQU 3ceh ;Graphics Controller Index register
|
||||
MAP_MASK EQU 2 ;Map Mask register index in SC
|
||||
READ_MAP EQU 4 ;Read Map register index in GC
|
||||
;
|
||||
; Base pattern for 16-color image.
|
||||
;
|
||||
PatternPlane0 label byte
|
||||
db 32 dup (0ffh,0ffh,0,0)
|
||||
PatternPlane1 label byte
|
||||
db 32 dup (0ffh,0,0ffh,0)
|
||||
PatternPlane2 label byte
|
||||
db 32 dup (0f0h,0f0h,0f0h,0f0h)
|
||||
PatternPlane3 label byte
|
||||
db 32 dup (0cch,0cch,0cch,0cch)
|
||||
;
|
||||
; Temporary storage for 16-color image during animation.
|
||||
;
|
||||
ImagePlane0 db 32*4 dup (?)
|
||||
ImagePlane1 db 32*4 dup (?)
|
||||
ImagePlane2 db 32*4 dup (?)
|
||||
ImagePlane3 db 32*4 dup (?)
|
||||
;
|
||||
; Current image location & direction.
|
||||
;
|
||||
ImageX dw 40 ;in bytes
|
||||
ImageY dw 100 ;in pixels
|
||||
ImageXDirection dw 1 ;in bytes
|
||||
data ends
|
||||
;
|
||||
code segment word 'CODE'
|
||||
assume cs:code,ds:data
|
||||
Start proc near
|
||||
cld
|
||||
mov ax,data
|
||||
mov ds,ax
|
||||
;
|
||||
; Select graphics mode 10h.
|
||||
;
|
||||
mov ax,10h
|
||||
int 10h
|
||||
;
|
||||
; Draw the initial image.
|
||||
;
|
||||
mov si,offset PatternPlane0
|
||||
call DrawImage
|
||||
;
|
||||
; Loop to animate by copying the image from VGA memory to system memory,
|
||||
; erasing the image, and copying the image from system memory to a new
|
||||
; location in VGA memory. Ends when a key is hit.
|
||||
;
|
||||
AnimateLoop:
|
||||
;
|
||||
; Copy the image from VGA memory to system memory.
|
||||
;
|
||||
mov di,offset ImagePlane0
|
||||
call GetImage
|
||||
;
|
||||
; Clear the image from VGA memory.
|
||||
;
|
||||
call EraseImage
|
||||
;
|
||||
; Advance the image X coordinate, reversing direction if either edge
|
||||
; of the screen has been reached.
|
||||
;
|
||||
mov ax,[ImageX]
|
||||
cmp ax,LEFT_BOUND
|
||||
jz ReverseDirection
|
||||
cmp ax,RIGHT_BOUND
|
||||
jnz SetNewX
|
||||
ReverseDirection:
|
||||
neg [ImageXDirection]
|
||||
SetNewX:
|
||||
add ax,[ImageXDirection]
|
||||
mov [ImageX],ax
|
||||
;
|
||||
; Draw the image by copying it from system memory to VGA memory.
|
||||
;
|
||||
mov si,offset ImagePlane0
|
||||
call DrawImage
|
||||
;
|
||||
; Slow things down a bit for visibility (adjust as needed).
|
||||
;
|
||||
mov cx,0
|
||||
DelayLoop:
|
||||
loop DelayLoop
|
||||
;
|
||||
; See if a key has been hit, ending the program.
|
||||
;
|
||||
mov ah,1
|
||||
int 16h
|
||||
jz AnimateLoop
|
||||
;
|
||||
; Clear the key, return to text mode, and return to DOS.
|
||||
;
|
||||
sub ah,ah
|
||||
int 16h
|
||||
mov ax,3
|
||||
int 10h
|
||||
mov ah,4ch
|
||||
int 21h
|
||||
Start endp
|
||||
;
|
||||
; Draws the image at offset DS:SI to the current image location in
|
||||
; VGA memory.
|
||||
;
|
||||
DrawImage proc near
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax
|
||||
call GetImageOffset ;ES:DI is the destination address for the
|
||||
; image in VGA memory
|
||||
mov dx,SC_INDEX
|
||||
mov al,1 ;do plane 0 first
|
||||
DrawImagePlaneLoop:
|
||||
push di ;image is drawn at the same offset in
|
||||
; each plane
|
||||
push ax ;preserve plane select
|
||||
mov al,MAP_MASK ;Map Mask index
|
||||
out dx,al ;point SC Index to the Map Mask register
|
||||
pop ax ;get back plane select
|
||||
inc dx ;point to SC index register
|
||||
out dx,al ;set up the Map Mask to allow writes to
|
||||
; the plane of interest
|
||||
dec dx ;point back to SC Data register
|
||||
mov bx,IMAGE_HEIGHT ;# of scan lines in image
|
||||
DrawImageLoop:
|
||||
mov cx,IMAGE_WIDTH ;# of bytes across image
|
||||
rep movsb
|
||||
add di,SCREEN_WIDTH-IMAGE_WIDTH
|
||||
;point to next scan line of image
|
||||
dec bx ;any more scan lines?
|
||||
jnz DrawImageLoop
|
||||
pop di ;get back image start offset in VGA memory
|
||||
shl al,1 ;Map Mask setting for next plane
|
||||
cmp al,10h ;have we done all four planes?
|
||||
jnz DrawImagePlaneLoop
|
||||
ret
|
||||
DrawImage endp
|
||||
;
|
||||
; Copies the image from its current location in VGA memory into the
|
||||
; buffer at DS:DI.
|
||||
;
|
||||
GetImage proc near
|
||||
mov si,di ;move destination offset into SI
|
||||
call GetImageOffset ;DI is offset of image in VGA memory
|
||||
xchg si,di ;SI is offset of image, DI is destination offset
|
||||
push ds
|
||||
pop es ;ES:DI is destination
|
||||
mov ax,VGA_SEGMENT
|
||||
mov ds,ax ;DS:SI is source
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
sub al,al ;do plane 0 first
|
||||
GetImagePlaneLoop:
|
||||
push si ;image comes from same offset in each plane
|
||||
push ax ;preserve plane select
|
||||
mov al,READ_MAP ;Read Map index
|
||||
out dx,al ;point GC Index to Read Map register
|
||||
pop ax ;get back plane select
|
||||
inc dx ;point to GC Index register
|
||||
out dx,al ;set up the Read Map to select reads from
|
||||
; the plane of interest
|
||||
dec dx ;point back to GC data register
|
||||
mov bx,IMAGE_HEIGHT ;# of scan lines in image
|
||||
GetImageLoop:
|
||||
mov cx,IMAGE_WIDTH ;# of bytes across image
|
||||
rep movsb
|
||||
add si,SCREEN_WIDTH-IMAGE_WIDTH
|
||||
;point to next scan line of image
|
||||
dec bx ;any more scan lines?
|
||||
jnz GetImageLoop
|
||||
pop si ;get back image start offset
|
||||
inc al ;Read Map setting for next plane
|
||||
cmp al,4 ;have we done all four planes?
|
||||
jnz GetImagePlaneLoop
|
||||
push es
|
||||
pop ds ;restore original DS
|
||||
ret
|
||||
GetImage endp
|
||||
;
|
||||
; Erases the image at its current location.
|
||||
;
|
||||
EraseImage proc near
|
||||
mov dx,SC_INDEX
|
||||
mov al,MAP_MASK
|
||||
out dx,al ;point SC Index to the Map Mask register
|
||||
inc dx ;point to SC Data register
|
||||
mov al,0fh
|
||||
out dx,al ;set up the Map Mask to allow writes to go to
|
||||
; all 4 planes
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax
|
||||
call GetImageOffset ;ES:DI points to the start address
|
||||
; of the image
|
||||
sub al,al ;erase with zeros
|
||||
mov bx,IMAGE_HEIGHT ;# of scan lines in image
|
||||
EraseImageLoop:
|
||||
mov cx,IMAGE_WIDTH ;# of bytes across image
|
||||
rep stosb
|
||||
add di,SCREEN_WIDTH-IMAGE_WIDTH
|
||||
;point to next scan line of image
|
||||
dec bx ;any more scan lines?
|
||||
jnz EraseImageLoop
|
||||
ret
|
||||
EraseImage endp
|
||||
;
|
||||
; Returns the current offset of the image in the VGA segment in DI.
|
||||
;
|
||||
GetImageOffset proc near
|
||||
mov ax,SCREEN_WIDTH
|
||||
mul [ImageY]
|
||||
add ax,[ImageX]
|
||||
mov di,ax
|
||||
ret
|
||||
GetImageOffset endp
|
||||
code ends
|
||||
end Start
|
||||
161
tests/pcx86/vga/L28-2.ASM
Normal file
161
tests/pcx86/vga/L28-2.ASM
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
; Program to illustrate use of read mode 1 (color compare mode)
|
||||
; to detect collisions in display memory. Draws a yellow line on a
|
||||
; blue background, then draws a perpendicular green line until the
|
||||
; yellow line is reached.
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
stack segment word stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
VGA_SEGMENT EQU 0a000h
|
||||
SCREEN_WIDTH EQU 80 ;in bytes
|
||||
GC_INDEX EQU 3ceh ;Graphics Controller Index register
|
||||
SET_RESET EQU 0 ;Set/Reset register index in GC
|
||||
ENABLE_SET_RESET EQU 1 ;Enable Set/Reset register index in GC
|
||||
COLOR_COMPARE EQU 2 ;Color Compare register index in GC
|
||||
GRAPHICS_MODE EQU 5 ;Graphics Mode register index in GC
|
||||
BIT_MASK EQU 8 ;Bit Mask register index in GC
|
||||
;
|
||||
code segment word 'CODE'
|
||||
assume cs:code
|
||||
Start proc near
|
||||
cld
|
||||
;
|
||||
; Select graphics mode 10h.
|
||||
;
|
||||
mov ax,10h
|
||||
int 10h
|
||||
;
|
||||
; Fill the screen with blue.
|
||||
;
|
||||
mov al,1 ;blue is color 1
|
||||
call SelectSetResetColor ;set to draw in blue
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax
|
||||
sub di,di
|
||||
mov cx,7000h
|
||||
rep stosb ;the value written actually doesn't
|
||||
; matter, since set/reset is providing
|
||||
; the data written to display memory
|
||||
;
|
||||
; Draw a vertical yellow line.
|
||||
;
|
||||
mov al,14 ;yellow is color 14
|
||||
call SelectSetResetColor ;set to draw in yellow
|
||||
mov dx,GC_INDEX
|
||||
mov al,BIT_MASK
|
||||
out dx,al ;point GC Index to Bit Mask
|
||||
inc dx ;point to GC Data
|
||||
mov al,10h
|
||||
out dx,al ;set Bit Mask to 10h
|
||||
mov di,40 ;start in the middle of the top line
|
||||
mov cx,350 ;do full height of screen
|
||||
VLineLoop:
|
||||
mov al,es:[di] ;load the latches
|
||||
stosb ;write next pixel of yellow line (set/reset
|
||||
; provides the data written to display
|
||||
; memory, and AL is actually ignored)
|
||||
add di,SCREEN_WIDTH-1 ;point to the next scan line
|
||||
loop VLineLoop
|
||||
;
|
||||
; Select write mode 0 and read mode 1.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GRAPHICS_MODE
|
||||
out dx,al ;point GC Index to Graphics Mode register
|
||||
inc dx ;point to GC Data
|
||||
mov al,00001000b ;bit 3=1 is read mode 1, bits 1 & 0=00
|
||||
; is write mode 0
|
||||
out dx,al ;set Graphics Mode to read mode 1,
|
||||
; write mode 0
|
||||
;
|
||||
; Draw a horizontal green line, one pixel at a time, from left
|
||||
; to right until color compare reports a yellow pixel is encountered.
|
||||
;
|
||||
; Draw in green.
|
||||
;
|
||||
mov al,2 ;green is color 2
|
||||
call SelectSetResetColor ;set to draw in green
|
||||
;
|
||||
; Set color compare to look for yellow.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,COLOR_COMPARE
|
||||
out dx,al ;point GC Index to Color Compare register
|
||||
inc dx ;point to GC Data
|
||||
mov al,14 ;we're looking for yellow, color 14
|
||||
out dx,al ;set color compare to look for yellow
|
||||
dec dx ;point to GC Index
|
||||
;
|
||||
; Set up for quick access to Bit Mask register.
|
||||
;
|
||||
mov al,BIT_MASK
|
||||
out dx,al ;point GC Index to Bit Mask register
|
||||
inc dx ;point to GC Data
|
||||
;
|
||||
; Set initial pixel mask and display memory offset.
|
||||
;
|
||||
mov al,80h ;initial pixel mask
|
||||
mov di,100*SCREEN_WIDTH
|
||||
;start at left edge of scan line 100
|
||||
HLineLoop:
|
||||
mov ah,es:[di] ;do a read mode 1 (color compare) read.
|
||||
; This also loads the latches.
|
||||
and ah,al ;is the pixel of current interest yellow?
|
||||
jnz WaitKeyAndDone ;yes-we've reached the yellow line, so we're
|
||||
; done
|
||||
out dx,al ;set the Bit Mask register so that we
|
||||
; modify only the pixel of interest
|
||||
mov es:[di],al ;draw the pixel. The value written is
|
||||
; irrelevant, since set/reset is providing
|
||||
; the data written to display memory
|
||||
ror al,1 ;shift pixel mask to the next pixel
|
||||
adc di,0 ;advance the display memory offset if
|
||||
; the pixel mask wrapped
|
||||
;
|
||||
; Slow things down a bit for visibility (adjust as needed).
|
||||
;
|
||||
mov cx,0
|
||||
DelayLoop:
|
||||
loop DelayLoop
|
||||
jmp HLineLoop
|
||||
;
|
||||
; Wait for a key to be pressed to end, then return to text mode and
|
||||
; return to DOS.
|
||||
;
|
||||
WaitKeyAndDone:
|
||||
WaitKeyLoop:
|
||||
mov ah,1
|
||||
int 16h
|
||||
jz WaitKeyLoop
|
||||
sub ah,ah
|
||||
int 16h ;clear the key
|
||||
mov ax,3
|
||||
int 10h ;return to text mode
|
||||
mov ah,4ch
|
||||
int 21h ;done
|
||||
Start endp
|
||||
;
|
||||
; Enables set/reset for all planes, and sets the set/reset color
|
||||
; to AL.
|
||||
;
|
||||
SelectSetResetColor proc near
|
||||
mov dx,GC_INDEX
|
||||
push ax ;preserve color
|
||||
mov al,SET_RESET
|
||||
out dx,al ;point GC Index to Set/Reset register
|
||||
inc dx ;point to GC Data
|
||||
pop ax ;get back color
|
||||
out dx,al ;set Set/Reset register to selected color
|
||||
dec dx ;point to GC Index
|
||||
mov al,ENABLE_SET_RESET
|
||||
out dx,al ;point GC Index to Enable Set/Reset register
|
||||
inc dx ;point to GC Data
|
||||
mov al,0fh
|
||||
out dx,al ;enable set/reset for all planes
|
||||
ret
|
||||
SelectSetResetColor endp
|
||||
code ends
|
||||
end Start
|
||||
103
tests/pcx86/vga/L28-3.ASM
Normal file
103
tests/pcx86/vga/L28-3.ASM
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
; Program that draws a diagonal line to illustrate the use of a
|
||||
; Color Don't Care register setting of 0FFH to support fast
|
||||
; read-modify-write operations to VGA memory in write mode 3 by
|
||||
; drawing a diagonal line.
|
||||
;
|
||||
; Note: Works on VGAs only.
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
stack segment word stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
VGA_SEGMENT EQU 0a000h
|
||||
SCREEN_WIDTH EQU 80 ;in bytes
|
||||
GC_INDEX EQU 3ceh ;Graphics Controller Index register
|
||||
SET_RESET EQU 0 ;Set/Reset register index in GC
|
||||
ENABLE_SET_RESET EQU 1 ;Enable Set/Reset register index in GC
|
||||
GRAPHICS_MODE EQU 5 ;Graphics Mode register index in GC
|
||||
COLOR_DONT_CARE EQU 7 ;Color Don't Care register index in GC
|
||||
;
|
||||
code segment word 'CODE'
|
||||
assume cs:code
|
||||
Start proc near
|
||||
;
|
||||
; Select graphics mode 12h.
|
||||
;
|
||||
mov ax,12h
|
||||
int 10h
|
||||
;
|
||||
; Select write mode 3 and read mode 1.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,GRAPHICS_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx ;VGA registers are readable, bless them!
|
||||
or al,00001011b ;bit 3=1 selects read mode 1, and
|
||||
; bits 1 & 0=11 selects write mode 3
|
||||
jmp $+2 ;delay between IN and OUT to same port
|
||||
out dx,al
|
||||
dec dx
|
||||
;
|
||||
; Set up set/reset to always draw in white.
|
||||
;
|
||||
mov al,SET_RESET
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,0fh
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,ENABLE_SET_RESET
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,0fh
|
||||
out dx,al
|
||||
dec dx
|
||||
;
|
||||
; Set Color Don't Care to 0, so reads of VGA memory always return 0FFH.
|
||||
;
|
||||
mov al,COLOR_DONT_CARE
|
||||
out dx,al
|
||||
inc dx
|
||||
sub al,al
|
||||
out dx,al
|
||||
;
|
||||
; Set up the initial memory pointer and pixel mask.
|
||||
;
|
||||
mov ax,VGA_SEGMENT
|
||||
mov ds,ax
|
||||
sub bx,bx
|
||||
mov al,80h
|
||||
;
|
||||
; Draw 400 points on a diagonal line sloping down and to the right.
|
||||
;
|
||||
mov cx,400
|
||||
DrawDiagonalLoop:
|
||||
and [bx],al ;reads display memory, loading the latches,
|
||||
; then writes AL to the VGA. AL becomes the
|
||||
; bit mask, and set/reset provides the
|
||||
; actual data written
|
||||
add bx,SCREEN_WIDTH
|
||||
; point to the next scan line
|
||||
ror al,1 ;move the pixel mask one pixel to the right
|
||||
adc bx,0 ;advance to the next byte if the pixel mask wrapped
|
||||
loop DrawDiagonalLoop
|
||||
;
|
||||
; Wait for a key to be pressed to end, then return to text mode and
|
||||
; return to DOS.
|
||||
;
|
||||
WaitKeyLoop:
|
||||
mov ah,1
|
||||
int 16h
|
||||
jz WaitKeyLoop
|
||||
sub ah,ah
|
||||
int 16h ;clear the key
|
||||
mov ax,3
|
||||
int 10h ;return to text mode
|
||||
mov ah,4ch
|
||||
int 21h ;done
|
||||
Start endp
|
||||
code ends
|
||||
end Start
|
||||
128
tests/pcx86/vga/L29-1.ASM
Normal file
128
tests/pcx86/vga/L29-1.ASM
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
; Program to put up a mode 10h EGA graphics screen, then save it
|
||||
; to the file SNAPSHOT.SCR.
|
||||
;
|
||||
VGA_SEGMENT equ 0a000h
|
||||
GC_INDEX equ 3ceh ;Graphics Controller Index register
|
||||
READ_MAP equ 4 ;Read Map register index in GC
|
||||
DISPLAYED_SCREEN_SIZE equ (640/8)*350 ;# of displayed bytes per plane in a
|
||||
; hi-res graphics screen
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
Data segment word 'DATA'
|
||||
SampleText db 'This is bit-mapped text, drawn in hi-res '
|
||||
db 'EGA graphics mode 10h.', 0dh, 0ah, 0ah
|
||||
db 'Saving the screen (including this text)...'
|
||||
db 0dh, 0ah, '$'
|
||||
Filename db 'SNAPSHOT.SCR',0;name of file we're saving to
|
||||
ErrMsg1 db "*** Couldn't open SNAPSHOT.SCR ***",0dh,0ah,'$'
|
||||
ErrMsg2 db '*** Error writing to SNAPSHOT.SCR ***',0dh,0ah,'$'
|
||||
WaitKeyMsg db 0dh, 0ah, 'Done. Press any key to end...',0dh,0ah,'$'
|
||||
Handle dw ? ;handle of file we're saving to
|
||||
Plane db ? ;plane being read
|
||||
Data ends
|
||||
;
|
||||
Code segment
|
||||
assume cs:Code, ds:Data
|
||||
Start proc near
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
;
|
||||
; Go to hi-res graphics mode.
|
||||
;
|
||||
mov ax,10h ;AH = 0 means mode set, AL = 10h selects
|
||||
; hi-res graphics mode
|
||||
int 10h ;BIOS video interrupt
|
||||
;
|
||||
; Put up some text, so the screen isn't empty.
|
||||
;
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset SampleText
|
||||
int 21h
|
||||
;
|
||||
; Delete SNAPSHOT.SCR if it exists.
|
||||
;
|
||||
mov ah,41h ;DOS unlink file function
|
||||
mov dx,offset Filename
|
||||
int 21h
|
||||
;
|
||||
; Create the file SNAPSHOT.SCR.
|
||||
;
|
||||
mov ah,3ch ;DOS create file function
|
||||
mov dx,offset Filename
|
||||
sub cx,cx ;make it a normal file
|
||||
int 21h
|
||||
mov [Handle],ax ;save the handle
|
||||
jnc SaveTheScreen ;we're ready to save if no error
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset ErrMsg1
|
||||
int 21h ;notify of the error
|
||||
jmp short Done ;and done
|
||||
;
|
||||
; Loop through the 4 planes, making each readable in turn and
|
||||
; writing it to disk. Note that all 4 planes are readable at
|
||||
; A000:0000; the Read Map register selects which plane is readable
|
||||
; at any one time.
|
||||
;
|
||||
SaveTheScreen:
|
||||
mov [Plane],0 ;start with plane 0
|
||||
SaveLoop:
|
||||
mov dx,GC_INDEX
|
||||
mov al,READ_MAP ;set GC Index to Read Map register
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,[Plane] ;get the # of the plane we want
|
||||
; to save
|
||||
out dx,al ;set to read from the desired plane
|
||||
mov ah,40h ;DOS write to file function
|
||||
mov bx,[Handle]
|
||||
mov cx,DISPLAYED_SCREEN_SIZE;# of bytes to save
|
||||
sub dx,dx ;write all displayed bytes at A000:0000
|
||||
push ds
|
||||
mov si,VGA_SEGMENT
|
||||
mov ds,si
|
||||
int 21h ;write the displayed portion of this plane
|
||||
pop ds
|
||||
cmp ax,DISPLAYED_SCREEN_SIZE;did all bytes get written?
|
||||
jz SaveLoopBottom
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset ErrMsg2
|
||||
int 21h ;notify about the error
|
||||
jmp short DoClose ;and done
|
||||
SaveLoopBottom:
|
||||
mov al,[Plane]
|
||||
inc ax ;point to the next plane
|
||||
mov [Plane],al
|
||||
cmp al,3 ;have we done all planes?
|
||||
jbe SaveLoop ;no, so do the next plane
|
||||
;
|
||||
; Close SNAPSHOT.SCR.
|
||||
;
|
||||
DoClose:
|
||||
mov ah,3eh ;DOS close file function
|
||||
mov bx,[Handle]
|
||||
int 21h
|
||||
;
|
||||
; Wait for a keypress.
|
||||
;
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset WaitKeyMsg
|
||||
int 21h ;prompt
|
||||
mov ah,8 ;DOS input without echo function
|
||||
int 21h
|
||||
;
|
||||
; Restore text mode.
|
||||
;
|
||||
mov ax,3
|
||||
int 10h
|
||||
;
|
||||
; Done.
|
||||
;
|
||||
Done:
|
||||
mov ah,4ch ;DOS terminate function
|
||||
int 21h
|
||||
Start endp
|
||||
Code ends
|
||||
end Start
|
||||
114
tests/pcx86/vga/L29-2.ASM
Normal file
114
tests/pcx86/vga/L29-2.ASM
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
; Program to restore a mode 10h EGA graphics screen from
|
||||
; the file SNAPSHOT.SCR.
|
||||
;
|
||||
VGA_SEGMENT equ 0a000h
|
||||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||||
MAP_MASK equ 2 ;Map Mask register index in SC
|
||||
DISPLAYED_SCREEN_SIZE equ (640/8)*350 ;# of displayed bytes per plane in a
|
||||
; hi-res graphics screen
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
Data segment word 'DATA'
|
||||
Filename db 'SNAPSHOT.SCR',0;name of file we're restoring from
|
||||
ErrMsg1 db "*** Couldn't open SNAPSHOT.SCR ***",0dh,0ah,'$'
|
||||
ErrMsg2 db '*** Error reading from SNAPSHOT.SCR ***',0dh,0ah,'$'
|
||||
WaitKeyMsg db 0dh, 0ah, 'Done. Press any key to end...',0dh,0ah,'$'
|
||||
Handle dw ? ;handle of file we're restoring from
|
||||
Plane db ? ;plane being written
|
||||
Data ends
|
||||
;
|
||||
Code segment
|
||||
assume cs:Code, ds:Data
|
||||
Start proc near
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
;
|
||||
; Go to hi-res graphics mode.
|
||||
;
|
||||
mov ax,10h ;AH = 0 means mode set, AL = 10h selects
|
||||
; hi-res graphics mode
|
||||
int 10h ;BIOS video interrupt
|
||||
;
|
||||
; Open SNAPSHOT.SCR.
|
||||
;
|
||||
mov ah,3dh ;DOS open file function
|
||||
mov dx,offset Filename
|
||||
sub al,al ;open for reading
|
||||
int 21h
|
||||
mov [Handle],ax ;save the handle
|
||||
jnc RestoreTheScreen ;we're ready to restore if no error
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset ErrMsg1
|
||||
int 21h ;notify of the error
|
||||
jmp short Done ;and done
|
||||
;
|
||||
; Loop through the 4 planes, making each writable in turn and
|
||||
; reading it from disk. Note that all 4 planes are writable at
|
||||
; A000:0000; the Map Mask register selects which planes are readable
|
||||
; at any one time. We only make one plane readable at a time.
|
||||
;
|
||||
RestoreTheScreen:
|
||||
mov [Plane],0 ;start with plane 0
|
||||
RestoreLoop:
|
||||
mov dx,SC_INDEX
|
||||
mov al,MAP_MASK ;set SC Index to Map Mask register
|
||||
out dx,al
|
||||
inc dx
|
||||
mov cl,[Plane] ;get the # of the plane we want
|
||||
; to restore
|
||||
mov al,1
|
||||
shl al,cl ;set the bit enabling writes to
|
||||
; only the one desired plane
|
||||
out dx,al ;set to read from desired plane
|
||||
mov ah,3fh ;DOS read from file function
|
||||
mov bx,[Handle]
|
||||
mov cx,DISPLAYED_SCREEN_SIZE;# of bytes to read
|
||||
sub dx,dx ;start loading bytes at A000:0000
|
||||
push ds
|
||||
mov si,VGA_SEGMENT
|
||||
mov ds,si
|
||||
int 21h ;read the displayed portion of this plane
|
||||
pop ds
|
||||
jc ReadError
|
||||
cmp ax,DISPLAYED_SCREEN_SIZE;did all bytes get read?
|
||||
jz RestoreLoopBottom
|
||||
ReadError:
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset ErrMsg2
|
||||
int 21h ;notify about the error
|
||||
jmp short DoClose ;and done
|
||||
RestoreLoopBottom:
|
||||
mov al,[Plane]
|
||||
inc ax ;point to the next plane
|
||||
mov [Plane],al
|
||||
cmp al,3 ;have we done all planes?
|
||||
jbe RestoreLoop ;no, so do the next plane
|
||||
;
|
||||
; Close SNAPSHOT.SCR.
|
||||
;
|
||||
DoClose:
|
||||
mov ah,3eh ;DOS close file function
|
||||
mov bx,[Handle]
|
||||
int 21h
|
||||
;
|
||||
; Wait for a keypress.
|
||||
;
|
||||
mov ah,8 ;DOS input without echo function
|
||||
int 21h
|
||||
;
|
||||
; Restore text mode.
|
||||
;
|
||||
mov ax,3
|
||||
int 10h
|
||||
;
|
||||
; Done.
|
||||
;
|
||||
Done:
|
||||
mov ah,4ch ;DOS terminate function
|
||||
int 21h
|
||||
Start endp
|
||||
Code ends
|
||||
end Start
|
||||
251
tests/pcx86/vga/L29-3.ASM
Normal file
251
tests/pcx86/vga/L29-3.ASM
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
; Program to illustrate the color mapping capabilities of the
|
||||
; EGA's palette registers.
|
||||
;
|
||||
VGA_SEGMENT equ 0a000h
|
||||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||||
MAP_MASK equ 2 ;Map Mask register index in SC
|
||||
BAR_HEIGHT equ 14 ;height of each bar
|
||||
TOP_BAR equ BAR_HEIGHT*6 ;start the bars down a bit to
|
||||
; leave room for text
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
Data segment word 'DATA'
|
||||
KeyMsg db 'Press any key to see the next color set. '
|
||||
db 'There are 64 color sets in all.'
|
||||
db 0dh, 0ah, 0ah, 0ah, 0ah
|
||||
db 13 dup (' '), 'Attribute'
|
||||
db 38 dup (' '), 'Color$'
|
||||
;
|
||||
; Used to label the attributes of the color bars.
|
||||
;
|
||||
AttributeNumbers label byte
|
||||
x= 0
|
||||
rept 16
|
||||
if x lt 10
|
||||
db '0', x+'0', 'h', 0ah, 8, 8, 8
|
||||
else
|
||||
db '0', x+'A'-10, 'h', 0ah, 8, 8, 8
|
||||
endif
|
||||
x= x+1
|
||||
endm
|
||||
db '$'
|
||||
;
|
||||
; Used to label the colors of the color bars. (Color values are
|
||||
; filled in on the fly.)
|
||||
;
|
||||
ColorNumbers label byte
|
||||
rept 16
|
||||
db '000h', 0ah, 8, 8, 8, 8
|
||||
endm
|
||||
COLOR_ENTRY_LENGTH equ ($-ColorNumbers)/16
|
||||
db '$'
|
||||
;
|
||||
CurrentColor db ?
|
||||
;
|
||||
; Space for the array of 16 colors we'll pass to the BIOS, plus
|
||||
; an overscan setting of black.
|
||||
;
|
||||
ColorTable db 16 dup (?), 0
|
||||
Data ends
|
||||
;
|
||||
Code segment
|
||||
assume cs:Code, ds:Data
|
||||
Start proc near
|
||||
cld
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
;
|
||||
; Go to hi-res graphics mode.
|
||||
;
|
||||
mov ax,10h ;AH = 0 means mode set, AL = 10h selects
|
||||
; hi-res graphics mode
|
||||
int 10h ;BIOS video interrupt
|
||||
;
|
||||
; Put up relevant text.
|
||||
;
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset KeyMsg
|
||||
int 21h
|
||||
;
|
||||
; Put up the color bars, one in each of the 16 possible pixel values
|
||||
; (which we'll call attributes).
|
||||
;
|
||||
mov cx,16 ;we'll put up 16 color bars
|
||||
sub al,al ;start with attribute 0
|
||||
BarLoop:
|
||||
push ax
|
||||
push cx
|
||||
call BarUp
|
||||
pop cx
|
||||
pop ax
|
||||
inc ax ;select the next attribute
|
||||
loop BarLoop
|
||||
;
|
||||
; Put up the attribute labels.
|
||||
;
|
||||
mov ah,2 ;video interrupt set cursor position function
|
||||
sub bh,bh ;page 0
|
||||
mov dh,TOP_BAR/14 ;counting in character rows, match to
|
||||
; top of first bar, counting in
|
||||
; scan lines
|
||||
mov dl,16 ;just to left of bars
|
||||
int 10h
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset AttributeNumbers
|
||||
int 21h
|
||||
;
|
||||
; Loop through the color set, one new setting per keypress.
|
||||
;
|
||||
mov [CurrentColor],0 ;start with color zero
|
||||
ColorLoop:
|
||||
;
|
||||
; Set the palette registers to the current color set, consisting
|
||||
; of the current color mapped to attribute 0, current color + 1
|
||||
; mapped to attribute 1, and so on.
|
||||
;
|
||||
mov al,[CurrentColor]
|
||||
mov bx,offset ColorTable
|
||||
mov cx,16 ;we have 16 colors to set
|
||||
PaletteSetLoop:
|
||||
and al,3fh ;limit to 6-bit color values
|
||||
mov [bx],al ;built the 16-color table used for setting
|
||||
inc bx ; the palette registers
|
||||
inc ax
|
||||
loop PaletteSetLoop
|
||||
mov ah,10h ;video interrupt palette function
|
||||
mov al,2 ;subfunction to set all 16 palette registers
|
||||
; and overscan at once
|
||||
mov dx,offset ColorTable
|
||||
push ds
|
||||
pop es ;ES:DX points to the color table
|
||||
int 10h ;invoke the video interrupt to set the palette
|
||||
;
|
||||
; Put up the color numbers, so we can see how attributes map
|
||||
; to color values, and so we can see how each color # looks
|
||||
; (at least on this particular screen).
|
||||
;
|
||||
call ColorNumbersUp
|
||||
;
|
||||
; Wait for a keypress, so they can see this color set.
|
||||
;
|
||||
WaitKey:
|
||||
mov ah,8 ;DOS input without echo function
|
||||
int 21h
|
||||
;
|
||||
; Advance to the next color set.
|
||||
;
|
||||
mov al,[CurrentColor]
|
||||
inc ax
|
||||
mov [CurrentColor],al
|
||||
cmp al,64
|
||||
jbe ColorLoop
|
||||
;
|
||||
; Restore text mode.
|
||||
;
|
||||
mov ax,3
|
||||
int 10h
|
||||
;
|
||||
; Done.
|
||||
;
|
||||
Done:
|
||||
mov ah,4ch ;DOS terminate function
|
||||
int 21h
|
||||
;
|
||||
; Puts up a bar consisting of the specified attribute (pixel value),
|
||||
; at a vertical position corresponding to the attribute.
|
||||
;
|
||||
; Input: AL = attribute
|
||||
;
|
||||
BarUp proc near
|
||||
mov dx,SC_INDEX
|
||||
mov ah,al
|
||||
mov al,MAP_MASK
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,ah
|
||||
out dx,al ;set the Map Mask register to produce
|
||||
; the desired color
|
||||
mov ah,BAR_HEIGHT
|
||||
mul ah ;row of top of bar
|
||||
add ax,TOP_BAR ;start a few lines down to leave room for
|
||||
; text
|
||||
mov dx,80 ;rows are 80 bytes long
|
||||
mul dx ;offset in bytes of start of scan line bar
|
||||
; starts on
|
||||
add ax,20 ;offset in bytes of upper left corner of bar
|
||||
mov di,ax
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax ;ES:DI points to offset of upper left
|
||||
; corner of bar
|
||||
mov dx,BAR_HEIGHT
|
||||
mov al,0ffh
|
||||
BarLineLoop:
|
||||
mov cx,40 ;make the bars 40 wide
|
||||
rep stosb ;do one scan line of the bar
|
||||
add di,40 ;point to the start of the next scan line
|
||||
; of the bar
|
||||
dec dx
|
||||
jnz BarLineLoop
|
||||
ret
|
||||
BarUp endp
|
||||
;
|
||||
; Converts AL to a hex digit in the range 0-F.
|
||||
;
|
||||
BinToHexDigit proc near
|
||||
cmp al,9
|
||||
ja IsHex
|
||||
add al,'0'
|
||||
ret
|
||||
IsHex:
|
||||
add al,'A'-10
|
||||
ret
|
||||
BinToHexDigit endp
|
||||
;
|
||||
; Displays the color values generated by the color bars given the
|
||||
; current palette register settings off to the right of the color
|
||||
; bars.
|
||||
;
|
||||
ColorNumbersUp proc near
|
||||
mov ah,2 ;video interrupt set cursor position function
|
||||
sub bh,bh ;page 0
|
||||
mov dh,TOP_BAR/14 ;counting in character rows, match to
|
||||
; top of first bar, counting in
|
||||
; scan lines
|
||||
mov dl,20+40+1 ;just to right of bars
|
||||
int 10h
|
||||
mov al,[CurrentColor] ;start with the current color
|
||||
mov bx,offset ColorNumbers+1
|
||||
;build the color number text string on the fly
|
||||
mov cx,16 ;we've got 16 colors to do
|
||||
ColorNumberLoop:
|
||||
push ax ;save the color #
|
||||
and al,3fh ;limit to 6-bit color values
|
||||
shr al,1
|
||||
shr al,1
|
||||
shr al,1
|
||||
shr al,1 ;isolate the high nibble of the
|
||||
; color #
|
||||
call BinToHexDigit ;convert the high color # nibble
|
||||
mov [bx],al ; and put it into the text
|
||||
pop ax ;get back the color #
|
||||
push ax ;save the color #
|
||||
and al,0fh ;isolate the low color # nibble
|
||||
call BinToHexDigit ;convert the low nibble of the
|
||||
; color # to ASCII
|
||||
mov [bx+1],al ; and put it into the text
|
||||
add bx,COLOR_ENTRY_LENGTH ;point to the next entry
|
||||
pop ax ;get back the color #
|
||||
inc ax ;next color #
|
||||
loop ColorNumberLoop
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset ColorNumbers
|
||||
int 21h ;put up the attribute numbers
|
||||
ret
|
||||
ColorNumbersUp endp
|
||||
;
|
||||
Start endp
|
||||
Code ends
|
||||
end Start
|
||||
81
tests/pcx86/vga/L29-4.ASM
Normal file
81
tests/pcx86/vga/L29-4.ASM
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
; Program to demonstrate screen blanking via bit 5 of the
|
||||
; Attribute Controller Index register.
|
||||
;
|
||||
AC_INDEX equ 3c0h ;Attribute Controller Index register
|
||||
INPUT_STATUS_1 equ 3dah ;color-mode address of the Input
|
||||
; Status 1 register
|
||||
;
|
||||
; Macro to wait for and clear the next keypress.
|
||||
;
|
||||
WAIT_KEY macro
|
||||
mov ah,8 ;DOS input without echo function
|
||||
int 21h
|
||||
endm
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
Data segment word 'DATA'
|
||||
SampleText db 'This is bit-mapped text, drawn in hi-res '
|
||||
db 'EGA graphics mode 10h.', 0dh, 0ah, 0ah
|
||||
db 'Press any key to blank the screen, then '
|
||||
db 'any key to unblank it,', 0dh, 0ah
|
||||
db 'then any key to end.$'
|
||||
Data ends
|
||||
;
|
||||
Code segment
|
||||
assume cs:Code, ds:Data
|
||||
Start proc near
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
;
|
||||
; Go to hi-res graphics mode.
|
||||
;
|
||||
mov ax,10h ;AH = 0 means mode set, AL = 10h selects
|
||||
; hi-res graphics mode
|
||||
int 10h ;BIOS video interrupt
|
||||
;
|
||||
; Put up some text, so the screen isn't empty.
|
||||
;
|
||||
mov ah,9 ;DOS print string function
|
||||
mov dx,offset SampleText
|
||||
int 21h
|
||||
;
|
||||
WAIT_KEY
|
||||
;
|
||||
; Blank the screen.
|
||||
;
|
||||
mov dx,INPUT_STATUS_1
|
||||
in al,dx ;reset port 3c0h to index (rather than data)
|
||||
; mode
|
||||
mov dx,AC_INDEX
|
||||
sub al,al ;make bit 5 zero...
|
||||
out dx,al ;...which blanks the screen
|
||||
;
|
||||
WAIT_KEY
|
||||
;
|
||||
; Unblank the screen.
|
||||
;
|
||||
mov dx,INPUT_STATUS_1
|
||||
in al,dx ;reset port 3c0h to Index (rather than data)
|
||||
; mode
|
||||
mov dx,AC_INDEX
|
||||
mov al,20h ;make bit 5 one...
|
||||
out dx,al ;...which unblanks the screen
|
||||
;
|
||||
WAIT_KEY
|
||||
;
|
||||
; Restore text mode.
|
||||
;
|
||||
mov ax,2
|
||||
int 10h
|
||||
;
|
||||
; Done.
|
||||
;
|
||||
Done:
|
||||
mov ah,4ch ;DOS terminate function
|
||||
int 21h
|
||||
Start endp
|
||||
Code ends
|
||||
end Start
|
||||
372
tests/pcx86/vga/L30-1.ASM
Normal file
372
tests/pcx86/vga/L30-1.ASM
Normal file
|
|
@ -0,0 +1,372 @@
|
|||
; Demonstrates the VGA/EGA split screen in action.
|
||||
;
|
||||
;*********************************************************************
|
||||
IS_VGA equ 1 ;set to 0 to assemble for EGA
|
||||
;
|
||||
VGA_SEGMENT equ 0a000h
|
||||
SCREEN_WIDTH equ 640
|
||||
SCREEN_HEIGHT equ 350
|
||||
CRTC_INDEX equ 3d4h ;CRT Controller Index register
|
||||
OVERFLOW equ 7 ;index of Overflow reg in CRTC
|
||||
MAXIMUM_SCAN_LINE equ 9 ;index of Maximum Scan Line register
|
||||
; in CRTC
|
||||
START_ADDRESS_HIGH equ 0ch ;index of Start Address High register
|
||||
; in CRTC
|
||||
START_ADDRESS_LOW equ 0dh ;index of Start Address Low register
|
||||
; in CRTC
|
||||
LINE_COMPARE equ 18h ;index of Line Compare reg (bits 7-0
|
||||
; of split screen start scan line)
|
||||
; in CRTC
|
||||
INPUT_STATUS_0 equ 3dah ;Input Status 0 register
|
||||
WORD_OUTS_OK equ 1 ;set to 0 to assemble for
|
||||
; computers that can't handle
|
||||
; word outs to indexed VGA registers
|
||||
;*********************************************************************
|
||||
; Macro to output a word value to a port.
|
||||
;
|
||||
OUT_WORD macro
|
||||
if WORD_OUTS_OK
|
||||
out dx,ax
|
||||
else
|
||||
out dx,al
|
||||
inc dx
|
||||
xchg ah,al
|
||||
out dx,al
|
||||
dec dx
|
||||
xchg ah,al
|
||||
endif
|
||||
endm
|
||||
;*********************************************************************
|
||||
MyStack segment para stack 'STACK'
|
||||
db 512 dup (0)
|
||||
MyStack ends
|
||||
;*********************************************************************
|
||||
Data segment
|
||||
SplitScreenLine dw ? ;line the split screen currently
|
||||
; starts after
|
||||
StartAddress dw ? ;display memory offset at which
|
||||
; scanning for video data starts
|
||||
; Message displayed in split screen.
|
||||
SplitScreenMsg db 'Split screen text row #'
|
||||
DigitInsert dw ?
|
||||
db '...$'
|
||||
Data ends
|
||||
;*********************************************************************
|
||||
Code segment
|
||||
assume cs:Code, ds:Data
|
||||
;*********************************************************************
|
||||
Start proc near
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
;
|
||||
; Select mode 10h, 640x350 16-color graphics mode.
|
||||
;
|
||||
mov ax,0010h ;AH=0 is select mode function
|
||||
;AL=10h is mode to select,
|
||||
; 640x350 16-color graphics mode
|
||||
int 10h
|
||||
;
|
||||
; Put text into display memory starting at offset 0, with each row
|
||||
; labelled as to number. This is the part of memory that will be
|
||||
; displayed in the split screen portion of the display.
|
||||
;
|
||||
mov cx,25 ;# of lines of text we'll draw into
|
||||
; the split screen part of memory
|
||||
FillSplitScreenLoop:
|
||||
mov ah,2 ;set cursor location function #
|
||||
sub bh,bh ;set cursor in page 0
|
||||
mov dh,25
|
||||
sub dh,cl ;calculate row to draw in
|
||||
sub dl,dl ;start in column 0
|
||||
int 10h ;set the cursor location
|
||||
mov al,25
|
||||
sub al,cl ;calculate row to draw in again
|
||||
sub ah,ah ;make the value a word for division
|
||||
mov dh,10
|
||||
div dh ;split the row # into two digits
|
||||
add ax,'00' ;convert the digits to ASCII
|
||||
mov [DigitInsert],ax ;put the digits into the text
|
||||
; to be displayed
|
||||
mov ah,9
|
||||
mov dx,offset SplitScreenMsg
|
||||
int 21h ;print the text
|
||||
loop FillSplitScreenLoop
|
||||
;
|
||||
; Fill display memory starting at 8000h with a diagonally striped
|
||||
; pattern.
|
||||
;
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax
|
||||
mov di,8000h
|
||||
mov dx,SCREEN_HEIGHT ;fill all lines
|
||||
mov ax,8888h ;starting fill pattern
|
||||
cld
|
||||
RowLoop:
|
||||
mov cx,SCREEN_WIDTH/8/2 ;fill 1 scan line a word at a time
|
||||
rep stosw ;fill the scan line
|
||||
ror ax,1 ;shift pattern word
|
||||
dec dx
|
||||
jnz RowLoop
|
||||
;
|
||||
; Set the start address to 8000h and display that part of memory.
|
||||
;
|
||||
mov [StartAddress],8000h
|
||||
call SetStartAddress
|
||||
;
|
||||
; Slide the split screen half way up the screen and then back down
|
||||
; a quarter of the screen.
|
||||
;
|
||||
mov [SplitScreenLine],SCREEN_HEIGHT-1
|
||||
;set the initial line just off
|
||||
; the bottom of the screen
|
||||
mov cx,SCREEN_HEIGHT/2
|
||||
call SplitScreenUp
|
||||
mov cx,SCREEN_HEIGHT/4
|
||||
call SplitScreenDown
|
||||
;
|
||||
; Now move up another half a screen and then back down a quarter.
|
||||
;
|
||||
mov cx,SCREEN_HEIGHT/2
|
||||
call SplitScreenUp
|
||||
mov cx,SCREEN_HEIGHT/4
|
||||
call SplitScreenDown
|
||||
;
|
||||
; Finally move up to the top of the screen.
|
||||
;
|
||||
mov cx,SCREEN_HEIGHT/2-2
|
||||
call SplitScreenUp
|
||||
;
|
||||
; Wait for a key press (don't echo character).
|
||||
;
|
||||
mov ah,8 ;DOS console input without echo function
|
||||
int 21h
|
||||
;
|
||||
; Turn the split screen off.
|
||||
;
|
||||
mov [SplitScreenLine],0ffffh
|
||||
call SetSplitScreenScanLine
|
||||
;
|
||||
; Wait for a key press (don't echo character).
|
||||
;
|
||||
mov ah,8 ;DOS console input without echo function
|
||||
int 21h
|
||||
;
|
||||
; Display the memory at 0 (the same memory the split screen displays).
|
||||
;
|
||||
mov [StartAddress],0
|
||||
call SetStartAddress
|
||||
;
|
||||
; Flip between the split screen and the normal screen every 10th
|
||||
; frame until a key is pressed.
|
||||
;
|
||||
FlipLoop:
|
||||
xor [SplitScreenLine],0ffffh
|
||||
call SetSplitScreenScanLine
|
||||
mov cx,10
|
||||
CountVerticalSyncsLoop:
|
||||
call WaitForVerticalSyncEnd
|
||||
loop CountVerticalSyncsLoop
|
||||
mov ah,0bh ;DOS character available status
|
||||
int 21h
|
||||
and al,al ;character available?
|
||||
jz FlipLoop ;no, toggle split screen on/off status
|
||||
mov ah,1
|
||||
int 21h ;clear the character
|
||||
;
|
||||
; Return to text mode and DOS.
|
||||
;
|
||||
mov ax,0003h ;AH=0 is select mode function
|
||||
;AL=3 is mode to select, text mode
|
||||
int 10h ;return to text mode
|
||||
mov ah,4ch
|
||||
int 21h ;return to DOS
|
||||
Start endp
|
||||
;*********************************************************************
|
||||
; Waits for the leading edge of the vertical sync pulse.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AL, DX
|
||||
;
|
||||
WaitForVerticalSyncStart proc near
|
||||
mov dx,INPUT_STATUS_0
|
||||
WaitNotVerticalSync:
|
||||
in al,dx
|
||||
test al,08h
|
||||
jnz WaitNotVerticalSync
|
||||
WaitVerticalSync:
|
||||
in al,dx
|
||||
test al,08h
|
||||
jz WaitVerticalSync
|
||||
ret
|
||||
WaitForVerticalSyncStart endp
|
||||
;*********************************************************************
|
||||
; Waits for the trailing edge of the vertical sync pulse.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AL, DX
|
||||
;
|
||||
WaitForVerticalSyncEnd proc near
|
||||
mov dx,INPUT_STATUS_0
|
||||
WaitVerticalSync2:
|
||||
in al,dx
|
||||
test al,08h
|
||||
jz WaitVerticalSync2
|
||||
WaitNotVerticalSync2:
|
||||
in al,dx
|
||||
test al,08h
|
||||
jnz WaitNotVerticalSync2
|
||||
ret
|
||||
WaitForVerticalSyncEnd endp
|
||||
;*********************************************************************
|
||||
; Sets the start address to the value specifed by StartAddress.
|
||||
; Wait for the trailing edge of vertical sync before setting so that
|
||||
; one half of the address isn't loaded before the start of the frame
|
||||
; and the other half after, resulting in flicker as one frame is
|
||||
; displayed with mismatched halves. The new start address won't be
|
||||
; loaded until the start of the next frame; that is, one full frame
|
||||
; will be displayed before the new start address takes effect.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AX, DX
|
||||
;
|
||||
SetStartAddress proc near
|
||||
call WaitForVerticalSyncEnd
|
||||
mov dx,CRTC_INDEX
|
||||
mov al,START_ADDRESS_HIGH
|
||||
mov ah,byte ptr [StartAddress+1]
|
||||
cli ;make sure both registers get set at once
|
||||
OUT_WORD
|
||||
mov al,START_ADDRESS_LOW
|
||||
mov ah,byte ptr [StartAddress]
|
||||
OUT_WORD
|
||||
sti
|
||||
ret
|
||||
SetStartAddress endp
|
||||
;*********************************************************************
|
||||
; Sets the scan line the split screen starts after to the scan line
|
||||
; specified by SplitScreenLine.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; All registers preserved
|
||||
;
|
||||
SetSplitScreenScanLine proc near
|
||||
push ax
|
||||
push cx
|
||||
push dx
|
||||
;
|
||||
; Wait for the leading edge of the vertical sync pulse. This ensures
|
||||
; that we don't get mismatched portions of the split screen setting
|
||||
; while setting the two or three split screen registers (register 18h
|
||||
; set but register 7 not yet set when a match occurs, for example),
|
||||
; which could produce brief flickering.
|
||||
;
|
||||
call WaitForVerticalSyncStart
|
||||
;
|
||||
; Set the split screen scan line.
|
||||
;
|
||||
mov dx,CRTC_INDEX
|
||||
mov ah,byte ptr [SplitScreenLine]
|
||||
mov al,LINE_COMPARE
|
||||
cli ;make sure all the registers get set at once
|
||||
OUT_WORD ;set bits 7-0 of the split screen scan line
|
||||
mov ah,byte ptr [SplitScreenLine+1]
|
||||
and ah,1
|
||||
mov cl,4
|
||||
shl ah,cl ;move bit 8 of the split split screen scan
|
||||
; line into position for the Overflow reg
|
||||
mov al,OVERFLOW
|
||||
if IS_VGA
|
||||
;
|
||||
; The Split Screen, Overflow, and Line Compare registers all contain
|
||||
; part of the split screen start scan line on the VGA. We'll take
|
||||
; advantage of the readable registers of the VGA to leave other bits
|
||||
; in the registers we access undisturbed.
|
||||
;
|
||||
out dx,al ;set CRTC Index reg to point to Overflow
|
||||
inc dx ;point to CRTC Data reg
|
||||
in al,dx ;get the current Overflow reg setting
|
||||
and al,not 10h ;turn off split screen bit 8
|
||||
or al,ah ;insert the new split screen bit 8
|
||||
; (works in any mode)
|
||||
out dx,al ;set the new split screen bit 8
|
||||
dec dx ;point to CRTC Index reg
|
||||
mov ah,byte ptr [SplitScreenLine+1]
|
||||
and ah,2
|
||||
mov cl,3
|
||||
ror ah,cl ;move bit 9 of the split split screen scan
|
||||
; line into position for the Maximum Scan
|
||||
; Line register
|
||||
mov al,MAXIMUM_SCAN_LINE
|
||||
out dx,al ;set CRTC Index reg to point to Maximum
|
||||
; Scan Line
|
||||
inc dx ;point to CRTC Data reg
|
||||
in al,dx ;get the current Maximum Scan Line setting
|
||||
and al,not 40h ;turn off split screen bit 9
|
||||
or al,ah ;insert the new split screen bit 9
|
||||
; (works in any mode)
|
||||
out dx,al ;set the new split screen bit 9
|
||||
else
|
||||
;
|
||||
; Only the Split Screen and Overflow registers contain part of the
|
||||
; Split Screen start scan line and need to be set on the EGA.
|
||||
; EGA registers are not readable, so we have to set the non-split
|
||||
; screen bits of the Overflow register to a preset value, in this
|
||||
; case the value for 350-scan-line modes.
|
||||
;
|
||||
or ah,0fh ;insert the new split screen bit 8
|
||||
; (only works in 350-scan-line EGA modes)
|
||||
OUT_WORD ;set the new split screen bit 8
|
||||
endif
|
||||
sti
|
||||
pop dx
|
||||
pop cx
|
||||
pop ax
|
||||
ret
|
||||
SetSplitScreenScanLine endp
|
||||
;*********************************************************************
|
||||
; Moves the split screen up the specified number of scan lines.
|
||||
;
|
||||
; Input: CX = # of scan lines to move the split screen up by
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: CX
|
||||
;
|
||||
SplitScreenUp proc near
|
||||
SplitScreenUpLoop:
|
||||
dec [SplitScreenLine]
|
||||
call SetSplitScreenScanLine
|
||||
loop SplitScreenUpLoop
|
||||
ret
|
||||
SplitScreenUp endp
|
||||
;*********************************************************************
|
||||
; Moves the split screen down the specified number of scan lines.
|
||||
;
|
||||
; Input: CX = # of scan lines to move the split screen down by
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: CX
|
||||
;
|
||||
SplitScreenDown proc near
|
||||
SplitScreenDownLoop:
|
||||
inc [SplitScreenLine]
|
||||
call SetSplitScreenScanLine
|
||||
loop SplitScreenDownLoop
|
||||
ret
|
||||
SplitScreenDown endp
|
||||
;*********************************************************************
|
||||
Code ends
|
||||
end Start
|
||||
419
tests/pcx86/vga/L30-2.ASM
Normal file
419
tests/pcx86/vga/L30-2.ASM
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
; Demonstrates the interaction of the split screen and
|
||||
; horizontal pel panning. On a VGA, first pans right in the top
|
||||
; half while the split screen jerks around, because split screen
|
||||
; pel panning suppression is disabled, then enables split screen
|
||||
; pel panning suppression and pans right in the top half while the
|
||||
; split screen remains stable. On an EGA, the split screen jerks
|
||||
; around in both cases, because the EGA doesn't support split
|
||||
; screen pel panning suppression.
|
||||
;
|
||||
; The jerking in the split screen occurs because the split screen
|
||||
; is being pel panned (panned by single pixels--intrabyte panning),
|
||||
; but is not and cannot be byte panned (panned by single bytes--
|
||||
; "extrabyte" panning) because the start address of the split screen
|
||||
; is forever fixed at 0.
|
||||
;*********************************************************************
|
||||
IS_VGA equ 1 ;set to 0 to assemble for EGA
|
||||
;
|
||||
VGA_SEGMENT equ 0a000h
|
||||
LOGICAL_SCREEN_WIDTH equ 1024 ;# of pixels across virtual
|
||||
; screen that we'll pan across
|
||||
SCREEN_HEIGHT equ 350
|
||||
SPLIT_SCREEN_START equ 200 ;start scan line for split screen
|
||||
SPLIT_SCREEN_HEIGHT equ SCREEN_HEIGHT-SPLIT_SCREEN_START-1
|
||||
CRTC_INDEX equ 3d4h ;CRT Controller Index register
|
||||
AC_INDEX equ 3c0h ;Attribute Controller Index reg
|
||||
OVERFLOW equ 7 ;index of Overflow reg in CRTC
|
||||
MAXIMUM_SCAN_LINE equ 9 ;index of Maximum Scan Line register
|
||||
; in CRTC
|
||||
START_ADDRESS_HIGH equ 0ch ;index of Start Address High register
|
||||
; in CRTC
|
||||
START_ADDRESS_LOW equ 0dh ;index of Start Address Low register
|
||||
; in CRTC
|
||||
HOFFSET equ 13h ;index of Horizontal Offset register
|
||||
; in CRTC
|
||||
LINE_COMPARE equ 18h ;index of Line Compare reg (bits 7-0
|
||||
; of split screen start scan line)
|
||||
; in CRTC
|
||||
AC_MODE_CONTROL equ 10h ;index of Mode Control reg in AC
|
||||
PEL_PANNING equ 13h ;index of Pel Panning reg in AC
|
||||
INPUT_STATUS_0 equ 3dah ;Input Status 0 register
|
||||
WORD_OUTS_OK equ 1 ;set to 0 to assemble for
|
||||
; computers that can't handle
|
||||
; word outs to indexed VGA registers
|
||||
;*********************************************************************
|
||||
; Macro to output a word value to a port.
|
||||
;
|
||||
OUT_WORD macro
|
||||
if WORD_OUTS_OK
|
||||
out dx,ax
|
||||
else
|
||||
out dx,al
|
||||
inc dx
|
||||
xchg ah,al
|
||||
out dx,al
|
||||
dec dx
|
||||
xchg ah,al
|
||||
endif
|
||||
endm
|
||||
;*********************************************************************
|
||||
MyStack segment para stack 'STACK'
|
||||
db 512 dup (0)
|
||||
MyStack ends
|
||||
;*********************************************************************
|
||||
Data segment
|
||||
SplitScreenLine dw ? ;line the split screen currently
|
||||
; starts after
|
||||
StartAddress dw ? ;display memory offset at which
|
||||
; scanning for video data starts
|
||||
PelPan db ? ;current intrabyte horizontal pel
|
||||
; panning setting
|
||||
Data ends
|
||||
;*********************************************************************
|
||||
Code segment
|
||||
assume cs:Code, ds:Data
|
||||
;*********************************************************************
|
||||
Start proc near
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
;
|
||||
; Select mode 10h, 640x350 16-color graphics mode.
|
||||
;
|
||||
mov ax,0010h ;AH=0 is select mode function
|
||||
;AL=10h is mode to select,
|
||||
; 640x350 16-color graphics mode
|
||||
int 10h
|
||||
;
|
||||
; Set the Offset register to make the offset from the start of one
|
||||
; scan line to the start of the next the desired number of pixels.
|
||||
; This gives us a virtual screen wider than the actual screen to
|
||||
; pan across.
|
||||
; Note that the Offset register is programmed with the logical
|
||||
; screen width in words, not bytes, hence the final division by 2.
|
||||
;
|
||||
mov dx,CRTC_INDEX
|
||||
mov ax,(LOGICAL_SCREEN_WIDTH/8/2 shl 8) or HOFFSET
|
||||
OUT_WORD
|
||||
;
|
||||
; Set the start address to display the memory just past the split
|
||||
; screen memory.
|
||||
;
|
||||
mov [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
|
||||
call SetStartAddress
|
||||
;
|
||||
; Set the split screen start scan line.
|
||||
;
|
||||
mov [SplitScreenLine],SPLIT_SCREEN_START
|
||||
call SetSplitScreenScanLine
|
||||
;
|
||||
; Fill the split screen portion of display memory (starting at
|
||||
; offset 0) with a choppy diagonal pattern sloping left.
|
||||
;
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax
|
||||
sub di,di
|
||||
mov dx,SPLIT_SCREEN_HEIGHT
|
||||
;fill all lines in the split screen
|
||||
mov ax,0FF0h ;starting fill pattern
|
||||
cld
|
||||
RowLoop:
|
||||
mov cx,LOGICAL_SCREEN_WIDTH/8/4
|
||||
;fill 1 scan line
|
||||
ColumnLoop:
|
||||
stosw ;draw part of a diagonal line
|
||||
mov word ptr es:[di],0 ;make vertical blank spaces so
|
||||
; panning effects can be seen easily
|
||||
inc di
|
||||
inc di
|
||||
loop ColumnLoop
|
||||
rol ax,1 ;shift pattern word
|
||||
dec dx
|
||||
jnz RowLoop
|
||||
;
|
||||
; Fill the portion of display memory that will be displayed in the
|
||||
; normal screen (the non-split screen part of the display) with a
|
||||
; choppy diagonal pattern sloping right.
|
||||
;
|
||||
mov di,SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
|
||||
mov dx,SCREEN_HEIGHT ;fill all lines
|
||||
mov ax,0c510h ;starting fill pattern
|
||||
cld
|
||||
RowLoop2:
|
||||
mov cx,LOGICAL_SCREEN_WIDTH/8/4
|
||||
;fill 1 scan line
|
||||
ColumnLoop2:
|
||||
stosw ;draw part of a diagonal line
|
||||
mov word ptr es:[di],0 ;make vertical blank spaces so
|
||||
; panning effects can be seen easily
|
||||
inc di
|
||||
inc di
|
||||
loop ColumnLoop2
|
||||
ror ax,1 ;shift pattern word
|
||||
dec dx
|
||||
jnz RowLoop2
|
||||
;
|
||||
; Pel pan the non-split screen portion of the display; because
|
||||
; split screen pel panning suppression is not turned on, the split
|
||||
; screen jerks back and forth as the pel panning setting cycles.
|
||||
;
|
||||
mov cx,200 ;pan 200 pixels to the left
|
||||
call PanRight
|
||||
;
|
||||
; Wait for a key press (don't echo character).
|
||||
;
|
||||
mov ah,8 ;DOS console input without echo function
|
||||
int 21h
|
||||
;
|
||||
; Return to the original screen location, with pel panning turned off.
|
||||
;
|
||||
mov [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
|
||||
call SetStartAddress
|
||||
mov [PelPan],0
|
||||
call SetPelPan
|
||||
;
|
||||
; Turn on split screen pel panning suppression, so the split screen
|
||||
; won't be affected by pel panning. Not done on EGA because both
|
||||
; readable registers and the split screen pel panning suppression bit
|
||||
; aren't supported by EGAs.
|
||||
;
|
||||
if IS_VGA
|
||||
mov dx,INPUT_STATUS_0
|
||||
in al,dx ;reset the AC Index/Data toggle to
|
||||
; Index state
|
||||
mov al,20h+AC_MODE_CONTROL
|
||||
;bit 5 set to 1 to keep video on
|
||||
mov dx,AC_INDEX ;point to AC Index/Data register
|
||||
out dx,al
|
||||
inc dx ;point to AC Data reg (for reads only)
|
||||
in al,dx ;get the current AC Mode Control reg
|
||||
or al,20h ;enable split screen pel panning
|
||||
; suppression
|
||||
dec dx ;point to AC Index/Data reg (Data for
|
||||
; writes only)
|
||||
out dx,al ;write the new AC Mode Control setting
|
||||
; with split screen pel panning
|
||||
; suppression turned on
|
||||
endif
|
||||
;
|
||||
; Pel pan the non-split screen portion of the display; because
|
||||
; split screen pel panning suppression is turned on, the split
|
||||
; screen will not move as the pel panning setting cycles.
|
||||
;
|
||||
mov cx,200 ;pan 200 pixels to the left
|
||||
call PanRight
|
||||
;
|
||||
; Wait for a key press (don't echo character).
|
||||
;
|
||||
mov ah,8 ;DOS console input without echo function
|
||||
int 21h
|
||||
;
|
||||
; Return to text mode and DOS.
|
||||
;
|
||||
mov ax,0003h ;AH=0 is select mode function
|
||||
;AL=3 is mode to select, text mode
|
||||
int 10h ;return to text mode
|
||||
mov ah,4ch
|
||||
int 21h ;return to DOS
|
||||
Start endp
|
||||
;*********************************************************************
|
||||
; Waits for the leading edge of the vertical sync pulse.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AL, DX
|
||||
;
|
||||
WaitForVerticalSyncStart proc near
|
||||
mov dx,INPUT_STATUS_0
|
||||
WaitNotVerticalSync:
|
||||
in al,dx
|
||||
test al,08h
|
||||
jnz WaitNotVerticalSync
|
||||
WaitVerticalSync:
|
||||
in al,dx
|
||||
test al,08h
|
||||
jz WaitVerticalSync
|
||||
ret
|
||||
WaitForVerticalSyncStart endp
|
||||
;*********************************************************************
|
||||
; Waits for the trailing edge of the vertical sync pulse.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AL, DX
|
||||
;
|
||||
WaitForVerticalSyncEnd proc near
|
||||
mov dx,INPUT_STATUS_0
|
||||
WaitVerticalSync2:
|
||||
in al,dx
|
||||
test al,08h
|
||||
jz WaitVerticalSync2
|
||||
WaitNotVerticalSync2:
|
||||
in al,dx
|
||||
test al,08h
|
||||
jnz WaitNotVerticalSync2
|
||||
ret
|
||||
WaitForVerticalSyncEnd endp
|
||||
;*********************************************************************
|
||||
; Sets the start address to the value specifed by StartAddress.
|
||||
; Wait for the trailing edge of vertical sync before setting so that
|
||||
; one half of the address isn't loaded before the start of the frame
|
||||
; and the other half after, resulting in flicker as one frame is
|
||||
; displayed with mismatched halves. The new start address won't be
|
||||
; loaded until the start of the next frame; that is, one full frame
|
||||
; will be displayed before the new start address takes effect.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AX, DX
|
||||
;
|
||||
SetStartAddress proc near
|
||||
call WaitForVerticalSyncEnd
|
||||
mov dx,CRTC_INDEX
|
||||
mov al,START_ADDRESS_HIGH
|
||||
mov ah,byte ptr [StartAddress+1]
|
||||
cli ;make sure both registers get set at once
|
||||
OUT_WORD
|
||||
mov al,START_ADDRESS_LOW
|
||||
mov ah,byte ptr [StartAddress]
|
||||
OUT_WORD
|
||||
sti
|
||||
ret
|
||||
SetStartAddress endp
|
||||
;*********************************************************************
|
||||
; Sets the horizontal pel panning setting to the value specified
|
||||
; by PelPan. Waits until the start of vertical sync to do so, so
|
||||
; the new pel pan setting can be loaded during non-display time
|
||||
; and can be ready by the start of the next frame.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AL, DX
|
||||
;
|
||||
SetPelPan proc near
|
||||
call WaitForVerticalSyncStart ;also resets the AC
|
||||
; Index/Data toggle
|
||||
; to Index state
|
||||
mov dx,AC_INDEX
|
||||
mov al,PEL_PANNING+20h
|
||||
;bit 5 set to 1 to keep video on
|
||||
out dx,al ;point the AC Index to Pel Pan reg
|
||||
mov al,[PelPan]
|
||||
out dx,al ;load the new Pel Pan setting
|
||||
ret
|
||||
SetPelPan endp
|
||||
;*********************************************************************
|
||||
; Sets the scan line the split screen starts after to the scan line
|
||||
; specified by SplitScreenLine.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; All registers preserved
|
||||
;
|
||||
SetSplitScreenScanLine proc near
|
||||
push ax
|
||||
push cx
|
||||
push dx
|
||||
;
|
||||
; Wait for the leading edge of the vertical sync pulse. This ensures
|
||||
; that we don't get mismatched portions of the split screen setting
|
||||
; while setting the two or three split screen registers (register 18h
|
||||
; set but register 7 not yet set when a match occurs, for example),
|
||||
; which could produce brief flickering.
|
||||
;
|
||||
call WaitForVerticalSyncStart
|
||||
;
|
||||
; Set the split screen scan line.
|
||||
;
|
||||
mov dx,CRTC_INDEX
|
||||
mov ah,byte ptr [SplitScreenLine]
|
||||
mov al,LINE_COMPARE
|
||||
cli ;make sure all the registers get set at once
|
||||
OUT_WORD ;set bits 7-0 of the split screen scan line
|
||||
mov ah,byte ptr [SplitScreenLine+1]
|
||||
and ah,1
|
||||
mov cl,4
|
||||
shl ah,cl ;move bit 8 of the split split screen scan
|
||||
; line into position for the Overflow reg
|
||||
mov al,OVERFLOW
|
||||
if IS_VGA
|
||||
;
|
||||
; The Split Screen, Overflow, and Line Compare registers all contain
|
||||
; part of the split screen start scan line on the VGA. We'll take
|
||||
; advantage of the readable registers of the VGA to leave other bits
|
||||
; in the registers we access undisturbed.
|
||||
;
|
||||
out dx,al ;set CRTC Index reg to point to Overflow
|
||||
inc dx ;point to CRTC Data reg
|
||||
in al,dx ;get the current Overflow reg setting
|
||||
and al,not 10h ;turn off split screen bit 8
|
||||
or al,ah ;insert the new split screen bit 8
|
||||
; (works in any mode)
|
||||
out dx,al ;set the new split screen bit 8
|
||||
dec dx ;point to CRTC Index reg
|
||||
mov ah,byte ptr [SplitScreenLine+1]
|
||||
and ah,2
|
||||
mov cl,3
|
||||
ror ah,cl ;move bit 9 of the split split screen scan
|
||||
; line into position for the Maximum Scan
|
||||
; Line register
|
||||
mov al,MAXIMUM_SCAN_LINE
|
||||
out dx,al ;set CRTC Index reg to point to Maximum
|
||||
; Scan Line
|
||||
inc dx ;point to CRTC Data reg
|
||||
in al,dx ;get the current Maximum Scan Line setting
|
||||
and al,not 40h ;turn off split screen bit 9
|
||||
or al,ah ;insert the new split screen bit 9
|
||||
; (works in any mode)
|
||||
out dx,al ;set the new split screen bit 9
|
||||
else
|
||||
;
|
||||
; Only the Split Screen and Overflow registers contain part of the
|
||||
; Split Screen start scan line and need to be set on the EGA.
|
||||
; EGA registers are not readable, so we have to set the non-split
|
||||
; screen bits of the Overflow register to a preset value, in this
|
||||
; case the value for 350-scan-line modes.
|
||||
;
|
||||
or ah,0fh ;insert the new split screen bit 8
|
||||
; (only works in 350-scan-line EGA modes)
|
||||
OUT_WORD ;set the new split screen bit 8
|
||||
endif
|
||||
sti
|
||||
pop dx
|
||||
pop cx
|
||||
pop ax
|
||||
ret
|
||||
SetSplitScreenScanLine endp
|
||||
;*********************************************************************
|
||||
; Pan horizontally to the right the number of pixels specified by CX.
|
||||
;
|
||||
; Input: CX = # of pixels by which to pan horizontally
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AX, CX, DX
|
||||
;
|
||||
PanRight proc near
|
||||
PanLoop:
|
||||
inc [PelPan]
|
||||
and [PelPan],07h
|
||||
jnz DoSetStartAddress
|
||||
inc [StartAddress]
|
||||
DoSetStartAddress:
|
||||
call SetStartAddress
|
||||
call SetPelPan
|
||||
loop PanLoop
|
||||
ret
|
||||
PanRight endp
|
||||
;*********************************************************************
|
||||
Code ends
|
||||
end Start
|
||||
326
tests/pcx86/vga/L31-1.ASM
Normal file
326
tests/pcx86/vga/L31-1.ASM
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
; Program to demonstrate pixel drawing in 320x400 256-color
|
||||
; mode on the VGA. Draws 8 lines to form an octagon, a pixel
|
||||
; at a time. Draws 8 octagons in all, one on top of the other,
|
||||
; each in a different color set. Although it's not used, a
|
||||
; pixel read function is also provided.
|
||||
;
|
||||
VGA_SEGMENT equ 0a000h
|
||||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||||
GC_INDEX equ 3ceh ;Graphics Controller Index register
|
||||
CRTC_INDEX equ 3d4h ;CRT Controller Index register
|
||||
MAP_MASK equ 2 ;Map Mask register index in SC
|
||||
MEMORY_MODE equ 4 ;Memory Mode register index in SC
|
||||
MAX_SCAN_LINE equ 9 ;Maximum Scan Line reg index in CRTC
|
||||
START_ADDRESS_HIGH equ 0ch ;Start Address High reg index in CRTC
|
||||
UNDERLINE equ 14h ;Underline Location reg index in CRTC
|
||||
MODE_CONTROL equ 17h ;Mode Control register index in CRTC
|
||||
READ_MAP equ 4 ;Read Map register index in GC
|
||||
GRAPHICS_MODE equ 5 ;Graphics Mode register index in GC
|
||||
MISCELLANEOUS equ 6 ;Miscellaneous register index in GC
|
||||
SCREEN_WIDTH equ 320 ;# of pixels across screen
|
||||
SCREEN_HEIGHT equ 400 ;# of scan lines on screen
|
||||
WORD_OUTS_OK equ 1 ;set to 0 to assemble for
|
||||
; computers that can't handle
|
||||
; word outs to indexed VGA registers
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
Data segment word 'DATA'
|
||||
;
|
||||
BaseColor db 0
|
||||
;
|
||||
; Structure used to control drawing of a line.
|
||||
;
|
||||
LineControl struc
|
||||
StartX dw ?
|
||||
StartY dw ?
|
||||
LineXInc dw ?
|
||||
LineYInc dw ?
|
||||
BaseLength dw ?
|
||||
LineColor db ?
|
||||
LineControl ends
|
||||
;
|
||||
; List of descriptors for lines to draw.
|
||||
;
|
||||
LineList label LineControl
|
||||
LineControl <130,110,1,0,60,0>
|
||||
LineControl <190,110,1,1,60,1>
|
||||
LineControl <250,170,0,1,60,2>
|
||||
LineControl <250,230,-1,1,60,3>
|
||||
LineControl <190,290,-1,0,60,4>
|
||||
LineControl <130,290,-1,-1,60,5>
|
||||
LineControl <70,230,0,-1,60,6>
|
||||
LineControl <70,170,1,-1,60,7>
|
||||
LineControl <-1,0,0,0,0,0>
|
||||
Data ends
|
||||
;
|
||||
; Macro to output a word value to a port.
|
||||
;
|
||||
OUT_WORD macro
|
||||
if WORD_OUTS_OK
|
||||
out dx,ax
|
||||
else
|
||||
out dx,al
|
||||
inc dx
|
||||
xchg ah,al
|
||||
out dx,al
|
||||
dec dx
|
||||
xchg ah,al
|
||||
endif
|
||||
endm
|
||||
;
|
||||
; Macro to output a constant value to an indexed VGA register.
|
||||
;
|
||||
CONSTANT_TO_INDEXED_REGISTER macro ADDRESS, INDEX, VALUE
|
||||
mov dx,ADDRESS
|
||||
mov ax,(VALUE shl 8) + INDEX
|
||||
OUT_WORD
|
||||
endm
|
||||
;
|
||||
Code segment
|
||||
assume cs:Code, ds:Data
|
||||
Start proc near
|
||||
mov ax,Data
|
||||
mov ds,ax
|
||||
;
|
||||
; Set 320x400 256-color mode.
|
||||
;
|
||||
call Set320By400Mode
|
||||
;
|
||||
; We're in 320x400 256-color mode. Draw each line in turn.
|
||||
;
|
||||
ColorLoop:
|
||||
mov si,offset LineList ;point to the start of the
|
||||
; line descriptor list
|
||||
LineLoop:
|
||||
mov cx,[si+StartX] ;set the initial X coordinate
|
||||
cmp cx,-1
|
||||
jz LinesDone ;a descriptor with a -1 X
|
||||
; coordinate marks the end
|
||||
; of the list
|
||||
mov dx,[si+StartY] ;set the initial Y coordinate,
|
||||
mov bl,[si+LineColor] ; line color,
|
||||
mov bp,[si+BaseLength] ; and pixel count
|
||||
add bl,[BaseColor] ;adjust the line color according
|
||||
; to BaseColor
|
||||
PixelLoop:
|
||||
push cx ;save the coordinates
|
||||
push dx
|
||||
call WritePixel ;draw this pixel
|
||||
pop dx ;retrieve the coordinates
|
||||
pop cx
|
||||
add cx,[si+LineXInc];set the coordinates of the
|
||||
add dx,[si+LineYInc]; next point of the line
|
||||
dec bp ;any more points?
|
||||
jnz PixelLoop ;yes, draw the next
|
||||
add si,size LineControl ;point to the next line descriptor
|
||||
jmp LineLoop ; and draw the next line
|
||||
LinesDone:
|
||||
call GetNextKey ;wait for a key, then
|
||||
inc [BaseColor] ; bump the color selection and
|
||||
cmp [BaseColor],8 ; see if we're done
|
||||
jb ColorLoop ;not done yet
|
||||
;
|
||||
; Wait for a key and return to text mode and end when
|
||||
; one is pressed.
|
||||
;
|
||||
call GetNextKey
|
||||
mov ax,0003h
|
||||
int 10h ;text mode
|
||||
mov ah,4ch
|
||||
int 21h ;done
|
||||
;
|
||||
Start endp
|
||||
;
|
||||
; Sets up 320x400 256-color modes.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
Set320By400Mode proc near
|
||||
;
|
||||
; First, go to normal 320x200 256-color mode, which is really a
|
||||
; 320x400 256-color mode with each line scanned twice.
|
||||
;
|
||||
mov ax,0013h ;AH = 0 means mode set, AL = 13h selects
|
||||
; 256-color graphics mode
|
||||
int 10h ;BIOS video interrupt
|
||||
;
|
||||
; Change CPU addressing of video memory to linear (not odd/even,
|
||||
; chain, or chain 4), to allow us to access all 256K of display
|
||||
; memory. When this is done, VGA memory will look just like memory
|
||||
; in modes 10h and 12h, except that each byte of display memory will
|
||||
; control one 256-color pixel, with 4 adjacent pixels at any given
|
||||
; address, one pixel per plane.
|
||||
;
|
||||
mov dx,SC_INDEX
|
||||
mov al,MEMORY_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 08h ;turn off chain 4
|
||||
or al,04h ;turn off odd/even
|
||||
out dx,al
|
||||
mov dx,GC_INDEX
|
||||
mov al,GRAPHICS_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 10h ;turn off odd/even
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,MISCELLANEOUS
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 02h ;turn off chain
|
||||
out dx,al
|
||||
;
|
||||
; Now clear the whole screen, since the mode 13h mode set only
|
||||
; cleared 64K out of the 256K of display memory. Do this before
|
||||
; we switch the CRTC out of mode 13h, so we don't see garbage
|
||||
; on the screen when we make the switch.
|
||||
;
|
||||
CONSTANT_TO_INDEXED_REGISTER SC_INDEX,MAP_MASK,0fh
|
||||
;enable writes to all planes, so
|
||||
; we can clear 4 pixels at a time
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax
|
||||
sub di,di
|
||||
mov ax,di
|
||||
mov cx,8000h ;# of words in 64K
|
||||
cld
|
||||
rep stosw ;clear all of display memory
|
||||
;
|
||||
; Tweak the mode to 320x400 256-color mode by not scanning each
|
||||
; line twice.
|
||||
;
|
||||
mov dx,CRTC_INDEX
|
||||
IF 1 ; the following code can be disabled to test memory access in 320x200 mode -JP
|
||||
mov al,MAX_SCAN_LINE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 1fh ;set maximum scan line = 0
|
||||
out dx,al
|
||||
dec dx
|
||||
ENDIF
|
||||
;
|
||||
; Change CRTC scanning from doubleword mode to byte mode, allowing
|
||||
; the CRTC to scan more than 64K of video data.
|
||||
;
|
||||
mov al,UNDERLINE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 40h ;turn off doubleword
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,MODE_CONTROL
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
or al,40h ;turn on the byte mode bit, so memory is
|
||||
; scanned for video data in a purely
|
||||
; linear way, just as in modes 10h and 12h
|
||||
out dx,al
|
||||
ret
|
||||
Set320By400Mode endp
|
||||
;
|
||||
; Draws a pixel in the specified color at the specified
|
||||
; location in 320x400 256-color mode.
|
||||
;
|
||||
; Input:
|
||||
; CX = X coordinate of pixel
|
||||
; DX = Y coordinate of pixel
|
||||
; BL = pixel color
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
; Registers altered: AX, CX, DX, DI, ES
|
||||
;
|
||||
WritePixel proc near
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax ;point to display memory
|
||||
mov ax,SCREEN_WIDTH/4
|
||||
;there are 4 pixels at each address, so
|
||||
; each 320-pixel row is 80 bytes wide
|
||||
; in each plane
|
||||
mul dx ;point to start of desired row
|
||||
push cx ;set aside the X coordinate
|
||||
shr cx,1 ;there are 4 pixels at each address
|
||||
shr cx,1 ; so divide the X coordinate by 4
|
||||
add ax,cx ;point to the pixel's address
|
||||
mov di,ax
|
||||
pop cx ;get back the X coordinate
|
||||
and cl,3 ;get the plane # of the pixel
|
||||
mov ah,1
|
||||
shl ah,cl ;set the bit corresponding to the plane
|
||||
; the pixel is in
|
||||
mov al,MAP_MASK
|
||||
mov dx,SC_INDEX
|
||||
OUT_WORD ;set to write to the proper plane for
|
||||
; the pixel
|
||||
mov es:[di],bl ;draw the pixel
|
||||
ret
|
||||
WritePixel endp
|
||||
;
|
||||
; Reads the color of the pixel at the specified location in 320x400
|
||||
; 256-color mode.
|
||||
;
|
||||
; Input:
|
||||
; CX = X coordinate of pixel to read
|
||||
; DX = Y coordinate of pixel to read
|
||||
;
|
||||
; Output:
|
||||
; AL = pixel color
|
||||
;
|
||||
; Registers altered: AX, CX, DX, SI, ES
|
||||
;
|
||||
ReadPixel proc near
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax ;point to display memory
|
||||
mov ax,SCREEN_WIDTH/4
|
||||
;there are 4 pixels at each address, so
|
||||
; each 320-pixel row is 80 bytes wide
|
||||
; in each plane
|
||||
mul dx ;point to start of desired row
|
||||
push cx ;set aside the X coordinate
|
||||
shr cx,1 ;there are 4 pixels at each address
|
||||
shr cx,1 ; so divide the X coordinate by 4
|
||||
add ax,cx ;point to the pixel's address
|
||||
mov si,ax
|
||||
pop ax ;get back the X coordinate
|
||||
and al,3 ;get the plane # of the pixel
|
||||
mov ah,al
|
||||
mov al,READ_MAP
|
||||
mov dx,GC_INDEX
|
||||
OUT_WORD ;set to read from the proper plane for
|
||||
; the pixel
|
||||
lods byte ptr es:[si];read the pixel
|
||||
ret
|
||||
ReadPixel endp
|
||||
;
|
||||
; Waits for the next key and returns it in AX.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output:
|
||||
; AX = full 16-bit code for key pressed
|
||||
;
|
||||
GetNextKey proc near
|
||||
WaitKey:
|
||||
mov ah,1
|
||||
int 16h
|
||||
jz WaitKey ;wait for a key to become available
|
||||
sub ah,ah
|
||||
int 16h ;read the key
|
||||
ret
|
||||
GetNextKey endp
|
||||
;
|
||||
Code ends
|
||||
;
|
||||
end Start
|
||||
259
tests/pcx86/vga/L31-2.ASM
Normal file
259
tests/pcx86/vga/L31-2.ASM
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
; Program to demonstrate the two pages available in 320x400
|
||||
; 256-color modes on a VGA. Draws diagonal color bars in all
|
||||
; 256 colors in page 0, then does the same in page 1 (but with
|
||||
; the bars tilted the other way), and finally draws vertical
|
||||
; color bars in page 0.
|
||||
;
|
||||
VGA_SEGMENT equ 0a000h
|
||||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||||
GC_INDEX equ 3ceh ;Graphics Controller Index register
|
||||
CRTC_INDEX equ 3d4h ;CRT Controller Index register
|
||||
MAP_MASK equ 2 ;Map Mask register index in SC
|
||||
MEMORY_MODE equ 4 ;Memory Mode register index in SC
|
||||
MAX_SCAN_LINE equ 9 ;Maximum Scan Line reg index in CRTC
|
||||
START_ADDRESS_HIGH equ 0ch ;Start Address High reg index in CRTC
|
||||
UNDERLINE equ 14h ;Underline Location reg index in CRTC
|
||||
MODE_CONTROL equ 17h ;Mode Control register index in CRTC
|
||||
GRAPHICS_MODE equ 5 ;Graphics Mode register index in GC
|
||||
MISCELLANEOUS equ 6 ;Miscellaneous register index in GC
|
||||
SCREEN_WIDTH equ 320 ;# of pixels across screen
|
||||
SCREEN_HEIGHT equ 400 ;# of scan lines on screen
|
||||
WORD_OUTS_OK equ 1 ;set to 0 to assemble for
|
||||
; computers that can't handle
|
||||
; word outs to indexed VGA registers
|
||||
;
|
||||
stack segment para stack 'STACK'
|
||||
db 512 dup (?)
|
||||
stack ends
|
||||
;
|
||||
; Macro to output a word value to a port.
|
||||
;
|
||||
OUT_WORD macro
|
||||
if WORD_OUTS_OK
|
||||
out dx,ax
|
||||
else
|
||||
out dx,al
|
||||
inc dx
|
||||
xchg ah,al
|
||||
out dx,al
|
||||
dec dx
|
||||
xchg ah,al
|
||||
endif
|
||||
endm
|
||||
;
|
||||
; Macro to output a constant value to an indexed VGA register.
|
||||
;
|
||||
CONSTANT_TO_INDEXED_REGISTER macro ADDRESS, INDEX, VALUE
|
||||
mov dx,ADDRESS
|
||||
mov ax,(VALUE shl 8) + INDEX
|
||||
OUT_WORD
|
||||
endm
|
||||
;
|
||||
Code segment
|
||||
assume cs:Code
|
||||
Start proc near
|
||||
;
|
||||
; Set 320x400 256-color mode.
|
||||
;
|
||||
call Set320By400Mode
|
||||
;
|
||||
; We're in 320x400 256-color mode, with page 0 displayed.
|
||||
; Let's fill page 0 with color bars slanting down and to the right.
|
||||
;
|
||||
sub di,di ;page 0 starts at address 0
|
||||
mov bl,1 ;make color bars slant down and
|
||||
; to the right
|
||||
call ColorBarsUp ;draw the color bars
|
||||
;
|
||||
; Now do the same for page 1, but with the color bars
|
||||
; tilting the other way.
|
||||
;
|
||||
mov di,8000h ;page 1 starts at address 8000h
|
||||
mov bl,-1 ;make color bars slant down and
|
||||
; to the left
|
||||
call ColorBarsUp ;draw the color bars
|
||||
;
|
||||
; Wait for a key and flip to page 1 when one is pressed.
|
||||
;
|
||||
call GetNextKey
|
||||
CONSTANT_TO_INDEXED_REGISTER CRTC_INDEX,START_ADDRESS_HIGH,80h
|
||||
;set the Start Address High register
|
||||
; to 80h, for a start address of 8000h
|
||||
;
|
||||
; Draw vertical bars in page 0 while page 1 is displayed.
|
||||
;
|
||||
sub di,di ;page 0 starts at address 0
|
||||
sub bl,bl ;make color bars vertical
|
||||
call ColorBarsUp ;draw the color bars
|
||||
;
|
||||
; Wait for another key and flip back to page 0 when one is pressed.
|
||||
;
|
||||
call GetNextKey
|
||||
CONSTANT_TO_INDEXED_REGISTER CRTC_INDEX,START_ADDRESS_HIGH,00h
|
||||
;set the Start Address High register
|
||||
; to 00h, for a start address of 0000h
|
||||
;
|
||||
; Wait for yet another key and return to text mode and end when
|
||||
; one is pressed.
|
||||
;
|
||||
call GetNextKey
|
||||
mov ax,0003h
|
||||
int 10h ;text mode
|
||||
mov ah,4ch
|
||||
int 21h ;done
|
||||
;
|
||||
Start endp
|
||||
;
|
||||
; Sets up 320x400 256-color modes.
|
||||
;
|
||||
; Input: none
|
||||
;
|
||||
; Output: none
|
||||
;
|
||||
Set320By400Mode proc near
|
||||
;
|
||||
; First, go to normal 320x200 256-color mode, which is really a
|
||||
; 320x400 256-color mode with each line scanned twice.
|
||||
;
|
||||
mov ax,0013h ;AH = 0 means mode set, AL = 13h selects
|
||||
; 256-color graphics mode
|
||||
int 10h ;BIOS video interrupt
|
||||
;
|
||||
; Change CPU addressing of video memory to linear (not odd/even,
|
||||
; chain, or chain 4), to allow us to access all 256K of display
|
||||
; memory. When this is done, VGA memory will look just like memory
|
||||
; in modes 10h and 12h, except that each byte of display memory will
|
||||
; control one 256-color pixel, with 4 adjacent pixels at any given
|
||||
; address, one pixel per plane.
|
||||
;
|
||||
mov dx,SC_INDEX
|
||||
mov al,MEMORY_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 08h ;turn off chain 4
|
||||
or al,04h ;turn off odd/even
|
||||
out dx,al
|
||||
mov dx,GC_INDEX
|
||||
mov al,GRAPHICS_MODE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 10h ;turn off odd/even
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,MISCELLANEOUS
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 02h ;turn off chain
|
||||
out dx,al
|
||||
;
|
||||
; Now clear the whole screen, since the mode 13h mode set only
|
||||
; cleared 64K out of the 256K of display memory. Do this before
|
||||
; we switch the CRTC out of mode 13h, so we don't see garbage
|
||||
; on the screen when we make the switch.
|
||||
;
|
||||
CONSTANT_TO_INDEXED_REGISTER SC_INDEX,MAP_MASK,0fh
|
||||
;enable writes to all planes, so
|
||||
; we can clear 4 pixels at a time
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax
|
||||
sub di,di
|
||||
mov ax,di
|
||||
mov cx,8000h ;# of words in 64K
|
||||
cld
|
||||
rep stosw ;clear all of display memory
|
||||
;
|
||||
; Tweak the mode to 320x400 256-color mode by not scanning each
|
||||
; line twice.
|
||||
;
|
||||
mov dx,CRTC_INDEX
|
||||
mov al,MAX_SCAN_LINE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 1fh ;set maximum scan line = 0
|
||||
out dx,al
|
||||
dec dx
|
||||
;
|
||||
; Change CRTC scanning from doubleword mode to byte mode, allowing
|
||||
; the CRTC to scan more than 64K of video data.
|
||||
;
|
||||
mov al,UNDERLINE
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,not 40h ;turn off doubleword
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,MODE_CONTROL
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
or al,40h ;turn on the byte mode bit, so memory is
|
||||
; scanned for video data in a purely
|
||||
; linear way, just as in modes 10h and 12h
|
||||
out dx,al
|
||||
ret
|
||||
Set320By400Mode endp
|
||||
;
|
||||
; Draws a full screen of slanting color bars in the specified page.
|
||||
;
|
||||
; Input:
|
||||
; DI = page start address
|
||||
; BL = 1 to make the bars slant down and to the right, -1 to
|
||||
; make them slant down and to the left, 0 to make
|
||||
; them vertical.
|
||||
;
|
||||
ColorBarsUp proc near
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax ;point to display memory
|
||||
sub bh,bh ;start with color 0
|
||||
mov si,SCREEN_HEIGHT;# of rows to do
|
||||
mov dx,SC_INDEX
|
||||
mov al,MAP_MASK
|
||||
out dx,al ;point the SC Index reg to the Map Mask reg
|
||||
inc dx ;point DX to the SC Data register
|
||||
RowLoop:
|
||||
mov cx,SCREEN_WIDTH/4
|
||||
;there are 4 pixels at each address, so
|
||||
; each 320-pixel row is 80 bytes wide
|
||||
; in each plane
|
||||
push bx ;save the row-start color
|
||||
ColumnLoop:
|
||||
MAP_SELECT = 1
|
||||
rept 4 ;do all 4 pixels at this address with
|
||||
; in-line code
|
||||
mov al,MAP_SELECT
|
||||
out dx,al ;select planes 0, 1, 2, and 3 in turn
|
||||
mov es:[di],bh ;write this plane's pixel
|
||||
inc bh ;set the color for the next pixel
|
||||
MAP_SELECT = MAP_SELECT shl 1
|
||||
endm
|
||||
inc di ;point to the address containing the next
|
||||
; 4 pixels
|
||||
loop ColumnLoop ;do any remaining pixels on this line
|
||||
pop bx ;get back the row-start color
|
||||
add bh,bl ;select next row-start color (controls
|
||||
; slanting of color bars)
|
||||
dec si ;count down lines on the screen
|
||||
jnz RowLoop
|
||||
ret
|
||||
ColorBarsUp endp
|
||||
;
|
||||
; Waits for the next key and returns it in AX.
|
||||
;
|
||||
GetNextKey proc near
|
||||
WaitKey:
|
||||
mov ah,1
|
||||
int 16h
|
||||
jz WaitKey ;wait for a key to become available
|
||||
sub ah,ah
|
||||
int 16h ;read the key
|
||||
ret
|
||||
GetNextKey endp
|
||||
;
|
||||
Code ends
|
||||
;
|
||||
end Start
|
||||
211
tests/pcx86/vga/L32-1.ASM
Normal file
211
tests/pcx86/vga/L32-1.ASM
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
; C tiny/small/medium model-callable assembler
|
||||
; subroutines to:
|
||||
; * Set 360x480 256-color VGA mode
|
||||
; * Draw a dot in 360x480 256-color VGA mode
|
||||
; * Read the color of a dot in 360x480 256-color VGA mode
|
||||
;
|
||||
; Assembled with TASM
|
||||
;
|
||||
; The 360x480 256-color mode set code and parameters were provided
|
||||
; by John Bridges, who has placed them into the public domain.
|
||||
;
|
||||
VGA_SEGMENT equ 0a000h ;display memory segment
|
||||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||||
GC_INDEX equ 3ceh ;Graphics Controller Index register
|
||||
MAP_MASK equ 2 ;Map Mask register index in SC
|
||||
READ_MAP equ 4 ;Read Map register index in GC
|
||||
SCREEN_WIDTH equ 360 ;# of pixels across screen
|
||||
WORD_OUTS_OK equ 1 ;set to 0 to assemble for
|
||||
; computers that can't handle
|
||||
; word outs to indexed VGA registers
|
||||
;
|
||||
_DATA segment public byte 'DATA'
|
||||
;
|
||||
; 360x480 256-color mode CRT Controller register settings.
|
||||
; (Courtesy of John Bridges.)
|
||||
;
|
||||
vptbl dw 06b00h ; horz total
|
||||
dw 05901h ; horz displayed
|
||||
dw 05a02h ; start horz blanking
|
||||
dw 08e03h ; end horz blanking
|
||||
dw 05e04h ; start h sync
|
||||
dw 08a05h ; end h sync
|
||||
dw 00d06h ; vertical total
|
||||
dw 03e07h ; overflow
|
||||
dw 04009h ; cell height
|
||||
dw 0ea10h ; v sync start
|
||||
dw 0ac11h ; v sync end and protect cr0-cr7
|
||||
dw 0df12h ; vertical displayed
|
||||
dw 02d13h ; offset
|
||||
dw 00014h ; turn off dword mode
|
||||
dw 0e715h ; v blank start
|
||||
dw 00616h ; v blank end
|
||||
dw 0e317h ; turn on byte mode
|
||||
vpend label word
|
||||
_DATA ends
|
||||
;
|
||||
; Macro to output a word value to a port.
|
||||
;
|
||||
OUT_WORD macro
|
||||
if WORD_OUTS_OK
|
||||
out dx,ax
|
||||
else
|
||||
out dx,al
|
||||
inc dx
|
||||
xchg ah,al
|
||||
out dx,al
|
||||
dec dx
|
||||
xchg ah,al
|
||||
endif
|
||||
endm
|
||||
;
|
||||
_TEXT segment byte public 'CODE'
|
||||
assume cs:_TEXT, ds:_DATA
|
||||
;
|
||||
; Sets up 360x480 256-color mode.
|
||||
; (Courtesy of John Bridges.)
|
||||
;
|
||||
; Call as: void Set360By480Mode()
|
||||
;
|
||||
; Returns: nothing
|
||||
;
|
||||
public _Set360x480Mode
|
||||
_Set360x480Mode proc near
|
||||
push si ;preserve C register vars
|
||||
push di
|
||||
mov ax,12h ; start with mode 12h
|
||||
int 10h ; let the bios clear the video memory
|
||||
|
||||
mov ax,13h ; start with standard mode 13h
|
||||
int 10h ; let the bios set the mode
|
||||
|
||||
mov dx,3c4h ; alter sequencer registers
|
||||
mov ax,0604h ; disable chain 4
|
||||
out dx,ax
|
||||
|
||||
mov ax,0100h ; synchronous reset
|
||||
out dx,ax ; asserted
|
||||
mov dx,3c2h ; misc output
|
||||
mov al,0e7h ; use 28 mHz dot clock
|
||||
out dx,al ; select it
|
||||
mov dx,3c4h ; sequencer again
|
||||
mov ax,0300h ; restart sequencer
|
||||
out dx,ax ; running again
|
||||
|
||||
mov dx,3d4h ; alter crtc registers
|
||||
|
||||
mov al,11h ; cr11
|
||||
out dx,al ; current value
|
||||
inc dx ; point to data
|
||||
in al,dx ; get cr11 value
|
||||
and al,7fh ; remove cr0 -> cr7
|
||||
out dx,al ; write protect
|
||||
dec dx ; point to index
|
||||
cld
|
||||
mov si,offset vptbl
|
||||
mov cx,((offset vpend)-(offset vptbl)) shr 1
|
||||
@b: lodsw
|
||||
out dx,ax
|
||||
loop @b
|
||||
pop di ;restore C register vars
|
||||
pop si
|
||||
ret
|
||||
_Set360x480Mode endp
|
||||
;
|
||||
; Draws a pixel in the specified color at the specified
|
||||
; location in 360x480 256-color mode.
|
||||
;
|
||||
; Call as: void Draw360x480Dot(int X, int Y, int Color)
|
||||
;
|
||||
; Returns: nothing
|
||||
;
|
||||
DParms struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;return address
|
||||
DrawX dw ? ;X coordinate at which to draw
|
||||
DrawY dw ? ;Y coordinate at which to draw
|
||||
Color dw ? ;color in which to draw (in the
|
||||
; range 0-255; upper byte ignored)
|
||||
DParms ends
|
||||
;
|
||||
public _Draw360x480Dot
|
||||
_Draw360x480Dot proc near
|
||||
push bp ;preserve caller's BP
|
||||
mov bp,sp ;point to stack frame
|
||||
push si ;preserve C register vars
|
||||
push di
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax ;point to display memory
|
||||
mov ax,SCREEN_WIDTH/4
|
||||
;there are 4 pixels at each address, so
|
||||
; each 360-pixel row is 90 bytes wide
|
||||
; in each plane
|
||||
mul [bp+DrawY] ;point to start of desired row
|
||||
mov di,[bp+DrawX] ;get the X coordinate
|
||||
shr di,1 ;there are 4 pixels at each address
|
||||
shr di,1 ; so divide the X coordinate by 4
|
||||
add di,ax ;point to the pixel's address
|
||||
mov cl,byte ptr [bp+DrawX] ;get the X coordinate again
|
||||
and cl,3 ;get the plane # of the pixel
|
||||
mov ah,1
|
||||
shl ah,cl ;set the bit corresponding to the plane
|
||||
; the pixel is in
|
||||
mov al,MAP_MASK
|
||||
mov dx,SC_INDEX
|
||||
OUT_WORD ;set to write to the proper plane for
|
||||
; the pixel
|
||||
mov al,byte ptr [bp+Color] ;get the color
|
||||
stosb ;draw the pixel
|
||||
pop di ;restore C register vars
|
||||
pop si
|
||||
pop bp ;restore caller's BP
|
||||
ret
|
||||
_Draw360x480Dot endp
|
||||
;
|
||||
; Reads the color of the pixel at the specified
|
||||
; location in 360x480 256-color mode.
|
||||
;
|
||||
; Call as: int Read360x480Dot(int X, int Y)
|
||||
;
|
||||
; Returns: pixel color
|
||||
;
|
||||
RParms struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;return address
|
||||
ReadX dw ? ;X coordinate from which to read
|
||||
ReadY dw ? ;Y coordinate from which to read
|
||||
RParms ends
|
||||
;
|
||||
public _Read360x480Dot
|
||||
_Read360x480Dot proc near
|
||||
push bp ;preserve caller's BP
|
||||
mov bp,sp ;point to stack frame
|
||||
push si ;preserve C register vars
|
||||
push di
|
||||
mov ax,VGA_SEGMENT
|
||||
mov es,ax ;point to display memory
|
||||
mov ax,SCREEN_WIDTH/4
|
||||
;there are 4 pixels at each address, so
|
||||
; each 360-pixel row is 90 bytes wide
|
||||
; in each plane
|
||||
mul [bp+DrawY] ;point to start of desired row
|
||||
mov si,[bp+DrawX] ;get the X coordinate
|
||||
shr si,1 ;there are 4 pixels at each address
|
||||
shr si,1 ; so divide the X coordinate by 4
|
||||
add si,ax ;point to the pixel's address
|
||||
mov ah,byte ptr [bp+DrawX]
|
||||
;get the X coordinate again
|
||||
and ah,3 ;get the plane # of the pixel
|
||||
mov al,READ_MAP
|
||||
mov dx,GC_INDEX
|
||||
OUT_WORD ;set to read from the proper plane for
|
||||
; the pixel
|
||||
lods byte ptr es:[si];read the pixel
|
||||
sub ah,ah ;make the return value a word for C
|
||||
pop di ;restore C register vars
|
||||
pop si
|
||||
pop bp ;restore caller's BP
|
||||
ret
|
||||
_Read360x480Dot endp
|
||||
_TEXT ends
|
||||
end
|
||||
201
tests/pcx86/vga/L32-2.C
Normal file
201
tests/pcx86/vga/L32-2.C
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Sample program to illustrate VGA line drawing in 360x480
|
||||
* 256-color mode.
|
||||
*
|
||||
* Compiled with Borland C/C++.
|
||||
*
|
||||
* Must be linked with Listing 32.1 with a command line like:
|
||||
*
|
||||
* bcc l32-2.c l32-1.asm
|
||||
*
|
||||
* By Michael Abrash
|
||||
*/
|
||||
#include <dos.h> /* contains geninterrupt */
|
||||
|
||||
#define TEXT_MODE 0x03
|
||||
#define BIOS_VIDEO_INT 0x10
|
||||
#define X_MAX 360 /* working screen width */
|
||||
#define Y_MAX 480 /* working screen height */
|
||||
|
||||
extern void Draw360x480Dot();
|
||||
extern void Set360x480Mode();
|
||||
|
||||
/*
|
||||
* Draws a line in octant 0 or 3 ( |DeltaX| >= DeltaY ).
|
||||
* |DeltaX|+1 points are drawn.
|
||||
*/
|
||||
void Octant0(X0, Y0, DeltaX, DeltaY, XDirection, Color)
|
||||
unsigned int X0, Y0; /* coordinates of start of the line */
|
||||
unsigned int DeltaX, DeltaY; /* length of the line */
|
||||
int XDirection; /* 1 if line is drawn left to right,
|
||||
-1 if drawn right to left */
|
||||
int Color; /* color in which to draw line */
|
||||
{
|
||||
int DeltaYx2;
|
||||
int DeltaYx2MinusDeltaXx2;
|
||||
int ErrorTerm;
|
||||
|
||||
/* Set up initial error term and values used inside drawing loop */
|
||||
DeltaYx2 = DeltaY * 2;
|
||||
DeltaYx2MinusDeltaXx2 = DeltaYx2 - (int) ( DeltaX * 2 );
|
||||
ErrorTerm = DeltaYx2 - (int) DeltaX;
|
||||
|
||||
/* Draw the line */
|
||||
Draw360x480Dot(X0, Y0, Color); /* draw the first pixel */
|
||||
while ( DeltaX-- ) {
|
||||
/* See if it's time to advance the Y coordinate */
|
||||
if ( ErrorTerm >= 0 ) {
|
||||
/* Advance the Y coordinate & adjust the error term
|
||||
back down */
|
||||
Y0++;
|
||||
ErrorTerm += DeltaYx2MinusDeltaXx2;
|
||||
} else {
|
||||
/* Add to the error term */
|
||||
ErrorTerm += DeltaYx2;
|
||||
}
|
||||
X0 += XDirection; /* advance the X coordinate */
|
||||
Draw360x480Dot(X0, Y0, Color); /* draw a pixel */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a line in octant 1 or 2 ( |DeltaX| < DeltaY ).
|
||||
* |DeltaY|+1 points are drawn.
|
||||
*/
|
||||
void Octant1(X0, Y0, DeltaX, DeltaY, XDirection, Color)
|
||||
unsigned int X0, Y0; /* coordinates of start of the line */
|
||||
unsigned int DeltaX, DeltaY; /* length of the line */
|
||||
int XDirection; /* 1 if line is drawn left to right,
|
||||
-1 if drawn right to left */
|
||||
int Color; /* color in which to draw line */
|
||||
{
|
||||
int DeltaXx2;
|
||||
int DeltaXx2MinusDeltaYx2;
|
||||
int ErrorTerm;
|
||||
|
||||
/* Set up initial error term and values used inside drawing loop */
|
||||
DeltaXx2 = DeltaX * 2;
|
||||
DeltaXx2MinusDeltaYx2 = DeltaXx2 - (int) ( DeltaY * 2 );
|
||||
ErrorTerm = DeltaXx2 - (int) DeltaY;
|
||||
|
||||
Draw360x480Dot(X0, Y0, Color); /* draw the first pixel */
|
||||
while ( DeltaY-- ) {
|
||||
/* See if it's time to advance the X coordinate */
|
||||
if ( ErrorTerm >= 0 ) {
|
||||
/* Advance the X coordinate & adjust the error term
|
||||
back down */
|
||||
X0 += XDirection;
|
||||
ErrorTerm += DeltaXx2MinusDeltaYx2;
|
||||
} else {
|
||||
/* Add to the error term */
|
||||
ErrorTerm += DeltaXx2;
|
||||
}
|
||||
Y0++; /* advance the Y coordinate */
|
||||
Draw360x480Dot(X0, Y0,Color); /* draw a pixel */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a line on the EGA or VGA.
|
||||
*/
|
||||
void EVGALine(X0, Y0, X1, Y1, Color)
|
||||
int X0, Y0; /* coordinates of one end of the line */
|
||||
int X1, Y1; /* coordinates of the other end of the line */
|
||||
unsigned char Color; /* color in which to draw line */
|
||||
{
|
||||
int DeltaX, DeltaY;
|
||||
int Temp;
|
||||
|
||||
/* Save half the line-drawing cases by swapping Y0 with Y1
|
||||
and X0 with X1 if Y0 is greater than Y1. As a result, DeltaY
|
||||
is always > 0, and only the octant 0-3 cases need to be
|
||||
handled. */
|
||||
if ( Y0 > Y1 ) {
|
||||
Temp = Y0;
|
||||
Y0 = Y1;
|
||||
Y1 = Temp;
|
||||
Temp = X0;
|
||||
X0 = X1;
|
||||
X1 = Temp;
|
||||
}
|
||||
|
||||
/* Handle as four separate cases, for the four octants in which
|
||||
Y1 is greater than Y0 */
|
||||
DeltaX = X1 - X0; /* calculate the length of the line
|
||||
in each coordinate */
|
||||
DeltaY = Y1 - Y0;
|
||||
if ( DeltaX > 0 ) {
|
||||
if ( DeltaX > DeltaY ) {
|
||||
Octant0(X0, Y0, DeltaX, DeltaY, 1, Color);
|
||||
} else {
|
||||
Octant1(X0, Y0, DeltaX, DeltaY, 1, Color);
|
||||
}
|
||||
} else {
|
||||
DeltaX = -DeltaX; /* absolute value of DeltaX */
|
||||
if ( DeltaX > DeltaY ) {
|
||||
Octant0(X0, Y0, DeltaX, DeltaY, -1, Color);
|
||||
} else {
|
||||
Octant1(X0, Y0, DeltaX, DeltaY, -1, Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Subroutine to draw a rectangle full of vectors, of the
|
||||
* specified length and in varying colors, around the
|
||||
* specified rectangle center.
|
||||
*/
|
||||
void VectorsUp(XCenter, YCenter, XLength, YLength)
|
||||
int XCenter, YCenter; /* center of rectangle to fill */
|
||||
int XLength, YLength; /* distance from center to edge
|
||||
of rectangle */
|
||||
{
|
||||
int WorkingX, WorkingY, Color = 1;
|
||||
|
||||
/* Lines from center to top of rectangle */
|
||||
WorkingX = XCenter - XLength;
|
||||
WorkingY = YCenter - YLength;
|
||||
for ( ; WorkingX < ( XCenter + XLength ); WorkingX++ )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color++);
|
||||
|
||||
/* Lines from center to right of rectangle */
|
||||
WorkingX = XCenter + XLength - 1;
|
||||
WorkingY = YCenter - YLength;
|
||||
for ( ; WorkingY < ( YCenter + YLength ); WorkingY++ )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color++);
|
||||
|
||||
/* Lines from center to bottom of rectangle */
|
||||
WorkingX = XCenter + XLength - 1;
|
||||
WorkingY = YCenter + YLength - 1;
|
||||
for ( ; WorkingX >= ( XCenter - XLength ); WorkingX-- )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color++);
|
||||
|
||||
/* Lines from center to left of rectangle */
|
||||
WorkingX = XCenter - XLength;
|
||||
WorkingY = YCenter + YLength - 1;
|
||||
for ( ; WorkingY >= ( YCenter - YLength ); WorkingY-- )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color++);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample program to draw four rectangles full of lines.
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
char temp;
|
||||
|
||||
Set360x480Mode();
|
||||
|
||||
/* Draw each of four rectangles full of vectors */
|
||||
VectorsUp(X_MAX / 4, Y_MAX / 4, X_MAX / 4, Y_MAX / 4, 1);
|
||||
VectorsUp(X_MAX * 3 / 4, Y_MAX / 4, X_MAX / 4, Y_MAX / 4, 2);
|
||||
VectorsUp(X_MAX / 4, Y_MAX * 3 / 4, X_MAX / 4, Y_MAX / 4, 3);
|
||||
VectorsUp(X_MAX * 3 / 4, Y_MAX * 3 / 4, X_MAX / 4, Y_MAX / 4, 4);
|
||||
|
||||
/* Wait for the enter key to be pressed */
|
||||
scanf("%c", &temp);
|
||||
|
||||
/* Back to text mode */
|
||||
_AX = TEXT_MODE;
|
||||
geninterrupt(BIOS_VIDEO_INT);
|
||||
}
|
||||
176
tests/pcx86/vga/L33-1.ASM
Normal file
176
tests/pcx86/vga/L33-1.ASM
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
; Program to demonstrate use of the DAC registers by selecting a
|
||||
; smoothly contiguous set of 256 colors, then filling the screen
|
||||
; with concentric diamonds in all 256 colors so that they blend
|
||||
; into one another to form a continuum of color.
|
||||
;
|
||||
.model small
|
||||
.stack 200h
|
||||
.data
|
||||
|
||||
; Table used to set all 256 DAC entries.
|
||||
;
|
||||
; Table format:
|
||||
; Byte 0: DAC register 0 red value
|
||||
; Byte 1: DAC register 0 green value
|
||||
; Byte 2: DAC register 0 blue value
|
||||
; Byte 3: DAC register 1 red value
|
||||
; Byte 4: DAC register 1 green value
|
||||
; Byte 5: DAC register 1 blue value
|
||||
; :
|
||||
; Byte 765: DAC register 255 red value
|
||||
; Byte 766: DAC register 255 green value
|
||||
; Byte 767: DAC register 255 blue value
|
||||
|
||||
ColorTable label byte
|
||||
|
||||
; The first 64 entries are increasingly dim pure green.
|
||||
X=0
|
||||
REPT 64
|
||||
db 0,63-X,0
|
||||
X=X+1
|
||||
ENDM
|
||||
|
||||
; The next 64 entries are increasingly strong pure blue.
|
||||
X=0
|
||||
REPT 64
|
||||
db 0,0,X
|
||||
X=X+1
|
||||
ENDM
|
||||
|
||||
; The next 64 entries fade through violet to red.
|
||||
X=0
|
||||
REPT 64
|
||||
db X,0,63-X
|
||||
X=X+1
|
||||
ENDM
|
||||
|
||||
; The last 64 entries are increasingly dim pure red.
|
||||
X=0
|
||||
REPT 64
|
||||
db 63-X,0,0
|
||||
X=X+1
|
||||
ENDM
|
||||
|
||||
.code
|
||||
Start:
|
||||
mov ax,0013h ;AH=0 selects set mode function,
|
||||
; AL=13h selects 320x200 256-color
|
||||
int 10h ; mode
|
||||
|
||||
;load the DAC registers with the
|
||||
; color settings
|
||||
mov ax,@data ;point ES to the default
|
||||
mov es,ax ; data segment
|
||||
mov dx,offset ColorTable
|
||||
;point ES:DX to the start of the
|
||||
; block of RGB three-byte values
|
||||
; to load into the DAC registers
|
||||
mov ax,1012h ;AH=10h selects set color function,
|
||||
; AL=12h selects set block of DAC
|
||||
; registers subfunction
|
||||
sub bx,bx ;load the block of registers
|
||||
; starting at DAC register #0
|
||||
mov cx,100h ;set all 256 registers
|
||||
int 10h ;load the DAC registers
|
||||
|
||||
;now fill the screen with
|
||||
; concentric diamonds in all 256
|
||||
; color attributes
|
||||
mov ax,0a000h ;point DS to the display memory
|
||||
mov ds,ax ; segment
|
||||
;
|
||||
;draw diagonal lines in the upper
|
||||
; left quarter of the screen
|
||||
mov al,2 ;start with color attribute #2
|
||||
mov ah,-1 ;cycle down through the colors
|
||||
mov bx,320 ;draw top to bottom (distance from
|
||||
; one line to the next)
|
||||
mov dx,160 ;width of rectangle
|
||||
mov si,100 ;height of rectangle
|
||||
sub di,di ;start at (0,0)
|
||||
mov bp,1 ;draw left to right (distance from
|
||||
; one column to the next)
|
||||
call FillBlock ;draw it
|
||||
;
|
||||
;draw diagonal lines in the upper
|
||||
; right quarter of the screen
|
||||
mov al,2 ;start with color attribute #2
|
||||
mov ah,-1 ;cycle down through the colors
|
||||
mov bx,320 ;draw top to bottom (distance from
|
||||
; one line to the next)
|
||||
mov dx,160 ;width of rectangle
|
||||
mov si,100 ;height of rectangle
|
||||
mov di,319 ;start at (319,0)
|
||||
mov bp,-1 ;draw right to left (distance from
|
||||
; one column to the next)
|
||||
call FillBlock ;draw it
|
||||
|
||||
;draw diagonal lines in the lower
|
||||
; left quarter of the screen
|
||||
mov al,2 ;start with color attribute #2
|
||||
mov ah,-1 ;cycle down through the colors
|
||||
mov bx,-320 ;draw bottom to top (distance from
|
||||
; one line to the next)
|
||||
mov dx,160 ;width of rectangle
|
||||
mov si,100 ;height of rectangle
|
||||
mov di,199*320 ;start at (0,199)
|
||||
mov bp,1 ;draw left to right (distance from
|
||||
; one column to the next)
|
||||
call FillBlock ;draw it
|
||||
;
|
||||
;draw diagonal lines in the lower
|
||||
; right quarter of the screen
|
||||
mov al,2 ;start with color attribute #2
|
||||
mov ah,-1 ;cycle down through the colors
|
||||
mov bx,-320 ;draw bottom to top (distance from
|
||||
; one line to the next)
|
||||
mov dx,160 ;width of rectangle
|
||||
mov si,100 ;height of rectangle
|
||||
mov di,199*320+319 ;start at (319,199)
|
||||
mov bp,-1 ;draw right to left (distance from
|
||||
; one column to the next)
|
||||
call FillBlock ;draw it
|
||||
|
||||
mov ah,1 ;wait for a key
|
||||
int 21h ;
|
||||
|
||||
mov ax,0003h ;return to text mode
|
||||
int 10h ;
|
||||
|
||||
mov ah,4ch ;done--return to DOS
|
||||
int 21h
|
||||
|
||||
; Fills the specified rectangular area of the screen with diagonal
|
||||
; lines.
|
||||
;
|
||||
; Input:
|
||||
; AL = initial attribute with which to draw
|
||||
; AH = amount by which to advance the attribute from
|
||||
; one pixel to the next
|
||||
; BX = distance to advance from one pixel to the next
|
||||
; DX = width of rectangle to fill
|
||||
; SI = height of rectangle to fill
|
||||
; DS:DN = screen address of first pixel to draw
|
||||
; BP = offset from the start of one column to the start of
|
||||
; the next
|
||||
|
||||
FillBlock:
|
||||
FillHorzLoop:
|
||||
push di ;preserve pointer to top of column
|
||||
push ax ;preserve initial attribute
|
||||
mov cx,si ;column height
|
||||
FillVertLoop:
|
||||
mov [di],al ;set the pixel
|
||||
add di,bx ;point to the next row in the column
|
||||
add al,ah ;advance the attribute
|
||||
loop FillVertLoop ;
|
||||
pop ax ;restore initial attribute
|
||||
add al,ah ;advance to the next attribute to
|
||||
; start the next column
|
||||
pop di ;retrieve pointer to top of column
|
||||
add di,bp ;point to next column
|
||||
dec dx ;have we done all columns?
|
||||
jnz FillHorzLoop ;no, do the next column
|
||||
ret ;
|
||||
|
||||
end Start
|
||||
250
tests/pcx86/vga/L34-1.ASM
Normal file
250
tests/pcx86/vga/L34-1.ASM
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
; Fills a band across the screen with vertical bars in all 256
|
||||
; attributes, then cycles a portion of the palette until a key is
|
||||
; pressed.
|
||||
; Assemble with MASM or TASM
|
||||
;
|
||||
USE_BIOS equ 1 ;set to 1 to use BIOS functions to access the
|
||||
; DAC, 0 to read and write the DAC directly
|
||||
GUARD_AGAINST_INTS equ 1 ;1 to turn off interrupts and set write index
|
||||
; before loading each DAC location, 0 to rely
|
||||
; on the DAC auto-incrementing
|
||||
WAIT_VSYNC equ 1 ;set to 1 to wait for the leading edge of
|
||||
; vertical sync before accessing the DAC, 0
|
||||
; not to wait
|
||||
NOT_8088 equ 0 ;set to 1 to use REP INSB and REP OUTSB when
|
||||
; accessing the DAC directly, 0 to use
|
||||
; IN/STOSB and LODSB/OUT
|
||||
CYCLE_SIZE equ 256 ;# of DAC locations to cycle, 256 max
|
||||
SCREEN_SEGMENT equ 0a000h ;mode 13h display memory segment
|
||||
SCREEN_WIDTH_IN_BYTES equ 320 ;# of bytes across the screen in mode 13h
|
||||
INPUT_STATUS_1 equ 03dah ;input status 1 register port
|
||||
DAC_READ_INDEX equ 03c7h ;DAC Read Index register
|
||||
DAC_WRITE_INDEX equ 03c8h ;DAC Write Index register
|
||||
DAC_DATA equ 03c9h ;DAC Data register
|
||||
|
||||
if NOT_8088
|
||||
.286
|
||||
endif ;NOT_8088
|
||||
|
||||
.model small
|
||||
.stack 100h
|
||||
.data
|
||||
;Storage for all 256 DAC locations, organized as one three-byte
|
||||
; (actually three 6-bit values; upper two bits of each byte aren't
|
||||
; significant) RGB triplet per color.
|
||||
PaletteTemp db 256*3 dup(?)
|
||||
.code
|
||||
start:
|
||||
mov ax,@data
|
||||
mov ds,ax
|
||||
|
||||
;Select VGA's standard 256-color graphics mode, mode 13h.
|
||||
mov ax,0013h ;AH = 0: set mode function,
|
||||
int 10h ; AL = 13h: mode # to set
|
||||
|
||||
;Read all 256 DAC locations into PaletteTemp (3 6-bit values, one
|
||||
; each for red, green, and blue, per DAC location).
|
||||
|
||||
if WAIT_VSYNC
|
||||
;Wait for the leading edge of the vertical sync pulse; this ensures
|
||||
; that we read the DAC starting during the vertical non-display
|
||||
; period.
|
||||
mov dx,INPUT_STATUS_1
|
||||
WaitNotVSync: ;wait to be out of vertical sync
|
||||
in al,dx
|
||||
and al,08h
|
||||
jnz WaitNotVSync
|
||||
WaitVSync: ;wait until vertical sync begins
|
||||
in al,dx
|
||||
and al,08h
|
||||
jz WaitVSync
|
||||
endif ;WAIT_VSYNC
|
||||
|
||||
if USE_BIOS
|
||||
mov ax,1017h ;AH = 10h: set DAC function,
|
||||
; AL = 17h: read DAC block subfunction
|
||||
sub bx,bx ;start with DAC location 0
|
||||
mov cx,256 ;read out all 256 locations
|
||||
mov dx,seg PaletteTemp
|
||||
mov es,dx
|
||||
mov dx,offset PaletteTemp ;point ES:DX to array in which
|
||||
; the DAC values are to be stored
|
||||
int 10h ;read the DAC
|
||||
else ;!USE_BIOS
|
||||
if GUARD_AGAINST_INTS
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to load
|
||||
mov di,seg PaletteTemp
|
||||
mov es,di
|
||||
mov di,offset PaletteTemp ;dump the DAC into this array
|
||||
sub ah,ah ;start with DAC location 0
|
||||
DACStoreLoop:
|
||||
mov dx,DAC_READ_INDEX
|
||||
mov al,ah
|
||||
cli
|
||||
out dx,al ;set the DAC location #
|
||||
mov dx,DAC_DATA
|
||||
in al,dx ;get the red component
|
||||
stosb
|
||||
in al,dx ;get the green component
|
||||
stosb
|
||||
in al,dx ;get the blue component
|
||||
stosb
|
||||
sti
|
||||
inc ah
|
||||
loop DACStoreLoop
|
||||
else ;!GUARD_AGAINST_INTS
|
||||
mov dx,DAC_READ_INDEX
|
||||
sub al,al
|
||||
out dx,al ;set the initial DAC location to 0
|
||||
mov di,seg PaletteTemp
|
||||
mov es,di
|
||||
mov di,offset PaletteTemp ;dump the DAC into this array
|
||||
mov dx,DAC_DATA
|
||||
if NOT_8088
|
||||
mov cx,CYCLE_SIZE*3
|
||||
rep insb ;read CYCLE_SIZE DAC locations at once
|
||||
else ;!NOT_8088
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to load
|
||||
DACStoreLoop:
|
||||
in al,dx ;get the red component
|
||||
stosb
|
||||
in al,dx ;get the green component
|
||||
stosb
|
||||
in al,dx ;get the blue component
|
||||
stosb
|
||||
loop DACStoreLoop
|
||||
endif ;NOT_8088
|
||||
endif ;GUARD_AGAINST_INTS
|
||||
endif ;USE_BIOS
|
||||
|
||||
;Draw a series of 1-pixel-wide vertical bars across the screen in
|
||||
; attributes 1 through 255.
|
||||
mov ax,SCREEN_SEGMENT
|
||||
mov es,ax
|
||||
mov di,50*SCREEN_WIDTH_IN_BYTES ;point ES:DI to the start
|
||||
; of line 50 on the screen
|
||||
cld
|
||||
mov dx,100 ;draw 100 lines high
|
||||
RowLoop:
|
||||
mov al,1 ;start each line with attr 1
|
||||
mov cx,SCREEN_WIDTH_IN_BYTES ;do a full line across
|
||||
ColumnLoop:
|
||||
stosb ;draw a pixel
|
||||
add al,1 ;increment the attribute
|
||||
adc al,0 ;if the attribute just turned
|
||||
; over to 0, increment it to 1
|
||||
; because we're not going to
|
||||
; cycle DAC location 0, so
|
||||
; attribute 0 won't change
|
||||
loop ColumnLoop
|
||||
dec dx
|
||||
jnz RowLoop
|
||||
|
||||
;Cycle the specified range of DAC locations until a key is pressed.
|
||||
CycleLoop:
|
||||
;Rotate colors 1-255 one position in the PaletteTemp array;
|
||||
; location 0 is always left unchanged so that the background
|
||||
; and border don't change.
|
||||
push word ptr PaletteTemp+(1*3) ;set aside PaletteTemp
|
||||
push word ptr PaletteTemp+(1*3)+2 ; setting for attr 1
|
||||
mov cx,254
|
||||
mov si,offset PaletteTemp+(2*3)
|
||||
mov di,offset PaletteTemp+(1*3)
|
||||
mov ax,ds
|
||||
mov es,ax
|
||||
mov cx,254*3/2
|
||||
rep movsw ;rotate PaletteTemp settings
|
||||
; for attrs 2 through 255 to
|
||||
; attrs 1 through 254
|
||||
pop bx ;get back original settings
|
||||
pop ax ; for attribute 1 and move
|
||||
stosw ; them to the PaletteTemp
|
||||
mov es:[di],bl ; location for attribute 255
|
||||
|
||||
if WAIT_VSYNC
|
||||
;Wait for the leading edge of the vertical sync pulse; this ensures
|
||||
; that we reload the DAC starting during the vertical non-display
|
||||
; period.
|
||||
mov dx,INPUT_STATUS_1
|
||||
WaitNotVSync2: ;wait to be out of vertical sync
|
||||
in al,dx
|
||||
and al,08h
|
||||
jnz WaitNotVSync2
|
||||
WaitVSync2: ;wait until vertical sync begins
|
||||
in al,dx
|
||||
and al,08h
|
||||
jz WaitVSync2
|
||||
endif ;WAIT_VSYNC
|
||||
|
||||
if USE_BIOS
|
||||
;Set the new, rotated palette.
|
||||
mov ax,1012h ;AH = 10h: set DAC function,
|
||||
; AL = 12h: set DAC block subfunction
|
||||
sub bx,bx ;start with DAC location 0
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to set
|
||||
mov dx,seg PaletteTemp
|
||||
mov es,dx
|
||||
mov dx,offset PaletteTemp ;point ES:DX to array from which
|
||||
; to load the DAC
|
||||
int 10h ;load the DAC
|
||||
else ;!USE_BIOS
|
||||
if GUARD_AGAINST_INTS
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to load
|
||||
mov si,offset PaletteTemp ;load the DAC from this array
|
||||
sub ah,ah ;start with DAC location 0
|
||||
DACLoadLoop:
|
||||
mov dx,DAC_WRITE_INDEX
|
||||
mov al,ah
|
||||
cli
|
||||
out dx,al ;set the DAC location #
|
||||
mov dx,DAC_DATA
|
||||
lodsb
|
||||
out dx,al ;set the red component
|
||||
lodsb
|
||||
out dx,al ;set the green component
|
||||
lodsb
|
||||
out dx,al ;set the blue component
|
||||
sti
|
||||
inc ah
|
||||
loop DACLoadLoop
|
||||
else ;!GUARD_AGAINST_INTS
|
||||
mov dx,DAC_WRITE_INDEX
|
||||
sub al,al
|
||||
out dx,al ;set the initial DAC location to 0
|
||||
mov si,offset PaletteTemp ;load the DAC from this array
|
||||
mov dx,DAC_DATA
|
||||
if NOT_8088
|
||||
mov cx,CYCLE_SIZE*3
|
||||
rep outsb ;load CYCLE_SIZE DAC locations at once
|
||||
else ;!NOT_8088
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to load
|
||||
DACLoadLoop:
|
||||
lodsb
|
||||
out dx,al ;set the red component
|
||||
lodsb
|
||||
out dx,al ;set the green component
|
||||
lodsb
|
||||
out dx,al ;set the blue component
|
||||
loop DACLoadLoop
|
||||
endif ;NOT_8088
|
||||
endif ;GUARD_AGAINST_INTS
|
||||
endif ;USE_BIOS
|
||||
|
||||
;See if a key has been pressed.
|
||||
mov ah,0bh ;DOS check standard input status fn
|
||||
int 21h
|
||||
and al,al ;is a key pending?
|
||||
jz CycleLoop ;no, cycle some more
|
||||
|
||||
;Clear the keypress.
|
||||
mov ah,1 ;DOS keyboard input fn
|
||||
int 21h
|
||||
|
||||
;Restore text mode and done.
|
||||
mov ax,0003h ;AH = 0: set mode function,
|
||||
int 10h ; AL = 03h: mode # to set
|
||||
mov ah,4ch ;DOS terminate process fn
|
||||
int 21h
|
||||
|
||||
end start
|
||||
|
||||
191
tests/pcx86/vga/L35-1.C
Normal file
191
tests/pcx86/vga/L35-1.C
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* C implementation of Bresenham's line drawing algorithm
|
||||
* for the EGA and VGA. Works in modes 0xE, 0xF, 0x10, and 0x12.
|
||||
*
|
||||
* Compiled with Borland C++
|
||||
*
|
||||
* By Michael Abrash
|
||||
*/
|
||||
|
||||
#include <dos.h> /* contains MK_FP macro */
|
||||
#include "regs.h"
|
||||
|
||||
#define EVGA_SCREEN_WIDTH_IN_BYTES 80
|
||||
/* memory offset from start of
|
||||
one row to start of next */
|
||||
#define EVGA_SCREEN_SEGMENT 0xA000
|
||||
/* display memory segment */
|
||||
#define GC_INDEX 0x3CE
|
||||
/* Graphics Controller
|
||||
Index register port */
|
||||
#define GC_DATA 0x3CF
|
||||
/* Graphics Controller
|
||||
Data register port */
|
||||
#define SET_RESET_INDEX 0 /* indexes of needed */
|
||||
#define ENABLE_SET_RESET_INDEX 1 /* Graphics Controller */
|
||||
#define BIT_MASK_INDEX 8 /* registers */
|
||||
|
||||
/*
|
||||
* Draws a dot at (X0,Y0) in whatever color the EGA/VGA hardware is
|
||||
* set up for. Leaves the bit mask set to whatever value the
|
||||
* dot required.
|
||||
*/
|
||||
void EVGADot(X0, Y0)
|
||||
unsigned int X0; /* coordinates at which to draw dot, with */
|
||||
unsigned int Y0; /* (0,0) at the upper left of the screen */
|
||||
{
|
||||
unsigned char far *PixelBytePtr;
|
||||
unsigned char PixelMask;
|
||||
|
||||
/* Calculate the offset in the screen segment of the byte in
|
||||
which the pixel lies */
|
||||
PixelBytePtr = MK_FP(EVGA_SCREEN_SEGMENT,
|
||||
( Y0 * EVGA_SCREEN_WIDTH_IN_BYTES ) + ( X0 / 8 ));
|
||||
|
||||
/* Generate a mask with a 1 bit in the pixel's position within the
|
||||
screen byte */
|
||||
PixelMask = 0x80 >> ( X0 & 0x07 );
|
||||
|
||||
/* Set up the Graphics Controller's Bit Mask register to allow
|
||||
only the bit corresponding to the pixel being drawn to
|
||||
be modified */
|
||||
outportb(GC_INDEX, BIT_MASK_INDEX);
|
||||
outportb(GC_DATA, PixelMask);
|
||||
|
||||
/* Draw the pixel. Because of the operation of the set/reset
|
||||
feature of the EGA/VGA, the value written doesn't matter.
|
||||
The screen byte is ORed in order to perform a read to latch the
|
||||
display memory, then perform a write in order to modify it. */
|
||||
*PixelBytePtr |= 0xFE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a line in octant 0 or 3 ( |DeltaX| >= DeltaY ).
|
||||
*/
|
||||
void Octant0(X0, Y0, DeltaX, DeltaY, XDirection)
|
||||
unsigned int X0, Y0; /* coordinates of start of the line */
|
||||
unsigned int DeltaX, DeltaY; /* length of the line (both > 0) */
|
||||
int XDirection; /* 1 if line is drawn left to right,
|
||||
-1 if drawn right to left */
|
||||
{
|
||||
int DeltaYx2;
|
||||
int DeltaYx2MinusDeltaXx2;
|
||||
int ErrorTerm;
|
||||
|
||||
/* Set up initial error term and values used inside drawing loop */
|
||||
DeltaYx2 = DeltaY * 2;
|
||||
DeltaYx2MinusDeltaXx2 = DeltaYx2 - (int) ( DeltaX * 2 );
|
||||
ErrorTerm = DeltaYx2 - (int) DeltaX;
|
||||
|
||||
/* Draw the line */
|
||||
EVGADot(X0, Y0); /* draw the first pixel */
|
||||
while ( DeltaX-- ) {
|
||||
/* See if it's time to advance the Y coordinate */
|
||||
if ( ErrorTerm >= 0 ) {
|
||||
/* Advance the Y coordinate & adjust the error term
|
||||
back down */
|
||||
Y0++;
|
||||
ErrorTerm += DeltaYx2MinusDeltaXx2;
|
||||
} else {
|
||||
/* Add to the error term */
|
||||
ErrorTerm += DeltaYx2;
|
||||
}
|
||||
X0 += XDirection; /* advance the X coordinate */
|
||||
EVGADot(X0, Y0); /* draw a pixel */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a line in octant 1 or 2 ( |DeltaX| < DeltaY ).
|
||||
*/
|
||||
void Octant1(X0, Y0, DeltaX, DeltaY, XDirection)
|
||||
unsigned int X0, Y0; /* coordinates of start of the line */
|
||||
unsigned int DeltaX, DeltaY; /* length of the line (both > 0) */
|
||||
int XDirection; /* 1 if line is drawn left to right,
|
||||
-1 if drawn right to left */
|
||||
{
|
||||
int DeltaXx2;
|
||||
int DeltaXx2MinusDeltaYx2;
|
||||
int ErrorTerm;
|
||||
|
||||
/* Set up initial error term and values used inside drawing loop */
|
||||
DeltaXx2 = DeltaX * 2;
|
||||
DeltaXx2MinusDeltaYx2 = DeltaXx2 - (int) ( DeltaY * 2 );
|
||||
ErrorTerm = DeltaXx2 - (int) DeltaY;
|
||||
|
||||
EVGADot(X0, Y0); /* draw the first pixel */
|
||||
while ( DeltaY-- ) {
|
||||
/* See if it's time to advance the X coordinate */
|
||||
if ( ErrorTerm >= 0 ) {
|
||||
/* Advance the X coordinate & adjust the error term
|
||||
back down */
|
||||
X0 += XDirection;
|
||||
ErrorTerm += DeltaXx2MinusDeltaYx2;
|
||||
} else {
|
||||
/* Add to the error term */
|
||||
ErrorTerm += DeltaXx2;
|
||||
}
|
||||
Y0++; /* advance the Y coordinate */
|
||||
EVGADot(X0, Y0); /* draw a pixel */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a line on the EGA or VGA.
|
||||
*/
|
||||
void EVGALine(X0, Y0, X1, Y1, Color)
|
||||
int X0, Y0; /* coordinates of one end of the line */
|
||||
int X1, Y1; /* coordinates of the other end of the line */
|
||||
char Color; /* color to draw line in */
|
||||
{
|
||||
int DeltaX, DeltaY;
|
||||
int Temp;
|
||||
|
||||
/* Set the drawing color */
|
||||
|
||||
/* Put the drawing color in the Set/Reset register */
|
||||
outportb(GC_INDEX, SET_RESET_INDEX);
|
||||
outportb(GC_DATA, Color);
|
||||
/* Cause all planes to be forced to the Set/Reset color */
|
||||
outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
|
||||
outportb(GC_DATA, 0xF);
|
||||
|
||||
/* Save half the line-drawing cases by swapping Y0 with Y1
|
||||
and X0 with X1 if Y0 is greater than Y1. As a result, DeltaY
|
||||
is always > 0, and only the octant 0-3 cases need to be
|
||||
handled. */
|
||||
if ( Y0 > Y1 ) {
|
||||
Temp = Y0;
|
||||
Y0 = Y1;
|
||||
Y1 = Temp;
|
||||
Temp = X0;
|
||||
X0 = X1;
|
||||
X1 = Temp;
|
||||
}
|
||||
|
||||
/* Handle as four separate cases, for the four octants in which
|
||||
Y1 is greater than Y0 */
|
||||
DeltaX = X1 - X0; /* calculate the length of the line
|
||||
in each coordinate */
|
||||
DeltaY = Y1 - Y0;
|
||||
if ( DeltaX > 0 ) {
|
||||
if ( DeltaX > DeltaY ) {
|
||||
Octant0(X0, Y0, DeltaX, DeltaY, 1);
|
||||
} else {
|
||||
Octant1(X0, Y0, DeltaX, DeltaY, 1);
|
||||
}
|
||||
} else {
|
||||
DeltaX = -DeltaX; /* absolute value of DeltaX */
|
||||
if ( DeltaX > DeltaY ) {
|
||||
Octant0(X0, Y0, DeltaX, DeltaY, -1);
|
||||
} else {
|
||||
Octant1(X0, Y0, DeltaX, DeltaY, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the state of the EGA/VGA to normal */
|
||||
outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
|
||||
outportb(GC_DATA, 0);
|
||||
outportb(GC_INDEX, BIT_MASK_INDEX);
|
||||
outportb(GC_DATA, 0xFF);
|
||||
}
|
||||
81
tests/pcx86/vga/L35-2.C
Normal file
81
tests/pcx86/vga/L35-2.C
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Sample program to illustrate EGA/VGA line drawing routines.
|
||||
*
|
||||
* Compiled with Borland C++
|
||||
*
|
||||
* By Michael Abrash
|
||||
*/
|
||||
|
||||
#include <dos.h>
|
||||
#include "regs.h"
|
||||
|
||||
#define GRAPHICS_MODE 0x10
|
||||
#define TEXT_MODE 0x03
|
||||
#define BIOS_VIDEO_INT 0x10
|
||||
#define X_MAX 640 /* working screen width */
|
||||
#define Y_MAX 348 /* working screen height */
|
||||
|
||||
extern void EVGALine();
|
||||
|
||||
/*
|
||||
* Subroutine to draw a rectangle full of vectors, of the specified
|
||||
* length and color, around the specified rectangle center.
|
||||
*/
|
||||
void VectorsUp(XCenter, YCenter, XLength, YLength, Color)
|
||||
int XCenter, YCenter; /* center of rectangle to fill */
|
||||
int XLength, YLength; /* distance from center to edge
|
||||
of rectangle */
|
||||
int Color; /* color to draw lines in */
|
||||
{
|
||||
int WorkingX, WorkingY;
|
||||
|
||||
/* Lines from center to top of rectangle */
|
||||
WorkingX = XCenter - XLength;
|
||||
WorkingY = YCenter - YLength;
|
||||
for ( ; WorkingX < ( XCenter + XLength ); WorkingX++ )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);
|
||||
|
||||
/* Lines from center to right of rectangle */
|
||||
WorkingX = XCenter + XLength - 1;
|
||||
WorkingY = YCenter - YLength;
|
||||
for ( ; WorkingY < ( YCenter + YLength ); WorkingY++ )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);
|
||||
|
||||
/* Lines from center to bottom of rectangle */
|
||||
WorkingX = XCenter + XLength - 1;
|
||||
WorkingY = YCenter + YLength - 1;
|
||||
for ( ; WorkingX >= ( XCenter - XLength ); WorkingX-- )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);
|
||||
|
||||
/* Lines from center to left of rectangle */
|
||||
WorkingX = XCenter - XLength;
|
||||
WorkingY = YCenter + YLength - 1;
|
||||
for ( ; WorkingY >= ( YCenter - YLength ); WorkingY-- )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color );
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample program to draw four rectangles full of lines.
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
char temp;
|
||||
|
||||
/* Set graphics mode */
|
||||
USES_REGS;
|
||||
_AX = GRAPHICS_MODE;
|
||||
geninterrupt(BIOS_VIDEO_INT);
|
||||
|
||||
/* Draw each of four rectangles full of vectors */
|
||||
VectorsUp(X_MAX / 4, Y_MAX / 4, X_MAX / 4, Y_MAX / 4, 1);
|
||||
VectorsUp(X_MAX * 3 / 4, Y_MAX / 4, X_MAX / 4, Y_MAX / 4, 2);
|
||||
VectorsUp(X_MAX / 4, Y_MAX * 3 / 4, X_MAX / 4, Y_MAX / 4, 3);
|
||||
VectorsUp(X_MAX * 3 / 4, Y_MAX * 3 / 4, X_MAX / 4, Y_MAX / 4, 4);
|
||||
|
||||
/* Wait for the enter key to be pressed */
|
||||
scanf("%c", &temp);
|
||||
|
||||
/* Back to text mode */
|
||||
_AX = TEXT_MODE;
|
||||
geninterrupt(BIOS_VIDEO_INT);
|
||||
}
|
||||
366
tests/pcx86/vga/L35-3.ASM
Normal file
366
tests/pcx86/vga/L35-3.ASM
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
; Fast assembler implementation of Bresenham's line drawing algorithm
|
||||
; for the EGA and VGA. Works in modes 0Eh, 0Fh, 10h, and 12h.
|
||||
; C near-callable.
|
||||
; Bit mask accumulation technique when |DeltaX| >= |DeltaY|
|
||||
; suggested by Jim Mackraz.
|
||||
;
|
||||
; Assembled with MASM
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
;****************************************************************
|
||||
; C-compatible line-drawing entry point at _EVGALine. *
|
||||
; Near C-callable as: *
|
||||
; EVGALine(X0, Y0, X1, Y1, Color); *
|
||||
;****************************************************************
|
||||
;
|
||||
.model small
|
||||
.code
|
||||
;
|
||||
; Equates.
|
||||
;
|
||||
EVGA_SCREEN_WIDTH_IN_BYTES equ 80 ;memory offset from start of
|
||||
; one row to start of next
|
||||
; in display memory
|
||||
EVGA_SCREEN_SEGMENT equ 0a000h ;display memory segment
|
||||
GC_INDEX equ 3ceh ;Graphics Controller
|
||||
; Index register port
|
||||
SET_RESET_INDEX equ 0 ;indexes of needed
|
||||
ENABLE_SET_RESET_INDEX equ 1 ; Graphics Controller
|
||||
BIT_MASK_INDEX equ 8 ; registers
|
||||
|
||||
;
|
||||
; Stack frame.
|
||||
;
|
||||
EVGALineParms struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;pushed return address (make double
|
||||
; word for far call)
|
||||
X0 dw ? ;starting X coordinate of line
|
||||
Y0 dw ? ;starting Y coordinate of line
|
||||
X1 dw ? ;ending X coordinate of line
|
||||
Y1 dw ? ;ending Y coordinate of line
|
||||
Color db ? ;color of line
|
||||
db ? ;dummy to pad to word size
|
||||
EVGALineParms ends
|
||||
|
||||
;****************************************************************
|
||||
; Line drawing macros. *
|
||||
;****************************************************************
|
||||
|
||||
;
|
||||
; Macro to loop through length of line, drawing each pixel in turn.
|
||||
; Used for case of |DeltaX| >= |DeltaY|.
|
||||
; Input:
|
||||
; MOVE_LEFT: 1 if DeltaX < 0, 0 else
|
||||
; AL: pixel mask for initial pixel
|
||||
; BX: |DeltaX|
|
||||
; DX: address of GC data register, with index register set to
|
||||
; index of Bit Mask register
|
||||
; SI: DeltaY
|
||||
; ES:DI: display memory address of byte containing initial
|
||||
; pixel
|
||||
;
|
||||
LINE1 macro MOVE_LEFT
|
||||
local LineLoop, MoveXCoord, NextPixel, Line1End
|
||||
local MoveToNextByte, ResetBitMaskAccumulator
|
||||
mov cx,bx ;# of pixels in line
|
||||
jcxz Line1End ;done if there are no more pixels
|
||||
; (there's always at least the one pixel
|
||||
; at the start location)
|
||||
shl si,1 ;DeltaY * 2
|
||||
mov bp,si ;error term
|
||||
sub bp,bx ;error term starts at DeltaY * 2 - DeltaX
|
||||
shl bx,1 ;DeltaX * 2
|
||||
sub si,bx ;DeltaY * 2 - DeltaX * 2 (used in loop)
|
||||
add bx,si ;DeltaY * 2 (used in loop)
|
||||
mov ah,al ;set aside pixel mask for initial pixel
|
||||
; with AL (the pixel mask accumulator) set
|
||||
; for the initial pixel
|
||||
LineLoop:
|
||||
;
|
||||
; See if it's time to advance the Y coordinate yet.
|
||||
;
|
||||
and bp,bp ;see if error term is negative
|
||||
js MoveXCoord ;yes, stay at the same Y coordinate
|
||||
;
|
||||
; Advance the Y coordinate, first writing all pixels in the current
|
||||
; byte, then move the pixel mask either left or right, depending
|
||||
; on MOVE_LEFT.
|
||||
;
|
||||
out dx,al ;set up bit mask for pixels in this byte
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
add di,EVGA_SCREEN_WIDTH_IN_BYTES ;increment Y coordinate
|
||||
add bp,si ;adjust error term back down
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address when pixel mask wraps.
|
||||
;
|
||||
if MOVE_LEFT
|
||||
rol ah,1 ;move pixel mask 1 pixel to the left
|
||||
else
|
||||
ror ah,1 ;move pixel mask 1 pixel to the right
|
||||
endif
|
||||
jnc ResetBitMaskAccumulator ;didn't wrap to next byte
|
||||
jmp short MoveToNextByte ;did wrap to next byte
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address and writing pixels
|
||||
; in this byte when pixel mask wraps.
|
||||
;
|
||||
MoveXCoord:
|
||||
add bp,bx ;increment error term & keep same
|
||||
if MOVE_LEFT
|
||||
rol ah,1 ;move pixel mask 1 pixel to the left
|
||||
else
|
||||
ror ah,1 ;move pixel mask 1 pixel to the right
|
||||
endif
|
||||
jnc NextPixel ;if still in same byte, no need to
|
||||
; modify display memory yet
|
||||
out dx,al ;set up bit mask for pixels in this byte.
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
MoveToNextByte:
|
||||
if MOVE_LEFT
|
||||
dec di ;next pixel is in byte to left
|
||||
else
|
||||
inc di ;next pixel is in byte to right
|
||||
endif
|
||||
ResetBitMaskAccumulator:
|
||||
sub al,al ;reset pixel mask accumulator
|
||||
NextPixel:
|
||||
or al,ah ;add the next pixel to the pixel mask
|
||||
; accumulator
|
||||
loop LineLoop
|
||||
;
|
||||
; Write the pixels in the final byte.
|
||||
;
|
||||
Line1End:
|
||||
out dx,al ;set up bit mask for pixels in this byte.
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
endm
|
||||
|
||||
;
|
||||
; Macro to loop through length of line, drawing each pixel in turn.
|
||||
; Used for case of DeltaX < DeltaY.
|
||||
; Input:
|
||||
; MOVE_LEFT: 1 if DeltaX < 0, 0 else
|
||||
; AL: pixel mask for initial pixel
|
||||
; BX: |DeltaX|
|
||||
; DX: address of GC data register, with index register set to
|
||||
; index of Bit Mask register
|
||||
; SI: DeltaY
|
||||
; ES:DI: display memory address of byte containing initial
|
||||
; pixel
|
||||
;
|
||||
LINE2 macro MOVE_LEFT
|
||||
local LineLoop, MoveYCoord, ETermAction, Line2End
|
||||
mov cx,si ;# of pixels in line
|
||||
jcxz Line2End ;done if there are no more pixels
|
||||
shl bx,1 ;DeltaX * 2
|
||||
mov bp,bx ;error term
|
||||
sub bp,si ;error term starts at DeltaX * 2 - DeltaY
|
||||
shl si,1 ;DeltaY * 2
|
||||
sub bx,si ;DeltaX * 2 - DeltaY * 2 (used in loop)
|
||||
add si,bx ;DeltaX * 2 (used in loop)
|
||||
;
|
||||
; Set up initial bit mask & write initial pixel.
|
||||
;
|
||||
out dx,al
|
||||
xchg byte ptr [di],ah
|
||||
;load latches and write pixel, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
LineLoop:
|
||||
;
|
||||
; See if it's time to advance the X coordinate yet.
|
||||
;
|
||||
and bp,bp ;see if error term is negative
|
||||
jns ETermAction ;no, advance X coordinate
|
||||
add bp,si ;increment error term & keep same
|
||||
jmp short MoveYCoord; X coordinate
|
||||
ETermAction:
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address when pixel mask wraps.
|
||||
;
|
||||
if MOVE_LEFT
|
||||
rol al,1
|
||||
sbb di,0
|
||||
else
|
||||
ror al,1
|
||||
adc di,0
|
||||
endif
|
||||
out dx,al ;set new bit mask
|
||||
add bp,bx ;adjust error term back down
|
||||
;
|
||||
; Advance Y coordinate.
|
||||
;
|
||||
MoveYCoord:
|
||||
add di,EVGA_SCREEN_WIDTH_IN_BYTES
|
||||
;
|
||||
; Write the next pixel.
|
||||
;
|
||||
xchg byte ptr [di],ah
|
||||
;load latches and write pixel, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
;
|
||||
loop LineLoop
|
||||
Line2End:
|
||||
endm
|
||||
|
||||
;****************************************************************
|
||||
; Line drawing routine. *
|
||||
;****************************************************************
|
||||
|
||||
public _EVGALine
|
||||
_EVGALine proc near
|
||||
push bp
|
||||
mov bp,sp
|
||||
push si ;preserve register variables
|
||||
push di
|
||||
push ds
|
||||
;
|
||||
; Point DS to display memory.
|
||||
;
|
||||
mov ax,EVGA_SCREEN_SEGMENT
|
||||
mov ds,ax
|
||||
;
|
||||
; Set the Set/Reset and Set/Reset Enable registers for
|
||||
; the selected color.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,[bp+Color]
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,ENABLE_SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,0ffh
|
||||
out dx,al
|
||||
;
|
||||
; Get DeltaY.
|
||||
;
|
||||
mov si,[bp+Y1] ;line Y start
|
||||
mov ax,[bp+Y0] ;line Y end, used later in
|
||||
;calculating the start address
|
||||
sub si,ax ;calculate DeltaY
|
||||
jns CalcStartAddress;if positive, we're set
|
||||
;
|
||||
; DeltaY is negative -- swap coordinates so we're always working
|
||||
; with a positive DeltaY.
|
||||
;
|
||||
mov ax,[bp+Y1] ;set line start to Y1, for use
|
||||
; in calculating the start address
|
||||
mov dx,[bp+X0]
|
||||
xchg dx,[bp+X1]
|
||||
mov [bp+X0],dx ;swap X coordinates
|
||||
neg si ;convert to positive DeltaY
|
||||
;
|
||||
; Calculate the starting address in display memory of the line.
|
||||
; Hardwired for a screen width of 80 bytes.
|
||||
;
|
||||
CalcStartAddress:
|
||||
shl ax,1 ;Y0 * 2 ;Y0 is already in AX
|
||||
shl ax,1 ;Y0 * 4
|
||||
shl ax,1 ;Y0 * 8
|
||||
shl ax,1 ;Y0 * 16
|
||||
mov di,ax
|
||||
shl ax,1 ;Y0 * 32
|
||||
shl ax,1 ;Y0 * 64
|
||||
add di,ax ;Y0 * 80
|
||||
mov dx,[bp+X0]
|
||||
mov cl,dl ;set aside lower 3 bits of column for
|
||||
and cl,7 ; pixel masking
|
||||
shr dx,1
|
||||
shr dx,1
|
||||
shr dx,1 ;get byte address of column (X0/8)
|
||||
add di,dx ;offset of line start in display segment
|
||||
;
|
||||
; Set up GC Index register to point to the Bit Mask register.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,BIT_MASK_INDEX
|
||||
out dx,al
|
||||
inc dx ;leave DX pointing to the GC Data register
|
||||
;
|
||||
; Set up pixel mask (in-byte pixel address).
|
||||
;
|
||||
mov al,80h
|
||||
shr al,cl
|
||||
;
|
||||
; Calculate DeltaX.
|
||||
;
|
||||
mov bx,[bp+X1]
|
||||
sub bx,[bp+X0]
|
||||
;
|
||||
; Handle correct one of four octants.
|
||||
;
|
||||
js NegDeltaX
|
||||
cmp bx,si
|
||||
jb Octant1
|
||||
;
|
||||
; DeltaX >= DeltaY >= 0.
|
||||
;
|
||||
LINE1 0
|
||||
jmp EVGALineDone
|
||||
;
|
||||
; DeltaY > DeltaX >= 0.
|
||||
;
|
||||
Octant1:
|
||||
LINE2 0
|
||||
jmp short EVGALineDone
|
||||
;
|
||||
NegDeltaX:
|
||||
neg bx ;|DeltaX|
|
||||
cmp bx,si
|
||||
jb Octant2
|
||||
;
|
||||
; |DeltaX| >= DeltaY and DeltaX < 0.
|
||||
;
|
||||
LINE1 1
|
||||
jmp short EVGALineDone
|
||||
;
|
||||
; |DeltaX| < DeltaY and DeltaX < 0.
|
||||
;
|
||||
Octant2:
|
||||
LINE2 1
|
||||
;
|
||||
EVGALineDone:
|
||||
;
|
||||
; Restore EVGA state.
|
||||
;
|
||||
mov al,0ffh
|
||||
out dx,al ;set Bit Mask register to 0ffh
|
||||
dec dx
|
||||
mov al,ENABLE_SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
sub al,al
|
||||
out dx,al ;set Enable Set/Reset register to 0
|
||||
;
|
||||
pop ds
|
||||
pop di
|
||||
pop si
|
||||
pop bp
|
||||
ret
|
||||
_EVGALine endp
|
||||
|
||||
end
|
||||
131
tests/pcx86/vga/L42-1.C
Normal file
131
tests/pcx86/vga/L42-1.C
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/* Function to draw an antialiased line from (X0,Y0) to (X1,Y1), using an
|
||||
* antialiasing approach published by Xiaolin Wu in the July 1991 issue of
|
||||
* Computer Graphics. Requires that the palette be set up so that there
|
||||
* are NumLevels intensity levels of the desired drawing color, starting at
|
||||
* color BaseColor (100% intensity) and followed by (NumLevels-1) levels of
|
||||
* evenly decreasing intensity, with color (BaseColor+NumLevels-1) being 0%
|
||||
* intensity of the desired drawing color (black). This code is suitable for
|
||||
* use at screen resolutions, with lines typically no more than 1K long; for
|
||||
* longer lines, 32-bit error arithmetic must be used to avoid problems with
|
||||
* fixed-point inaccuracy. No clipping is performed in DrawWuLine; it must be
|
||||
* performed either at a higher level or in the DrawPixel function.
|
||||
* Tested with Borland C++ in C compilation mode and the small model.
|
||||
*/
|
||||
extern void DrawPixel(int, int, int);
|
||||
|
||||
/* Wu antialiased line drawer.
|
||||
* (X0,Y0),(X1,Y1) = line to draw
|
||||
* BaseColor = color # of first color in block used for antialiasing, the
|
||||
* 100% intensity version of the drawing color
|
||||
* NumLevels = size of color block, with BaseColor+NumLevels-1 being the
|
||||
* 0% intensity version of the drawing color
|
||||
* IntensityBits = log base 2 of NumLevels; the # of bits used to describe
|
||||
* the intensity of the drawing color. 2**IntensityBits==NumLevels
|
||||
*/
|
||||
void DrawWuLine(int X0, int Y0, int X1, int Y1, int BaseColor, int NumLevels, unsigned int IntensityBits)
|
||||
{
|
||||
unsigned int IntensityShift, ErrorAdj, ErrorAcc;
|
||||
unsigned int ErrorAccTemp, Weighting, WeightingComplementMask;
|
||||
int DeltaX, DeltaY, Temp, XDir;
|
||||
|
||||
/* Make sure the line runs top to bottom */
|
||||
if (Y0 > Y1) {
|
||||
Temp = Y0; Y0 = Y1; Y1 = Temp;
|
||||
Temp = X0; X0 = X1; X1 = Temp;
|
||||
}
|
||||
/* Draw the initial pixel, which is always exactly intersected by
|
||||
the line and so needs no weighting */
|
||||
DrawPixel(X0, Y0, BaseColor);
|
||||
|
||||
if ((DeltaX = X1 - X0) >= 0) {
|
||||
XDir = 1;
|
||||
} else {
|
||||
XDir = -1;
|
||||
DeltaX = -DeltaX; /* make DeltaX positive */
|
||||
}
|
||||
/* Special-case horizontal, vertical, and diagonal lines, which
|
||||
require no weighting because they go right through the center of
|
||||
every pixel */
|
||||
if ((DeltaY = Y1 - Y0) == 0) {
|
||||
/* Horizontal line */
|
||||
while (DeltaX-- != 0) {
|
||||
X0 += XDir;
|
||||
DrawPixel(X0, Y0, BaseColor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (DeltaX == 0) {
|
||||
/* Vertical line */
|
||||
do {
|
||||
Y0++;
|
||||
DrawPixel(X0, Y0, BaseColor);
|
||||
} while (--DeltaY != 0);
|
||||
return;
|
||||
}
|
||||
if (DeltaX == DeltaY) {
|
||||
/* Diagonal line */
|
||||
do {
|
||||
X0 += XDir;
|
||||
Y0++;
|
||||
DrawPixel(X0, Y0, BaseColor);
|
||||
} while (--DeltaY != 0);
|
||||
return;
|
||||
}
|
||||
/* Line is not horizontal, diagonal, or vertical */
|
||||
ErrorAcc = 0; /* initialize the line error accumulator to 0 */
|
||||
/* # of bits by which to shift ErrorAcc to get intensity level */
|
||||
IntensityShift = 16 - IntensityBits;
|
||||
/* Mask used to flip all bits in an intensity weighting, producing the
|
||||
result (1 - intensity weighting) */
|
||||
WeightingComplementMask = NumLevels - 1;
|
||||
/* Is this an X-major or Y-major line? */
|
||||
if (DeltaY > DeltaX) {
|
||||
/* Y-major line; calculate 16-bit fixed-point fractional part of a
|
||||
pixel that X advances each time Y advances 1 pixel, truncating the
|
||||
result so that we won't overrun the endpoint along the X axis */
|
||||
ErrorAdj = ((unsigned long) DeltaX << 16) / (unsigned long) DeltaY;
|
||||
/* Draw all pixels other than the first and last */
|
||||
while (--DeltaY) {
|
||||
ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
|
||||
ErrorAcc += ErrorAdj; /* calculate error for next pixel */
|
||||
if (ErrorAcc <= ErrorAccTemp) {
|
||||
/* The error accumulator turned over, so advance the X coord */
|
||||
X0 += XDir;
|
||||
}
|
||||
Y0++; /* Y-major, so always advance Y */
|
||||
/* The IntensityBits most significant bits of ErrorAcc give us the
|
||||
intensity weighting for this pixel, and the complement of the
|
||||
weighting for the paired pixel */
|
||||
Weighting = ErrorAcc >> IntensityShift;
|
||||
DrawPixel(X0, Y0, BaseColor + Weighting);
|
||||
DrawPixel(X0 + XDir, Y0, BaseColor + (Weighting ^ WeightingComplementMask));
|
||||
}
|
||||
/* Draw the final pixel, which is always exactly intersected by the line
|
||||
and so needs no weighting */
|
||||
DrawPixel(X1, Y1, BaseColor);
|
||||
return;
|
||||
}
|
||||
/* It's an X-major line; calculate 16-bit fixed-point fractional part of a
|
||||
pixel that Y advances each time X advances 1 pixel, truncating the
|
||||
result to avoid overrunning the endpoint along the X axis */
|
||||
ErrorAdj = ((unsigned long) DeltaY << 16) / (unsigned long) DeltaX;
|
||||
/* Draw all pixels other than the first and last */
|
||||
while (--DeltaX) {
|
||||
ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
|
||||
ErrorAcc += ErrorAdj; /* calculate error for next pixel */
|
||||
if (ErrorAcc <= ErrorAccTemp) {
|
||||
/* The error accumulator turned over, so advance the Y coord */
|
||||
Y0++;
|
||||
}
|
||||
X0 += XDir; /* X-major, so always advance X */
|
||||
/* The IntensityBits most significant bits of ErrorAcc give us the
|
||||
intensity weighting for this pixel, and the complement of the
|
||||
weighting for the paired pixel */
|
||||
Weighting = ErrorAcc >> IntensityShift;
|
||||
DrawPixel(X0, Y0, BaseColor + Weighting);
|
||||
DrawPixel(X0, Y0 + 1, BaseColor + (Weighting ^ WeightingComplementMask));
|
||||
}
|
||||
/* Draw the final pixel, which is always exactly intersected by the line
|
||||
and so needs no weighting */
|
||||
DrawPixel(X1, Y1, BaseColor);
|
||||
}
|
||||
124
tests/pcx86/vga/L42-2.C
Normal file
124
tests/pcx86/vga/L42-2.C
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/* Sample line-drawing program to demonstrate Wu antialiasing. Also draws
|
||||
* non-antialiased lines for comparison.
|
||||
* Tested with Borland C++ in C compilation mode and the small model.
|
||||
*/
|
||||
#include <dos.h>
|
||||
#include <conio.h>
|
||||
|
||||
void SetPalette(struct WuColor *);
|
||||
extern void DrawWuLine(int, int, int, int, int, int, unsigned int);
|
||||
extern void DrawLine(int, int, int, int, int);
|
||||
extern void SetMode(void);
|
||||
extern int ScreenWidthInPixels; /* screen dimension globals */
|
||||
extern int ScreenHeightInPixels;
|
||||
|
||||
#define NUM_WU_COLORS 2 /* # of colors we'll do antialiased drawing with */
|
||||
struct WuColor { /* describes one color used for antialiasing */
|
||||
int BaseColor; /* # of start of palette intensity block in DAC */
|
||||
int NumLevels; /* # of intensity levels */
|
||||
int IntensityBits; /* IntensityBits == log2 NumLevels */
|
||||
int MaxRed; /* red component of color at full intensity */
|
||||
int MaxGreen; /* green component of color at full intensity */
|
||||
int MaxBlue; /* blue component of color at full intensity */
|
||||
};
|
||||
enum {WU_BLUE=0, WU_WHITE=1}; /* drawing colors */
|
||||
struct WuColor WuColors[NUM_WU_COLORS] = /* blue and white */
|
||||
{{192, 32, 5, 0, 0, 0x3F}, {224, 32, 5, 0x3F, 0x3F, 0x3F}};
|
||||
|
||||
void main()
|
||||
{
|
||||
int CurrentColor, i;
|
||||
union REGS regset;
|
||||
|
||||
/* Draw Wu-antialiased lines in all directions */
|
||||
SetMode();
|
||||
SetPalette(WuColors);
|
||||
for (i=5; i<ScreenWidthInPixels; i += 10) {
|
||||
DrawWuLine(ScreenWidthInPixels/2-ScreenWidthInPixels/10+i/5,
|
||||
ScreenHeightInPixels/5, i, ScreenHeightInPixels-1,
|
||||
WuColors[WU_BLUE].BaseColor, WuColors[WU_BLUE].NumLevels,
|
||||
WuColors[WU_BLUE].IntensityBits);
|
||||
}
|
||||
for (i=0; i<ScreenHeightInPixels; i += 10) {
|
||||
DrawWuLine(ScreenWidthInPixels/2-ScreenWidthInPixels/10, i/5, 0, i,
|
||||
WuColors[WU_BLUE].BaseColor, WuColors[WU_BLUE].NumLevels,
|
||||
WuColors[WU_BLUE].IntensityBits);
|
||||
}
|
||||
for (i=0; i<ScreenHeightInPixels; i += 10) {
|
||||
DrawWuLine(ScreenWidthInPixels/2+ScreenWidthInPixels/10, i/5,
|
||||
ScreenWidthInPixels-1, i, WuColors[WU_BLUE].BaseColor,
|
||||
WuColors[WU_BLUE].NumLevels, WuColors[WU_BLUE].IntensityBits);
|
||||
}
|
||||
for (i=0; i<ScreenWidthInPixels; i += 10) {
|
||||
DrawWuLine(ScreenWidthInPixels/2-ScreenWidthInPixels/10+i/5,
|
||||
ScreenHeightInPixels, i, 0, WuColors[WU_WHITE].BaseColor,
|
||||
WuColors[WU_WHITE].NumLevels,
|
||||
WuColors[WU_WHITE].IntensityBits);
|
||||
}
|
||||
getch(); /* wait for a key press */
|
||||
|
||||
/* Now clear the screen and draw non-antialiased lines */
|
||||
SetMode();
|
||||
SetPalette(WuColors);
|
||||
for (i=0; i<ScreenWidthInPixels; i += 10) {
|
||||
DrawLine(ScreenWidthInPixels/2-ScreenWidthInPixels/10+i/5,
|
||||
ScreenHeightInPixels/5, i, ScreenHeightInPixels-1,
|
||||
WuColors[WU_BLUE].BaseColor);
|
||||
}
|
||||
for (i=0; i<ScreenHeightInPixels; i += 10) {
|
||||
DrawLine(ScreenWidthInPixels/2-ScreenWidthInPixels/10, i/5, 0, i,
|
||||
WuColors[WU_BLUE].BaseColor);
|
||||
}
|
||||
for (i=0; i<ScreenHeightInPixels; i += 10) {
|
||||
DrawLine(ScreenWidthInPixels/2+ScreenWidthInPixels/10, i/5,
|
||||
ScreenWidthInPixels-1, i, WuColors[WU_BLUE].BaseColor);
|
||||
}
|
||||
for (i=0; i<ScreenWidthInPixels; i += 10) {
|
||||
DrawLine(ScreenWidthInPixels/2-ScreenWidthInPixels/10+i/5,
|
||||
ScreenHeightInPixels, i, 0, WuColors[WU_WHITE].BaseColor);
|
||||
}
|
||||
getch(); /* wait for a key press */
|
||||
|
||||
regset.x.ax = 0x0003; /* AL = 3 selects 80x25 text mode */
|
||||
int86(0x10, ®set, ®set); /* return to text mode */
|
||||
}
|
||||
|
||||
/* Sets up the palette for antialiasing with the specified colors.
|
||||
* Intensity steps for each color are scaled from the full desired intensity
|
||||
* of the red, green, and blue components for that color down to 0%
|
||||
* intensity; each step is rounded to the nearest integer. Colors are
|
||||
* corrected for a gamma of 2.3. The values that the palette is programmed
|
||||
* with are hardwired for the VGA's 6 bit per color DAC.
|
||||
*/
|
||||
void SetPalette(struct WuColor * WColors)
|
||||
{
|
||||
int i, j;
|
||||
union REGS regset;
|
||||
struct SREGS sregset;
|
||||
static unsigned char PaletteBlock[256][3]; /* 256 RGB entries */
|
||||
/* Gamma-corrected DAC color components for 64 linear levels from 0% to 100% intensity */
|
||||
static unsigned char GammaTable[] = {
|
||||
0, 10, 14, 17, 19, 21, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34,
|
||||
35, 36, 37, 37, 38, 39, 40, 41, 41, 42, 43, 44, 44, 45, 46, 46,
|
||||
47, 48, 48, 49, 49, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55,
|
||||
56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63};
|
||||
|
||||
for (i=0; i<NUM_WU_COLORS; i++) {
|
||||
for (j=0; j<WColors[i].NumLevels; j++) {
|
||||
PaletteBlock[j][0] = GammaTable[((double)WColors[i].MaxRed * (1.0 -
|
||||
(double)j / (double)(WColors[i].NumLevels - 1))) + 0.5];
|
||||
PaletteBlock[j][1] = GammaTable[((double)WColors[i].MaxGreen * (1.0 -
|
||||
(double)j / (double)(WColors[i].NumLevels - 1))) + 0.5];
|
||||
PaletteBlock[j][2] = GammaTable[((double)WColors[i].MaxBlue * (1.0 -
|
||||
(double)j / (double)(WColors[i].NumLevels - 1))) + 0.5];
|
||||
}
|
||||
/* Now set up the palette to do Wu antialiasing for this color */
|
||||
regset.x.ax = 0x1012; /* set block of DAC registers function */
|
||||
regset.x.bx = WColors[i].BaseColor; /* first DAC location to load */
|
||||
regset.x.cx = WColors[i].NumLevels; /* # of DAC locations to load */
|
||||
regset.x.dx = (unsigned int)PaletteBlock; /* offset of array from which
|
||||
to load RGB settings */
|
||||
sregset.es = _DS; /* segment of array from which to load settings */
|
||||
int86x(0x10, ®set, ®set, &sregset); /* load the palette block */
|
||||
}
|
||||
}
|
||||
29
tests/pcx86/vga/L42-3.C
Normal file
29
tests/pcx86/vga/L42-3.C
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* VGA mode 13h pixel-drawing and mode set functions.
|
||||
* Tested with Borland C++ in C compilation mode and the small model.
|
||||
*/
|
||||
#include <dos.h>
|
||||
|
||||
/* Screen dimension globals, used in main program to scale. */
|
||||
int ScreenWidthInPixels = 320;
|
||||
int ScreenHeightInPixels = 200;
|
||||
|
||||
/* Mode 13h draw pixel function. */
|
||||
void DrawPixel(int X, int Y, int Color)
|
||||
{
|
||||
#define SCREEN_SEGMENT 0xA000
|
||||
unsigned char far *ScreenPtr;
|
||||
|
||||
FP_SEG(ScreenPtr) = SCREEN_SEGMENT;
|
||||
FP_OFF(ScreenPtr) = (unsigned int) Y * ScreenWidthInPixels + X;
|
||||
*ScreenPtr = Color;
|
||||
}
|
||||
|
||||
/* Mode 13h mode-set function. */
|
||||
void SetMode()
|
||||
{
|
||||
union REGS regset;
|
||||
|
||||
/* Set to 320x200 256-color graphics mode */
|
||||
regset.x.ax = 0x0013;
|
||||
int86(0x10, ®set, ®set);
|
||||
}
|
||||
64
tests/pcx86/vga/L42-4.C
Normal file
64
tests/pcx86/vga/L42-4.C
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* Function to draw a non-antialiased line from (X0,Y0) to (X1,Y1), using a
|
||||
* simple fixed-point error accumulation approach.
|
||||
* Tested with Borland C++ in C compilation mode and the small model.
|
||||
*/
|
||||
extern void DrawPixel(int, int, int);
|
||||
|
||||
/* Non-antialiased line drawer.
|
||||
* (X0,Y0),(X1,Y1) = line to draw, Color = color in which to draw
|
||||
*/
|
||||
void DrawLine(int X0, int Y0, int X1, int Y1, int Color)
|
||||
{
|
||||
unsigned long ErrorAcc, ErrorAdj;
|
||||
int DeltaX, DeltaY, XDir, Temp;
|
||||
|
||||
/* Make sure the line runs top to bottom */
|
||||
if (Y0 > Y1) {
|
||||
Temp = Y0; Y0 = Y1; Y1 = Temp;
|
||||
Temp = X0; X0 = X1; X1 = Temp;
|
||||
}
|
||||
DrawPixel(X0, Y0, Color); /* draw the initial pixel */
|
||||
if ((DeltaX = X1 - X0) >= 0) {
|
||||
XDir = 1;
|
||||
} else {
|
||||
XDir = -1;
|
||||
DeltaX = -DeltaX; /* make DeltaX positive */
|
||||
}
|
||||
if ((DeltaY = Y1 - Y0) == 0) /* done if only one point in the line */
|
||||
if (DeltaX == 0) return;
|
||||
|
||||
ErrorAcc = 0x8000; /* initialize line error accumulator to .5, so we can
|
||||
advance when we get halfway to the next pixel */
|
||||
/* Is this an X-major or Y-major line? */
|
||||
if (DeltaY > DeltaX) {
|
||||
/* Y-major line; calculate 16-bit fixed-point fractional part of a
|
||||
pixel that X advances each time Y advances 1 pixel */
|
||||
ErrorAdj = ((((unsigned long)DeltaX << 17) / (unsigned long)DeltaY) + 1) >> 1;
|
||||
/* Draw all pixels between the first and last */
|
||||
do {
|
||||
ErrorAcc += ErrorAdj; /* calculate error for this pixel */
|
||||
if (ErrorAcc & ~0xFFFFL) {
|
||||
/* The error accumulator turned over, so advance the X coord */
|
||||
X0 += XDir;
|
||||
ErrorAcc &= 0xFFFFL; /* clear integer part of result */
|
||||
}
|
||||
Y0++; /* Y-major, so always advance Y */
|
||||
DrawPixel(X0, Y0, Color);
|
||||
} while (--DeltaY);
|
||||
return;
|
||||
}
|
||||
/* It's an X-major line; calculate 16-bit fixed-point fractional part of a
|
||||
pixel that Y advances each time X advances 1 pixel */
|
||||
ErrorAdj = ((((unsigned long)DeltaY << 17) / (unsigned long)DeltaX) + 1) >> 1;
|
||||
/* Draw all remaining pixels */
|
||||
do {
|
||||
ErrorAcc += ErrorAdj; /* calculate error for this pixel */
|
||||
if (ErrorAcc & ~0xFFFFL) {
|
||||
/* The error accumulator turned over, so advance the Y coord */
|
||||
Y0++;
|
||||
ErrorAcc &= 0xFFFFL; /* clear integer part of result */
|
||||
}
|
||||
X0 += XDir; /* X-major, so always advance X */
|
||||
DrawPixel(X0, Y0, Color);
|
||||
} while (--DeltaX);
|
||||
}
|
||||
40
tests/pcx86/vga/L42-5.C
Normal file
40
tests/pcx86/vga/L42-5.C
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* Mode set and pixel-drawing functions for the 640x480 256-color mode of
|
||||
* Tseng Labs ET4000-based SuperVGAs.
|
||||
* Tested with Borland C++ in C compilation mode and the small model.
|
||||
*/
|
||||
#include <dos.h>
|
||||
|
||||
/* Screen dimension globals, used in main program to scale */
|
||||
int ScreenWidthInPixels = 640;
|
||||
int ScreenHeightInPixels = 480;
|
||||
|
||||
/* ET4000 640x480 256-color draw pixel function. */
|
||||
void DrawPixel(int X, int Y, int Color)
|
||||
{
|
||||
#define SCREEN_SEGMENT 0xA000
|
||||
#define GC_SEGMENT_SELECT 0x3CD /* ET4000 segment (bank) select reg */
|
||||
unsigned char far *ScreenPtr;
|
||||
unsigned int Bank;
|
||||
unsigned long BitmapAddress;
|
||||
|
||||
/* Full bitmap address of pixel, as measured from address 0 to 0xFFFFF */
|
||||
BitmapAddress = (unsigned long) Y * ScreenWidthInPixels + X;
|
||||
/* Bank # is upper word of bitmap addr */
|
||||
Bank = BitmapAddress >> 16;
|
||||
/* Upper nibble is read bank #, lower nibble is write bank # */
|
||||
outp(GC_SEGMENT_SELECT, (Bank << 4) | Bank);
|
||||
/* Draw into the bank */
|
||||
FP_SEG(ScreenPtr) = SCREEN_SEGMENT;
|
||||
FP_OFF(ScreenPtr) = (unsigned int) BitmapAddress;
|
||||
*ScreenPtr = Color;
|
||||
}
|
||||
|
||||
/* ET4000 640x480 256-color mode-set function. */
|
||||
void SetMode()
|
||||
{
|
||||
union REGS regset;
|
||||
|
||||
/* Set to 640x480 256-color graphics mode */
|
||||
regset.x.ax = 0x002E;
|
||||
int86(0x10, ®set, ®set);
|
||||
}
|
||||
269
tests/pcx86/vga/L42-6.ASM
Normal file
269
tests/pcx86/vga/L42-6.ASM
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
; C near-callable function to draw an antialiased line from
|
||||
; (X0,Y0) to (X1,Y1), in mode 13h, the VGA's standard 320x200 256-color
|
||||
; mode. Uses an antialiasing approach published by Xiaolin Wu in the July
|
||||
; 1991 issue of Computer Graphics. Requires that the palette be set up so
|
||||
; that there are NumLevels intensity levels of the desired drawing color,
|
||||
; starting at color BaseColor (100% intensity) and followed by (NumLevels-1)
|
||||
; levels of evenly decreasing intensity, with color (BaseColor+NumLevels-1)
|
||||
; being 0% intensity of the desired drawing color (black). No clipping is
|
||||
; performed in DrawWuLine. Handles a maximum of 256 intensity levels per
|
||||
; antialiased color. This code is suitable for use at screen resolutions,
|
||||
; with lines typically no more than 1K long; for longer lines, 32-bit error
|
||||
; arithmetic must be used to avoid problems with fixed-point inaccuracy.
|
||||
; Tested with TASM.
|
||||
;
|
||||
; C near-callable as:
|
||||
; void DrawWuLine(int X0, int Y0, int X1, int Y1, int BaseColor,
|
||||
; int NumLevels, unsigned int IntensityBits);
|
||||
|
||||
SCREEN_WIDTH_IN_BYTES equ 320 ;# of bytes from the start of one scan line
|
||||
; to the start of the next
|
||||
SCREEN_SEGMENT equ 0a000h ;segment in which screen memory resides
|
||||
|
||||
; Parameters passed in stack frame.
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
X0 dw ? ;X coordinate of line start point
|
||||
Y0 dw ? ;Y coordinate of line start point
|
||||
X1 dw ? ;X coordinate of line end point
|
||||
Y1 dw ? ;Y coordinate of line end point
|
||||
BaseColor dw ? ;color # of first color in block used for
|
||||
;antialiasing, the 100% intensity version of the
|
||||
;drawing color
|
||||
NumLevels dw ? ;size of color block, with BaseColor+NumLevels-1
|
||||
; being the 0% intensity version of the drawing color
|
||||
; (maximum NumLevels = 256)
|
||||
IntensityBits dw ? ;log base 2 of NumLevels; the # of bits used to
|
||||
; describe the intensity of the drawing color.
|
||||
; 2**IntensityBits==NumLevels
|
||||
; (maximum IntensityBits = 8)
|
||||
parms ends
|
||||
|
||||
.model small
|
||||
.code
|
||||
; Screen dimension globals, used in main program to scale.
|
||||
_ScreenWidthInPixels dw 320
|
||||
_ScreenHeightInPixels dw 200
|
||||
|
||||
.code
|
||||
public _DrawWuLine
|
||||
_DrawWuLine proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
push si ;preserve C's register variables
|
||||
push di
|
||||
push ds ;preserve C's default data segment
|
||||
cld ;make string instructions increment their pointers
|
||||
|
||||
; Make sure the line runs top to bottom.
|
||||
mov si,[bp].X0
|
||||
mov ax,[bp].Y0
|
||||
cmp ax,[bp].Y1 ;swap endpoints if necessary to ensure that
|
||||
jna NoSwap ; Y0 <= Y1
|
||||
xchg [bp].Y1,ax
|
||||
mov [bp].Y0,ax
|
||||
xchg [bp].X1,si
|
||||
mov [bp].X0,si
|
||||
NoSwap:
|
||||
|
||||
; Draw the initial pixel, which is always exactly intersected by the line
|
||||
; and so needs no weighting.
|
||||
mov dx,SCREEN_SEGMENT
|
||||
mov ds,dx ;point DS to the screen segment
|
||||
mov dx,SCREEN_WIDTH_IN_BYTES
|
||||
mul dx ;Y0 * SCREEN_WIDTH_IN_BYTES yields the offset
|
||||
; of the start of the row start the initial
|
||||
; pixel is on
|
||||
add si,ax ;point DS:SI to the initial pixel
|
||||
mov al,byte ptr [bp].BaseColor ;color with which to draw
|
||||
mov [si],al ;draw the initial pixel
|
||||
|
||||
mov bx,1 ;XDir = 1; assume DeltaX >= 0
|
||||
mov cx,[bp].X1
|
||||
sub cx,[bp].X0 ;DeltaX; is it >= 1?
|
||||
jns DeltaXSet ;yes, move left->right, all set
|
||||
;no, move right->left
|
||||
neg cx ;make DeltaX positive
|
||||
neg bx ;XDir = -1
|
||||
DeltaXSet:
|
||||
|
||||
; Special-case horizontal, vertical, and diagonal lines, which require no
|
||||
; weighting because they go right through the center of every pixel.
|
||||
mov dx,[bp].Y1
|
||||
sub dx,[bp].Y0 ;DeltaY; is it 0?
|
||||
jnz NotHorz ;no, not horizontal
|
||||
;yes, is horizontal, special case
|
||||
and bx,bx ;draw from left->right?
|
||||
jns DoHorz ;yes, all set
|
||||
std ;no, draw right->left
|
||||
DoHorz:
|
||||
lea di,[bx+si] ;point DI to next pixel to draw
|
||||
mov ax,ds
|
||||
mov es,ax ;point ES:DI to next pixel to draw
|
||||
mov al,byte ptr [bp].BaseColor ;color with which to draw
|
||||
;CX = DeltaX at this point
|
||||
rep stosb ;draw the rest of the horizontal line
|
||||
cld ;restore default direction flag
|
||||
jmp Done ;and we're done
|
||||
|
||||
align 2
|
||||
NotHorz:
|
||||
and cx,cx ;is DeltaX 0?
|
||||
jnz NotVert ;no, not a vertical line
|
||||
;yes, is vertical, special case
|
||||
mov al,byte ptr [bp].BaseColor ;color with which to draw
|
||||
VertLoop:
|
||||
add si,SCREEN_WIDTH_IN_BYTES ;point to next pixel to draw
|
||||
mov [si],al ;draw the next pixel
|
||||
dec dx ;--DeltaY
|
||||
jnz VertLoop
|
||||
jmp Done ;and we're done
|
||||
|
||||
align 2
|
||||
NotVert:
|
||||
cmp cx,dx ;DeltaX == DeltaY?
|
||||
jnz NotDiag ;no, not diagonal
|
||||
;yes, is diagonal, special case
|
||||
mov al,byte ptr [bp].BaseColor ;color with which to draw
|
||||
DiagLoop:
|
||||
lea si,[si+SCREEN_WIDTH_IN_BYTES+bx]
|
||||
;advance to next pixel to draw by
|
||||
; incrementing Y and adding XDir to X
|
||||
mov [si],al ;draw the next pixel
|
||||
dec dx ;--DeltaY
|
||||
jnz DiagLoop
|
||||
jmp Done ;and we're done
|
||||
|
||||
; Line is not horizontal, diagonal, or vertical.
|
||||
align 2
|
||||
NotDiag:
|
||||
; Is this an X-major or Y-major line?
|
||||
cmp dx,cx
|
||||
jb XMajor ;it's X-major
|
||||
|
||||
; It's a Y-major line. Calculate the 16-bit fixed-point fractional part of a
|
||||
; pixel that X advances each time Y advances 1 pixel, truncating the result
|
||||
; to avoid overrunning the endpoint along the X axis.
|
||||
xchg dx,cx ;DX = DeltaX, CX = DeltaY
|
||||
sub ax,ax ;make DeltaX 16.16 fixed-point value in DX:AX
|
||||
div cx ;AX = (DeltaX << 16) / DeltaY. Won't overflow
|
||||
; because DeltaX < DeltaY
|
||||
mov di,cx ;DI = DeltaY (loop count)
|
||||
sub si,bx ;back up the start X by 1, as explained below
|
||||
mov dx,-1 ;initialize the line error accumulator to -1,
|
||||
; so that it will turn over immediately and
|
||||
; advance X to the start X. This is necessary
|
||||
; properly to bias error sums of 0 to mean
|
||||
; "advance next time" rather than "advance
|
||||
; this time," so that the final error sum can
|
||||
; never cause drawing to overrun the final X
|
||||
; coordinate (works in conjunction with
|
||||
; truncating ErrorAdj, to make sure X can't
|
||||
; overrun)
|
||||
mov cx,8 ;CL = # of bits by which to shift
|
||||
sub cx,[bp].IntensityBits ; ErrorAcc to get intensity level (8
|
||||
; instead of 16 because we work only
|
||||
; with the high byte of ErrorAcc)
|
||||
mov ch,byte ptr [bp].NumLevels ;mask used to flip all bits in an
|
||||
dec ch ; intensity weighting, producing
|
||||
; result (1 - intensity weighting)
|
||||
mov bp,BaseColor[bp] ;***stack frame not available***
|
||||
;***from now on ***
|
||||
xchg bp,ax ;BP = ErrorAdj, AL = BaseColor,
|
||||
; AH = scratch register
|
||||
|
||||
; Draw all remaining pixels.
|
||||
YMajorLoop:
|
||||
add dx,bp ;calculate error for next pixel
|
||||
jnc NoXAdvance ;not time to step in X yet
|
||||
;the error accumulator turned over,
|
||||
;so advance the X coord
|
||||
add si,bx ;add XDir to the pixel pointer
|
||||
NoXAdvance:
|
||||
add si,SCREEN_WIDTH_IN_BYTES ;Y-major, so always advance Y
|
||||
|
||||
; The IntensityBits most significant bits of ErrorAcc give us the intensity
|
||||
; weighting for this pixel, and the complement of the weighting for the
|
||||
; paired pixel.
|
||||
mov ah,dh ;msb of ErrorAcc
|
||||
shr ah,cl ;Weighting = ErrorAcc >> IntensityShift;
|
||||
add ah,al ;BaseColor + Weighting
|
||||
mov [si],ah ;DrawPixel(X, Y, BaseColor + Weighting);
|
||||
mov ah,dh ;msb of ErrorAcc
|
||||
shr ah,cl ;Weighting = ErrorAcc >> IntensityShift;
|
||||
xor ah,ch ;Weighting ^ WeightingComplementMask
|
||||
add ah,al ;BaseColor + (Weighting ^ WeightingComplementMask)
|
||||
mov [si+bx],ah ;DrawPixel(X+XDir, Y,
|
||||
; BaseColor + (Weighting ^ WeightingComplementMask));
|
||||
dec di ;--DeltaY
|
||||
jnz YMajorLoop
|
||||
jmp Done ;we're done with this line
|
||||
|
||||
; It's an X-major line.
|
||||
align 2
|
||||
XMajor:
|
||||
; Calculate the 16-bit fixed-point fractional part of a pixel that Y advances
|
||||
; each time X advances 1 pixel, truncating the result to avoid overrunning
|
||||
; the endpoint along the X axis.
|
||||
sub ax,ax ;make DeltaY 16.16 fixed-point value in DX:AX
|
||||
div cx ;AX = (DeltaY << 16) / Deltax. Won't overflow
|
||||
; because DeltaY < DeltaX
|
||||
mov di,cx ;DI = DeltaX (loop count)
|
||||
sub si,SCREEN_WIDTH_IN_BYTES;back up the start X by 1, as
|
||||
; explained below
|
||||
mov dx,-1 ;initialize the line error accumulator to -1,
|
||||
; so that it will turn over immediately and
|
||||
; advance Y to the start Y. This is necessary
|
||||
; properly to bias error sums of 0 to mean
|
||||
; "advance next time" rather than "advance
|
||||
; this time," so that the final error sum can
|
||||
; never cause drawing to overrun the final Y
|
||||
; coordinate (works in conjunction with
|
||||
; truncating ErrorAdj, to make sure Y can't
|
||||
; overrun)
|
||||
mov cx,8 ;CL = # of bits by which to shift
|
||||
sub cx,[bp].IntensityBits ; ErrorAcc to get intensity level (8
|
||||
; instead of 16 because we work only
|
||||
; with the high byte of ErrorAcc)
|
||||
mov ch,byte ptr [bp].NumLevels ;mask used to flip all bits in an
|
||||
dec ch ; intensity weighting, producing
|
||||
; result (1 - intensity weighting)
|
||||
mov bp,BaseColor[bp] ;***stack frame not available***
|
||||
;***from now on ***
|
||||
xchg bp,ax ;BP = ErrorAdj, AL = BaseColor,
|
||||
; AH = scratch register
|
||||
; Draw all remaining pixels.
|
||||
XMajorLoop:
|
||||
add dx,bp ;calculate error for next pixel
|
||||
jnc NoYAdvance ;not time to step in Y yet
|
||||
;the error accumulator turned over,
|
||||
; so advance the Y coord
|
||||
add si,SCREEN_WIDTH_IN_BYTES;advance Y
|
||||
NoYAdvance:
|
||||
add si,bx ;X-major, so add XDir to the pixel pointer
|
||||
|
||||
; The IntensityBits most significant bits of ErrorAcc give us the intensity
|
||||
; weighting for this pixel, and the complement of the weighting for the
|
||||
; paired pixel.
|
||||
mov ah,dh ;msb of ErrorAcc
|
||||
shr ah,cl ;Weighting = ErrorAcc >> IntensityShift;
|
||||
add ah,al ;BaseColor + Weighting
|
||||
mov [si],ah ;DrawPixel(X, Y, BaseColor + Weighting);
|
||||
mov ah,dh ;msb of ErrorAcc
|
||||
shr ah,cl ;Weighting = ErrorAcc >> IntensityShift;
|
||||
xor ah,ch ;Weighting ^ WeightingComplementMask
|
||||
add ah,al ;BaseColor + (Weighting ^ WeightingComplementMask)
|
||||
mov [si+SCREEN_WIDTH_IN_BYTES],ah
|
||||
|
||||
; DrawPixel(X, Y+SCREEN_WIDTH_IN_BYTES, BaseColor + (Weighting ^ WeightingComplementMask));
|
||||
dec di ;--DeltaX
|
||||
jnz XMajorLoop
|
||||
|
||||
Done: ;we're done with this line
|
||||
pop ds ;restore C's default data segment
|
||||
pop di ;restore C's register variables
|
||||
pop si
|
||||
pop bp ;restore caller's stack frame
|
||||
ret ;done
|
||||
_DrawWuLine endp
|
||||
end
|
||||
88
tests/pcx86/vga/L47-1.ASM
Normal file
88
tests/pcx86/vga/L47-1.ASM
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
; Mode X (320x240, 256 colors) mode set routine. Works on all VGAs.
|
||||
; ****************************************************************
|
||||
; * Revised 6/19/91 to select correct clock; fixes vertical roll *
|
||||
; * problems on fixed-frequency (IBM 851X-type) monitors. *
|
||||
; ****************************************************************
|
||||
; C near-callable as:
|
||||
; void Set320x240Mode(void);
|
||||
; Tested with TASM
|
||||
; Modified from public-domain mode set code by John Bridges.
|
||||
|
||||
SC_INDEX equ 03c4h ;Sequence Controller Index
|
||||
CRTC_INDEX equ 03d4h ;CRT Controller Index
|
||||
MISC_OUTPUT equ 03c2h ;Miscellaneous Output register
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in mode X
|
||||
|
||||
.model small
|
||||
.data
|
||||
; Index/data pairs for CRT Controller registers that differ between
|
||||
; mode 13h and mode X.
|
||||
CRTParms label word
|
||||
dw 00d06h ;vertical total
|
||||
dw 03e07h ;overflow (bit 8 of vertical counts)
|
||||
dw 04109h ;cell height (2 to double-scan)
|
||||
dw 0ea10h ;v sync start
|
||||
dw 0ac11h ;v sync end and protect cr0-cr7
|
||||
dw 0df12h ;vertical displayed
|
||||
dw 00014h ;turn off dword mode
|
||||
dw 0e715h ;v blank start
|
||||
dw 00616h ;v blank end
|
||||
dw 0e317h ;turn on byte mode
|
||||
CRT_PARM_LENGTH equ (($-CRTParms)/2)
|
||||
|
||||
.code
|
||||
public _Set320x240Mode
|
||||
_Set320x240Mode proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
push si ;preserve C register vars
|
||||
push di ; (don't count on BIOS preserving anything)
|
||||
|
||||
mov ax,13h ;let the BIOS set standard 256-color
|
||||
int 10h ; mode (320x200 linear)
|
||||
|
||||
mov dx,SC_INDEX
|
||||
mov ax,0604h
|
||||
out dx,ax ;disable chain4 mode
|
||||
mov ax,0100h
|
||||
out dx,ax ;synchronous reset while setting Misc Output
|
||||
; for safety, even though clock unchanged
|
||||
mov dx,MISC_OUTPUT
|
||||
mov al,0e3h
|
||||
out dx,al ;select 25 MHz dot clock & 60 Hz scanning rate
|
||||
|
||||
mov dx,SC_INDEX
|
||||
mov ax,0300h
|
||||
out dx,ax ;undo reset (restart sequencer)
|
||||
|
||||
mov dx,CRTC_INDEX ;reprogram the CRT Controller
|
||||
mov al,11h ;VSync End reg contains register write
|
||||
out dx,al ; protect bit
|
||||
inc dx ;CRT Controller Data register
|
||||
in al,dx ;get current VSync End register setting
|
||||
and al,7fh ;remove write protect on various
|
||||
out dx,al ; CRTC registers
|
||||
dec dx ;CRT Controller Index
|
||||
cld
|
||||
mov si,offset CRTParms ;point to CRT parameter table
|
||||
mov cx,CRT_PARM_LENGTH ;# of table entries
|
||||
SetCRTParmsLoop:
|
||||
lodsw ;get the next CRT Index/Data pair
|
||||
out dx,ax ;set the next CRT Index/Data pair
|
||||
loop SetCRTParmsLoop
|
||||
|
||||
mov dx,SC_INDEX
|
||||
mov ax,0f02h
|
||||
out dx,ax ;enable writes to all four planes
|
||||
mov ax,SCREEN_SEG ;now clear all display memory, 8 pixels
|
||||
mov es,ax ; at a time
|
||||
sub di,di ;point ES:DI to display memory
|
||||
sub ax,ax ;clear to zero-value pixels
|
||||
mov cx,8000h ;# of words in display memory
|
||||
rep stosw ;clear all of display memory
|
||||
|
||||
pop di ;restore C register vars
|
||||
pop si
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_Set320x240Mode endp
|
||||
end
|
||||
52
tests/pcx86/vga/L47-2.ASM
Normal file
52
tests/pcx86/vga/L47-2.ASM
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
; Mode X (320x240, 256 colors) write pixel routine. Works on all VGAs.
|
||||
; No clipping is performed.
|
||||
; C near-callable as:
|
||||
;
|
||||
; void WritePixelX(int X, int Y, unsigned int PageBase, int Color);
|
||||
|
||||
SC_INDEX equ 03c4h ;Sequence Controller Index
|
||||
MAP_MASK equ 02h ;index in SC of Map Mask register
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in mode X
|
||||
SCREEN_WIDTH equ 80 ;width of screen in bytes from one scan line
|
||||
; to the next
|
||||
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
X dw ? ;X coordinate of pixel to draw
|
||||
Y dw ? ;Y coordinate of pixel to draw
|
||||
PageBase dw ? ;base offset in display memory of page in
|
||||
; which to draw pixel
|
||||
Color dw ? ;color in which to draw pixel
|
||||
parms ends
|
||||
|
||||
.model small
|
||||
.code
|
||||
public _WritePixelX
|
||||
_WritePixelX proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
|
||||
mov ax,SCREEN_WIDTH
|
||||
mul [bp+Y] ;offset of pixel's scan line in page
|
||||
mov bx,[bp+X]
|
||||
shr bx,1
|
||||
shr bx,1 ;X/4 = offset of pixel in scan line
|
||||
add bx,ax ;offset of pixel in page
|
||||
add bx,[bp+PageBase] ;offset of pixel in display memory
|
||||
mov ax,SCREEN_SEG
|
||||
mov es,ax ;point ES:BX to the pixel's address
|
||||
|
||||
mov cl,byte ptr [bp+X]
|
||||
and cl,011b ;CL = pixel's plane
|
||||
mov ax,0100h + MAP_MASK ;AL = index in SC of Map Mask reg
|
||||
shl ah,cl ;set only the bit for the pixel's plane to 1
|
||||
mov dx,SC_INDEX ;set the Map Mask to enable only the
|
||||
out dx,ax ; pixel's plane
|
||||
|
||||
mov al,byte ptr [bp+Color]
|
||||
mov es:[bx],al ;draw the pixel in the desired color
|
||||
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_WritePixelX endp
|
||||
end
|
||||
49
tests/pcx86/vga/L47-3.ASM
Normal file
49
tests/pcx86/vga/L47-3.ASM
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
; Mode X (320x240, 256 colors) read pixel routine. Works on all VGAs.
|
||||
; No clipping is performed.
|
||||
; C near-callable as:
|
||||
;
|
||||
; unsigned int ReadPixelX(int X, int Y, unsigned int PageBase);
|
||||
|
||||
GC_INDEX equ 03ceh ;Graphics Controller Index
|
||||
READ_MAP equ 04h ;index in GC of the Read Map register
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in mode X
|
||||
SCREEN_WIDTH equ 80 ;width of screen in bytes from one scan line
|
||||
; to the next
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
X dw ? ;X coordinate of pixel to read
|
||||
Y dw ? ;Y coordinate of pixel to read
|
||||
PageBase dw ? ;base offset in display memory of page from
|
||||
; which to read pixel
|
||||
parms ends
|
||||
|
||||
.model small
|
||||
.code
|
||||
public _ReadPixelX
|
||||
_ReadPixelX proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
|
||||
mov ax,SCREEN_WIDTH
|
||||
mul [bp+Y] ;offset of pixel's scan line in page
|
||||
mov bx,[bp+X]
|
||||
shr bx,1
|
||||
shr bx,1 ;X/4 = offset of pixel in scan line
|
||||
add bx,ax ;offset of pixel in page
|
||||
add bx,[bp+PageBase] ;offset of pixel in display memory
|
||||
mov ax,SCREEN_SEG
|
||||
mov es,ax ;point ES:BX to the pixel's address
|
||||
|
||||
mov ah,byte ptr [bp+X]
|
||||
and ah,011b ;AH = pixel's plane
|
||||
mov al,READ_MAP ;AL = index in GC of the Read Map reg
|
||||
mov dx,GC_INDEX ;set the Read Map to read the pixel's
|
||||
out dx,ax ; plane
|
||||
|
||||
mov al,es:[bx] ;read the pixel's color
|
||||
sub ah,ah ;convert it to an unsigned int
|
||||
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_ReadPixelX endp
|
||||
end
|
||||
90
tests/pcx86/vga/L47-4.ASM
Normal file
90
tests/pcx86/vga/L47-4.ASM
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
; Mode X (320x240, 256 colors) rectangle fill routine. Works on all
|
||||
; VGAs. Uses slow approach that selects the plane explicitly for each
|
||||
; pixel. Fills up to but not including the column at EndX and the row
|
||||
; at EndY. No clipping is performed.
|
||||
; C near-callable as:
|
||||
;
|
||||
; void FillRectangleX(int StartX, int StartY, int EndX, int EndY,
|
||||
; unsigned int PageBase, int Color);
|
||||
|
||||
SC_INDEX equ 03c4h ;Sequence Controller Index
|
||||
MAP_MASK equ 02h ;index in SC of Map Mask register
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in mode X
|
||||
SCREEN_WIDTH equ 80 ;width of screen in bytes from one scan line
|
||||
; to the next
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
StartX dw ? ;X coordinate of upper left corner of rect
|
||||
StartY dw ? ;Y coordinate of upper left corner of rect
|
||||
EndX dw ? ;X coordinate of lower right corner of rect
|
||||
; (the row at EndX is not filled)
|
||||
EndY dw ? ;Y coordinate of lower right corner of rect
|
||||
; (the column at EndY is not filled)
|
||||
PageBase dw ? ;base offset in display memory of page in
|
||||
; which to fill rectangle
|
||||
Color dw ? ;color in which to draw pixel
|
||||
parms ends
|
||||
|
||||
.model small
|
||||
.code
|
||||
public _FillRectangleX
|
||||
_FillRectangleX proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
push si ;preserve caller's register variables
|
||||
push di
|
||||
|
||||
mov ax,SCREEN_WIDTH
|
||||
mul [bp+StartY] ;offset in page of top rectangle scan line
|
||||
mov di,[bp+StartX]
|
||||
shr di,1
|
||||
shr di,1 ;X/4 = offset of first rectangle pixel in scan
|
||||
; line
|
||||
add di,ax ;offset of first rectangle pixel in page
|
||||
add di,[bp+PageBase] ;offset of first rectangle pixel in
|
||||
; display memory
|
||||
mov ax,SCREEN_SEG
|
||||
mov es,ax ;point ES:DI to the first rectangle pixel's
|
||||
; address
|
||||
mov dx,SC_INDEX ;set the Sequence Controller Index to
|
||||
mov al,MAP_MASK ; point to the Map Mask register
|
||||
out dx,al
|
||||
inc dx ;point DX to the SC Data register
|
||||
mov cl,byte ptr [bp+StartX]
|
||||
and cl,011b ;CL = first rectangle pixel's plane
|
||||
mov al,01h
|
||||
shl al,cl ;set only the bit for the pixel's plane to 1
|
||||
mov ah,byte ptr [bp+Color] ;color with which to fill
|
||||
mov bx,[bp+EndY]
|
||||
sub bx,[bp+StartY] ;BX = height of rectangle
|
||||
jle FillDone ;skip if 0 or negative height
|
||||
mov si,[bp+EndX]
|
||||
sub si,[bp+StartX] ;CX = width of rectangle
|
||||
jle FillDone ;skip if 0 or negative width
|
||||
FillRowsLoop:
|
||||
push ax ;remember the plane mask for the left edge
|
||||
push di ;remember the start offset of the scan line
|
||||
mov cx,si ;set count of pixels in this scan line
|
||||
FillScanLineLoop:
|
||||
out dx,al ;set the plane for this pixel
|
||||
mov es:[di],ah ;draw the pixel
|
||||
shl al,1 ;adjust the plane mask for the next pixel's
|
||||
and al,01111b ; bit, modulo 4
|
||||
jnz AddressSet ;advance address if we turned over from
|
||||
inc di ; plane 3 to plane 0
|
||||
mov al,00001b ;set plane mask bit for plane 0
|
||||
AddressSet:
|
||||
loop FillScanLineLoop
|
||||
pop di ;retrieve the start offset of the scan line
|
||||
add di,SCREEN_WIDTH ;point to the start of the next scan
|
||||
; line of the rectangle
|
||||
pop ax ;retrieve the plane mask for the left edge
|
||||
dec bx ;count down scan lines
|
||||
jnz FillRowsLoop
|
||||
FillDone:
|
||||
pop di ;restore caller's register variables
|
||||
pop si
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_FillRectangleX endp
|
||||
end
|
||||
127
tests/pcx86/vga/L47-5.ASM
Normal file
127
tests/pcx86/vga/L47-5.ASM
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
; Mode X (320x240, 256 colors) rectangle fill routine. Works on all
|
||||
; VGAs. Uses medium-speed approach that selects each plane only once
|
||||
; per rectangle; this results in a fade-in effect for large
|
||||
; rectangles. Fills up to but not including the column at EndX and the
|
||||
; row at EndY. No clipping is performed.
|
||||
; C near-callable as:
|
||||
;
|
||||
; void FillRectangleX(int StartX, int StartY, int EndX, int EndY,
|
||||
; unsigned int PageBase, int Color);
|
||||
|
||||
SC_INDEX equ 03c4h ;Sequence Controller Index
|
||||
MAP_MASK equ 02h ;index in SC of Map Mask register
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in mode X
|
||||
SCREEN_WIDTH equ 80 ;width of screen in bytes from one scan line
|
||||
; to the next
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
StartX dw ? ;X coordinate of upper left corner of rect
|
||||
StartY dw ? ;Y coordinate of upper left corner of rect
|
||||
EndX dw ? ;X coordinate of lower right corner of rect
|
||||
; (the row at EndX is not filled)
|
||||
EndY dw ? ;Y coordinate of lower right corner of rect
|
||||
; (the column at EndY is not filled)
|
||||
PageBase dw ? ;base offset in display memory of page in
|
||||
; which to fill rectangle
|
||||
Color dw ? ;color in which to draw pixel
|
||||
parms ends
|
||||
|
||||
_StartOffset equ -2 ;local storage for start offset of rectangle
|
||||
_Width equ -4 ;local storage for address width of rectangle
|
||||
_Height equ -6 ;local storage for height of rectangle
|
||||
_PlaneInfo equ -8 ;local storage for plane # and plane mask
|
||||
STACK_FRAME_SIZE equ 8
|
||||
|
||||
.model small
|
||||
.code
|
||||
public _FillRectangleX
|
||||
_FillRectangleX proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
sub sp,STACK_FRAME_SIZE ;allocate space for local vars
|
||||
push si ;preserve caller's register variables
|
||||
push di
|
||||
|
||||
cld
|
||||
mov ax,SCREEN_WIDTH
|
||||
mul [bp+StartY] ;offset in page of top rectangle scan line
|
||||
mov di,[bp+StartX]
|
||||
shr di,1
|
||||
shr di,1 ;X/4 = offset of first rectangle pixel in scan
|
||||
; line
|
||||
add di,ax ;offset of first rectangle pixel in page
|
||||
add di,[bp+PageBase] ;offset of first rectangle pixel in
|
||||
; display memory
|
||||
mov ax,SCREEN_SEG
|
||||
mov es,ax ;point ES:DI to the first rectangle pixel's
|
||||
mov [bp+_StartOffset],di ; address
|
||||
mov dx,SC_INDEX ;set the Sequence Controller Index to
|
||||
mov al,MAP_MASK ; point to the Map Mask register
|
||||
out dx,al
|
||||
mov bx,[bp+EndY]
|
||||
sub bx,[bp+StartY] ;BX = height of rectangle
|
||||
jle FillDone ;skip if 0 or negative height
|
||||
mov [bp+_Height],bx
|
||||
mov dx,[bp+EndX]
|
||||
mov cx,[bp+StartX]
|
||||
cmp dx,cx
|
||||
jle FillDone ;skip if 0 or negative width
|
||||
dec dx
|
||||
and cx,not 011b
|
||||
sub dx,cx
|
||||
shr dx,1
|
||||
shr dx,1
|
||||
inc dx ;# of addresses across rectangle to fill
|
||||
mov [bp+_Width],dx
|
||||
mov word ptr [bp+_PlaneInfo],0001h
|
||||
;lower byte = plane mask for plane 0,
|
||||
; upper byte = plane # for plane 0
|
||||
FillPlanesLoop:
|
||||
mov ax,word ptr [bp+_PlaneInfo]
|
||||
mov dx,SC_INDEX+1 ;point DX to the SC Data register
|
||||
out dx,al ;set the plane for this pixel
|
||||
mov di,[bp+_StartOffset] ;point ES:DI to rectangle start
|
||||
mov dx,[bp+_Width]
|
||||
mov cl,byte ptr [bp+StartX]
|
||||
and cl,011b ;plane # of first pixel in initial byte
|
||||
cmp ah,cl ;do we draw this plane in the initial byte?
|
||||
jae InitAddrSet ;yes
|
||||
dec dx ;no, so skip the initial byte
|
||||
jz FillLoopBottom ;skip this plane if no pixels in it
|
||||
inc di
|
||||
InitAddrSet:
|
||||
mov cl,byte ptr [bp+EndX]
|
||||
dec cl
|
||||
and cl,011b ;plane # of last pixel in final byte
|
||||
cmp ah,cl ;do we draw this plane in the final byte?
|
||||
jbe WidthSet ;yes
|
||||
dec dx ;no, so skip the final byte
|
||||
jz FillLoopBottom ;skip this planes if no pixels in it
|
||||
WidthSet:
|
||||
mov si,SCREEN_WIDTH
|
||||
sub si,dx ;distance from end of one scan line to start
|
||||
; of next
|
||||
mov bx,[bp+_Height] ;# of lines to fill
|
||||
mov al,byte ptr [bp+Color] ;color with which to fill
|
||||
FillRowsLoop:
|
||||
mov cx,dx ;# of bytes across scan line
|
||||
rep stosb ;fill the scan line in this plane
|
||||
add di,si ;point to the start of the next scan
|
||||
; line of the rectangle
|
||||
dec bx ;count down scan lines
|
||||
jnz FillRowsLoop
|
||||
FillLoopBottom:
|
||||
mov ax,word ptr [bp+_PlaneInfo]
|
||||
shl al,1 ;set the plane bit to the next plane
|
||||
inc ah ;increment the plane #
|
||||
mov word ptr [bp+_PlaneInfo],ax
|
||||
cmp ah,4 ;have we done all planes?
|
||||
jnz FillPlanesLoop ;continue if any more planes
|
||||
FillDone:
|
||||
pop di ;restore caller's register variables
|
||||
pop si
|
||||
mov sp,bp ;discard storage for local variables
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_FillRectangleX endp
|
||||
end
|
||||
113
tests/pcx86/vga/L47-6.ASM
Normal file
113
tests/pcx86/vga/L47-6.ASM
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
; Mode X (320x240, 256 colors) rectangle fill routine. Works on all
|
||||
; VGAs. Uses fast approach that fans data out to up to four planes at
|
||||
; once to draw up to four pixels at once. Fills up to but not
|
||||
; including the column at EndX and the row at EndY. No clipping is
|
||||
; performed.
|
||||
; C near-callable as:
|
||||
; void FillRectangleX(int StartX, int StartY, int EndX, int EndY,
|
||||
; unsigned int PageBase, int Color);
|
||||
|
||||
SC_INDEX equ 03c4h ;Sequence Controller Index
|
||||
MAP_MASK equ 02h ;index in SC of Map Mask register
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in mode X
|
||||
SCREEN_WIDTH equ 80 ;width of screen in bytes from one scan line
|
||||
; to the next
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
StartX dw ? ;X coordinate of upper left corner of rect
|
||||
StartY dw ? ;Y coordinate of upper left corner of rect
|
||||
EndX dw ? ;X coordinate of lower right corner of rect
|
||||
; (the row at EndX is not filled)
|
||||
EndY dw ? ;Y coordinate of lower right corner of rect
|
||||
; (the column at EndY is not filled)
|
||||
PageBase dw ? ;base offset in display memory of page in
|
||||
; which to fill rectangle
|
||||
Color dw ? ;color in which to draw pixel
|
||||
parms ends
|
||||
|
||||
.model small
|
||||
.data
|
||||
; Plane masks for clipping left and right edges of rectangle.
|
||||
LeftClipPlaneMask db 00fh,00eh,00ch,008h
|
||||
RightClipPlaneMask db 00fh,001h,003h,007h
|
||||
.code
|
||||
public _FillRectangleX
|
||||
_FillRectangleX proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
push si ;preserve caller's register variables
|
||||
push di
|
||||
|
||||
cld
|
||||
mov ax,SCREEN_WIDTH
|
||||
mul [bp+StartY] ;offset in page of top rectangle scan line
|
||||
mov di,[bp+StartX]
|
||||
shr di,1 ;X/4 = offset of first rectangle pixel in scan
|
||||
shr di,1 ; line
|
||||
add di,ax ;offset of first rectangle pixel in page
|
||||
add di,[bp+PageBase] ;offset of first rectangle pixel in
|
||||
; display memory
|
||||
mov ax,SCREEN_SEG ;point ES:DI to the first rectangle
|
||||
mov es,ax ; pixel's address
|
||||
mov dx,SC_INDEX ;set the Sequence Controller Index to
|
||||
mov al,MAP_MASK ; point to the Map Mask register
|
||||
out dx,al
|
||||
inc dx ;point DX to the SC Data register
|
||||
mov si,[bp+StartX]
|
||||
and si,0003h ;look up left edge plane mask
|
||||
mov bh,LeftClipPlaneMask[si] ; to clip & put in BH
|
||||
mov si,[bp+EndX]
|
||||
and si,0003h ;look up right edge plane
|
||||
mov bl,RightClipPlaneMask[si] ; mask to clip & put in BL
|
||||
|
||||
mov cx,[bp+EndX] ;calculate # of addresses across rect
|
||||
mov si,[bp+StartX]
|
||||
cmp cx,si
|
||||
jle FillDone ;skip if 0 or negative width
|
||||
dec cx
|
||||
and si,not 011b
|
||||
sub cx,si
|
||||
shr cx,1
|
||||
shr cx,1 ;# of addresses across rectangle to fill - 1
|
||||
jnz MasksSet ;there's more than one byte to draw
|
||||
and bh,bl ;there's only one byte, so combine the left
|
||||
; and right edge clip masks
|
||||
MasksSet:
|
||||
mov si,[bp+EndY]
|
||||
sub si,[bp+StartY] ;BX = height of rectangle
|
||||
jle FillDone ;skip if 0 or negative height
|
||||
mov ah,byte ptr [bp+Color] ;color with which to fill
|
||||
mov bp,SCREEN_WIDTH ;stack frame isn't needed any more
|
||||
sub bp,cx ;distance from end of one scan line to start
|
||||
dec bp ; of next
|
||||
FillRowsLoop:
|
||||
push cx ;remember width in addresses - 1
|
||||
mov al,bh ;put left-edge clip mask in AL
|
||||
out dx,al ;set the left-edge plane (clip) mask
|
||||
mov al,ah ;put color in AL
|
||||
stosb ;draw the left edge
|
||||
dec cx ;count off left edge byte
|
||||
js FillLoopBottom ;that's the only byte
|
||||
jz DoRightEdge ;there are only two bytes
|
||||
mov al,00fh ;middle addresses are drawn 4 pixels at a pop
|
||||
out dx,al ;set the middle pixel mask to no clip
|
||||
mov al,ah ;put color in AL
|
||||
rep stosb ;draw the middle addresses four pixels apiece
|
||||
DoRightEdge:
|
||||
mov al,bl ;put right-edge clip mask in AL
|
||||
out dx,al ;set the right-edge plane (clip) mask
|
||||
mov al,ah ;put color in AL
|
||||
stosb ;draw the right edge
|
||||
FillLoopBottom:
|
||||
add di,bp ;point to the start of the next scan line of
|
||||
; the rectangle
|
||||
pop cx ;retrieve width in addresses - 1
|
||||
dec si ;count down scan lines
|
||||
jnz FillRowsLoop
|
||||
FillDone:
|
||||
pop di ;restore caller's register variables
|
||||
pop si
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_FillRectangleX endp
|
||||
end
|
||||
25
tests/pcx86/vga/L47-7.C
Normal file
25
tests/pcx86/vga/L47-7.C
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* Program to demonstrate mode X (320x240, 256-colors) rectangle
|
||||
fill by drawing adjacent 20x20 rectangles in successive colors from
|
||||
0 on up across and down the screen
|
||||
*/
|
||||
#include <conio.h>
|
||||
#include <dos.h>
|
||||
|
||||
void Set320x240Mode(void);
|
||||
void FillRectangleX(int, int, int, int, unsigned int, int);
|
||||
|
||||
void main() {
|
||||
int i,j;
|
||||
union REGS regset;
|
||||
|
||||
Set320x240Mode();
|
||||
FillRectangleX(0,0,320,240,0,0); /* clear the screen to black */
|
||||
for (j = 1; j < 220; j += 21) {
|
||||
for (i = 1; i < 300; i += 21) {
|
||||
FillRectangleX(i, j, i+20, j+20, 0, ((j/21*15)+i/21) & 0xFF);
|
||||
}
|
||||
}
|
||||
getch();
|
||||
regset.x.ax = 0x0003; /* switch back to text mode and done */
|
||||
int86(0x10, ®set, ®set);
|
||||
}
|
||||
44
tests/pcx86/vga/L48-1.C
Normal file
44
tests/pcx86/vga/L48-1.C
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* Program to demonstrate Mode X (320x240, 256 colors) patterned
|
||||
rectangle fills by filling the screen with adjacent 80x60
|
||||
rectangles in a variety of patterns. Tested with Borland C++
|
||||
in C compilation mode and the small model */
|
||||
#include <conio.h>
|
||||
#include <dos.h>
|
||||
|
||||
void Set320x240Mode(void);
|
||||
void FillPatternX(int, int, int, int, unsigned int, char*);
|
||||
|
||||
/* 16 4x4 patterns */
|
||||
static char Patt0[]={10,0,10,0,0,10,0,10,10,0,10,0,0,10,0,10};
|
||||
static char Patt1[]={9,0,0,0,0,9,0,0,0,0,9,0,0,0,0,9};
|
||||
static char Patt2[]={5,0,0,0,0,0,5,0,5,0,0,0,0,0,5,0};
|
||||
static char Patt3[]={14,0,0,14,0,14,14,0,0,14,14,0,14,0,0,14};
|
||||
static char Patt4[]={15,15,15,1,15,15,1,1,15,1,1,1,1,1,1,1};
|
||||
static char Patt5[]={12,12,12,12,6,6,6,12,6,6,6,12,6,6,6,12};
|
||||
static char Patt6[]={80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,15};
|
||||
static char Patt7[]={78,78,78,78,80,80,80,80,82,82,82,82,84,84,84,84};
|
||||
static char Patt8[]={78,80,82,84,80,82,84,78,82,84,78,80,84,78,80,82};
|
||||
static char Patt9[]={78,80,82,84,78,80,82,84,78,80,82,84,78,80,82,84};
|
||||
static char Patt10[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
|
||||
static char Patt11[]={0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3};
|
||||
static char Patt12[]={14,14,9,9,14,9,9,14,9,9,14,14,9,14,14,9};
|
||||
static char Patt13[]={15,8,8,8,15,15,15,8,15,15,15,8,15,8,8,8};
|
||||
static char Patt14[]={3,3,3,3,3,7,7,3,3,7,7,3,3,3,3,3};
|
||||
static char Patt15[]={0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,89};
|
||||
/* Table of pointers to the 16 4x4 patterns with which to draw */
|
||||
static char* PattTable[] = {Patt0,Patt1,Patt2,Patt3,Patt4,Patt5,Patt6,
|
||||
Patt7,Patt8,Patt9,Patt10,Patt11,Patt12,Patt13,Patt14,Patt15};
|
||||
void main() {
|
||||
int i,j;
|
||||
union REGS regset;
|
||||
|
||||
Set320x240Mode();
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
FillPatternX(i*80,j*60,i*80+80,j*60+60,0,PattTable[j*4+i]);
|
||||
}
|
||||
}
|
||||
getch();
|
||||
regset.x.ax = 0x0003; /* switch back to text mode and done */
|
||||
int86(0x10, ®set, ®set);
|
||||
}
|
||||
174
tests/pcx86/vga/L48-2.ASM
Normal file
174
tests/pcx86/vga/L48-2.ASM
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine.
|
||||
; Upper left corner of pattern is always aligned to a multiple-of-4
|
||||
; row and column. Works on all VGAs. Uses approach of copying the
|
||||
; pattern to off-screen display memory, then loading the latches with
|
||||
; the pattern for each scan line and filling each scan line four
|
||||
; pixels at a time. Fills up to but not including the column at EndX
|
||||
; and the row at EndY. No clipping is performed. All ASM code tested
|
||||
; with TASM. C near-callable as:
|
||||
;
|
||||
; void FillPatternX(int StartX, int StartY, int EndX, int EndY,
|
||||
; unsigned int PageBase, char* Pattern);
|
||||
|
||||
SC_INDEX equ 03c4h ;Sequence Controller Index register port
|
||||
MAP_MASK equ 02h ;index in SC of Map Mask register
|
||||
GC_INDEX equ 03ceh ;Graphics Controller Index register port
|
||||
BIT_MASK equ 08h ;index in GC of Bit Mask register
|
||||
PATTERN_BUFFER equ 0fffch ;offset in screen memory of the buffer used
|
||||
; to store each pattern during drawing
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in Mode X
|
||||
SCREEN_WIDTH equ 80 ;width of screen in addresses from one scan
|
||||
; line to the next
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
StartX dw ? ;X coordinate of upper left corner of rect
|
||||
StartY dw ? ;Y coordinate of upper left corner of rect
|
||||
EndX dw ? ;X coordinate of lower right corner of rect
|
||||
; (the row at EndX is not filled)
|
||||
EndY dw ? ;Y coordinate of lower right corner of rect
|
||||
; (the column at EndY is not filled)
|
||||
PageBase dw ? ;base offset in display memory of page in
|
||||
; which to fill rectangle
|
||||
Pattern dw ? ;4x4 pattern with which to fill rectangle
|
||||
parms ends
|
||||
|
||||
NextScanOffset equ -2 ;local storage for distance from end of one
|
||||
; scan line to start of next
|
||||
RectAddrWidth equ -4 ;local storage for address width of rectangle
|
||||
Height equ -6 ;local storage for height of rectangle
|
||||
STACK_FRAME_SIZE equ 6
|
||||
|
||||
.model small
|
||||
.data
|
||||
; Plane masks for clipping left and right edges of rectangle.
|
||||
LeftClipPlaneMask db 00fh,00eh,00ch,008h
|
||||
RightClipPlaneMask db 00fh,001h,003h,007h
|
||||
.code
|
||||
public _FillPatternX
|
||||
_FillPatternX proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
sub sp,STACK_FRAME_SIZE ;allocate space for local vars
|
||||
push si ;preserve caller's register variables
|
||||
push di
|
||||
|
||||
cld
|
||||
mov ax,SCREEN_SEG ;point ES to display memory
|
||||
mov es,ax
|
||||
;copy pattern to display memory buffer
|
||||
mov si,[bp+Pattern] ;point to pattern to fill with
|
||||
mov di,PATTERN_BUFFER ;point ES:DI to pattern buffer
|
||||
mov dx,SC_INDEX ;point Sequence Controller Index to
|
||||
mov al,MAP_MASK ; Map Mask
|
||||
out dx,al
|
||||
inc dx ;point to SC Data register
|
||||
mov cx,4 ;4 pixel quadruplets in pattern
|
||||
DownloadPatternLoop:
|
||||
mov al,1 ;
|
||||
out dx,al ;select plane 0 for writes
|
||||
movsb ;copy over next plane 0 pattern pixel
|
||||
dec di ;stay at same address for next plane
|
||||
mov al,2 ;
|
||||
out dx,al ;select plane 1 for writes
|
||||
movsb ;copy over next plane 1 pattern pixel
|
||||
dec di ;stay at same address for next plane
|
||||
mov al,4 ;
|
||||
out dx,al ;select plane 2 for writes
|
||||
movsb ;copy over next plane 2 pattern pixel
|
||||
dec di ;stay at same address for next plane
|
||||
mov al,8 ;
|
||||
out dx,al ;select plane 3 for writes
|
||||
movsb ;copy over next plane 3 pattern pixel
|
||||
; and advance address
|
||||
loop DownloadPatternLoop
|
||||
|
||||
mov dx,GC_INDEX ;set the bit mask to select all bits
|
||||
mov ax,00000h+BIT_MASK ; from the latches and none from
|
||||
out dx,ax ; the CPU, so that we can write the
|
||||
; latch contents directly to memory
|
||||
mov ax,[bp+StartY] ;top rectangle scan line
|
||||
mov si,ax
|
||||
and si,011b ;top rect scan line modulo 4
|
||||
add si,PATTERN_BUFFER ;point to pattern scan line that
|
||||
; maps to top line of rect to draw
|
||||
mov dx,SCREEN_WIDTH
|
||||
mul dx ;offset in page of top rectangle scan line
|
||||
mov di,[bp+StartX]
|
||||
mov bx,di
|
||||
shr di,1 ;X/4 = offset of first rectangle pixel in scan
|
||||
shr di,1 ; line
|
||||
add di,ax ;offset of first rectangle pixel in page
|
||||
add di,[bp+PageBase] ;offset of first rectangle pixel in
|
||||
; display memory
|
||||
and bx,0003h ;look up left edge plane mask
|
||||
mov ah,LeftClipPlaneMask[bx] ; to clip
|
||||
mov bx,[bp+EndX]
|
||||
and bx,0003h ;look up right edge plane
|
||||
mov al,RightClipPlaneMask[bx] ; mask to clip
|
||||
mov bx,ax ;put the masks in BX
|
||||
|
||||
mov cx,[bp+EndX] ;calculate # of addresses across rect
|
||||
mov ax,[bp+StartX]
|
||||
cmp cx,ax
|
||||
jle FillDone ;skip if 0 or negative width
|
||||
dec cx
|
||||
and ax,not 011b
|
||||
sub cx,ax
|
||||
shr cx,1
|
||||
shr cx,1 ;# of addresses across rectangle to fill - 1
|
||||
jnz MasksSet ;there's more than one pixel to draw
|
||||
and bh,bl ;there's only one pixel, so combine the left
|
||||
; and right edge clip masks
|
||||
MasksSet:
|
||||
mov ax,[bp+EndY]
|
||||
sub ax,[bp+StartY] ;AX = height of rectangle
|
||||
jle FillDone ;skip if 0 or negative height
|
||||
mov [bp+Height],ax
|
||||
mov ax,SCREEN_WIDTH
|
||||
sub ax,cx ;distance from end of one scan line to start
|
||||
dec ax ; of next
|
||||
mov [bp+NextScanOffset],ax
|
||||
mov [bp+RectAddrWidth],cx ;remember width in addresses - 1
|
||||
mov dx,SC_INDEX+1 ;point to Sequence Controller Data reg
|
||||
; (SC Index still points to Map Mask)
|
||||
FillRowsLoop:
|
||||
mov cx,[bp+RectAddrWidth] ;width across - 1
|
||||
mov al,es:[si] ;read display memory to latch this scan
|
||||
; line's pattern
|
||||
inc si ;point to the next pattern scan line, wrapping
|
||||
jnz short NoWrap ; back to the start of the pattern if
|
||||
sub si,4 ; we've run off the end
|
||||
NoWrap:
|
||||
mov al,bh ;put left-edge clip mask in AL
|
||||
out dx,al ;set the left-edge plane (clip) mask
|
||||
stosb ;draw the left edge (pixels come from latches;
|
||||
; value written by CPU doesn't matter)
|
||||
dec cx ;count off left edge address
|
||||
js FillLoopBottom ;that's the only address
|
||||
jz DoRightEdge ;there are only two addresses
|
||||
mov al,00fh ;middle addresses are drawn 4 pixels at a pop
|
||||
out dx,al ;set the middle pixel mask to no clip
|
||||
rep stosb ;draw the middle addresses four pixels apiece
|
||||
; (from latches; value written doesn't matter)
|
||||
DoRightEdge:
|
||||
mov al,bl ;put right-edge clip mask in AL
|
||||
out dx,al ;set the right-edge plane (clip) mask
|
||||
stosb ;draw the right edge (from latches; value
|
||||
; written doesn't matter)
|
||||
FillLoopBottom:
|
||||
add di,[bp+NextScanOffset] ;point to the start of the next scan
|
||||
; line of the rectangle
|
||||
dec word ptr [bp+Height] ;count down scan lines
|
||||
jnz FillRowsLoop
|
||||
FillDone:
|
||||
mov dx,GC_INDEX+1 ;restore the bit mask to its default,
|
||||
mov al,0ffh ; which selects all bits from the CPU
|
||||
out dx,al ; and none from the latches (the GC
|
||||
; Index still points to Bit Mask)
|
||||
pop di ;restore caller's register variables
|
||||
pop si
|
||||
mov sp,bp ;discard storage for local variables
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_FillPatternX endp
|
||||
end
|
||||
173
tests/pcx86/vga/L48-3.ASM
Normal file
173
tests/pcx86/vga/L48-3.ASM
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
; Mode X (320x240, 256 colors) display memory to display memory copy
|
||||
; routine. Left edge of source rectangle modulo 4 must equal left edge
|
||||
; of destination rectangle modulo 4. Works on all VGAs. Uses approach
|
||||
; of reading 4 pixels at a time from the source into the latches, then
|
||||
; writing the latches to the destination. Copies up to but not
|
||||
; including the column at SourceEndX and the row at SourceEndY. No
|
||||
; clipping is performed. Results are not guaranteed if the source and
|
||||
; destination overlap. C near-callable as:
|
||||
;
|
||||
; void CopyScreenToScreenX(int SourceStartX, int SourceStartY,
|
||||
; int SourceEndX, int SourceEndY, int DestStartX,
|
||||
; int DestStartY, unsigned int SourcePageBase,
|
||||
; unsigned int DestPageBase, int SourceBitmapWidth,
|
||||
; int DestBitmapWidth);
|
||||
|
||||
SC_INDEX equ 03c4h ;Sequence Controller Index register port
|
||||
MAP_MASK equ 02h ;index in SC of Map Mask register
|
||||
GC_INDEX equ 03ceh ;Graphics Controller Index register port
|
||||
BIT_MASK equ 08h ;index in GC of Bit Mask register
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in Mode X
|
||||
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
SourceStartX dw ? ;X coordinate of upper left corner of source
|
||||
SourceStartY dw ? ;Y coordinate of upper left corner of source
|
||||
SourceEndX dw ? ;X coordinate of lower right corner of source
|
||||
; (the row at SourceEndX is not copied)
|
||||
SourceEndY dw ? ;Y coordinate of lower right corner of source
|
||||
; (the column at SourceEndY is not copied)
|
||||
DestStartX dw ? ;X coordinate of upper left corner of dest
|
||||
DestStartY dw ? ;Y coordinate of upper left corner of dest
|
||||
SourcePageBase dw ? ;base offset in display memory of page in
|
||||
; which source resides
|
||||
DestPageBase dw ? ;base offset in display memory of page in
|
||||
; which dest resides
|
||||
SourceBitmapWidth dw ? ;# of pixels across source bitmap
|
||||
; (must be a multiple of 4)
|
||||
DestBitmapWidth dw ? ;# of pixels across dest bitmap
|
||||
; (must be a multiple of 4)
|
||||
parms ends
|
||||
|
||||
SourceNextScanOffset equ -2 ;local storage for distance from end of
|
||||
; one source scan line to start of next
|
||||
DestNextScanOffset equ -4 ;local storage for distance from end of
|
||||
; one dest scan line to start of next
|
||||
RectAddrWidth equ -6 ;local storage for address width of rectangle
|
||||
Height equ -8 ;local storage for height of rectangle
|
||||
STACK_FRAME_SIZE equ 8
|
||||
|
||||
.model small
|
||||
.data
|
||||
; Plane masks for clipping left and right edges of rectangle.
|
||||
LeftClipPlaneMask db 00fh,00eh,00ch,008h
|
||||
RightClipPlaneMask db 00fh,001h,003h,007h
|
||||
.code
|
||||
public _CopyScreenToScreenX
|
||||
_CopyScreenToScreenX proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
sub sp,STACK_FRAME_SIZE ;allocate space for local vars
|
||||
push si ;preserve caller's register variables
|
||||
push di
|
||||
push ds
|
||||
|
||||
cld
|
||||
mov dx,GC_INDEX ;set the bit mask to select all bits
|
||||
mov ax,00000h+BIT_MASK ; from the latches and none from
|
||||
out dx,ax ; the CPU, so that we can write the
|
||||
; latch contents directly to memory
|
||||
mov ax,SCREEN_SEG ;point ES to display memory
|
||||
mov es,ax
|
||||
mov ax,[bp+DestBitmapWidth]
|
||||
shr ax,1 ;convert to width in addresses
|
||||
shr ax,1
|
||||
mul [bp+DestStartY] ;top dest rect scan line
|
||||
mov di,[bp+DestStartX]
|
||||
shr di,1 ;X/4 = offset of first dest rect pixel in
|
||||
shr di,1 ; scan line
|
||||
add di,ax ;offset of first dest rect pixel in page
|
||||
add di,[bp+DestPageBase] ;offset of first dest rect pixel
|
||||
; in display memory
|
||||
mov ax,[bp+SourceBitmapWidth]
|
||||
shr ax,1 ;convert to width in addresses
|
||||
shr ax,1
|
||||
mul [bp+SourceStartY] ;top source rect scan line
|
||||
mov si,[bp+SourceStartX]
|
||||
mov bx,si
|
||||
shr si,1 ;X/4 = offset of first source rect pixel in
|
||||
shr si,1 ; scan line
|
||||
add si,ax ;offset of first source rect pixel in page
|
||||
add si,[bp+SourcePageBase] ;offset of first source rect
|
||||
; pixel in display memory
|
||||
and bx,0003h ;look up left edge plane mask
|
||||
mov ah,LeftClipPlaneMask[bx]; to clip
|
||||
mov bx,[bp+SourceEndX]
|
||||
and bx,0003h ;look up right edge plane
|
||||
mov al,RightClipPlaneMask[bx] ; mask to clip
|
||||
mov bx,ax ;put the masks in BX
|
||||
|
||||
mov cx,[bp+SourceEndX] ;calculate # of addresses across
|
||||
mov ax,[bp+SourceStartX] ; rect
|
||||
cmp cx,ax
|
||||
jle CopyDone ;skip if 0 or negative width
|
||||
dec cx
|
||||
and ax,not 011b
|
||||
sub cx,ax
|
||||
shr cx,1
|
||||
shr cx,1 ;# of addresses across rectangle to copy - 1
|
||||
jnz MasksSet ;there's more than one address to draw
|
||||
and bh,bl ;there's only one address, so combine the left
|
||||
; and right edge clip masks
|
||||
MasksSet:
|
||||
mov ax,[bp+SourceEndY]
|
||||
sub ax,[bp+SourceStartY] ;AX = height of rectangle
|
||||
jle CopyDone ;skip if 0 or negative height
|
||||
mov [bp+Height],ax
|
||||
mov ax,[bp+DestBitmapWidth]
|
||||
shr ax,1 ;convert to width in addresses
|
||||
shr ax,1
|
||||
sub ax,cx ;distance from end of one dest scan line to
|
||||
dec ax ; start of next
|
||||
mov [bp+DestNextScanOffset],ax
|
||||
mov ax,[bp+SourceBitmapWidth]
|
||||
shr ax,1 ;convert to width in addresses
|
||||
shr ax,1
|
||||
sub ax,cx ;distance from end of one source scan line to
|
||||
dec ax ; start of next
|
||||
mov [bp+SourceNextScanOffset],ax
|
||||
mov [bp+RectAddrWidth],cx ;remember width in addresses - 1
|
||||
;-----------------------BUG FIX
|
||||
mov dx,SC_INDEX
|
||||
mov al,MAP_MASK
|
||||
out dx,al ;point SC Index reg to Map Mask
|
||||
inc dx ;point to SC Data reg
|
||||
;-----------------------BUG FIX
|
||||
mov ax,es ;DS=ES=screen segment for MOVS
|
||||
mov ds,ax
|
||||
CopyRowsLoop:
|
||||
mov cx,[bp+RectAddrWidth] ;width across - 1
|
||||
mov al,bh ;put left-edge clip mask in AL
|
||||
out dx,al ;set the left-edge plane (clip) mask
|
||||
movsb ;copy the left edge (pixels go through
|
||||
; latches)
|
||||
dec cx ;count off left edge address
|
||||
js CopyLoopBottom ;that's the only address
|
||||
jz DoRightEdge ;there are only two addresses
|
||||
mov al,00fh ;middle addresses are drawn 4 pixels at a pop
|
||||
out dx,al ;set the middle pixel mask to no clip
|
||||
rep movsb ;draw the middle addresses four pixels apiece
|
||||
; (pixels copied through latches)
|
||||
DoRightEdge:
|
||||
mov al,bl ;put right-edge clip mask in AL
|
||||
out dx,al ;set the right-edge plane (clip) mask
|
||||
movsb ;draw the right edge (pixels copied through
|
||||
; latches)
|
||||
CopyLoopBottom:
|
||||
add si,[bp+SourceNextScanOffset] ;point to the start of
|
||||
add di,[bp+DestNextScanOffset] ; next source & dest lines
|
||||
dec word ptr [bp+Height] ;count down scan lines
|
||||
jnz CopyRowsLoop
|
||||
CopyDone:
|
||||
mov dx,GC_INDEX+1 ;restore the bit mask to its default,
|
||||
mov al,0ffh ; which selects all bits from the CPU
|
||||
out dx,al ; and none from the latches (the GC
|
||||
; Index still points to Bit Mask)
|
||||
pop ds
|
||||
pop di ;restore caller's register variables
|
||||
pop si
|
||||
mov sp,bp ;discard storage for local variables
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_CopyScreenToScreenX endp
|
||||
end
|
||||
118
tests/pcx86/vga/L48-4.ASM
Normal file
118
tests/pcx86/vga/L48-4.ASM
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
; Mode X (320x240, 256 colors) system memory to display memory copy
|
||||
; routine. Uses approach of changing the plane for each pixel copied;
|
||||
; this is slower than copying all pixels in one plane, then all pixels
|
||||
; in the next plane, and so on, but it is simpler; besides, images for
|
||||
; which performance is critical should be stored in off-screen memory
|
||||
; and copied to the screen via the latches. Copies up to but not
|
||||
; including the column at SourceEndX and the row at SourceEndY. No
|
||||
; clipping is performed. C near-callable as:
|
||||
;
|
||||
; void CopySystemToScreenX(int SourceStartX, int SourceStartY,
|
||||
; int SourceEndX, int SourceEndY, int DestStartX,
|
||||
; int DestStartY, char* SourcePtr, unsigned int DestPageBase,
|
||||
; int SourceBitmapWidth, int DestBitmapWidth);
|
||||
|
||||
SC_INDEX equ 03c4h ;Sequence Controller Index register port
|
||||
MAP_MASK equ 02h ;index in SC of Map Mask register
|
||||
SCREEN_SEG equ 0a000h ;segment of display memory in Mode X
|
||||
|
||||
parms struc
|
||||
dw 2 dup (?) ;pushed BP and return address
|
||||
SourceStartX dw ? ;X coordinate of upper left corner of source
|
||||
SourceStartY dw ? ;Y coordinate of upper left corner of source
|
||||
SourceEndX dw ? ;X coordinate of lower right corner of source
|
||||
; (the row at EndX is not copied)
|
||||
SourceEndY dw ? ;Y coordinate of lower right corner of source
|
||||
; (the column at EndY is not copied)
|
||||
DestStartX dw ? ;X coordinate of upper left corner of dest
|
||||
DestStartY dw ? ;Y coordinate of upper left corner of dest
|
||||
SourcePtr dw ? ;pointer in DS to start of bitmap in which
|
||||
; source resides
|
||||
DestPageBase dw ? ;base offset in display memory of page in
|
||||
; which dest resides
|
||||
SourceBitmapWidth dw ? ;# of pixels across source bitmap
|
||||
DestBitmapWidth dw ? ;# of pixels across dest bitmap
|
||||
; (must be a multiple of 4)
|
||||
parms ends
|
||||
|
||||
RectWidth equ -2 ;local storage for width of rectangle
|
||||
LeftMask equ -4 ;local storage for left rect edge plane mask
|
||||
STACK_FRAME_SIZE equ 4
|
||||
|
||||
.model small
|
||||
.code
|
||||
public _CopySystemToScreenX
|
||||
_CopySystemToScreenX proc near
|
||||
push bp ;preserve caller's stack frame
|
||||
mov bp,sp ;point to local stack frame
|
||||
sub sp,STACK_FRAME_SIZE ;allocate space for local vars
|
||||
push si ;preserve caller's register variables
|
||||
push di
|
||||
|
||||
cld
|
||||
mov ax,SCREEN_SEG ;point ES to display memory
|
||||
mov es,ax
|
||||
mov ax,[bp+SourceBitmapWidth]
|
||||
mul [bp+SourceStartY] ;top source rect scan line
|
||||
add ax,[bp+SourceStartX]
|
||||
add ax,[bp+SourcePtr] ;offset of first source rect pixel
|
||||
mov si,ax ; in DS
|
||||
|
||||
mov ax,[bp+DestBitmapWidth]
|
||||
shr ax,1 ;convert to width in addresses
|
||||
shr ax,1
|
||||
mov [bp+DestBitmapWidth],ax ;remember address width
|
||||
mul [bp+DestStartY] ;top dest rect scan line
|
||||
mov di,[bp+DestStartX]
|
||||
mov cx,di
|
||||
shr di,1 ;X/4 = offset of first dest rect pixel in
|
||||
shr di,1 ; scan line
|
||||
add di,ax ;offset of first dest rect pixel in page
|
||||
add di,[bp+DestPageBase] ;offset of first dest rect pixel
|
||||
; in display memory
|
||||
and cl,011b ;CL = first dest pixel's plane
|
||||
mov al,11h ;upper nibble comes into play when plane wraps
|
||||
; from 3 back to 0
|
||||
shl al,cl ;set the bit for the first dest pixel's plane
|
||||
mov [bp+LeftMask],al ; in each nibble to 1
|
||||
|
||||
mov cx,[bp+SourceEndX] ;calculate # of pixels across
|
||||
sub cx,[bp+SourceStartX] ; rect
|
||||
jle CopyDone ;skip if 0 or negative width
|
||||
mov [bp+RectWidth],cx
|
||||
mov bx,[bp+SourceEndY]
|
||||
sub bx,[bp+SourceStartY] ;BX = height of rectangle
|
||||
jle CopyDone ;skip if 0 or negative height
|
||||
mov dx,SC_INDEX ;point to SC Index register
|
||||
mov al,MAP_MASK
|
||||
out dx,al ;point SC Index reg to the Map Mask
|
||||
inc dx ;point DX to SC Data reg
|
||||
CopyRowsLoop:
|
||||
mov ax,[bp+LeftMask]
|
||||
mov cx,[bp+RectWidth]
|
||||
push si ;remember the start offset in the source
|
||||
push di ;remember the start offset in the dest
|
||||
CopyScanLineLoop:
|
||||
out dx,al ;set the plane for this pixel
|
||||
movsb ;copy the pixel to the screen
|
||||
rol al,1 ;set mask for next pixel's plane
|
||||
cmc ;advance destination address only when
|
||||
sbb di,0 ; wrapping from plane 3 to plane 0
|
||||
; (else undo INC DI done by MOVSB)
|
||||
loop CopyScanLineLoop
|
||||
pop di ;retrieve the dest start offset
|
||||
add di,[bp+DestBitmapWidth] ;point to the start of the
|
||||
; next scan line of the dest
|
||||
pop si ;retrieve the source start offset
|
||||
add si,[bp+SourceBitmapWidth] ;point to the start of the
|
||||
; next scan line of the source
|
||||
dec bx ;count down scan lines
|
||||
jnz CopyRowsLoop
|
||||
CopyDone:
|
||||
pop di ;restore caller's register variables
|
||||
pop si
|
||||
mov sp,bp ;discard storage for local variables
|
||||
pop bp ;restore caller's stack frame
|
||||
ret
|
||||
_CopySystemToScreenX endp
|
||||
end
|
||||
37
tests/pcx86/vga/MAKEFILE
Normal file
37
tests/pcx86/vga/MAKEFILE
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
CL=C:\MSDEV\BIN\WIN95\C816\BIN\CL.EXE
|
||||
INCLUDE=C:\MSDEV\BIN\WIN95\C816\INC
|
||||
LIB=C:\MSDEV\BIN\WIN95\C816\LIB
|
||||
MASM=C:\MSDEV\BIN\WIN95\MASM\MASM.EXE
|
||||
LINK=C:\MSDEV\BIN\WIN95\C816\BIN\LINK.EXE
|
||||
|
||||
.C.OBJ:
|
||||
$(CL) /c $<
|
||||
|
||||
.ASM.OBJ:
|
||||
$(MASM) $<;
|
||||
|
||||
.ASM.EXE:
|
||||
$(MASM) $*;
|
||||
$(LINK) $*;
|
||||
|
||||
ALL: L23-1.EXE L24-1.EXE L25-1.EXE L25-2.EXE L25-3.EXE L25-4.EXE L26-1.EXE L26-2.EXE L27-1.EXE L27-2.EXE L27-3.EXE \
|
||||
L28-1.EXE L28-2.EXE L28-3.EXE L29-1.EXE L29-2.EXE L29-3.EXE L29-4.EXE L30-1.EXE L30-2.EXE L31-1.EXE L31-2.EXE \
|
||||
L33-1.EXE L34-1.EXE L35-1.EXE L35-3.EXE L47-4.EXE L47-5.EXE L47-6.EXE L48-2.EXE
|
||||
|
||||
L35-1.EXE: L35-1.OBJ L35-2.OBJ
|
||||
$(LINK) $**,$@;
|
||||
|
||||
L35-3.EXE: L35-3.OBJ L35-2.OBJ
|
||||
$(LINK) $**,$@;
|
||||
|
||||
L47-4.EXE: L47-1.OBJ L47-2.OBJ L47-3.OBJ L47-4.OBJ L47-7.OBJ
|
||||
$(LINK) $**,$@;
|
||||
|
||||
L47-5.EXE: L47-1.OBJ L47-2.OBJ L47-3.OBJ L47-5.OBJ L47-7.OBJ
|
||||
$(LINK) $**,$@;
|
||||
|
||||
L47-6.EXE: L47-1.OBJ L47-2.OBJ L47-3.OBJ L47-6.OBJ L47-7.OBJ
|
||||
$(LINK) $**,$@;
|
||||
|
||||
L48-2.EXE: L48-1.OBJ L47-1.OBJ L48-2.OBJ
|
||||
$(LINK) $**,$@;
|
||||
131
tests/pcx86/vga/README.md
Normal file
131
tests/pcx86/vga/README.md
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
layout: page
|
||||
title: VGA "Black Book" Tests
|
||||
permalink: /tests/pcx86/vga/
|
||||
redirect_from:
|
||||
- /tests/pc/vga/
|
||||
machines:
|
||||
- type: pcx86
|
||||
id: deskpro386
|
||||
debugger: true
|
||||
config: /devices/pcx86/machine/compaq/deskpro386/vga/2048kb/debugger/machine.xml
|
||||
autoMount:
|
||||
A:
|
||||
path: /disks/pcx86/dos/compaq/3.31/COMPAQ-DOS331-DISK2.json
|
||||
B:
|
||||
path: /tests/pcx86/vga/VGABIN.json
|
||||
---
|
||||
|
||||
VGA "Black Book" Tests
|
||||
---
|
||||
|
||||
To aid in the development of PCjs VGA support, I've added some VGA tests to the project.
|
||||
For now, the only "tests" are samples taken directly from
|
||||
[Michael Abrash's Graphics Programming Black Book](https://github.com/jeffpar/abrash-black-book), which you
|
||||
can run in the [VGA "Black Book" Test Machine](#vga-black-book-test-machine) below.
|
||||
|
||||
Abrash's book is available on many sites, but I'm partial to the Markdown version that [James Gregory](https://github.com/jagregory)
|
||||
has made available on GitHub, because (a) it's a brilliant way to render and share the text, and (b) it apparently has
|
||||
Abrash's blessing, so I feel more comfortable forking it, using it, and resharing it.
|
||||
|
||||
The main reasons for my [fork](https://github.com/jeffpar/abrash-black-book) are to make the book's
|
||||
images display properly on GitHub, and to extract and add assorted source code listings as I need them. Since that
|
||||
project's [/src](https://github.com/jeffpar/abrash-black-book/tree/master/src) folder contains just the book's text,
|
||||
I've added a [/code](https://github.com/jeffpar/abrash-black-book/tree/master/code) folder for the source code listings.
|
||||
The name of each source code file matches the name displayed in the text (eg, [L23-1.ASM](L23-1.ASM) is Listing 23.1
|
||||
from [Chapter 23](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-23.md)).
|
||||
|
||||
I assume something similar was done on the CD-ROM that accompanied the Black Book, but since I don't have the original
|
||||
book or its CD-ROM, I'm extracting the source code directly from the Markdown text, and then "tabifying" it with 8-column
|
||||
tab stops.
|
||||
|
||||
Development of PCjs VGA support has just begun (June 2015), so don't expect everything here to to run properly yet.
|
||||
|
||||
---
|
||||
|
||||
List of VGA Samples from [Michael Abrash's Graphics Programming Black Book](https://github.com/jeffpar/abrash-black-book):
|
||||
|
||||
* [Chapter 23: Bones and Sinew](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-23.md)
|
||||
* [L23-1.ASM: Animates four balls bouncing around a playfield by using page flipping and panning](L23-1.ASM)
|
||||
* [Chapter 24: Parallel Processing with the VGA](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-24.md)
|
||||
* [L24-1.ASM: Illustrates operation of ALUs and latches of the VGA's Graphics Controller](L24-1.ASM)
|
||||
* [Chapter 25: VGA Data Machinery](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-25.md)
|
||||
* [L25-1.ASM: Illustrates operation of data rotate and bit mask features of Graphics Controller](L25-1.ASM)
|
||||
* [L25-2.ASM: Illustrates operation of Map Mask register when drawing to memory that already contains data](L25-2.ASM)
|
||||
* [L25-3.ASM: Illustrates operation of set/reset circuitry to force setting of memory that already contains data](L25-3.ASM)
|
||||
* [L25-4.ASM: Illustrates operation of set/reset circuitry in conjunction with CPU data](L25-4.ASM)
|
||||
* [Chapter 26: VGA Write Mode 3](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-26.md)
|
||||
* [L26-1.ASM: Illustrates operation of write mode 3 of the VGA](L26-1.ASM)
|
||||
* [L26-2.ASM: Illustrates high-speed text-drawing operation of write mode 3 of the VGA](L26-2.ASM)
|
||||
* [Chapter 27: Yet Another VGA Write Mode](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-27.md)
|
||||
* [L27-1.ASM: Illustrates one use of write mode 2 of the VGA and EGA by animating the image of an "A"](L27-1.ASM)
|
||||
* [L27-2.ASM: Illustrates one use of write mode 2 of the VGA and EGA by drawing lines in color patterns](L27-2.ASM)
|
||||
* [L27-3.ASM: Illustrates flipping from bit-mapped graphics mode to text mode and back](L27-3.ASM)
|
||||
* [Chapter 28: Reading VGA Memory](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-28.md)
|
||||
* [L28-1.ASM: Illustrates the use of the Read Map register in read mode 0](L28-1.ASM)
|
||||
* [L28-2.ASM: Illustrates use of read mode 1 (color compare mode) to detect collisions in display memory](L28-2.ASM)
|
||||
* [L28-3.ASM: Illustrates the use of Color Don't Care to support fast read-modify-write operations](L28-3.ASM)
|
||||
* [Chapter 29: Saving Screens and Other VGA Mysteries](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-29.md)
|
||||
* [L29-1.ASM: Puts up a mode 10h EGA graphics screen, then saves it to the file SNAPSHOT.SCR](L29-1.ASM)
|
||||
* [L29-2.ASM: Restores a mode 10h EGA graphics screen from the file SNAPSHOT.SCR](L29-2.ASM)
|
||||
* [L29-3.ASM: Illustrates the color mapping capabilities of the EGA's palette registers](L29-3.ASM)
|
||||
* [L29-4.ASM: Demonstrates screen blanking via bit 5 of the Attribute Controller Index register](L29-4.ASM)
|
||||
* [Chapter 30: Video Est Omnis Divisa](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-30.md)
|
||||
* [L30-1.ASM: Demonstrates the VGA/EGA split screen in action](L30-1.ASM)
|
||||
* [L30-2.ASM: Demonstrates the interaction of the split screen and horizontal pel panning](L30-2.ASM)
|
||||
* [Chapter 31: Higher 256-Color Resolution on the VGA](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-31.md)
|
||||
* [L31-1.ASM: Demonstrates pixel drawing in 320x400 256-color mode on the VGA](L31-1.ASM)
|
||||
* [L31-2.ASM: Demonstrates the two pages available in 320x400 256-color modes on a VGA](L31-2.ASM)
|
||||
* [Chapter 32: Be It Resolved: 360x480](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-32.md)
|
||||
* [L32-1.ASM: Illustrates VGA line drawing in 360x480 256-color mode](L32-1.ASM)
|
||||
* [L32-2.C: Sample program to illustrate VGA line drawing in 360x480 256-color mode](L32-2.C)
|
||||
* [Chapter 33: Yogi Bear and Eurythmics Confront VGA Colors](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-33.md)
|
||||
* [L33-1.ASM: Demonstrates use of the DAC registers by selecting a smoothly contiguous set of 256 colors](L33-1.ASM)
|
||||
* [Chapter 34: Changing Colors without Writing Pixels](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-34.md)
|
||||
* [L34-1.ASM: Fills a band across the screen with vertical bars in all 256 attributes](L34-1.ASM)
|
||||
* [Chapter 35: Bresenham Is Fast, and Fast Is Good](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-35.md)
|
||||
* [L35-1.C: C implementation of Bresenham's line drawing algorithm](L35-1.C)
|
||||
* [L35-2.C: Sample program to illustrate EGA/VGA line drawing routines](L35-2.C)
|
||||
* [L35-3.ASM: Fast assembler implementation of Bresenham's line drawing algorithm](L35-3.ASM)
|
||||
* [Chapter 47: Mode X: 256-Color VGA Magic](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-35.md)
|
||||
* [L47-1.ASM: Mode X (320x240, 256 colors) mode set routine](L47-1.ASM)
|
||||
* [L47-2.ASM: Mode X (320x240, 256 colors) write pixel routine](L47-2.ASM)
|
||||
* [L47-3.ASM: Mode X (320x240, 256 colors) read pixel routine](L47-3.ASM)
|
||||
* [L47-4.ASM: Mode X (320x240, 256 colors) rectangle fill routine (slow)](L47-4.ASM)
|
||||
* [L47-5.ASM: Mode X (320x240, 256 colors) rectangle fill routine (medium)](L47-5.ASM)
|
||||
* [L47-6.ASM: Mode X (320x240, 256 colors) rectangle fill routine (fast)](L47-6.ASM)
|
||||
* [L47-7.C: Program to demonstrate mode X (320x240, 256-colors) rectangle fill](L47-7.C)
|
||||
|
||||
---
|
||||
|
||||
Also, I've updated the PCjs [Library](/disks/pcx86/library.xml) disk collection to include a disk containing executables
|
||||
built from the sources in this directory:
|
||||
|
||||
```xml
|
||||
<disk path="/tests/pcx86/vga/VGABIN.json">VGA Tests (Black Book)</disk>
|
||||
```
|
||||
|
||||
The "VGA Tests (Black Book)" disk image (VGABIN) was built with this command:
|
||||
|
||||
diskdump --dir=bin --format=json --output=VGABIN.json
|
||||
|
||||
Alternatively, if *path* refers to a directory (ending with a slash) instead of a disk image, the PCjs client will ask
|
||||
the PCjs web server to enumerate the contents of that directory and send back a JSON-encoded disk image containing all
|
||||
the files in that directory (including any subdirectories) every time that disk is requested. Since this puts an added
|
||||
burden on the server, it's best to do this only when running PCjs from a local PCjs web server.
|
||||
|
||||
```xml
|
||||
<disk path="/tests/pcx86/vga/">VGA Tests (Black Book)</disk>
|
||||
```
|
||||
|
||||
One advantage of using [DiskDump](/modules/diskdump/) is that it automatically converts linefeeds in known text files
|
||||
(including ASM files) into DOS-compatible CR/LF sequences.
|
||||
|
||||
VGA "Black Book" Test Machine
|
||||
---
|
||||
|
||||
The [Compaq DeskPro 386](/devices/pcx86/machine/compaq/deskpro386/vga/2048kb/) machine below loads the
|
||||
"VGA Tests (Black Book)" disk from the PCjs [Library](/disks/pcx86/library.xml) disk collection into Drive B.
|
||||
Click the "Run" button to start the machine.
|
||||
|
||||
{% include machine.html id="deskpro386" %}
|
||||
27
tests/pcx86/vga/REGS.H
Normal file
27
tests/pcx86/vga/REGS.H
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifdef __TURBOC__
|
||||
#define USES_REGS
|
||||
#else
|
||||
#define USES_REGS union REGS reg; struct SREGS sreg;
|
||||
#define _AH reg.h.ah
|
||||
#define _AL reg.h.al
|
||||
#define _BH reg.h.bh
|
||||
#define _BL reg.h.bl
|
||||
#define _CH reg.h.ch
|
||||
#define _CL reg.h.cl
|
||||
#define _DH reg.h.dh
|
||||
#define _DL reg.h.dl
|
||||
#define _AX reg.x.ax
|
||||
#define _BX reg.x.bx
|
||||
#define _CX reg.x.cx
|
||||
#define _DX reg.x.dx
|
||||
#define _SI reg.x.si
|
||||
#define _DI reg.x.di
|
||||
#define _DS sreg.ds
|
||||
#define _ES sreg.es
|
||||
#define _SS sreg.ss
|
||||
#define geninterrupt(n) int86x(n,®,®,&sreg)
|
||||
#define inport(port) _inpw(port)
|
||||
#define inportb(port) _inp(port)
|
||||
#define outport(port,data) _outpw(port,data)
|
||||
#define outportb(port,data) _outp(port,data)
|
||||
#endif
|
||||
1
tests/pcx86/vga/VGABIN.json
Normal file
1
tests/pcx86/vga/VGABIN.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue