DataMuseum.dk

Presents historical artifacts from the history of:

CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦1b0c4c030⟧ TextFile

    Length: 19712 (0x4d00)
    Types: TextFile
    Names: »XAMN.BAS«

Derivation

└─⟦f77262dd7⟧ Bits:30002865 SWEEP version 4.1 for JET80
    └─ ⟦this⟧ »XAMN.BAS« 

TextFile

	$lines

	REM XAMN Disk track and sector editor.
	REM No warranty is made, expressed, or implied.

	var	hl,de,bc,a_psw	; cpu registers
		dph		; location of disk parameter header
		block_size	; cp/m logical block size
		max_tracks	; number of tracks/disk
		seldsk		; bios select disk
		settrk		; bios set track routine
		setsec		; bios set sector routine
		setdma		; bios set dma address
		b_read		; bios read sector
		b_write		; bios write sector
		sectran		; bios sector skew
		disk_number	; disk number to examine
		= integer

	var	crt		; logical device
		list		; logical device
		CR		; ASCII CR
		BS		; ASCII BS
		ascii_mask	; ASCII mask
		bit_0_mask	; mask used to look at bit 0
		true, false	; true/false logical flags
		= integer

	var	menu_selection	; prompt return
		= char

	var	r1, r2, r3, r4	; Real number for computations
		= real

	based	spt		; sectors/track
		dsm		; max data block number
		drm		; number of dir blocks
		off		; number of reserved tracks
		wboot		; entry to bios
		dpb		; location of disk parameter block
		skew_table	; location of bios skew table (used by sectran)
		alv		; pointer to allocation table
		= integer

	based	bsh		; block shift factor
		blm		; block mask
		exm		; extent mask
		alloc_byte	; used in searching allocation table
		= byte


	crt = 0				rem S-BASIC device # for con:
	list = 1			rem S-BASIC device # for lst:
	CR = 0DH
	BS = 8
	ascii_mask = 007FH
	bit_0_mask = 1
	true = -1
	false = not true

	base wboot at 1			rem location of bios wboot entry
	seldsk = wboot + 0018H		rem set up bios entry address
	settrk = wboot + 001BH
	setsec = wboot + 001EH
	setdma = wboot + 0021H
	b_read = wboot + 0024H
	b_write= wboot + 0027H
	sectran= wboot + 002DH

	rem dma buffer for read/write sector operations
	dim byte sector(128)
	var loc_sector = integer
	location array loc_sector = sector
	dim base char file_chars(11) fcb_name(11)  byte_dm(15)
	dim base integer word_dm(7)

	based bios_return = byte		rem high order byte of a_psw only
	location var hl = a_psw
	base bios_return at hl+1

0seldsk	input "Disk number (0,1,...,15) ";disk_number
	bc = disk_number
	call ( seldsk, dph, de, bc, a_psw )
	if dph=0 then 0seldsk
	base skew_table at dph
	base dpb at dph+10
	base alv at dph+14
	bc = loc_sector+1
	call ( setdma, hl, de, bc, a_psw )

	base spt at dpb
	base bsh at dpb+2
	base blm at dpb+3
	base exm at dpb+4
	base dsm at dpb+5
	base drm at dpb+7
	base off at dpb+13

	block_size = 1024*(2^(bsh-3))
	r1 = ((dsm+1)*(block_size/128))/spt
	max_tracks = r1 + off

	function physical_sec ( sectr = integer ) = integer
		if skew_table=0 then sectr=sectr-1
	end = sectr

	function skew ( sectr = integer ) = integer
		if skew_table<>0 then begin
			bc = sectr - 1
			de = skew_table
			call (sectran, hl, de, bc, a_psw)
			end
		    else hl = sectr - 1
	end = hl

	procedure get_sector( track, sec = integer )
		var x = integer
		for x=1 to 128
		  sectorÆxÅ = 0
		next x
		bc = track
		call ( settrk, hl, de, bc, a_psw )
		bc = sec
		call ( setsec, hl, de, bc, a_psw )
		call ( b_read, hl, de, bc, a_psw )
		sectorÆ0Å = bios_return
	end of get_sector

	procedure put_sector( track, sec = integer )
		bc = track
		call ( settrk, hl, de, bc, a_psw )
		bc = sec
		call ( setsec, hl, de, bc, a_psw )
		call ( b_write, hl, de, bc, a_psw )
		sectorÆ0Å = bios_return
	end of put_sector

	function ascii_character ( x = integer ) = char
	  x = x and ascii_mask
	  if x<32 then x = 46
	end = x

	procedure display_sector  ( device = integer )
		var x, j = integer
		for x=1 to 128 step 16
			print hex$(x-1);"  ";
			for j=0 to 15
			  if j=8 then print ' ';
			  print #device; right$(hex$(sectorÆx+jÅ),2);' ';
			next hex byte
			for j=0 to 15
			  if j=8 then print ' ';
			  print #device; ascii_character(sectorÆx+jÅ);
			next ascii byte
			print #device
		next line of sector display
	end of display sector

