Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* vax780_fload.c: VAX780 FLOAD command\r |
2 | \r | |
3 | Copyright (c) 2006-2008, Robert M Supnik\r | |
4 | \r | |
5 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
6 | copy of this software and associated documentation files (the "Software"),\r | |
7 | to deal in the Software without restriction, including without limitation\r | |
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
9 | and/or sell copies of the Software, and to permit persons to whom the\r | |
10 | Software is furnished to do so, subject to the following conditions:\r | |
11 | \r | |
12 | The above copyright notice and this permission notice shall be included in\r | |
13 | all copies or substantial portions of the Software.\r | |
14 | \r | |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
21 | \r | |
22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r | |
23 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
24 | in this Software without prior written authorization from Robert M Supnik.\r | |
25 | \r | |
26 | This code is based on the CP/M RT11 utility, which bears the following\r | |
27 | copyrights:\r | |
28 | \r | |
29 | copyright (c) 1980, William C. Colley, III\r | |
30 | \r | |
31 | Rev. 1.2 -- Craig Davenport - Incitec Ltd (Feb 1984)\r | |
32 | P O Box 140\r | |
33 | Morningside,\r | |
34 | Qld 4170,\r | |
35 | Australia.\r | |
36 | -- Modified for Digital Research C compiler under CP/M-86\r | |
37 | -- Assebmbly language routines added for BIOS calls etc.\r | |
38 | \r | |
39 | Thanks to Phil Budne for the original adaptation of RT11 to SimH.\r | |
40 | \r | |
41 | 28-May-08 RMS Inlined physical memory routines\r | |
42 | */\r | |
43 | \r | |
44 | #include "vax_defs.h"\r | |
45 | #include <ctype.h>\r | |
46 | \r | |
47 | #define BLK_SIZE 256 /* RT11 block size */\r | |
48 | \r | |
49 | /* Floppy disk parameters */\r | |
50 | \r | |
51 | #define BPT 26 /* blocks/track */\r | |
52 | #define NTRACKS 77\r | |
53 | #define SECTOR_SKEW 2\r | |
54 | #define TRACK_SKEW 6\r | |
55 | #define TRACK_OFFSET 1 /* track 0 unused */\r | |
56 | \r | |
57 | /* RT11 directory segment (2 blocks = 512 16b words) */\r | |
58 | \r | |
59 | #define DS_TOTAL 0 /* segments available */\r | |
60 | #define DS_MAX 31 /* segment max */\r | |
61 | #define DS_NEXT 1 /* zero for last segment */\r | |
62 | #define DS_HIGHEST 2 /* only in 1st segment */\r | |
63 | #define DS_EXTRA 3 /* extra bytes/entry */\r | |
64 | #define DS_FIRST 4 /* first block */\r | |
65 | #define DS_ENTRIES 5 /* start of entries */\r | |
66 | #define DS_SIZE (2 * BLK_SIZE) /* segment size, words */\r | |
67 | \r | |
68 | /* RT11 directory entry offsets */\r | |
69 | \r | |
70 | #define DE_STATUS 0 /* status (odd byte) */\r | |
71 | #define TENTAT 001 /* tentative */\r | |
72 | #define EMPTY 002\r | |
73 | #define PERM 004\r | |
74 | #define ENDSEG 010 /* end of segment */\r | |
75 | #define DE_NAME 1 /* file name */\r | |
76 | #define DE_FLNT 4 /* file length */\r | |
77 | #define DE_SIZE 7 /* entry size in words */\r | |
78 | #define DE_GET_STAT(x) (((x) >> 8) & 0377)\r | |
79 | \r | |
80 | extern UNIT cpu_unit;\r | |
81 | extern UNIT fl_unit;\r | |
82 | \r | |
83 | t_bool rtfile_parse (char *pntr, uint16 *file_name);\r | |
84 | uint32 rtfile_lookup (uint16 *file_name, uint32 *start);\r | |
85 | uint32 rtfile_ator50 (uint32 ascii);\r | |
86 | t_bool rtfile_read (uint32 block, uint32 count, uint16 *buffer);\r | |
87 | uint32 rtfile_find (uint32 block, uint32 sector);\r | |
88 | \r | |
89 | /* FLOAD file_name {file_origin} */\r | |
90 | \r | |
91 | t_stat vax780_fload (int flag, char *cptr)\r | |
92 | {\r | |
93 | char gbuf[CBUFSIZE];\r | |
94 | uint16 file_name[3], blkbuf[BLK_SIZE];\r | |
95 | t_stat r;\r | |
96 | uint32 i, j, start, size, origin;\r | |
97 | \r | |
98 | if ((fl_unit.flags & UNIT_ATT) == 0) /* floppy attached? */\r | |
99 | return SCPE_UNATT;\r | |
100 | if (*cptr == 0) return SCPE_2FARG;\r | |
101 | cptr = get_glyph (cptr, gbuf, 0); /* get file name */\r | |
102 | if (!rtfile_parse (gbuf, file_name)) /* legal file name? */\r | |
103 | return SCPE_ARG;\r | |
104 | if ((size = rtfile_lookup (file_name, &start)) == 0) /* file on floppy? */\r | |
105 | return SCPE_ARG;\r | |
106 | if (*cptr) { /* origin? */\r | |
107 | origin = (uint32) get_uint (cptr, 16, MEMSIZE, &r);\r | |
108 | if ((r != SCPE_OK) || (origin & 1)) /* must be even */\r | |
109 | return SCPE_ARG;\r | |
110 | }\r | |
111 | else origin = 512; /* no, use default */\r | |
112 | \r | |
113 | for (i = 0; i < size; i++) { /* loop thru blocks */\r | |
114 | if (!rtfile_read (start + i, 1, blkbuf)) /* read block */\r | |
115 | return SCPE_FMT;\r | |
116 | for (j = 0; j < BLK_SIZE; j++) { /* loop thru words */\r | |
117 | if (ADDR_IS_MEM (origin))\r | |
118 | WriteW (origin, blkbuf[j]);\r | |
119 | else return SCPE_NXM;\r | |
120 | origin = origin + 2;\r | |
121 | }\r | |
122 | }\r | |
123 | return SCPE_OK;\r | |
124 | }\r | |
125 | \r | |
126 | /* Parse an RT11 file name and convert it to radix-50 */\r | |
127 | \r | |
128 | t_bool rtfile_parse (char *pntr, uint16 *file_name)\r | |
129 | {\r | |
130 | char c;\r | |
131 | uint16 d;\r | |
132 | uint32 i, j;\r | |
133 | \r | |
134 | file_name[0] = file_name[1] = file_name[2] = 0; /* zero file name */\r | |
135 | for (i = 0; i < 2; i++) { /* 6 characters */\r | |
136 | for (j = 0; j < 3; j++) {\r | |
137 | c = *pntr;\r | |
138 | if ((c == '.') || (c == 0)) d = 0; /* fill if . or end */\r | |
139 | else {\r | |
140 | if ((d = rtfile_ator50 (c)) == 0) return FALSE;\r | |
141 | pntr++;\r | |
142 | }\r | |
143 | file_name[i] = (file_name[i] * 050) + d; /* merge into name */\r | |
144 | }\r | |
145 | }\r | |
146 | if (file_name[0] == 0) return FALSE; /* no name? lose */\r | |
147 | while ((c = *pntr++) != '.') { /* scan for . */\r | |
148 | if (c == 0) return TRUE; /* end? done */\r | |
149 | }\r | |
150 | for (i = 0; i < 3; i++) { /* 3 characters */\r | |
151 | c = *pntr;\r | |
152 | if (c == 0) d = 0; /* fill if end */\r | |
153 | else {\r | |
154 | if ((d = rtfile_ator50 (c)) == 0) return FALSE;\r | |
155 | pntr++;\r | |
156 | }\r | |
157 | file_name[2] = (file_name[2] * 050) + d; /* merge into ext */\r | |
158 | }\r | |
159 | return TRUE;\r | |
160 | }\r | |
161 | \r | |
162 | /* ASCII to radix-50 conversion */\r | |
163 | \r | |
164 | uint32 rtfile_ator50 (uint32 ascii)\r | |
165 | {\r | |
166 | static char *r50 = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";\r | |
167 | char *fptr;\r | |
168 | \r | |
169 | ascii = toupper (ascii);\r | |
170 | if ((fptr = strchr (r50, toupper (ascii))) != NULL)\r | |
171 | return ((uint32) (fptr - r50));\r | |
172 | else return 0;\r | |
173 | }\r | |
174 | \r | |
175 | /* Lookup an RT11 file name in the directory */\r | |
176 | \r | |
177 | uint32 rtfile_lookup (uint16 *file_name, uint32 *start)\r | |
178 | {\r | |
179 | uint16 dirseg[DS_SIZE];\r | |
180 | uint32 segnum, dirent;\r | |
181 | \r | |
182 | for (segnum = 1; /* loop thru segments */\r | |
183 | (segnum != 0) && (segnum <= DS_MAX);\r | |
184 | segnum = dirseg[DS_NEXT]) {\r | |
185 | if (!rtfile_read ((segnum * 2) + 4, 2, dirseg)) /* read segment */\r | |
186 | return 0; /* error? */\r | |
187 | *start = dirseg[DS_FIRST]; /* init file start */\r | |
188 | for (dirent = DS_ENTRIES; /* loop thru entries */\r | |
189 | (dirent < DS_SIZE) &&\r | |
190 | (DE_GET_STAT (dirseg[dirent + DE_STATUS]) != ENDSEG);\r | |
191 | dirent += DE_SIZE + (dirseg[DS_EXTRA] / 2)) {\r | |
192 | if ((DE_GET_STAT (dirseg[dirent + DE_STATUS]) == PERM) &&\r | |
193 | (dirseg[dirent + DE_NAME + 0] == file_name[0]) &&\r | |
194 | (dirseg[dirent + DE_NAME + 1] == file_name[1]) &&\r | |
195 | (dirseg[dirent + DE_NAME + 2] == file_name[2]))\r | |
196 | return dirseg[dirent + DE_FLNT];\r | |
197 | *start += dirseg[dirent + DE_FLNT]; /* incr file start */\r | |
198 | }\r | |
199 | }\r | |
200 | return 0;\r | |
201 | }\r | |
202 | \r | |
203 | /* Read blocks */\r | |
204 | \r | |
205 | t_stat rtfile_read (uint32 block, uint32 count, uint16 *buffer)\r | |
206 | {\r | |
207 | uint32 i, j;\r | |
208 | uint32 pos;\r | |
209 | uint8 *fbuf = fl_unit.filebuf;\r | |
210 | \r | |
211 | for (; count > 0; count--, block++) {\r | |
212 | for (i = 0; i < 4; i++) { /* 4 sectors/block */\r | |
213 | pos = rtfile_find (block, i); /* position */\r | |
214 | if ((pos + 128) >= (uint32) fl_unit.capac) /* off end of disk? */\r | |
215 | return FALSE;\r | |
216 | for (j = 0; j < 128; j = j + 2) /* copy 128 bytes */\r | |
217 | *buffer++ = (((uint16) fbuf[pos + j + 1]) << 8) |\r | |
218 | ((uint16) fbuf[pos + j]);\r | |
219 | }\r | |
220 | }\r | |
221 | return TRUE;\r | |
222 | }\r | |
223 | \r | |
224 | /* Map an RT-11 block number to a physical byte number */\r | |
225 | \r | |
226 | uint32 rtfile_find (uint32 block, uint32 sector)\r | |
227 | {\r | |
228 | uint32 ls, lt, pt, ps;\r | |
229 | uint32 off, bb;\r | |
230 | \r | |
231 | /* get logical block, track & sector */\r | |
232 | \r | |
233 | bb = (block * 4) + sector;\r | |
234 | \r | |
235 | lt = bb / BPT;\r | |
236 | ls = bb % BPT;\r | |
237 | \r | |
238 | /* logic from 4.3BSD rx.c\r | |
239 | * calculate phys track & sector\r | |
240 | * 2:1 skew, 6 sector skew for each track\r | |
241 | */\r | |
242 | \r | |
243 | pt = lt + TRACK_OFFSET;\r | |
244 | ps = ((ls * SECTOR_SKEW) + (ls / (BPT / SECTOR_SKEW)) + (TRACK_SKEW * lt)) % BPT;\r | |
245 | \r | |
246 | /* byte offset in logical disk */\r | |
247 | \r | |
248 | off = (pt * BPT + ps) * 128;\r | |
249 | return off;\r | |
250 | }\r |