ZXNet эхоконференция «hardware.zx»


тема: ОЗУ с адреса #0000



от: Valerij Kozhevnikoff
кому: All
дата: 14 Sep 2002
Здравствуй, All!

Как в доработанных Пентагонах компах сделано сабж? Только кеш через #FB и
все? Есть какие-то варианты? А ВГ на прямой доступ ка включают?

Копаясь в доках нашел вот такое, оно у многих есть?

······------====== Стеклорез мониторный ======------······

Порт #EFF7.

bit 0 - pежим экpана 256*192, байт цвета на байт точек.
В #6000-#77FF лежат атpубуты, они стандаpтные, за исключением
битов 6 и 7. Тут это paper bright и ink bright соответственно.

bit 1 - pежим экpана 512*192, ч/б.
Hу это всем понятно.

bit 2 - блокиpовка ОЗУ свыше 128К.
Также этот бит управляет назначением бита 5 в #7ffd.
1 - ОЗУ свыше 128к заблокировано, бит 5 в #7ffd работает
стандартной защелкой "48k only".
0 - доступна верхняя память, а бит 5 в #7ffd служит для
управления памятью свыше 512к, иначе называемой "метр
по-пентагоновски".

bit 3 - включение TURBO.
(планиpовалось, имхо ни у кого не pеализовано)
Hекоторые юзали этот бит как "разрешение записи" в стат. ОЗУ,
подключаемое битом 6.

bit 4 - GIGASCREEN.
Аппаратный интерлейс.
Как известно, Спек имеет два экрана, и в каждом из них по 192
строки. Цикл работы интерлейса занимает два кадра. В первом на
экран выводятся четные строки из нулевого экрана и нечетные из
первого, во втором -- нечетные из нулевого и четные из первого.
Эффект схож с тем, когда каждое прерывание переключают экран, но
без явно выраженного мерцания.
У мя есть, в Скорпе делается на одной ЛП5.
Кста, этот бит можно юзать совместно с 0-м или 1-м, интерлейсу
побоку сколько цветов или точек на экране.

bit 5 - включение ПЗУ DOS и портов ВГ на прямой доступ из ОЗУ.
_Это у многих сделано?_

bit 6 - блокиpовка ПЗУ и подключение дpугого, или 16k стат. ОЗУ.
В 1998 году было так, в эти 16k статики люди заливали нужную
версию доса и юзали ее.
Потом кто-то предлагал переключать этим битом половинки
Cache-32, хотя переключение этих половинок вроде уже тогда
устаканили на #7ffd bit 4.
Позднее этот бит заняли под графику 384х304 без бордюра. Видимо
Cache RAM, включаемая вместо ПЗУ по IN #FB оказалась удобнее.

bit 7 - включение доступа к часам.
Имхо, нафиг не нужно прятать часы.

······------====== Стеклорез мониторный ======------······

WBR, Jason.

/*e-mail: jason2000(собака страшная)yandex.ru ICQ: 62235830*/

/np:/ *silence*

от: Kirill Frolov
кому: Valerij Kozhevnikoff
дата: 17 Sep 2002
Hемедленно нажми на RESET, Valerij!

14 Sep 02 17:15, Valerij Kozhevnikoff wrote to All:

VK> Как в доработанных Пентагонах компах сделано сабж?

Каких пентагонах?

VK> Только кеш через #FB и все?

Вроде только так.

VK> А ВГ на прямой доступ ка включают?

