[net.micro.atari] Single to double density switching

long@sask.UUCP (Warren Long) (02/04/86)

I have been trying (unsuccessfully) to switch my disk drives
to and fro from double density.  It is easy to do from a 
DOS that does it.  (eg. TOP DOS or MYDOS).

What I want to do is to be able to do it from my program.
I write everything in ACTION so assembly or machine code is
quite acceptable.  I will even translate it from BASIC string
machine codes if I have to.  Help!!!!



			   Warren Long
			   University of Saskatchewan
			   Canada

langdon@lll-lcc.UUCP (02/07/86)

In article <328@sask.UUCP>, long@sask.UUCP (Warren Long) writes:
> 
> I have been trying (unsuccessfully) to switch my disk drives
> to and fro from double density.  It is easy to do from a 
> DOS that does it.  (eg. TOP DOS or MYDOS).
> What I want to do is to be able to do it from my program.
> I write everything in ACTION so assembly or machine code is
> quite acceptable.  


Try this. It is supposed to become a directory fixer for DD diskettes;
that is only part started, but density detection and switching are in there
and they worked.

----------------------------------------------------------------------
	Bruce Langdon  L-472                langdon%lll-lcc@lll-crg.ARPA
	Physics Department                  "langdon#bruce%d"@lll-mfe.ARPA
	Lawrence Livermore National Laboratory       
	Livermore, CA 94550                 (415) 422-5444
UUCP: ..{gymble,ihnp4,seismo}!lll-crg!lll-lcc!langdon
---------------------------------------------------------------------------

; DISKFIX.AC1 12/23/85 A. B. Langdon
 
DEFINE SIOUT="$80", SIOIN="$40"
BYTE Dtimeout=[15]

; Device Control Block for SIO:
BYTE DDEVIC=$0300, DUNIT=$0301,
     DCOMND=$0302, DSTATS=$0303, DTIMLO=$0306
CARD DBUF=$0304,   DBYTE=$0308,  DAUX12=$030A

PROC SIOV=$E459()   ;define location of serial bus handler

BYTE FUNC DSio()
; finish set up of Device Control Block
; and call the serial I/O routine.
  DDEVIC = '1
  DTIMLO = Dtimeout
  SIOV()
RETURN (DSTATS)

MODULE; SECTIO ----------------------
; Adapted from OSS bbs.
; Sectors are numbered 1-720.

BYTE FUNC SectIO(BYTE drive, CARD sector, buffer, BYTE density)
  DUNIT = drive
  DBUF = buffer
; Set byte count for this density
  IF (sector<=3) OR (density<3) THEN
    DBYTE = 128
  ELSE
    DBYTE = 256
  FI
  DAUX12 = sector
RETURN (DSio())

BYTE FUNC ReadSector(BYTE drive, CARD sector, buffer, BYTE density)
  DCOMND = 'R
  DSTATS = SIOIN
  SectIO(drive, sector, buffer, density)
[$60]; RETURN (SIO error code)

BYTE FUNC WriteSector(BYTE drive, CARD sector, buffer, BYTE density)
  DCOMND = 'W
  DSTATS = SIOUT
  SectIO(drive, sector, buffer, density)
[$60]; RETURN (SIO error code)

