Programming:Filling memory with a byte

From CPCWiki - THE Amstrad CPC encyclopedia!
Revision as of 23:29, 12 December 2012 by Db6128 (Talk | contribs) (adding SP-based method)

Jump to: navigation, search

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