Difference between revisions of "Programming:Filling memory with a byte"

From CPCWiki - THE Amstrad CPC encyclopedia!
Jump to: navigation, search
(adding SP-based method)
Line 1: Line 1:
 +
==Using LDIR==
 +
 
From the '''The Unofficial Amstrad WWW Resource'''
 
From the '''The Unofficial Amstrad WWW Resource'''
  
Line 59: Line 61:
 
;;
 
;;
 
;; etc....
 
;; etc....
 +
</pre>
 +
 +
==Using the stack==
 +
 +
This method write bytes at a considerably faster rate by exploiting the speed of the stack pointer (SP) moving through RAM and its 2-byte steps. It is especially good for very rapidly clearing the screen.--[[User:Db6128|Db6128]] ([[User talk:Db6128|talk]]) 06:29, 13 December 2012 (EET)
 +
 +
<pre>
 +
; Save the stack pointer
 +
ld (SAVE_SP),sp        ; Only remove if you're sure you don't need the stack
 +
ld sp,FINAL_ADDRESS+1  ; e.g. to fill from &C000 to &FFFF (&4000 bytes), set SP to &FFFF+1 = &0000
 +
 +
; Define the region of RAM to be filled
 +
ld h,YOUR_BYTE        ; Use HL or whichever 16-bit register you prefer
 +
ld l,YOUR_BYTE        ; For 0, you can save 1 byte of memory by instead using XOR A:LD H,A:LD L,A
 +
ld de,LENGTH_TO_FILL/2 ; divided by 2 because DE is 2 bytes wide and PUSH pushes both
 +
 +
; Set up a fast 16-bit loop counter
 +
dec de                ; This method takes advantage of the fact that DJNZ leaves B as 0, which subsequent DJNZs see as 256
 +
ld b,e                ; B = (length/2) MOD 256, so 0 = a 512-byte block
 +
inc b                  ; D = the number of 512-byte blocks to write, or just = 1 if the length is <512
 +
inc d                  ; Of course, if you know the length ahead of run-time, you can set B and D directly in your ASM
 +
 +
; Fill the memory
 +
        PUSHLOOP:
 +
push hl                ; Writes DE to (SP-2) and DECs SP by 2.
 +
                      ; For even more speed, use multiple PUSH HLs in a row (I like 8, = &10 bytes) and adjust counters to match
 +
djnz PUSHLOOP
 +
dec d
 +
jr nz,PUSHLOOP
 +
 +
; Restore the stack pointer
 +
        SAVE_SP equ $+1
 +
ld SP,&9999            ; &9999 will be replaced by the actual previous value
 
</pre>
 
</pre>
  
 
[[Category:Programming]]
 
[[Category:Programming]]

Revision as of 23:29, 12 December 2012

Using LDIR

From the The Unofficial Amstrad WWW Resource

;; This code snippet will show one method to fill a block
;; of memory with a single data byte using Z80 assembly
;; language.

;;--------------------------------------------------

;; HL = start address of block
ld hl,&4000

;; DE = HL + 1
ld e,l
ld d,h
inc de

;; initialise first byte of block
;; with data byte (&00)
ld (hl),&00
	
;; BC = length of block in bytes
;; HL+BC-1 = end address of block

ld bc,&4000	

;; fill memory
ldir

;;--------------------------------------------------


;; For each iteration of the LDIR command:
;;
;; 1. This command will copy the byte from the memory 
;; address pointed to by HL to the memory address pointed to by DE.
;; i.e. (DE) = (HL).
;; 2. Then HL and DE will be incremented. BC will be decremented.
;;
;;
;; For the first byte:
;; 
;; HL = start
;; DE = start+1
;; BC = length
;; (HL)=0
;; 
;; For the second byte:
;; 
;; HL = start + 1 (initialised to 0 by the previous iteration)
;; DE = start + 2
;; BC = length - 1
;;
;; For the third byte:
;;
;; HL = start + 2 (initialised to 0 by the previous iteration)
;; DE = start + 3
;; BC = length - 2
;;
;; etc....

Using the stack

This method write bytes at a considerably faster rate by exploiting the speed of the stack pointer (SP) moving through RAM and its 2-byte steps. It is especially good for very rapidly clearing the screen.--Db6128 (talk) 06:29, 13 December 2012 (EET)

; Save the stack pointer
ld (SAVE_SP),sp        ; Only remove if you're sure you don't need the stack
ld sp,FINAL_ADDRESS+1  ; e.g. to fill from &C000 to &FFFF (&4000 bytes), set SP to &FFFF+1 = &0000

; Define the region of RAM to be filled
ld h,YOUR_BYTE         ; Use HL or whichever 16-bit register you prefer
ld l,YOUR_BYTE         ; For 0, you can save 1 byte of memory by instead using XOR A:LD H,A:LD L,A
ld de,LENGTH_TO_FILL/2 ; divided by 2 because DE is 2 bytes wide and PUSH pushes both

; Set up a fast 16-bit loop counter
dec de                 ; This method takes advantage of the fact that DJNZ leaves B as 0, which subsequent DJNZs see as 256
ld b,e                 ; B = (length/2) MOD 256, so 0 = a 512-byte block
inc b                  ; D = the number of 512-byte blocks to write, or just = 1 if the length is <512
inc d                  ; Of course, if you know the length ahead of run-time, you can set B and D directly in your ASM

; Fill the memory
        PUSHLOOP:
push hl                ; Writes DE to (SP-2) and DECs SP by 2.
                       ; For even more speed, use multiple PUSH HLs in a row (I like 8, = &10 bytes) and adjust counters to match
djnz PUSHLOOP
dec d
jr nz,PUSHLOOP

; Restore the stack pointer
        SAVE_SP equ $+1
ld SP,&9999            ; &9999 will be replaced by the actual previous value