First Commit of my working state
[simh.git] / VAX / vax780_fload.c
CommitLineData
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
80extern UNIT cpu_unit;\r
81extern UNIT fl_unit;\r
82\r
83t_bool rtfile_parse (char *pntr, uint16 *file_name);\r
84uint32 rtfile_lookup (uint16 *file_name, uint32 *start);\r
85uint32 rtfile_ator50 (uint32 ascii);\r
86t_bool rtfile_read (uint32 block, uint32 count, uint16 *buffer);\r
87uint32 rtfile_find (uint32 block, uint32 sector);\r
88\r
89/* FLOAD file_name {file_origin} */\r
90\r
91t_stat vax780_fload (int flag, char *cptr)\r
92{\r
93char gbuf[CBUFSIZE];\r
94uint16 file_name[3], blkbuf[BLK_SIZE];\r
95t_stat r;\r
96uint32 i, j, start, size, origin;\r
97\r
98if ((fl_unit.flags & UNIT_ATT) == 0) /* floppy attached? */\r
99 return SCPE_UNATT;\r
100if (*cptr == 0) return SCPE_2FARG;\r
101cptr = get_glyph (cptr, gbuf, 0); /* get file name */\r
102if (!rtfile_parse (gbuf, file_name)) /* legal file name? */\r
103 return SCPE_ARG;\r
104if ((size = rtfile_lookup (file_name, &start)) == 0) /* file on floppy? */\r
105 return SCPE_ARG;\r
106if (*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
111else origin = 512; /* no, use default */\r
112\r
113for (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
123return SCPE_OK;\r
124}\r
125\r
126/* Parse an RT11 file name and convert it to radix-50 */\r
127\r
128t_bool rtfile_parse (char *pntr, uint16 *file_name)\r
129{\r
130char c;\r
131uint16 d;\r
132uint32 i, j;\r
133\r
134file_name[0] = file_name[1] = file_name[2] = 0; /* zero file name */\r
135for (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
146if (file_name[0] == 0) return FALSE; /* no name? lose */\r
147while ((c = *pntr++) != '.') { /* scan for . */\r
148 if (c == 0) return TRUE; /* end? done */\r
149 }\r
150for (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
159return TRUE;\r
160}\r
161\r
162/* ASCII to radix-50 conversion */\r
163\r
164uint32 rtfile_ator50 (uint32 ascii)\r
165{\r
166static char *r50 = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";\r
167char *fptr;\r
168\r
169ascii = toupper (ascii);\r
170if ((fptr = strchr (r50, toupper (ascii))) != NULL)\r
171 return ((uint32) (fptr - r50));\r
172else return 0;\r
173}\r
174\r
175/* Lookup an RT11 file name in the directory */\r
176\r
177uint32 rtfile_lookup (uint16 *file_name, uint32 *start)\r
178{\r
179uint16 dirseg[DS_SIZE];\r
180uint32 segnum, dirent;\r
181\r
182for (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
200return 0;\r
201}\r
202\r
203/* Read blocks */\r
204\r
205t_stat rtfile_read (uint32 block, uint32 count, uint16 *buffer)\r
206{\r
207uint32 i, j;\r
208uint32 pos;\r
209uint8 *fbuf = fl_unit.filebuf;\r
210\r
211for (; 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
221return TRUE;\r
222}\r
223\r
224/* Map an RT-11 block number to a physical byte number */\r
225\r
226uint32 rtfile_find (uint32 block, uint32 sector)\r
227{\r
228uint32 ls, lt, pt, ps;\r
229uint32 off, bb;\r
230\r
231/* get logical block, track & sector */\r
232\r
233bb = (block * 4) + sector;\r
234\r
235lt = bb / BPT;\r
236ls = 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
243pt = lt + TRACK_OFFSET;\r
244ps = ((ls * SECTOR_SKEW) + (ls / (BPT / SECTOR_SKEW)) + (TRACK_SKEW * lt)) % BPT;\r
245\r
246/* byte offset in logical disk */\r
247\r
248off = (pt * BPT + ps) * 128;\r
249return off;\r
250}\r