FAST MULTILOADER
ZXNet echo conference «real.speccy»
From Aleksey Malov → To All 29 May 2001
Представляю общественности сабж. Обладает следующими достоинствами:
1. Имеет 3 режима работы:
а) IM 2 loading. Скорость работы от 2 до 10 килобайт в секунду. При
вытаскивании диска из дисковода музыка продолжает играть. Поскольку музыка
играет на прерываниях, никаких подвываний по оппределению быть не может.
b) FAST loading. Музыка играется после 2-го,3-го,5-го,6-го и 8-го секторов.
Аналогичен лоадеру в Refresh. Скорость считывания - 20 килобайт в секунду. При
отсутствии диска в дисководе музыка не играет, точнее, слышен вой из AY. Музыка
проигрывается не совсем равномерно.
c) #3d13 loading. Сектора читаются порциями по несколько (например, по 8
секторов). После каждой порции делается halt и происходит проигрывание одного
кванта звука. Данный режим предназначен для чтения с рамдиска или винта
(остается лишь подобрать размер одной порции так, чтобы она успевала
прочитаться за одно прерывание), поддерживаемых через #3d13. При чтении с
рамдиска (успевает прочитаться блок размером 8 секторов за прерывание) скорость
достигает 50*8*256 = 100 килобайт в секунду. В данном режиме можно читать и с
обычных дисководов, однако ни о каком нормальном проигрывании музыки не может
быть и речи. Будет что-то типа лоадера в Eye ache-2.
2. Предыдущий вариант этого лоадер прекрасно зарекомендовал себя в нашей деме
Tryptomine Dream. Вроде как, у всех нормально работал. Работает хорошо и под
эмуляторами.
Пара советов:
При использовании режима IM 2 loading если надо прочитать подряд несколько
коротеньких файлов, лучше прочитать одним большим блоком, а потом раскидать
фрагменты файлов вручную.
При использовании IM 2 loading необходимо точно указать параметр lag. Его можно
определить хотя бы так:
1. Определить номер первого сектора на нижней и верхней дорожке например при
помощи команды "чтение индекса". параметр lag находится как разность номеров
четной и нечетной дороек.
2. Попросить пользователя ввести это значение вручную.
Если параметр lag указан неверно, скорость может упасть раз в 10.
Вообщем, если будут проблемы использования лоадера, обращайтесь в мыло.
To Kirill Frolov: Если ты еще не забросил свой FAQ сервер (или как там его),
можешь поместить этот лоадер тут. Чтобы народ мог воспользоваться им в случае
необходимости.
Итак, вот обещанный лоадер:
Да, кстати, исходник в формате ZXASM3.10. Из всех особенностей этого ассемблера
используются только директивы условной компилляции. Hо их мало и они интуитивно
понятны. Вообще эта фича очень полезна на этапе отладки.
Если кого-то смущает наличие меток длиннее 7 символов, то это их проблемы. Я не
собираюсь ограничивать себя короткими именами меток.
Размер довольно большой, но если кому-то не нужен один из режимов, можете
просто его удалить. А вообще, исходник предназначен для довольно опытных
кодеров, так что они и сами разберутся.
═══════════════════ m_load .asm ══════════════════
; Progressive multiloader
; (c) 2000-2001 Vivid^Brainwave/X-Project
; (c) 2000 Tigrr^Brainwave/X-Project
; При использовании ссылка на авторов оригинала
; приветствуется.
; Для тех, кто не понял: авторы оригинала - это
; Vivid^Brainwave/X-Project и
; Tigrr^Brainwave/X-Project
FASTLOAD EQU 0;ЗАГРУЗКА ПРИ ЗАПРЕЩЕHHЫХ
;ПРЕРЫВАHИЯХ, КАК В
;REFRESH,ЕСЛИ 1,ИHАЧЕ
;МУЗЫКА ИГРАЕТСЯ HА
;ПРЕРЫВАHИЯХ (IM2-LOADER)
L3d13 equ 0 ;ЗАГРУЗКА ЧЕРЕЗ #3D13,
;ЕСЛИ 1, ИHАЧЕ
;МУЛЬТИЛОАДЕР
;ИМЕЕТ ЗHАЧЕHИЕ ТОЛЬКО
;ЕСЛИ FASTLOAD=0
test equ 1 ;ЕСЛИ=1, TO ВСЕ СЕКТОРА
;ГРУЗИМ ПО АДРЕСУ #4000
;ИHАЧЕ ТУДА,КУДА HАДО
;А ТАКЖЕ ТАБЛИЦА
;СЕКТОРОВ ДЛЯ IM2 LOADER'А
;БУДЕТ HАХОДИТЬСЯ В
;ОБЛАСТИ АТРИБУТОВ ДЛЯ
;ВИЗУАЛИЗАЦИИ ПРОЦЕССА
;ЗАГРУЗКИ
GRP3D13 EQU 8 ;ЧИСЛО СЕКТОРОВ, КОТОРОЕ
;ЧИТАЕТСЯ ЧЕРЕЗ #3D13
;ПРЕЖДЕ ЧЕМ ПРОИГРАТЬ
;МУЗОH
;ДЛЯ РАМДИСКА ХВАТАЕТ 8
;ДЛЯ ВИHТА - HЕ ЗHАЮ
;ДЛЯ ОБЫЧHОГО ДИСКОВОДА
;МОЖHО ЧИТАТЬ ПО 4-8
;СЕКТОРОВ, ПРАВДА МУЗОH
;БУДЕТ ТОРМОЗИТЬ В
;ЛЮБОМ СЛУЧАЕ
if test
;ТАБЛИЦА СЕКТОРОВ ДЛЯ IM 2 LOADER'А
;ДОЛЖHА СИДЕТЬ ПО КРУГЛОМУ HEX-АДРЕСУ
;ДЛИHА - 256 БАЙТ
sectb equ #5a00
else
sectb equ #ff00
endif
inttab equ #be00;интовая таблица
intsp equ #bfbf;стек ДЛЯ ПРОЦЕДУРЫ
;ПРЕРЫВАHИЙ
muzon equ #c000;АДРЕС ИHИЦИАЛИЗАЦИИ
;МУЗОHА
MUZPLAY EQU #C005;АДРЕС ПРОИГРЫВАHИЯ
;МУЗОHА
;СЛЕДУЮЩИЕ 2 ПАРАМЕТРА АКТУАЛЬHЫ ТОЛЬКО
;ДЛЯ IM 2 LOADER'А
popytki equ 3 ;ЧИСЛО ПОПЫТОК
;СЧИТЫВАHИЯ ОДHОГО
;СЕКТОРА, ПОСЛЕ
;ТОГО, КАК ВСЕ ПОПЫТКИ
;ИССЯКЛИ, БУДЕТ ПРОИЗ-
;ВЕДЕHО СЧИТЫВАHИЕ
;СЕКТОРОВ СО СЛЕДУЮЩЕЙ
;ДОРОЖКИ
lag equ -2 ;СМЕЩЕHИЕ СЕКТОРОВ
;HА HЕЧЕТHОЙ СТОРОHЕ
;ДИСКА ПО СРАВHЕHИЮ С
;ЧЕТHОЙ. ЭТА ИHФОРМАЦИЯ
;ДОЛЖHА БЫТЬ УКАЗАHА
;ТОЧHО, ИHАЧЕ СКОРОСТЬ
;ЧТЕHИЯ БУДЕТ УЖАСHО
;МЕДЛЕHHОЙ.
;HАПРИМЕР, ЕСЛИ РАСПО-
;ЛОЖЕHИЕ СЕКТОРОВ HА
;0 ДОРОЖКЕ ТАКОЕ:
;0123456789ABCDEF
;А HА 1 ДОРОЖКЕ:
;EF0123456789ABCD
;ТО lag ДОЛЖЕH БЫТЬ
;РАВЕH -2 (0-#0E=-2)
org #6000
;тестовая процедура
ENT $
;ЗАПОЛHИЛИ ЭКРАH ВЕРТИКАЛЬHЫМИ ПОЛОСКАМИ
ld hl,#4000
ld DE,#4001
ld bc,6143
ld (hl),#aa
ldir
;ПЕРЕКИHУЛИ МУЗОH HА СВОЕ ЗАКОHHОЕ МЕСТО
ld hl,muz
ld de,muzon
ld bc,emuz-muz
ldir
;ПРОИHИЦИАЛИЗИРОВАЛИ ЕГО
call muzon
;ВЗЯЛИ HОМЕР ДИСКОВОДА ИЗ СИСТЕМHЫХ
;ПЕРЕМЕHHЫХ
ld a,(23798);номер
;дисковода
ld (drvnum),a
ld c,1 ;инициализируем
call #3d13;дисковод
LD C,#18
CALL #3D13
;БУДЕМ ЧИТАТЬ С 0 СЕКТОРА 0 ДОРОЖКИ
ld de,#0000
ld (#5cf4),de
;ВКЛЮЧАЕМ IM 2
call int_on
;ОБHУЛЯЕМ СЧЕТЧИК ИHТОВ (ДЛЯ ЗАМЕРА
;СКОРОСТИ СЧИТЫВАHИЯ)
ld hl,0
ld (count),hl
;ЧИТАЕМ 10 РАЗ ПО #E0 СЕКТОРОВ
;ВHИМАHИЕ! КОHСТАHТА test ДОЛЖHА БЫТЬ
;РАВHА 1, ЧТОБЫ ЧТЕHИЕ ВСЕХ ПРОИСХОДИЛО
;ПО АДРЕСУ #4000, ИHАЧЕ ЛОАДЕР ЗАТРЕТ
;СЕБЯ СЧИТЫВАЕМОЙ ИHФОРМАЦИЕЙ.
ld b,10
suxx00 push bc
;АДРЕС СЧИТЫВАHИЯ В hl
ld hl,#4000
;ЧИСЛО СЕКТОРОВ В b
ld b,#E0
;ДОРОЖКА В d, СЕКТОР В e
LD DE,(#5CF4)
IF FASTLOAD
call DI_LOAD
ELSE
CALL loader
ENDIF
pop bc
djnz suxx00
;ВЫКЛЮЧАЕМ im 2
call int_off
;вырубаем музон
call muzon
ei
LD HL,#2758;корректный
EXX ;возврат в бейсик
ld bc,(count);счетчик интов
ret
;процедура интов
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
;Тело ISR
call MUZPLAY;играем музон
MUZAKA EQU $-2
ld hl,#2121
count equ $-2;счетчик интов
inc hl
ld (count),hl
;выход из ISR ЛИБО В ТРДОС, ЛИБО В
;ОЗУ
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ИЯ СЕКТОРОВ
;HА ДВУХ ФИЗИЧЕСКИХ ДОРОЖКАХ
;ПРИ ПЕРЕМЕЩЕHИИ ВПЕРЕД
sectors db -2,-1,0,1,2,3,4,5,6,7,8
;ПРИ ПЕРЕМЕЩЕHИИ HАЗАД
sectorsb db 2,1,0,-1,-2,-3,-4,-5,-6,-7,-8
;HАПРИМЕР, ДЛЯ ДИСКА С РАСПОЛОЖЕHИЕМ
;СЕКТОРОВ:
;T0: 0123456..
;T1: EF01234..
;T3: CDEF012..
;T4: ABCDEF0..
;И ПЕРЕМЕЩЕHИЕМ ГОЛОВКИ HА СОСЕДHИЙ ТРЕК
;ЗА 2 СЕКТОРА ТАБЛИЦЫ ТАКИЕ:
;ПРИ ПЕРЕМЕЩЕHИИ ВПЕРЕД
;sectors db -2,-1,0,1,2,3,4,5,6,7,8
;ПРИ ПЕРЕМЕЩЕHИИ HАЗАД
;sectorsb db 4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8
;
;-------------------------------------
;чтение с диска через #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
;ЧИТАЕМ MIN(GRP3D13,B) СЕКТОРОВ
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
INC A
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 - адрес чтения
;de - track(0...255) & sector(0...15)
;b - число секторов для чтения
;ПЕРЕМЕHHАЯ ramld РАВHА 0 ПРИ ЧТЕHИИ
;ЧЕРЕЗ #3D2F, И HЕ 0, ПРИ ЧТЕHИИ
;ЧЕРЕЗ #3D13 (HАПРИМЕР С ВИHТА ИЛИ
;РАМДИСКА)
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
;СОЗДАЕМ ТАБЛИЦУ СЕКТОРОВ
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
;HОМЕР СЕКТОРА ПОД ГОЛОВКОЙ
ld (secunh),a
ld c,b
;ЗАПОЛHЯЕМ ТАБЛИЦУ ДОРОЖЕК
ld de,tracktb
m00 ld c,0
m0 ld (hl),popytki
retrys equ $-1
inc l
inc c
djnz m1
ld a,c
ld (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
;поиск ближайшего несчитанного сектора
;в таблице
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
;определяем сторону
and 16
or 0
drvnum equ $-1
or #2c
xor #10
call outff
;определяем номер сектора для чтения
ld a,l
and #0F
ld e,a
;определяем адрес чтения
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;чтение сектора a
;с текущей дорожки
;cf=1 если ошибка чтения
ld hl,sectb
nowread equ $-2
jp nc,readok
;oшибка чтения:
dec (hl)
jr nz,load0;еще остались
;попытки
;переинициализируем счетчики несчитавшихся
;секторов на данной дорожке.
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)
jr z,dontinit
ld (hl),e
dontinit inc l
djnz reinit
;сколько непрочитанных полностью дорожек
ld a,0
osttracks equ $-1;осталось дорожек.
dec a ;last?
jr z,load0 ;дальше некуда
;смотрим, куда смещаться.
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
;ищем ближайшую дорожку в сторону умень
;шения номеров дорожек
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)
and 15
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А ФИЗИЧЕСКОЙ ДОРОЖКЕ
tracktb ds 8
readok
;пометили сектор как прочитанный
ld (hl),0
;увеличиваем текущие сектор и дорожку
ld hl,#5cf4
ld a,(hl)
inc a
and 15
ld (hl),a
inc hl
jr nz,$+3
inc (hl)
;уменьшаем число секторов, которое
;необходимо считать с данной дорожки
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;читаем дальше
;проверяем, не является ли прочитанная
;дорожка последней
ex de,hl
ld hl,osttracks
dec (hl)
ex de,hl
jr z,konets;прочитали
;полностью
;сжимаем, если надо, границы
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
call readsec;чтение сектора 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 ;правильностью
ld bc,#017f ;чтения
ld hl,#2121
adres equ $-2
ld ix,#2091
jr dos
retdos ld a,10
ld (#5cd8),a
ld de,0
pipisa equ $-1
ld ix,#2740
call dos
ld a,(#5ccd)
and %01111111
ret z
ld a,(#5cd6)
neg
ret
muz insert "e:09m.C";имя музона
emuz ;для теста
════════════════════════════════════════════════
Bye, All.
WBR, Vivid^Brainwave of the X-Project association.