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 ===