'===========================================================================
' 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
