Compare commits
35 changed files with 536 additions and 535 deletions
4
Makefile
Normal file → Executable file
4
Makefile
Normal file → Executable file
|
|
@ -7,12 +7,12 @@ all: html epub mobi
|
||||||
html:
|
html:
|
||||||
rm -rf out/html && mkdir -p out/html
|
rm -rf out/html && mkdir -p out/html
|
||||||
cp -r images html/book.css out/html/
|
cp -r images html/book.css out/html/
|
||||||
pandoc --to html5+smart -o out/html/black-book.html --section-divs --toc --standalone --template=html/template.html $(FILES)
|
pandoc -S --to html5 -o out/html/black-book.html --section-divs --toc --standalone --template=html/template.html $(FILES)
|
||||||
|
|
||||||
epub:
|
epub:
|
||||||
mkdir -p out
|
mkdir -p out
|
||||||
rm -f out/black-book.epub
|
rm -f out/black-book.epub
|
||||||
pandoc --to epub3+smart -o out/black-book.epub --epub-cover-image images/cover.png --toc --epub-chapter-level=2 --data-dir=epub --template=epub/template.html $(FILES)
|
pandoc -S --to epub3 -o out/black-book.epub --epub-cover-image images/cover.png --toc --epub-chapter-level=2 --data-dir=epub --template=epub/template.html $(FILES)
|
||||||
|
|
||||||
mobi:
|
mobi:
|
||||||
rm -f out/black-book.mobi
|
rm -f out/black-book.mobi
|
||||||
|
|
|
||||||
24
README.md
24
README.md
|
|
@ -2,38 +2,36 @@
|
||||||
|
|
||||||
This is the source for an ebook version of Michael Abrash's Black Book of Graphics Programming (Special Edition), originally published in 1997 and [released online for free in 2001](http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919).
|
This is the source for an ebook version of Michael Abrash's Black Book of Graphics Programming (Special Edition), originally published in 1997 and [released online for free in 2001](http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919).
|
||||||
|
|
||||||
Reproduced with blessing of Michael Abrash, converted and maintained by [James Gregory](mailto:james@jagregory.com).
|
Reproduced with permission of Michael Abrash, converted and maintained by [James Gregory](mailto:james@jagregory.com).
|
||||||
|
|
||||||
The [GitHub releases list](https://github.com/jagregory/abrash-black-book/releases) has an EPUB and Mobi version available for download, and you can find a mirror of the HTML version at [www.jagregory.com/abrash-black-book](http://www.jagregory.com/abrash-black-book/).
|
|
||||||
|
|
||||||
## How does this differ from the previously released versions?
|
## How does this differ from the previously released versions?
|
||||||
|
|
||||||
The book is now out of print, and hard to come by. Last time I checked, it was going for over $200 on eBay.
|
The book is now out of print, and hard to come by. Last time I checked it was going for over $200 on ebay.
|
||||||
|
|
||||||
The version which Michael and Dr. Dobbs released in 2001 was a collection of PDF files. That version is [still available](http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919). However, the structure (multiple files) and the format (PDF) result in a poor user experience on an ebook reader or other mobile device.
|
The version which Michael and Dr. Dobbs released in 2001 was as a collection PDFs. This version is [still available](http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919); however, the structure (multiple files) and the format (PDF) doesn't lend itself well to reading on a ebook reader or other mobile device.
|
||||||
|
|
||||||
This version has been thoroughly cleaned of artifacts and condensed into something which can easily be converted into an ebook-friendly format. You can read this version online at GitHub, or download any of the EPUB or Mobi releases. You can clone the repository and generate your own version with [pandoc](http://johnmacfarlane.net/pandoc/) if necessary.
|
This version has been thoroughly cleaned of artefacts and condensed into something which can be easily converted into a ebook friendly format. You can read this version online at Github, or download any of the Epub or Mobi releases. You can clone the repository and generate your own version with [pandoc](http://johnmacfarlane.net/pandoc/) if necessary.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Changes are welcome, especially conversion-related ones. If you spot any problems while reading, please [submit an issue](https://github.com/jagregory/abrash-black-book/issues) and I'll correct it. Pull requests are always welcome.
|
Changes are welcome, especially conversion related ones. If you spot any issues whilst reading, please submit an issue and I'll correct it. Pull Requests are always welcome.
|
||||||
|
|
||||||
Some larger changes could be made to improve the content. I'd love to see some of the images converted to a vector representation so we can provide higher-resolution versions. Formulas and equations could be typeset with [MathJax](http://www.mathjax.org/).
|
There's some larger changes that could be made to help preserve the content longer term. I'd love to see some of the images converted to a vector representation so we can provide higher-resolution versions, and similarly formulas and maths could be represented in MathML.
|
||||||
|
|
||||||
## Generating your own ebook
|
## Generating your own ebook
|
||||||
|
|
||||||
You need to have the following software installed and on your `PATH` before you begin:
|
You need to have the following software installed and on your `PATH` before you begin:
|
||||||
|
|
||||||
* [pandoc](http://johnmacfarlane.net/pandoc/) version 2.0 or greater for Markdown to HTML and EPUB conversion.
|
* [pandoc](http://johnmacfarlane.net/pandoc/) for Markdown to HTML and Epub conversion.
|
||||||
* [kindlegen](http://www.amazon.com/gp/feature.html?docId=1000765211) for Epub to Mobi conversion.
|
* [kindlegen](http://www.amazon.com/gp/feature.html?docId=1000765211) for Epub to Mobi conversion.
|
||||||
|
|
||||||
To generate an e-reader friendly version of the book, you can use `make` with one of the following options:
|
To generate an e-reader friendly version of the book, you can use `make` with one of the following options:
|
||||||
|
|
||||||
* `html` - build an HTML5 single-page version of the book
|
* `html` - build a HTML5 single-page version of the book
|
||||||
* `epub` - build an EPUB3 ebook
|
* `epub` - build an Epub3 ebook
|
||||||
* `mobi` - build a Kindle-friendly Mobi
|
* `mobi` - build a Kindle-friendly Mobi
|
||||||
* `all` - do all of the above
|
* `all` - do all of the above
|
||||||
|
|
||||||
Once complete, there will be an `out` directory with a `black-book.epub`, a `black-book.mobi` and an `html` directory with a `black-book.html` file.
|
Once complete, there'll be an `out` directory with a `black-book.epub`, a `black-book.mobi` and a `html` directory with a `black-book.html` file.
|
||||||
|
|
||||||
> Note: Generating a Mobi requires an EPUB to already exist. Also, Mobi generation can be *slow* because of compression. If you want a quick Mobi conversion you can just run `kindlegen out/black-book.epub`.
|
> Note: Generating a mobi requires an epub to already exist. Also, mobi generation can be *slow* because of compression. If you want a quick mobi conversion you can just run `kindlegen out/black-book.epub`.
|
||||||
|
|
|
||||||
BIN
images/13-01.jpg
Normal file
BIN
images/13-01.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
images/13-01.png
BIN
images/13-01.png
Binary file not shown.
|
Before Width: | Height: | Size: 88 KiB |
|
|
@ -23,7 +23,7 @@ learn in the space of a few months on the PC.
|
||||||
|
|
||||||
The biggest benefit to me of actually making money as a programmer was
|
The biggest benefit to me of actually making money as a programmer was
|
||||||
the ability to buy all the books and magazines I wanted. I bought a lot.
|
the ability to buy all the books and magazines I wanted. I bought a lot.
|
||||||
I was in territory that I knew almost nothing about, so I read
|
I was in territory that I new almost nothing about, so I read
|
||||||
*everything* that I could get my hands on. Feature articles, editorials,
|
*everything* that I could get my hands on. Feature articles, editorials,
|
||||||
even advertisements held information for me to assimilate.
|
even advertisements held information for me to assimilate.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ requires over two and one-half minutes to checksum *one* file!
|
||||||
These results make it clear that it's folly to rely on your compiler's
|
These results make it clear that it's folly to rely on your compiler's
|
||||||
optimization to make your programs fast. Listing 1.1 is simply poorly
|
optimization to make your programs fast. Listing 1.1 is simply poorly
|
||||||
designed, and no amount of compiler optimization will compensate for
|
designed, and no amount of compiler optimization will compensate for
|
||||||
that failing. To drive home the point, Listings 1.2 and 1.3, which
|
that failing. To drive home the point, conListings 1.2 and 1.3, which
|
||||||
together are equivalent to Listing 1.1 except that the entire checksum
|
together are equivalent to Listing 1.1 except that the entire checksum
|
||||||
loop is written in tight assembly code. The assembly language
|
loop is written in tight assembly code. The assembly language
|
||||||
implementation is indeed faster than any of the C versions, as shown in
|
implementation is indeed faster than any of the C versions, as shown in
|
||||||
|
|
@ -363,12 +363,12 @@ _ChecksumFile proc near
|
||||||
ChecksumLoop:
|
ChecksumLoop:
|
||||||
mov ah,3fh ;DOS read file function #
|
mov ah,3fh ;DOS read file function #
|
||||||
int 21h ;read the byte
|
int 21h ;read the byte
|
||||||
jc ErrorEnd ;an error occurred
|
jcErrorEnd;an error occurred
|
||||||
and ax,ax ;any bytes read?
|
and ax,ax ;any bytes read?
|
||||||
jz Success ;no-end of file reached-we're done
|
jz Success ;no-end of file reached-we're done
|
||||||
add si,[TempWord] ;add the byte into the
|
add si,[TempWord] ;add the byte into the
|
||||||
;checksum total
|
;checksum total
|
||||||
jmp ChecksumLoop
|
jmpChecksumLoop
|
||||||
ErrorEnd:
|
ErrorEnd:
|
||||||
sub ax,ax ;error
|
sub ax,ax ;error
|
||||||
jmp short Done
|
jmp short Done
|
||||||
|
|
@ -381,7 +381,7 @@ Done:
|
||||||
pop si ;restore C's register variable
|
pop si ;restore C's register variable
|
||||||
pop bp
|
pop bp
|
||||||
ret
|
ret
|
||||||
_ChecksumFile endp
|
_ChecksumFileendp
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -500,7 +500,7 @@ your programs that directly affect response time. Notice, for example,
|
||||||
that I haven't bothered to implement a version of the checksum program
|
that I haven't bothered to implement a version of the checksum program
|
||||||
entirely in assembly; Listings 1.2 and 1.6 call assembly subroutines
|
entirely in assembly; Listings 1.2 and 1.6 call assembly subroutines
|
||||||
that handle the time-critical operations, but C is still used for
|
that handle the time-critical operations, but C is still used for
|
||||||
checking command-line parameters, opening files, printing, and the
|
checking command-line parameters, operning files, printing, and the
|
||||||
like.
|
like.
|
||||||
|
|
||||||
> 
|
> 
|
||||||
|
|
@ -521,7 +521,7 @@ Listing 1.4 is good, but let's see if there are other—perhaps less
|
||||||
obvious—ways to get the same results faster. Let's start by considering
|
obvious—ways to get the same results faster. Let's start by considering
|
||||||
why Listing 1.4 is so much better than Listing 1.1. Like `read()`,
|
why Listing 1.4 is so much better than Listing 1.1. Like `read()`,
|
||||||
`getc()` calls DOS to read from the file; the speed improvement of
|
`getc()` calls DOS to read from the file; the speed improvement of
|
||||||
Listing 1.4 over Listing 1.1 occurs because `getc()` reads many bytes
|
Listing 1.4 over Listing 1.1 occurs because `getc()` eads many bytes
|
||||||
at once via DOS, then manages those bytes for us. That's faster than
|
at once via DOS, then manages those bytes for us. That's faster than
|
||||||
reading them one at a time using `read()`—but there's no reason to
|
reading them one at a time using `read()`—but there's no reason to
|
||||||
think that it's faster than having our program read and manage blocks
|
think that it's faster than having our program read and manage blocks
|
||||||
|
|
@ -563,7 +563,7 @@ The third reason is often fallacious. C library functions are not always
|
||||||
written in assembly, nor are they always particularly well-optimized.
|
written in assembly, nor are they always particularly well-optimized.
|
||||||
(In fact, they're often written for *portability*, which has nothing to
|
(In fact, they're often written for *portability*, which has nothing to
|
||||||
do with optimization.) What's more, they're general-purpose functions,
|
do with optimization.) What's more, they're general-purpose functions,
|
||||||
and often can be outperformed by well-but-not-brilliantly-written code
|
and often can be outperformed by well-but-not- brilliantly-written code
|
||||||
that is well-matched to a specific task. As an example, consider Listing
|
that is well-matched to a specific task. As an example, consider Listing
|
||||||
1.5, which uses internal buffering to handle blocks of bytes at a time.
|
1.5, which uses internal buffering to handle blocks of bytes at a time.
|
||||||
Table 1.1 shows that Listing 1.5 is 2.5 to 4 times faster than Listing
|
Table 1.1 shows that Listing 1.5 is 2.5 to 4 times faster than Listing
|
||||||
|
|
@ -629,7 +629,7 @@ main(int argc, char *argv[]) {
|
||||||
while ( LengthCount-- ) {
|
while ( LengthCount-- ) {
|
||||||
/* Add each byte in turn into the checksum accumulator */
|
/* Add each byte in turn into the checksum accumulator */
|
||||||
Checksum += (unsigned int) *WorkingPtr++;
|
Checksum += (unsigned int) *WorkingPtr++;
|
||||||
}
|
}
|
||||||
} while ( WorkingLength );
|
} while ( WorkingLength );
|
||||||
|
|
||||||
/* Report the result */
|
/* Report the result */
|
||||||
|
|
@ -667,7 +667,7 @@ indeed make a significant difference. Table 1.1 indicates that the
|
||||||
optimized version of Listing 1.5 produced by Microsoft C outperforms an
|
optimized version of Listing 1.5 produced by Microsoft C outperforms an
|
||||||
unoptimized version of the same code by more than 60 percent. What's
|
unoptimized version of the same code by more than 60 percent. What's
|
||||||
more, a mostly-assembly version of Listing 1.5, shown in Listings 1.6
|
more, a mostly-assembly version of Listing 1.5, shown in Listings 1.6
|
||||||
and 1.7, outperforms even the best-optimized C version of Listing 1.5 by 26
|
and 1.7, outperforms even the best-optimized C version of List1.5 by 26
|
||||||
percent. These are considerable improvements, well worth pursuing—once
|
percent. These are considerable improvements, well worth pursuing—once
|
||||||
the design has been maxed out.
|
the design has been maxed out.
|
||||||
|
|
||||||
|
|
@ -754,12 +754,12 @@ Parms struc
|
||||||
Buffer dw ?
|
Buffer dw ?
|
||||||
BufferLength dw ?
|
BufferLength dw ?
|
||||||
Checksum dw ?
|
Checksum dw ?
|
||||||
Parms ends
|
Parmsends
|
||||||
;
|
;
|
||||||
.model small
|
.model small
|
||||||
.code
|
.code
|
||||||
public _ChecksumChunk
|
public _ChecksumChunk
|
||||||
_ChecksumChunk proc near
|
_ChecksumChunkprocnear
|
||||||
push bp
|
push bp
|
||||||
mov bp,sp
|
mov bp,sp
|
||||||
push si ;save C's register variable
|
push si ;save C's register variable
|
||||||
|
|
@ -779,7 +779,7 @@ ChecksumLoop:
|
||||||
pop si ;restore C's register variable
|
pop si ;restore C's register variable
|
||||||
pop bp
|
pop bp
|
||||||
ret
|
ret
|
||||||
_ChecksumChunk endp
|
_ChecksumChunkendp
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ much different from the original, and in fact still contains exactly the
|
||||||
same number of instructions, the performance of the entire subroutine
|
same number of instructions, the performance of the entire subroutine
|
||||||
improved by about 10 percent from just this one change. (Incidentally,
|
improved by about 10 percent from just this one change. (Incidentally,
|
||||||
that wasn't the end of the optimization; I eliminated the `DEC` and
|
that wasn't the end of the optimization; I eliminated the `DEC` and
|
||||||
`JNZ` instructions by expanding the four iterations of the loop—but
|
`JNJ` instructions by expanding the four iterations of the loop—but
|
||||||
that's a tale for another chapter.)
|
that's a tale for another chapter.)
|
||||||
|
|
||||||
The point is this: To write truly superior assembly programs, you need
|
The point is this: To write truly superior assembly programs, you need
|
||||||
|
|
@ -200,7 +200,7 @@ enough.
|
||||||
The single most critical aspect of the hardware, and the one about which
|
The single most critical aspect of the hardware, and the one about which
|
||||||
it is hardest to learn, is the CPU. The x86 family CPUs have a complex,
|
it is hardest to learn, is the CPU. The x86 family CPUs have a complex,
|
||||||
irregular instruction set, and, unlike most processors, they are neither
|
irregular instruction set, and, unlike most processors, they are neither
|
||||||
straightforward nor well-documented true code performance. What's more,
|
straightforward nor wellregarding true code performance. What's more,
|
||||||
assembly is so difficult to learn that most articles and books that
|
assembly is so difficult to learn that most articles and books that
|
||||||
present assembly code settle for code that just works, rather than code
|
present assembly code settle for code that just works, rather than code
|
||||||
that pushes the CPU to its limits. In fact, since most articles and
|
that pushes the CPU to its limits. In fact, since most articles and
|
||||||
|
|
@ -293,7 +293,7 @@ all the more so given that compilers are constrained by the limitations
|
||||||
of high-level languages and by the process of transformation from
|
of high-level languages and by the process of transformation from
|
||||||
high-level to machine language. Consequently, carefully optimized
|
high-level to machine language. Consequently, carefully optimized
|
||||||
assembly is not just the language of choice but the *only* choice for
|
assembly is not just the language of choice but the *only* choice for
|
||||||
the 1 percent to 10 percent of code—usually consisting of small,
|
the 1percent to 10 percent of code—usually consisting of small,
|
||||||
well-defined subroutines—that determines overall program performance,
|
well-defined subroutines—that determines overall program performance,
|
||||||
and it is the only choice for code that must be as compact as possible,
|
and it is the only choice for code that must be as compact as possible,
|
||||||
as well. In the run-of-the-mill, non-time-critical portions of your
|
as well. In the run-of-the-mill, non-time-critical portions of your
|
||||||
|
|
|
||||||
|
|
@ -163,34 +163,34 @@ presented in Chapter K on the companion CD-ROM.
|
||||||
; in when ZTimerOn was called.
|
; in when ZTimerOn was called.
|
||||||
;
|
;
|
||||||
|
|
||||||
Code segment word public 'CODE'
|
Code segment word public ‘CODE'
|
||||||
assume cs:Code, ds:nothing
|
assumecs: Code, ds:nothing
|
||||||
public ZTimerOn, ZTimerOff, ZTimerReport
|
public ZTimerOn, ZTimerOff, ZTimerReport
|
||||||
|
|
||||||
;
|
;
|
||||||
; Base address of the 8253 timer chip.
|
; Base address of the 8253 timer chip.
|
||||||
;
|
;
|
||||||
BASE_8253 equ 40h
|
BASE_8253equ40h
|
||||||
;
|
;
|
||||||
; The address of the timer 0 count registers in the 8253.
|
; The address of the timer 0 count registers in the 8253.
|
||||||
;
|
;
|
||||||
TIMER_0_8253 equ BASE_8253 + 0
|
TIMER_0_8253 equBASE_8253 + 0
|
||||||
;
|
;
|
||||||
; The address of the mode register in the 8253.
|
; The address of the mode register in the 8253.
|
||||||
;
|
;
|
||||||
MODE_8253 equ BASE_8253 + 3
|
MODE_8253 equBASE_8253 + 3
|
||||||
;
|
;
|
||||||
; The address of Operation Command Word 3 in the 8259 Programmable
|
; The address of Operation Command Word 3 in the 8259 Programmable
|
||||||
; Interrupt Controller (PIC) (write only, and writable only when
|
; Interrupt Controller (PIC) (write only, and writable only when
|
||||||
; bit 4 of the byte written to this address is 0 and bit 3 is 1).
|
; bit 4 of the byte written to this address is 0 and bit 3 is 1).
|
||||||
;
|
;
|
||||||
OCW3 equ 20h
|
OCW3 equ20h
|
||||||
;
|
;
|
||||||
; The address of the Interrupt Request register in the 8259 PIC
|
; The address of the Interrupt Request register in the 8259 PIC
|
||||||
; (read only, and readable only when bit 1 of OCW3 = 1 and bit 0
|
; (read only, and readable only when bit 1 of OCW3 = 1 and bit 0
|
||||||
; of OCW3 = 0).
|
; of OCW3 = 0).
|
||||||
;
|
;
|
||||||
IRR equ 20h
|
IRR equ20h
|
||||||
;
|
;
|
||||||
; Macro to emulate a POPF instruction in order to fix the bug in some
|
; Macro to emulate a POPF instruction in order to fix the bug in some
|
||||||
; 80286 chips which allows interrupts to occur during a POPF even when
|
; 80286 chips which allows interrupts to occur during a POPF even when
|
||||||
|
|
@ -220,7 +220,7 @@ OriginalFlags db ? ; storage for upper byte of
|
||||||
; ZTimerOn called
|
; ZTimerOn called
|
||||||
TimedCount dw ? ; timer 0 count when the timer
|
TimedCount dw ? ; timer 0 count when the timer
|
||||||
; is stopped
|
; is stopped
|
||||||
ReferenceCount dw ? ; number of counts required to
|
ReferenceCount dw ; number of counts required to
|
||||||
; execute timer overhead code
|
; execute timer overhead code
|
||||||
OverflowFlag db ? ; used to indicate whether the
|
OverflowFlag db ? ; used to indicate whether the
|
||||||
; timer overflowed during the
|
; timer overflowed during the
|
||||||
|
|
@ -229,28 +229,28 @@ OverflowFlag db ? ; used to indicate whether the
|
||||||
; String printed to report results.
|
; String printed to report results.
|
||||||
;
|
;
|
||||||
OutputStr label byte
|
OutputStr label byte
|
||||||
db 0dh, 0ah, 'Timed count: ', 5 dup (?)
|
db 0dh, 0ah, ‘Timed count: ‘, 5 dup (?)
|
||||||
ASCIICountEnd label byte
|
ASCIICountEnd labelbyte
|
||||||
db ' microseconds', 0dh, 0ah
|
db ‘ microseconds', 0dh, 0ah
|
||||||
db '$'
|
db ‘$'
|
||||||
;
|
;
|
||||||
; String printed to report timer overflow.
|
; String printed to report timer overflow.
|
||||||
;
|
;
|
||||||
OverflowStr label byte
|
OverflowStr label byte
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '****************************************************'
|
db ‘****************************************************'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* The timer overflowed, so the interval timed was *'
|
db ‘* The timer overflowed, so the interval timed was *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* too long for the precision timer to measure. *'
|
db ‘* too long for the precision timer to measure. *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* Please perform the timing test again with the *'
|
db ‘* Please perform the timing test again with the *'
|
||||||
|
db0dh, 0ah
|
||||||
|
db ‘* long-period timer. *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* long-period timer. *'
|
db ‘****************************************************'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '****************************************************'
|
db ‘$'
|
||||||
db 0dh, 0ah
|
|
||||||
db '$'
|
|
||||||
|
|
||||||
; ********************************************************************
|
; ********************************************************************
|
||||||
; * Routine called to start timing. *
|
; * Routine called to start timing. *
|
||||||
|
|
@ -350,9 +350,9 @@ ZTimerOff proc near
|
||||||
; timer interrupt.
|
; timer interrupt.
|
||||||
;
|
;
|
||||||
mov al,00001010b ; OCW3, set up to read
|
mov al,00001010b ; OCW3, set up to read
|
||||||
out OCW3,al ; Interrupt Request register
|
out OCW3,al; Int errupt Request register
|
||||||
DELAY
|
DELAY
|
||||||
in al,IRR ; read Interrupt Request
|
ina l,IRR; read Interrupt Request
|
||||||
; register
|
; register
|
||||||
and al,1 ; set AL to 1 if IRQ0 (the
|
and al,1 ; set AL to 1 if IRQ0 (the
|
||||||
; timer interrupt) is pending
|
; timer interrupt) is pending
|
||||||
|
|
@ -418,7 +418,7 @@ ZTimerOff endp
|
||||||
; Called by ZTimerOff to start timer for overhead measurements.
|
; Called by ZTimerOff to start timer for overhead measurements.
|
||||||
;
|
;
|
||||||
|
|
||||||
ReferenceZTimerOn proc near
|
ReferenceZTimerOnproc near
|
||||||
;
|
;
|
||||||
; Save the context of the program being timed.
|
; Save the context of the program being timed.
|
||||||
;
|
;
|
||||||
|
|
@ -445,7 +445,7 @@ ReferenceZTimerOn proc near
|
||||||
pop ax
|
pop ax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
ReferenceZTimerOn endp
|
ReferenceZTimerOnendp
|
||||||
|
|
||||||
;
|
;
|
||||||
; Called by ZTimerOff to stop timer and add result to ReferenceCount
|
; Called by ZTimerOff to stop timer and add result to ReferenceCount
|
||||||
|
|
@ -488,7 +488,7 @@ ReferenceZTimerOff endp
|
||||||
; * Routine called to report timing results. *
|
; * Routine called to report timing results. *
|
||||||
; ********************************************************************
|
; ********************************************************************
|
||||||
|
|
||||||
ZTimerReport proc near
|
ZTimerReport procnear
|
||||||
|
|
||||||
pushf
|
pushf
|
||||||
push ax
|
push ax
|
||||||
|
|
@ -671,7 +671,7 @@ count reaches zero, the timer turns over and starts counting down again
|
||||||
without stopping, and a pulse is generated for a single clock period.
|
without stopping, and a pulse is generated for a single clock period.
|
||||||
While the pulse is not held for nearly as long as in square wave mode,
|
While the pulse is not held for nearly as long as in square wave mode,
|
||||||
it doesn't matter, since the 8259 interrupt controller is configured in
|
it doesn't matter, since the 8259 interrupt controller is configured in
|
||||||
the PC to be edge-triggered and hence cares only about the existence of a pulse
|
the PC to be edgeand hence cares only about the existence of a pulse
|
||||||
from timer 0, not the duration of the pulse. As a result, timer 0
|
from timer 0, not the duration of the pulse. As a result, timer 0
|
||||||
continues to generate timer interrupts in divide-by-N mode, and the
|
continues to generate timer interrupts in divide-by-N mode, and the
|
||||||
system clock continues to maintain good time.
|
system clock continues to maintain good time.
|
||||||
|
|
@ -688,7 +688,7 @@ the Zen timer shown in Listing 3.1 supports.
|
||||||
In fact, the Zen timer shown in Listing 3.1 can only time intervals of
|
In fact, the Zen timer shown in Listing 3.1 can only time intervals of
|
||||||
up to about 54 ms in length, since that is the period of time that can
|
up to about 54 ms in length, since that is the period of time that can
|
||||||
be measured by timer 0 before its count turns over and repeats.
|
be measured by timer 0 before its count turns over and repeats.
|
||||||
Fifty-four ms may not seem like a very long time, but even a CPU as slow
|
fifty-four ms may not seem like a very long time, but even a CPU as slow
|
||||||
as the 8088 can perform more than 1,000 divides in 54 ms, and division
|
as the 8088 can perform more than 1,000 divides in 54 ms, and division
|
||||||
is the single instruction that the 8088 performs most slowly. If a
|
is the single instruction that the 8088 performs most slowly. If a
|
||||||
measured period turns out to be longer than 54 ms (that is, if timer 0
|
measured period turns out to be longer than 54 ms (that is, if timer 0
|
||||||
|
|
@ -730,11 +730,11 @@ restart until the timing interval ends, losing time all the while.
|
||||||
|
|
||||||
The effects on the system time of the Zen timer aren't a matter for
|
The effects on the system time of the Zen timer aren't a matter for
|
||||||
great concern, as they are temporary, lasting only until the next warm
|
great concern, as they are temporary, lasting only until the next warm
|
||||||
or cold boot. System that have battery-backed clocks, (AT-style machines; that
|
or cold boot. System that have batteryclocks, (AT-style machines; that
|
||||||
is, virtually all machines in common use) automatically reset the
|
is, virtually all machines in common use) automatically reset the
|
||||||
correct time whenever the computer is booted, and systems without
|
correct time whenever the computer is booted, and systems without
|
||||||
battery-backed clocks prompt for the correct date and time when booted.
|
battery-clocks prompt for the correct date and time when booted.
|
||||||
Also, repeated use of the Zen timer usually makes the system clock slow
|
Also,repeated use of the Zen timer usually makes the system clock slow
|
||||||
by at most a total of a few seconds, unless code that takes much longer
|
by at most a total of a few seconds, unless code that takes much longer
|
||||||
than 54 ms to run is timed (in which case the Zen timer will notify you
|
than 54 ms to run is timed (in which case the Zen timer will notify you
|
||||||
that the code is too long to time).
|
that the code is too long to time).
|
||||||
|
|
@ -789,8 +789,8 @@ from timer counts to microseconds, and prints the resulting time in
|
||||||
microseconds to the standard output.
|
microseconds to the standard output.
|
||||||
|
|
||||||
Note that `ZTimerReport` need not be called immediately after
|
Note that `ZTimerReport` need not be called immediately after
|
||||||
`ZTimerOff`. In fact, after a given call to `ZTimerOff`,
|
`ZTimerOff`. In fact, after a given call to `ZTimerOff,
|
||||||
`ZTimerReport` can be called at any time right up until the next call to
|
ZTimerReport` can be called at any time right up until the next call to
|
||||||
`ZTimerOn`.
|
`ZTimerOn`.
|
||||||
|
|
||||||
You may want to use the Zen timer to measure several portions of a
|
You may want to use the Zen timer to measure several portions of a
|
||||||
|
|
@ -880,7 +880,7 @@ performance will be similar even on different IBM models; in fact, quite
|
||||||
the opposite is true. For example, every PS/2 computer, even the
|
the opposite is true. For example, every PS/2 computer, even the
|
||||||
relatively slow Model 30, executes code much faster than does a PC or
|
relatively slow Model 30, executes code much faster than does a PC or
|
||||||
XT. As another example, I set out to do the timings for my earlier book
|
XT. As another example, I set out to do the timings for my earlier book
|
||||||
*Zen of Assembly Language* on an XT-compatible computer, only to find that the
|
*Zen of Assembly Language* on an XTcomputer, only to find that the
|
||||||
computer wasn't quite IBM-compatible regarding code performance. The
|
computer wasn't quite IBM-compatible regarding code performance. The
|
||||||
differences were minor, mind you, but my experience illustrates the risk
|
differences were minor, mind you, but my experience illustrates the risk
|
||||||
of assuming that a specific make of computer will perform in a certain
|
of assuming that a specific make of computer will perform in a certain
|
||||||
|
|
@ -913,13 +913,13 @@ and should contain calls to `ZTimerOn` and `ZTimerOff` .
|
||||||
;
|
;
|
||||||
; By Michael Abrash
|
; By Michael Abrash
|
||||||
;
|
;
|
||||||
mystack segment para stack 'STACK'
|
mystack segment para stack ‘STACK'
|
||||||
db 512 dup(?)
|
db 512 dup(?)
|
||||||
mystack ends
|
mystack ends
|
||||||
;
|
;
|
||||||
Code segment para public 'CODE'
|
Code segment para public ‘CODE'
|
||||||
assume cs:Code, ds:Code
|
assume cs:Code, ds:Code
|
||||||
extrn ZTimerOn:near, ZTimerOff:near, ZTimerReport:near
|
extrnZTimerOn:near, ZTimerOff:near, ZTimerReport:near
|
||||||
Start proc near
|
Start proc near
|
||||||
push cs
|
push cs
|
||||||
pop ds ; set DS to point to the code segment,
|
pop ds ; set DS to point to the code segment,
|
||||||
|
|
@ -996,7 +996,7 @@ timing interval.
|
||||||
|
|
||||||
Listing 3.3 is used by naming it TESTCODE, assembling both Listing 3.2
|
Listing 3.3 is used by naming it TESTCODE, assembling both Listing 3.2
|
||||||
(which includes TESTCODE) and Listing 3.1 with TASM or MASM, and linking
|
(which includes TESTCODE) and Listing 3.1 with TASM or MASM, and linking
|
||||||
the two resulting OBJ files together by way of the Borland or Microsoft
|
the two resulting OBJ files together by way of the Borland orMicrosoft
|
||||||
linker. Listing 3.4 shows a batch file, PZTIME.BAT, which does all that;
|
linker. Listing 3.4 shows a batch file, PZTIME.BAT, which does all that;
|
||||||
when run, this batch file generates and runs the executable file
|
when run, this batch file generates and runs the executable file
|
||||||
PZTEST.EXE. PZTIME.BAT (Listing 3.4) assumes that the file PZTIMER.ASM
|
PZTEST.EXE. PZTIME.BAT (Listing 3.4) assumes that the file PZTIMER.ASM
|
||||||
|
|
@ -1111,8 +1111,8 @@ pztime <filename>
|
||||||
In fact, that's exactly how I timed each of the listings in this book.
|
In fact, that's exactly how I timed each of the listings in this book.
|
||||||
Code fragments you write yourself can be timed in just the same way. If
|
Code fragments you write yourself can be timed in just the same way. If
|
||||||
you wish to time code directly in place in your programs, rather than in
|
you wish to time code directly in place in your programs, rather than in
|
||||||
the test-bed program of Listing 3.2, simply insert calls to `ZTimerOn`,
|
the test-bed program of Listing 3.2, simply insert calls to `ZTimerOn,
|
||||||
`ZTimerOff`, and `ZTimerReport` in the appropriate places and link
|
ZTimerOff`, and `ZTimerReport` in the appropriate places and link
|
||||||
PZTIMER to your program.
|
PZTIMER to your program.
|
||||||
|
|
||||||
### The Long-Period Zen Timer
|
### The Long-Period Zen Timer
|
||||||
|
|
@ -1303,8 +1303,8 @@ computers.
|
||||||
; All registers and all flags are preserved by all routines.
|
; All registers and all flags are preserved by all routines.
|
||||||
;
|
;
|
||||||
|
|
||||||
Code segment word public 'CODE'
|
Code segment word public ‘CODE'
|
||||||
assume cs:Code, ds:nothing
|
assume cs: Code, ds:nothing
|
||||||
public ZTimerOn, ZTimerOff, ZTimerReport
|
public ZTimerOn, ZTimerOff, ZTimerReport
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
@ -1326,24 +1326,24 @@ Code segment word public 'CODE'
|
||||||
; which support the undocumented timer-stopping feature of the
|
; which support the undocumented timer-stopping feature of the
|
||||||
; 8253. The choice is yours.
|
; 8253. The choice is yours.
|
||||||
;
|
;
|
||||||
PS2 equ 1
|
PS2 equ1
|
||||||
;
|
;
|
||||||
; Base address of the 8253 timer chip.
|
; Base address of the 8253 timer chip.
|
||||||
;
|
;
|
||||||
BASE_8253 equ 40h
|
BASE_8253 equ40h
|
||||||
;
|
;
|
||||||
; The address of the timer 0 count registers in the 8253.
|
; The address of the timer 0 count registers in the 8253.
|
||||||
;
|
;
|
||||||
TIMER_0_8253 equ BASE_8253 + 0
|
TIMER_0_8253 equBASE_8253 + 0
|
||||||
;
|
;
|
||||||
; The address of the mode register in the 8253.
|
; The address of the mode register in the 8253.
|
||||||
;
|
;
|
||||||
MODE_8253 equ BASE_8253 + 3
|
MODE_8253 equBASE_8253 + 3
|
||||||
;
|
;
|
||||||
; The address of the BIOS timer count variable in the BIOS
|
; The address of the BIOS timer count variable in the BIOS
|
||||||
; data segment.
|
; data segment.
|
||||||
;
|
;
|
||||||
TIMER_COUNT equ 46ch
|
TIMER_COUNT equ46ch
|
||||||
;
|
;
|
||||||
; Macro to emulate a POPF instruction in order to fix the bug in some
|
; Macro to emulate a POPF instruction in order to fix the bug in some
|
||||||
; 80286 chips which allows interrupts to occur during a POPF even when
|
; 80286 chips which allows interrupts to occur during a POPF even when
|
||||||
|
|
@ -1353,9 +1353,9 @@ MPOPF macro
|
||||||
local p1, p2
|
local p1, p2
|
||||||
jmp short p2
|
jmp short p2
|
||||||
p1: iret ;jump to pushed address & pop flags
|
p1: iret ;jump to pushed address & pop flags
|
||||||
p2: push cs ;construct far return address to
|
p2: pushcs ;construct far return address to
|
||||||
call p1 ; the next instruction
|
call p1 ; the next instruction
|
||||||
endm
|
endm
|
||||||
|
|
||||||
;
|
;
|
||||||
; Macro to delay briefly to ensure that enough time has elapsed
|
; Macro to delay briefly to ensure that enough time has elapsed
|
||||||
|
|
@ -1383,11 +1383,11 @@ ReferenceCount dw ? ;number of counts required to
|
||||||
;
|
;
|
||||||
; String printed to report results.
|
; String printed to report results.
|
||||||
;
|
;
|
||||||
OutputStr label byte
|
OutputStr labelbyte
|
||||||
db 0dh, 0ah, 'Timed count: '
|
db 0dh, 0ah, ‘Timed count: ‘
|
||||||
TimedCountStr db 10 dup (?)
|
TimedCountStr db10 dup (?)
|
||||||
db ' microseconds', 0dh, 0ah
|
db' microseconds', 0dh, 0ah
|
||||||
db '$'
|
db ‘$'
|
||||||
;
|
;
|
||||||
; Temporary storage for timed count as it's divided down by powers
|
; Temporary storage for timed count as it's divided down by powers
|
||||||
; of ten when converting from doubleword binary to ASCII.
|
; of ten when converting from doubleword binary to ASCII.
|
||||||
|
|
@ -1398,7 +1398,7 @@ CurrentCountHigh dw ?
|
||||||
; Powers of ten table used to perform division by 10 when doing
|
; Powers of ten table used to perform division by 10 when doing
|
||||||
; doubleword conversion from binary to ASCII.
|
; doubleword conversion from binary to ASCII.
|
||||||
;
|
;
|
||||||
PowersOfTen label word
|
PowersOfTenlabelword
|
||||||
dd 1
|
dd 1
|
||||||
dd 10
|
dd 10
|
||||||
dd 100
|
dd 100
|
||||||
|
|
@ -1409,33 +1409,33 @@ PowersOfTen label word
|
||||||
dd 10000000
|
dd 10000000
|
||||||
dd 100000000
|
dd 100000000
|
||||||
dd 1000000000
|
dd 1000000000
|
||||||
PowersOfTenEnd label word
|
PowersOfTenEnd labelword
|
||||||
;
|
;
|
||||||
; String printed to report that the high word of the BIOS count
|
; String printed to report that the high word of the BIOS count
|
||||||
; changed while timing (an hour elapsed or midnight was crossed),
|
; changed while timing (an hour elapsed or midnight was crossed),
|
||||||
; and so the count is invalid and the test needs to be rerun.
|
; and so the count is invalid and the test needs to be rerun.
|
||||||
;
|
;
|
||||||
TurnOverStr label byte
|
TurnOverStrlabelbyte
|
||||||
|
db 0dh, 0ah
|
||||||
|
db ‘****************************************************'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '****************************************************'
|
db'* Either midnight passed or an hour or more passed *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* Either midnight passed or an hour or more passed *'
|
db'* while timing was in progress. If the former was *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* while timing was in progress. If the former was *'
|
db'* the case, please rerun the test; if the latter *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* the case, please rerun the test; if the latter *'
|
db'* was the case, the test code takes too long to *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* was the case, the test code takes too long to *'
|
db'* run to be timed by the long-period Zen timer. *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* run to be timed by the long-period Zen timer. *'
|
db ‘* Suggestions: use the DOS TIME command, the DOS *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* Suggestions: use the DOS TIME command, the DOS *'
|
db ‘* time function, or a watch. *'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '* time function, or a watch. *'
|
db ‘****************************************************'
|
||||||
db 0dh, 0ah
|
db 0dh, 0ah
|
||||||
db '****************************************************'
|
db'$'
|
||||||
db 0dh, 0ah
|
|
||||||
db '$'
|
|
||||||
|
|
||||||
;********************************************************************
|
;********************************************************************
|
||||||
;* Routine called to start timing. *
|
;* Routine called to start timing. *
|
||||||
|
|
@ -1447,7 +1447,7 @@ ZTimerOn proc near
|
||||||
; Save the context of the program being timed.
|
; Save the context of the program being timed.
|
||||||
;
|
;
|
||||||
push ax
|
push ax
|
||||||
pushf
|
pus hf
|
||||||
;
|
;
|
||||||
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
|
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
|
||||||
; linear counting rather than count-by-two counting. Also stops
|
; linear counting rather than count-by-two counting. Also stops
|
||||||
|
|
@ -1463,10 +1463,10 @@ ZTimerOn proc near
|
||||||
; clock count each time it is executed.
|
; clock count each time it is executed.
|
||||||
;
|
;
|
||||||
DELAY
|
DELAY
|
||||||
sub al,al
|
subal,al
|
||||||
out TIMER_0_8253,al ;lsb
|
outTIMER_0_8253,al ;lsb
|
||||||
DELAY
|
DELAY
|
||||||
out TIMER_0_8253,al ;msb
|
outTIMER_0_8253,al ;msb
|
||||||
;
|
;
|
||||||
; In case interrupts are disabled, enable interrupts briefly to allow
|
; In case interrupts are disabled, enable interrupts briefly to allow
|
||||||
; the interrupt generated when switching from mode 3 to mode 2 to be
|
; the interrupt generated when switching from mode 3 to mode 2 to be
|
||||||
|
|
@ -1488,12 +1488,12 @@ ZTimerOn proc near
|
||||||
; interrupts in order to avoid getting a half-changed count.)
|
; interrupts in order to avoid getting a half-changed count.)
|
||||||
;
|
;
|
||||||
push ds
|
push ds
|
||||||
sub ax, ax
|
subax, ax
|
||||||
mov ds, ax
|
movds, ax
|
||||||
mov ax, ds:[TIMER_COUNT+2]
|
movax, ds:[TIMER_COUNT+2]
|
||||||
mov cs:[StartBIOSCountHigh],ax
|
movcs: [StartBIOSCountHigh],ax
|
||||||
mov ax, ds:[TIMER_COUNT]
|
movax, ds:[TIMER_COUNT]
|
||||||
mov cs:[StartBIOSCountLow],ax
|
movcs: [StartBIOSCountLow],ax
|
||||||
pop ds
|
pop ds
|
||||||
;
|
;
|
||||||
; Set the timer count to 0 again to start the timing interval.
|
; Set the timer count to 0 again to start the timing interval.
|
||||||
|
|
@ -1501,7 +1501,7 @@ ZTimerOn proc near
|
||||||
mov al,00110100b ;set up to load initial
|
mov al,00110100b ;set up to load initial
|
||||||
out MODE_8253,al ; timer count
|
out MODE_8253,al ; timer count
|
||||||
DELAY
|
DELAY
|
||||||
sub al, al
|
subal, al
|
||||||
out TIMER_0_8253,al; load count lsb
|
out TIMER_0_8253,al; load count lsb
|
||||||
DELAY
|
DELAY
|
||||||
out TIMER_0_8253,al; load count msb
|
out TIMER_0_8253,al; load count msb
|
||||||
|
|
@ -1509,23 +1509,23 @@ ZTimerOn proc near
|
||||||
; Restore the context of the program being timed and return to it.
|
; Restore the context of the program being timed and return to it.
|
||||||
;
|
;
|
||||||
MPOPF
|
MPOPF
|
||||||
pop ax
|
popax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
ZTimerOn endp
|
ZTimerOnendp
|
||||||
|
|
||||||
;********************************************************************
|
;********************************************************************
|
||||||
;* Routine called to stop timing and get count. *
|
;* Routine called to stop timing and get count. *
|
||||||
;********************************************************************
|
;********************************************************************
|
||||||
|
|
||||||
ZTimerOff proc near
|
ZTimerOff procnear
|
||||||
|
|
||||||
;
|
;
|
||||||
; Save the context of the program being timed.
|
; Save the context of the program being timed.
|
||||||
;
|
;
|
||||||
pushf
|
pushf
|
||||||
push ax
|
pushax
|
||||||
push cx
|
pushcx
|
||||||
;
|
;
|
||||||
; In case interrupts are disabled, enable interrupts briefly to allow
|
; In case interrupts are disabled, enable interrupts briefly to allow
|
||||||
; any pending timer interrupt to be handled. Interrupts must be
|
; any pending timer interrupt to be handled. Interrupts must be
|
||||||
|
|
@ -1618,7 +1618,7 @@ ife PS2
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
sti ;let the BIOS count continue
|
sti;let the BIOS count continue
|
||||||
;
|
;
|
||||||
; Time a zero-length code fragment, to get a reference for how
|
; Time a zero-length code fragment, to get a reference for how
|
||||||
; much overhead this routine has. Time it 16 times and average it,
|
; much overhead this routine has. Time it 16 times and average it,
|
||||||
|
|
@ -1633,14 +1633,14 @@ RefLoop:
|
||||||
call ReferenceZTimerOff
|
call ReferenceZTimerOff
|
||||||
loop RefLoop
|
loop RefLoop
|
||||||
sti
|
sti
|
||||||
add cs:[ReferenceCount],8 ;total + (0.5 * 16)
|
add cs:[ReferenceCount],8; total + (0.5 * 16)
|
||||||
mov cl,4
|
mov cl,4
|
||||||
shr cs:[ReferenceCount],cl ;(total) / 16 + 0.5
|
shr cs:[ReferenceCount],cl;(total) / 16 + 0.5
|
||||||
;
|
;
|
||||||
; Restore the context of the program being timed and return to it.
|
; Restore the context of the program being timed and return to it.
|
||||||
;
|
;
|
||||||
pop cx
|
popcx
|
||||||
pop ax
|
popax
|
||||||
MPOPF
|
MPOPF
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
@ -1650,11 +1650,11 @@ ZTimerOff endp
|
||||||
; Called by ZTimerOff to start the timer for overhead measurements.
|
; Called by ZTimerOff to start the timer for overhead measurements.
|
||||||
;
|
;
|
||||||
|
|
||||||
ReferenceZTimerOn proc near
|
ReferenceZTimerOnprocnear
|
||||||
;
|
;
|
||||||
; Save the context of the program being timed.
|
; Save the context of the program being timed.
|
||||||
;
|
;
|
||||||
push ax
|
pushax
|
||||||
pushf
|
pushf
|
||||||
;
|
;
|
||||||
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
|
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
|
||||||
|
|
@ -1674,10 +1674,10 @@ ReferenceZTimerOn proc near
|
||||||
; Restore the context of the program being timed and return to it.
|
; Restore the context of the program being timed and return to it.
|
||||||
;
|
;
|
||||||
MPOPF
|
MPOPF
|
||||||
pop ax
|
popax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
ReferenceZTimerOn endp
|
ReferenceZTimerOnendp
|
||||||
|
|
||||||
;
|
;
|
||||||
; Called by ZTimerOff to stop the timer and add the result to
|
; Called by ZTimerOff to stop the timer and add the result to
|
||||||
|
|
@ -1686,20 +1686,20 @@ ReferenceZTimerOn endp
|
||||||
; isn't going to take anywhere near 54 ms.
|
; isn't going to take anywhere near 54 ms.
|
||||||
;
|
;
|
||||||
|
|
||||||
ReferenceZTimerOff proc near
|
ReferenceZTimerOff procnear
|
||||||
;
|
;
|
||||||
; Save the context of the program being timed.
|
; Save the context of the program being timed.
|
||||||
;
|
;
|
||||||
pushf
|
pushf
|
||||||
push ax
|
pushax
|
||||||
push cx
|
pushcx
|
||||||
|
|
||||||
;
|
;
|
||||||
; Match the interrupt-window delay in ZTimerOff.
|
; Match the interrupt-window delay in ZTimerOff.
|
||||||
;
|
;
|
||||||
sti
|
sti
|
||||||
rept 10
|
rept10
|
||||||
jmp $+2
|
jmp$+2
|
||||||
endm
|
endm
|
||||||
|
|
||||||
mov al,00000000b
|
mov al,00000000b
|
||||||
|
|
@ -1720,8 +1720,8 @@ ReferenceZTimerOff proc near
|
||||||
;
|
;
|
||||||
; Restore the context and return.
|
; Restore the context and return.
|
||||||
;
|
;
|
||||||
pop cx
|
popcx
|
||||||
pop ax
|
popax
|
||||||
MPOPF
|
MPOPF
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
@ -1731,7 +1731,7 @@ ReferenceZTimerOff endp
|
||||||
;* Routine called to report timing results. *
|
;* Routine called to report timing results. *
|
||||||
;********************************************************************
|
;********************************************************************
|
||||||
|
|
||||||
ZTimerReport proc near
|
ZTimerReportprocnear
|
||||||
|
|
||||||
pushf
|
pushf
|
||||||
push ax
|
push ax
|
||||||
|
|
@ -1741,7 +1741,7 @@ ZTimerReport proc near
|
||||||
push si
|
push si
|
||||||
push di
|
push di
|
||||||
push ds
|
push ds
|
||||||
;
|
;
|
||||||
push cs ;DOS functions require that DS point
|
push cs ;DOS functions require that DS point
|
||||||
pop ds ; to text to be displayed on the screen
|
pop ds ; to text to be displayed on the screen
|
||||||
assume ds :Code
|
assume ds :Code
|
||||||
|
|
@ -1780,7 +1780,7 @@ TestTooLong:
|
||||||
; Convert the BIOS time to microseconds.
|
; Convert the BIOS time to microseconds.
|
||||||
;
|
;
|
||||||
CalcBIOSTime:
|
CalcBIOSTime:
|
||||||
mov ax,[EndBIOSCountLow]
|
mov ax,[EndBIOSCountLow]
|
||||||
sub ax,[StartBIOSCountLow]
|
sub ax,[StartBIOSCountLow]
|
||||||
mov dx,54925 ;number of microseconds each
|
mov dx,54925 ;number of microseconds each
|
||||||
; BIOS count represents
|
; BIOS count represents
|
||||||
|
|
@ -1808,7 +1808,7 @@ CalcBIOSTime:
|
||||||
mov si,8381 ;convert the reference count
|
mov si,8381 ;convert the reference count
|
||||||
mul si ; to microseconds
|
mul si ; to microseconds
|
||||||
mov si,10000
|
mov si,10000
|
||||||
div si ;* .8381 = * 8381 / 10000
|
div si;* .8381 = * 8381 / 10000
|
||||||
sub bx,ax
|
sub bx,ax
|
||||||
sbb cx,0
|
sbb cx,0
|
||||||
mov [CurrentCountLow],bx
|
mov [CurrentCountLow],bx
|
||||||
|
|
@ -1896,7 +1896,7 @@ substantially.
|
||||||
|
|
||||||
Finally, please note that the *precision* Zen timer works perfectly well
|
Finally, please note that the *precision* Zen timer works perfectly well
|
||||||
on both PS/2 and non-PS/2 computers. The PS/2 and 8253 considerations
|
on both PS/2 and non-PS/2 computers. The PS/2 and 8253 considerations
|
||||||
we've just discussed apply *only* to the long-period Zen timer.
|
we've just discussed apply *only* to the longZen timer.
|
||||||
|
|
||||||
### Example Use of the Long-Period Zen Timer
|
### Example Use of the Long-Period Zen Timer
|
||||||
|
|
||||||
|
|
@ -1932,25 +1932,25 @@ timing.
|
||||||
;
|
;
|
||||||
; By Michael Abrash
|
; By Michael Abrash
|
||||||
;
|
;
|
||||||
mystack segment para stack 'STACK'
|
mystack segment para stack ‘STACK'
|
||||||
db 512 dup(?)
|
db 512 dup(?)
|
||||||
mystack ends
|
mystack ends
|
||||||
;
|
;
|
||||||
Code segment para public 'CODE'
|
Code segment para public ‘CODE'
|
||||||
assume cs:Code, ds:Code
|
assume cs:Code, ds:Code
|
||||||
extrn ZTimerOn:near, ZTimerOff:near, ZTimerReport:near
|
extrn ZTimerOn:near, ZTimerOff:near, ZTimerReport:near
|
||||||
Start proc near
|
Startproc near
|
||||||
push cs
|
push cs
|
||||||
pop ds ;point DS to the code segment,
|
pop ds ;point DS to the code segment,
|
||||||
; so data as well as code can easily
|
; so data as well as code can easily
|
||||||
; be included in TESTCODE
|
; be included in TESTCODE
|
||||||
;
|
;
|
||||||
; Delay for 6-7 seconds, to let the Enter keystroke that started the
|
; Delay for 6-7 seconds, to let the Enter keystroke that started the
|
||||||
; program come back up.
|
; program come back up.
|
||||||
;
|
;
|
||||||
mov ah,2ch
|
mov ah,2ch
|
||||||
int 21h ;get the current time
|
int 21h ;get the current time
|
||||||
mov bh,dh ;set the current time aside
|
mov bh,dh ;set the current time aside
|
||||||
DelayLoop:
|
DelayLoop:
|
||||||
mov ah,2ch
|
mov ah,2ch
|
||||||
push bx ;preserve start time
|
push bx ;preserve start time
|
||||||
|
|
@ -1962,12 +1962,12 @@ DelayLoop:
|
||||||
add dh,60 ;yes, a minute must have turned over,
|
add dh,60 ;yes, a minute must have turned over,
|
||||||
; so add one minute
|
; so add one minute
|
||||||
CheckDelayTime:
|
CheckDelayTime:
|
||||||
sub dh,bh ;get time that's passed
|
sub dh,bh ;get time that's passed
|
||||||
cmp dh,7 ;has it been more than 6 seconds yet?
|
cmp dh,7 ;has it been more than 6 seconds yet?
|
||||||
jb DelayLoop ;not yet
|
jb DelayLoop ;not yet
|
||||||
;
|
;
|
||||||
include TESTCODE ;code to be measured, including calls
|
include TESTCODE ;code to be measured, including calls
|
||||||
; to ZTimerOn and ZTimerOff
|
; to ZTimerOn and ZTimerOff
|
||||||
;
|
;
|
||||||
; Display the results.
|
; Display the results.
|
||||||
;
|
;
|
||||||
|
|
@ -1975,8 +1975,8 @@ CheckDelayTime:
|
||||||
;
|
;
|
||||||
; Terminate the program.
|
; Terminate the program.
|
||||||
;
|
;
|
||||||
mov ah,4ch
|
mov ah,4ch
|
||||||
int 21h
|
int 21h
|
||||||
Start endp
|
Start endp
|
||||||
Code ends
|
Code ends
|
||||||
end Start
|
end Start
|
||||||
|
|
@ -2075,23 +2075,23 @@ the precision Zen timer to handle on the 8088.
|
||||||
; Note: takes about ten minutes to assemble on a slow PC if
|
; Note: takes about ten minutes to assemble on a slow PC if
|
||||||
;you are using MASM
|
;you are using MASM
|
||||||
;
|
;
|
||||||
jmp Skip ;jump around defined data
|
jmpSkip;jump around defined data
|
||||||
;
|
;
|
||||||
MemVar db ?
|
MemVardb?
|
||||||
;
|
;
|
||||||
Skip:
|
Skip:
|
||||||
;
|
;
|
||||||
; Start timing.
|
; Start timing.
|
||||||
;
|
;
|
||||||
call ZTimerOn
|
callZTimerOn
|
||||||
;
|
;
|
||||||
rept 20000
|
rept20000
|
||||||
mov al,[MemVar]
|
moval,[MemVar]
|
||||||
endm
|
endm
|
||||||
;
|
;
|
||||||
; Stop timing.
|
; Stop timing.
|
||||||
;
|
;
|
||||||
call ZTimerOff
|
callZTimerOff
|
||||||
```
|
```
|
||||||
|
|
||||||
When LZTIME.BAT is run on a PC with the following command line (assuming
|
When LZTIME.BAT is run on a PC with the following command line (assuming
|
||||||
|
|
@ -2126,7 +2126,7 @@ be dealt with here: small code model and large; I'll tackle the simpler
|
||||||
one, the small code model, first.
|
one, the small code model, first.
|
||||||
|
|
||||||
Altering the Zen timer for linking to a small code model C program
|
Altering the Zen timer for linking to a small code model C program
|
||||||
involves the following steps: Change `ZTimerOn` to
|
involves the following steps: `C` hange `ZTimerOn` to
|
||||||
`_ZTimerOn`, change `ZTimerOff` to `_ZTimerOff`, change
|
`_ZTimerOn`, change `ZTimerOff` to `_ZTimerOff`, change
|
||||||
`ZTimerReport` to `_ZTimerReport`, and change `Code` to
|
`ZTimerReport` to `_ZTimerReport`, and change `Code` to
|
||||||
`_TEXT` . Figure 3.2 shows the line numbers and new states of all
|
`_TEXT` . Figure 3.2 shows the line numbers and new states of all
|
||||||
|
|
@ -2187,16 +2187,16 @@ push cs
|
||||||
call near ptr ReferenceZTimerOn
|
call near ptr ReferenceZTimerOn
|
||||||
```
|
```
|
||||||
|
|
||||||
(and likewise for `ReferenceZTimerOff`), which works because
|
(and likewise for `ReferenceZTimerOff` ), which works because
|
||||||
`ReferenceZTimerOn` is in the same segment as the calling code. This
|
`ReferenceZTimerOn` is in the same segment as the calling code. This
|
||||||
is normally a great optimization, being both smaller and faster than a
|
is normally a great optimization, being both smaller and faster than a
|
||||||
far call.
|
far call. However, it's not so great for the Zen
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
However, it's not so great for the Zen timer, because our purpose in calling the reference timing code is to
|
timer, because our purpose in calling the reference timing code is to
|
||||||
determine exactly how much time is taken by overhead code—including the
|
determine exactly how much time is taken by overhead code—including the
|
||||||
far calls to `ZTimerOn` and `ZTimerOf`! By converting the far calls
|
far calls to `ZTimerOn` and `ZTimerOf`f! By converting the far calls
|
||||||
to push/near call pairs within the Zen timer module, TASM makes it
|
to push/near call pairs within the Zen timer module, TASM makes it
|
||||||
impossible to emulate exactly the overhead of the Zen timer, and makes
|
impossible to emulate exactly the overhead of the Zen timer, and makes
|
||||||
timings slightly (about 16 cycles on a 386) less accurate.
|
timings slightly (about 16 cycles on a 386) less accurate.
|
||||||
|
|
@ -2255,7 +2255,7 @@ processor cache at the start of the code being timed, because the timing
|
||||||
code is not necessarily fetched and does not necessarily access memory
|
code is not necessarily fetched and does not necessarily access memory
|
||||||
in exactly the same time sequence as the code immediately preceding the
|
in exactly the same time sequence as the code immediately preceding the
|
||||||
code under measurement normally does. This prefetch effect can introduce
|
code under measurement normally does. This prefetch effect can introduce
|
||||||
as much as 3 to 4 µs of inaccuracy. Similarly, the state of the prefetch
|
as much as 3 to 4 µ of inaccuracy. Similarly, the state of the prefetch
|
||||||
queue at the end of the code being timed affects how long the code that
|
queue at the end of the code being timed affects how long the code that
|
||||||
stops the timer takes to execute. Consequently, the Zen timer tends to
|
stops the timer takes to execute. Consequently, the Zen timer tends to
|
||||||
be more accurate for longer code sequences, since the relative magnitude
|
be more accurate for longer code sequences, since the relative magnitude
|
||||||
|
|
|
||||||
|
|
@ -878,8 +878,8 @@ the PC must be completely refreshed about once every four milliseconds
|
||||||
in order to ensure the integrity of the data it stores. Obviously, it's
|
in order to ensure the integrity of the data it stores. Obviously, it's
|
||||||
highly desirable that the memory in the PC retain the correct data
|
highly desirable that the memory in the PC retain the correct data
|
||||||
indefinitely, so each DRAM chip in the PC *must* always be refreshed
|
indefinitely, so each DRAM chip in the PC *must* always be refreshed
|
||||||
within 4 ms of the last refresh. Since there's no guarantee that a given
|
within 4 µs of the last refresh. Since there's no guarantee that a given
|
||||||
program will access each and every DRAM block once every 4 ms, the PC
|
program will access each and every DRAM block once every 4 µs, the PC
|
||||||
contains special circuitry and programming for providing DRAM refresh.
|
contains special circuitry and programming for providing DRAM refresh.
|
||||||
|
|
||||||
#### How DRAM Refresh Works in the PC
|
#### How DRAM Refresh Works in the PC
|
||||||
|
|
@ -900,8 +900,8 @@ purpose of refreshing the DRAM; the data that is read isn't used.)
|
||||||
The 256 addresses accessed by the refresh DMA accesses are arranged so
|
The 256 addresses accessed by the refresh DMA accesses are arranged so
|
||||||
that taken together they properly refresh all the memory in the PC. By
|
that taken together they properly refresh all the memory in the PC. By
|
||||||
accessing one of the 256 addresses every 15.08 µs, all of the PC's DRAM
|
accessing one of the 256 addresses every 15.08 µs, all of the PC's DRAM
|
||||||
is refreshed in 256 x 15.08 µs, or 3.86 ms, which is just about the
|
is refreshed in 256 x 15.08 µs, or 3.86 µs, which is just about the
|
||||||
desired 4 ms time I mentioned earlier. (Only the first 640K of memory is
|
desired 4 µs time I mentioned earlier. (Only the first 640K of memory is
|
||||||
refreshed in the PC; video adapters and other adapters above 640K
|
refreshed in the PC; video adapters and other adapters above 640K
|
||||||
containing memory that requires refreshing must provide their own DRAM
|
containing memory that requires refreshing must provide their own DRAM
|
||||||
refresh in pre-AT systems.)
|
refresh in pre-AT systems.)
|
||||||
|
|
@ -1053,7 +1053,7 @@ reduction can vary considerably and unpredictably, depending on how the
|
||||||
DRAM refreshes interact with your code's pattern of memory accesses.
|
DRAM refreshes interact with your code's pattern of memory accesses.
|
||||||
When you use the Zen timer and get a fractional cycle count for the
|
When you use the Zen timer and get a fractional cycle count for the
|
||||||
execution time of an instruction, that's often the DRAM refresh
|
execution time of an instruction, that's often the DRAM refresh
|
||||||
cycle-eater at work. (The display adapter cycle is another possible
|
cycle-eater at work. (The display adapter cycleis another possible
|
||||||
culprit, and, on 386s and later processors, cache misses and pipeline
|
culprit, and, on 386s and later processors, cache misses and pipeline
|
||||||
execution hazards produce this sort of effect as well.) Whenever you get
|
execution hazards produce this sort of effect as well.) Whenever you get
|
||||||
two timing results that differ less or more than they seemingly should,
|
two timing results that differ less or more than they seemingly should,
|
||||||
|
|
@ -1223,7 +1223,7 @@ display, and even with the display adapter cycle-eater it just doesn't
|
||||||
take that long to manipulate 4,000 bytes. Even if the display adapter
|
take that long to manipulate 4,000 bytes. Even if the display adapter
|
||||||
cycle-eater were to cause the 8088 to take as much as 5µs per display
|
cycle-eater were to cause the 8088 to take as much as 5µs per display
|
||||||
memory access—more than five times normal—it would still take only
|
memory access—more than five times normal—it would still take only
|
||||||
4,000x 2x 5µs, or 40 ms, to read and write every byte of display memory.
|
4,000x 2x 5µs, or 40 µs, to read and write every byte of display memory.
|
||||||
That's a lot of time as measured in 8088 cycles, but it's less than the
|
That's a lot of time as measured in 8088 cycles, but it's less than the
|
||||||
blink of an eye in human time, and video performance only matters in
|
blink of an eye in human time, and video performance only matters in
|
||||||
human time. After all, the whole point of drawing graphics is to convey
|
human time. After all, the whole point of drawing graphics is to convey
|
||||||
|
|
@ -1261,7 +1261,7 @@ seriously impact code performance, even as measured in human time.
|
||||||
|
|
||||||
For example, if we assume the same 5 µs per display memory access for
|
For example, if we assume the same 5 µs per display memory access for
|
||||||
the EGA's high-resolution graphics mode that we assumed for text mode,
|
the EGA's high-resolution graphics mode that we assumed for text mode,
|
||||||
it would take 26,000 x 2 x 5 µs, or 260 ms, to scroll the screen once in
|
it would take 26,000 x 2 x 5 µs, or 260 µs, to scroll the screen once in
|
||||||
the EGA's high-resolution graphics mode, mode 10H. That's more than
|
the EGA's high-resolution graphics mode, mode 10H. That's more than
|
||||||
one-quarter of a second—noticeable by human standards, an eternity by
|
one-quarter of a second—noticeable by human standards, an eternity by
|
||||||
computer standards.
|
computer standards.
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ standard memory addressing operand, but does nothing more than store the
|
||||||
calculated memory offset in the specified register, which may be any
|
calculated memory offset in the specified register, which may be any
|
||||||
general-purpose register. The operation of `LEA` is illustrated in
|
general-purpose register. The operation of `LEA` is illustrated in
|
||||||
Figure 6.1, which also shows the operation of register-to-register
|
Figure 6.1, which also shows the operation of register-to-register
|
||||||
`ADD`, for comparison.
|
`ADD`, for comparis on.
|
||||||
|
|
||||||
What does that give us? Two things that `ADD` doesn't provide: the
|
What does that give us? Two things that `ADD` doesn't provide: the
|
||||||
ability to perform addition with either two or three operands, and the
|
ability to perform addition with either two or three operands, and the
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ the whole point.)
|
||||||
.stack 100h
|
.stack 100h
|
||||||
.data
|
.data
|
||||||
; Sample string to search through.
|
; Sample string to search through.
|
||||||
SampleString label byte
|
SampleString labelbyte
|
||||||
db ‘This is a sample string of a long enough length '
|
db ‘This is a sample string of a long enough length '
|
||||||
db ‘so that raw searching speed can outweigh any '
|
db ‘so that raw searching speed can outweigh any '
|
||||||
db ‘extra set-up time that may be required.',0
|
db ‘extra set-up time that may be required.',0
|
||||||
|
|
@ -263,7 +263,7 @@ NoByteFoundMsg db 0dh,0ah
|
||||||
db ‘Buffer exhausted with no match.', 0dh, 0ah, ‘$'
|
db ‘Buffer exhausted with no match.', 0dh, 0ah, ‘$'
|
||||||
|
|
||||||
.code
|
.code
|
||||||
Start proc near
|
Startprocnear
|
||||||
mov ax,@data ;point to standard data segment
|
mov ax,@data ;point to standard data segment
|
||||||
mov ds,ax
|
mov ds,ax
|
||||||
mov dx,offset Prompt
|
mov dx,offset Prompt
|
||||||
|
|
@ -289,7 +289,7 @@ PrintStatus:
|
||||||
int 21h ;report status
|
int 21h ;report status
|
||||||
mov ah,4ch ;return to DOS
|
mov ah,4ch ;return to DOS
|
||||||
int 21h
|
int 21h
|
||||||
Start endp
|
Startendp
|
||||||
|
|
||||||
; Function to search a buffer of a specified length until either a
|
; Function to search a buffer of a specified length until either a
|
||||||
; specified byte or a zero byte is encountered.
|
; specified byte or a zero byte is encountered.
|
||||||
|
|
@ -306,7 +306,7 @@ Start endp
|
||||||
; byte is found
|
; byte is found
|
||||||
; Carry Flag = set if searched-for byte found, reset otherwise
|
; Carry Flag = set if searched-for byte found, reset otherwise
|
||||||
|
|
||||||
SearchMaxLength proc near
|
SearchMaxLengthprocnear
|
||||||
cld
|
cld
|
||||||
SearchMaxLengthLoop:
|
SearchMaxLengthLoop:
|
||||||
lodsb ;get the next byte
|
lodsb ;get the next byte
|
||||||
|
|
@ -324,7 +324,7 @@ ByteFound:
|
||||||
;we found the searched-for byte
|
;we found the searched-for byte
|
||||||
stc ;return "found" status
|
stc ;return "found" status
|
||||||
ret
|
ret
|
||||||
SearchMaxLength endp
|
SearchMaxLengthendp
|
||||||
end Start
|
end Start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -350,7 +350,7 @@ all the difference.
|
||||||
.stack 100h
|
.stack 100h
|
||||||
.data
|
.data
|
||||||
; Sample string to search through.
|
; Sample string to search through.
|
||||||
SampleString label byte
|
SampleStringlabelbyte
|
||||||
db ‘This is a sample string of a long enough length '
|
db ‘This is a sample string of a long enough length '
|
||||||
db ‘so that raw searching speed can outweigh any '
|
db ‘so that raw searching speed can outweigh any '
|
||||||
db ‘extra set-up time that may be required.',0
|
db ‘extra set-up time that may be required.',0
|
||||||
|
|
@ -403,7 +403,7 @@ PrintStatus:
|
||||||
|
|
||||||
mov ah,4ch ;return to DOS
|
mov ah,4ch ;return to DOS
|
||||||
int 21h
|
int 21h
|
||||||
Start endp
|
Startendp
|
||||||
|
|
||||||
; Function to search a buffer of a specified length until either a
|
; Function to search a buffer of a specified length until either a
|
||||||
; specified byte or a zero byte is encountered.
|
; specified byte or a zero byte is encountered.
|
||||||
|
|
@ -468,7 +468,7 @@ ByteFound:
|
||||||
; we found the searched-for byte
|
; we found the searched-for byte
|
||||||
stc ;return "found" status
|
stc ;return "found" status
|
||||||
ret
|
ret
|
||||||
SearchMaxLength endp
|
SearchMaxLengthendp
|
||||||
end Start
|
end Start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -213,13 +213,13 @@ display modes):
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
SHL AX,1 ;*2
|
SHL AX,1 ;*2
|
||||||
SHL AX,1 ;*4
|
SH LAX,1 ;*4
|
||||||
SHL AX,1 ;*8
|
SH LAX,1 ;*8
|
||||||
SHL AX,1 ;*16
|
SH LAX,1 ;*16
|
||||||
MOV BX,AX
|
MO VBX,AX
|
||||||
SHL AX,1 ;*32
|
SH LAX,1 ;*32
|
||||||
SHL AX,1 ;*64
|
SH LAX,1 ;*64
|
||||||
ADD AX,BX ;*80
|
ADD AX,BX ;*80
|
||||||
```
|
```
|
||||||
|
|
||||||
Using `LEA` on the 386, the above could be reduced to
|
Using `LEA` on the 386, the above could be reduced to
|
||||||
|
|
@ -242,7 +242,7 @@ Of course, on the 386, the shift and add version could also be reduced
|
||||||
to this considerably more efficient code:
|
to this considerably more efficient code:
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
SHL AX,4 ;*16
|
SH LAX,4 ;*16
|
||||||
MOV BX,AX
|
MOV BX,AX
|
||||||
SHL AX,2 ;*64
|
SHL AX,2 ;*64
|
||||||
ADD AX,BX ;*80
|
ADD AX,BX ;*80
|
||||||
|
|
@ -395,7 +395,7 @@ Parmsends
|
||||||
.model small
|
.model small
|
||||||
.code
|
.code
|
||||||
public _FindString
|
public _FindString
|
||||||
_FindString proc near
|
_FindStringprocnear
|
||||||
push bp ;preserve caller's stack frame
|
push bp ;preserve caller's stack frame
|
||||||
mov bp,sp ;point to our stack frame
|
mov bp,sp ;point to our stack frame
|
||||||
push si ;preserve caller's register variables
|
push si ;preserve caller's register variables
|
||||||
|
|
@ -458,7 +458,7 @@ FindStringDone:
|
||||||
pop si
|
pop si
|
||||||
pop bp ;restore caller's stack frame
|
pop bp ;restore caller's stack frame
|
||||||
ret
|
ret
|
||||||
_FindString endp
|
_FindStringendp
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -492,7 +492,7 @@ Parmsends
|
||||||
.model small
|
.model small
|
||||||
.code
|
.code
|
||||||
public _FindString
|
public _FindString
|
||||||
_FindString proc near
|
_FindStringprocnear
|
||||||
push bp ;preserve caller's stack frame
|
push bp ;preserve caller's stack frame
|
||||||
mov bp,sp ;point to our stack frame
|
mov bp,sp ;point to our stack frame
|
||||||
push si ;preserve caller's register variables
|
push si ;preserve caller's register variables
|
||||||
|
|
@ -559,7 +559,7 @@ FindStringDone:
|
||||||
pop si
|
pop si
|
||||||
pop bp ;restore caller's stack frame
|
pop bp ;restore caller's stack frame
|
||||||
ret
|
ret
|
||||||
_FindString endp
|
_FindStringendp
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -743,7 +743,7 @@ parmsends
|
||||||
.model small
|
.model small
|
||||||
.code
|
.code
|
||||||
public _Div
|
public _Div
|
||||||
_Div proc near
|
_Divprocnear
|
||||||
push bp ;preserve caller's stack frame
|
push bp ;preserve caller's stack frame
|
||||||
mov bp,sp ;point to our stack frame
|
mov bp,sp ;point to our stack frame
|
||||||
push si ;preserve caller's register variables
|
push si ;preserve caller's register variables
|
||||||
|
|
@ -766,9 +766,9 @@ _Div proc near
|
||||||
sub dx,dx ;convert initial divisor word to a 32-bit
|
sub dx,dx ;convert initial divisor word to a 32-bit
|
||||||
;value for DIV
|
;value for DIV
|
||||||
DivLoop:
|
DivLoop:
|
||||||
lodsw ;get next most significant word of divisor
|
lod sw ;get next most significant word of divisor
|
||||||
div bx
|
div bx
|
||||||
stosw ;save this word of the quotient
|
sto sw ;save this word of the quotient
|
||||||
;DX contains the remainder at this point,
|
;DX contains the remainder at this point,
|
||||||
; ready to prepend to the next divisor word
|
; ready to prepend to the next divisor word
|
||||||
loop DivLoop
|
loop DivLoop
|
||||||
|
|
@ -778,7 +778,7 @@ DivLoop:
|
||||||
pop si
|
pop si
|
||||||
pop bp ;restore caller's stack frame
|
pop bp ;restore caller's stack frame
|
||||||
ret
|
ret
|
||||||
_Div endp
|
_Divendp
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1020,7 +1020,7 @@ pushed on the stack will point to the instruction we want to continue
|
||||||
with. The code works out like this:
|
with. The code works out like this:
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
jmp short popfskip
|
jmpshort popfskip
|
||||||
popfiret:
|
popfiret:
|
||||||
iret; branches to the instruction after the
|
iret; branches to the instruction after the
|
||||||
; call, popping the word below the address
|
; call, popping the word below the address
|
||||||
|
|
@ -1082,8 +1082,8 @@ an 8088.)
|
||||||
.286
|
.286
|
||||||
:
|
:
|
||||||
EMULATE_POPFmacro
|
EMULATE_POPFmacro
|
||||||
push cs
|
pushcs
|
||||||
push offset $+4
|
pushoffset $+4
|
||||||
iret
|
iret
|
||||||
endm
|
endm
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -346,7 +346,7 @@ For example, you'd certainly expect a sequence such as
|
||||||
pop ax
|
pop ax
|
||||||
ret
|
ret
|
||||||
pop ax
|
pop ax
|
||||||
ret
|
et
|
||||||
:
|
:
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ from the use of DI to address memory (remember, the loop is unrolled, so
|
||||||
the last instruction is followed by the first instruction), but because
|
the last instruction is followed by the first instruction), but because
|
||||||
the intervening instruction takes two cycles, there's no penalty at all.
|
the intervening instruction takes two cycles, there's no penalty at all.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
> 
|
> 
|
||||||
> Remember, pipeline penalties diminish with increasing number of cycles,
|
> Remember, pipeline penalties diminish with increasing number of cycles,
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,8 @@ the pike. The success or failure of the search can then be determined
|
||||||
outside the loop, if necessary, by checking for the tail node's special
|
outside the loop, if necessary, by checking for the tail node's special
|
||||||
pointer—but the inside of the loop is streamlined to just one test, as
|
pointer—but the inside of the loop is streamlined to just one test, as
|
||||||
shown in Listing 15.5. Not all linked lists lend themselves to
|
shown in Listing 15.5. Not all linked lists lend themselves to
|
||||||
sentinels, but the performance benefits are considerable
|
sentinels, but the performance benefits are considerable for those lend
|
||||||
|
themselves to sentinels, but the performance benefits are considerable
|
||||||
for those that do.
|
for those that do.
|
||||||
|
|
||||||

|

|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ contention. Such operations, as in
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
mov eax,edx ;U-pipe cycle 1
|
mov eax,edx ;U-pipe cycle 1
|
||||||
sub edx,edx ;V-pipe cycle 1
|
sub edx,edxX ;V-pipe cycle 1
|
||||||
```
|
```
|
||||||
|
|
||||||
are free of charge.
|
are free of charge.
|
||||||
|
|
@ -475,33 +475,33 @@ ckloopsetup:
|
||||||
mov dx,[esi] ;load most of 1st word to
|
mov dx,[esi] ;load most of 1st word to
|
||||||
mov bl,[esi+2] ; checksum (last byte loaded in loop)
|
mov bl,[esi+2] ; checksum (last byte loaded in loop)
|
||||||
dec ecx ;any more dwords to checksum?
|
dec ecx ;any more dwords to checksum?
|
||||||
jz short ckloopend ;no
|
jz short ckloopend ;no
|
||||||
|
|
||||||
ckloop:
|
ckloop:
|
||||||
mov bh,[esi+3] ;cycle 1 U-pipe
|
mov bh,[esi+3] ;cycle 1 U-pipe
|
||||||
add esi,4 ;cycle 1 V-pipe
|
add esi,4 ;cycle 1 V-pipe
|
||||||
shl ebx,16 ;cycle 2 U-pipe
|
shl ebx,16 ;cycle 2 U-pipe
|
||||||
;cycle 2 V-pipe idle
|
;cycle 2 V-pipe idle
|
||||||
; (register contention)
|
; (register contention)
|
||||||
or ebx,edx ;cycle 3 U-pipe
|
or ebx,edx ;cycle 3 U-pipe
|
||||||
mov dl,[esi] ;cycle 3 V-pipe
|
mov dl,[esi] ;cycle 3 V-pipe
|
||||||
add eax,ebx ;cycle 4 U-pipe
|
add eax,ebx ;cycle 4 U-pipe
|
||||||
mov bl,[esi+2] ;cycle 4 V-pipe
|
mov bl,[esi+2] ;cycle 4 V-pipe
|
||||||
adc eax,0 ;cycle 5 U-pipe
|
adc eax,0 ;cycle 5 U-pipe
|
||||||
mov dh,[esi+1] ;cycle 5 V-pipe
|
mov dh,[esi+1] ;cycle 5 V-pipe
|
||||||
dec ecx ;cycle 6 U-pipe
|
dec ecx ;cycle 6 U-pipe
|
||||||
jnz ckloop ;cycle 6 V-pipe
|
jnz ckloop ;cycle 6 V-pipe
|
||||||
|
|
||||||
ckloopend:
|
ckloopend:
|
||||||
mov bh,[esi+3] ;checksum the last dword
|
mov bh,[esi+3] ;checksum the last dword
|
||||||
add ax,dx
|
add ax,dx
|
||||||
adc ax,bx
|
adc ax,bx
|
||||||
adc ax,0
|
adc ax,0
|
||||||
|
|
||||||
mov edx,eax ;compress the 32-bit checksum
|
mov edx,eax ;compress the 32-bit checksum
|
||||||
shr edx,16 ; into a 16-bit checksum
|
shr edx,16 ; into a 16-bit checksum
|
||||||
add ax,dx
|
add ax,dx
|
||||||
adc eax,0
|
adc eax,0
|
||||||
ckloopdone:
|
ckloopdone:
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -598,29 +598,29 @@ more registers.
|
||||||
jz short ckloopdone ;no, done
|
jz short ckloopdone ;no, done
|
||||||
add esi,4 ;point to the next dword
|
add esi,4 ;point to the next dword
|
||||||
noodddword:
|
noodddword:
|
||||||
mov edx,[esi] ;preload the first dword
|
mov edx,[esi] ;preload the first dword
|
||||||
mov ebx,[esi+4] ;preload the second dword
|
mov ebx,[esi+4] ;preload the second dword
|
||||||
dec ecx ;we'll do 1 checksum outside the loop
|
dec ecx ;we'll do 1 checksum outside the loop
|
||||||
jz short ckloopend ;only 1 checksum to do
|
jz short ckloopend ;only 1 checksum to do
|
||||||
add esi,8 ;point to the next dword
|
add esi,8 ;point to the next dword
|
||||||
|
|
||||||
ckloop:
|
ckloop:
|
||||||
add eax,edx ;cycle 1 U-pipe
|
add eax,edx ;cycle 1 U-pipe
|
||||||
mov edx,[esi] ;cycle 1 V-pipe
|
mov edx,[esi] ;cycle 1 V-pipe
|
||||||
adc eax,ebx ;cycle 2 U-pipe
|
adc eax,ebx ;cycle 2 U-pipe
|
||||||
mov ebx,[esi+4] ;cycle 2 V-pipe
|
mov ebx,[esi+4] ;cycle 2 V-pipe
|
||||||
adc eax,0 ;cycle 3 U-pipe
|
adc eax,0 ;cycle 3 U-pipe
|
||||||
add esi,8 ;cycle 3 V-pipe
|
add esi,8 ;cycle 3 V-pipe
|
||||||
dec ecx ;cycle 4 U-pipe
|
dec ecx ;cycle 4 U-pipe
|
||||||
jnz ckloop ;cycle 4 V-pipe
|
jnz ckloop ;cycle 4 V-pipe
|
||||||
|
|
||||||
ckloopend:
|
ckloopend:
|
||||||
add eax,edx ;checksum the last two dwords
|
add eax,edx ;checksum the last two dwords
|
||||||
adc eax,ebx
|
adc eax,ebx
|
||||||
adc eax,0
|
adc eax,0
|
||||||
ckloopdone:
|
ckloopdone:
|
||||||
mov edx,eax ;compress the 32-bit checksum
|
mov edx,eax ;compress the 32-bit checksum
|
||||||
shr edx,16 ; into a 16-bit checksum
|
shr edx,16 ; into a 16-bit checksum
|
||||||
add ax,dx
|
add ax,dx
|
||||||
adc eax,0
|
adc eax,0
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -68,29 +68,29 @@ BufSeg dw ? ;buffer segment
|
||||||
EndMrk db ? ;marker for the end of the stack frame
|
EndMrk db ? ;marker for the end of the stack frame
|
||||||
OnStack ends
|
OnStack ends
|
||||||
;
|
;
|
||||||
ClearS proc near
|
ClearS proc near
|
||||||
push bp ;save caller's BP
|
push bp ;save caller's BP
|
||||||
mov bp,sp ;point to stack frame
|
mov bp,sp ;point to stack frame
|
||||||
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
||||||
jne Start ; pointer is passed
|
jne Start ; pointer is passed
|
||||||
cmp word ptr [bp].BufOfs,0
|
cmp word ptr [bp].BufOfs,0
|
||||||
je Bye
|
je Bye
|
||||||
Start: cld ;make STOSW count up
|
Start: cld ;make STOSW count up
|
||||||
mov ax,[bp].Attrib ;load AX with attribute parameter
|
mov ax,[bp].Attrib ;load AX with attribute parameter
|
||||||
and ax,0ff00h ;prepare for merging with fill char
|
and ax,0ff00h ;prepare for merging with fill char
|
||||||
mov bx,[bp].Filler ;load BX with fill char
|
mov bx,[bp].Filler ;load BX with fill char
|
||||||
and bx,0ffh ;prepare for merging with attribute
|
and bx,0ffh ;prepare for merging with attribute
|
||||||
or ax,bx ;combine attribute and fill char
|
or ax,bx ;combine attribute and fill char
|
||||||
mov bx,[bp].BufOfs ;load DI with target buffer offset
|
mov bx,[bp].BufOfs ;load DI with target buffer offset
|
||||||
mov di,bx
|
mov di,bx
|
||||||
mov bx,[bp].BufSeg ;load ES with target buffer segment
|
mov bx,[bp].BufSeg ;load ES with target buffer segment
|
||||||
mov es,bx
|
mov es,bx
|
||||||
mov cx,[bp].BufSize ;load CX with buffer size
|
mov cx,[bp].BufSize ;load CX with buffer size
|
||||||
rep stosw ;fill the buffer
|
rep stosw ;fill the buffer
|
||||||
Bye: mov sp,bp ;restore original stack pointer
|
Bye:mov sp,bp ;restore original stack pointer
|
||||||
pop bp ; and caller's BP
|
pop bp ; and caller's BP
|
||||||
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
||||||
ClearS endp
|
ClearS endp
|
||||||
```
|
```
|
||||||
|
|
||||||
The first thing you'll notice about Listing 22.1 is that `ClearS` uses
|
The first thing you'll notice about Listing 22.1 is that `ClearS` uses
|
||||||
|
|
@ -121,27 +121,27 @@ DI directly as shown in Listing 22.2.
|
||||||
**LISTING 22.2 L22-2.ASM**
|
**LISTING 22.2 L22-2.ASM**
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
ClearS proc near
|
ClearS proc near
|
||||||
push bp ;save caller's BP
|
push bp ;save caller's BP
|
||||||
mov bp,sp ;point to stack frame
|
mov bp,sp ;point to stack frame
|
||||||
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
||||||
jne Start ; pointer is passed
|
jne Start ; pointer is passed
|
||||||
cmp word ptr [bp].BufOfs,0
|
cmp word ptr [bp].BufOfs,0
|
||||||
je Bye
|
je Bye
|
||||||
Start: cld ;make STOSW count up
|
Start: cld ;make STOSW count up
|
||||||
mov ax,[bp].Attrib ;load AX with attribute parameter
|
mov ax,[bp].Attrib ;load AX with attribute parameter
|
||||||
and ax,0ff00h ;prepare for merging with fill char
|
and ax,0ff00h ;prepare for merging with fill char
|
||||||
mov bx,[bp].Filler ;load BX with fill char
|
mov bx,[bp].Filler ;load BX with fill char
|
||||||
and bx,0ffh ;prepare for merging with attribute
|
and bx,0ffh ;prepare for merging with attribute
|
||||||
or ax,bx ;combine attribute and fill char
|
or ax,bx ;combine attribute and fill char
|
||||||
mov di,[bp].BufOfs ;load DI with target buffer offset
|
mov di,[bp].BufOfs ;load DI with target buffer offset
|
||||||
mov es,[bp].BufSeg ;load ES with target buffer segment
|
mov es,[bp].BufSeg ;load ES with target buffer segment
|
||||||
mov cx,[bp].BufSize ;load CX with buffer size
|
mov cx,[bp].BufSize ;load CX with buffer size
|
||||||
rep stosw ;fill the buffer
|
rep stosw ;fill the buffer
|
||||||
Bye:
|
Bye:
|
||||||
pop bp ;restore caller's BP
|
pop bp ;restore caller's BP
|
||||||
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
||||||
ClearS endp
|
ClearS endp
|
||||||
```
|
```
|
||||||
|
|
||||||
(The `OnStack` structure definition doesn't change in any of our
|
(The `OnStack` structure definition doesn't change in any of our
|
||||||
|
|
@ -158,27 +158,27 @@ loading ES and DI as shown in Listing 22.3.
|
||||||
**LISTING 22.3 L22-3.ASM**
|
**LISTING 22.3 L22-3.ASM**
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
ClearS proc near
|
ClearS proc near
|
||||||
push bp ;save caller's BP
|
push bp ;save caller's BP
|
||||||
mov bp,sp ;point to stack frame
|
mov bp,sp ;point to stack frame
|
||||||
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
||||||
jne Start ; pointer is passed
|
jne Start ; pointer is passed
|
||||||
cmp word ptr [bp].BufOfs,0
|
cmp word ptr [bp].BufOfs,0
|
||||||
je Bye
|
je Bye
|
||||||
Start: cld ;make STOSW count up
|
Start: cld ;make STOSW count up
|
||||||
mov ax,[bp].Attrib ;load AX with attribute parameter
|
mov ax,[bp].Attrib ;load AX with attribute parameter
|
||||||
and ax,0ff00h ;prepare for merging with fill char
|
and ax,0ff00h ;prepare for merging with fill char
|
||||||
mov bx,[bp].Filler ;load BX with fill char
|
mov bx,[bp].Filler ;load BX with fill char
|
||||||
and bx,0ffh ;prepare for merging with attribute
|
and bx,0ffh ;prepare for merging with attribute
|
||||||
or ax,bx ;combine attribute and fill char
|
or ax,bx ;combine attribute and fill char
|
||||||
les di,dword ptr [bp].BufOfs ;load ES:DI with target buffer
|
les di,dword ptr [bp].BufOfs ;load ES:DI with target buffer
|
||||||
;segment:offset
|
;segment:offset
|
||||||
mov cx,[bp].BufSize ;load CX with buffer size
|
mov cx,[bp].BufSize ;load CX with buffer size
|
||||||
rep stosw ;fill the buffer
|
rep stosw ;fill the buffer
|
||||||
Bye:
|
Bye:
|
||||||
pop bp ;restore caller's BP
|
pop bp ;restore caller's BP
|
||||||
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
||||||
ClearS endp
|
ClearS endp
|
||||||
```
|
```
|
||||||
|
|
||||||
That's good for another three bytes. We're down to 43 bytes, and
|
That's good for another three bytes. We're down to 43 bytes, and
|
||||||
|
|
@ -190,27 +190,27 @@ values as shown in Listing 22.4.
|
||||||
|
|
||||||
**LISTING 22.4 L22-4.ASM**
|
**LISTING 22.4 L22-4.ASM**
|
||||||
|
|
||||||
ClearS proc near
|
ClearS proc near
|
||||||
push bp ;save caller's BP
|
push bp ;save caller's BP
|
||||||
mov bp,sp ;point to stack frame
|
mov bp,sp ;point to stack frame
|
||||||
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
||||||
jne Start ; pointer is passed
|
jne Start ; pointer is passed
|
||||||
cmp word ptr [bp].BufOfs,0
|
cmp word ptr [bp].BufOfs,0
|
||||||
je Bye
|
je Bye
|
||||||
Start: cld ;make STOSW count up
|
Start: cld ;make STOSW count up
|
||||||
mov ax,[bp].Attrib ;load AX with attribute parameter
|
mov ax,[bp].Attrib ;load AX with attribute parameter
|
||||||
sub al,al ;prepare for merging with fill char
|
sub al,al ;prepare for merging with fill char
|
||||||
mov bx,[bp].Filler ;load BX with fill char
|
mov bx,[bp].Filler ;load BX with fill char
|
||||||
sub bh,bh ;prepare for merging with attribute
|
sub bh,bh ;prepare for merging with attribute
|
||||||
or ax,bx ;combine attribute and fill char
|
or ax,bx ;combine attribute and fill char
|
||||||
les di,dword ptr [bp].BufOfs ;load ES:DI with target buffer
|
les di,dword ptr [bp].BufOfs ;load ES:DI with target buffer
|
||||||
;segment:offset
|
;segment:offset
|
||||||
mov cx,[bp].BufSize ;load CX with buffer size
|
mov cx,[bp].BufSize ;load CX with buffer size
|
||||||
rep stosw ;fill the buffer
|
rep stosw ;fill the buffer
|
||||||
Bye:
|
Bye:
|
||||||
pop bp ;restore caller's BP
|
pop bp ;restore caller's BP
|
||||||
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
||||||
ClearS endp
|
ClearS endp
|
||||||
|
|
||||||
Now we're down to 40 bytes—more than 20 percent smaller than the
|
Now we're down to 40 bytes—more than 20 percent smaller than the
|
||||||
original code. That's pretty much it for simple instruction
|
original code. That's pretty much it for simple instruction
|
||||||
|
|
@ -232,23 +232,23 @@ shows the new code.
|
||||||
**LISTING 22.5 L22-5.ASM**
|
**LISTING 22.5 L22-5.ASM**
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
ClearS proc near
|
ClearS proc near
|
||||||
push bp ;save caller's BP
|
push bp ;save caller's BP
|
||||||
mov bp,sp ;point to stack frame
|
mov bp,sp ;point to stack frame
|
||||||
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
cmp word ptr [bp].BufSeg,0 ;skip the fill if a null
|
||||||
jne Start ; pointer is passed
|
jne Start ; pointer is passed
|
||||||
cmp word ptr [bp].BufOfs,0
|
cmp word ptr [bp].BufOfs,0
|
||||||
je Bye
|
je Bye
|
||||||
Start: cld ;make STOSW count up
|
Start: cld ;make STOSW count up
|
||||||
mov ah,byte ptr [bp].Attrib[1] ;load AH with attribute
|
mov ah,byte ptr [bp].Attrib[1];load AH with attribute
|
||||||
mov al,byte ptr [bp].Filler ;load AL with fill char
|
mov al,byte ptr [bp].Filler ;load AL with fill char
|
||||||
les di,dword ptr [bp].BufOfs ;load ES:DI with target buffer segment:offset
|
les di,dword ptr [bp].BufOfs ;load ES:DI with target buffer segment:offset
|
||||||
mov cx,[bp].BufSize ;load CX with buffer size
|
mov cx,[bp].BufSize ;load CX with buffer size
|
||||||
rep stosw ;fill the buffer
|
rep stosw ;fill the buffer
|
||||||
Bye:
|
Bye:
|
||||||
pop bp ;restore caller's BP
|
pop bp ;restore caller's BP
|
||||||
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
||||||
ClearS endp
|
ClearS endp
|
||||||
```
|
```
|
||||||
|
|
||||||
(We could get rid of yet another instruction by having the calling code
|
(We could get rid of yet another instruction by having the calling code
|
||||||
|
|
@ -266,22 +266,22 @@ shown in Listing 22.6.
|
||||||
**LISTING 22.6 L22-6.ASM**
|
**LISTING 22.6 L22-6.ASM**
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
ClearS proc near
|
ClearS proc near
|
||||||
push bp ;save caller's BP
|
push bp ;save caller's BP
|
||||||
mov bp,sp ;point to stack frame
|
mov bp,sp ;point to stack frame
|
||||||
les di,dword ptr [bp].BufOfs ;load ES:DI with target buffer;segment:offset
|
les di,dword ptr [bp].BufOfs ;load ES:DI with target buffer;segment:offset
|
||||||
mov ax,es ;put segment where we can test it
|
mov ax,es ;put segment where we can test it
|
||||||
or ax,di ;is it a null pointer?
|
or ax,di ;is it a null pointer?
|
||||||
je Bye ;yes, so we're done
|
je Bye ;yes, so we're done
|
||||||
Start: cld ;make STOSW count up
|
Start: cld ;make STOSW count up
|
||||||
mov ah,byte ptr [bp].Attrib[1] ;load AH with attribute
|
mov ah,byte ptr [bp].Attrib[1];load AH with attribute
|
||||||
mov al,byte ptr [bp].Filler ;load AL with fill char
|
mov al,byte ptr [bp].Filler ;load AL with fill char
|
||||||
mov cx,[bp].BufSize ;load CX with buffer size
|
mov cx,[bp].BufSize ;load CX with buffer size
|
||||||
rep stosw ;fill the buffer
|
rep stosw ;fill the buffer
|
||||||
Bye:
|
Bye:
|
||||||
pop bp ;restore caller's BP
|
pop bp ;restore caller's BP
|
||||||
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
ret EndMrk-RetAddr-2 ;return, clearing the parms from the stack
|
||||||
ClearS endp
|
ClearS endp
|
||||||
```
|
```
|
||||||
|
|
||||||
Well. Now we're down to 28 bytes, having reduced the size of this
|
Well. Now we're down to 28 bytes, having reduced the size of this
|
||||||
|
|
@ -327,22 +327,22 @@ With that problem dealt with, Listing 22.7 shows the Zenned version of
|
||||||
**LISTING 22.7 L22-7.ASM**
|
**LISTING 22.7 L22-7.ASM**
|
||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
ClearS proc near
|
ClearS procnear
|
||||||
pop dx ;get the return address
|
pop dx ;get the return address
|
||||||
pop ax ;put fill char into AL
|
pop ax ;put fill char into AL
|
||||||
pop bx ;get the attribute
|
pop bx ;get the attribute
|
||||||
mov ah,bh ;put attribute into AH
|
mov ah,bh ;put attribute into AH
|
||||||
pop cx ;get the buffer size
|
pop cx ;get the buffer size
|
||||||
pop di ;get the offset of the buffer origin
|
pop di ;get the offset of the buffer origin
|
||||||
pop es ;get the segment of the buffer origin
|
pop es ;get the segment of the buffer origin
|
||||||
mov bx,es ;put the segment where we can test it
|
mov bx,es ;put the segment where we can test it
|
||||||
or bx,di ;null pointer?
|
or bx,di ;null pointer?
|
||||||
je Bye ;yes, so we're done
|
je Bye ;yes, so we're done
|
||||||
cld ;make STOSW count up
|
cld ;make STOSW count up
|
||||||
rep stosw ;do the string store
|
rep stosw ;do the string store
|
||||||
Bye:
|
Bye:
|
||||||
jmp dx ;return to the calling code
|
jmp dx ;return to the calling code
|
||||||
ClearS endp
|
ClearS endp
|
||||||
```
|
```
|
||||||
|
|
||||||
At long last, we're down to the bare metal. This version of `ClearS`
|
At long last, we're down to the bare metal. This version of `ClearS`
|
||||||
|
|
|
||||||
|
|
@ -85,12 +85,12 @@ registers.
|
||||||
;
|
;
|
||||||
; By Michael Abrash
|
; By Michael Abrash
|
||||||
;
|
;
|
||||||
stack segment word stack 'STACK'
|
stacksegmentword stack 'STACK'
|
||||||
db 512 dup (?)
|
db512 dup (?)
|
||||||
stack ends
|
stackends
|
||||||
;
|
;
|
||||||
data segment word 'DATA'
|
datasegment word 'DATA'
|
||||||
IMAGE_WIDTH EQU 4 ;in bytes
|
IMAGE_WIDTHEQU 4 ;in bytes
|
||||||
IMAGE_HEIGHT EQU 32 ;in pixels
|
IMAGE_HEIGHT EQU 32 ;in pixels
|
||||||
LEFT_BOUND EQU 10 ;in bytes
|
LEFT_BOUND EQU 10 ;in bytes
|
||||||
RIGHT_BOUND EQU 66 ;in bytes
|
RIGHT_BOUND EQU 66 ;in bytes
|
||||||
|
|
@ -105,11 +105,11 @@ READ_MAP EQU 4 ;Read Map register index in GC
|
||||||
;
|
;
|
||||||
PatternPlane0 label byte
|
PatternPlane0 label byte
|
||||||
db 32 dup (0ffh,0ffh,0,0)
|
db 32 dup (0ffh,0ffh,0,0)
|
||||||
PatternPlane1 label byte
|
PatternPlane1 labelbyte
|
||||||
db 32 dup (0ffh,0,0ffh,0)
|
db 32 dup (0ffh,0,0ffh,0)
|
||||||
PatternPlane2 label byte
|
PatternPlane2 labelbyte
|
||||||
db 32 dup (0f0h,0f0h,0f0h,0f0h)
|
db 32 dup (0f0h,0f0h,0f0h,0f0h)
|
||||||
PatternPlane3 label byte
|
PatternPlane3 labelbyte
|
||||||
db 32 dup (0cch,0cch,0cch,0cch)
|
db 32 dup (0cch,0cch,0cch,0cch)
|
||||||
;
|
;
|
||||||
; Temporary storage for 16-color image during animation.
|
; Temporary storage for 16-color image during animation.
|
||||||
|
|
@ -124,7 +124,7 @@ ImagePlane3 db 32*4 dup (?)
|
||||||
ImageX dw 40 ;in bytes
|
ImageX dw 40 ;in bytes
|
||||||
ImageY dw 100 ;in pixels
|
ImageY dw 100 ;in pixels
|
||||||
ImageXDirection dw 1 ;in bytes
|
ImageXDirection dw 1 ;in bytes
|
||||||
data ends
|
dataends
|
||||||
;
|
;
|
||||||
code segment word 'CODE'
|
code segment word 'CODE'
|
||||||
assume cs:code,ds:data
|
assume cs:code,ds:data
|
||||||
|
|
@ -197,12 +197,12 @@ DelayLoop:
|
||||||
int 10h
|
int 10h
|
||||||
mov ah,4ch
|
mov ah,4ch
|
||||||
int 21h
|
int 21h
|
||||||
Start endp
|
Startendp
|
||||||
;
|
;
|
||||||
; Draws the image at offset DS:SI to the current image location in
|
; Draws the image at offset DS:SI to the current image location in
|
||||||
; VGA memory.
|
; VGA memory.
|
||||||
;
|
;
|
||||||
DrawImage proc near
|
DrawImageprocnear
|
||||||
mov ax,VGA_SEGMENT
|
mov ax,VGA_SEGMENT
|
||||||
mov es,ax
|
mov es,ax
|
||||||
call GetImageOffset ;ES:DI is the destination address for the
|
call GetImageOffset ;ES:DI is the destination address for the
|
||||||
|
|
@ -233,7 +233,7 @@ DrawImageLoop:
|
||||||
cmp al,10h ;have we done all four planes?
|
cmp al,10h ;have we done all four planes?
|
||||||
jnz DrawImagePlaneLoop
|
jnz DrawImagePlaneLoop
|
||||||
ret
|
ret
|
||||||
DrawImage endp
|
DrawImageendp
|
||||||
;
|
;
|
||||||
; Copies the image from its current location in VGA memory into the
|
; Copies the image from its current location in VGA memory into the
|
||||||
; buffer at DS:DI.
|
; buffer at DS:DI.
|
||||||
|
|
@ -274,7 +274,7 @@ GetImageLoop:
|
||||||
push es
|
push es
|
||||||
pop ds ;restore original DS
|
pop ds ;restore original DS
|
||||||
ret
|
ret
|
||||||
GetImage endp
|
GetImageendp
|
||||||
;
|
;
|
||||||
; Erases the image at its current location.
|
; Erases the image at its current location.
|
||||||
;
|
;
|
||||||
|
|
@ -410,7 +410,7 @@ Start proc near
|
||||||
mov al,1 ;blue is color 1
|
mov al,1 ;blue is color 1
|
||||||
call SelectSetResetColor ;set to draw in blue
|
call SelectSetResetColor ;set to draw in blue
|
||||||
mov ax,VGA_SEGMENT
|
mov ax,VGA_SEGMENT
|
||||||
mov es,ax
|
move s,ax
|
||||||
sub di,di
|
sub di,di
|
||||||
mov cx,7000h
|
mov cx,7000h
|
||||||
rep stosb ;the value written actually doesn't
|
rep stosb ;the value written actually doesn't
|
||||||
|
|
@ -435,7 +435,7 @@ VLineLoop:
|
||||||
; provides the data written to display
|
; provides the data written to display
|
||||||
; memory, and AL is actually ignored)
|
; memory, and AL is actually ignored)
|
||||||
add di,SCREEN_WIDTH-1 ;point to the next scan line
|
add di,SCREEN_WIDTH-1 ;point to the next scan line
|
||||||
loop VLineLoop
|
loopVLineLoop
|
||||||
;
|
;
|
||||||
; Select write mode 0 and read mode 1.
|
; Select write mode 0 and read mode 1.
|
||||||
;
|
;
|
||||||
|
|
@ -513,12 +513,12 @@ WaitKeyLoop:
|
||||||
int 10h ;return to text mode
|
int 10h ;return to text mode
|
||||||
mov ah,4ch
|
mov ah,4ch
|
||||||
int 21h ;done
|
int 21h ;done
|
||||||
Start endp
|
Startendp
|
||||||
;
|
;
|
||||||
; Enables set/reset for all planes, and sets the set/reset color
|
; Enables set/reset for all planes, and sets the set/reset color
|
||||||
; to AL.
|
; to AL.
|
||||||
;
|
;
|
||||||
SelectSetResetColor proc near
|
SelectSetResetColorprocnear
|
||||||
mov dx,GC_INDEX
|
mov dx,GC_INDEX
|
||||||
push ax ;preserve color
|
push ax ;preserve color
|
||||||
mov al,SET_RESET
|
mov al,SET_RESET
|
||||||
|
|
@ -533,7 +533,7 @@ SelectSetResetColor proc near
|
||||||
mov al,0fh
|
mov al,0fh
|
||||||
out dx,al ;enable set/reset for all planes
|
out dx,al ;enable set/reset for all planes
|
||||||
ret
|
ret
|
||||||
SelectSetResetColor endp
|
SelectSetResetColorendp
|
||||||
code ends
|
code ends
|
||||||
end Start
|
end Start
|
||||||
```
|
```
|
||||||
|
|
@ -636,7 +636,7 @@ COLOR_DONT_CARE EQU 7 ;Color Don't Care register index in GC
|
||||||
;
|
;
|
||||||
code segment word 'CODE'
|
code segment word 'CODE'
|
||||||
assume cs:code
|
assume cs:code
|
||||||
Start proc near
|
Startprocnear
|
||||||
;
|
;
|
||||||
; Select graphics mode 12h.
|
; Select graphics mode 12h.
|
||||||
;
|
;
|
||||||
|
|
@ -698,7 +698,7 @@ DrawDiagonalLoop:
|
||||||
; point to the next scan line
|
; point to the next scan line
|
||||||
ror al,1 ;move the pixel mask one pixel to the right
|
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
|
adc bx,0 ;advance to the next byte if the pixel mask wrapped
|
||||||
loop DrawDiagonalLoop
|
loopDrawDiagonalLoop
|
||||||
;
|
;
|
||||||
; Wait for a key to be pressed to end, then return to text mode and
|
; Wait for a key to be pressed to end, then return to text mode and
|
||||||
; return to DOS.
|
; return to DOS.
|
||||||
|
|
@ -713,7 +713,7 @@ WaitKeyLoop:
|
||||||
int 10h ;return to text mode
|
int 10h ;return to text mode
|
||||||
mov ah,4ch
|
mov ah,4ch
|
||||||
int 21h ;done
|
int 21h ;done
|
||||||
Start endp
|
Startendp
|
||||||
code ends
|
code ends
|
||||||
end Start
|
end Start
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ RestoreTheScreen:
|
||||||
RestoreLoop:
|
RestoreLoop:
|
||||||
mov dx,SC_INDEX
|
mov dx,SC_INDEX
|
||||||
mov al,MAP_MASK ;set SC Index to Map Mask register
|
mov al,MAP_MASK ;set SC Index to Map Mask register
|
||||||
out dx,al
|
outdx,al
|
||||||
inc dx
|
inc dx
|
||||||
mov cl,[Plane] ;get the # of the plane we want
|
mov cl,[Plane] ;get the # of the plane we want
|
||||||
; to restore
|
; to restore
|
||||||
|
|
@ -557,14 +557,14 @@ x= x+1
|
||||||
; Used to label the colors of the color bars. (Color values are
|
; Used to label the colors of the color bars. (Color values are
|
||||||
; filled in on the fly.)
|
; filled in on the fly.)
|
||||||
;
|
;
|
||||||
ColorNumbers label byte
|
ColorNumberslabelbyte
|
||||||
rept 16
|
rept 16
|
||||||
db ‘000h', 0ah, 8, 8, 8, 8
|
db ‘000h', 0ah, 8, 8, 8, 8
|
||||||
endm
|
endm
|
||||||
COLOR_ENTRY_LENGTH equ ($-ColorNumbers)/16
|
COLOR_ENTRY_LENGTHequ($-ColorNumbers)/16
|
||||||
db ‘$'
|
db ‘$'
|
||||||
;
|
;
|
||||||
CurrentColor db ?
|
CurrentColordb?
|
||||||
;
|
;
|
||||||
; Space for the array of 16 colors we'll pass to the BIOS, plus
|
; Space for the array of 16 colors we'll pass to the BIOS, plus
|
||||||
; an overscan setting of black.
|
; an overscan setting of black.
|
||||||
|
|
@ -574,7 +574,7 @@ Data ends
|
||||||
;
|
;
|
||||||
Code segment
|
Code segment
|
||||||
assume cs:Code, ds:Data
|
assume cs:Code, ds:Data
|
||||||
Start proc near
|
Start procnear
|
||||||
cld
|
cld
|
||||||
mov ax,Data
|
mov ax,Data
|
||||||
mov ds,ax
|
mov ds,ax
|
||||||
|
|
@ -764,7 +764,7 @@ ColorNumberLoop:
|
||||||
mov dx,offset ColorNumbers
|
mov dx,offset ColorNumbers
|
||||||
int 21h ;put up the attribute numbers
|
int 21h ;put up the attribute numbers
|
||||||
ret
|
ret
|
||||||
ColorNumbersUp endp
|
ColorNumbersUpendp
|
||||||
;
|
;
|
||||||
Start endp
|
Start endp
|
||||||
Code ends
|
Code ends
|
||||||
|
|
@ -820,7 +820,7 @@ WAIT_KEY macro
|
||||||
endm
|
endm
|
||||||
;
|
;
|
||||||
stack segment para stack ‘STACK'
|
stack segment para stack ‘STACK'
|
||||||
db 512 dup (?)
|
db512 dup (?)
|
||||||
stack ends
|
stack ends
|
||||||
;
|
;
|
||||||
Data segment word ‘DATA'
|
Data segment word ‘DATA'
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ SCREEN_WIDTH equ 640
|
||||||
SCREEN_HEIGHT equ 350
|
SCREEN_HEIGHT equ 350
|
||||||
CRTC_INDEX equ 3d4h ;CRT Controller Index register
|
CRTC_INDEX equ 3d4h ;CRT Controller Index register
|
||||||
OVERFLOW equ 7 ;index of Overflow reg in CRTC
|
OVERFLOW equ 7 ;index of Overflow reg in CRTC
|
||||||
MAXIMUM_SCAN_LINE equ 9 ;index of Maximum Scan Line register
|
MAXIMUM_SCAN_LINEequ 9 ;index of Maximum Scan Line register
|
||||||
; in CRTC
|
; in CRTC
|
||||||
START_ADDRESS_HIGH equ 0ch ;index of Start Address High register
|
START_ADDRESS_HIGH equ 0ch ;index of Start Address High register
|
||||||
; in CRTC
|
; in CRTC
|
||||||
|
|
@ -318,7 +318,7 @@ CountVerticalSyncsLoop:
|
||||||
int 10h ;return to text mode
|
int 10h ;return to text mode
|
||||||
mov ah,4ch
|
mov ah,4ch
|
||||||
int 21h ;return to DOS
|
int 21h ;return to DOS
|
||||||
Start endp
|
Startendp
|
||||||
;*********************************************************************
|
;*********************************************************************
|
||||||
; Waits for the leading edge of the vertical sync pulse.
|
; Waits for the leading edge of the vertical sync pulse.
|
||||||
;
|
;
|
||||||
|
|
@ -328,7 +328,7 @@ Start endp
|
||||||
;
|
;
|
||||||
; Registers altered: AL, DX
|
; Registers altered: AL, DX
|
||||||
;
|
;
|
||||||
WaitForVerticalSyncStart proc near
|
WaitForVerticalSyncStartprocnear
|
||||||
mov dx,INPUT_STATUS_0
|
mov dx,INPUT_STATUS_0
|
||||||
WaitNotVerticalSync:
|
WaitNotVerticalSync:
|
||||||
in al,dx
|
in al,dx
|
||||||
|
|
@ -349,7 +349,7 @@ WaitForVerticalSyncStart endp
|
||||||
;
|
;
|
||||||
; Registers altered: AL, DX
|
; Registers altered: AL, DX
|
||||||
;
|
;
|
||||||
WaitForVerticalSyncEnd proc near
|
WaitForVerticalSyncEndprocnear
|
||||||
mov dx,INPUT_STATUS_0
|
mov dx,INPUT_STATUS_0
|
||||||
WaitVerticalSync2:
|
WaitVerticalSync2:
|
||||||
in al,dx
|
in al,dx
|
||||||
|
|
@ -360,7 +360,7 @@ WaitNotVerticalSync2:
|
||||||
test al,08h
|
test al,08h
|
||||||
jnz WaitNotVerticalSync2
|
jnz WaitNotVerticalSync2
|
||||||
ret
|
ret
|
||||||
WaitForVerticalSyncEnd endp
|
WaitForVerticalSyncEndendp
|
||||||
;*********************************************************************
|
;*********************************************************************
|
||||||
; Sets the start address to the value specifed by StartAddress.
|
; Sets the start address to the value specifed by StartAddress.
|
||||||
; Wait for the trailing edge of vertical sync before setting so that
|
; Wait for the trailing edge of vertical sync before setting so that
|
||||||
|
|
@ -751,7 +751,7 @@ MyStack segment para stack 'STACK'
|
||||||
db 512 dup (0)
|
db 512 dup (0)
|
||||||
MyStack ends
|
MyStack ends
|
||||||
;*********************************************************************
|
;*********************************************************************
|
||||||
Data segment
|
Datasegment
|
||||||
SplitScreenLine dw ? ;line the split screen currently
|
SplitScreenLine dw ? ;line the split screen currently
|
||||||
; starts after
|
; starts after
|
||||||
StartAddress dw ? ;display memory offset at which
|
StartAddress dw ? ;display memory offset at which
|
||||||
|
|
@ -763,7 +763,7 @@ Data ends
|
||||||
Code segment
|
Code segment
|
||||||
assume cs:Code, ds:Data
|
assume cs:Code, ds:Data
|
||||||
;*********************************************************************
|
;*********************************************************************
|
||||||
Start proc near
|
Startproc near
|
||||||
mov ax,Data
|
mov ax,Data
|
||||||
mov ds,ax
|
mov ds,ax
|
||||||
;
|
;
|
||||||
|
|
@ -810,7 +810,7 @@ RowLoop:
|
||||||
mov cx,LOGICAL_SCREEN_WIDTH/8/4
|
mov cx,LOGICAL_SCREEN_WIDTH/8/4
|
||||||
;fill 1 scan line
|
;fill 1 scan line
|
||||||
ColumnLoop:
|
ColumnLoop:
|
||||||
stosw ;draw part of a diagonal line
|
sto sw ;draw part of a diagonal line
|
||||||
mov word ptr es:[di],0 ;make vertical blank spaces so
|
mov word ptr es:[di],0 ;make vertical blank spaces so
|
||||||
; panning effects can be seen easily
|
; panning effects can be seen easily
|
||||||
inc di
|
inc di
|
||||||
|
|
@ -832,12 +832,12 @@ RowLoop2:
|
||||||
mov cx,LOGICAL_SCREEN_WIDTH/8/4
|
mov cx,LOGICAL_SCREEN_WIDTH/8/4
|
||||||
;fill 1 scan line
|
;fill 1 scan line
|
||||||
ColumnLoop2:
|
ColumnLoop2:
|
||||||
stosw ;draw part of a diagonal line
|
sto sw ;draw part of a diagonal line
|
||||||
mov word ptr es:[di],0 ;make vertical blank spaces so
|
mov word ptr es:[di],0 ;make vertical blank spaces so
|
||||||
; panning effects can be seen easily
|
; panning effects can be seen easily
|
||||||
inc di
|
inc di
|
||||||
inc di
|
inc di
|
||||||
loop ColumnLoop2
|
loopColumnLoop2
|
||||||
ror ax,1 ;shift pattern word
|
ror ax,1 ;shift pattern word
|
||||||
dec dx
|
dec dx
|
||||||
jnz RowLoop2
|
jnz RowLoop2
|
||||||
|
|
@ -847,7 +847,7 @@ loop ColumnLoop2
|
||||||
; screen jerks back and forth as the pel panning setting cycles.
|
; screen jerks back and forth as the pel panning setting cycles.
|
||||||
;
|
;
|
||||||
mov cx,200 ;pan 200 pixels to the left
|
mov cx,200 ;pan 200 pixels to the left
|
||||||
call PanRight
|
callPanRight
|
||||||
;
|
;
|
||||||
; Wait for a key press (don't echo character).
|
; Wait for a key press (don't echo character).
|
||||||
;
|
;
|
||||||
|
|
@ -904,7 +904,7 @@ endif
|
||||||
int 10h ;return to text mode
|
int 10h ;return to text mode
|
||||||
mov ah,4ch
|
mov ah,4ch
|
||||||
int 21h ;return to DOS
|
int 21h ;return to DOS
|
||||||
Start endp
|
Startendp
|
||||||
;*********************************************************************
|
;*********************************************************************
|
||||||
; Waits for the leading edge of the vertical sync pulse.
|
; Waits for the leading edge of the vertical sync pulse.
|
||||||
;
|
;
|
||||||
|
|
@ -997,7 +997,7 @@ SetPelPan proc near
|
||||||
mov al,[PelPan]
|
mov al,[PelPan]
|
||||||
out dx,al ;load the new Pel Pan setting
|
out dx,al ;load the new Pel Pan setting
|
||||||
ret
|
ret
|
||||||
SetPelPan endp
|
SetPelPanendp
|
||||||
;*********************************************************************
|
;*********************************************************************
|
||||||
; Sets the scan line the split screen starts after to the scan line
|
; Sets the scan line the split screen starts after to the scan line
|
||||||
; specified by SplitScreenLine.
|
; specified by SplitScreenLine.
|
||||||
|
|
@ -1104,8 +1104,8 @@ DoSetStartAddress:
|
||||||
ret
|
ret
|
||||||
PanRight endp
|
PanRight endp
|
||||||
;*********************************************************************
|
;*********************************************************************
|
||||||
Code ends
|
Codeends
|
||||||
end Start
|
endStart
|
||||||
```
|
```
|
||||||
|
|
||||||
### Notes on Setting and Reading Registers
|
### Notes on Setting and Reading Registers
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ the way up to 360x480—and that's with the vanilla IBM VGA!
|
||||||
|
|
||||||
In this chapter, I'm going to focus on one of my favorite 256-color
|
In this chapter, I'm going to focus on one of my favorite 256-color
|
||||||
modes, which provides 320x400 resolution and two graphics pages and can
|
modes, which provides 320x400 resolution and two graphics pages and can
|
||||||
be set up with very little reprogramming of the VGA. In the next chapter, I'll
|
be set up with very little reof the VGA. In the next chapter, I'll
|
||||||
discuss higher-resolution 256-color modes, and starting in Chapter 47,
|
discuss higher-resolution 256-color modes, and starting in Chapter 47,
|
||||||
I'll cover the high-performance "Mode X" 256-color programming that many
|
I'll cover the high-performance "Mode X" 256-color programming that many
|
||||||
games use.
|
games use.
|
||||||
|
|
@ -283,7 +283,7 @@ endif
|
||||||
;
|
;
|
||||||
; Macro to output a constant value to an indexed VGA register.
|
; Macro to output a constant value to an indexed VGA register.
|
||||||
;
|
;
|
||||||
CONSTANT_TO_INDEXED_REGISTER macro ADDRESS, INDEX, VALUE
|
CONSTANT_TO_INDEXED_REGISTERmacroADDRESS, INDEX, VALUE
|
||||||
mov dx,ADDRESS
|
mov dx,ADDRESS
|
||||||
mov ax,(VALUE shl 8) + INDEX
|
mov ax,(VALUE shl 8) + INDEX
|
||||||
OUT_WORD
|
OUT_WORD
|
||||||
|
|
@ -309,7 +309,7 @@ ColorLoop:
|
||||||
; line descriptor list
|
; line descriptor list
|
||||||
LineLoop:
|
LineLoop:
|
||||||
mov cx,[si+StartX] ;set the initial X coordinate
|
mov cx,[si+StartX] ;set the initial X coordinate
|
||||||
cmp cx,-1
|
cmpcx,-1
|
||||||
jz LinesDone ;a descriptor with a -1 X
|
jz LinesDone ;a descriptor with a -1 X
|
||||||
; coordinate marks the end
|
; coordinate marks the end
|
||||||
; of the list
|
; of the list
|
||||||
|
|
@ -341,7 +341,7 @@ LinesDone:
|
||||||
;
|
;
|
||||||
call GetNextKey
|
call GetNextKey
|
||||||
mov ax,0003h
|
mov ax,0003h
|
||||||
int 10h ;text mode
|
int 10h text mode
|
||||||
mov ah,4ch
|
mov ah,4ch
|
||||||
int 21h ;done
|
int 21h ;done
|
||||||
;
|
;
|
||||||
|
|
@ -373,22 +373,22 @@ Set320By400Mode proc near
|
||||||
mov al,MEMORY_MODE
|
mov al,MEMORY_MODE
|
||||||
out dx,al
|
out dx,al
|
||||||
inc dx
|
inc dx
|
||||||
in al,dx
|
ina l,dx
|
||||||
and al,not 08h ;turn off chain 4
|
and al,not 08h ;turn off chain 4
|
||||||
or al,04h ;turn off odd/even
|
ora l,04h ;turn off odd/even
|
||||||
out dx,al
|
out dx,al
|
||||||
mov dx,GC_INDEX
|
mov dx,GC_INDEX
|
||||||
mov al,GRAPHICS_MODE
|
mov al,GRAPHICS_MODE
|
||||||
out dx,al
|
out dx,al
|
||||||
inc dx
|
inc dx
|
||||||
in al,dx
|
ina l,dx
|
||||||
and al,not 10h ;turn off odd/even
|
and al,not 10h ;turn off odd/even
|
||||||
out dx,al
|
out dx,al
|
||||||
dec dx
|
dec dx
|
||||||
mov al,MISCELLANEOUS
|
mov al,MISCELLANEOUS
|
||||||
out dx,al
|
out dx,al
|
||||||
inc dx
|
inc dx
|
||||||
in al,dx
|
ina l,dx
|
||||||
and al,not 02h ;turn off chain
|
and al,not 02h ;turn off chain
|
||||||
out dx,al
|
out dx,al
|
||||||
;
|
;
|
||||||
|
|
@ -477,7 +477,7 @@ WritePixel proc near
|
||||||
; the pixel
|
; the pixel
|
||||||
mov es:[di],bl ;draw the pixel
|
mov es:[di],bl ;draw the pixel
|
||||||
ret
|
ret
|
||||||
WritePixel endp
|
WritePixelendp
|
||||||
;
|
;
|
||||||
; Reads the color of the pixel at the specified location in 320x400
|
; Reads the color of the pixel at the specified location in 320x400
|
||||||
; 256-color mode.
|
; 256-color mode.
|
||||||
|
|
@ -491,7 +491,7 @@ WritePixel endp
|
||||||
;
|
;
|
||||||
; Registers altered: AX, CX, DX, SI, ES
|
; Registers altered: AX, CX, DX, SI, ES
|
||||||
;
|
;
|
||||||
ReadPixel proc near
|
ReadPixelprocnear
|
||||||
mov ax,VGA_SEGMENT
|
mov ax,VGA_SEGMENT
|
||||||
mov es,ax ;point to display memory
|
mov es,ax ;point to display memory
|
||||||
mov ax,SCREEN_WIDTH/4
|
mov ax,SCREEN_WIDTH/4
|
||||||
|
|
@ -511,9 +511,9 @@ ReadPixel proc near
|
||||||
mov dx,GC_INDEX
|
mov dx,GC_INDEX
|
||||||
OUT_WORD ;set to read from the proper plane for
|
OUT_WORD ;set to read from the proper plane for
|
||||||
; the pixel
|
; the pixel
|
||||||
lods byte ptr es:[si] ;read the pixel
|
lodsbyte ptr es:[si] ;read the pixel
|
||||||
ret
|
ret
|
||||||
ReadPixel endp
|
ReadPixelendp
|
||||||
;
|
;
|
||||||
; Waits for the next key and returns it in AX.
|
; Waits for the next key and returns it in AX.
|
||||||
;
|
;
|
||||||
|
|
@ -677,20 +677,20 @@ stack ends
|
||||||
;
|
;
|
||||||
OUT_WORDmacro
|
OUT_WORDmacro
|
||||||
if WORD_OUTS_OK
|
if WORD_OUTS_OK
|
||||||
out dx,ax
|
outdx,ax
|
||||||
else
|
else
|
||||||
out dx,al
|
out dx,al
|
||||||
inc dx
|
inc dx
|
||||||
xchg ah,al
|
xch gah,al
|
||||||
out dx,al
|
out dx,al
|
||||||
dec dx
|
dec dx
|
||||||
xchg ah,al
|
xch gah,al
|
||||||
endif
|
endif
|
||||||
endm
|
endm
|
||||||
;
|
;
|
||||||
; Macro to output a constant value to an indexed VGA register.
|
; Macro to output a constant value to an indexed VGA register.
|
||||||
;
|
;
|
||||||
CONSTANT_TO_INDEXED_REGISTER macro ADDRESS, INDEX, VALUE
|
CONSTANT_TO_INDEXED_REGISTERmacroADDRESS, INDEX, VALUE
|
||||||
mov dx,ADDRESS
|
mov dx,ADDRESS
|
||||||
mov ax,(VALUE shl 8) + INDEX
|
mov ax,(VALUE shl 8) + INDEX
|
||||||
OUT_WORD
|
OUT_WORD
|
||||||
|
|
@ -702,7 +702,7 @@ Start proc near
|
||||||
;
|
;
|
||||||
; Set 320x400 256-color mode.
|
; Set 320x400 256-color mode.
|
||||||
;
|
;
|
||||||
call Set320By400Mode
|
callSet320By400Mode
|
||||||
;
|
;
|
||||||
; We're in 320x400 256-color mode, with page 0 displayed.
|
; 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.
|
; Let's fill page 0 with color bars slanting down and to the right.
|
||||||
|
|
@ -722,7 +722,7 @@ call Set320By400Mode
|
||||||
;
|
;
|
||||||
; Wait for a key and flip to page 1 when one is pressed.
|
; Wait for a key and flip to page 1 when one is pressed.
|
||||||
;
|
;
|
||||||
call GetNextKey
|
callGetNextKey
|
||||||
CONSTANT_TO_INDEXED_REGISTER CRTC_INDEX,START_ADDRESS_HIGH,80h
|
CONSTANT_TO_INDEXED_REGISTER CRTC_INDEX,START_ADDRESS_HIGH,80h
|
||||||
;set the Start Address High register
|
;set the Start Address High register
|
||||||
; to 80h, for a start address of 8000h
|
; to 80h, for a start address of 8000h
|
||||||
|
|
@ -735,7 +735,7 @@ call Set320By400Mode
|
||||||
;
|
;
|
||||||
; Wait for another key and flip back to page 0 when one is pressed.
|
; Wait for another key and flip back to page 0 when one is pressed.
|
||||||
;
|
;
|
||||||
call GetNextKey
|
callGetNextKey
|
||||||
CONSTANT_TO_INDEXED_REGISTER CRTC_INDEX,START_ADDRESS_HIGH,00h
|
CONSTANT_TO_INDEXED_REGISTER CRTC_INDEX,START_ADDRESS_HIGH,00h
|
||||||
;set the Start Address High register
|
;set the Start Address High register
|
||||||
; to 00h, for a start address of 0000h
|
; to 00h, for a start address of 0000h
|
||||||
|
|
@ -757,7 +757,7 @@ Start endp
|
||||||
;
|
;
|
||||||
; Output: none
|
; Output: none
|
||||||
;
|
;
|
||||||
Set320By400Mode proc near
|
Set320By400Modeprocnear
|
||||||
;
|
;
|
||||||
; First, go to normal 320x200 256-color mode, which is really a
|
; First, go to normal 320x200 256-color mode, which is really a
|
||||||
; 320x400 256-color mode with each line scanned twice.
|
; 320x400 256-color mode with each line scanned twice.
|
||||||
|
|
@ -777,22 +777,22 @@ Set320By400Mode proc near
|
||||||
mov al,MEMORY_MODE
|
mov al,MEMORY_MODE
|
||||||
out dx,al
|
out dx,al
|
||||||
inc dx
|
inc dx
|
||||||
in al,dx
|
ina l,dx
|
||||||
and al,not 08h ;turn off chain 4
|
and al,not 08h ;turn off chain 4
|
||||||
or al,04h ;turn off odd/even
|
ora l,04h ;turn off odd/even
|
||||||
out dx,al
|
out dx,al
|
||||||
mov dx,GC_INDEX
|
mov dx,GC_INDEX
|
||||||
mov al,GRAPHICS_MODE
|
mov al,GRAPHICS_MODE
|
||||||
out dx,al
|
out dx,al
|
||||||
inc dx
|
inc dx
|
||||||
in al,dx
|
ina l,dx
|
||||||
and al,not 10h ;turn off odd/even
|
and al,not 10h ;turn off odd/even
|
||||||
out dx,al
|
out dx,al
|
||||||
dec dx
|
dec dx
|
||||||
mov al,MISCELLANEOUS
|
mov al,MISCELLANEOUS
|
||||||
out dx,al
|
out dx,al
|
||||||
inc dx
|
inc dx
|
||||||
in al,dx
|
ina l,dx
|
||||||
and al,not 02h ;turn off chain
|
and al,not 02h ;turn off chain
|
||||||
out dx,al
|
out dx,al
|
||||||
;
|
;
|
||||||
|
|
@ -830,8 +830,8 @@ CONSTANT_TO_INDEXED_REGISTER SC_INDEX,MAP_MASK,0fh
|
||||||
mov al,UNDERLINE
|
mov al,UNDERLINE
|
||||||
out dx,al
|
out dx,al
|
||||||
inc dx
|
inc dx
|
||||||
in al,dx
|
ina l,dx
|
||||||
and al,not 40h ;turn off doubleword
|
and al,not40h ;turn off doubleword
|
||||||
out dx,al
|
out dx,al
|
||||||
dec dx
|
dec dx
|
||||||
mov al,MODE_CONTROL
|
mov al,MODE_CONTROL
|
||||||
|
|
@ -853,7 +853,7 @@ Set320By400Mode endp
|
||||||
; make them slant down and to the left, 0 to make
|
; make them slant down and to the left, 0 to make
|
||||||
; them vertical.
|
; them vertical.
|
||||||
;
|
;
|
||||||
ColorBarsUp proc near
|
ColorBarsUpprocnear
|
||||||
mov ax,VGA_SEGMENT
|
mov ax,VGA_SEGMENT
|
||||||
mov es,ax ;point to display memory
|
mov es,ax ;point to display memory
|
||||||
sub bh,bh ;start with color 0
|
sub bh,bh ;start with color 0
|
||||||
|
|
@ -867,7 +867,7 @@ RowLoop:
|
||||||
;4 pixels at each address, so
|
;4 pixels at each address, so
|
||||||
; each 320-pixel row is 80 bytes wide
|
; each 320-pixel row is 80 bytes wide
|
||||||
; in each plane
|
; in each plane
|
||||||
push bx ;save the row-start color
|
pus h bx ;save the row-start color
|
||||||
ColumnLoop:
|
ColumnLoop:
|
||||||
MAP_SELECT = 1
|
MAP_SELECT = 1
|
||||||
rept 4 ;do all 4 pixels at this address with
|
rept 4 ;do all 4 pixels at this address with
|
||||||
|
|
@ -887,11 +887,11 @@ MAP_SELECT = MAP_SELECT shl 1
|
||||||
dec si ;count down lines on the screen
|
dec si ;count down lines on the screen
|
||||||
jnz RowLoop
|
jnz RowLoop
|
||||||
ret
|
ret
|
||||||
ColorBarsUp endp
|
ColorBarsUpendp
|
||||||
;
|
;
|
||||||
; Waits for the next key and returns it in AX.
|
; Waits for the next key and returns it in AX.
|
||||||
;
|
;
|
||||||
GetNextKey proc near
|
GetNextKeyprocnear
|
||||||
WaitKey:
|
WaitKey:
|
||||||
mov ah,1
|
mov ah,1
|
||||||
int 16h
|
int 16h
|
||||||
|
|
@ -901,9 +901,9 @@ WaitKey:
|
||||||
ret
|
ret
|
||||||
GetNextKey endp
|
GetNextKey endp
|
||||||
;
|
;
|
||||||
Code ends
|
Codeends
|
||||||
;
|
;
|
||||||
end Start
|
endStart
|
||||||
```
|
```
|
||||||
|
|
||||||
When you run Listing 31.2, note the extremely smooth edges and fine
|
When you run Listing 31.2, note the extremely smooth edges and fine
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ WORD_OUTS_OK equ 1 ;set to 0 to assemble for
|
||||||
; computers that can't handle
|
; computers that can't handle
|
||||||
; word outs to indexed VGA registers
|
; word outs to indexed VGA registers
|
||||||
;
|
;
|
||||||
_DATA segment public byte ‘DATA'
|
_DATAsegmentpublic byte ‘DATA'
|
||||||
;
|
;
|
||||||
; 360x480 256-color mode CRT Controller register settings.
|
; 360x480 256-color mode CRT Controller register settings.
|
||||||
; (Courtesy of John Bridges.)
|
; (Courtesy of John Bridges.)
|
||||||
|
|
@ -171,7 +171,7 @@ vptbl dw 06b00h ; horz total
|
||||||
dw 00616h ; v blank end
|
dw 00616h ; v blank end
|
||||||
dw 0e317h ; turn on byte mode
|
dw 0e317h ; turn on byte mode
|
||||||
vpend label word
|
vpend label word
|
||||||
_DATA ends
|
_DATAends
|
||||||
;
|
;
|
||||||
; Macro to output a word value to a port.
|
; Macro to output a word value to a port.
|
||||||
;
|
;
|
||||||
|
|
@ -199,7 +199,7 @@ _TEXTsegment byte public ‘CODE'
|
||||||
; Returns: nothing
|
; Returns: nothing
|
||||||
;
|
;
|
||||||
public _Set360x480Mode
|
public _Set360x480Mode
|
||||||
_Set360x480Mode proc near
|
_Set360x480Modeprocnear
|
||||||
push si ;preserve C register vars
|
push si ;preserve C register vars
|
||||||
push di
|
push di
|
||||||
mov ax,12h ; start with mode 12h
|
mov ax,12h ; start with mode 12h
|
||||||
|
|
@ -239,7 +239,7 @@ _Set360x480Mode proc near
|
||||||
pop di ;restore C register vars
|
pop di ;restore C register vars
|
||||||
pop si
|
pop si
|
||||||
ret
|
ret
|
||||||
_Set360x480Mode endp
|
_Set360x480Modeendp
|
||||||
;
|
;
|
||||||
; Draws a pixel in the specified color at the specified
|
; Draws a pixel in the specified color at the specified
|
||||||
; location in 360x480 256-color mode.
|
; location in 360x480 256-color mode.
|
||||||
|
|
@ -258,7 +258,7 @@ Color dw ? ;color in which to draw (in the
|
||||||
DParms ends
|
DParms ends
|
||||||
;
|
;
|
||||||
public _Draw360x480Dot
|
public _Draw360x480Dot
|
||||||
_Draw360x480Dot proc near
|
_Draw360x480Dotprocnear
|
||||||
push bp ;preserve caller's BP
|
push bp ;preserve caller's BP
|
||||||
mov bp,sp ;point to stack frame
|
mov bp,sp ;point to stack frame
|
||||||
push si ;preserve C register vars
|
push si ;preserve C register vars
|
||||||
|
|
@ -289,7 +289,7 @@ _Draw360x480Dot proc near
|
||||||
pop si
|
pop si
|
||||||
pop bp ;restore caller's BP
|
pop bp ;restore caller's BP
|
||||||
ret
|
ret
|
||||||
_Draw360x480Dot endp
|
_Draw360x480Dotendp
|
||||||
;
|
;
|
||||||
; Reads the color of the pixel at the specified
|
; Reads the color of the pixel at the specified
|
||||||
; location in 360x480 256-color mode.
|
; location in 360x480 256-color mode.
|
||||||
|
|
@ -306,7 +306,7 @@ ReadY dw ? ;Y coordinate from which to read
|
||||||
RParms ends
|
RParms ends
|
||||||
;
|
;
|
||||||
public _Read360x480Dot
|
public _Read360x480Dot
|
||||||
_Read360x480Dot proc near
|
_Read360x480Dotprocnear
|
||||||
push bp ;preserve caller's BP
|
push bp ;preserve caller's BP
|
||||||
mov bp,sp ;point to stack frame
|
mov bp,sp ;point to stack frame
|
||||||
push si ;preserve C register vars
|
push si ;preserve C register vars
|
||||||
|
|
@ -336,7 +336,7 @@ _Read360x480Dot proc near
|
||||||
pop bp ;restore caller's BP
|
pop bp ;restore caller's BP
|
||||||
ret
|
ret
|
||||||
_Read360x480Dot endp
|
_Read360x480Dot endp
|
||||||
_TEXT ends
|
_TEX Tends
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -532,7 +532,7 @@ FillVertLoop:
|
||||||
jnz FillHorzLoop ;no, do the next column
|
jnz FillHorzLoop ;no, do the next column
|
||||||
ret;
|
ret;
|
||||||
|
|
||||||
end Start
|
endStart
|
||||||
```
|
```
|
||||||
|
|
||||||
Note the jagged lines at the corners of the screen when you run Listing
|
Note the jagged lines at the corners of the screen when you run Listing
|
||||||
|
|
|
||||||
|
|
@ -390,7 +390,7 @@ RowLoop:
|
||||||
ColumnLoop:
|
ColumnLoop:
|
||||||
stosb ;draw a pixel
|
stosb ;draw a pixel
|
||||||
add al,1 ;increment the attribute
|
add al,1 ;increment the attribute
|
||||||
adc al,0 ;if the attribute just turned
|
ad cal,0 ;if the attribute just turned
|
||||||
; over to 0, increment it to 1
|
; over to 0, increment it to 1
|
||||||
; because we're not going to
|
; because we're not going to
|
||||||
; cycle DAC location 0, so
|
; cycle DAC location 0, so
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ _LineDraw proc near
|
||||||
cld
|
cld
|
||||||
push bp ;preserve caller's stack frame
|
push bp ;preserve caller's stack frame
|
||||||
mov bp,sp ;point to our stack frame
|
mov bp,sp ;point to our stack frame
|
||||||
sub sp, LOCAL_SIZE ;allocate space for local variables
|
sub sp, LOCAL_SIZE ;allocate space for local variables
|
||||||
push si ;preserve C register variables
|
push si ;preserve C register variables
|
||||||
push di
|
push di
|
||||||
push ds ;preserve caller's DS
|
push ds ;preserve caller's DS
|
||||||
|
|
@ -115,7 +115,7 @@ _LineDraw proc near
|
||||||
jle LineIsTopToBottom
|
jle LineIsTopToBottom
|
||||||
xchg [bp].YEnd,ax; swap endpoints
|
xchg [bp].YEnd,ax; swap endpoints
|
||||||
mov [bp].YStart,ax
|
mov [bp].YStart,ax
|
||||||
mov bx,[bp].XStart
|
movbx, [bp].XStart
|
||||||
xchg [bp].XEnd,bx
|
xchg [bp].XEnd,bx
|
||||||
mov [bp].XStart,bx
|
mov [bp].XStart,bx
|
||||||
LineIsTopToBottom:
|
LineIsTopToBottom:
|
||||||
|
|
|
||||||
|
|
@ -718,7 +718,7 @@ DiagonalSkipEntry:
|
||||||
jmp ScanEdgeDone
|
jmp ScanEdgeDone
|
||||||
align 2
|
align 2
|
||||||
YMajor:
|
YMajor:
|
||||||
push bp ;preserve stack frame pointer
|
pushbp ;preserve stack frame pointer
|
||||||
mov si,[bp+X1] ;starting X coordinate
|
mov si,[bp+X1] ;starting X coordinate
|
||||||
cmp [bp+SkipFirst],1 ;skip the first point?
|
cmp [bp+SkipFirst],1 ;skip the first point?
|
||||||
mov bp,bx ;put Height in BP for error term calcs
|
mov bp,bx ;put Height in BP for error term calcs
|
||||||
|
|
@ -734,7 +734,7 @@ YMajorSkipEntry:
|
||||||
YMajorNoAdvance:
|
YMajorNoAdvance:
|
||||||
dec bx ;count off this scan line
|
dec bx ;count off this scan line
|
||||||
jnz YMajorLoop
|
jnz YMajorLoop
|
||||||
pop bp ;restore stack frame pointer
|
popbp ;restore stack frame pointer
|
||||||
ScanEdgeDone:
|
ScanEdgeDone:
|
||||||
cmp [bp+SetXStart],1 ;were we working with XStart field?
|
cmp [bp+SetXStart],1 ;were we working with XStart field?
|
||||||
jz UpdateHLinePtr ;yes, DI points to the next XStart
|
jz UpdateHLinePtr ;yes, DI points to the next XStart
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,7 @@ Dataends
|
||||||
;
|
;
|
||||||
; Macro to output a word value to a port.
|
; Macro to output a word value to a port.
|
||||||
;
|
;
|
||||||
OUT_WORD macro
|
OUT_WORDmacro
|
||||||
if WORD_OUTS_OK
|
if WORD_OUTS_OK
|
||||||
out dx,ax
|
out dx,ax
|
||||||
else
|
else
|
||||||
|
|
@ -459,9 +459,9 @@ endif
|
||||||
; Macro to output a constant value to an indexed VGA
|
; Macro to output a constant value to an indexed VGA
|
||||||
; register.
|
; register.
|
||||||
;
|
;
|
||||||
CONSTANT_TO_INDEXED_REGISTER macro ADDRESS, INDEX, VALUE
|
CONSTANT_TO_INDEXED_REGISTERmacro ADDRESS, INDEX, VALUE
|
||||||
mov dx, ADDRESS
|
movdx, ADDRESS
|
||||||
mov ax, (VALUE shl 8) + INDEX
|
movax, (VALUE shl 8) + INDEX
|
||||||
OUT_WORD
|
OUT_WORD
|
||||||
endm
|
endm
|
||||||
;
|
;
|
||||||
|
|
@ -704,7 +704,7 @@ DrawObject proc near
|
||||||
mov dx,ax ;# of lines in the image
|
mov dx,ax ;# of lines in the image
|
||||||
lodsw ;# of bytes across the image
|
lodsw ;# of bytes across the image
|
||||||
mov bp,SCREEN_WIDTH
|
mov bp,SCREEN_WIDTH
|
||||||
sub bp,ax ;# of bytes to add to the display
|
subbp,ax ;# of bytes to add to the display
|
||||||
; memory offset after copying a line
|
; memory offset after copying a line
|
||||||
; of the image to display memory in
|
; of the image to display memory in
|
||||||
; order to point to the address
|
; order to point to the address
|
||||||
|
|
@ -718,9 +718,9 @@ DrawLoop:
|
||||||
; next line will go in display
|
; next line will go in display
|
||||||
; memory
|
; memory
|
||||||
dec dx ;count down the lines of the image
|
dec dx ;count down the lines of the image
|
||||||
jnz DrawLoop
|
jnzDrawLoop
|
||||||
ret
|
ret
|
||||||
DrawObject endp
|
DrawObjectendp
|
||||||
;
|
;
|
||||||
Code ends
|
Code ends
|
||||||
end Start
|
end Start
|
||||||
|
|
|
||||||
|
|
@ -447,7 +447,7 @@ DrawRectParms ends
|
||||||
mov dh,RightMask[bx] ;set the right-edge clip mask
|
mov dh,RightMask[bx] ;set the right-edge clip mask
|
||||||
mov bx,LeftX[bp]
|
mov bx,LeftX[bp]
|
||||||
and bx,NOT 7 ;intrapixel address of left edge
|
and bx,NOT 7 ;intrapixel address of left edge
|
||||||
sub si,bx
|
su si,bx
|
||||||
shr si,1
|
shr si,1
|
||||||
shr si,1
|
shr si,1
|
||||||
shr si,1 ;# of bytes across spanned by rectangle - 1
|
shr si,1 ;# of bytes across spanned by rectangle - 1
|
||||||
|
|
@ -455,7 +455,7 @@ DrawRectParms ends
|
||||||
and dl,dh ; combine the masks
|
and dl,dh ; combine the masks
|
||||||
MasksSet:
|
MasksSet:
|
||||||
mov bx,BottomY[bp]
|
mov bx,BottomY[bp]
|
||||||
sub bx,TopY[bp] ;# of scan lines to fill - 1
|
su bx,TopY[bp] ;# of scan lines to fill - 1
|
||||||
FillLoop:
|
FillLoop:
|
||||||
push di ;remember line start offset
|
push di ;remember line start offset
|
||||||
mov al,dl ;left edge clip mask
|
mov al,dl ;left edge clip mask
|
||||||
|
|
@ -661,7 +661,7 @@ TextUpDone:
|
||||||
CharUp: ;draws the character in AL at ES:DI
|
CharUp: ;draws the character in AL at ES:DI
|
||||||
lds si,[BIOS8x8Ptr] ;point to the 8x8 font start
|
lds si,[BIOS8x8Ptr] ;point to the 8x8 font start
|
||||||
mov bl,al
|
mov bl,al
|
||||||
sub bh,bh
|
su bh,bh
|
||||||
shl bx,1
|
shl bx,1
|
||||||
shl bx,1
|
shl bx,1
|
||||||
shl bx,1 ;*8 to look up character offset in font
|
shl bx,1 ;*8 to look up character offset in font
|
||||||
|
|
|
||||||
|
|
@ -499,7 +499,7 @@ parms ends
|
||||||
les di,[bp+BufferPtr]
|
les di,[bp+BufferPtr]
|
||||||
mov dx,[bp+RectHeight]
|
mov dx,[bp+RectHeight]
|
||||||
mov bx,[bp+BufferWidth]
|
mov bx,[bp+BufferWidth]
|
||||||
sub bx,[bp+RectWidth] ;distance from end of one dest scan
|
su bx,[bp+RectWidth] ;distance from end of one dest scan
|
||||||
; to start of next
|
; to start of next
|
||||||
mov al,byte ptr [bp+Color]
|
mov al,byte ptr [bp+Color]
|
||||||
mov ah,al ;double the color for REP STOSW
|
mov ah,al ;double the color for REP STOSW
|
||||||
|
|
@ -544,7 +544,7 @@ parms2 ends
|
||||||
mov bx,[bp+Pixels]
|
mov bx,[bp+Pixels]
|
||||||
mov dx,[bp+ImageHeight]
|
mov dx,[bp+ImageHeight]
|
||||||
mov ax,[bp+BufferWidth2]
|
mov ax,[bp+BufferWidth2]
|
||||||
sub ax,[bp+ImageWidth] ;distance from end of one dest scan
|
su ax,[bp+ImageWidth] ;distance from end of one dest scan
|
||||||
mov [bp+BufferWidth2],ax ; to start of next
|
mov [bp+BufferWidth2],ax ; to start of next
|
||||||
RowLoop2:
|
RowLoop2:
|
||||||
mov cx,[bp+ImageWidth]
|
mov cx,[bp+ImageWidth]
|
||||||
|
|
@ -556,7 +556,7 @@ ColumnLoop:
|
||||||
mov es:[di],al
|
mov es:[di],al
|
||||||
SkipPixel:
|
SkipPixel:
|
||||||
inc bx ;point to next source pixel
|
inc bx ;point to next source pixel
|
||||||
inc di ;point to next dest pixel
|
inc d ;point to next dest pixel
|
||||||
dec cx
|
dec cx
|
||||||
jnz ColumnLoop
|
jnz ColumnLoop
|
||||||
add di,[bp+BufferWidth2] ;point to next scan to fill
|
add di,[bp+BufferWidth2] ;point to next scan to fill
|
||||||
|
|
@ -596,9 +596,9 @@ parms3 ends
|
||||||
lds si,[bp+SrcBufferPtr]
|
lds si,[bp+SrcBufferPtr]
|
||||||
mov dx,[bp+CopyHeight]
|
mov dx,[bp+CopyHeight]
|
||||||
mov bx,[bp+DestBufferWidth] ;distance from end of one dest scan
|
mov bx,[bp+DestBufferWidth] ;distance from end of one dest scan
|
||||||
sub bx,[bp+CopyWidth] ; of copy to the next
|
su bx,[bp+CopyWidth] ; of copy to the next
|
||||||
mov ax,[bp+SrcBufferWidth] ;distance from end of one source scan
|
mov ax,[bp+SrcBufferWidth] ;distance from end of one source scan
|
||||||
sub ax,[bp+CopyWidth] ; of copy to the next
|
su ax,[bp+CopyWidth] ; of copy to the next
|
||||||
RowLoop3:
|
RowLoop3:
|
||||||
mov cx,[bp+CopyWidth] ;# of bytes to copy
|
mov cx,[bp+CopyWidth] ;# of bytes to copy
|
||||||
shr cx,1
|
shr cx,1
|
||||||
|
|
|
||||||
|
|
@ -521,7 +521,7 @@ MasksSet:
|
||||||
mov [bp+SourceNextScanOffset],ax
|
mov [bp+SourceNextScanOffset],ax
|
||||||
mov [bp+RectAddrWidth],cx ;remember width in addresses - 1
|
mov [bp+RectAddrWidth],cx ;remember width in addresses - 1
|
||||||
;----------------------BUG FIX
|
;----------------------BUG FIX
|
||||||
mov dx,SC_INDEX
|
mov dx,SC_INDEX
|
||||||
mov al,MAP_MASK
|
mov al,MAP_MASK
|
||||||
out dx,al ;point SC Index reg to Map Mask
|
out dx,al ;point SC Index reg to Map Mask
|
||||||
inc dx ;point to SC Data reg
|
inc dx ;point to SC Data reg
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ else ; !ROUNDING-ON
|
||||||
sub eax,eax
|
sub eax,eax
|
||||||
shrd eax,edx,16 ;position so that result ends up
|
shrd eax,edx,16 ;position so that result ends up
|
||||||
sar edx,16 ; in EAX
|
sar edx,16 ; in EAX
|
||||||
idiv dword ptr [bp+Divisor]
|
idivdword ptr [bp+Divisor]
|
||||||
endif ;ROUNDING-ON
|
endif ;ROUNDING-ON
|
||||||
shld edx,eax,16 ;whole part of result in DX;
|
shld edx,eax,16 ;whole part of result in DX;
|
||||||
; fractional part is already in AX
|
; fractional part is already in AX
|
||||||
|
|
@ -199,7 +199,7 @@ SCparms ends
|
||||||
|
|
||||||
align ALIGNMENT
|
align ALIGNMENT
|
||||||
public -CosSin
|
public -CosSin
|
||||||
-CosSin proc near
|
-CosSinprocnear
|
||||||
push bp ;preserve stack frame
|
push bp ;preserve stack frame
|
||||||
mov bp,sp ;set up local stack frame
|
mov bp,sp ;set up local stack frame
|
||||||
|
|
||||||
|
|
@ -224,9 +224,9 @@ jg MakeInRange
|
||||||
ja Quadrant1
|
ja Quadrant1
|
||||||
;quadrant 0
|
;quadrant 0
|
||||||
shl bx,2
|
shl bx,2
|
||||||
mov eax,CosTable[bx] ;look up sine
|
move ax,CosTable[bx] ;look up sine
|
||||||
neg bx ;sin(Angle) = cos(90-Angle)
|
neg bx ;sin(Angle) = cos(90-Angle)
|
||||||
mov edx,CosTable[bx+90*10*4] ;look up cosine
|
move dx,CosTable[bx+90*10*4] ;look up cosine
|
||||||
jmp short CSDone
|
jmp short CSDone
|
||||||
|
|
||||||
align ALIGNMENT
|
align ALIGNMENT
|
||||||
|
|
@ -237,7 +237,7 @@ Quadrant1:
|
||||||
mov eax,CosTable[bx] ;look up cosine
|
mov eax,CosTable[bx] ;look up cosine
|
||||||
neg eax ;negative in this quadrant
|
neg eax ;negative in this quadrant
|
||||||
neg bx ;sin(Angle) = cos(90-Angle)
|
neg bx ;sin(Angle) = cos(90-Angle)
|
||||||
mov edx,CosTable[bx+90*10*4] ;look up cosine
|
move dx,CosTable[bx+90*10*4] ;look up cosine
|
||||||
jmp short CSDone
|
jmp short CSDone
|
||||||
|
|
||||||
align ALIGNMENT
|
align ALIGNMENT
|
||||||
|
|
@ -248,11 +248,11 @@ BottomHalf: ;quadrant 2 or 3
|
||||||
ja Quadrant2
|
ja Quadrant2
|
||||||
;quadrant 3
|
;quadrant 3
|
||||||
shl bx, 2
|
shl bx, 2
|
||||||
mov eax,CosTable[bx] ;look up cosine
|
mov eax,CosTable[bx] ;look up cosine
|
||||||
neg bx ;sin(Angle) = cos(90-Angle)
|
neg bx ;sin(Angle) = cos(90-Angle)
|
||||||
mov edx,CosTable[90*10*4+bx] ;look up sine
|
movedx,CosTable[90*10*4+bx] ;look up sine
|
||||||
neg edx ;negative in this quadrant
|
nege dx ;negative in this quadrant
|
||||||
jmp short CSDone
|
jmp short CSDone
|
||||||
|
|
||||||
align ALIGNMENT
|
align ALIGNMENT
|
||||||
Quadrant2:
|
Quadrant2:
|
||||||
|
|
@ -262,8 +262,8 @@ Quadrant2:
|
||||||
mov eax,CosTable[bx] ;look up cosine
|
mov eax,CosTable[bx] ;look up cosine
|
||||||
neg eax ;negative in this quadrant
|
neg eax ;negative in this quadrant
|
||||||
neg bx ;sin(Angle) = cos(90-Angle)
|
neg bx ;sin(Angle) = cos(90-Angle)
|
||||||
mov edx,CosTable[90*10*4+bx] ;look up sine
|
move dx,CosTable[90*10*4+bx] ;look up sine
|
||||||
neg edx ;negative in this quadrant
|
nege dx ;negative in this quadrant
|
||||||
CSDone:
|
CSDone:
|
||||||
mov bx,[bp].Cos
|
mov bx,[bp].Cos
|
||||||
mov [bx],eax
|
mov [bx],eax
|
||||||
|
|
@ -272,7 +272,7 @@ CSDone:
|
||||||
|
|
||||||
pop bp;restore stack frame
|
pop bp;restore stack frame
|
||||||
ret
|
ret
|
||||||
-CosSin endp
|
-CosSinendp
|
||||||
;=====================================================================
|
;=====================================================================
|
||||||
; Matrix multiplies Xform by SourceVec, and stores the result in
|
; Matrix multiplies Xform by SourceVec, and stores the result in
|
||||||
; DestVec. Multiplies a 4x4 matrix times a 4x1 matrix; the result
|
; DestVec. Multiplies a 4x4 matrix times a 4x1 matrix; the result
|
||||||
|
|
@ -347,11 +347,11 @@ soff=soff+16
|
||||||
doff=doff+4
|
doff=doff+4
|
||||||
ENDM
|
ENDM
|
||||||
|
|
||||||
pop di;restore register variables
|
popdi;restore register variables
|
||||||
pop si
|
popsi
|
||||||
pop bp;restore stack frame
|
popbp;restore stack frame
|
||||||
ret
|
ret
|
||||||
-XformVec endp
|
-XformVecendp
|
||||||
;=====================================================================
|
;=====================================================================
|
||||||
; Matrix multiplies SourceXform1 by SourceXform2 and stores the
|
; Matrix multiplies SourceXform1 by SourceXform2 and stores the
|
||||||
; result in DestXform. Multiplies a 4x4 matrix times a 4x4 matrix;
|
; result in DestXform. Multiplies a 4x4 matrix times a 4x4 matrix;
|
||||||
|
|
@ -391,7 +391,7 @@ CXparms ends
|
||||||
push bp ;preserve stack frame
|
push bp ;preserve stack frame
|
||||||
mov bp,sp ;set up local stack frame
|
mov bp,sp ;set up local stack frame
|
||||||
push si ;preserve register variables
|
push si ;preserve register variables
|
||||||
push di
|
pushdi
|
||||||
|
|
||||||
mov bx,[bp].SourceXform2 ;BX points to xform2 matrix
|
mov bx,[bp].SourceXform2 ;BX points to xform2 matrix
|
||||||
mov si,[bp].SourceXform1 ;SI points to xform1 matrix
|
mov si,[bp].SourceXform1 ;SI points to xform1 matrix
|
||||||
|
|
@ -407,7 +407,7 @@ coff=0 ;column offset
|
||||||
imul dword ptr [bx+coff];times row 0 entry in column
|
imul dword ptr [bx+coff];times row 0 entry in column
|
||||||
if ROUNDING-ON
|
if ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
adc edx,0 ;whole part of result is in DX
|
adcedx,0;whole part of result is in DX
|
||||||
endif ;ROUNDING-ON
|
endif ;ROUNDING-ON
|
||||||
shrd eax,edx,16 ;shift the result back to 16.16 form
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
||||||
mov ecx,eax ;set running total
|
mov ecx,eax ;set running total
|
||||||
|
|
@ -471,11 +471,11 @@ coff=coff+4 ;point to next col in xform2 & dest
|
||||||
roff=roff+16 ;point to next col in xform2 & dest
|
roff=roff+16 ;point to next col in xform2 & dest
|
||||||
ENDM
|
ENDM
|
||||||
|
|
||||||
pop di;restore register variables
|
popdi;restore register variables
|
||||||
pop si
|
popsi
|
||||||
pop bp;restore stack frame
|
popbp;restore stack frame
|
||||||
ret
|
ret
|
||||||
-ConcatXforms endp
|
-ConcatXformsendp
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,14 +203,14 @@ _FixedMul endp
|
||||||
; Fixedpoint FixedDiv(Fixedpoint Dividend, Fixedpoint Divisor);
|
; Fixedpoint FixedDiv(Fixedpoint Dividend, Fixedpoint Divisor);
|
||||||
FDparms struc
|
FDparms struc
|
||||||
dw 2 dup(?) ;return address & pushed BP
|
dw 2 dup(?) ;return address & pushed BP
|
||||||
Dividend dd ?
|
Dividend dd?
|
||||||
Divisor dd ?
|
Divisor dd?
|
||||||
FDparms ends
|
FDparms ends
|
||||||
align ALIGNMENT
|
alignALIGNMENT
|
||||||
public _FixedDiv
|
public_FixedDiv
|
||||||
_FixedDivproc near
|
_FixedDivproc near
|
||||||
push bp
|
pushbp
|
||||||
mov bp,sp
|
movbp,sp
|
||||||
|
|
||||||
if USE386
|
if USE386
|
||||||
|
|
||||||
|
|
@ -268,13 +268,13 @@ else ;!USE386
|
||||||
; projection can't be performed for points closer to the viewpoint than Z=1.
|
; projection can't be performed for points closer to the viewpoint than Z=1.
|
||||||
;figure out signs, so we can use
|
;figure out signs, so we can use
|
||||||
; unsigned divisions
|
; unsigned divisions
|
||||||
sub cx,cx ;assume both operands positive
|
subcx, cx ;assume both operands positive
|
||||||
mov ax,word ptr [bp+Dividend+2]
|
mov ax,word ptr [bp+Dividend+2]
|
||||||
and ax,ax;first operand negative?
|
and ax,ax;first operand negative?
|
||||||
jns CheckSecondOperandD ;no
|
jns CheckSecondOperandD ;no
|
||||||
neg ax ;yes, so negate first operand
|
neg ax ;yes, so negate first operand
|
||||||
neg word ptr [bp+Dividend]
|
neg word ptr [bp+Dividend]
|
||||||
sbb ax,0
|
sbbax,0
|
||||||
inc cx ;mark that first operand is negative
|
inc cx ;mark that first operand is negative
|
||||||
CheckSecondOperandD:
|
CheckSecondOperandD:
|
||||||
mov bx,word ptr [bp+Divisor+2]
|
mov bx,word ptr [bp+Divisor+2]
|
||||||
|
|
@ -339,7 +339,7 @@ SCparms ends
|
||||||
|
|
||||||
alignALIGNMENT
|
alignALIGNMENT
|
||||||
public _CosSin
|
public _CosSin
|
||||||
_CosSin proc near
|
_CosSin procnear
|
||||||
push bp ;preserve stack frame
|
push bp ;preserve stack frame
|
||||||
mov bp,sp ;set up local stack frame
|
mov bp,sp ;set up local stack frame
|
||||||
|
|
||||||
|
|
@ -366,9 +366,9 @@ CheckInRange:
|
||||||
ja Quadrant1
|
ja Quadrant1
|
||||||
;quadrant 0
|
;quadrant 0
|
||||||
shl bx,2
|
shl bx,2
|
||||||
mov eax,CosTable[bx] ;look up sine
|
move ax,CosTable[bx] ;look up sine
|
||||||
neg bx;sin(Angle) = cos(90-Angle)
|
neg bx;sin(Angle) = cos(90-Angle)
|
||||||
mov edx,CosTable[bx+90*10*4] ;look up cosine
|
move dx,CosTable[bx+90*10*4] ;look up cosine
|
||||||
jmp short CSDone
|
jmp short CSDone
|
||||||
|
|
||||||
align ALIGNMENT
|
align ALIGNMENT
|
||||||
|
|
@ -376,10 +376,10 @@ Quadrant1:
|
||||||
neg bx
|
neg bx
|
||||||
add bx,180*10 ;convert to angle between 0 and 90
|
add bx,180*10 ;convert to angle between 0 and 90
|
||||||
shl bx,2
|
shl bx,2
|
||||||
mov eax,CosTable[bx] ;look up cosine
|
move ax,CosTable[bx] ;look up cosine
|
||||||
neg eax ;negative in this quadrant
|
neg eax ;negative in this quadrant
|
||||||
neg bx ;sin(Angle) = cos(90-Angle)
|
neg bx ;sin(Angle) = cos(90-Angle)
|
||||||
mov edx,CosTable[bx+90*10*4] ;look up cosine
|
move dx,CosTable[bx+90*10*4] ;look up cosine
|
||||||
jmp short CSDone
|
jmp short CSDone
|
||||||
|
|
||||||
align ALIGNMENT
|
align ALIGNMENT
|
||||||
|
|
@ -390,9 +390,9 @@ BottomHalf: ;quadrant 2 or 3
|
||||||
ja Quadrant2
|
ja Quadrant2
|
||||||
;quadrant 3
|
;quadrant 3
|
||||||
shl bx,2
|
shl bx,2
|
||||||
mov eax,CosTable[bx] ;look up cosine
|
move ax,CosTable[bx] ;look up cosine
|
||||||
neg bx;sin(Angle) = cos(90-Angle)
|
neg bx;sin(Angle) = cos(90-Angle)
|
||||||
mov edx,CosTable[90*10*4+bx] ;look up sine
|
move dx,CosTable[90*10*4+bx] ;look up sine
|
||||||
neg edx ;negative in this quadrant
|
neg edx ;negative in this quadrant
|
||||||
jmp short CSDone
|
jmp short CSDone
|
||||||
|
|
||||||
|
|
@ -401,10 +401,10 @@ Quadrant2:
|
||||||
neg bx
|
neg bx
|
||||||
add bx,180*10 ;convert to angle between 0 and 90
|
add bx,180*10 ;convert to angle between 0 and 90
|
||||||
shl bx,2
|
shl bx,2
|
||||||
mov eax,CosTable[bx] ;look up cosine
|
move ax,CosTable[bx] ;look up cosine
|
||||||
neg eax ;negative in this quadrant
|
neg eax ;negative in this quadrant
|
||||||
neg bx ;sin(Angle) = cos(90-Angle)
|
neg bx ;sin(Angle) = cos(90-Angle)
|
||||||
mov edx,CosTable[90*10*4+bx] ;look up sine
|
move dx,CosTable[90*10*4+bx] ;look up sine
|
||||||
neg edx ;negative in this quadrant
|
neg edx ;negative in this quadrant
|
||||||
CSDone:
|
CSDone:
|
||||||
mov bx,[bp].Cos
|
mov bx,[bp].Cos
|
||||||
|
|
@ -597,7 +597,7 @@ FixedMulDone:
|
||||||
|
|
||||||
align ALIGNMENT
|
align ALIGNMENT
|
||||||
public _XformVec
|
public _XformVec
|
||||||
_XformVec proc near
|
_XformVecprocnear
|
||||||
push bp ;preserve stack frame
|
push bp ;preserve stack frame
|
||||||
mov bp,sp ;set up local stack frame
|
mov bp,sp ;set up local stack frame
|
||||||
push si ;preserve register variables
|
push si ;preserve register variables
|
||||||
|
|
@ -619,9 +619,9 @@ if MUL-ROUNDING-ON
|
||||||
adc edx,0 ;whole part of result is in DX
|
adc edx,0 ;whole part of result is in DX
|
||||||
endif ;MUL-ROUNDING-ON
|
endif ;MUL-ROUNDING-ON
|
||||||
shrd eax,edx,16 ;shift the result back to 16.16 form
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
||||||
mov ecx,eax ;set running total
|
move cx,eax ;set running total
|
||||||
|
|
||||||
mov eax,[si+soff+4] ;column 1 entry on this row
|
move ax,[si+soff+4] ;column 1 entry on this row
|
||||||
imul dword ptr [bx+4] ;xform entry times source Y entry
|
imul dword ptr [bx+4] ;xform entry times source Y entry
|
||||||
if MUL-ROUNDING-ON
|
if MUL-ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
|
|
@ -630,7 +630,7 @@ endif ;MUL-ROUNDING-ON
|
||||||
shrd eax,edx,16 ;shift the result back to 16.16 form
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
||||||
add ecx,eax ;running total for this row
|
add ecx,eax ;running total for this row
|
||||||
|
|
||||||
mov eax,[si+soff+8] ;column 2 entry on this row
|
move ax,[si+soff+8] ;column 2 entry on this row
|
||||||
imul dword ptr [bx+8] ;xform entry times source Z entry
|
imul dword ptr [bx+8] ;xform entry times source Z entry
|
||||||
if MUL-ROUNDING-ON
|
if MUL-ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
|
|
@ -704,7 +704,7 @@ endif ;USE386
|
||||||
pop si
|
pop si
|
||||||
pop bp ;restore stack frame
|
pop bp ;restore stack frame
|
||||||
ret
|
ret
|
||||||
_XformVec endp
|
_XformVecendp
|
||||||
|
|
||||||
;=====================================================================
|
;=====================================================================
|
||||||
; Matrix multiplies SourceXform1 by SourceXform2 and stores the
|
; Matrix multiplies SourceXform1 by SourceXform2 and stores the
|
||||||
|
|
@ -741,7 +741,7 @@ CXparms ends
|
||||||
|
|
||||||
align ALIGNMENT
|
align ALIGNMENT
|
||||||
public _ConcatXforms
|
public _ConcatXforms
|
||||||
_ConcatXforms proc near
|
_ConcatXformsprocnear
|
||||||
push bp ;preserve stack frame
|
push bp ;preserve stack frame
|
||||||
mov bp,sp ;set up local stack frame
|
mov bp,sp ;set up local stack frame
|
||||||
push si ;preserve register variables
|
push si ;preserve register variables
|
||||||
|
|
@ -759,17 +759,17 @@ coff=0 ;column offset
|
||||||
REPT 3 ;once for each of the first 3 columns,
|
REPT 3 ;once for each of the first 3 columns,
|
||||||
; assuming 0 as the bottom entry (no
|
; assuming 0 as the bottom entry (no
|
||||||
; translation)
|
; translation)
|
||||||
mov eax,[si+roff] ;column 0 entry on this row
|
move ax,[si+roff] ;column 0 entry on this row
|
||||||
imul dword ptr [bx+coff] ;times row 0 entry in column
|
imul dword ptr [bx+coff] ;times row 0 entry in column
|
||||||
if MUL-ROUNDING-ON
|
if MUL-ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
adc edx,0 ;whole part of result is in DX
|
adc edx,0 ;whole part of result is in DX
|
||||||
endif ;MUL-ROUNDING-ON
|
endif ;MUL-ROUNDING-ON
|
||||||
shrd eax,edx,16 ;shift the result back to 16.16 form
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
||||||
mov ecx,eax ;set running total
|
move cx,eax ;set running total
|
||||||
|
|
||||||
mov eax,[si+roff+4] ;column 1 entry on this row
|
move ax,[si+roff+4] ;column 1 entry on this row
|
||||||
imul dword ptr [bx+coff+16] ;times row 1 entry in col
|
imuld word ptr [bx+coff+16] ;times row 1 entry in col
|
||||||
if MUL-ROUNDING-ON
|
if MUL-ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
adc edx,0 ;whole part of result is in DX
|
adc edx,0 ;whole part of result is in DX
|
||||||
|
|
@ -777,8 +777,8 @@ endif ;MUL-ROUNDING-ON
|
||||||
shrd eax,edx,16 ;shift the result back to 16.16 form
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
||||||
add ecx,eax ;running total
|
add ecx,eax ;running total
|
||||||
|
|
||||||
mov eax,[si+roff+8] ;column 2 entry on this row
|
move ax,[si+roff+8] ;column 2 entry on this row
|
||||||
imul dword ptr [bx+coff+32] ;times row 2 entry in col
|
imuld word ptr [bx+coff+32] ;times row 2 entry in col
|
||||||
if MUL-ROUNDING-ON
|
if MUL-ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
adc edx,0 ;whole part of result is in DX
|
adc edx,0 ;whole part of result is in DX
|
||||||
|
|
@ -792,17 +792,17 @@ coff=coff+4 ;point to next col in xform2 & dest
|
||||||
;now do the fourth column, assuming
|
;now do the fourth column, assuming
|
||||||
; 1 as the bottom entry, causing
|
; 1 as the bottom entry, causing
|
||||||
; translation to be performed
|
; translation to be performed
|
||||||
mov eax,[si+roff] ;column 0 entry on this row
|
move ax,[si+roff] ;column 0 entry on this row
|
||||||
imul dword ptr [bx+coff] ;times row 0 entry in column
|
imuld word ptr [bx+coff] ;times row 0 entry in column
|
||||||
if MUL-ROUNDING-ON
|
if MUL-ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
adc edx,0 ;whole part of result is in DX
|
adc edx,0 ;whole part of result is in DX
|
||||||
endif ;MUL-ROUNDING-ON
|
endif ;MUL-ROUNDING-ON
|
||||||
shrd eax,edx,16 ;shift the result back to 16.16 form
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
||||||
mov ecx,eax ;set running total
|
move cx,eax ;set running total
|
||||||
|
|
||||||
mov eax,[si+roff+4] ;column 1 entry on this row
|
move ax,[si+roff+4] ;column 1 entry on this row
|
||||||
imul dword ptr [bx+coff+16] ;times row 1 entry in col
|
imuld word ptr [bx+coff+16] ;times row 1 entry in col
|
||||||
if MUL-ROUNDING-ON
|
if MUL-ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
adc edx,0 ;whole part of result is in DX
|
adc edx,0 ;whole part of result is in DX
|
||||||
|
|
@ -810,8 +810,8 @@ endif ;MUL-ROUNDING-ON
|
||||||
shrd eax,edx,16 ;shift the result back to 16.16 form
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
||||||
add ecx,eax ;running total
|
add ecx,eax ;running total
|
||||||
|
|
||||||
mov eax,[si+roff+8] ;column 2 entry on this row
|
move ax,[si+roff+8] ;column 2 entry on this row
|
||||||
imul dword ptr [bx+coff+32] ;times row 2 entry in col
|
imuld word ptr [bx+coff+32] ;times row 2 entry in col
|
||||||
if MUL-ROUNDING-ON
|
if MUL-ROUNDING-ON
|
||||||
add eax,8000h ;round by adding 2^(-17)
|
add eax,8000h ;round by adding 2^(-17)
|
||||||
adc edx,0 ;whole part of result is in DX
|
adc edx,0 ;whole part of result is in DX
|
||||||
|
|
|
||||||
|
|
@ -547,7 +547,7 @@ void WalkTree(NODE *pNode)
|
||||||
// Pop the next node from the stack so
|
// Pop the next node from the stack so
|
||||||
// we can visit it and see if it has a
|
// we can visit it and see if it has a
|
||||||
// right subtree to be traversed
|
// right subtree to be traversed
|
||||||
if ((pNode = *--pNodeStack) == NULL)
|
if ((pNode = *—pNodeStack) == NULL)
|
||||||
{
|
{
|
||||||
// Stack is empty and the current node
|
// Stack is empty and the current node
|
||||||
// has no right child; we're done
|
// has no right child; we're done
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
# About this version
|
# About this version
|
||||||
|
|
||||||
|
All rights belong to Michael Abrash. Reproduced with permission.
|
||||||
|
|
||||||
This version was extracted from the PDFs which were [released by Michael Abrash and Dr. Dobbs in 2001](http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919). The intention is to maintain a canonical electronic version of the book, and make it easier to read in other formats and on other devices than were available when the book was released online.
|
This version was extracted from the PDFs which were [released by Michael Abrash and Dr. Dobbs in 2001](http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919). The intention is to maintain a canonical electronic version of the book, and make it easier to read in other formats and on other devices than were available when the book was released online.
|
||||||
|
|
||||||
For comments, suggestions, and improvements contact James Gregory at [james@jagregory.com](mailto:james@jagregory.com).
|
For comments, suggestions, and improvements contact James Gregory at [james@jagregory.com](mailto:james@jagregory.com).
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue