Compare commits
13 commits
img-writec
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0351c481c0 | ||
|
|
ca7144b454 | ||
|
|
e829d827da | ||
|
|
c6310b803b | ||
|
|
3946e7f7a6 | ||
|
|
18ecd15be9 | ||
|
|
ae4245018d | ||
|
|
cbbac4e3c2 | ||
|
|
69e2c545a3 | ||
|
|
959fd9a4a0 | ||
|
|
da6188ae7e | ||
|
|
9ac66c313e | ||
|
|
25742f6ecf |
14 changed files with 358 additions and 157 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -5,7 +5,7 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set environment variables
|
- name: Set environment variables
|
||||||
id: vars
|
id: vars
|
||||||
|
|
@ -43,7 +43,7 @@ jobs:
|
||||||
mv flashfloppy-$VER.zip _cidist/
|
mv flashfloppy-$VER.zip _cidist/
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: FlashFloppy.CI.${{ steps.vars.outputs.sha_short }}
|
name: FlashFloppy.CI.${{ steps.vars.outputs.sha_short }}
|
||||||
path: _cidist
|
path: _cidist
|
||||||
|
|
|
||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
|
@ -10,7 +10,7 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set environment variables
|
- name: Set environment variables
|
||||||
id: vars
|
id: vars
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,11 @@
|
||||||
** Keir Fraser <keir.xen@gmail.com>
|
** Keir Fraser <keir.xen@gmail.com>
|
||||||
************************************
|
************************************
|
||||||
|
|
||||||
|
** v3.42 - 11 January 2024
|
||||||
|
- HFEv3: Various read/write improvements
|
||||||
|
- WDATA: Merge short write pulses, and apply de-jitter/precomp
|
||||||
|
- IMG, EDSK: Stream large sector writes to flash
|
||||||
|
|
||||||
** v3.41 - 14 July 2023
|
** v3.41 - 14 July 2023
|
||||||
- AT32F415: Fix timer handling since clock speed increase (v3.39).
|
- AT32F415: Fix timer handling since clock speed increase (v3.39).
|
||||||
- LCD: Faster power-on initialisation. Don't wait for display to clear.
|
- LCD: Faster power-on initialisation. Don't wait for display to clear.
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@
|
||||||
# jc: Specified by jumper JC (open: shugart, closed: ibmpc)
|
# jc: Specified by jumper JC (open: shugart, closed: ibmpc)
|
||||||
# shugart: P2=DSKCHG, P34=RDY (Amiga, Atari ST, many others)
|
# shugart: P2=DSKCHG, P34=RDY (Amiga, Atari ST, many others)
|
||||||
# ibmpc: P2=unused, P34=DSKCHG (IBM PC interface)
|
# ibmpc: P2=unused, P34=DSKCHG (IBM PC interface)
|
||||||
# ibmpc-hdout: P2=HD_OUT, P34=DSKCHG (not generally needed: prefer 'ibmpc')
|
# ibmpc-hdout: P2=HD_OUT, P34=DSKCHG (not generally needed: prefer ibmpc)
|
||||||
# jppc: P2=unused, P34=RDY (Japanese PC standard)
|
# jppc: P2=unused, P34=RDY (Japanese PC standard)
|
||||||
# jppc-hdout: P2=HD_OUT, P34=RDY (Japanese PC alternate: prefer 'jppc')
|
# jppc-hdout: P2=HD_OUT, P34=RDY (Japanese PC alternate: prefer jppc)
|
||||||
# akai-s950: Legacy alias of 'jppc-hdout', previously used for Akai S950
|
# akai-s950: Legacy alias of jppc-hdout, previously used for Akai S950
|
||||||
# amiga: P2=DSKCHG, P34=DRIVE_ID (not generally needed: prefer 'shugart')
|
# amiga: P2=DSKCHG, P34=DRIVE_ID (not generally needed: prefer shugart)
|
||||||
interface = jc
|
interface = jc
|
||||||
|
|
||||||
# Host platform: Improves image-format detection for generic types such as IMG
|
# Host platform: Improves image-format detection for generic types such as IMG
|
||||||
|
|
@ -172,9 +172,9 @@ twobutton-action = zero
|
||||||
# Input sensor type at the rotary-encoder inputs (pins PC10 and PC11):
|
# Input sensor type at the rotary-encoder inputs (pins PC10 and PC11):
|
||||||
# [full | half | quarter]:
|
# [full | half | quarter]:
|
||||||
# Rotary encoder, identified by fraction of a Gray-code cycle performed
|
# Rotary encoder, identified by fraction of a Gray-code cycle performed
|
||||||
# per detent/click. If default value ('full') requires multiple
|
# per detent/click. If default value (full) requires multiple
|
||||||
# clicks/detents to move position then change to 'half' (if 2 clicks
|
# clicks/detents to move position then change to half (if 2 clicks
|
||||||
# per move) or 'quarter' (if 4 clicks).
|
# per move) or quarter (if 4 clicks).
|
||||||
# [trackball]:
|
# [trackball]:
|
||||||
# Blackberry-style trackball (eg. using Hall-effect sensors).
|
# Blackberry-style trackball (eg. using Hall-effect sensors).
|
||||||
# [buttons]:
|
# [buttons]:
|
||||||
|
|
@ -220,15 +220,15 @@ oled-font = 6x13
|
||||||
oled-contrast = 143
|
oled-contrast = 143
|
||||||
|
|
||||||
# Text height and arrangement on LCD/OLED and on OSD, respectively.
|
# Text height and arrangement on LCD/OLED and on OSD, respectively.
|
||||||
# 'default', or a comma-separated list (one entry per LCD/OLED row, top down).
|
# Comma-separated list, one entry per display row, top down.
|
||||||
# Each list item is a digit plus optional height specifier: <content-row>[d]
|
# Each list item is a digit plus optional height specifier: [0-7][d]
|
||||||
# content-row: '0-3' = specified content row, '7' = blank
|
# content-row: 0-3 = specified content, 7 = blank
|
||||||
# 0: Current image name
|
# 0: Current image name
|
||||||
# 1: Status
|
# 1: Status
|
||||||
# 2: Image/Volume info
|
# 2: Image/Volume info
|
||||||
# 3: Current subfolder name
|
# 3: Current subfolder name
|
||||||
# height specifier: 'd' = double height (32px, OLED only; ignored for LCD)
|
# height-specifier: d = double height (32px, OLED only; ignored for LCD)
|
||||||
# 'default' depends on display, eg.: oled-128x32='0,1' ; oled-128x64='3,0d,1'
|
# Default depends on display, eg.: oled-128x32 -> 0,1 ; oled-128x64 -> 3,0d,1
|
||||||
# Values: [0-7][d] | default
|
# Values: [0-7][d] | default
|
||||||
display-order = default
|
display-order = default
|
||||||
osd-display-order = default
|
osd-display-order = default
|
||||||
|
|
|
||||||
17
examples/Host/GRiD/IMG.CFG
Normal file
17
examples/Host/GRiD/IMG.CFG
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
## IMG.CFG for machines produced by GRiD Systems Corp.
|
||||||
|
|
||||||
|
# NOTE: The tags match on filesize alone. If you wish to define an explicit
|
||||||
|
# tagname match, you can for example add 'flex' to the square-bracketed tags
|
||||||
|
# to limit matches to filenames of the form *.flex.{img,ima,dsk}
|
||||||
|
|
||||||
|
# 360k 40-cylinder DS/DD format used by GRiD Compass
|
||||||
|
[::368640]
|
||||||
|
cyls = 40
|
||||||
|
heads = 2
|
||||||
|
bps = 512
|
||||||
|
secs = 9
|
||||||
|
mode = mfm
|
||||||
|
interleave = 5
|
||||||
|
id = 1
|
||||||
|
tracks = 0-39.1
|
||||||
|
id = 10
|
||||||
45
examples/Host/Sinclair_ZX_Spectrum/Sandy_FDD2/IMG.CFG
Normal file
45
examples/Host/Sinclair_ZX_Spectrum/Sandy_FDD2/IMG.CFG
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
## IMG.CFG for the Sandy FDD2 interface.
|
||||||
|
|
||||||
|
# Sandy FDD2 is a clone of the FDC-1 by Technology Research Ltd.
|
||||||
|
# Using a 1771 controller chip, it supports single-density (FM) recording
|
||||||
|
# only, unlike the later Beta Disk interfaces.
|
||||||
|
|
||||||
|
# *.ss40.img: Single-sided 40 cylinders.
|
||||||
|
[ss40::102400]
|
||||||
|
cyls = 40
|
||||||
|
heads = 1
|
||||||
|
secs = 10
|
||||||
|
bps = 256
|
||||||
|
mode = fm
|
||||||
|
interleave = 2
|
||||||
|
|
||||||
|
# *.ss80.img: Single-sided 80 cylinders.
|
||||||
|
[ss80::204800]
|
||||||
|
cyls = 80
|
||||||
|
heads = 1
|
||||||
|
secs = 10
|
||||||
|
bps = 256
|
||||||
|
mode = fm
|
||||||
|
interleave = 2
|
||||||
|
|
||||||
|
# *.ds40.img: Double-sided 40 cylinders.
|
||||||
|
[ds40::204800]
|
||||||
|
cyls = 40
|
||||||
|
heads = 2
|
||||||
|
secs = 10
|
||||||
|
bps = 256
|
||||||
|
mode = fm
|
||||||
|
interleave = 2
|
||||||
|
tracks = 0-39.1
|
||||||
|
h = 0
|
||||||
|
|
||||||
|
# *.ds80.img: Double-sided 80 cylinders.
|
||||||
|
[ds80::409600]
|
||||||
|
cyls = 80
|
||||||
|
heads = 2
|
||||||
|
secs = 10
|
||||||
|
bps = 256
|
||||||
|
mode = fm
|
||||||
|
interleave = 2
|
||||||
|
tracks = 0-79.1
|
||||||
|
h = 0
|
||||||
|
|
@ -69,6 +69,8 @@ int snprintf(char *str, size_t size, const char *format, ...)
|
||||||
#define htobe16(x) _rev16(x)
|
#define htobe16(x) _rev16(x)
|
||||||
#define htobe32(x) _rev32(x)
|
#define htobe32(x) _rev32(x)
|
||||||
|
|
||||||
|
uint32_t udiv64(uint64_t dividend, uint32_t divisor);
|
||||||
|
|
||||||
/* Arena-based memory allocation */
|
/* Arena-based memory allocation */
|
||||||
void *arena_alloc(uint32_t sz);
|
void *arena_alloc(uint32_t sz);
|
||||||
uint32_t arena_total(void);
|
uint32_t arena_total(void);
|
||||||
|
|
|
||||||
|
|
@ -674,7 +674,7 @@ static void IRQ_wdata_dma(void)
|
||||||
bc_dat = image->write_bc_window;
|
bc_dat = image->write_bc_window;
|
||||||
for (cons = dma_wr->cons; cons != prod; cons = (cons+1) & buf_mask) {
|
for (cons = dma_wr->cons; cons != prod; cons = (cons+1) & buf_mask) {
|
||||||
next = dma_wr->buf[cons];
|
next = dma_wr->buf[cons];
|
||||||
curr = (uint16_t)(next - prev) - (cell >> 1);
|
curr = (int16_t)(next - prev) - (cell >> 1);
|
||||||
if (unlikely(curr < 0)) {
|
if (unlikely(curr < 0)) {
|
||||||
/* Runt flux, much shorter than bitcell clock. Merge it forward. */
|
/* Runt flux, much shorter than bitcell clock. Merge it forward. */
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -686,6 +686,8 @@ static void IRQ_wdata_dma(void)
|
||||||
if (!(bc_prod&31))
|
if (!(bc_prod&31))
|
||||||
bc_buf[((bc_prod-1) / 32) & bc_bufmask] = htobe32(bc_dat);
|
bc_buf[((bc_prod-1) / 32) & bc_bufmask] = htobe32(bc_dat);
|
||||||
}
|
}
|
||||||
|
curr += cell >> 1; /* remove the 1/2-cell bias */
|
||||||
|
prev -= curr >> 2; /* de-jitter/precomp: carry 1/4 of phase error */
|
||||||
bc_dat = (bc_dat << 1) | 1;
|
bc_dat = (bc_dat << 1) | 1;
|
||||||
bc_prod++;
|
bc_prod++;
|
||||||
switch (sync) {
|
switch (sync) {
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ static bool_t adf_open(struct image *im)
|
||||||
im->tracklen_bc = DD_TRACKLEN_BC;
|
im->tracklen_bc = DD_TRACKLEN_BC;
|
||||||
im->ticks_per_cell = ((sampleclk_stk(im->stk_per_rev) * 16u)
|
im->ticks_per_cell = ((sampleclk_stk(im->stk_per_rev) * 16u)
|
||||||
/ im->tracklen_bc);
|
/ im->tracklen_bc);
|
||||||
|
im->write_bc_ticks = im->ticks_per_cell / 16u;
|
||||||
|
|
||||||
im->nr_cyls = f_size(&im->fp) / (2 * 11 * 512);
|
im->nr_cyls = f_size(&im->fp) / (2 * 11 * 512);
|
||||||
|
|
||||||
|
|
|
||||||
132
src/image/dsk.c
132
src/image/dsk.c
|
|
@ -271,15 +271,17 @@ static void dsk_setup_track(
|
||||||
im->cur_ticks = im->cur_bc * im->ticks_per_cell;
|
im->cur_ticks = im->cur_bc * im->ticks_per_cell;
|
||||||
im->ticks_since_flux = 0;
|
im->ticks_since_flux = 0;
|
||||||
|
|
||||||
decode_off = calc_start_pos(im);
|
|
||||||
|
|
||||||
rd->prod = rd->cons = 0;
|
rd->prod = rd->cons = 0;
|
||||||
bc->prod = bc->cons = 0;
|
bc->prod = bc->cons = 0;
|
||||||
|
|
||||||
if (start_pos) {
|
if (start_pos) {
|
||||||
|
decode_off = calc_start_pos(im);
|
||||||
|
|
||||||
image_read_track(im);
|
image_read_track(im);
|
||||||
bc->cons = decode_off * 16;
|
bc->cons = decode_off * 16;
|
||||||
*start_pos = start_ticks;
|
*start_pos = start_ticks;
|
||||||
|
} else {
|
||||||
|
im->dsk.decode_pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -481,10 +483,9 @@ static bool_t dsk_write_track(struct image *im)
|
||||||
unsigned int bufmask = (wr->len / 2) - 1;
|
unsigned int bufmask = (wr->len / 2) - 1;
|
||||||
uint8_t *wrbuf = (uint8_t *)im->bufs.write_data.p + 512; /* skip DIB/TIB */
|
uint8_t *wrbuf = (uint8_t *)im->bufs.write_data.p + 512; /* skip DIB/TIB */
|
||||||
uint32_t c = wr->cons / 16, p = wr->prod / 16;
|
uint32_t c = wr->cons / 16, p = wr->prod / 16;
|
||||||
unsigned int i;
|
unsigned int i, off;
|
||||||
time_t t;
|
time_t t;
|
||||||
uint16_t crc, off;
|
uint16_t crc = im->dsk.crc;
|
||||||
uint8_t x;
|
|
||||||
|
|
||||||
/* If we are processing final data then use the end index, rounded up. */
|
/* If we are processing final data then use the end index, rounded up. */
|
||||||
barrier();
|
barrier();
|
||||||
|
|
@ -494,77 +495,103 @@ static bool_t dsk_write_track(struct image *im)
|
||||||
|
|
||||||
while ((int16_t)(p - c) > 128) {
|
while ((int16_t)(p - c) > 128) {
|
||||||
|
|
||||||
uint32_t sc = c;
|
if (im->dsk.decode_pos == 0) {
|
||||||
|
|
||||||
if (be16toh(buf[c++ & bufmask]) != 0x4489)
|
uint8_t x;
|
||||||
continue;
|
|
||||||
if ((x = mfmtobin(buf[c & bufmask])) == 0xa1)
|
|
||||||
continue;
|
|
||||||
c++;
|
|
||||||
|
|
||||||
switch (x) {
|
if (be16toh(buf[c++ & bufmask]) != 0x4489)
|
||||||
|
continue;
|
||||||
|
if ((x = mfmtobin(buf[c & bufmask])) == 0xa1)
|
||||||
|
continue;
|
||||||
|
c++;
|
||||||
|
|
||||||
case 0xfe: /* IDAM */
|
switch (x) {
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
wrbuf[i] = 0xa1;
|
case 0xfe: /* IDAM */
|
||||||
wrbuf[i++] = x;
|
for (i = 0; i < 3; i++)
|
||||||
for (; i < 10; i++)
|
wrbuf[i] = 0xa1;
|
||||||
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
wrbuf[i++] = x;
|
||||||
crc = crc16_ccitt(wrbuf, i, 0xffff);
|
for (; i < 10; i++)
|
||||||
if (crc != 0) {
|
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
||||||
log("IDAM Bad CRC: %04x, %02x\n", crc, wrbuf[6]);
|
crc = crc16_ccitt(wrbuf, i, 0xffff);
|
||||||
|
if (crc != 0) {
|
||||||
|
log("IDAM Bad CRC: %04x, %02x\n", crc, wrbuf[6]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Convert logical sector number -> rotational number. */
|
||||||
|
for (i = 0; i < tib->nr_secs; i++)
|
||||||
|
if (wrbuf[6] == tib->sib[i].r)
|
||||||
|
break;
|
||||||
|
im->dsk.write_sector = i;
|
||||||
|
if (im->dsk.write_sector >= tib->nr_secs) {
|
||||||
|
log("IDAM Bad Sector: %02x\n", wrbuf[6]);
|
||||||
|
im->dsk.write_sector = -2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xfb: /* DAM */
|
||||||
|
im->dsk.decode_pos = 1;
|
||||||
|
im->dsk.decode_data_pos = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Convert logical sector number -> rotational number. */
|
|
||||||
for (i = 0; i < tib->nr_secs; i++)
|
|
||||||
if (wrbuf[6] == tib->sib[i].r)
|
|
||||||
break;
|
|
||||||
im->dsk.write_sector = i;
|
|
||||||
if (im->dsk.write_sector >= tib->nr_secs) {
|
|
||||||
log("IDAM Bad Sector: %02x\n", wrbuf[6]);
|
|
||||||
im->dsk.write_sector = -2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xfb: /* DAM */ {
|
} else {
|
||||||
unsigned int nr, todo, sec_sz;
|
|
||||||
|
/* Data record, shy address mark */
|
||||||
|
unsigned int sec_sz;
|
||||||
int sec_nr = im->dsk.write_sector;
|
int sec_nr = im->dsk.write_sector;
|
||||||
|
|
||||||
|
ASSERT(im->dsk.decode_pos == 1);
|
||||||
|
|
||||||
if (sec_nr < 0) {
|
if (sec_nr < 0) {
|
||||||
if (sec_nr == -1)
|
if (sec_nr == -1) {
|
||||||
sec_nr = dsk_find_first_write_sector(im, write, tib);
|
sec_nr = dsk_find_first_write_sector(im, write, tib);
|
||||||
|
im->dsk.write_sector = sec_nr;
|
||||||
|
}
|
||||||
if (sec_nr < 0) {
|
if (sec_nr < 0) {
|
||||||
log("DAM Unknown\n");
|
log("DAM Unknown\n");
|
||||||
goto dam_out;
|
goto data_complete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sec_sz = data_sz(&tib->sib[sec_nr]);
|
sec_sz = data_sz(&tib->sib[sec_nr]);
|
||||||
if ((int16_t)(p - c) < (sec_sz + 2)) {
|
|
||||||
c = sc;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
crc = MFM_DAM_CRC;
|
|
||||||
|
|
||||||
log("Write %u[%02x]/%u... ",
|
|
||||||
sec_nr, tib->sib[sec_nr].r, tib->nr_secs);
|
|
||||||
t = time_now();
|
|
||||||
|
|
||||||
for (i = off = 0; i < sec_nr; i++)
|
for (i = off = 0; i < sec_nr; i++)
|
||||||
off += tib->sib[i].actual_length;
|
off += tib->sib[i].actual_length;
|
||||||
F_lseek(&im->fp, im->dsk.trk_off + off);
|
off += im->dsk.trk_off;
|
||||||
|
off += im->dsk.decode_data_pos;
|
||||||
|
|
||||||
for (todo = sec_sz; todo != 0; todo -= nr) {
|
if (im->dsk.decode_data_pos < sec_sz) {
|
||||||
nr = min_t(unsigned int, todo, CHUNK_SIZE);
|
unsigned int nr = sec_sz - im->dsk.decode_data_pos;
|
||||||
|
nr = min_t(unsigned int, nr, CHUNK_SIZE - (off & 511));
|
||||||
|
if ((int16_t)(p - c) < nr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!im->dsk.decode_data_pos) {
|
||||||
|
crc = MFM_DAM_CRC;
|
||||||
|
log("Write %d[%02x]/%u...",
|
||||||
|
sec_nr, tib->sib[sec_nr].r, tib->nr_secs);
|
||||||
|
F_lseek(&im->fp, off);
|
||||||
|
}
|
||||||
|
|
||||||
|
t = time_now();
|
||||||
mfm_ring_to_bin(buf, bufmask, c, wrbuf, nr);
|
mfm_ring_to_bin(buf, bufmask, c, wrbuf, nr);
|
||||||
c += nr;
|
c += nr;
|
||||||
crc = crc16_ccitt(wrbuf, nr, crc);
|
crc = crc16_ccitt(wrbuf, nr, crc);
|
||||||
F_write(&im->fp, wrbuf, nr, NULL);
|
F_write(&im->fp, wrbuf, nr, NULL);
|
||||||
|
printk(" %u us", time_diff(t, time_now()) / TIME_MHZ);
|
||||||
|
im->dsk.decode_data_pos += nr;
|
||||||
|
if (im->dsk.decode_data_pos < sec_sz)
|
||||||
|
printk("...");
|
||||||
|
else
|
||||||
|
printk("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("%u us\n", time_diff(t, time_now()) / TIME_MHZ);
|
if (im->dsk.decode_data_pos < sec_sz)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((int16_t)(p - c) < 2)
|
||||||
|
break;
|
||||||
mfm_ring_to_bin(buf, bufmask, c, wrbuf, 2);
|
mfm_ring_to_bin(buf, bufmask, c, wrbuf, 2);
|
||||||
c += 2;
|
c += 2;
|
||||||
crc = crc16_ccitt(wrbuf, 2, crc);
|
crc = crc16_ccitt(wrbuf, 2, crc);
|
||||||
|
|
@ -573,15 +600,14 @@ static bool_t dsk_write_track(struct image *im)
|
||||||
crc, sec_nr, tib->sib[sec_nr].r);
|
crc, sec_nr, tib->sib[sec_nr].r);
|
||||||
}
|
}
|
||||||
|
|
||||||
dam_out:
|
data_complete:
|
||||||
im->dsk.write_sector = -2;
|
im->dsk.write_sector = -2;
|
||||||
break;
|
im->dsk.decode_pos = 0;
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
im->dsk.crc = crc;
|
||||||
wr->cons = c * 16;
|
wr->cons = c * 16;
|
||||||
return flush;
|
return flush;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,9 +128,10 @@ static void hfe_seek_track(struct image *im, uint16_t track)
|
||||||
im->hfe.trk_off = le16toh(thdr.offset);
|
im->hfe.trk_off = le16toh(thdr.offset);
|
||||||
im->hfe.trk_len = le16toh(thdr.len) / 2;
|
im->hfe.trk_len = le16toh(thdr.len) / 2;
|
||||||
im->tracklen_bc = im->hfe.trk_len * 8;
|
im->tracklen_bc = im->hfe.trk_len * 8;
|
||||||
/* Opcodes in v3 make it difficult to predict the track's length. Keep the
|
if (im->hfe.is_v3 && im->tracklen_ticks) {
|
||||||
* previous track's value if this isn't the first seek. */
|
/* Opcodes in v3 make it difficult to predict the track's length. Keep
|
||||||
if (!(im->hfe.is_v3 && im->tracklen_ticks)) {
|
* the previous track's value since this isn't the first seek. */
|
||||||
|
} else {
|
||||||
im->tracklen_ticks = im->tracklen_bc * im->ticks_per_cell;
|
im->tracklen_ticks = im->tracklen_bc * im->ticks_per_cell;
|
||||||
im->stk_per_rev = stk_sampleclk(im->tracklen_ticks / 16);
|
im->stk_per_rev = stk_sampleclk(im->tracklen_ticks / 16);
|
||||||
}
|
}
|
||||||
|
|
@ -152,13 +153,16 @@ static void hfe_setup_track(
|
||||||
hfe_seek_track(im, track);
|
hfe_seek_track(im, track);
|
||||||
|
|
||||||
start_ticks = start_pos ? *start_pos : get_write(im, im->wr_cons)->start;
|
start_ticks = start_pos ? *start_pos : get_write(im, im->wr_cons)->start;
|
||||||
im->cur_bc = (start_ticks * 16) / im->ticks_per_cell;
|
|
||||||
if (im->cur_bc >= im->tracklen_bc)
|
|
||||||
im->cur_bc = 0;
|
|
||||||
im->cur_ticks = im->cur_bc * im->ticks_per_cell;
|
|
||||||
im->ticks_since_flux = 0;
|
|
||||||
|
|
||||||
start_ticks = im->cur_ticks / 16;
|
im->cur_ticks = start_ticks * 16;
|
||||||
|
im->cur_bc = udiv64((uint64_t)im->cur_ticks * im->tracklen_bc,
|
||||||
|
im->tracklen_ticks);
|
||||||
|
if ((im->cur_ticks >= im->tracklen_ticks) ||
|
||||||
|
(im->cur_bc >= im->tracklen_bc)) {
|
||||||
|
im->cur_ticks = 0;
|
||||||
|
im->cur_bc = 0;
|
||||||
|
}
|
||||||
|
im->ticks_since_flux = 0;
|
||||||
|
|
||||||
rd->prod = rd->cons = 0;
|
rd->prod = rd->cons = 0;
|
||||||
bc->prod = bc->cons = 0;
|
bc->prod = bc->cons = 0;
|
||||||
|
|
@ -172,10 +176,16 @@ static void hfe_setup_track(
|
||||||
im->hfe.trk_pos = (im->cur_bc/8) & ~255;
|
im->hfe.trk_pos = (im->cur_bc/8) & ~255;
|
||||||
image_read_track(im);
|
image_read_track(im);
|
||||||
bc->cons = im->cur_bc & 2047;
|
bc->cons = im->cur_bc & 2047;
|
||||||
*start_pos = start_ticks;
|
|
||||||
} else {
|
} else {
|
||||||
/* Write mode. */
|
/* Write mode. */
|
||||||
im->hfe.trk_pos = im->cur_bc / 8;
|
im->hfe.trk_pos = im->cur_bc / 8;
|
||||||
|
if (im->hfe.is_v3) {
|
||||||
|
/* Provide context to the write to avoid corrupting an opcode. */
|
||||||
|
if ((im->hfe.trk_pos & 255) == 0 && im->hfe.trk_pos != 0)
|
||||||
|
im->hfe.trk_pos--;
|
||||||
|
else if ((im->hfe.trk_pos & 255) == 1)
|
||||||
|
im->hfe.trk_pos = (im->hfe.trk_pos+1) % im->hfe.trk_len;
|
||||||
|
}
|
||||||
im->hfe.write.start = im->hfe.trk_pos;
|
im->hfe.write.start = im->hfe.trk_pos;
|
||||||
im->hfe.write.wrapped = FALSE;
|
im->hfe.write.wrapped = FALSE;
|
||||||
im->hfe.write_batch.len = 0;
|
im->hfe.write_batch.len = 0;
|
||||||
|
|
@ -270,6 +280,7 @@ static uint16_t hfe_rdata_flux(struct image *im, uint16_t *tbuf, uint16_t nr)
|
||||||
x = _rbit32(bc_b[(bc_c/8) & bc_mask]) >> 24;
|
x = _rbit32(bc_b[(bc_c/8) & bc_mask]) >> 24;
|
||||||
im->ticks_per_cell = ticks_per_cell =
|
im->ticks_per_cell = ticks_per_cell =
|
||||||
(sampleclk_us(2) * 16 * x) / 72;
|
(sampleclk_us(2) * 16 * x) / 72;
|
||||||
|
im->write_bc_ticks = ticks_per_cell / 16;
|
||||||
bc_c += 8;
|
bc_c += 8;
|
||||||
im->cur_bc += 8;
|
im->cur_bc += 8;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -330,6 +341,7 @@ static bool_t hfe_write_track(struct image *im)
|
||||||
unsigned int bufmask = wr->len - 1;
|
unsigned int bufmask = wr->len - 1;
|
||||||
uint8_t *w, *wrbuf = im->bufs.write_data.p;
|
uint8_t *w, *wrbuf = im->bufs.write_data.p;
|
||||||
uint32_t i, space, c = wr->cons / 8, p = wr->prod / 8;
|
uint32_t i, space, c = wr->cons / 8, p = wr->prod / 8;
|
||||||
|
bool_t is_v3 = im->hfe.is_v3;
|
||||||
bool_t writeback = FALSE;
|
bool_t writeback = FALSE;
|
||||||
time_t t;
|
time_t t;
|
||||||
|
|
||||||
|
|
@ -381,11 +393,62 @@ static bool_t hfe_write_track(struct image *im)
|
||||||
+ (im->cur_track & 1) * 256
|
+ (im->cur_track & 1) * 256
|
||||||
+ batch_off - im->hfe.write_batch.off
|
+ batch_off - im->hfe.write_batch.off
|
||||||
+ (off & 255);
|
+ (off & 255);
|
||||||
for (i = 0; i < nr; i++)
|
|
||||||
*w++ = _rbit32(buf[c++ & bufmask]) >> 24;
|
i = 0;
|
||||||
|
|
||||||
|
if (is_v3 && off == im->hfe.write.start && off != 0) {
|
||||||
|
/* Avoid starting write in the middle of an opcode. */
|
||||||
|
if (w[-2] == OP_SkipBits) {
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
switch (w[-1]) {
|
||||||
|
case OP_SkipBits:
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
case OP_Bitrate:
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < nr) {
|
||||||
|
if (is_v3 && (w[i] & 0xf) == 0xf) {
|
||||||
|
switch (w[i]) {
|
||||||
|
case OP_SkipBits:
|
||||||
|
/* Keep the write byte-aligned. This changes the length of
|
||||||
|
* the track by 8+skip bitcells, but overwriting OP_SkipBits
|
||||||
|
* should be rare. */
|
||||||
|
w[i++] = OP_Nop;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case OP_Bitrate:
|
||||||
|
/* Assume bitrate does not change significantly for the
|
||||||
|
* entire track, and write_bc_ticks already adjusted when
|
||||||
|
* reading. */
|
||||||
|
i += 2;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case OP_Nop:
|
||||||
|
case OP_Index:
|
||||||
|
default:
|
||||||
|
/* Preserve opcode. But making sure not to write past end of
|
||||||
|
* buffer. */
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case OP_Rand:
|
||||||
|
/* Replace with data. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w[i++] = _rbit32(buf[c++ & bufmask]) >> 24;
|
||||||
|
}
|
||||||
im->hfe.write_batch.dirty = TRUE;
|
im->hfe.write_batch.dirty = TRUE;
|
||||||
|
|
||||||
im->hfe.trk_pos += nr;
|
im->hfe.trk_pos += i; /* i may be larger than nr due to opcodes. */
|
||||||
if (im->hfe.trk_pos >= im->hfe.trk_len) {
|
if (im->hfe.trk_pos >= im->hfe.trk_len) {
|
||||||
ASSERT(im->hfe.trk_pos == im->hfe.trk_len);
|
ASSERT(im->hfe.trk_pos == im->hfe.trk_len);
|
||||||
im->hfe.trk_pos = 0;
|
im->hfe.trk_pos = 0;
|
||||||
|
|
|
||||||
176
src/image/img.c
176
src/image/img.c
|
|
@ -1876,15 +1876,17 @@ static void raw_setup_track(
|
||||||
im->cur_ticks = im->cur_bc * im->ticks_per_cell;
|
im->cur_ticks = im->cur_bc * im->ticks_per_cell;
|
||||||
im->ticks_since_flux = 0;
|
im->ticks_since_flux = 0;
|
||||||
|
|
||||||
decode_off = calc_start_pos(im);
|
|
||||||
|
|
||||||
rd->prod = rd->cons = 0;
|
rd->prod = rd->cons = 0;
|
||||||
bc->prod = bc->cons = 0;
|
bc->prod = bc->cons = 0;
|
||||||
|
|
||||||
if (start_pos) {
|
if (start_pos) {
|
||||||
|
decode_off = calc_start_pos(im);
|
||||||
|
|
||||||
image_read_track(im);
|
image_read_track(im);
|
||||||
bc->cons = decode_off * 16;
|
bc->cons = decode_off * 16;
|
||||||
*start_pos = start_ticks;
|
*start_pos = start_ticks;
|
||||||
|
} else {
|
||||||
|
im->img.decode_pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1963,8 +1965,8 @@ static bool_t raw_write_track(struct image *im)
|
||||||
struct raw_sec *sec;
|
struct raw_sec *sec;
|
||||||
unsigned int i, off;
|
unsigned int i, off;
|
||||||
time_t t;
|
time_t t;
|
||||||
uint16_t crc;
|
uint16_t crc = im->img.crc;
|
||||||
uint8_t idam_r, x;
|
uint8_t idam_r;
|
||||||
|
|
||||||
/* If we are processing final data then use the end index, rounded up. */
|
/* If we are processing final data then use the end index, rounded up. */
|
||||||
barrier();
|
barrier();
|
||||||
|
|
@ -1974,110 +1976,137 @@ static bool_t raw_write_track(struct image *im)
|
||||||
|
|
||||||
while ((int16_t)(p - c) > 128) {
|
while ((int16_t)(p - c) > 128) {
|
||||||
|
|
||||||
uint32_t sc = c;
|
if (im->img.decode_pos == 0) {
|
||||||
|
|
||||||
if (im->sync == SYNC_fm) {
|
uint8_t x;
|
||||||
|
|
||||||
uint16_t sync;
|
|
||||||
if (buf[c++ & bufmask] != 0xaaaa)
|
|
||||||
continue;
|
|
||||||
sync = buf[c & bufmask];
|
|
||||||
if (mfmtobin(sync >> 1) != FM_SYNC_CLK)
|
|
||||||
continue;
|
|
||||||
x = mfmtobin(sync);
|
|
||||||
c++;
|
|
||||||
|
|
||||||
} else { /* MFM */
|
|
||||||
|
|
||||||
if (be16toh(buf[c++ & bufmask]) != 0x4489)
|
|
||||||
continue;
|
|
||||||
if ((x = mfmtobin(buf[c & bufmask])) == 0xa1)
|
|
||||||
continue;
|
|
||||||
c++;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (x) {
|
|
||||||
|
|
||||||
case 0xfe: /* IDAM */
|
|
||||||
if (im->sync == SYNC_fm) {
|
if (im->sync == SYNC_fm) {
|
||||||
wrbuf[0] = x;
|
|
||||||
for (i = 1; i < 7; i++)
|
uint16_t sync;
|
||||||
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
if (buf[c++ & bufmask] != 0xaaaa)
|
||||||
idam_r = wrbuf[3];
|
continue;
|
||||||
|
sync = buf[c & bufmask];
|
||||||
|
if (mfmtobin(sync >> 1) != FM_SYNC_CLK)
|
||||||
|
continue;
|
||||||
|
x = mfmtobin(sync);
|
||||||
|
c++;
|
||||||
|
|
||||||
} else { /* MFM */
|
} else { /* MFM */
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
wrbuf[i] = 0xa1;
|
if (be16toh(buf[c++ & bufmask]) != 0x4489)
|
||||||
wrbuf[i++] = x;
|
continue;
|
||||||
for (; i < 10; i++)
|
if ((x = mfmtobin(buf[c & bufmask])) == 0xa1)
|
||||||
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
continue;
|
||||||
idam_r = wrbuf[6];
|
c++;
|
||||||
|
|
||||||
}
|
}
|
||||||
crc = crc16_ccitt(wrbuf, i, 0xffff);
|
|
||||||
if (crc != 0) {
|
switch (x) {
|
||||||
log("IDAM Bad CRC: %04x, %u\n", crc, idam_r);
|
|
||||||
|
case 0xfe: /* IDAM */
|
||||||
|
if (im->sync == SYNC_fm) {
|
||||||
|
wrbuf[0] = x;
|
||||||
|
for (i = 1; i < 7; i++)
|
||||||
|
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
||||||
|
idam_r = wrbuf[3];
|
||||||
|
} else { /* MFM */
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
wrbuf[i] = 0xa1;
|
||||||
|
wrbuf[i++] = x;
|
||||||
|
for (; i < 10; i++)
|
||||||
|
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
||||||
|
idam_r = wrbuf[6];
|
||||||
|
}
|
||||||
|
crc = crc16_ccitt(wrbuf, i, 0xffff);
|
||||||
|
if (crc != 0) {
|
||||||
|
log("IDAM Bad CRC: %04x, %u\n", crc, idam_r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Search by sector id for this sector's logical order. */
|
||||||
|
for (i = 0, sec = im->img.sec_info;
|
||||||
|
(i < trk->nr_sectors) && (sec->r != idam_r);
|
||||||
|
i++, sec++)
|
||||||
|
continue;
|
||||||
|
im->img.write_sector = i;
|
||||||
|
if (i >= trk->nr_sectors) {
|
||||||
|
log("IDAM Bad Sector: %02x\n", idam_r);
|
||||||
|
im->img.write_sector = -2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xfb: /* DAM */
|
||||||
|
im->img.decode_pos = 1;
|
||||||
|
im->img.decode_data_pos = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Search by sector id for this sector's logical order. */
|
|
||||||
for (i = 0, sec = im->img.sec_info;
|
|
||||||
(i < trk->nr_sectors) && (sec->r != idam_r);
|
|
||||||
i++, sec++)
|
|
||||||
continue;
|
|
||||||
im->img.write_sector = i;
|
|
||||||
if (i >= trk->nr_sectors) {
|
|
||||||
log("IDAM Bad Sector: %02x\n", idam_r);
|
|
||||||
im->img.write_sector = -2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xfb: /* DAM */ {
|
} else {
|
||||||
unsigned int nr, todo, sec_sz;
|
|
||||||
|
/* Data record, shy address mark */
|
||||||
|
unsigned int sec_sz;
|
||||||
int sec_nr = im->img.write_sector;
|
int sec_nr = im->img.write_sector;
|
||||||
|
|
||||||
|
ASSERT(im->img.decode_pos == 1);
|
||||||
|
|
||||||
if (sec_nr < 0) {
|
if (sec_nr < 0) {
|
||||||
if (sec_nr == -1)
|
if (sec_nr == -1) {
|
||||||
sec_nr = raw_find_first_write_sector(im, write, trk);
|
sec_nr = raw_find_first_write_sector(im, write, trk);
|
||||||
|
im->img.write_sector = sec_nr;
|
||||||
|
}
|
||||||
if (sec_nr < 0) {
|
if (sec_nr < 0) {
|
||||||
log("DAM Unknown\n");
|
log("DAM Unknown\n");
|
||||||
goto dam_out;
|
goto data_complete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sec_sz = sec_sz(im->img.sec_info[sec_nr].n);
|
sec_sz = sec_sz(im->img.sec_info[sec_nr].n);
|
||||||
if ((int16_t)(p - c) < (sec_sz + 2)) {
|
|
||||||
c = sc;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
crc = (im->sync == SYNC_fm) ? FM_DAM_CRC : MFM_DAM_CRC;
|
|
||||||
|
|
||||||
sec = &im->img.sec_info[sec_nr];
|
sec = &im->img.sec_info[sec_nr];
|
||||||
log("Write %u[%02x]/%u... ", sec_nr, sec->r, trk->nr_sectors);
|
|
||||||
t = time_now();
|
|
||||||
|
|
||||||
if (im->img.file_sec_offsets) {
|
if (im->img.file_sec_offsets) {
|
||||||
off = im->img.file_sec_offsets[sec_nr];
|
off = im->img.file_sec_offsets[sec_nr];
|
||||||
} else if (trk->img_bps != 0) {
|
} else if (trk->img_bps != 0) {
|
||||||
off = sec_nr * trk->img_bps;
|
off = sec_nr * trk->img_bps;
|
||||||
} else {
|
} else {
|
||||||
off = 0;
|
|
||||||
sec = im->img.sec_info;
|
sec = im->img.sec_info;
|
||||||
for (i = 0; i < sec_nr; i++)
|
for (i = off = 0; i < sec_nr; i++)
|
||||||
off += sec_sz(sec++->n);
|
off += sec_sz(sec++->n);
|
||||||
}
|
}
|
||||||
F_lseek(&im->fp, im->img.trk_off + off);
|
off += im->img.trk_off;
|
||||||
|
off += im->img.decode_data_pos;
|
||||||
|
|
||||||
for (todo = sec_sz; todo != 0; todo -= nr) {
|
if (im->img.decode_data_pos < sec_sz) {
|
||||||
nr = min_t(unsigned int, todo, CHUNK_SIZE);
|
unsigned int nr = sec_sz - im->img.decode_data_pos;
|
||||||
|
nr = min_t(unsigned int, nr, CHUNK_SIZE - (off & 511));
|
||||||
|
if ((int16_t)(p - c) < nr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!im->img.decode_data_pos) {
|
||||||
|
crc = (im->sync == SYNC_fm) ? FM_DAM_CRC : MFM_DAM_CRC;
|
||||||
|
log("Write %u[%02x]/%u...",
|
||||||
|
sec_nr, sec->r, trk->nr_sectors);
|
||||||
|
F_lseek(&im->fp, off);
|
||||||
|
}
|
||||||
|
|
||||||
|
t = time_now();
|
||||||
mfm_ring_to_bin(buf, bufmask, c, wrbuf, nr);
|
mfm_ring_to_bin(buf, bufmask, c, wrbuf, nr);
|
||||||
c += nr;
|
c += nr;
|
||||||
crc = crc16_ccitt(wrbuf, nr, crc);
|
crc = crc16_ccitt(wrbuf, nr, crc);
|
||||||
process_data(im, wrbuf, nr);
|
process_data(im, wrbuf, nr);
|
||||||
F_write(&im->fp, wrbuf, nr, NULL);
|
F_write(&im->fp, wrbuf, nr, NULL);
|
||||||
|
printk(" %u us", time_diff(t, time_now()) / TIME_MHZ);
|
||||||
|
im->img.decode_data_pos += nr;
|
||||||
|
if (im->img.decode_data_pos < sec_sz)
|
||||||
|
printk("...");
|
||||||
|
else
|
||||||
|
printk("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("%u us\n", time_diff(t, time_now()) / TIME_MHZ);
|
if (im->img.decode_data_pos < sec_sz)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((int16_t)(p - c) < 2)
|
||||||
|
break;
|
||||||
mfm_ring_to_bin(buf, bufmask, c, wrbuf, 2);
|
mfm_ring_to_bin(buf, bufmask, c, wrbuf, 2);
|
||||||
c += 2;
|
c += 2;
|
||||||
crc = crc16_ccitt(wrbuf, 2, crc);
|
crc = crc16_ccitt(wrbuf, 2, crc);
|
||||||
|
|
@ -2085,15 +2114,14 @@ static bool_t raw_write_track(struct image *im)
|
||||||
log("Bad CRC: %04x, %u[%02x]\n", crc, sec_nr, sec->r);
|
log("Bad CRC: %04x, %u[%02x]\n", crc, sec_nr, sec->r);
|
||||||
}
|
}
|
||||||
|
|
||||||
dam_out:
|
data_complete:
|
||||||
im->img.write_sector = -2;
|
im->img.write_sector = -2;
|
||||||
break;
|
im->img.decode_pos = 0;
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
im->img.crc = crc;
|
||||||
wr->cons = c * 16;
|
wr->cons = c * 16;
|
||||||
return flush;
|
return flush;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ static bool_t qd_open(struct image *im)
|
||||||
im->qd.tb = 1;
|
im->qd.tb = 1;
|
||||||
im->nr_cyls = 1;
|
im->nr_cyls = 1;
|
||||||
im->nr_sides = 1;
|
im->nr_sides = 1;
|
||||||
im->write_bc_ticks = sampleclk_us(4) + 66; /* 4.917us */
|
im->write_bc_ticks = sampleclk_ns(4917); /* 4.917us */
|
||||||
im->ticks_per_cell = im->write_bc_ticks;
|
im->ticks_per_cell = im->write_bc_ticks;
|
||||||
im->sync = SYNC_none;
|
im->sync = SYNC_none;
|
||||||
|
|
||||||
|
|
|
||||||
12
src/util.c
12
src/util.c
|
|
@ -335,6 +335,18 @@ unsigned int popcount(uint32_t x)
|
||||||
return (((x + (x >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
|
return (((x + (x >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 64:32->32q division requiring 32:32->64 multiply. Cortex M3+ */
|
||||||
|
uint32_t udiv64(uint64_t dividend, uint32_t divisor)
|
||||||
|
{
|
||||||
|
uint32_t x, q = 0;
|
||||||
|
for (x = 1u<<31; x != 0; x >>= 1) {
|
||||||
|
if (((uint64_t)(q|x)*divisor) <= dividend)
|
||||||
|
q |= x;
|
||||||
|
}
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* mode: C
|
* mode: C
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue