RAM from address #0000
ZXNet echo conference «hardware.zx»
From Valerij Kozhevnikoff → To All 14 September 2002
Hello, All!
How is the subject made in the modified Pentagon computers? Only cache via #FB and
everything? Are there any options? Is VG enabled for direct access?
While digging through the docks I found this, do many people have it?
······------====== Monitor glass cutter ======------······
Port #EFF7.
bit 0 - screen mode 256*192, byte of color per byte of dots.
In #6000-#77FF there are attributes, they are standard, with the exception of
bits 6 and 7. Here these are paper bright and ink bright, respectively.
bit 1 - screen mode 512*192, b/w.
Well, this is clear to everyone.
bit 2 - blocking RAM over 128K.
This bit also controls the assignment of bit 5 in #7ffd.
1 - RAM over 128k is locked, bit 5 in #7ffd works
standard latch "48k only".
0 - upper memory is available, and bit 5 in #7ffd is used for
memory management over 512k, otherwise called "meter
Pentagon style."
bit 3 - enable TURBO.
(it was planned, IMHO it was not implemented by anyone)
Some people used this bit as “write permission” in the stat. RAM,
connected by bit 6.
bit 4 - GIGASCREEN.
Hardware interlace.
As you know, Spec has two screens, and each of them has 192
lines. The interlacing cycle takes two frames. In the first on
the screen displays even lines from the zero screen and odd lines from
the first, in the second - odd from zero and even from first.The effect is similar to when every interruption switches the screen, but
without obvious flicker.
I have it, in Scorp it’s done on one LP5.
By the way, this bit can be used together with 0 or 1, interlace
on the side how many colors or dots are on the screen.
bit 5 - enable DOS ROM and VG ports for direct access from RAM.
_A lot of people have done this?_
bit 6 - blocking ROM and connecting another, or 16k stat. RAM.
In 1998 it was like this, people filled these 16k statics with the necessary
version of DOS and used it.
Then someone suggested switching halves with this bit
Cache-32, although switching these halves seemed to be already then
set to #7ffd bit 4.
Later this bit was used for 384x304 graphics without border. Apparently
Cache RAM, enabled instead of ROM via IN #FB, turned out to be more convenient.
bit 7 - enable access to the clock.
IMHO, there's no need to hide your watch.
······------====== Monitor glass cutter ======------······
WBR, Jason.
/*e-mail: jason2000(scary dog)yandex.ru ICQ: 62235830*/
/np:/ *silence*
From Kirill Frolov → To Valerij Kozhevnikoff 17 September 2002
Press RESET immediately, Valerij!
14 Sep 02 17:15, Valerij Kozhevnikoff wrote to All:
VK> How is the subject made in the modified Pentagon computers?
Which pentagons?
VK> Only cache via #FB and that's it?
It seems like that's the only way.
VK> Is VG enabled for direct access?
No way. Or via cache (jp #3dxx and tr-dos enabled).
VK> While digging in the docks, you found this, do many people have it?
There are a lot of things that everyone is missing or done differently.
VK> bit 1 - screen mode 512*192, b/w.
VK> Well, this is clear to everyone.
VK> --------------------------------------------------------------
VK> bit 2 - blocking RAM over 128K.
VK> This bit also controls the assignment of bit 5 in #7ffd.
VK> 1 - RAM over 128k is blocked, bit 5 in #7ffd works
VK> standard latch "48k only".
VK> 0 - upper memory is available, and bit 5 in #7ffd is used for
VK> memory management over 512k, otherwise called "meter
VK> in Pentagon style."
VK> -------------------------------------------------------------- VK> bit 4 - GIGASCREEN.
VK> Hardware interlace.
VK> As you know, Speck has two screens, and each of them has 192
VK> lines. The interlacing cycle takes two frames. In the first one
VK> screen displays even lines from the zero screen and odd lines from
VK> of the first, in the second - odd from zero and even from first.
VK> The effect is similar to when each interruption switches the screen, but
VK> without obvious flickering.
VK> I have it, in Scorpa it’s done on one LP5.
VK> By the way, this bit can be used together with the 0th or 1st interlace
VK> on the side, how many colors or dots are on the screen.
VK> --------------------------------------------------------------
VK> bit 7 - enable access to the clock.
These four are more or less present.
VK> IMHO, there’s no need to hide the clock.
Even harmful. Writing to register #eff7 changes the contents of other bits...
VK> --------------------------------------------------------------
VK> bit 5 - enable DOS ROM and VG ports for direct access from RAM. VK> _Has this been done by many?_
No. Forget it. I don’t understand at all why direct access is needed on the Pentagon.
For a flop it is desirable, but not necessary, to have TR-DOS in the ROM at address #3ff3
teams
IN A,(C): RET.
Flop driver (there are bugs):
=== 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 equiv 3
mrdonl equ 80h ; 1=readonly (*) -- used in betadisk module
brdonl equ 7
; IY+var -- drive variables
drive equ 0 ; physical drive 0..3
speed 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 ===