fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 338 lines 6.4 kB view raw
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}