'=========================================================================== ' Subject: ASM MEMORY TRANSFER ROUTINES Date: 03-03-98 (00:00) ' Author: Jonathan L. Leger Code: QB, QBasic, PDS ' Origin: leger@earthlink.net Packet: MEMORY.ABC '=========================================================================== '***************************************** '*** ASMMEM.BAS *** by Jonathan Leger *** '***************************************** '*** A collection of routines for the *** '*** transfer of data between memory *** '*** addresses. They were written in *** '*** Jon's Snazy QBASIC Assembler v1.1 *** '*** and are hereby released into the *** '*** public domain. *** '***************************************** '*** Notice that although bearing the *** '*** same name, FillChar and MemCopy *** '*** have been optomized from their *** '*** earlier versions (esp MemCopy). *** '*** So if you are using the older one *** '*** you may want to switch. *** '***************************************** '*** Questions? Comments? *** '*** Requests for new ASM routines? *** '*** *** '*** Leger@Earthlink.Net *** '***************************************** DEFINT A-Z DECLARE SUB InitASM () DECLARE SUB FillChar (DestSeg%, DestOff%, Value%, bytes%) DECLARE SUB FillWord (DestSeg%, DestOff%, Value%, NumWords%) DECLARE SUB FillDoubleWord (DestSeg%, DestOff%, Value1%, Value2%, NumDbls%) DECLARE SUB MemCopy (FromSeg%, FromOff%, ToSeg%, ToOff%, bytes%) DECLARE SUB WordCopy (FromSeg%, FromOff%, ToSeg%, ToOff%, NumWords%) DECLARE SUB DoubleWordCopy (FromSeg%, FromOff%, ToSeg%, ToOff%, NumDbls%) DIM SHARED MemCopy.ASM$, WordCopy.ASM$, DoubleWordCopy.ASM$ DIM SHARED FillChar.ASM$, FillWord.ASM$, FillDoubleWord.ASM$ '******************************************************* '*** These routines were tested for speed by copying *** '*** 64k of data to the screen [Fill*()] and between *** '*** arrays [*Copy()]. All tests were in Qbasic 1.1 *** '*** *** '*** Here are approximate transfer rates of these *** '*** routines as they were performed on my 486dx2/66:*** '*** *** '*** FillChar() 5mb/sec *** '*** FillWord() 10mb/sec *** '*** FillDoubleWord() 5mb/sec [386+ only] *** '*** *** '*** MemCopy() 10mb/sec *** '*** WordCopy() 8mb/sec *** '*** DoubleWordCopy() 12mb/sec [386+ only] *** '*** *** '*** It seems odd to me that the WordCopy() is not *** '*** as fast as MemCopy() [since WordCopy() copies *** '*** in words and MemCopy() in bytes], especially *** '*** since FillWord() was faster than FillChar(). *** '*** If anyone understands why, please send me the *** '*** explanation! *** '******************************************************* '*** My thanks and gratitude go to Rick Elbers for *** '*** his information on using 386 Op-Codes w/DEBUG. *** '*** [Jon's Snazy QBASIC Assembler uses DEBUG.] *** '******************************************************* DIM a(1 TO 32000), b(1 TO 32000) InitASM '*** Must be called FIRST! '*** Test for Fill*() routines. SCREEN 13 T! = TIMER: frames = 0 DO FillDoubleWord &HA000, 0, &H101, &H101, 16000 frames = frames + 1 LOOP UNTIL TIMER - T! >= 10 SCREEN 0: WIDTH 80: PRINT "Approx."; (frames * 64000) / 10; "bytes/second." END '*** Test for *Copy() routines. FOR x = 1 TO 32000: a(x) = x: NEXT x T! = TIMER: count = 0 DO DoubleWordCopy VARSEG(a(1)), VARPTR(a(1)), VARSEG(b(1)), VARPTR(b(1)), 16000 count = count + 1 LOOP UNTIL TIMER - T! >= 10 PRINT "Approx. "; (count * 64000) / 10; "bytes/second." END '********************************************** '*** DoubleWordCopy() *** by Jonathan Leger *** '********************************************** '*** Copies the specified number of 4 byte *** '*** [DoubleWord] blocks from the location *** '*** FromSeg%:FromOff% to ToSeg%:ToOff%. *** '*** On my 486dx2/66, it does about 12mb/sec*** '********************************************** SUB DoubleWordCopy (FromSeg%, FromOff%, ToSeg%, ToOff%, NumDbls%) DEF SEG = VARSEG(DoublWordCopy.ASM$) CALL ABSOLUTE(BYVAL FromSeg%, BYVAL FromOff%, BYVAL ToSeg%, BYVAL ToOff%, BYVAL NumDbls%, SADD(DoubleWordCopy.ASM$)) DEF SEG END SUB '**************************************** '*** FillChar() *** by Jonathan Leger *** '**************************************** '*** Fills DestSeg%:DestOff% with the *** '*** Value% bytes% times. On this CPU*** '*** [486dx2/66] it averaged 5mb/sec. *** '**************************************** SUB FillChar (DestSeg%, DestOff%, Value%, bytes%) DEF SEG = VARSEG(FillChar.ASM$) CALL ABSOLUTE(BYVAL DestSeg%, BYVAL DestOff%, BYVAL Value%, BYVAL bytes%, SADD(FillChar.ASM$)) DEF SEG END SUB '***************************************** '*** FillDoubleWord() *** by Jon Leger *** '***************************************** '*** Fills DestSeg%:DestOff% with the *** '*** Value1% and Value2% [4 bytes] *** '*** NumDbls% times. *** '*** my 486dx2/66 it filled 5mb/sec. *** '***************************************** '*** NOTE: To calculate the two values *** '*** into one integer (if you want to *** '*** fill the screen) use this formula:*** '*** Value%=HEX$(byt1%) OR HEX$(byt2%) *** '*** Where byt1% & byt2% are values of *** '*** 0-255. Do this for Value1% and *** '*** Value2%. *** '***************************************** SUB FillDoubleWord (DestSeg%, DestOff%, Value1%, Value2%, NumDbls%) DEF SEG = VARSEG(FillDoubleWord.ASM$) CALL ABSOLUTE(BYVAL DestSeg%, BYVAL DestOff%, BYVAL Value1%, BYVAL Value2%, BYVAL NumDbls%, SADD(FillDoubleWord.ASM$)) DEF SEG END SUB '***************************************** '*** FillWord() *** by Jonathan Leger *** '***************************************** '*** Fills DestSeg%:DestOff% with the *** '*** Value% [2 bytes] NumWrds% times. *** '*** My 486dx2/66 filled 10mb/sec. *** '***************************************** '*** NOTE: To calculate the two values *** '*** into one integer (if you want to *** '*** fill the screen) use this formula:*** '*** Value%=HEX$(byt1%) OR HEX$(byt2%) *** '*** Where byt1% & byt2% are values of *** '*** 0-255. *** '***************************************** SUB FillWord (DestSeg%, DestOff%, Value%, NumWords%) DEF SEG = VARSEG(FillWord.ASM$) CALL ABSOLUTE(BYVAL DestSeg%, BYVAL DestOff%, BYVAL Value%, BYVAL NumWords%, SADD(FillWord.ASM$)) DEF SEG END SUB '********************************************************************* '*** Formatted and Assembled by Jon's Sanzy QBASIC Assembler v1.1! *** '********************************************************************* SUB InitASM FillChar.ASM$ = "" FillChar.ASM$ = FillChar.ASM$ + CHR$(&H55) 'PUSH BP FillChar.ASM$ = FillChar.ASM$ + CHR$(&H89) + CHR$(&HE5) 'MOV BP,SP FillChar.ASM$ = FillChar.ASM$ + CHR$(&H8E) + CHR$(&H46) + CHR$(&HC) 'MOV ES,[BP+0C] FillChar.ASM$ = FillChar.ASM$ + CHR$(&H8B) + CHR$(&H7E) + CHR$(&HA) 'MOV DI,[BP+0A] FillChar.ASM$ = FillChar.ASM$ + CHR$(&H8B) + CHR$(&H4E) + CHR$(&H6) 'MOV CX,[BP+06] FillChar.ASM$ = FillChar.ASM$ + CHR$(&H8B) + CHR$(&H46) + CHR$(&H8) 'MOV AX,[BP+08] FillChar.ASM$ = FillChar.ASM$ + CHR$(&HF3) 'REPZ FillChar.ASM$ = FillChar.ASM$ + CHR$(&HAA) 'STOSB FillChar.ASM$ = FillChar.ASM$ + CHR$(&H5D) 'POP BP FillChar.ASM$ = FillChar.ASM$ + CHR$(&HCB) 'RETF FillWord.ASM$ = "" FillWord.ASM$ = FillWord.ASM$ + CHR$(&H55) 'PUSH BP FillWord.ASM$ = FillWord.ASM$ + CHR$(&H89) + CHR$(&HE5) 'MOV BP,SP FillWord.ASM$ = FillWord.ASM$ + CHR$(&H8E) + CHR$(&H46) + CHR$(&HC) 'MOV ES,[BP+0C] FillWord.ASM$ = FillWord.ASM$ + CHR$(&H8B) + CHR$(&H7E) + CHR$(&HA) 'MOV DI,[BP+0A] FillWord.ASM$ = FillWord.ASM$ + CHR$(&H8B) + CHR$(&H4E) + CHR$(&H6) 'MOV CX,[BP+06] FillWord.ASM$ = FillWord.ASM$ + CHR$(&H8B) + CHR$(&H46) + CHR$(&H8) 'MOV AX,[BP+08] FillWord.ASM$ = FillWord.ASM$ + CHR$(&HF3) 'REPZ FillWord.ASM$ = FillWord.ASM$ + CHR$(&HAB) 'STOSW FillWord.ASM$ = FillWord.ASM$ + CHR$(&H5D) 'POP BP FillWord.ASM$ = FillWord.ASM$ + CHR$(&HCB) 'RETF FillDoubleWord.ASM$ = "" FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&H55) 'PUSH BP FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&H89) + CHR$(&HE5)'MOV BP,SP FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&H8E) + CHR$(&H46) + CHR$(&HE) 'MOV ES,[BP+0E] FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&H8B) + CHR$(&H7E) + CHR$(&HC) 'MOV DI,[BP+0C] FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&H8B) + CHR$(&H4E) + CHR$(&H0) 'MOV CX,[BP+00] FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&H66) + CHR$(&H8B) + CHR$(&H46) + CHR$(&H8)'MOV EAX,[BP+06] FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&HF3) 'REPZ FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&H66) + CHR$(&HAB)'STOSD FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&H5D) 'POP BP FillDoubleWord.ASM$ = FillDoubleWord.ASM$ + CHR$(&HCB) 'RETF MemCopy.ASM$ = "" MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H55) 'PUSH BP MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H89) + CHR$(&HE5) 'MOV BP,SP MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H1E) 'PUSH DS MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H8E) + CHR$(&H46) + CHR$(&HA) 'MOV ES,[BP+0A] MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H8B) + CHR$(&H7E) + CHR$(&H8) 'MOV DI,[BP+08] MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H8E) + CHR$(&H5E) + CHR$(&HE) 'MOV DS,[BP+0E] MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H8B) + CHR$(&H76) + CHR$(&HC) 'MOV SI,[BP+0C] MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H8B) + CHR$(&H4E) + CHR$(&H0) 'MOV CX,[BP+00] MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&HF3) 'REPZ MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&HA4) 'MOVSB MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H1F) 'POP DS MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&H5D) 'POP BP MemCopy.ASM$ = MemCopy.ASM$ + CHR$(&HCB) 'RETF WordCopy.ASM$ = "" WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H55) 'PUSH BP WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H89) + CHR$(&HE5) 'MOV BP,SP WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H1E) 'PUSH DS WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H8E) + CHR$(&H46) + CHR$(&HA) 'MOV ES,[BP+0A] WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H8B) + CHR$(&H7E) + CHR$(&H8) 'MOV DI,[BP+08] WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H8E) + CHR$(&H5E) + CHR$(&HE) 'MOV DS,[BP+0E] WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H8B) + CHR$(&H76) + CHR$(&HC) 'MOV SI,[BP+0C] WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H8B) + CHR$(&H4E) + CHR$(&H0) 'MOV CX,[BP+00] WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&HF3) 'REPZ WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&HA5) 'MOVSW WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H1F) 'POP DS WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&H5D) 'POP BP WordCopy.ASM$ = WordCopy.ASM$ + CHR$(&HCB) 'RETF DoubleWordCopy.ASM$ = "" DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H55) 'PUSH BP DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H89) + CHR$(&HE5)'MOV BP,SP DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H1E) 'PUSH DS DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H8E) + CHR$(&H46) + CHR$(&HA) 'MOV ES,[BP+0A] DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H8B) + CHR$(&H7E) + CHR$(&H8) 'MOV DI,[BP+08] DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H8E) + CHR$(&H5E) + CHR$(&HE) 'MOV DS,[BP+0E] DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H8B) + CHR$(&H76) + CHR$(&HC) 'MOV SI,[BP+0C] DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H8B) + CHR$(&H4E) + CHR$(&H6) 'MOV CX,[BP+06] DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&HF3) 'REPZ DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H66) + CHR$(&HA5)'MOVSD DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H1F) 'POP DS DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&H5D) 'POP BP DoubleWordCopy.ASM$ = DoubleWordCopy.ASM$ + CHR$(&HCB) 'RETF END SUB '********************************************** '*** MemCopy() *** by Jonathan Leger *** '********************************************** '*** Copies the specified number bytes from *** '*** the location FromSeg%:FromOffset% to *** '*** ToSeg%:ToOff%. On my 486dx2/66, I get *** '*** about 10mb/sec (which is faster than *** '*** WordCopy()--that surprised me--but its *** '*** considerably slower than DoubleWordCopy*** '*** [which averaged about 12mb/sec]. *** '********************************************** SUB MemCopy (FromSeg%, fromoffset%, ToSeg%, tooffset%, bytes%) DEF SEG = VARSEG(MemCopy.ASM) CALL ABSOLUTE(BYVAL FromSeg%, BYVAL fromoffset%, BYVAL ToSeg%, BYVAL tooffset%, BYVAL bytes%, SADD(MemCopy.ASM$)) DEF SEG END SUB '********************************************** '*** WordCopy() *** by Jonathan Leger *** '********************************************** '*** Copies the specified number of 2 byte *** '*** [One Word] blocks from the location *** '*** FromSeg%:FromOff% to ToSeg%:ToOff%. *** '*** On my 486dx2/66, it does about 8mb/sec *** '********************************************** SUB WordCopy (FromSeg%, FromOff%, ToSeg%, ToOff%, NumWrds%) DEF SEG = VARSEG(WordCopy.ASM$) CALL ABSOLUTE(BYVAL FromSeg%, BYVAL FromOff%, BYVAL ToSeg%, BYVAL ToOff%, BYVAL NumWrds%, SADD(WordCopy.ASM$)) DEF SEG END SUB