each DMA transfer must be programed so you need to set some I/O registers of the DMA chip like:
BYTE DMA mode
WORD source address
WORD destination address
WORD block size
These are usually send by 8bit I/O requiring at least 1 instruction per 8 bit value but usually more depending on the DMA chip interconnection to computer and interface.
Now if the duration of this programming code and transfer is longer than CPU transfer you got your threshold. On Z80 you can use LDIR
where you also need set up source/destination and code block. So the programming part is not that much different. But if the DMA chip is after some interfaces like i8255
than it requires much more code to program ... And your question starts to be a valid one.
To ease this up DMA chips usually provide command que which means you can program more DMA transfers ahead ...
You are still missing one very important point which makes DMA invaluable for some applications and that is that during the DMA transfer on some platforms the CPU runs too and can do stuff that would not be possible otherwise (but you need to take contention into account if present).
for example of DMA chips usage on 8bit computers see:
Anyway to answer your question you would need to specify the architecture more closely. Let us consider 3.547MHz Z80 CPU (ZX128+ with DATAGEAR which is Z8410 based):
opc T0 T1 MC1 MC2 MC3 MC4 MC5 MC6 MC7 mnemonic
EDB0 21 16 M1R 4 M1R 4 MRD 3 MWR 5 NON 5 ... 0 ... 0 LDIR
so the theoretical transfer rate on CPU (without contention) is
3 547 000 / 21 = 168904 Byte/s = 164.9 KByte/s
It is a shame Zilog encoded the instruction under 0xED
prefix without it would be 4T
faster leading to 208647 Byte/s
.
The 3.547MHz Z8410 DMA chip has measured transfer rate ~865.6 kB/s
which is ~5.25
times faster.
So just compare programing code on CPU and DMA and the duration difference must be shorter than Time boost gained by the DMA.
This is Z80 code for DMA doing the same as LDIR
taken from YourSpectrum #04 January 1998:
org 45000
ld hl,50000 ; source address
ld (source),hl
ld hl,6911 ; block size
ld (len),hl
ld hl,16384 ; destination address
ld (dest),hl
ld hl,dma
ld b,length ; size of DMA command stream
ld c,11
otir
ret
dma: defb #C3,#C7,#CB,#7D
source:defw 0 ;source address
len: defw 0 ;length of data to be transferred
defb #14,#10,#C0,#AD
dest: defw 0 ; destination address
defb #92,#CF,#B3,#87
length equ $-dma
As you can see you can hardcode the stuff into 18 byte defb
array:
dma:ld hl,cmd ; 10T address of stored command stream
ld b,len ; 7T size of stored command stream
ld c,11 ; 7T DATAGEAR port
otir ;373T = 17*21 + 16
ret ; 10T
cmd:defb #C3,#C7,#CB,#7D
defw source_address,block_size
defb #14,#10,#C0,#AD
defw destination_address
defb #92,#CF,#B3,#87
len equ $-dma
Here the same on Z80 only:
cpu:ld hl,50000 ; 10T source address
ld bc,6911 ; 10T block size
ld de,16384 ; 10T destination address
ldir
ret ; 10T
Now just compare the timings of the code without transfer:
DMA: +407T
CPU: - 40T
----------
diff: 367T
dt = 367T / 3547000Hz = 0.00010346771919932337186354665914858 s
Now we need to compute the transfer size which will have ~same dt
time boost
x / cpu_rate = x / dma_rate + dt
x * dma_rate = x * cpu_rate + dt * cpu_rate * dma_rate
x * dma_rate - x * cpu_rate = dt * cpu_rate * dma_rate
x * (dma_rate - cpu_rate) = dt * cpu_rate * dma_rate
x = dt * cpu_rate * dma_rate / (dma_rate - cpu_rate)
x = 0.00010346771919932337186354665914858 * 168904 * 886350 / (886350 - 168904)
x = 15489951.555342542994079503806033 / 717446
x = ~21.59 Byte
So the theoretical transfer block size threshold is 22 Byte. Btw the ld b,N
and ld c,N
can be optimized into ld bc,NN
which is 4T
shorter and it would a bit change the numbers ... also ldir
can be unrolled into n
times ldi
which leads to cpu_rate = 221687.5 Byte/s
but that is impractical for larger blocks (unless looped).
[Edit1] more optimized code
DMA:
dma:ld hl,cmd ; 10T address of stored command stream
ld c,11 ; 7T DATAGEAR port
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
outi ; 16T
ret ; 10T
cmd:defb #C3,#C7,#CB,#7D
defw source_address,block_size
defb #14,#10,#C0,#AD
defw destination_address
defb #92,#CF,#B3,#87
CPU:
cpu:ld hl,50000 ; 10T source address
ld de,16384 ; 10T destination address
ldi ; 16T
ldi ; 16T
ldi ; 16T
...
ldi ; 16T
ldi ; 16T
ldi ; 16T
ret ; 10T
times equation:
DMA: +315T
CPU: - 30T
----------
diff: 285T
dt = 285T / 3547000Hz = 0.000080349591203834226106568931491401 s
x = dt * cpu_rate * dma_rate / (dma_rate - cpu_rate)
x = 0.000080349591203834226106568931491401 * 221687.5 * 886350 / (886350 - 221687.5)
x = 23.75357
So the theoretical threshold for optimized transfers is 24
Bytes.