MODULE; DENSITY ---------------------
; From Mark Reed, on ACS bulletin board. Mods by B. Langdon
;This program changes the density of a PERCOM-compatible drive from
;single to double density and vice versa.  It also displays the values
;in the drive option table before and after the change.
;Note that by changing the Set_DENSITY() procedure you could configure
;the disk controller to handle a double sided or 96TPI (quad density)
;drive, assuming your controller can handle these drive types.
;(The PERCOM RFD-1 and ATR8000 can, the TRAK, INDUS, etc. can't)

DEFINE RdOCmd="'N", WrOCmd="'O"
BYTE ARRAY OptTable(12) 
BYTE Ntracks=OptTable, StepRate=OptTable+1, Nsides=OptTable+4,
     density=OptTable+5, present=OptTable+8
CARD Nsectors=OptTable+2, Nbytes=OptTable+6

PROC OPTION_TABLE_ERROR()
  PrintF("ERROR %D%E",DSTATS)
RETURN

PROC OPTION_TABLE(BYTE drive, CMND)
  DUNIT = drive
  DCOMND = CMND
  IF CMND=RdOCmd THEN     ;read option table
    DSTATS = SIOIN        ;set for data in
  ELSEIF CMND=WrOCmd THEN ;write option table
    DSTATS = SIOUT        ;set for data out
  ELSE
    OPTION_TABLE_ERROR()
    RETURN
  FI
  DBYTE = 12
  DBUF = OptTable
  DSio()
  IF DSTATS<>1 THEN
    OPTION_TABLE_ERROR()
  FI        
RETURN

CARD FUNC SwapHiLo=*(CARD in)
; For Percom's 6809, must use Hi,Lo order.
  [$86 $A0] ; STX value low
  [$85 $A1] ; STA value high
  [$60]     ; RETURN

PROC TEST_OPTION_TABLE(BYTE drive)
; read the option table and displays the values
  BYTE ARRAY SR=[6 12 20 30]   ; step rates
  CARD Ctemp
  OPTION_TABLE(drive, RdOCmd)
  IF DSTATS<>1 THEN RETURN FI
  Ctemp=SwapHiLo(Nsectors) 
  PrintF("%D tracks of %D sectors, %D sides%E",Ntracks,Ctemp,Nsides+1)
  PrintF("step rate %D ms. 'present'=%D%E",SR(StepRate),present)
  Ctemp=SwapHiLo(Nbytes) 
  PrintF("%D bytes/sector; 'density'=%D%E",Ctemp,density)
RETURN

PROC Set_DENSITY(BYTE drive, NEW_DENSITY)
  OPTION_TABLE(drive, RdOCmd)   ;read option table
  IF NEW_DENSITY=1 THEN         ;sets single density
    density=0                   ;single/double flag
    Nbytes=SwapHiLo(128)
    OPTION_TABLE(drive, WrOCmd) ;write new info
  ELSEIF NEW_DENSITY=2 THEN     ;sets double density
    density=4                   ;density flag
    Nbytes=SwapHiLo(256)
    OPTION_TABLE(drive, WrOCmd)
  FI
RETURN

MODULE; -----------------------------

BYTE drive, j
BYTE ARRAY buf(256), directory(1028)
BYTE ARRAY VTOC(256), SMap(90)=VTOC+10
CARD TotSect=VTOC+1, NSUnused=VTOC+3
CARD sector, i
CARD ARRAY SLinks(720)
CARD POINTER link
BYTE POINTER nfile
; Sectors are numbered 1-720 by drive.
; TotSec may always be 707.
TYPE DirEntry=[BYTE flag CARD count, sect]
; flag:
; =$00 entry never used
;   01 now writing file
;   02 a version 2 file
;   20 entry protected
;   40 entry in use
;   80 entry was deleted
; count=number of sectors,
; start=number of 1st sector.
DirEntry POINTER filedat

BYTE FUNC TestVTOC(CARD sector, BYTE ARRAY map)
; FMS bug: there is no sector for bit 0,
; no bit for sector 720.
  BYTE index, mask
  mask = $80 RSH (sector&7)
  index = sector RSH 3
RETURN( map(index)&mask )

PROC SetVTOC(CARD sector, BYTE ARRAY map)
  BYTE index, mask
  mask = $80 RSH (sector&7)
  index = sector RSH 3
  map(index) ==% mask  
; also dec sectors avail***
RETURN

CARD FUNC NextSect()

BYTE FUNC TraceFile(BYTE filen, CARD sector, BYTE ARRAY map)
; follow file 'filen' starting at 'sector'
; setting VTOC as we go.
  CARD ns
  link = buf+Nbytes-3
  nfile = link
  DO  
    ReadSector(drive,sector,buf,density)
    SetVTOC(sector,map)
    nfile^ = ($FC&nfile^) RSH 2
    PrintF("sec %U file %U%E",sector,nfile^)
    IF nfile^<>filen THEN RETURN(1) FI
    ns = SwapHiLo(link^) & $3FF
    SLinks(sector) = ns
    sector = ns
  UNTIL sector=0 OD   
RETURN(0)

PROC TraceDisk()
  link = buf+Nbytes-3
  nfile = link
  FOR sector=4 TO 719 DO
    ReadSector(drive,sector,buf,density)
    SLinks(sector) = SwapHiLo(link^) & $3FF
    PrintF("sec %U file %U%E",link^,nfile^)
  OD
RETURN

PROC GetDir() ; assemble all directory sectors
  Zero(directory, 1028)
  i = directory
  FOR sector=361 TO 368 DO
    ReadSector(drive, sector, buf, density)
    IF buf(0)=0 THEN EXIT FI ;no more after this
    MoveBlock(i, buf, 128) ;128 bytes used even in DD
    i ==+ 128
  OD
RETURN

PROC PrintFN(BYTE POINTER name)
  BYTE DSPFLG=$2FE, i
  DSPFLG = 1
  name ==+ 5
  FOR i=1 TO 11 DO
    Put(name^)
    name ==+ 1
  OD
  DSPFLG = 0
RETURN

PROC ShowDir()
  BYTE nf
  CARD Nfree
  Nfree = 707 ;=720 -1 unused -3 boot -1 VTOC -8 directory
  i = 0
  FOR nf=0 to 63 DO
    filedat = i+directory
    IF filedat.flag=0 THEN EXIT FI ;no more after this
    PrintFN(filedat)
    PrintF(" %U %H %U %U%E",nf,filedat.flag,filedat.count,filedat.sect)
    IF filedat.flag<$80 THEN
      Nfree ==- filedat.count
    FI
    i ==+ 16
  OD
  PrintF("%U FREE SECTORS%E",Nfree)
  PrintF("VTOC: %U %U%E",TotSect,NSUnused)
RETURN

PROC MAIN()

  Print("ENTER THE DRIVE NUMBER: ")
  drive=InputB()

  TEST_OPTION_TABLE(drive)
  IF DSTATS<> 1 THEN RETURN FI
  NBytes = SwapHiLo(NBytes)

  ReadSector(drive,360,VTOC,density)

  Tracefile(0,4,SMap)
RETURN
  GetDir()
  ShowDir()
RETURN

DYOUNG@USC-ISID.ARPA (C. David Young) (02/10/86)

If I remember correctly, making a drive change densities to match the
disk inserted is as easy as reading sector 1.  Then you need only do a
status call to find out what the density is.

David Young
-------

rb@mtuxn.UUCP (R.BOTWIN) (02/12/86)

[]
David mentions reading sector 1 to switch densities, but I don't believe
that is what was asked, or will in fact help.

In fact, to insure compatible booting, the first three sectors are
always 128 bytes, even if 18 X 256 DD formatting is used on the
remainder of the disk.

Most switchable drives use additional commands (M, N, O) to switch
density according to a table passed in the call.  These are documented
by manufacturers using the system developed by PERCOM, and copied
by AMDEK, ASTRA, TRAK, INDUS, etc. (even ATARI)....

If you need the table layout, I can probably dig it up....

	Rob Botwin, N2FC
    .....{utah-cs|seismo|decvax}!harpo!eagle!houxm!mtuxo!mtuxn!rb
	ATT/IS Labs (201) 577-5016 (Cornet 8-270-5016)
	FJ 1B-130