Difference between revisions of "Programming:Filling memory with a byte"
From CPCWiki - THE Amstrad CPC encyclopedia!
(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