0menu	print
	print
	print	"Drive number ...............";disk_number, "Current disk ";'A'+disk_number;':'
	print	"Sectors/track ..............";spt, 'Æ'; hex$(spt) ;'Å'
	print	"Tracks/Disk ................";max_tracks, 'Æ'; hex$(max_tracks) ;'Å',Ø
"XAMN Disk editor"
	print	"Number of reserved tracks ..";off, 'Æ'; hex$(off) ;'Å',Ø
"Version 1.1"
	print	"# of logical blocks ........";dsm+1, 'Æ'; hex$(dsm+1) ;'Å'
	print	"# of directory entries .....";drm+1, 'Æ'; hex$(drm) ;'Å'
	print	"Block size .................";block_size, 'Æ'; hex$(block_size) ;'Å'
	print	"128 byte sectors/block .....";block_size/128, 'Æ'; hex$(block_size/128) ;'Å'
	print	"Disk size in K .............";(dsm+1)*(2^(bsh-3)), 'Æ'; hex$( (dsm+1)*(2^(bsh-3)) ) ;'Å'

	text 0,%
							Help
		Examin a sector (physical)......... 1	 A
		Examin a sector (logical skew)..... 2	 B
		Move Sectors ...................... 3	 C
		Produce a map of a file ........... 4	 D
		Produce a map of disk ............. 5	 E
		Find bad sectors .................. 6	 F
		Compute Block from Trk & Sec ...... 7	 G
		Compute Trk & Sec from Block ...... 8	 H
		Select disk ....................... 9	 I

%
	input2 "Please enter selection ==>"; menu_selection

	var track, sectr =integer
	var letter = char

	function group ( trk, sec = integer ) = integer
		var sectrs, grp = real
		sectrs = ((trk-off)*spt)+sec-1
		grp = sectrs/(block_size/128)
	end = grp

	procedure trk_sec ( grp = integer ) = integer
		var sectrs, sec, trk = real
		sectrs = grp*(block_size/128)
		trk = sectrs/spt
		track = trk + off
		sec = sectrs-((track-off)*spt)
		sectr = sec + 1
	end

	procedure bump ( amount = integer )
		sectr = sectr + amount
		if sectr>spt then begin
			track = track +1
			if track>=max_tracks then track=max_tracks-1
			sectr = 1
			end
		if sectr<1 then begin
			track = track -1
			if track<0 then track=0
			sectr = spt
			end
	end of bump

	procedure dump_physical ( device = integer )
	    get_sector track, physical_sec(sectr)
	    print #device; "Track=";track; "  Physical sector=";sectr, Ø
		" Logical sector=";skew(sectr);
	    if sectorÆ0Å=1 then print #device; " æBADå" else print #device
	    display_sector device
	    print
	end of dump_physical

	procedure dump_logical ( device = integer )
	    get_sector track, skew(sectr)
	    print #device; "Track=";track; "   Logical sector=";sectr, Ø
		" Physical sector=";skew(sectr);
	    if sectorÆ0Å=1 then print #device; " æBADå" else print #device
	    display_sector device
	    print
	end of dump_logical

	function hex_byte ( c = char ) = char
		c = c-'0'
		if c>9 then c=c-7
	end = c

	procedure modify ( t, s = integer )
	var c=char
	var x=integer
	repeat begin
		x=1
		repeat begin
			print hex$(x-1) ;' '; right$(hex$(sectorÆxÅ),2) ;' ';Ø
				ascii_character(sectorÆxÅ);' ';
			input3 c
			if c<>'.' and c<>CR and c<>BS then begin
				sectorÆxÅ=hex_byte(c)
				input3 c
				if c<>'.' and c<>CR and c<>BS then 
					sectorÆxÅ=(sectorÆxÅ*16)+hex_byte(c)
				end
			if c='.' then x=128
			if c=BS then begin
				x = x-2
				if x<0 then x=0
				end
			if c=CR and x=128 then x=127
			print
			x=x+1
		end until x>128
		print
		print t,s
		display_sector crt
		repeat begin
			print
			input "(W)rite to disk, (C)hange more bytes, (A)bort ";c
			if c='W' then begin
				print "Writing sector to disk..."
				put_sector t, s
				if sectorÆ0Å=1 then begin
					input2 "Write fault. <ret> to continue";c
					print
					display_sector crt
					c=' '
					end
				    else
					c='A'
				end of write
		end until c='A' or c='C'
	end until c='A'
	end of procedure modify

	$page
	case menu_selection of
'1':	begin
	    input "Track, sectr"; track, sectr
	    print
	    dump_physical crt
	    repeat begin
		input "(F)oward, (B)ackward, (R)ange, (C)hange, (E)xit ";letter
		case letter of
		    'F': begin
			     bump 1
			     dump_physical crt
			     end
		    'B': begin
			     bump -1
			     dump_physical crt
			     end
		    'R': begin
				var s, c, device =integer
				input "Number of sectors to display";c
				device = crt
				for s=1 to c
				    dump_physical device
				    bump 1
				next Sector
			end of 'R'
		    'C': modify track, physical_sec(sectr)
		    end of case
		end until letter='E'
	    end of option #1
'2':	begin
	    input "Track, sectr"; track, sectr
	    print
	    dump_logical crt
	    repeat begin
		input "(F)oward, (B)ackward, (R)ange, (C)hange, (E)xit ";letter
		case letter of
		    'F': begin
			     bump 1
			     dump_logical crt
			     end
		    'B': begin
			     bump -1
			     dump_logical crt
			     end
		    'R': begin
				var s, c, device =integer
				input "Number of sectors to display";c
				device = crt
				for s=1 to c
				    dump_logical device
				    bump 1
				next Sector
			end of 'R'
		    'C': modify track, skew(sectr)
		    end of case
		end until letter='E'
	    end of option #2
'3':	begin
		var t = char
		repeat begin
		t = ' '
		while t<>'L' and t<>'P' and t<>'E' do
			input "Move (L)logical sectors, (P)hysical sectors, (E)xit ";t
		if t<>'E' then begin
			var ok = char
			var trk1, trk2, sec1, sec2, cnt, x = integer
			ok = ' '
			while ok<>'Y' and ok<>'A' do begin
				input "Source Track, Sector ";trk1, sec1
				input "Dest. Track, Sector  ";trk2, sec2
				input "Number of sectors to move";cnt
				print
				print "Source Track, Sector = ";trk1, sec1
				print "Dest. Track, Sector  = ";trk2, sec2
				print "Number of sectors to move ";cnt
				print
				input "Is the above correct (Y/N/(A)bort) ";ok
				end
			if ok<>'A' then begin
				for x=1 to cnt
					print "Reading track";trk1;" Sector";sec1;
					if t='L' then print " Physical #";skew(sec1);
					if t='P' then get_sector trk1, physical_sec(sec1)
					    else get_sector trk1, skew(sec1)
					if sectorÆ0Å<>0 then print " Fault" else print

					print "Writing track";trk2;" Sector";sec2;
					if t='L' then print " Physical #";skew(sec2);
					if t='P' then put_sector trk2, physical_sec(sec2)
					    else put_sector trk2, skew(sec2)
					if sectorÆ0Å<>0 then print " Fault" else print

					track = trk1
					sectr = sec1
					bump 1
					trk1 = track
					sec1 = sectr
					track = trk2
					sectr = sec2
					bump 1
					trk2 = track
					sec2 = sectr
				next sector
				end
			end
		end until t='E'
	end of option #3