Hикак. Или через кеш (jp #3dxx и тр-дос включен).

VK> Копаясь в доках нашел вот такое, оно у многих есть?

Тут много чего у всех отсутствует или сделано по-разному.

VK> bit 1 - pежим экpана 512*192, ч/б.
VK> Hу это всем понятно.
VK> --------------------------------------------------------------
VK> bit 2 - блокиpовка ОЗУ свыше 128К.
VK> Также этот бит управляет назначением бита 5 в #7ffd.
VK> 1 - ОЗУ свыше 128к заблокировано, бит 5 в #7ffd работает
VK> стандартной защелкой "48k only".
VK> 0 - доступна верхняя память, а бит 5 в #7ffd служит для
VK> управления памятью свыше 512к, иначе называемой "метр
VK> по-пентагоновски".
VK> --------------------------------------------------------------
VK> bit 4 - GIGASCREEN.
VK> Аппаратный интерлейс.
VK> Как известно, Спек имеет два экрана, и в каждом из них по 192
VK> строки. Цикл работы интерлейса занимает два кадра. В первом на
VK> экран выводятся четные строки из нулевого экрана и нечетные из
VK> первого, во втором -- нечетные из нулевого и четные из первого.
VK> Эффект схож с тем, когда каждое прерывание переключают экран, но
VK> без явно выраженного мерцания.
VK> У мя есть, в Скорпе делается на одной ЛП5.
VK> Кста, этот бит можно юзать совместно с 0-м или 1-м, интерлейсу
VK> побоку сколько цветов или точек на экране.
VK> --------------------------------------------------------------
VK> bit 7 - включение доступа к часам.

Эти четыре более-менее присутствуют.

VK> Имхо, нафиг не нужно прятать часы.

Даже вредно. Запись в регистр #eff7 меняет содержимое других битов...

VK> --------------------------------------------------------------
VK> bit 5 - включение ПЗУ DOS и портов ВГ на прямой доступ из ОЗУ.
VK> _Это у многих сделано?_

Hет. Забей. Я вообще не понимаю зачем нужен прямой доступ на пентагоне.
Для флопика желательно, но не обязательно, иметь в ПЗУ ТР-ДОС по адресу #3ff3
команды
IN A,(C): RET.

Драйвер флопика (баги есть):

=== Cut ===

*Include floppy.inc
=== Cut ===

; mode mask and bits
mmfm equ 01h ; 1=mfm (*)
bmfm equ 0
mcside equ 02h ; 1=check side (*)
bcside equ 1
mwrdel equ 04h ; 1=write delay (for slow drives)
bwrdel equ 2
mauto equ 08h ; 1=auto disk change
bauto equ 3
mrdonl equ 80h ; 1=readonly (*) -- used in betadisk module
brdonl equ 7

; IY+var -- drive variables
drive equ 0 ; physical drive 0..3
sspeed equ 1 ; seek speed 0..3
dmode equ 2 ; mode bits
track equ 3 ; track 0xff = undefined
side equ 4 ; side 0=bottom, 1=top
chflag equ 5 ; write protect status(call fdchange)
changed equ 6 ; 1=disk changed
reservx equ 7 ; reserved

dpbsize equ 8 ; size of drive vars.

; error codes
efdok equ 0 ; no errors
efdfail equ 1 ; hardware failure
efdwprot equ 2 ; write protect
efdnosec equ 3 ; sector not found
efdcrc equ 4 ; crc error
efdtout equ 5 ; timeout



=== Cut ===


*Include betadisk.inc
=== Cut ===

; IY=Drive Parameters Block pointer

global fdreset ; reset controller
global fdstop ; stop all drives
global fdready ; check drive ready/not -> CF=0 if ready
global fdindex ; return INDEX state -> CF=0 if active
global fdchange ; -> CF=1 disk changed
global fdpresent ; -> CF=1 drive not present
global fdctl ; call it first for new drive!
global fdside ; set side A?0:1
global fdtrack ; set heads to track A -> CF=1 on error
global fdrdsec ; read sector A \n
global fdwrsec ; write sector A |

global fdrdadr ; read address mark > CF=1 on error, A=status bits
global fdrdtrk ; read track | buffer=(HL++)
global fdwrtrk ; write track /

=== Cut ===

rsttime equ 1000

; controller io registers
rgcmd equ 1fh ; write only -- command register
rgstat equ 1fh ; read only -- status register
rgtrk equ 3fh ; track register
rgsec equ 5fh ; sector register
rgdata equ 7fh ; data register
rgctl equ 0ffh ; write only -- external controller register

; command modifiers
cs0 equ 01h ; head moving speed bit 0
cJ0 equ 01h ; interrupt command modifier, see below
ca0 equ 01h ; special sector mark, not used
cs1 equ 02h ; head moving speed bit 1
cJ1 equ 02h
cC equ 02h ; check side (for read/write commands)
cV equ 04h ; read and verify head position (for seek, step and
reset commands)
cE equ 04h ; delay before reading/writing?
cJ2 equ 04h
ch equ 08h ; load head (for seek, step and reset commands)
cS equ 08h ; disk side (for read/write commands, used only if cC=1)
cJ3 equ 08h
cI equ 10h ; modify or not rgtrk, used only for step commands
cm equ 10h ; multisector operation (for read/write sector commands
only)

; command interrupt bits
ci_noi equ 0 ; stop command execution but don't interrupt host
(INTRQ signal)
ci_rdy equ cJ0 ; stop command execution when DRDY is active (drive
ready)
ci_off equ cJ1 ; stop command execution when DRDY is inactive (drive
not ready)
ci_idx equ cJ2 ; stop command execution when INDEX impulse detected
ci_imm equ cJ3 ; stop command execution now and set INTRQ

; commands
creset equ 00 ; reset controller, seek track 0
cseek equ 10 ; seek track in rgdata
cstep equ 20 ; repeat last cfstep or cbstep
cfstep equ 40 ; forward step (from track 0)
cbstep equ 60 ; back step (to track 0)
crdsec equ 80 ; read sector(s)
cwrsec equ 0a0h ; write sector(s)
crdadr equ 0c0h ; read address mark (6 bytes)
crdtrk equ 0e0h ; read whole track with all address marks, etc...
cwrtrk equ 0f0h ; write whole track (format track)
cint equ 0d0h ; interrupt command execution

; status bits
sbusy equ 01h ; 1=controller busy (command executed)
sdrq equ 02h ; 1=data read/write requested
sidx equ 02h ; 1=index impulse
strk0 equ 04h ; 1=heads at track 0
sover equ 04h ; 1=data overrun
scrc equ 08h ; 1=crc failed, sector corrupted
sseek equ 10h ; 1=seek failed
snosec equ 10h ; 1=sector not found
shead equ 20h ; 1=head loaded
serase equ 20h ; 1=special sector mark, not used
swfail equ 20h ; 1=write failed
swprot equ 40h ; 1=write protected disk
sdrdy equ 80h ; 1=drive ready (really it's HEAD/MOTOR signal
indicator)

; control register bits
dd0 equ 01h ; drive number bit 0
dd1 equ 02h ; drive number bit 1
dreset equ 04h ; 0=reset controller
ddrdy equ 08h ; 1=floppy drive ready (emulation of real DRDY signal)
dside equ 10h ; 1=bottom size(0), 0=upper side(1)
dmfm equ 20h ; 1=double density (MFM method), 0=single density (FM) for
8" floppy

; interrupt bits
idrq equ 40h ; 1=active only if data read/write requested
iintrq equ 80h ; 1=active after execution of all commands


trentr equ 3d2fh ; tr-dos entry point
troutc equ 2a53h ; out(c),a
trintr equ 3fcah ; wait for intrq !set C to rgtrk, rgsec or rgdata only!
trread equ 3fd5h ; reading routine address
trwrite equ 3fbah ; writing routine address

trstat equ 2470h ; read status

trssv equ 5d04h ; word
trsst equ 5ccdh ; byte
trshl equ 5d02h ; word
trsjp equ 5cc2h ; byte
trsadr equ 5cc3h ; word



; get STATUS REGISTER in A

fdstat: ld a, (trsjp)
push af
ld hl, (trsadr)
push hl
ld hl, (trssv)
push hl
ld a, (trsst)
push af

ld hl, trsjp
ld (hl), 0c3h ; JP instruction
ld hl, fdstret
ld (trsadr), hl

ld d, (iy+track)

ld hl, trstat
push hl
ld hl, (trshl)
jp trentr

; 2740: in a,(1fh)
; ld (5ccdh),a
; ld e,d
; push de
; ld a,e
; out (7fh),a
; ld a,18h
; call 3d9ah
;
; 3d9a: out (1fh),a
; push hl
; rst 20h
; dw 1f54h
;
; 0020: jp 2f72h
;
; 2f72: ld (5d02h),hl
; ld (5d04h),de
; pop hl
; ld e,(hl)
; inc hl
; ld d,(hl)
; inc hl
; push hl
; ld hl,3d2fh
; push hl
; push de
; ld hl,5cc2h
; push hl
; ld hl,(5d02h)
; ld de,(5d04h)
; ret


fdstret:
; pop hl ; 1f54h
; pop hl ; 3d2fh
; pop hl ; rst 20h ...
; pop hl ; push hl
; pop hl ; call 3d9ah ...
; pop hl ; de

ld hl, 12
add hl, sp
ld sp, hl ; restore stack

ld a, (trsst) ; e = rgstat
ld e,a
pop af
ld (trsst), a
pop hl
ld (trssv), hl
pop hl
ld (trsadr), hl
pop af
ld (trsjp), a
ld a, e
ret



; write command A to COMMAND REGISTER

fdcmd: ld c, rgcmd
; jp fdwreg

; write A to register C

fdwreg: ld hl, troutc
push hl
jp trentr


; write command A to COMMAND REGISTER and wait INTRQ

fdcserv: call fdcmd
ld c, rgtrk
; jp fdwait

; wait for INTRQ !DANGER may never return!

fdwait: ld hl, trintr
push hl
jp trentr


; jump to READ proc. hl=data

fdjpread: ld c, rgdata
push hl
ld hl, trread
ex (sp), hl
jp trentr

; jump to WRITE proc. hl=data

fdjpwrite: ld c, rgdata
push hl
ld hl, trwrite
ex (sp), hl
jp trentr


; reset controller

fdreset: ld c, rgctl
xor a
call fdwreg
ld bc, rsttime
fdres1: dec bc
ld a, b
or c
jr nz, fdres1
call fdctl
call fdcserv
call fdtrack0
xor a
ret

; turn off motor

fdstop: ld a, (iy+track)
ld c, rgdata
call fdwreg
ld a, cseek
ld c, rgcmd
jp fdcserv


; set head to track 0 -> CF=1 on error

fdtrack0: ld a, creset+ch
or (iy+sspeed)
ld c, rgcmd
call fdcserv
call fdstat
ld (iy+track), 0
and strk0
ld a, 0
ret nz ; all ok
scf
ld (iy+track), 0ffh ; reset failed!
ret


; set head to track A -> CF=1 on error

fdtrack: or a
jr z, fdtrack0
ld b, (iy+track)
cp b
ret z
push af
inc b
jr nz, fdtrack_1
call fdtrack0
pop bc
ret c
push bc
fdtrack_1: pop af
ld b, (iy+track)
ld (iy+track), a
ld c, rgdata
call fdwreg
ld a, b
ld c, rgtrk
call fdwreg
ld a, cseek+ch
or (iy+sspeed)
ld c, rgcmd
call fdcserv
xor a
ret


; check if drive ready (HEAD/MOTOR is active?) and start it -> CF=0 if ready

fdready: call fdstat
and sdrdy
ret nz
scf
ret


; return index state -> CF=0 - INDEX

fdindex: call fdstat
and sidx
ret nz
scf
ret


; check if disk changed? CF=1 if changed

fdchange: call fdstat
push af
and sdrdy
jr nz, fdch1
call fdstop ; stop drive if it is inactive
fdch1: pop af
and swprot
xor (iy+chflag)
ret z
xor (iy+chflag)
ld (iy+chflag), a
scf
ret



; check if drive present? CF=1 drive not present

fdpresent: call fdtrack0
ret c
ld a, 1
call fdtrack
call fdstat
and strk0
ret z ; all ok, drive present
ld (iy+track), 0ffh ; no drive!
scf
ret


; set side A

fdside: and 01h
ld (iy+side), a
; jp fdctl

; set control register(s)

fdctl: ld a, (iy+drive)
and dd0+dd1 ; hack... why?
bit bmfm, (iy+dmode)
jr z, fdctl1
or dmfm
fdctl1: bit 0, (iy+side)
jr nz, fdctl2
or dside
fdctl2: or ddrdy+dreset
ld c, rgctl
call fdwreg
ld a, (iy+track) ; 0xff... bug?
ld c, rgtrk
jp fdwreg




; read sector A from current track to (HL++) !DANGER: NO SECTOR SIZE CHECKING!
; return CF=1 if error, A=status bits

fdrdsec: push hl
ld c, rgsec
call fdwreg
bit bcside, (iy+dmode)
ld a, crdsec
jr z, frds1
or cC
bit 0, (iy+side)
jr z, frds1
or cS
frds1: ld c, rgcmd
call fdwreg
pop hl
call fdjpread
jp z, fdtout ; timeout!
call fdstat
and sover+scrc+snosec
ret z ; all ok
jp fderror


; write sector A to current track from (HL++) !WARNING: NO SECTOR SIZE
CHECKING!
; return CF=1 if error, A=error code

fdwrsec: bit brdonl, (iy+dmode)
jr z, fdwrs0
ld a, efdwprot
scf
ret

fdwrs0: push hl
ld c, rgsec
call fdwreg
bit bcside, (iy+dmode)
ld a, crdsec
jr z, fwrs1
or cC
bit 0, (iy+side)
jr z, fwrs1
or cS
fwrs1: ld c, rgcmd
call fdwreg
pop hl
call fdjpwrite
jr z, fdtout ; timeout!
call fdstat
and sover+scrc+snosec+swfail+swprot
ret z ; all ok
jr fderror


; read address mark to (HL++) 6 bytes.
; return CF=1 if error, A=error code

fdrdadr: push hl
ld a, crdadr
ld c, rgcmd
call fdwreg
pop hl
call fdjpread
jr z, fdtout ; timeout!
call fdstat
and sover+scrc
ret z ; all ok
jr fderror


; read track to (HL++) ~7kb max.
; return CF=1 if error, A=error code

fdrdtrk: push hl
ld a, crdtrk
ld c, rgcmd
call fdwreg
pop hl
call fdjpread
jr z, fdtout ; timeout!
call fdstat
and sover
ret z ; all ok
jr fderror


; write track from (HL++) ~7kb max.
; return CF=1 if error, A=error code

fdwrtrk: bit brdonl, (iy+dmode)
jr z, fdwrt0
ld a, efdwprot
scf
ret

fdwrt0: push hl
ld a, cwrtrk
ld c, rgcmd
call fdwreg
pop hl
call fdjpwrite
jr z, fdtout ; timeout!
call fdstat
and sover+swfail+swprot
ret z ; all ok
and 0ffh-swprot
ld a, efdwprot
scf
ret z ; error A=status
jr fderror


; read/write sector/track/addressmark error

fderror: ld c, a
and swprot
ld a, efdwprot
scf
ret nz
ld a, c
and snosec
ld a, efdnosec
scf
ret nz
ld a, c
and scrc
ld a, efdcrc
scf
ret nz
ld a, efdfail
ret


; read/write sector/track/addressmark timeout

fdtout: ld a, cint+ci_imm ; stop command execution
call fdcmd
ld a, creset
or (iy+sspeed) ; stop drive, move heads to track 0
call fdcmd
ld (iy+track), 0ffh
ld a, efdtout ; return error status
scf
ret

end

=== Cut ===


Кеш диска (баги есть):


=== Cut ===

global bdread ; bc=blockno, a=devno -> NO ERRORS!
global bdwrite
global sleeplocked ; store ix, bc, de
global sleepnofree ; store bc, de


global bread ; a=devno, bc=blockno -> hl=bufptr
global bfree ; hl=bufptr, e=dirty flag
global bufsync ; a=devno/0xff
global bufinit ; hl=memptr, de=maxsize, bc=blocksize
; -> hl=unused memptr, bc=blocks in cache


; globals

null equ 0


; ----------------------- global routines -----------------------------------

; create buffers cache
; HL=mem ptr, DE=max.size, BC=blocksize
; -> HL=unused mem ptr, BC=blocks

bufinit: ld (bhash), hl
ld (blocksize), bc
; blocks=(cashesize-hashsize)/(blocksize+bdscsize)
ex de, hl
ld de, hashsize*2
xor a
sbc hl, de
jr c, cr_nomem
ld de, bdscsize
cr_count: sbc hl, de
jr c, cr_endmem1
sbc hl, bc
jr c, cr_endmem2
inc a
jr cr_count
cr_nomem:
ld bc, 0
scf
ret
cr_endmem2:
add hl, bc
cr_endmem1: add hl, de
or a
jr z, cr_nomem
ld de, (bhash)
add hl, de
push hl ; ptr to free mem
ld (cachesize), a
ld l, a
ld h, 0
push hl ; cache size

; clear hash table
ex de, hl
ld b, hashsize*2
xor a
cr_hash: ld (hl), a
inc hl
djnz cr_hash

; clear block descr. table and create free-links
push hl
pop ix
ld hl, (blocksize)
ld bc, bdscsize
add ix, bc
ld (bdata), ix
ld (bfreefirst), ix ; ix=first block descr. ptr
add hl, bc
ex de, hl
pop bc
push bc
ld b, c ; blocks
ld hl, null

cr_desc: ld (ix+bstatus), b_unused
ld (ix+bfreeprev), l
ld (ix+bfreeprev+1), h
djnz cr_last

push ix
add ix, de
push ix
pop hl
pop ix
ld (ix+bfreenext), l
ld (ix+bfreenext+1), h
push ix
ex (sp), hl
pop ix
jr cr_desc

cr_last: ld (ix+bfreenext), b
ld (ix+bfreenext+1), b
ld (bfreelast), ix

pop bc
pop hl
ret


;--------------------------------------------------------------------------
;; write out all modified blocks for device A=0..0xfe or all devices
A=0xff.;
bufsync: ld ix, (bdata) ; ix=first block data/descriptor
ld hl, cachesize
ld b, (hl)
ld hl, (blocksize)
ld de, bdscsize
add hl, de
ex de, hl

bsyncheck: push af
cp 0xff
jr z, bsynch1
cp (ix+bdevno)
jr nz, bsynnext
bsynch1: bit bit_unwritten, (ix+bstatus)
jr z, bsynnext

push bc
push de
ld a, (ix+bdevno)
ld c, (ix+bblockno)
ld b, (ix+bblockno+1)
push ix
push ix
pop hl
call bdwrite
pop ix
res bit_unwritten, (ix+bstatus)
pop de
pop bc

bsynnext: pop af
add ix, de
djnz bsyncheck
ret




;bread(devno,blockno,rewrite) : block ptr // INTERRUPTS DISABLED!
;{
; if (block found in hash chain)
; {
; while (block locked) sleep? ;
; lock block ;
; exclude block from free-blocks chain ;
; }
; else
; {
; while (free-blocks chain is empty) sleep? ;
; lock block ;
; exclude first block from free-blocks chain ;
; if (first free block is unwritten) write block ;
; exclude block from hash chain ;
; set new devno and blockno ;
; if (rewrite==0) read block ;
; insert block in hash chain ;
; }
;}
;

; A=devno, BC=blockno, E=rewrite flag -> HL=bufptr

bread: ld d, a
push de
call hashptr ; de=first block desc. in hash chain.
ex af, af' ; devno
ld e, (hl)
inc hl
ld d, (hl) ; de=first block desc. in chain
ex de, hl
pop de ; D=devno

; find block in hash chain
ghashcomp: push hl
pop ix ; ix=block desc.
ld a, d
cp (ix+bdevno)
jr nz, ghashnext ; check devno, blockno and lock
ld a, c
cp (ix+bblockno)
jr nz, ghashnext
ld a, b
cp (ix+bblockno+1)
jr nz, ghashnext

; sleep while block is locked
ghashsleep: bit bit_locked, (ix+bstatus)
jp z, ghashfind
call sleeplocked
jr ghashsleep

ghashnext: ex af, af'
ld l, (ix+bhashnext)
ld h, (ix+bhashnext+1)
ld a, h
or l
jr nz, ghashcomp

; block not found in hash chain -- find any free block or sleep
gfindfree: ld hl, (bfreefirst)
ld a, h
or l
jr z, gisfree
call sleepnofree
jr gfindfree

; found free block
gisfree: push hl
pop ix
set bit_locked, (ix+bstatus)
push bc
push de
call excl_free
bit bit_unwritten, (ix+bstatus)
jr z, gnewblock

; write old block to disk // MAY BE INTERRUPTED
ld a, (ix+bdevno)
ld c, (ix+bblockno)
ld b, (ix+bblockno+1)
push ix
push ix
pop hl
call bdwrite
pop ix
res bit_unwritten, (ix+bstatus)
pop de
pop bc

; data not valid -- set blockno, devno, add block to hash chain
gnewblock: pop de
pop bc
ld (ix+bdevno), d
ld (ix+bblockno), c
ld (ix+bblockno+1), b
dec e
jr z, gnewread ; fill block with
zeroes push ix pop hl ld e, l ld
d, h inc de ld bc, (blocksize) dec bc ld (hl), 0
ldir jr gnewrewrite

; read from disk, d=devno, bc=blockno // MAY BE INTERRUPTED
gnewread: ld a, d
push ix
push ix
pop hl
call bdread
pop ix

gnewrewrite: call hashptr
ld e, (hl)
inc hl
ld d, (hl)
push de ; get old ptr to first block
push ix
pop de
ld (hl), d ; set new ptr to first block
dec hl
ld (hl), e
pop ix ; ix=first block desc. in chain (old)
ex de, hl ; hl=curr. block desc.
ld (ix+bhashprev), l
ld (ix+bhashprev+1), h
push ix
ex (sp), hl ; hl=next. ptr
pop ix ; ix=curr. ptr
ld (ix+bhashprev), 0
ld (ix+bhashprev+1), 0
ld (ix+bhashnext), l
ld (ix+bhashnext+1), h
push ix
pop hl
ret

; found block in hash chain and it is not locked
ghashfind: set bit_locked, (ix+bstatus)
call excl_free
push ix
pop hl
ret



;bfree(blockptr,dirty) // INTERRUPTS DISABLED!
;{
; if (dirty=1) set unwritten flag
; if (dirty<2) insert block to end of free-blocks chain ;
; else {
; write block ;
; insert block to begin of free-blocks chain ;
; }
; unlock block ;
;}

; free block HL=block ptr, E=dirty flag (0=unchanged, 1=write, 2=immend.write)

bfree: push hl
pop ix
ld a, e
or e
jr z, bretoend ; block unchanged
set bit_unwritten, (ix+bstatus)
dec a
jr z, bretoend ; write later

; immendiatelly write block // MAY BE INTERRUPTED
; hl=data ptr block must be locked!
ld a, (ix+bdevno)
ld c, (ix+bblockno)
ld b, (ix+bblockno+1)
push ix
call bdwrite
pop ix
res bit_unwritten, (ix+bstatus)

; select strategy -- uncomment it
;; jr bretoend

; add block to begin of free-blocks chain
bretobegin: res bit_locked, (ix+bstatus)
ld hl, (bfreefirst)
ld (bfreefirst), ix
push hl
push ix
push ix
ex (sp), hl ; hl=curr.
pop ix ; ix=first in chain (old)
ld (ix+bfreeprev), l
ld (ix+bfreeprev+1), h
pop ix ; hl=first in chain (old)
pop hl ; ix=curr.
ld (ix+bfreenext), l
ld (ix+bfreenext+1), h
ld (ix+bfreeprev), 0
ld (ix+bfreeprev+1), 0
ret

; add block to end of free-blocks chain
bretoend: res bit_locked, (ix+bstatus)
ld hl, (bfreelast)
ld (bfreelast), ix
push hl
push ix
push ix
ex (sp), hl ; hl=curr.
pop ix ; ix=last in chain (old)
ld (ix+bfreenext), l
ld (ix+bfreenext+1), h
pop ix ; hl=last in chain (old)
pop hl ; ix=curr.
ld (ix+bfreeprev), l
ld (ix+bfreeprev+1), h
ld (ix+bfreenext), 0
ld (ix+bfreenext+1), 0
ret





;------------------- local subroutines and variables -----------------------

; exclude block from free-blocks chain IX=descriptor

excl_free: ld l, (ix+bfreenext)
ld h, (ix+bfreenext+1) ; hl=next block desc.
ld e, (ix+bfreeprev)
ld d, (ix+bfreeprev+1) ; de=prev block desc.
push ix
; if (prev exist) prev.next=next else firstlink=next;
ld a, d
or e
jr z, exfnoprev
push de
pop ix
ld (ix+bfreenext), l
ld (ix+bfreenext+1), h
jr exfchnext
exfnoprev: ld (bfreefirst), hl
; if (next exist) next.prev=prev else lastlink=prev;
exfchnext: ld a, h
or l
jr z, exfnonext
push hl
pop ix
ld (ix+bfreeprev), e
ld (ix+bfreeprev+1), d
jr exfchend
exfnonext: ld (bfreelast), de
exfchend: pop ix
ret


; get first block desc. ptr in hash chain
; A=devno, BC=blockno -> HL=pointer to chain start A,B,C must be unchanged!

hashsize equ 16 ; 4-bit hash

hashptr: push af
xor b
xor c
and hashsize-1 ; calculate hash
ld e, a
ld d, 0
ld hl, bhash
add hl, de
pop af
ret



; ! hashsize : 7-bit value!
; ! blocks : 8-bit value!
; ! blocksize : word
; ! devno : one byte !

; blocks = cashesize/(blocksize+bdscsize+2/bhashcap)
; hashsize = blocks/bhashcap

; status

b_unused equ 0 ; status=0 if blockno and devno is invalid !

bit_locked equ 0
bit_unwritten equ 1
bit_valid equ 7


; buffers cache struct:
;bdata equ 0..blocksize-1
bdevno equ -1
bstatus equ -2
bblockno equ -4
bhashprev equ -6
bhashnext equ -8
bfreeprev equ -0ah
bfreenext equ -0ch

bdscsize equ 0ch

blocksize: dw 0 ; size of data in one block
cachesize: db 0 ; 01..FF blocks in cache

bfreefirst: dw 0 ; pointer to first free block
bfreelast: dw 0 ; pointer to last free block

bhash: dw 0 ; pointer to start of hash array
bdata: dw 0 ; pointer to start of cache data

end
=== Cut ===




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Железо - Модем: мифы и реальность.
МinskZxNet - Значит русский рэп можно, а чеченский блек нельзя?
Бездна - Cон, или реальность?.. Она не знала что это. но что бы это ни было, это было невообразимо!
ASCII'2003 - Рассуждение: ижевская пати, смысл которой объеденить спектрумистов соседних городов и, конечно, же ижевских челов.
Wanted - Список Заслуженных Пользователей AC Edit.

В этот день...   18 апреля