fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/utils/pfi/fold.c *
7 * Created: 2019-06-19 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2019-2021 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include <drivers/pfi/pfi.h>
31#include <drivers/pfi/track.h>
32
33
34typedef struct {
35 pfi_trk_t *trk;
36
37 unsigned long c;
38 unsigned long h;
39
40 unsigned long wdw;
41 unsigned long cnt;
42
43 char only_right;
44
45 unsigned rev1;
46 unsigned rev2;
47
48 unsigned long idx0pos;
49 unsigned long idx0rem;
50
51 unsigned long idx1pos;
52 unsigned long idx1rem;
53} pfi_fold_t;
54
55
56static
57int fold_get_index_pos (pfi_fold_t *fold, unsigned rev)
58{
59 unsigned long i, n;
60 unsigned long idx0, idx1, clk;
61 unsigned done;
62 uint32_t *pulse;
63
64 if ((rev < 1) || (rev >= fold->trk->index_cnt)) {
65 return (1);
66 }
67
68 idx0 = fold->trk->index[rev - 1];
69 idx1 = fold->trk->index[rev];
70
71 n = fold->trk->pulse_cnt;
72 pulse = fold->trk->pulse;
73
74 clk = 0;
75
76 done = 0;
77
78 for (i = 0; i < n; i++) {
79 if ((clk <= idx0) && ((clk + pulse[i]) > idx0)) {
80 fold->idx0pos = i;
81 fold->idx0rem = idx0 - clk;
82 done |= 1;
83
84 if (done == 3) {
85 return (0);
86 }
87 }
88
89 if ((clk <= idx1) && ((clk + pulse[i]) > idx1)) {
90 fold->idx1pos = i;
91 fold->idx1rem = idx1 - clk;
92 done |= 2;
93
94 if (done == 3) {
95 return (0);
96 }
97 }
98
99 clk += pulse[i];
100 }
101
102 return (1);
103}
104
105static
106void fold_set_index (pfi_fold_t *fold, unsigned idx, unsigned long pos, unsigned long rem)
107{
108 unsigned long i;
109 unsigned long clk, clk0, diff;
110 int sub;
111 uint32_t *pulse;
112
113 if (idx >= fold->trk->index_cnt) {
114 return;
115 }
116
117 if (pos >= fold->trk->pulse_cnt) {
118 pos = fold->trk->pulse_cnt;
119 }
120
121 pulse = fold->trk->pulse;
122
123 clk0 = (idx > 0) ? fold->trk->index[idx - 1] : 0;
124
125 clk = rem;
126
127 for (i = 0; i < pos; i++) {
128 clk += pulse[i];
129 }
130
131 if (clk < fold->trk->index[idx]) {
132 diff = fold->trk->index[idx] - clk;
133 sub = 1;
134 }
135 else {
136 diff = clk - fold->trk->index[idx];
137 sub = 0;
138 }
139
140 if (par_verbose) {
141 fprintf (stderr, "track %lu/%lu index %u %lu (%c%lu)\n",
142 fold->c, fold->h,
143 idx,
144 clk - clk0,
145 sub ? '-' : '+',
146 diff
147 );
148 }
149
150 for (i = idx; i < fold->trk->index_cnt; i++) {
151 if (sub) {
152 fold->trk->index[i] -= diff;
153 }
154 else {
155 fold->trk->index[i] += diff;
156 }
157 }
158}
159
160static
161unsigned long fold_get_diff (const uint32_t *p1, const uint32_t *p2, unsigned long cnt)
162{
163 unsigned long i;
164 unsigned long val, tmp, dif;
165
166 val = 0;
167
168 for (i = 0; i < cnt; i++) {
169 dif = (*p1 < *p2) ? (*p2 - *p1) : (*p1 - *p2);
170
171 tmp = val;
172 val += dif * dif;
173
174 if (val < tmp) {
175 return (-1);
176 }
177
178 p1 += 1;
179 p2 += 1;
180 }
181
182 return (val);
183}
184
185static
186int fold_revolution (pfi_fold_t *fold, unsigned rev)
187{
188 unsigned long i, n;
189 unsigned long p1, p2;
190 unsigned long w1, w2;
191 unsigned long val, opt_val, opt_pos;
192 pfi_trk_t *trk;
193
194 trk = fold->trk;
195
196 if (fold_get_index_pos (fold, rev)) {
197 return (1);
198 }
199
200 if (fold->idx1pos < fold->wdw / 2) {
201 w1 = 0;
202 }
203 else {
204 w1 = fold->idx1pos - fold->wdw / 2;
205 }
206
207 if ((fold->idx1pos + fold->wdw / 2) >= trk->pulse_cnt) {
208 w2 = trk->pulse_cnt - 1;
209 }
210 else {
211 w2 = fold->idx1pos + fold->wdw / 2;
212 }
213
214 opt_val = -1;
215 opt_pos = 0;
216
217 for (i = w1; i <= w2; i++) {
218 p1 = fold->idx0pos;
219 p2 = i;
220 n = fold->cnt;
221
222 if (fold->only_right == 0) {
223 if (p1 >= (fold->cnt / 2)) {
224 p2 -= fold->cnt / 2;
225 p1 -= fold->cnt / 2;
226 }
227 else {
228 p2 -= p1;
229 p1 = 0;
230 }
231 }
232
233 if ((p2 + n) >= fold->trk->pulse_cnt) {
234 unsigned long k;
235
236 k = p2 + n - fold->trk->pulse_cnt;
237
238 if (p1 < k) {
239 p2 -= p1;
240 p1 = 0;
241 fprintf (stderr, "%lu/%lu: fold overrun (rev=%u)\n",
242 fold->c, fold->h, rev
243 );
244 return (1);
245 }
246 else {
247 p1 -= k;
248 p2 -= k;
249 }
250
251 n = fold->trk->pulse_cnt - p2;
252 }
253
254 val = fold_get_diff (trk->pulse + p1, trk->pulse + p2, n);
255
256 if (val < opt_val) {
257 opt_val = val;
258 opt_pos = i;
259 }
260 }
261
262 if (opt_pos != 0) {
263 if (opt_val > (64 * fold->cnt)) {
264 fprintf (stderr, "%lu/%lu: POS=%lu DIF=%lu AVG=%lu\n",
265 fold->c, fold->h,
266 opt_pos, opt_val, opt_val / fold->cnt
267 );
268 }
269
270 fold_set_index (fold, rev, opt_pos, fold->idx0rem);
271 }
272
273 return (0);
274}
275
276static
277int fold_track (pfi_fold_t *fold)
278{
279 unsigned r, r1, r2;
280
281 if (fold->trk->index_cnt < 2) {
282 return (0);
283 }
284
285 r1 = fold->rev1;
286 r2 = fold->rev2;
287
288 if (r1 < 1) {
289 r1 = 1;
290 }
291
292 if (r2 >= fold->trk->index_cnt) {
293 r2 = fold->trk->index_cnt - 1;
294 }
295
296 for (r = r1; r <= r2; r++) {
297 fold_revolution (fold, r);
298 }
299
300 return (0);
301}
302
303static
304int pfi_fold_cb (pfi_img_t *img, pfi_trk_t *trk, unsigned long c, unsigned long h, void *opaque)
305{
306 pfi_fold_t *fold;
307
308 fold = opaque;
309
310 fold->trk = trk;
311 fold->c = c;
312 fold->h = h;
313
314 fold_track (fold);
315
316 return (0);
317}
318
319int pfi_fold (pfi_img_t *img)
320{
321 pfi_fold_t fold;
322
323 fold.only_right = par_pfi_fold_right;
324
325 if (par_pfi_fold_revolution == 0) {
326 fold.rev1 = 1;
327 fold.rev2 = -1;
328 }
329 else {
330 fold.rev1 = par_pfi_fold_revolution;
331 fold.rev2 = par_pfi_fold_revolution;
332 }
333
334 fold.wdw = par_pfi_fold_window;
335 fold.cnt = par_pfi_fold_compare;
336
337 return (pfi_for_all_tracks (img, pfi_fold_cb, &fold));
338}