11

I wish to build a small database using Sinclair ZX Microdrive: one can think to create a text file using some simple BASIC. For simplicity let's say the record is 512 bytes in length, i.e. the same as a Microdrive sector.

100 INPUT "Filename"'n$
110 LET N=4    
120 LET unit=1
130 DIM b$(512)
200 OPEN #N,"M",unit,n$
210 FOR r=0 TO 10
220  LET b$="Record "+STR$ r
250  PRINT #N;b$;
290 NEXT r
300 CLOSE #N

Later, is it possible to directly seek the n-th record then read it, modify it and write it back to the same file position using only BASIC?

1 Answer 1

10

Let's have few functions and (system) variables names

 15 DEF FN p(a)=256*PEEK (a+1)+PEEK a : REM DPEEK(a)
 16 DEF FN m(n,d)=n-d*INT (n/d)       : REM MOD(n,d)
 17 DEF FN l(v)=v-256*FN h(v)         : REM Low byte  
 18 DEF FN h(v)=INT (v/256)           : REM High byte
 99 CLEAR # : REM be sure Interface 1 is attached.
100 LET STRMS=23606
110 LET CHANS=23631

Let's determine the address of the channel (cha) already open and the address of microdrive map (map).

1010 LET cha=FN p(CHANS)-1+FN p(STRMS-32+2*N)
1020 LET map=FN p(cha+26)
1030 LET buf=cha+82

Even if there is no "seek" operation we still can force the system to read record R by let him believe we just read the end of record R-1. We can POKE inside the microdrive channel information the variables CHBYTE, RECFLG, CHFLAG and CHREC, then accept one character from stream to read the whole record R into buffer at address (buf)

1040 POKE cha+12,3:   REM CHBYTE (high buff pointer)
1050 POKE cha+67,0:   REM RECFLG (not end-of-file)
1060 POKE cha+24,254: REM CHFLAG (file open for read)
1070 POKE cha+13,r-1: REM CHREC  (record number)
1080 LET d$=INKEY$#N

Modifying the record requires a little bit of experimentation that is beyond the scope of this answer.

To force the system to write record R back to Microdrive, having just read the record R into buffer using the previous piece of code, and modified it in place, we first have to make the system believe there is only one sector available in the Microdrive cartridge by setting all bits but the one we need

1110 LET sect=PEEK (cha+41): REM HDNUMB (physical sector number)
1120 FOR m=map TO map+31
1130  POKE m,255
1140 NEXT m
1150 POKE map+INT (sect/8), 255-2^FN m(sect,8)

then re-create the situation when the buffer pointer is on the last byte of buffer and re-writing it forcing the system to flush the whole buffer back to Microdrive via PRINT #;

1210 POKE cha+24,255: REM CHFLAG (for write)
1220 POKE cha+11,FN l(511): REM CHBYTE (low buf pointer)        
1230 POKE cha+12,FN h(511): REM CHBYTE (high buf pointer)
1250 POKE cha+67,0:         REM RECFLG (not end-of-file)
1240 PRINT #N;CHR$ PEEK (cha+593); : REM buf+511
4
  • I work with code, but I don't have the chance to work with constrained devices. I miss my ZX-81 and Spec, great answer.
    – rsenna
    Commented Nov 25, 2023 at 20:04
  • 1
    @rsenna nowadays real hardware is rare, but several emulators support Microdrives where you can have almost the same touch and feeling Commented Nov 25, 2023 at 22:05
  • 1
    Machine Code doesn't need messing (much) with system variables. There's a hook code for "READ RANDOM"
    – tofro
    Commented Dec 11, 2023 at 19:37
  • Yes @tofro : hook code $28 for READ and $2A for WRITE, if I remember correctly. Commented Dec 12, 2023 at 17:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .