c74e3f930c5e14c1aa377e69bc70d2bc79429eeb
1 /* vax780_fload.c: VAX780 FLOAD command
3 Copyright (c) 2006-2008, Robert M Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
26 This code is based on the CP/M RT11 utility, which bears the following
29 copyright (c) 1980, William C. Colley, III
31 Rev. 1.2 -- Craig Davenport - Incitec Ltd (Feb 1984)
36 -- Modified for Digital Research C compiler under CP/M-86
37 -- Assebmbly language routines added for BIOS calls etc.
39 Thanks to Phil Budne for the original adaptation of RT11 to SimH.
41 28-May-08 RMS Inlined physical memory routines
47 #define BLK_SIZE 256 /* RT11 block size */
49 /* Floppy disk parameters */
51 #define BPT 26 /* blocks/track */
55 #define TRACK_OFFSET 1 /* track 0 unused */
57 /* RT11 directory segment (2 blocks = 512 16b words) */
59 #define DS_TOTAL 0 /* segments available */
60 #define DS_MAX 31 /* segment max */
61 #define DS_NEXT 1 /* zero for last segment */
62 #define DS_HIGHEST 2 /* only in 1st segment */
63 #define DS_EXTRA 3 /* extra bytes/entry */
64 #define DS_FIRST 4 /* first block */
65 #define DS_ENTRIES 5 /* start of entries */
66 #define DS_SIZE (2 * BLK_SIZE) /* segment size, words */
68 /* RT11 directory entry offsets */
70 #define DE_STATUS 0 /* status (odd byte) */
71 #define TENTAT 001 /* tentative */
74 #define ENDSEG 010 /* end of segment */
75 #define DE_NAME 1 /* file name */
76 #define DE_FLNT 4 /* file length */
77 #define DE_SIZE 7 /* entry size in words */
78 #define DE_GET_STAT(x) (((x) >> 8) & 0377)
83 t_bool
rtfile_parse (char *pntr
, uint16
*file_name
);
84 uint32
rtfile_lookup (uint16
*file_name
, uint32
*start
);
85 uint32
rtfile_ator50 (uint32 ascii
);
86 t_bool
rtfile_read (uint32 block
, uint32 count
, uint16
*buffer
);
87 uint32
rtfile_find (uint32 block
, uint32 sector
);
89 /* FLOAD file_name {file_origin} */
91 t_stat
vax780_fload (int flag
, char *cptr
)
94 uint16 file_name
[3], blkbuf
[BLK_SIZE
];
96 uint32 i
, j
, start
, size
, origin
;
98 if ((fl_unit
.flags
& UNIT_ATT
) == 0) /* floppy attached? */
100 if (*cptr
== 0) return SCPE_2FARG
;
101 cptr
= get_glyph (cptr
, gbuf
, 0); /* get file name */
102 if (!rtfile_parse (gbuf
, file_name
)) /* legal file name? */
104 if ((size
= rtfile_lookup (file_name
, &start
)) == 0) /* file on floppy? */
106 if (*cptr
) { /* origin? */
107 origin
= (uint32
) get_uint (cptr
, 16, MEMSIZE
, &r
);
108 if ((r
!= SCPE_OK
) || (origin
& 1)) /* must be even */
111 else origin
= 512; /* no, use default */
113 for (i
= 0; i
< size
; i
++) { /* loop thru blocks */
114 if (!rtfile_read (start
+ i
, 1, blkbuf
)) /* read block */
116 for (j
= 0; j
< BLK_SIZE
; j
++) { /* loop thru words */
117 if (ADDR_IS_MEM (origin
))
118 WriteW (origin
, blkbuf
[j
]);
119 else return SCPE_NXM
;
126 /* Parse an RT11 file name and convert it to radix-50 */
128 t_bool
rtfile_parse (char *pntr
, uint16
*file_name
)
134 file_name
[0] = file_name
[1] = file_name
[2] = 0; /* zero file name */
135 for (i
= 0; i
< 2; i
++) { /* 6 characters */
136 for (j
= 0; j
< 3; j
++) {
138 if ((c
== '.') || (c
== 0)) d
= 0; /* fill if . or end */
140 if ((d
= rtfile_ator50 (c
)) == 0) return FALSE
;
143 file_name
[i
] = (file_name
[i
] * 050) + d
; /* merge into name */
146 if (file_name
[0] == 0) return FALSE
; /* no name? lose */
147 while ((c
= *pntr
++) != '.') { /* scan for . */
148 if (c
== 0) return TRUE
; /* end? done */
150 for (i
= 0; i
< 3; i
++) { /* 3 characters */
152 if (c
== 0) d
= 0; /* fill if end */
154 if ((d
= rtfile_ator50 (c
)) == 0) return FALSE
;
157 file_name
[2] = (file_name
[2] * 050) + d
; /* merge into ext */
162 /* ASCII to radix-50 conversion */
164 uint32
rtfile_ator50 (uint32 ascii
)
166 static char *r50
= " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
169 ascii
= toupper (ascii
);
170 if ((fptr
= strchr (r50
, toupper (ascii
))) != NULL
)
171 return ((uint32
) (fptr
- r50
));
175 /* Lookup an RT11 file name in the directory */
177 uint32
rtfile_lookup (uint16
*file_name
, uint32
*start
)
179 uint16 dirseg
[DS_SIZE
];
180 uint32 segnum
, dirent
;
182 for (segnum
= 1; /* loop thru segments */
183 (segnum
!= 0) && (segnum
<= DS_MAX
);
184 segnum
= dirseg
[DS_NEXT
]) {
185 if (!rtfile_read ((segnum
* 2) + 4, 2, dirseg
)) /* read segment */
186 return 0; /* error? */
187 *start
= dirseg
[DS_FIRST
]; /* init file start */
188 for (dirent
= DS_ENTRIES
; /* loop thru entries */
189 (dirent
< DS_SIZE
) &&
190 (DE_GET_STAT (dirseg
[dirent
+ DE_STATUS
]) != ENDSEG
);
191 dirent
+= DE_SIZE
+ (dirseg
[DS_EXTRA
] / 2)) {
192 if ((DE_GET_STAT (dirseg
[dirent
+ DE_STATUS
]) == PERM
) &&
193 (dirseg
[dirent
+ DE_NAME
+ 0] == file_name
[0]) &&
194 (dirseg
[dirent
+ DE_NAME
+ 1] == file_name
[1]) &&
195 (dirseg
[dirent
+ DE_NAME
+ 2] == file_name
[2]))
196 return dirseg
[dirent
+ DE_FLNT
];
197 *start
+= dirseg
[dirent
+ DE_FLNT
]; /* incr file start */
205 t_stat
rtfile_read (uint32 block
, uint32 count
, uint16
*buffer
)
209 uint8
*fbuf
= fl_unit
.filebuf
;
211 for (; count
> 0; count
--, block
++) {
212 for (i
= 0; i
< 4; i
++) { /* 4 sectors/block */
213 pos
= rtfile_find (block
, i
); /* position */
214 if ((pos
+ 128) >= (uint32
) fl_unit
.capac
) /* off end of disk? */
216 for (j
= 0; j
< 128; j
= j
+ 2) /* copy 128 bytes */
217 *buffer
++ = (((uint16
) fbuf
[pos
+ j
+ 1]) << 8) |
218 ((uint16
) fbuf
[pos
+ j
]);
224 /* Map an RT-11 block number to a physical byte number */
226 uint32
rtfile_find (uint32 block
, uint32 sector
)
228 uint32 ls
, lt
, pt
, ps
;
231 /* get logical block, track & sector */
233 bb
= (block
* 4) + sector
;
238 /* logic from 4.3BSD rx.c
239 * calculate phys track & sector
240 * 2:1 skew, 6 sector skew for each track
243 pt
= lt
+ TRACK_OFFSET
;
244 ps
= ((ls
* SECTOR_SKEW
) + (ls
/ (BPT
/ SECTOR_SKEW
)) + (TRACK_SKEW
* lt
)) % BPT
;
246 /* byte offset in logical disk */
248 off
= (pt
* BPT
+ ps
) * 128;