'4':	begin
		var count	; number of sectors to search
				= integer
		var file_name	; file name to search for
				= string:12
		location var count=file_name
		locate file_chars at count
		track = off		rem starting track
		sectr = 1		rem starting sector
		input "File name (<Ret> only to skip) ";file_name
		if len(file_name)>0 then begin

			function match = integer
				var result, x = integer
				result = true
				if fcb_nameÆ0Å=0E5H then result=false else
				for x=1 to 11
					if file_charsÆxÅ<>(fcb_nameÆxÅ) and file_charsÆxÅ<>'?' Ø
						then result = false
				next x
			end = result

			procedure dump_fcb( device = integer )
				var x = integer
				print #device; "Track";track; " Sector";sectr; ' ';
				for x=1 to 11
					print #device; fcb_nameÆxÅ;
				next x
				print #device; ' ';
				if dsm>255 then
					for x=0 to 7
					    print #device; hex$(word_dmÆxÅ); ' ';
					next x
				    else
					for x=0 to 15
					    print #device; right$( hex$(byte_dmÆxÅ),2 ); ' ';
					next x
				print #device
			end

			file_name = fcb$( file_name )
			print "Search for file:";file_name
			for count = 1 to (drm+1)/4
				get_sector track, skew(sectr)
				print "Searching Track:";track; " Sector:";skew(sectr);"      ";chr(0DH);
				locate fcb_name at loc_sector+1
				locate byte_dm at loc_sector+17
				locate word_dm at loc_sector+17
				if match then dump_fcb crt
				locate fcb_name at loc_sector+33
				locate byte_dm at loc_sector+49
				locate word_dm at loc_sector+49
				if match then dump_fcb crt
				locate fcb_name at loc_sector+65
				locate byte_dm at loc_sector+81
				locate word_dm at loc_sector+81
				if match then dump_fcb crt
				locate fcb_name at loc_sector+97
				locate byte_dm at loc_sector+113
				locate word_dm at loc_sector+113
				if match then dump_fcb crt
				bump 1
			next directory sector
			var x=char
			print
			input2 "Press <Ret> to continue";x
			end
	end of option #4
'5':	begin
		function bin( x = integer ) = string
			var bits = string:8
			var y = integer
			bits = ""
			for y=1 to 8
				if x and bit_0_mask then bits="1"+bits else
					bits="0"+bits
				x=x/2
			next y
		end = bits

		bc = 14
		de = disk_number
		call(5,hl,de,bc,a_psw)	rem bdos seldsk function
		var x, y = integer
		print
		for x = 0 to (dsm/8) step 8
			print hex$(x*8);": ";
			for y = 0 to 7
			    if x+y<=(dsm/8) then begin
				base alloc_byte at alv+x+y
				print bin(alloc_byte);' ';
				end
			next y
			print
		next x
		print "Last block is";dsm+1,'Æ';hex$(dsm+1);'Å'
		input2 "Press return to cont.";x
	end of option #5
'6':	begin
		var x = real
		var t1, t2 = integer
		input "Starting track, last track ";t1,t2
		track = t1
		sectr = 1
		for x = 1 to (t2-t1+1)*spt
			print "Track:";track; " Sector:";sectr; "  ";
			get_sector track, physical_sec(sectr)
			if sectorÆ0Å<>0 then print "æBADå" else print chr(0DH);
			bump 1
		next x
		print
		input2 "Read complete, press <Ret> to cont.";x
	end of option #6
'7':	begin
		input "Track, Sector ";track,sectr
		print "Group #";group(track,sectr), hex$(group(track,sectr))
		input "Press <Ret> to cont. ";track
	end of #7
'8':	begin
		var x = integer
		input "Group number";x
		trk_sec x
		print "Track:";track,"Sector:";sectr
		input "Press <Ret> to cont.";x
	end of #8

	end of function number menu selection

	if menu_selection = '9' then 0seldsk

	case menu_selection of
