FAST MULTILOADER
ZXNet echo conference «real.speccy»
From Aleksey Malov → To All 29 May 2001
I present the subject to the public. It has the following advantages:
1. Has 3 operating modes:
a) IM 2 loading. Operating speed from 2 to 10 kilobytes per second. When
the disc is removed from the drive, the music continues to play. Since the music
plays at interruptions, there can be no howls by definition.
b) FAST loading. Music is played after the 2nd, 3rd, 5th, 6th and 8th sectors.
Similar to the loader in Refresh. Reading speed is 20 kilobytes per second. When
there is no disc in the drive, the music does not play, or rather, a howl is heard from AY. Music
is not played quite evenly.
c) #3d13 loading. Sectors are read in several portions (for example, 8
sectors). After each portion, a halt is made and one quantum of sound is played. This mode is intended for reading from a ramdisk or a screw
(all that remains is to select the size of one portion so that it can be
read in one interruption), supported through #3d13. When reading from a ramdisk (a block of 8 sectors can be read per interrupt), the speed
reaches 50*8*256 = 100 kilobytes per second. In this mode, you can read from
conventional disk drives, but normal music playback is out of the question. There will be something like a loader in Eye ache-2.
2. The previous version of this loader worked well in our demo
TryptomineDream. It seemed to work fine for everyone. Works well under
emulators.
A couple of tips:
When using IM 2 loading mode, if you need to read several
short files in a row, it is better to read in one large block, and then scatter
file fragments manually.
When using IM 2 loading, you must specify the lag parameter exactly. It can
be defined at least like this:
1. Determine the number of the first sector on the lower and upper track, for example using the "read index" command. the lag parameter is found as the difference between the numbers
of even and odd tracks.
2. Ask the user to enter this value manually.
If the lag parameter is specified incorrectly, the speed may drop by a factor of 10.
In general, if you have problems using the loader, please contact us.
To Kirill Frolov: If you have not abandoned your FAQ server (or whatever it is),
you can place this loader here. So that people can use it if
necessary.
So, here is the promised loader:
Yes, by the way, the source is in ZXASM3.10 format. Of all the features of this assembler
only conditional compilation directives are used. But there are few of them and they are intuitively understandable. In general, this feature is very useful at the debugging stage.
If someone is confused by the presence of labels longer than 7 characters, then that’s their problem. I'm not
going to limit myself to short label names.
The size is quite large, but ifIf someone doesn't need one of the modes, you can
just remove it. In general, the source code is intended for fairly experienced
coders, so they can figure it out themselves.
═══════════════════ m_load .asm ══════════════════
; Progressive multiloader
; (c) 2000-2001 Vivid^Brainwave/X-Project
; (c) 2000 Tigrr^Brainwave/X-Project
; When used, reference to the original authors
; welcome.
; For those who do not understand: the original authors are
; Vivid^Brainwave/X-Project and
; Tigrr^Brainwave/X-Project
FASTLOAD EQU 0;LOADING AT PROHIBITED
;INTERRUPTS, AS IN
;REFRESH,IF 1,ELSE
;MUSIC PLAYED ON
;INTERRUPTS (IM2-LOADER)
L3d13 equ 0 ;LOADING VIA #3D13,
;IF 1, ELSE
;MULTILOADER
;IS ONLY VALUE
;IF FASTLOAD=0
test equ 1 ;IF=1, TO ALL SECTORS
;LOADING TO ADDRESS #4000
;ELSE WHERE YOU NEED
;AND ALSO A TABLE
;SECTORS FOR IM2 LOADER
;WILL BE LOCATED IN
;ATTRIBUTES AREA FOR
;VISUALIZATION OF THE PROCESS
;LOADING
GRP3D13 EQU 8 ;NUMBER OF SECTORS, WHICH
;READ THROUGH #3D13
;BEFORE PLAYING
;MUSON
;FORTHE RAM DISK IS ENOUGH 8
;FOR A SCREW - I DON’T KNOW
;FOR A REGULAR DISK DRIVE
;CAN BE READED IN 4-8
;SECTORS, TRUTH MUSIC
;WILL SLOCK IN
;ANY CASE
if test
;TABLE SECTORS FOR IM 2 LOADER
;MUST SIT AT ROUND HEX ADDRESS
;LENGTH - 256 BYTES
sectb equ #5a00
else
sectb equ #ff00
endif
inttab equ #be00;intt table
intsp equ #bfbf;STACK FOR PROCEDURE
;INTERRUPTS
muzon equ #c000;INITIALIZATION ADDRESS
;MUZONA
MUZPLAY EQU #C005;PLAYING ADDRESS
;MUZONA
;THE FOLLOWING 2 PARAMETERS ARE ACTUAL ONLY
;FOR IM 2 LOADER
popytki equ 3 ;NUMBER OF ATTEMPTS
;READING ONE
;SECTOR, AFTER
;AFTER ALL ATTEMPTS
;HAVE EXHAUSTED, THERE WILL BE -
;READING
;SECTORS WILL BE PRODUCED FROM THE NEXT
;TRACK
lag equ -2 ;SHIFTING SECTORS
;ON THE ODD SIDE
; OF THE DISK COMPARED TO
;EVEN. THIS INFORMATION
;MUST BE INDICATED
;EXACTLY, OTHERWISE THE SPEED
;READING WILL BE TERRIBLE
;SLOW.
;For example, IF THE LOCATION OF SECTORS ON
;0 TRACK IS:
;0123456789ABCDEF
;AND ON TRACK 1:
;EF0123456789ABCD
;THEN lag SHOULD BE
;EQUAL -2 (0-#0E=-2)
org #6000
;test procedure
ENT $
;FILLED THE SCREEN WITH VERTICAL STRIPES
ld hl,#4000
ld DE,#4001
ld bc,6143
ld (hl),#aa
ldir
;THROWED THE MUSON TO ITS RIGHTFUL PLACE
ld hl,muz
ld de,muzon
ld bc,emuz-muz
ldir
;INITIALIZED HIM
call muzon
;TOOK THE DISK DRIVE NUMBER FROM SYSTEM
;VARIABLES
ld a,(23798);number
;disk drive
ld (drvnum),a
ld c,1 ;initialize
call #3d13;disk drive
LD C,#18
CALL #3D13
;WILL READ FROM 0 SECTOR 0 TRACKS
ld de,#0000
ld (#5cf4),de
;TURN ON IM 2
call int_on
;REASE THE INT COUNTER (FOR MEASUREMENT
;READING SPEED)
ld hl,0
ld (count),hl
;READ 10 TIMES BY #E0 SECTORS
;ATTENTION! THE CONSTANT test MUST BE
EQUAL TO 1 TO READ ALLHAPPENED
;AT ADDRESS #4000, OTHERWISE THE LOADER WILL OVER
;THESELF WITH THE INFORMATION READ.
ld b,10
suxx00 push bc
;READ ADDRESS IN hl
ld hl,#4000
;NUMBER OF SECTORS IN b
ld b,#E0
;TRACK B d, SECTOR B e
LD DE,(#5CF4)
IF FASTLOAD
call DI_LOAD
ELSE
CALL loader
ENDIF
pop bc
djnz suxx00
;TURN OFF im 2
call int_off
;turn off Mouzon
call muzon
ei
LD HL,#2758;correct
EXX ;return to BASIC
ld bc,(count);int counter
ret
;int procedure
inter ex (sp),hl
ld (intjp+1),hl
ex (sp),hl
inc sp
inc sp
ld (intex+1),sp
ld sp,intsp
push af
push bc
push de
push hl
exx
ex af,af'
push af
push bc
push de
push hl
push ix
push iy
;Body ISR
call MUZPLAY;play music
MUZAKA EQU $-2
ld hl,#2121
count equ $-2;int count
inc hl
ld (count),hl
;exit ISR EITHER TO TRDOS ORВ
;ОЗУ
ld a,(intjp+2)
cp #40
jr c,zabij
inex pop iy
pop ix
pop hl
pop de
pop bc
pop af
exx
ex af,af'
pop hl
pop de
pop bc
pop af
intex ld sp,#3131
ei
intjp jp #c3c3
zabij ;мы в трдосе
ld hl,(intex+1)
dec hl
dec hl
ld (intex+1),hl
ld hl,#3d2f
ld (intjp+1),hl
jr inex
;процедура включения int'ов
int_on di
ld hl,inttab
ld de,inttab+1
ld b,e
ld c,l
ld a,h
ld i,a
ld (hl),inttab/256+1
ldir
ld a,#c3
ld hl,inter
ld (inttab/256+inttab+257),a
ld (inttab/256+inttab+258),hl
im 2
ei
RETADR ret
;ВЫКЛЮЧАЕМ ИHТЫ
int_off di
ld a,63
ld i,a
im 1
ei
ret
;-------------------------------------
;ТАБЛИЦА, ПОКАЗЫВАЮЩАЯ, HА СКОЛЬКО
;СЕКТОРОВ HУЖHО СМЕСТИТЬСЯ ПРИ ПЕРЕМЕ-
;ЩЕHИИ ГОЛОВКИ HА 1-8 ДОРОЖЕК
;HАПРЯМУЮ ЗАВИСИТ ОТ СМЕЩЕHИЯSECTORS
;ON TWO PHYSICAL TRACKS
;WHEN MOving FORWARD
sectors db -2,-1,0,1,2,3,4,5,6,7,8
;WHEN MOving BACK
sectorsb db T4: ABCDEF0..
;AND MOVE THE HEAD TO THE NEIGHBORING TRACK
;BY 2 SECTORS THE TABLES ARE THE FOLLOWING:
;WHEN MOving FORWARD
;sectors db -2,-1,0,1,2,3,4,5,6,7,8
;WHEN MOving BACK
;sectorsb db 4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8
;
;-------------------------------------
;reading from disk via #3d13
ram_dsk ld (#5cf4),de
push hl
ld hl,(#5cc2);break protect
ld hl,#c9f1
ld (#5cc2),hl
ex (sp),hl
dermo push bc
EI
halt
di
im 1
push hl
ld de,(#5cf4)
ld C,5
;READ MIN(GRP3D13,B) SECTORS
LD A,B
CP GRP3D13
JR C,$+4
LD B,GRP3D13
if test
ld hl,#4000
endif
PUSH BC
call #3d13
POP BC
pop hl
ld a,h
add a,B
ld h,a
im 2
ei
pop bc
LD A,B
INCA
SUB GRP3D13
DEC A
LD B,A
JR NC,dermo
pop hl
ld (#5cc2),hl
im 2
ei
ret
;IM 2 LOADER
;(C)2000-2001 VIVID & TIGGR FROM BW/XPJ
;hl - read address
;de - track(0...255) & sector(0...15)
;b - number of sectors to read
;VARIABLE ramld EQUALS 0 WHEN READING
;THE VIA #3D2F, AND NOT 0 WHEN READING
;THE VIA #3D13 (FOR EXAMPLE FROM A SCREW OR
;RAMDISC)
loader ld a,L3d13
ramld equ $-1
or a
jr nz,ram_dsk
EI
ld a,(#5cd6)
push af
ld (readadr),hl
ld (trsec),de
ld (#5cf4),de
ld hl,(#5cc2);break protect
ld (runfile+1),hl
ld hl,#c9f1
ld (#5cc2),hl
push bc
push de
call posit ;track d
pop de
pop bc
;CREATE SECTOR TABLE
ld hl,sectb
xor a
mksectb ld (hl),a
inc l
jr nz,mksectb
ld a,d
rra
sbc a,a
and #10
or e
ld l,a
ld (startsec),a
and #ef
;NUMBER OF THE SECTOR UNDER THE HEAD
ld(second) (de),a
jr m2
m1 ld a,l
and 31
jr nz,m0
ld a,c
ld (de),a
inc de
jr m00
;----------------------------------------
m2 ld a,e
sub tracktb\256
ld (hitrk),a
inc a
ld (osttracks),a
xor a
ld (direct),a
ld (lowtrk),a
ld (curtrk),a
;----------------------------------------
load0 ld hl,sectb
secunh equ $-2
;search for the nearest uncounted sector
;in the table
ld a,l
and #e0
ld d,a
sseek ld a,(hl)
ld e,l
or a
jr nz,found
ld a,l
add a,lag
lagtrack equ $-1
and #0f
or d
or #10;up side
ld l,a
ld a,(hl)
or a
jr nz,found
ld a,e
inc a
and #0f
or d
ld l,a
jr sseek
found ld a,e
inc a
and #0f
or d
ld (secunh),a
ld a,l
ld (nowread),a
;determine the side
and 16
or 0
drvnum equ $-1
or #2c
xor #10
call outff
;determine the sector number to read
ld a,l
and #0F
ld e,a
;determine the read address
ld a,l
sub 0
startsec equ $-1
ld hl,#2121
readadr equ $-2
add a,h
ld h,a
ld a,e
if test
ld hl,#4000
endif
call readsec;read sector a
;from current track
;cf=1 if read error
ld hl,sectb
nowread equ $-2
jp nc,readok
;read error:
dec (hl)
jr nz,load0;still left
;attempts
;reinitialize the counters of uncounted
;sectors on this track.
ld a,(retrys)
ld (hl),a
ld e,a
ld a,l
and #e0
ld l,a
xor a
ld b,32
reinit cp (hl)
jrz,dontinit
ld (hl),e
dontinit inc l
djnz reinit
;how many unread tracks
ld a,0
osttracks equ $-1;tracks left.
dec a ;last?
jr z,load0 ;nowhere further
;look where to move.
polzem ld a,255
direct equ $-1
or A
ld a,0
curtrk equ $-1
ld b,a
jr z,forward
cp 0
lowtrk equ $-1
jr nz,nchdir
xor a
ld (direct),a
ld a,b
jr forward1
nchdir
;looking for the nearest track in the direction of decreasing
;decrease in track numbers
add a,tracktb\256
ld l,a
adc a,tracktb/256
sub l
ld h,a
xor a
ld c,a
seeklow dec hl
dec b
inc c
cp (hl)
jr z,seeklow
ld a,b
ld (curtrk),a
;c-offset
ld a,c
add a,sectorsb-1
ld l,a
adc a,0+(sectorsb-1)/256
sub l
ld h,a
ld a,b
rrca
rrca
rrca
ld e,a
ld a,(secunh)
ADD A,(HL)
and15
add a,e
ld (secunh),a
nostbw ld a,b
add a,a
ld de,#1111
trsec equ $-2
add a,d
ld d,a
call posit
jp load0
forward cp 0
hitrk equ $-1
jr nz,forward1
ld a,#ff
ld (direct),a
ld a,b
jr nchdir
forward1 add a,tracktb\256
ld l,a
adc a,tracktb/256
sub l
ld h,a
xor a
ld c,a
seekhi inc hl
inc b
inc c
cp (hl)
jr z,seekhi
ld a,b
ld (curtrk),a
;c-offset
ld a,c
add a,sectors-1
ld l,a
adc a,0+(sectors-1)/256
sub l
ld h,a
ld a,b
rrca
rrca
rrca
ld e,a
ld a,(secunh)
add a,(hl)
and 15
add a,e
ld (secunh),a
nostf ld a,(trsec+1)
add a,b
add a,b
ld d,a
call posit
jp load0
;БУФФЕР ДЛЯ ХРАHЕHИЯ ЧИСЛА СЕКТОРОВ
;HА ФИЗИЧЕСКОЙ ДОРОЖКЕ
tracktbds 8
readok
;marked sector as read
ld (hl),0
;increase the current sector and track
ld hl,#5cf4
ld a,(hl)
inc a
and 15
ld (hl),a
inc hl
jr nz,$+3
inc (hl)
;reduce the number of sectors that
;need to be read from a given track
ld a,(curtrk)
ld b,a
add a,tracktb
ld l,a
adc a,tracktb/256
sub l
ld h,a
dec (hl)
jp nz,load0;read further
;checking whether the read
;track is the last
ex de,hl
ld hl,osttracks
dec (hl)
ex de,hl
jr z,konets;read
;completely
;compress the boundaries if necessary
ld a,(lowtrk)
cp b
jr nz,nosqueezelow
ld c,a
xor a
squeezel inc hl
inc c
inc b
cp (hl)
jr z,squeezel
ld a,b
ld (lowtrk),a
xor a
ld (direct),a
jp polzem
nosqueezelow
ld a,(hitrk)
cp b
jp nz,polzem
ld c,a
xor a
squeezeh dec hl
inc c
dec b
cp (hl)
jr z,squeezeh
ld a,b
ld (hitrk),a
ld a,#ff
ld (direct),a
jp polzem
konets pop af
ld (#5cd6),a
runfile ld hl,#2121
ld (#5cc2),hl
ret
;HL-ADDR
;DE-TRACK
;B-COUNT
DI_LOAD LD (CURTS),DE
LD (CURADR),HL
LD A,B
LD (CURLEN),A
LD HL,RETADR
LD (MUZAKA),HL
DI
ld a,(#5cd6)
push af
ld hl,(#5cc2);break protect
PUSH HL
ld hl,#c9f1
ld (#5cc2),hl
call posit ;track d
DI
LD HL,MTAB
LD A,(HL)
LD (MCOUNT),A
INC HL
LD (MPOS),HL
DIL1 LD HL,#2121
CURADR EQU $-2
LD DE,#1111
CURTS EQU $-2
LD A,(drvnum)
LD C,A
ld a,D
RRA
SBC A,A
CPL
AND #10
OR #2C
or C
DI
call outff
;определяем адрес чтения
ld a,E
AND #0F
if test
ld hl,#4000
endif
callreadsec;чтение сектора a
DI
JR C,CURTS
CALL CHECKM
LD HL,CURADR+1
INC (HL)
LD HL,(CURTS)
LD A,L
INC A
AND #0F
LD L,A
JR NZ,NONXTT
INC H
BIT 0,H
JR NZ,NONXTT
LD A,#3E
CURLEN EQU $-1
DEC A
JR Z,NONXTT
PUSH HL
EX DE,HL
CALL posit
DI
POP HL
NONXTT LD (#5CF4),HL
LD (CURTS),HL
LD HL,CURLEN
DEC (HL)
JR NZ,DIL1
POP HL
POP AF
LD (#5CC2),HL
LD (#5CD6),A
RET
CHECKM LD A,#3E
MCOUNT EQU $-1
DEC A
JR NZ,CHKM1
CALL muzon+5
LD HL,#2121
MPOS EQU $-2
LD A,(HL)
OR A
JR NZ,CHKM0
LD HL,MTAB
LD A,(HL)
CHKM0 INC HL
LD (MPOS),HL
CHKM1 LD (MCOUNT),A
RET
MTAB DB 2,1,2,1,2,0
;сброс ВГ93 (один раз для кривых тачек),
;или при первом обращении к данному
;драйву
posit ld a,#3e
or a
jr z,track
xor a;при следующемобращении
ld (posit+1),a
ld a,(drvnum)
or #3c
call outff
ld a,%00001000
call out1f
call gundos
track ld a,d
srl a
ld (pipisa),a
ld c,#7f
call outc
ld a,%00011000
call out1f
jr gundos
outff ld c,#ff
outc ld ix,#2a53
jr dos
stepbkw ld hl,pipisa
dec (hl)
ld a,%01111100
jr out1f
stepfw ld hl,pipisa
inc (hl)
ld a,%01011100
out1f ld ix,#2fc3
jr dos
gundos ld ix,#3ef5
dos push ix
jp #3d2f
deby db 1;нужно для опроса #1f
;читаем сектор с тек. дороги
readsec if 0
ld hl,0
aaaa equ $-2
inc hl
res 6,h
ld (aaaa),hl
ld a,(hl)
add a,a
ret
endif
ld (adres),hl
inc a
ld c,#5f;физ. номер сектора
call outc;в регистр сектора
xor a
ld (#5cd6),a
ld hl,retdos;действия для
push hl ;для контроля
ld hl,deby ;за
push hl ;subject
ld bc,#017f ;subject
ld hl,#2121
address equ $-2
ld ix,#2091
jr two
rights ld a,10
ld (#5cd8),a
ld de,0
pee equ $-1
ld ix,#2740
call dos
ld a,(#5ccd)
and %01111111
right z
ld a,(#5cd6)
neg
right
mouse insert "e:09m.C";имана
emuz ;“ теста
═════════════════════ ════════════════════
Bye, All.
WBR, Vivid^Brainwave of the X-Project association.