'A':	begin
	    text 0,%
        	To examine a physical sector use this command.  Sectors are 
        numbered from 1 to the end of the track. Tracks are numbered from 0 
        to the end of the disk. The physical sector number displayed is the 
        sector number from 1 to end of track,  the logical sector number is 
        the number your BIOS uses to access this physical sector.
        	When  you type this command you will be asked for the track 
        and sector you wish to examine.  After you respond the sector  will 
        be displayed. You will then be asked if you want to move forward or 
        backward from your current position on the disk.  You may,  at this 
        time,  specify  a range of sectors to be displayed from the current 
        position on the disk.  You may also edit the sector making  changes 
        to it in an buffer internal to XAMN. And last but not least you can 
        exit  to the main menu.  Each option is selected by one key  press. 
        The letters are F, B, R, C, and E.
        	When  changing  a sector the sector address in hex will  be 
        displayed  along  with the hex contents of the byte and  the  ASCII 
        character it represents (Period if none). To enter a new value type 
        it in,  to move forward push return,  backward push back space, and 
        to exit push period. Upon exit you may re-edit, write the sector to 
        the disk, or abort leaving the sector on the disk un-changed.
	%
	input2 "Press <Ret> to cont.";track
	end of 'A'
'B':	begin
	    text 0,%
        	Use  this  command  to examine and  edit  logical  sectors. 
        Logical  sectors  are  the sectors that the  BDOS  refers  to,  the 
        physical sector number may be different. It is the physical sectors 
        that the BIOS access.
        	For more info see 'A' above.
	%
	input2 "Press <Ret> to cont.";track
	end of 'B'
'C':	begin
	    text 0,%
        	This command is used to move sectors around on the disk. It 
        can be used to move physical sectors or logical sectors around. The 
        main purpose for moving sectors around is to allow re-formatting of 
        a track on the disk.  First, move the data on the track you wish to 
        re-format to an unused  area of the disk. This area can be found by 
        generating a map of the disk using another of XAMN's commands  (Map 
        disk,  see also help 'E').  Second, exit XAMN and using your system 
        format utility format ONLY the track with the bad sector.  Re-enter 
        XAMN. Third, move the data back onto the track.
        	This command will start by asking you if this is a physical 
        move or a logical move (use logical if you want to move CP/M groups 
        around).  You can exit at this point.  Next,  you will be asked for 
        the  starting  track and sector number,  the destination track  and 
        sector and the number of sectors to move.
        	BEFORE  each sector is read or written you will be told  of 
        it,  if  an error occurs you can see where it  happens.  AFTER  the 
        operation  the  program will move on to the next sector if  all  is 
        well or print "Fault" to show a read or write error.
	%
	input2 "Press <Ret> to cont.";track
	end of 'C'
'D':	begin
	    text 0,%
        	This command generates a map of a file showing all the CP/M 
        groups  assigned  to that file.  It also reports on  the  directory 
        sectors  that contain that file's FCB.  As each directory sector is 
        searched a report of that operation is made sector by sector.
	%
	input2 "Press <Ret> to cont.";track
	end of 'D'
'E':	begin
	    text 0,%
        	This command generated a disk map showing allocated groups. 
        A 0 is an empty group,  un-used by any file.  A 1 is a group in use 
        by a file. WARNING: this command makes a BDOS disk select call.
        	At the end of the map a few groups that do not exist may be 
        displayed  as  empty.  This is because the disk map is made  up  of 
        bytes where each bit in the byte is a group,  the last byte in  the 
        map may not be fully used up.  At the end of the map the last group 
        number is given, use this number.
        	This command can be used to find unused disk space. 
	%
	input2 "Press <Ret> to cont.";track
	end of 'E'
'F':	begin
	    text 0,%
        	This command is used to find a bad sector.  It will ask for 
        a  starting track and an ending track.  As it reads each track  and 
        sector  it  will  report  its progress.  Any bad  sectors  will  be 
        reported.
	%
	input2 "Press <Ret> to cont.";track
	end of 'F'
'G':	begin
	    text 0,%
        	Use  this  command  to  compute a  group  number  from  the 
        LOGICAL  track and sector.  Remember that  logical groups start  in 
        the directory, NOT in the reserved, or 'OFF' tracks.
	%
	input2 "Press <Ret> to cont.";track
	end of 'G'
'H':	begin
	    text 0,%
        	Use  this command to compute the track and  LOGICAL  sector 
        number for a given group.
	%
	input2 "Press <Ret> to cont.";track
	end of 'H'
'I':	begin
	    text 0,%
        	Use  this command to select another disk. XAMN commands are 
        in reference to the current disk number (see the display above  the 
        menu).
	%
	input2 "Press <Ret> to cont.";track
	end of 'I'
	end of help case statement

	if menu_selection=03H then stop

	goto 0menu
«eof»