Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53eb0bac5f | ||
|
|
5c9f701adc |
65 changed files with 853 additions and 1804 deletions
49
.github/workflows/ci.yml
vendored
49
.github/workflows/ci.yml
vendored
|
|
@ -1,49 +0,0 @@
|
|||
name: CI
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set environment variables
|
||||
id: vars
|
||||
run: |
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Dependency packages (apt)
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt -y install git gcc-arm-none-eabi python3-pip srecord stm32flash zip unzip wget
|
||||
|
||||
- name: Dependency packages (pip)
|
||||
run: python3 -m pip install --user crcmod intelhex
|
||||
|
||||
- name: Build dist
|
||||
run: |
|
||||
export VER=${{ steps.vars.outputs.sha_short }}
|
||||
make -j4 dist VER=$VER
|
||||
mkdir -p _cidist
|
||||
mv out/flashfloppy-$VER .
|
||||
rm flashfloppy-$VER/RELEASE_NOTES
|
||||
git rev-parse HEAD >flashfloppy-$VER/COMMIT
|
||||
zip -r flashfloppy-$VER.zip flashfloppy-$VER
|
||||
mv flashfloppy-$VER.zip _cidist/
|
||||
|
||||
- name: Build debug dist
|
||||
run: |
|
||||
export VER=${{ steps.vars.outputs.sha_short }}-debug
|
||||
make -j4 dist VER=$VER level=debug
|
||||
mv out/flashfloppy-$VER .
|
||||
rm flashfloppy-$VER/RELEASE_NOTES
|
||||
git rev-parse HEAD >flashfloppy-$VER/COMMIT
|
||||
echo debug >>flashfloppy-$VER/COMMIT
|
||||
zip -r flashfloppy-$VER.zip flashfloppy-$VER
|
||||
mv flashfloppy-$VER.zip _cidist/
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: FlashFloppy.CI.${{ steps.vars.outputs.sha_short }}
|
||||
path: _cidist
|
||||
45
.github/workflows/release.yml
vendored
45
.github/workflows/release.yml
vendored
|
|
@ -1,45 +0,0 @@
|
|||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*'
|
||||
|
||||
name: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set environment variables
|
||||
id: vars
|
||||
run: |
|
||||
echo "ver=$(echo ${{ github.ref }} | sed -e's#.*/v##')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Dependency packages (apt)
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt -y install git gcc-arm-none-eabi python3-pip srecord stm32flash zip unzip wget
|
||||
|
||||
- name: Dependency packages (pip)
|
||||
run: python3 -m pip install --user crcmod intelhex
|
||||
|
||||
- name: Build release
|
||||
run: |
|
||||
export VER=${{ steps.vars.outputs.ver }}
|
||||
make -j4 dist VER=$VER
|
||||
mv out/flashfloppy-$VER.zip .
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: ${{ github.ref }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: FlashFloppy ${{ steps.vars.outputs.ver }}
|
||||
body: "[**Release Notes:**](https://github.com/keirf/flashfloppy/blob/master/RELEASE_NOTES)"
|
||||
draft: false
|
||||
prerelease: false
|
||||
artifacts: flashfloppy-${{ steps.vars.outputs.ver }}.zip
|
||||
artifactContentType: application/zip
|
||||
19
Makefile
19
Makefile
|
|
@ -15,21 +15,14 @@ export ROOT := $(CURDIR)
|
|||
prod-%: FORCE
|
||||
$(MAKE) target mcu=$* target=bootloader level=prod
|
||||
$(MAKE) target mcu=$* target=floppy level=prod
|
||||
$(MAKE) target mcu=$* target=quickdisk level=prod
|
||||
$(MAKE) target mcu=$* target=bl_update level=prod
|
||||
$(MAKE) target mcu=$* target=io_test level=prod
|
||||
|
||||
debug-%: FORCE
|
||||
$(MAKE) target mcu=$* target=bootloader level=debug
|
||||
$(MAKE) target mcu=$* target=floppy level=debug
|
||||
$(MAKE) target mcu=$* target=quickdisk level=debug
|
||||
$(MAKE) target mcu=$* target=bl_update level=debug
|
||||
$(MAKE) target mcu=$* target=io_test level=debug
|
||||
|
||||
logfile-%: FORCE
|
||||
$(MAKE) target mcu=$* target=bootloader level=logfile
|
||||
$(MAKE) target mcu=$* target=floppy level=logfile
|
||||
$(MAKE) target mcu=$* target=quickdisk level=logfile
|
||||
|
||||
all-%: FORCE prod-% debug-% logfile-% ;
|
||||
|
||||
|
|
@ -42,7 +35,8 @@ mrproper: FORCE clean
|
|||
rm -rf ext
|
||||
|
||||
out: FORCE
|
||||
+mkdir -p out/$(mcu)/$(level)/$(target)
|
||||
mkdir -p out/$(mcu)/$(level)/$(target)
|
||||
rsync -a --include="*/" --exclude="*" src/ out/$(mcu)/$(level)/$(target)
|
||||
|
||||
target: FORCE out
|
||||
$(MAKE) -C out/$(mcu)/$(level)/$(target) -f $(ROOT)/Rules.mk target.bin target.hex target.dfu $(mcu)=y $(level)=y $(target)=y
|
||||
|
|
@ -108,15 +102,13 @@ dist: FORCE all
|
|||
mkdir -p $(t)/alt/io-test
|
||||
mkdir -p $(t)/alt/quickdisk/logfile
|
||||
$(MAKE) _legacy_dist mcu=stm32f105 level=$(level) t=$(t)
|
||||
$(MAKE) _dist mcu=stm32f105 n=at415-st105 level=$(level) t=$(t)
|
||||
$(MAKE) _dist mcu=stm32f105 n=stm105-at415 level=$(level) t=$(t)
|
||||
$(MAKE) _dist mcu=at32f435 n=at435 level=$(level) t=$(t)
|
||||
$(PYTHON) scripts/mk_qd.py --window=6.5 $(t)/alt/quickdisk/Blank.qd
|
||||
cp -a COPYING $(t)/
|
||||
cp -a README $(t)/
|
||||
cp -a RELEASE_NOTES $(t)/
|
||||
cp -a examples $(t)/
|
||||
# Clive Drive is particularly fussy about QD timings.
|
||||
$(PYTHON) scripts/mk_qd.py --window=6.4 --total=7.5 --round $(t)/examples/Host/Sinclair_ZX_Spectrum/Clive_Drive/CliveDrive_Blank.qd
|
||||
[ -e ext/HxC_Compat_Mode-$(HXC_FF_VER).zip ] || \
|
||||
(mkdir -p ext ; cd ext ; wget -q --show-progress $(HXC_FF_URL)/$(HXC_FF_VER)/HxC_Compat_Mode-$(HXC_FF_VER).zip ; rm -rf index.html)
|
||||
(cd $(t) && unzip -q ../../ext/HxC_Compat_Mode-$(HXC_FF_VER).zip)
|
||||
|
|
@ -129,13 +121,12 @@ BAUD=115200
|
|||
DEV=/dev/ttyUSB0
|
||||
SUDO=sudo
|
||||
STM32FLASH=stm32flash
|
||||
T=out/$(target)/target.hex
|
||||
|
||||
ocd: FORCE all
|
||||
$(PYTHON) scripts/openocd/flash.py $(T)
|
||||
$(PYTHON) scripts/openocd/flash.py $(target)/target.hex
|
||||
|
||||
flash: FORCE all
|
||||
$(SUDO) $(STM32FLASH) -b $(BAUD) -w $(T) $(DEV)
|
||||
$(SUDO) $(STM32FLASH) -b $(BAUD) -w $(target)/target.hex $(DEV)
|
||||
|
||||
start: FORCE
|
||||
$(SUDO) $(STM32FLASH) -b $(BAUD) -g 0 $(DEV)
|
||||
|
|
|
|||
2
README
2
README
|
|
@ -27,7 +27,7 @@ to program a HEX or DFU firmware file as explained in the wiki, linked above.
|
|||
These files are located in the hex/ and dfu/ folders respectively, and you
|
||||
must use the correct file for your microcontroller:
|
||||
STM32F105, AT32F415
|
||||
- Use file "dfu/flashfloppy-at415-st105-<ver>.dfu" (or .hex equivalent)
|
||||
- Use file "dfu/flashfloppy-stm105-at415-<ver>.dfu" (or .hex equivalent)
|
||||
AT32F435
|
||||
- Use file "dfu/flashfloppy-at435-<ver>.dfu" (or .hex equivalent)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
![Downloads Badge][downloads-badge]
|
||||
![Version Badge][version-badge]
|
||||
|
||||
<img src="https://raw.githubusercontent.com/wiki/keirf/flashfloppy/assets/banner.jpg">
|
||||
|
||||
**FlashFloppy** is a floppy-drive emulator for the ubiquitous
|
||||
[**Gotek**][Gotek-Compatibility] hardware. Connect to retro machines just
|
||||
like a real floppy drive but use disk images on a modern USB stick!
|
||||
|
|
|
|||
|
|
@ -3,56 +3,6 @@
|
|||
** 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
|
||||
- AT32F415: Fix timer handling since clock speed increase (v3.39).
|
||||
- LCD: Faster power-on initialisation. Don't wait for display to clear.
|
||||
|
||||
** v3.40 - 27 June 2023
|
||||
- XDF: Fix writes to side 1 of XDF disk images
|
||||
- HFE: Better handling of long No Flux Areas
|
||||
- QuickDisk: Reduce motor spinup time to 1 second (previously 2 seconds)
|
||||
- LCD: Completely blank display when backlight is off
|
||||
|
||||
** v3.39 - 1 March 2023
|
||||
- AT32F415: Run this MCU at 144MHz (previously 72MHz).
|
||||
- HFE: Fix HFEv3 support. Support Dungeon Master & Chaos Strikes Back.
|
||||
- IMG.CFG: Support mixed sector sizes per track (Ensoniq Mirage etc).
|
||||
- IMG.CFG: New option img_bps= allows padding of short sectors in IMG files.
|
||||
- FF.CFG: New option notify-volume= for notifying on insert/eject events.
|
||||
- FF.CFG: New OLED display sub-option 'hflip' horizontally flips display.
|
||||
- Various other small fixes.
|
||||
|
||||
** v3.38 - 4 December 2022
|
||||
- AT32F435: Fix RDATA release on drive deassert
|
||||
- SF7: Support Sega SF-7000 *.SF7 images
|
||||
|
||||
** v3.37 - 20 October 2022
|
||||
- Amiga: Fix firmware crash when mounting read-only disk image
|
||||
- Since v3.36 when interface=amiga and motor-delay= is configured
|
||||
- Amiga: Respect MOTOR when motor-delay= is configured and disk ejected
|
||||
- Previously the MOTOR signal was ignored when no disk inserted
|
||||
|
||||
** v3.36 - 10 October 2022
|
||||
- AT32F435: Fix SD card handling on boards which support it
|
||||
- FF.CFG, OSD: New options osd-columns= and osd-display-order=
|
||||
- Amiga: Improved pin 34 ID/RDY emulation
|
||||
- Requires AT32F435 MCU and MOR jumper strap
|
||||
- Requires FF.CFG options: interface=amiga, motor-delay=500
|
||||
|
||||
** v3.35 - 4 August 2022
|
||||
- AT32F435: Fix Quick Disk firmware
|
||||
|
||||
** v3.34 - 4 July 2022
|
||||
- AT32F435: Fix startup to MCU spec (LDO voltage, Flash clock divisor)
|
||||
- AT32F435: Cache HFE and QD image data, since there is plenty of RAM
|
||||
- Allow rotary encoder on pins PA13/PA14 on any board except QFN32 MCU
|
||||
- io-test: Fix io-test alt firmware for modern Gotek boards
|
||||
|
||||
** v3.33 - 20 June 2022
|
||||
- Support new board SFRKC30.AT4.35
|
||||
- Support new chip AT32F435 (288MHz M4, 256kB+ Flash, 384kB SRAM)
|
||||
|
|
|
|||
2
Rules.mk
2
Rules.mk
|
|
@ -73,7 +73,6 @@ build.o: $(OBJS)
|
|||
$(LD) -r -o $@ $^
|
||||
|
||||
%/build.o: FORCE
|
||||
+mkdir -p $*
|
||||
$(MAKE) -f $(ROOT)/Rules.mk -C $* build.o
|
||||
|
||||
%.ld: $(SRCDIR)/%.ld.S $(SRCDIR)/Makefile
|
||||
|
|
@ -89,7 +88,6 @@ build.o: $(OBJS)
|
|||
@echo OBJCOPY $@
|
||||
$(OBJCOPY) -O ihex $< $@
|
||||
chmod a-x $@
|
||||
$(PYTHON) $(ROOT)/scripts/check_hex.py $@ $(mcu)
|
||||
ifneq ($(bootloader),y)
|
||||
srec_cat ../bootloader/target.hex -Intel $@ -Intel -o $@ -Intel
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@
|
|||
# jc: Specified by jumper JC (open: shugart, closed: ibmpc)
|
||||
# shugart: P2=DSKCHG, P34=RDY (Amiga, Atari ST, many others)
|
||||
# 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-hdout: P2=HD_OUT, P34=RDY (Japanese PC alternate: prefer jppc)
|
||||
# akai-s950: Legacy alias of jppc-hdout, previously used for Akai S950
|
||||
# amiga: P2=DSKCHG, P34=DRIVE_ID (not generally needed: prefer shugart)
|
||||
# jppc-hdout: P2=HD_OUT, P34=RDY (Japanese PC alternate: prefer 'jppc')
|
||||
# akai-s950: Legacy alias of 'jppc-hdout', previously used for Akai S950
|
||||
# amiga: P2=DSKCHG, P34=DRIVE_ID (not generally needed: prefer 'shugart')
|
||||
interface = jc
|
||||
|
||||
# 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):
|
||||
# [full | half | quarter]:
|
||||
# Rotary encoder, identified by fraction of a Gray-code cycle performed
|
||||
# per detent/click. If default value (full) requires multiple
|
||||
# clicks/detents to move position then change to half (if 2 clicks
|
||||
# per move) or quarter (if 4 clicks).
|
||||
# per detent/click. If default value ('full') requires multiple
|
||||
# clicks/detents to move position then change to 'half' (if 2 clicks
|
||||
# per move) or 'quarter' (if 4 clicks).
|
||||
# [trackball]:
|
||||
# Blackberry-style trackball (eg. using Hall-effect sensors).
|
||||
# [buttons]:
|
||||
|
|
@ -199,7 +199,6 @@ indexed-prefix = "DSKA"
|
|||
# lcd-CCxRR: CCxRR backlit LCD with I2C backpack (16<=CC<=40, 02<=RR<=04)
|
||||
# oled-128xNN: 128xNN I2C OLED (NN = 32 | 64)
|
||||
# -rotate: OLED view is rotated 180 degrees
|
||||
# -hflip: OLED view is flipped horizontally
|
||||
# -narrow[er]: OLED view is restricted to Gotek display cutout
|
||||
# (-narrow: 18 chars; -narrower: 16 chars)
|
||||
# -inverse: Inverse/reverse video (black text on white background)
|
||||
|
|
@ -219,23 +218,18 @@ oled-font = 6x13
|
|||
# Values: 0 <= N <= 255
|
||||
oled-contrast = 143
|
||||
|
||||
# Text height and arrangement on LCD/OLED and on OSD, respectively.
|
||||
# Comma-separated list, one entry per display row, top down.
|
||||
# Each list item is a digit plus optional height specifier: [0-7][d]
|
||||
# content-row: 0-3 = specified content, 7 = blank
|
||||
# Text height and arrangement on LCD/OLED
|
||||
# 'default', or a comma-separated list (one entry per LCD/OLED row, top down).
|
||||
# Each list item is a digit plus optional height specifier: <content-row>[d]
|
||||
# content-row: '0-3' = specified content row, '7' = blank
|
||||
# 0: Current image name
|
||||
# 1: Status
|
||||
# 2: Image/Volume info
|
||||
# 3: Current subfolder name
|
||||
# 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
|
||||
# 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'
|
||||
# Values: [0-7][d] | default
|
||||
display-order = default
|
||||
osd-display-order = default
|
||||
|
||||
# OSD text columns. This is currently respected only when no LCD/OLED is found.
|
||||
# Values: 16 <= N <= 40
|
||||
osd-columns = 40
|
||||
|
||||
# Turn an LCD or OLED display off after N seconds of inactivity
|
||||
# N=0: always off; N=255: always on
|
||||
|
|
@ -273,14 +267,6 @@ nav-scroll-pause = 300
|
|||
# Values: 0 <= N <= 20
|
||||
step-volume = 10
|
||||
|
||||
# Speaker volume for insert, eject, and slot-number notifications.
|
||||
# Slot number is indicated by a sequence of beeps when an image is mounted
|
||||
# iff "slotnr" is specified. The slot number is then notified by a sequence of
|
||||
# long beeps (each counting +5), followed by a sequence of short beeps
|
||||
# (each counting +1).
|
||||
# Values: N[,slotnr] (0 <= N <= 15)
|
||||
notify-volume = 0
|
||||
|
||||
# Report the specified version number to host software
|
||||
# Values: <quoted-string> ("" means report real version)
|
||||
# eg. da-report-version = "v3.0.0.0"
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
## IMG.CFG for Dynacord ADS hosts.
|
||||
|
||||
# NOTE: The tags match on filesize alone. If you wish to define an explicit
|
||||
# tagname match, you can for example add 'dyna' to the square-bracketed tags
|
||||
# to limit matches to filenames of the form *.dyna.{img,ima,dsk}
|
||||
|
||||
[::1638400]
|
||||
cyls = 80
|
||||
heads = 2
|
||||
bps = 512
|
||||
secs = 20
|
||||
interleave = 2
|
||||
tracks = 0-79.0 ## Head 0
|
||||
id = 1
|
||||
tracks = 0-79.1 ## Head 1
|
||||
id = 21 # Follows on from head 0 (1..20 -> 21..40)
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
# IMG.CFG for Ensoniq hosts
|
||||
|
||||
# 800kB and 1.6MB image types are also handled by FF.CFG: host=ensoniq
|
||||
|
||||
# NOTE: The tags match on filesize alone. If you wish to define an explicit
|
||||
# tagname match, you can for example add 'ensoniq' to the square-bracketed tags
|
||||
# to limit matches to filenames of the form *.ensoniq.{img,ima,dsk}
|
||||
|
||||
# Ensoniq 800kB DSDD
|
||||
# Also handled by FF.CFG: host=ensoniq
|
||||
[::819200]
|
||||
cyls = 80
|
||||
heads = 2
|
||||
secs = 10
|
||||
bps = 512
|
||||
gap3 = 30
|
||||
id = 0
|
||||
rate = 250
|
||||
|
||||
# Ensoniq 1.6MB DSHD
|
||||
# Also handled by FF.CFG: host=ensoniq
|
||||
[::1638400]
|
||||
cyls = 80
|
||||
heads = 2
|
||||
secs = 20
|
||||
bps = 512
|
||||
gap3 = 40
|
||||
id = 0
|
||||
rate = 500
|
||||
|
||||
# Ensoniq Mirage 440kB SSDD
|
||||
# Mixed sector sizes *NOT* handled by FF.CFG: host=ensoniq
|
||||
[::450560]
|
||||
cyls = 80
|
||||
heads = 1
|
||||
secs = 6
|
||||
bps = 1024,1024,1024,1024,1024,512
|
||||
id = 0
|
||||
rate = 250
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
## 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
|
||||
|
|
@ -11,7 +11,7 @@ cyls = 40
|
|||
heads = 1
|
||||
secs = 10
|
||||
bps = 256
|
||||
cskew = 2
|
||||
skew = 2
|
||||
mode = fm
|
||||
iam = no
|
||||
|
||||
|
|
@ -35,6 +35,6 @@ cyls = 40
|
|||
heads = 2
|
||||
secs = 5
|
||||
bps = 1024
|
||||
cskew = 2
|
||||
skew = 2
|
||||
mode = mfm
|
||||
iam = yes
|
||||
|
|
|
|||
|
|
@ -37,24 +37,3 @@ tracks = 0-79 # This line can be adjusted
|
|||
interleave = 2
|
||||
hskew = 1
|
||||
cskew = 2
|
||||
|
||||
# Matches 720kB images named *.mc.{img,ima,dsk}.
|
||||
# This higher level of interleave is found on all disks for the
|
||||
# Roland MC-300, MC-500 and MC-50.
|
||||
[mc::737280]
|
||||
cyls = 80
|
||||
heads = 2
|
||||
secs = 9
|
||||
bps = 512
|
||||
tracks = 0-79
|
||||
interleave = 4
|
||||
|
||||
# Roland 1.44MB format may apply sector skew.
|
||||
# This is as seen on a Roland MT-200.
|
||||
[::1474560]
|
||||
cyls = 80
|
||||
heads = 2
|
||||
secs = 18
|
||||
bps = 512
|
||||
hskew = 3
|
||||
cskew = 6
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
# IMG.CFG for Sequential Circuits hosts
|
||||
|
||||
# NOTE: The tags match on filesize alone. If you wish to define an explicit
|
||||
# tagname match, you can for example add 'sci' to the square-bracketed tags
|
||||
# to limit matches to filenames of the form *.sci.{img,ima,dsk}
|
||||
|
||||
# Sequential Circuits Prophet 840kB DSDD
|
||||
[::860160]
|
||||
cyls = 80
|
||||
heads = 2
|
||||
secs = 6
|
||||
bps = 1024,1024,1024,1024,1024,256
|
||||
id = 0
|
||||
rate = 250
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
The Clive Drive controller has a 16-pin drive interface. Pins 3-12
|
||||
inclusive correspond to the usual 10-pin QD interface. For reference,
|
||||
see the Clive Drive schematic at:
|
||||
https://speccy4ever.speccy.org/rom/clive/Clive%20Drive.pdf
|
||||
|
||||
Clive Controller QDD Gotek
|
||||
|
||||
1---------NC
|
||||
2---------NC
|
||||
3---------WRITE PROTECT (WRPR) 1 28
|
||||
4---------WRITE DATA (WRDT) 2 22
|
||||
5---------WRITE GATE 1 (WRGT1) 3 24
|
||||
6---------MOTOR ON 1 (MTON1) 4 16
|
||||
7---------READ DATA (RDDT) 5 30
|
||||
8---------READY 6 34
|
||||
9---------MEDIA SENSE (MDST) 7 2
|
||||
10--------QD RESET (QDDRST) 8 20
|
||||
11--------VCC +5V 9 +5v
|
||||
12--------GND 10 GND
|
||||
13--------MOTOR ON 2 (MTON2) NC NC
|
||||
14--------WRITE GATE 2 (WRGT2) NC NC
|
||||
15--------SEL IN (SELIN) NC NC
|
||||
16--------NC
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
## 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,15 +69,6 @@ secs = 9
|
|||
# Mandatory if @secs is non-zero.
|
||||
bps = 512
|
||||
|
||||
# Alternative form in which bytes per sector is specified per sector.
|
||||
# The list is comma separated; no white space allowed.
|
||||
# bps = 512,512,512,512,512,512,512,512,256
|
||||
|
||||
# Bytes per sector within the IMG file. Smaller sectors will be padded.
|
||||
# The default is 0: Sectors occupy precisely their data size; No padding.
|
||||
# Supported values: 0, 128, 256, 512, 1024, 2048, 4096, 8192.
|
||||
# img_bps = 0
|
||||
|
||||
# ID of first sector on each track (0-255). Default is 1.
|
||||
# Numbers may be expressed in hexadecimal with 0x prefix (eg. 0xab).
|
||||
# id = 1
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ struct packed ff_cfg {
|
|||
#define DISPLAY_oled_64 (1<<5)
|
||||
#define DISPLAY_inverse (1<<6)
|
||||
#define DISPLAY_slow (1<<7)
|
||||
#define DISPLAY_hflip (1<<8)
|
||||
/* Only if DISPLAY_lcd: */
|
||||
#define _DISPLAY_lcd_columns 5
|
||||
#define DISPLAY_lcd_columns(x) ((x)<<_DISPLAY_lcd_columns)
|
||||
|
|
@ -165,11 +164,6 @@ struct packed ff_cfg {
|
|||
#define WDRAIN_eot 2
|
||||
uint8_t write_drain;
|
||||
uint8_t max_cyl;
|
||||
uint16_t osd_display_order;
|
||||
uint8_t osd_columns;
|
||||
#define NOTIFY_volume_mask 15
|
||||
#define NOTIFY_slotnr (1<<4)
|
||||
uint8_t notify_volume;
|
||||
};
|
||||
|
||||
extern struct ff_cfg ff_cfg;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "mcu/common.h"
|
||||
#if MCU == STM32F105
|
||||
#include "mcu/stm32f105_regs.h"
|
||||
#include "mcu/at32f415_regs.h"
|
||||
#include "mcu/stm32f105.h"
|
||||
#elif MCU == AT32F435
|
||||
#include "mcu/at32f435_regs.h"
|
||||
|
|
|
|||
17
inc/floppy.h
17
inc/floppy.h
|
|
@ -9,13 +9,6 @@
|
|||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
#define SAMPLECLK_MHZ 72
|
||||
#define sampleclk_ns(x) (((x) * SAMPLECLK_MHZ) / 1000)
|
||||
#define sampleclk_us(x) ((x) * SAMPLECLK_MHZ)
|
||||
#define sampleclk_ms(x) ((x) * SAMPLECLK_MHZ * 1000)
|
||||
#define sampleclk_stk(x) ((x) * (SAMPLECLK_MHZ / STK_MHZ))
|
||||
#define stk_sampleclk(x) ((x) / (SAMPLECLK_MHZ / STK_MHZ))
|
||||
|
||||
#ifdef QUICKDISK
|
||||
#define is_quickdisk TRUE
|
||||
#else
|
||||
|
|
@ -91,7 +84,6 @@ struct raw_trk {
|
|||
uint16_t sec_off;
|
||||
uint16_t data_rate;
|
||||
uint16_t rpm;
|
||||
uint16_t img_bps; /* could squeeze this field into uint8_t or bitfield */
|
||||
int16_t gap_2, gap_3, gap_4a;
|
||||
uint8_t interleave, cskew, hskew;
|
||||
uint8_t has_iam:1, is_fm:1, invert_data:1;
|
||||
|
|
@ -187,7 +179,7 @@ struct image {
|
|||
|
||||
/* Info about current track. */
|
||||
uint16_t cur_track;
|
||||
uint16_t write_bc_ticks; /* SAMPLECLK ticks per bitcell in write stream */
|
||||
uint16_t write_bc_ticks; /* Nr SYSCLK ticks per bitcell in write stream */
|
||||
uint32_t ticks_per_cell; /* Nr 'ticks' per bitcell in read stream. */
|
||||
uint32_t tracklen_bc, cur_bc; /* Track length and cursor, in bitcells */
|
||||
uint32_t tracklen_ticks; /* Timing of previous revolution, in 'ticks' */
|
||||
|
|
@ -240,7 +232,7 @@ void image_open(struct image *im, struct slot *slot, DWORD *cltbl);
|
|||
void image_extend(struct image *im);
|
||||
|
||||
/* Seek to given track and start reading track data at specified rotational
|
||||
* position (specified as number of SAMPLECLK ticks past the index mark).
|
||||
* position (specified as number of SYSCLK ticks past the index mark).
|
||||
*
|
||||
* If start_pos is NULL then the caller is in write mode and thus is not
|
||||
* interested in fetching data from a particular rotational position.
|
||||
|
|
@ -260,7 +252,7 @@ uint16_t bc_rdata_flux(struct image *im, uint16_t *tbuf, uint16_t nr);
|
|||
* was completed for the write at the tail of the pipeline. */
|
||||
bool_t image_write_track(struct image *im);
|
||||
|
||||
/* Rotational position of last-generated flux (SAMPLECLK ticks past index). */
|
||||
/* Rotational position of last-generated flux (SYSCLK ticks past index). */
|
||||
uint32_t image_ticks_since_index(struct image *im);
|
||||
|
||||
/* MFM conversion. */
|
||||
|
|
@ -299,9 +291,6 @@ static inline bool_t in_da_mode(struct image *im, unsigned int cyl)
|
|||
return cyl >= max_t(unsigned int, DA_FIRST_CYL, im_nphys_cyls(im));
|
||||
}
|
||||
|
||||
extern uint32_t motor_chgrst_exti_mask;
|
||||
void motor_chgrst_setup_exti(void);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* at32f415_regs.h
|
||||
*
|
||||
* Extra registers and features of the AT32F415 that we use, over and above
|
||||
* the baseline features of the STM32F105.
|
||||
*
|
||||
* Written & released by Keir Fraser <keir.xen@gmail.com>
|
||||
*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
#define RCC_CFGR_PLLMUL_18 ((uint32_t)0x20040000)
|
||||
#define RCC_CFGR_USBPSC_3 ((uint32_t)0x08400000)
|
||||
|
||||
#define RCC_PLL (&rcc->cfgr2)
|
||||
#define RCC_PLL_PLLCFGEN (1u<<31)
|
||||
#define RCC_PLL_FREF_MASK (7u<<24)
|
||||
#define RCC_PLL_FREF_8M (2u<<24)
|
||||
|
||||
static volatile uint32_t * const RCC_MISC2 = (uint32_t *)(RCC_BASE + 0x54);
|
||||
#define RCC_MISC2_AUTOSTEP_EN (3u<< 4)
|
||||
|
||||
#define TIM_CR1_PMEN (1u<<10)
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-file-style: "Linux"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
|
|
@ -56,9 +56,9 @@ static USB_OTG usb_otg = (struct usb_otg *)USB_OTG_BASE;
|
|||
|
||||
/* Clocks */
|
||||
#define SYSCLK_MHZ 288
|
||||
#define AHB_MHZ 288
|
||||
#define APB1_MHZ 144
|
||||
#define APB2_MHZ 144
|
||||
#define AHB_MHZ (SYSCLK_MHZ / 1) /* 288MHz */
|
||||
#define APB1_MHZ (SYSCLK_MHZ / 2) /* 144MHz */
|
||||
#define APB2_MHZ (SYSCLK_MHZ / 2) /* 144MHz */
|
||||
|
||||
/* GPIO */
|
||||
void gpio_set_af(GPIO gpio, unsigned int pin, unsigned int af);
|
||||
|
|
|
|||
|
|
@ -9,18 +9,6 @@
|
|||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
/* Power control */
|
||||
struct pwr {
|
||||
uint32_t cr; /* 00: Power control */
|
||||
uint32_t csr; /* 04: Power control/status */
|
||||
uint32_t rsvd[2];
|
||||
uint32_t ldoov; /* 10: LDO output voltage */
|
||||
};
|
||||
|
||||
#define PWR_LDOOV_1V3 (1u<<0)
|
||||
|
||||
#define PWR_BASE 0x40007000
|
||||
|
||||
/* Flash memory interface */
|
||||
struct flash_bank {
|
||||
uint32_t sr; /* +00: Flash status */
|
||||
|
|
@ -42,8 +30,7 @@ struct flash {
|
|||
uint32_t rsvd4; /* 48: - */
|
||||
struct flash_bank bank2;
|
||||
uint32_t contr; /* 58: Continue read */
|
||||
uint32_t rsvd5; /* 5C: - */
|
||||
uint32_t divr; /* 60: Divider */
|
||||
uint32_t divr; /* 5C: Divider */
|
||||
};
|
||||
|
||||
#define FLASH_SR_EOP (1u<< 5)
|
||||
|
|
@ -250,7 +237,6 @@ struct gpio {
|
|||
#define GPO_opendrain(speed,level) (0x5u|((speed)<<3)|((level)<<7))
|
||||
#define AFI(pupd) (0x2u|((pupd)<<5))
|
||||
#define AFO_pushpull(speed) (0x2u|((speed)<<3))
|
||||
#define _AFO_pushpull(speed,level) (0x2u|((speed)<<3)|((level)<<7))
|
||||
#define AFO_opendrain(speed) (0x6u|((speed)<<3))
|
||||
#define _2MHz 0
|
||||
#define _10MHz 0
|
||||
|
|
|
|||
|
|
@ -100,8 +100,7 @@ void fpec_write(const void *data, unsigned int size, uint32_t flash_address);
|
|||
extern unsigned int flash_page_size;
|
||||
extern unsigned int ram_kb;
|
||||
|
||||
extern uint8_t mcu_package;
|
||||
enum { MCU_LQFP64=0, MCU_LQFP48, MCU_QFN32 };
|
||||
extern bool_t is_32pin_mcu;
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
|
|
|||
|
|
@ -109,6 +109,16 @@ struct dbg {
|
|||
|
||||
#define DBG_BASE 0xe0042000
|
||||
|
||||
/* Power control */
|
||||
struct pwr {
|
||||
uint32_t cr; /* 00: Power control */
|
||||
uint32_t csr; /* 04: Power control/status */
|
||||
};
|
||||
|
||||
#define PWR_CR_DBP (1u<< 8)
|
||||
|
||||
#define PWR_BASE 0x40007000
|
||||
|
||||
/* Backup */
|
||||
struct bkp {
|
||||
uint32_t _0[1]; /* 00: - */
|
||||
|
|
@ -323,17 +333,6 @@ struct spi {
|
|||
uint32_t i2spr; /* 20: I2S prescaler */
|
||||
};
|
||||
|
||||
#define SPI_BR_DIV2 0
|
||||
#define SPI_BR_DIV4 1
|
||||
#define SPI_BR_DIV8 2
|
||||
#define SPI_BR_DIV16 3
|
||||
#define SPI_BR_DIV32 4
|
||||
#define SPI_BR_DIV64 5
|
||||
#define SPI_BR_DIV128 6
|
||||
#define SPI_BR_DIV256 7
|
||||
#define SPI_BR_DIV512 8
|
||||
#define SPI_BR_DIV1024 9
|
||||
|
||||
#define SPI_CR1_BIDIMODE (1u<<15)
|
||||
#define SPI_CR1_BIDIOE (1u<<14)
|
||||
#define SPI_CR1_CRCEN (1u<<13)
|
||||
|
|
@ -344,6 +343,15 @@ struct spi {
|
|||
#define SPI_CR1_SSI (1u<< 8)
|
||||
#define SPI_CR1_LSBFIRST (1u<< 7)
|
||||
#define SPI_CR1_SPE (1u<< 6)
|
||||
#define SPI_CR1_BR_DIV2 (0u<< 3)
|
||||
#define SPI_CR1_BR_DIV4 (1u<< 3)
|
||||
#define SPI_CR1_BR_DIV8 (2u<< 3)
|
||||
#define SPI_CR1_BR_DIV16 (3u<< 3)
|
||||
#define SPI_CR1_BR_DIV32 (4u<< 3)
|
||||
#define SPI_CR1_BR_DIV64 (5u<< 3)
|
||||
#define SPI_CR1_BR_DIV128 (6u<< 3)
|
||||
#define SPI_CR1_BR_DIV256 (7u<< 3)
|
||||
#define SPI_CR1_BR_MASK (7u<< 3)
|
||||
#define SPI_CR1_MSTR (1u<< 2)
|
||||
#define SPI_CR1_CPOL (1u<< 1)
|
||||
#define SPI_CR1_CPHA (1u<< 0)
|
||||
|
|
|
|||
|
|
@ -50,12 +50,10 @@ static USART usart3 = (struct usart *)USART3_BASE;
|
|||
static USB_OTG usb_otg = (struct usb_otg *)USB_OTG_BASE;
|
||||
|
||||
/* Clocks */
|
||||
extern unsigned int sysclk_mhz;
|
||||
extern unsigned int apb1_mhz;
|
||||
#define SYSCLK_MHZ sysclk_mhz
|
||||
#define AHB_MHZ sysclk_mhz
|
||||
#define APB1_MHZ apb1_mhz
|
||||
#define APB2_MHZ 72
|
||||
#define SYSCLK_MHZ 72
|
||||
#define AHB_MHZ (SYSCLK_MHZ / 1) /* 72MHz */
|
||||
#define APB1_MHZ (SYSCLK_MHZ / 2) /* 36MHz */
|
||||
#define APB2_MHZ (SYSCLK_MHZ / 1) /* 72MHz */
|
||||
|
||||
#define SOFTIRQ_0 43
|
||||
#define SOFTIRQ_1 44
|
||||
|
|
|
|||
|
|
@ -9,16 +9,6 @@
|
|||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
/* Power control */
|
||||
struct pwr {
|
||||
uint32_t cr; /* 00: Power control */
|
||||
uint32_t csr; /* 04: Power control/status */
|
||||
};
|
||||
|
||||
#define PWR_CR_DBP (1u<< 8)
|
||||
|
||||
#define PWR_BASE 0x40007000
|
||||
|
||||
/* Flash memory interface */
|
||||
struct flash {
|
||||
uint32_t acr; /* 00: Flash access control */
|
||||
|
|
@ -89,8 +79,7 @@ struct rcc {
|
|||
#define RCC_CFGR_PLLSRC_HSI (0u<<16)
|
||||
#define RCC_CFGR_PLLSRC_PREDIV1 (1u<<16)
|
||||
#define RCC_CFGR_ADCPRE_DIV8 (3u<<14)
|
||||
#define RCC_CFGR_APB2PSC_2 (4u<<11)
|
||||
#define RCC_CFGR_APB1PSC_2 (4u<< 8)
|
||||
#define RCC_CFGR_PPRE1_DIV2 (4u<<8)
|
||||
#define RCC_CFGR_SWS_HSI (0u<<2)
|
||||
#define RCC_CFGR_SWS_HSE (1u<<2)
|
||||
#define RCC_CFGR_SWS_PLL (2u<<2)
|
||||
|
|
@ -166,7 +155,6 @@ struct gpio {
|
|||
#define GPO_pushpull(speed,level) (0x0u|(speed)|((level)<<4))
|
||||
#define GPO_opendrain(speed,level) (0x4u|(speed)|((level)<<4))
|
||||
#define AFO_pushpull(speed) (0x8u|(speed))
|
||||
#define _AFO_pushpull(speed,level) (0x8u|(speed)|((level)<<4))
|
||||
#define AFO_opendrain(speed) (0xcu|(speed))
|
||||
#define _2MHz 2
|
||||
#define _10MHz 1
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ typedef uint32_t time_t;
|
|||
#define TIME_MHZ STK_MHZ
|
||||
#define time_us(x) stk_us(x)
|
||||
#define time_ms(x) stk_ms(x)
|
||||
#define time_stk(x) (x)
|
||||
#define time_sysclk(x) stk_sysclk(x)
|
||||
#define sysclk_time(x) sysclk_stk(x)
|
||||
|
||||
|
|
|
|||
|
|
@ -69,8 +69,6 @@ int snprintf(char *str, size_t size, const char *format, ...)
|
|||
#define htobe16(x) _rev16(x)
|
||||
#define htobe32(x) _rev32(x)
|
||||
|
||||
uint32_t udiv64(uint64_t dividend, uint32_t divisor);
|
||||
|
||||
/* Arena-based memory allocation */
|
||||
void *arena_alloc(uint32_t sz);
|
||||
uint32_t arena_total(void);
|
||||
|
|
@ -91,8 +89,6 @@ static inline int vprintk(const char *format, va_list ap) { return 0; }
|
|||
static inline int printk(const char *format, ...) { return 0; }
|
||||
#endif
|
||||
|
||||
#define log(f, a...) printk("%s: " f, LOG_PREFIX, ## a)
|
||||
|
||||
#if defined(LOGFILE)
|
||||
/* Logfile management */
|
||||
void logfile_flush(FIL *file);
|
||||
|
|
@ -124,8 +120,6 @@ extern uint8_t display_type;
|
|||
/* Speaker. */
|
||||
void speaker_init(void);
|
||||
void speaker_pulse(void);
|
||||
void speaker_notify_insert(unsigned int slotnr);
|
||||
void speaker_notify_eject(void);
|
||||
|
||||
/* Display: 3-digit 7-segment display */
|
||||
void led_7seg_init(void);
|
||||
|
|
@ -179,7 +173,6 @@ unsigned int board_get_buttons(void);
|
|||
#define B_LEFT 1
|
||||
#define B_RIGHT 2
|
||||
#define B_SELECT 4
|
||||
void board_jc_set_mode(unsigned int mode);
|
||||
bool_t board_jc_strapped(void);
|
||||
|
||||
/* Build info. */
|
||||
|
|
|
|||
|
|
@ -1,89 +0,0 @@
|
|||
# check_hex.py
|
||||
#
|
||||
# Check the base address and size of segments in an Intel Hex target file,
|
||||
# based on known constraints for the specified MCU target.
|
||||
#
|
||||
# Written & released by Keir Fraser <keir.xen@gmail.com>
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
# See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
|
||||
import os, re, sys
|
||||
from intelhex import IntelHex
|
||||
|
||||
def kb(n):
|
||||
return n*1024
|
||||
|
||||
def _fatal(s):
|
||||
print('*** ' + s, file=sys.stderr)
|
||||
|
||||
def fatal(s):
|
||||
_fatal(s)
|
||||
sys.exit(1)
|
||||
|
||||
class Target:
|
||||
|
||||
FLASH_BASE = 0x8000000
|
||||
|
||||
def __init__(self, bootloader_size, flash_size, page_size):
|
||||
self._bootloader_size = bootloader_size
|
||||
self._flash_size = flash_size
|
||||
self._page_size = page_size
|
||||
|
||||
def bootloader_base(self):
|
||||
return self.FLASH_BASE
|
||||
|
||||
def bootloader_size(self):
|
||||
return self._bootloader_size
|
||||
|
||||
def firmware_base(self):
|
||||
return self.FLASH_BASE + self._bootloader_size
|
||||
|
||||
def firmware_size(self):
|
||||
# Allow for bootloader at start of Flash, and cached config at end
|
||||
return self._flash_size - self._bootloader_size - self._page_size
|
||||
|
||||
targets = { 'stm32f105': Target(kb(32), kb(128), kb(2)),
|
||||
'at32f435': Target(kb(48), kb(256), kb(2)) }
|
||||
|
||||
def usage(argv):
|
||||
fatal("Usage: %s file.hex target" % argv[0])
|
||||
|
||||
def main(argv):
|
||||
|
||||
if len(argv) != 3:
|
||||
usage(argv)
|
||||
|
||||
h = argv[1]
|
||||
try:
|
||||
t = targets[argv[2]]
|
||||
except KeyError:
|
||||
_fatal('Unknown target: ' + argv[2])
|
||||
usage(argv)
|
||||
|
||||
# Informational prefix for log lines
|
||||
prefix = h
|
||||
m = re.match(r'.*/out/(.*)', os.path.abspath(h))
|
||||
if m is not None:
|
||||
prefix = m.group(1)
|
||||
|
||||
ih = IntelHex(h)
|
||||
for (s,e) in ih.segments():
|
||||
sz = e - s
|
||||
if s == t.bootloader_base():
|
||||
if sz > t.bootloader_size():
|
||||
fatal('%s: Bootloader overflows by %d bytes'
|
||||
% (prefix, sz - t.bootloader_size()))
|
||||
print('%s: Bootloader has %d bytes headroom'
|
||||
% (prefix, t.bootloader_size() - sz))
|
||||
elif s == t.firmware_base():
|
||||
if sz > t.firmware_size():
|
||||
fatal('%s: Firmware overflows by %d bytes'
|
||||
% (prefix, sz - t.firmware_size()))
|
||||
print('%s: Firmware has %d bytes headroom'
|
||||
% (prefix, t.firmware_size() - sz))
|
||||
else:
|
||||
fatal('%s: Unexpected start address %x' % (prefix, s))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
||||
|
|
@ -46,16 +46,7 @@ def main(argv):
|
|||
else:
|
||||
opts += ['DISPLAY_' + x]
|
||||
val = '|'.join(opts)
|
||||
elif opt == "notify-volume":
|
||||
opts = []
|
||||
for x in val.split(","):
|
||||
vol = re.match("([0-9]+)", x)
|
||||
if vol:
|
||||
opts.append(vol.group(1))
|
||||
else:
|
||||
opts.append('NOTIFY_' + x)
|
||||
val = '|'.join(opts)
|
||||
elif opt == "display-order" or opt == "osd-display-order":
|
||||
elif opt == "display-order":
|
||||
if val == "default":
|
||||
val = "DORD_" + val
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -9,59 +9,39 @@
|
|||
|
||||
import sys,struct,argparse
|
||||
|
||||
def round_up(x, y):
|
||||
return (x + y - 1) & ~(y - 1)
|
||||
|
||||
def main(argv):
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("--lead-in", type=float, default=0.5,
|
||||
help="lead-in, seconds")
|
||||
parser.add_argument("--window", type=float, default=5.5,
|
||||
help="data window, seconds")
|
||||
parser.add_argument("--total", type=float, default=8.0,
|
||||
help="total length, seconds")
|
||||
parser.add_argument("--round", action="store_true",
|
||||
help="round values up to 512-byte block size")
|
||||
parser.add_argument("outfile", help="output filename")
|
||||
args = parser.parse_args(argv[1:])
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("--window", type=float, default=5.5,
|
||||
help="data window, seconds")
|
||||
parser.add_argument("--total", type=float, default=8.0,
|
||||
help="total length, seconds")
|
||||
parser.add_argument("outfile", help="output filename")
|
||||
args = parser.parse_args(argv[1:])
|
||||
|
||||
lead_in, window, total = args.lead_in, args.window, args.total
|
||||
bit_ms = 0.004916
|
||||
total_bytes = int(args.total * 1000.0 / bit_ms / 8)
|
||||
window_bytes = int(args.window * 1000.0 / bit_ms / 8)
|
||||
init_bytes = int(500.0 / bit_ms / 8)
|
||||
|
||||
assert lead_in >= 0.1, "Insufficient lead-in"
|
||||
assert total - window - lead_in >= 0.1, "Insufficient lead-out"
|
||||
assert (2*init_bytes + window_bytes) < total_bytes, "Window too large"
|
||||
print("Lead-In: %.2f sec -> %u bytes" % (0.5, init_bytes))
|
||||
print("Window: %.2f sec -> %u bytes" % (args.window, window_bytes))
|
||||
print("TOTAL: %.2f sec -> %u bytes" % (args.total, total_bytes))
|
||||
|
||||
bit_ms = 0.004916
|
||||
total_bytes = int(total * 1000.0 / bit_ms / 8)
|
||||
window_bytes = int(window * 1000.0 / bit_ms / 8)
|
||||
init_bytes = int(lead_in * 1000.0 / bit_ms / 8)
|
||||
# Header
|
||||
out_f = open(args.outfile, "wb")
|
||||
out_f.write(struct.pack("<3x2s3x", b"QD"))
|
||||
out_f.write(bytearray(b'\x00'*(512-8)))
|
||||
|
||||
if args.round:
|
||||
total_bytes = round_up(total_bytes, 512)
|
||||
window_bytes = round_up(window_bytes, 512)
|
||||
init_bytes = round_up(init_bytes, 512)
|
||||
# Track
|
||||
out_f.write(struct.pack("<4I", 1024, total_bytes, init_bytes,
|
||||
init_bytes + window_bytes))
|
||||
out_f.write(bytearray(b'\x00'*(512-16)))
|
||||
|
||||
print("Lead-In: %.2f sec -> %u bytes" % (lead_in, init_bytes))
|
||||
print("Window: %.2f sec -> %u bytes" % (window, window_bytes))
|
||||
print("TOTAL: %.2f sec -> %u bytes" % (total, total_bytes))
|
||||
|
||||
# Header
|
||||
out_f = open(args.outfile, "wb")
|
||||
out_f.write(struct.pack("<3x2s3x", b"QD"))
|
||||
out_f.write(bytearray(b'\x00'*(512-8)))
|
||||
|
||||
# Track
|
||||
out_f.write(struct.pack("<4I", 1024, total_bytes, init_bytes,
|
||||
init_bytes + window_bytes))
|
||||
out_f.write(bytearray(b'\x00'*(512-16)))
|
||||
|
||||
# Data
|
||||
blocks = (total_bytes + 511) // 512
|
||||
out_f.write(bytearray(b'\x11'*(blocks*512)))
|
||||
# Data
|
||||
blocks = (total_bytes + 511) // 512
|
||||
out_f.write(bytearray(b'\x11'*(blocks*512)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
||||
|
||||
# Local variables:
|
||||
# python-indent: 4
|
||||
# End:
|
||||
|
|
|
|||
|
|
@ -52,10 +52,6 @@ endif
|
|||
.PHONY: $(SRCDIR)/build_info.c
|
||||
build_info.o: CFLAGS += -DFW_VER="\"$(FW_VER)\""
|
||||
|
||||
# Avoid infinite loops due to GCC noticing code that can be replaced by a call
|
||||
# to a standard library function... within our implementation of that function.
|
||||
util.o: CFLAGS += -fno-tree-loop-distribute-patterns
|
||||
|
||||
ff_cfg_defaults.h: $(ROOT)/examples/FF.CFG
|
||||
$(PYTHON) $(ROOT)/scripts/mk_config.py $< $@
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ int main(void)
|
|||
int retries = 0;
|
||||
|
||||
/* Relocate DATA. Initialise BSS. */
|
||||
if (&_sdat[0] != &_ldat[0])
|
||||
if (_sdat != _ldat)
|
||||
memcpy(_sdat, _ldat, _edat-_sdat);
|
||||
memset(_sbss, 0, _ebss-_sbss);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,12 @@
|
|||
#define usart_gpio gpioa
|
||||
#define usart_tx_pin 9
|
||||
#define usart_rx_pin 10
|
||||
#define PCLK (APB2_MHZ * 1000000)
|
||||
#else
|
||||
#define usart usart3
|
||||
#define USART_IRQ USART3_IRQ
|
||||
#define usart_gpio gpioc
|
||||
#define usart_tx_pin 10
|
||||
#define usart_rx_pin 11
|
||||
#define PCLK (APB1_MHZ * 1000000)
|
||||
#endif
|
||||
|
||||
/* Normally flush to serial is asynchronously executed in a low-pri IRQ. */
|
||||
|
|
@ -149,7 +147,7 @@ void console_init(void)
|
|||
#endif
|
||||
|
||||
/* BAUD, 8n1. */
|
||||
usart->brr = PCLK / BAUD;
|
||||
usart->brr = (APB2_MHZ * 1000000) / BAUD;
|
||||
usart->cr1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||
usart->cr3 = 0;
|
||||
|
||||
|
|
@ -161,7 +159,7 @@ void console_init(void)
|
|||
* any serial input to cause a crash dump of the stuck context. */
|
||||
void console_crash_on_input(void)
|
||||
{
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
if (is_32pin_mcu) {
|
||||
/* Unavailable: PA10 is reassigned from SER_RX to K4 (rotary select
|
||||
* on the KC30 header). */
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -219,39 +219,20 @@ static unsigned int osd_prep_buffer(void)
|
|||
uint16_t order = menu_mode ? 0x7903 : 0x7183;
|
||||
char *p;
|
||||
uint8_t *q = buffer;
|
||||
unsigned int row, rows, heights;
|
||||
int i;
|
||||
unsigned int row;
|
||||
|
||||
if (++in_osd == OSD_read) {
|
||||
memset(buffer, 0x11, sizeof(struct i2c_osd_info));
|
||||
return sizeof(struct i2c_osd_info);
|
||||
}
|
||||
|
||||
if ((ff_cfg.osd_display_order != DORD_default)
|
||||
&& (display_mode == DM_normal))
|
||||
order = ff_cfg.osd_display_order;
|
||||
|
||||
heights = rows = 0;
|
||||
for (i = 3; i >= 0; i--) {
|
||||
/* Iterate over rows, bottom to top. */
|
||||
row = order >> (i<<2);
|
||||
/* Skip all trailing empty rows. */
|
||||
if ((rows == 0) && ((row&7) == 7))
|
||||
continue;
|
||||
/* Count this row and check if it is double height. */
|
||||
rows++;
|
||||
heights <<= 1;
|
||||
if (row & 8)
|
||||
heights |= 1;
|
||||
}
|
||||
|
||||
*q++ = OSD_BACKLIGHT | !!_bl;
|
||||
*q++ = OSD_COLUMNS | lcd_columns;
|
||||
*q++ = OSD_ROWS | rows;
|
||||
*q++ = OSD_HEIGHTS | heights;
|
||||
*q++ = OSD_ROWS | 3;
|
||||
*q++ = OSD_HEIGHTS | (menu_mode ? 4 : 2);
|
||||
*q++ = OSD_BUTTONS | osd_buttons_tx;
|
||||
*q++ = OSD_DATA;
|
||||
for (row = 0; row < rows; row++) {
|
||||
for (row = 0; row < 3; row++) {
|
||||
p = text[(order >> (row * DORD_shift)) & DORD_row];
|
||||
memcpy(q, p, lcd_columns);
|
||||
q += lcd_columns;
|
||||
|
|
@ -290,7 +271,7 @@ static unsigned int lcd_prep_buffer(void)
|
|||
order = ff_cfg.display_order;
|
||||
|
||||
row = (order >> (i2c_row * DORD_shift)) & DORD_row;
|
||||
p = (_bl && row < ARRAY_SIZE(text)) ? text[row] : NULL;
|
||||
p = (row < ARRAY_SIZE(text)) ? text[row] : NULL;
|
||||
|
||||
emit8(&q, CMD_SETDDRADDR | row_offs[i2c_row], 0);
|
||||
for (i = 0; i < lcd_columns; i++)
|
||||
|
|
@ -570,14 +551,18 @@ bool_t lcd_init(void)
|
|||
: ((a&~1) == OLED_ADDR);
|
||||
|
||||
if (is_oled_display) {
|
||||
oled_height = (ff_cfg.display_type & DISPLAY_oled_64) ? 64 : 32;
|
||||
oled_height = 64;//(ff_cfg.display_type & DISPLAY_oled_64) ? 64 : 32;
|
||||
lcd_columns = (ff_cfg.oled_font == FONT_8x16) ? 16
|
||||
: (ff_cfg.display_type & DISPLAY_narrower) ? 16
|
||||
: (ff_cfg.display_type & DISPLAY_narrow) ? 18 : 21;
|
||||
lcd_rows = 4;
|
||||
} else {
|
||||
lcd_columns = (ff_cfg.display_type >> _DISPLAY_lcd_columns) & 63;
|
||||
lcd_columns = max_t(uint8_t, lcd_columns, 16);
|
||||
lcd_columns = min_t(uint8_t, lcd_columns, 40);
|
||||
lcd_rows = (ff_cfg.display_type >> _DISPLAY_lcd_rows) & 7;
|
||||
lcd_rows = max_t(uint8_t, lcd_rows, 2);
|
||||
lcd_rows = min_t(uint8_t, lcd_rows, 4);
|
||||
}
|
||||
|
||||
if (a != 0) {
|
||||
|
|
@ -586,14 +571,10 @@ bool_t lcd_init(void)
|
|||
i2c_addr = a;
|
||||
} else {
|
||||
is_oled_display = FALSE;
|
||||
lcd_columns = ff_cfg.osd_columns;
|
||||
if (ff_cfg.display_type == DISPLAY_auto)
|
||||
lcd_columns = 40;
|
||||
}
|
||||
|
||||
lcd_columns = max_t(uint8_t, lcd_columns, 16);
|
||||
lcd_columns = min_t(uint8_t, lcd_columns, 40);
|
||||
lcd_rows = max_t(uint8_t, lcd_rows, 2);
|
||||
lcd_rows = min_t(uint8_t, lcd_rows, 4);
|
||||
|
||||
lcd_clear();
|
||||
|
||||
}
|
||||
|
|
@ -650,8 +631,11 @@ bool_t lcd_init(void)
|
|||
emit8(&p, CMD_DISPLAYCTL | 4, 0); /* display on */
|
||||
dma_start(p - buffer);
|
||||
|
||||
if (!reinit)
|
||||
/* Wait for DMA engine to initialise RAM, then turn on backlight. */
|
||||
if (!reinit) {
|
||||
lcd_sync();
|
||||
lcd_backlight(TRUE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
|
@ -954,6 +938,7 @@ static void oled_init(void)
|
|||
0xa0, /* segment mapping (default) */
|
||||
0xc0, /* com scan direction (default) */
|
||||
};
|
||||
const uint8_t *cmds;
|
||||
uint8_t dynamic_cmds[7], *dc;
|
||||
uint8_t *p = buffer;
|
||||
|
||||
|
|
@ -977,13 +962,9 @@ static void oled_init(void)
|
|||
*dc++ = (oled_height == 64) ? 0x12 : 0x02;
|
||||
p += oled_queue_cmds(p, dynamic_cmds, dc - dynamic_cmds);
|
||||
|
||||
/* Display orientation. */
|
||||
dc = dynamic_cmds;
|
||||
memcpy(dc, (ff_cfg.display_type & DISPLAY_rotate) ? rot_cmds : norot_cmds,
|
||||
2);
|
||||
if (ff_cfg.display_type & DISPLAY_hflip)
|
||||
dc[0] ^= 1;
|
||||
p += oled_queue_cmds(p, dc, 2);
|
||||
/* Display is right-way-up, or rotated. */
|
||||
cmds = 1 ? rot_cmds : norot_cmds; //(ff_cfg.display_type & DISPLAY_rotate) ? rot_cmds : norot_cmds;
|
||||
p += oled_queue_cmds(p, cmds, sizeof(rot_cmds));
|
||||
|
||||
/* Start off the I2C transaction. */
|
||||
p += oled_start_i2c(p);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ struct packed i2c_osd_info {
|
|||
};
|
||||
|
||||
/* STM32 I2C peripheral. */
|
||||
static volatile struct i2c *i2c;
|
||||
static volatile struct i2c *i2c = i2c2;
|
||||
|
||||
const static struct i2c_cfg {
|
||||
uint8_t en;
|
||||
|
|
@ -74,8 +74,6 @@ const static struct i2c_cfg {
|
|||
#define SCL i2c_cfg->scl
|
||||
#define SDA i2c_cfg->sda
|
||||
|
||||
#define PCLK_MHZ APB1_MHZ
|
||||
|
||||
/* I2C error ISR. */
|
||||
#define I2C_ERROR_IRQ i2c_cfg->error_irq
|
||||
void IRQ_34(void) __attribute__((alias("IRQ_i2c_error")));
|
||||
|
|
@ -248,8 +246,7 @@ static unsigned int osd_prep_buffer(void)
|
|||
uint16_t order = menu_mode ? 0x7903 : 0x7183;
|
||||
char *p;
|
||||
uint8_t *q = buffer;
|
||||
unsigned int row, rows, heights;
|
||||
int i;
|
||||
unsigned int row;
|
||||
|
||||
if (++in_osd == OSD_read) {
|
||||
i2c->cr2 |= I2C_CR2_LAST | I2C_CR2_ITEVTEN;
|
||||
|
|
@ -257,31 +254,13 @@ static unsigned int osd_prep_buffer(void)
|
|||
return sizeof(struct i2c_osd_info);
|
||||
}
|
||||
|
||||
if ((ff_cfg.osd_display_order != DORD_default)
|
||||
&& (display_mode == DM_normal))
|
||||
order = ff_cfg.osd_display_order;
|
||||
|
||||
heights = rows = 0;
|
||||
for (i = 3; i >= 0; i--) {
|
||||
/* Iterate over rows, bottom to top. */
|
||||
row = order >> (i<<2);
|
||||
/* Skip all trailing empty rows. */
|
||||
if ((rows == 0) && ((row&7) == 7))
|
||||
continue;
|
||||
/* Count this row and check if it is double height. */
|
||||
rows++;
|
||||
heights <<= 1;
|
||||
if (row & 8)
|
||||
heights |= 1;
|
||||
}
|
||||
|
||||
*q++ = OSD_BACKLIGHT | !!_bl;
|
||||
*q++ = OSD_COLUMNS | lcd_columns;
|
||||
*q++ = OSD_ROWS | rows;
|
||||
*q++ = OSD_HEIGHTS | heights;
|
||||
*q++ = OSD_ROWS | 3;
|
||||
*q++ = OSD_HEIGHTS | (menu_mode ? 4 : 2);
|
||||
*q++ = OSD_BUTTONS | osd_buttons_tx;
|
||||
*q++ = OSD_DATA;
|
||||
for (row = 0; row < rows; row++) {
|
||||
for (row = 0; row < 3; row++) {
|
||||
p = text[(order >> (row * DORD_shift)) & DORD_row];
|
||||
memcpy(q, p, lcd_columns);
|
||||
q += lcd_columns;
|
||||
|
|
@ -327,7 +306,7 @@ static unsigned int lcd_prep_buffer(void)
|
|||
order = ff_cfg.display_order;
|
||||
|
||||
row = (order >> (i2c_row * DORD_shift)) & DORD_row;
|
||||
p = (_bl && row < ARRAY_SIZE(text)) ? text[row] : NULL;
|
||||
p = (row < ARRAY_SIZE(text)) ? text[row] : NULL;
|
||||
|
||||
emit8(&q, CMD_SETDDRADDR | row_offs[i2c_row], 0);
|
||||
for (i = 0; i < lcd_columns; i++)
|
||||
|
|
@ -533,7 +512,7 @@ bool_t lcd_init(void)
|
|||
in_osd = OSD_no;
|
||||
osd_buttons_rx = 0;
|
||||
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
if (is_32pin_mcu) {
|
||||
i2c = i2c1;
|
||||
i2c_cfg = &i2c1_cfg;
|
||||
} else {
|
||||
|
|
@ -588,9 +567,9 @@ bool_t lcd_init(void)
|
|||
|
||||
/* Standard Mode (100kHz) */
|
||||
i2c->cr1 = 0;
|
||||
i2c->cr2 = I2C_CR2_FREQ(PCLK_MHZ);
|
||||
i2c->ccr = I2C_CCR_CCR(PCLK_MHZ*5);
|
||||
i2c->trise = (PCLK_MHZ <= 62) ? PCLK_MHZ + 1 : 63;
|
||||
i2c->cr2 = I2C_CR2_FREQ(36);
|
||||
i2c->ccr = I2C_CCR_CCR(180);
|
||||
i2c->trise = 37;
|
||||
i2c->cr1 = I2C_CR1_PE;
|
||||
|
||||
if (!reinit) {
|
||||
|
|
@ -632,7 +611,11 @@ bool_t lcd_init(void)
|
|||
lcd_rows = 4;
|
||||
} else {
|
||||
lcd_columns = (ff_cfg.display_type >> _DISPLAY_lcd_columns) & 63;
|
||||
lcd_columns = max_t(uint8_t, lcd_columns, 16);
|
||||
lcd_columns = min_t(uint8_t, lcd_columns, 40);
|
||||
lcd_rows = (ff_cfg.display_type >> _DISPLAY_lcd_rows) & 7;
|
||||
lcd_rows = max_t(uint8_t, lcd_rows, 2);
|
||||
lcd_rows = min_t(uint8_t, lcd_rows, 4);
|
||||
}
|
||||
|
||||
if (a != 0) {
|
||||
|
|
@ -641,14 +624,10 @@ bool_t lcd_init(void)
|
|||
i2c_addr = a;
|
||||
} else {
|
||||
is_oled_display = FALSE;
|
||||
lcd_columns = ff_cfg.osd_columns;
|
||||
if (ff_cfg.display_type == DISPLAY_auto)
|
||||
lcd_columns = 40;
|
||||
}
|
||||
|
||||
lcd_columns = max_t(uint8_t, lcd_columns, 16);
|
||||
lcd_columns = min_t(uint8_t, lcd_columns, 40);
|
||||
lcd_rows = max_t(uint8_t, lcd_rows, 2);
|
||||
lcd_rows = min_t(uint8_t, lcd_rows, 4);
|
||||
|
||||
lcd_clear();
|
||||
|
||||
}
|
||||
|
|
@ -715,8 +694,11 @@ bool_t lcd_init(void)
|
|||
i2c->cr2 |= I2C_CR2_DMAEN;
|
||||
dma_start(p - buffer);
|
||||
|
||||
if (!reinit)
|
||||
/* Wait for DMA engine to initialise RAM, then turn on backlight. */
|
||||
if (!reinit) {
|
||||
lcd_sync();
|
||||
lcd_backlight(TRUE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
|
@ -1050,9 +1032,9 @@ static void oled_init_fast_mode(void)
|
|||
i2c->cr1 = 0;
|
||||
|
||||
/* Fast Mode (400kHz). */
|
||||
i2c->cr2 = I2C_CR2_FREQ(PCLK_MHZ);
|
||||
i2c->ccr = I2C_CCR_FS | I2C_CCR_CCR(PCLK_MHZ*5/6);
|
||||
i2c->trise = PCLK_MHZ*3/10 + 1;
|
||||
i2c->cr2 = I2C_CR2_FREQ(36);
|
||||
i2c->ccr = I2C_CCR_FS | I2C_CCR_CCR(30);
|
||||
i2c->trise = 12;
|
||||
i2c->cr1 = I2C_CR1_PE;
|
||||
i2c->cr2 |= I2C_CR2_ITERREN;
|
||||
}
|
||||
|
|
@ -1076,6 +1058,7 @@ static void oled_init(void)
|
|||
0xa0, /* segment mapping (default) */
|
||||
0xc0, /* com scan direction (default) */
|
||||
};
|
||||
const uint8_t *cmds;
|
||||
uint8_t dynamic_cmds[7], *dc;
|
||||
uint8_t *p = buffer;
|
||||
|
||||
|
|
@ -1099,13 +1082,9 @@ static void oled_init(void)
|
|||
*dc++ = (oled_height == 64) ? 0x12 : 0x02;
|
||||
p += oled_queue_cmds(p, dynamic_cmds, dc - dynamic_cmds);
|
||||
|
||||
/* Display orientation. */
|
||||
dc = dynamic_cmds;
|
||||
memcpy(dc, (ff_cfg.display_type & DISPLAY_rotate) ? rot_cmds : norot_cmds,
|
||||
2);
|
||||
if (ff_cfg.display_type & DISPLAY_hflip)
|
||||
dc[0] ^= 1;
|
||||
p += oled_queue_cmds(p, dc, 2);
|
||||
/* Display is right-way-up, or rotated. */
|
||||
cmds = (ff_cfg.display_type & DISPLAY_rotate) ? rot_cmds : norot_cmds;
|
||||
p += oled_queue_cmds(p, cmds, sizeof(rot_cmds));
|
||||
|
||||
/* Start off the I2C transaction. */
|
||||
p += oled_start_i2c(p);
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@
|
|||
static uint8_t DAT_PIN = 10;
|
||||
static uint8_t CLK_PIN = 11;
|
||||
|
||||
/* TM1651, 74HC164: Alphanumeric segment arrangements.
|
||||
* Bit positions 0-6 correspond to conventional segment labels A-G resp. */
|
||||
/* TM1651, 74HC164: Alphanumeric segment arrangements. */
|
||||
static const uint8_t letters[] = {
|
||||
0x77, 0x7c, 0x58, 0x5e, 0x79, 0x71, 0x6f, 0x74, 0x04, /* a-i */
|
||||
0x0e, 0x08, 0x38, 0x40, 0x54, 0x5c, 0x73, 0x67, 0x50, /* j-r */
|
||||
|
|
@ -262,7 +261,7 @@ void led_7seg_write_decimal(unsigned int val)
|
|||
|
||||
void led_7seg_init(void)
|
||||
{
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
if (is_32pin_mcu) {
|
||||
DAT_PIN = 6; /* PB6 */
|
||||
CLK_PIN = 7; /* PB7 */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3748,8 +3748,6 @@ FRESULT f_open (
|
|||
|
||||
if (!fp) return FR_INVALID_OBJECT;
|
||||
|
||||
dj.obj.attr = 0; /* FlashFloppy: avoid uninitialised assignment warn */
|
||||
|
||||
/* Get logical drive number */
|
||||
mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND;
|
||||
res = mount_volume(&path, &fs, mode);
|
||||
|
|
|
|||
124
src/floppy.c
124
src/floppy.c
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#define GPI_bus GPI_floating
|
||||
#define GPO_bus GPO_pushpull(_2MHz,O_FALSE)
|
||||
#define AFO_bus _AFO_pushpull(_2MHz,O_FALSE)
|
||||
#define AFO_bus (AFO_pushpull(_2MHz) | (O_FALSE<<4))
|
||||
|
||||
#define GPO_rdata GPO_bus
|
||||
#define AFO_rdata AFO_bus
|
||||
|
|
@ -34,8 +34,6 @@ static time_t prefetch_start_time;
|
|||
static uint32_t max_prefetch_us;
|
||||
|
||||
struct drive;
|
||||
static always_inline void drive_change_pin(
|
||||
struct drive *drv, uint8_t pin, bool_t assert);
|
||||
static always_inline void drive_change_output(
|
||||
struct drive *drv, uint8_t outp, bool_t assert);
|
||||
|
||||
|
|
@ -132,20 +130,13 @@ static void drive_change_output(
|
|||
|
||||
static void update_amiga_id(struct drive *drv, bool_t amiga_hd_id)
|
||||
{
|
||||
/* JC and pin 34 are overridden only for the Amiga interface. */
|
||||
if (fintf_mode != FINTF_AMIGA) {
|
||||
drv->amiga_pin34 = FALSE;
|
||||
board_jc_set_mode(GPI_pull_up);
|
||||
/* Only for the Amiga interface, with hacked RDY (pin 34) signal. */
|
||||
if (fintf_mode != FINTF_AMIGA)
|
||||
return;
|
||||
}
|
||||
|
||||
/* JC and HDEN are set according to Amiga density. */
|
||||
board_jc_set_mode(GPO_opendrain(_2MHz, amiga_hd_id));
|
||||
drive_change_output(drv, outp_hden, amiga_hd_id);
|
||||
|
||||
/* If pin 34 is explicitly configured, we do not mess with it. */
|
||||
drv->amiga_pin34 = (pin34 == outp_unused);
|
||||
if (!drv->amiga_pin34)
|
||||
if (pin34 != outp_unused)
|
||||
return;
|
||||
|
||||
IRQ_global_disable();
|
||||
|
|
@ -154,20 +145,13 @@ static void update_amiga_id(struct drive *drv, bool_t amiga_hd_id)
|
|||
* every time the drive is selected. */
|
||||
update_SELA_irq(amiga_hd_id);
|
||||
|
||||
if (ff_cfg.motor_delay == MOTOR_ignore) {
|
||||
/* Best-effort pin 34 handling:
|
||||
* DD-ID: We permanently assert pin 34, even when no disk is inserted.
|
||||
* Properly we should only do this when MTR is asserted.
|
||||
* HD-ID: Without knowledge of MTR signal we cannot synchronise the
|
||||
* HD-ID sequence 101010... with the host poll loop. It turns out that
|
||||
* starting with pin 34 asserted when the HD image is mounted seems to
|
||||
* generally work! (But see GitHub issue #354) */
|
||||
drive_change_pin(&drive, pin_34, TRUE);
|
||||
} else {
|
||||
/* Do nothing here. Pin 34 will be updated by IRQ_MOTOR() via
|
||||
* motor_chgrst_update_status(). */
|
||||
IRQ_global_enable();
|
||||
}
|
||||
/* DD-ID: !!HACK!! We permanently assert pin 34, even when no disk is
|
||||
* inserted. Properly we should only do this when MTR is asserted. */
|
||||
/* HD ID: !!HACK!! Without knowledge of MTR signal we cannot synchronise
|
||||
* the HD-ID sequence 101010... with the host poll loop. It turns out that
|
||||
* starting with pin 34 asserted when the HD image is mounted seems to
|
||||
* generally work! */
|
||||
drive_change_pin(&drive, pin_34, TRUE);
|
||||
}
|
||||
|
||||
void floppy_cancel(void)
|
||||
|
|
@ -204,7 +188,7 @@ void floppy_cancel(void)
|
|||
index.fake_fired = FALSE;
|
||||
barrier(); /* /then/ cancel index.timer_deassert */
|
||||
timer_cancel(&index.timer_deassert);
|
||||
motor_chgrst_update_status(drv);
|
||||
motor_chgrst_eject(drv);
|
||||
|
||||
/* Set outputs for empty drive. */
|
||||
barrier();
|
||||
|
|
@ -307,20 +291,21 @@ void floppy_init(void)
|
|||
|
||||
board_floppy_init();
|
||||
|
||||
if (0) {
|
||||
timer_init(&drv->step.timer, drive_step_timer, drv);
|
||||
timer_init(&drv->motor.timer, motor_spinup_timer, drv);
|
||||
timer_init(&drv->chgrst_timer, chgrst_timer, drv);
|
||||
|
||||
}
|
||||
drive_configure_output_pin(pin_02);
|
||||
drive_configure_output_pin(pin_08);
|
||||
drive_configure_output_pin(pin_26);
|
||||
drive_configure_output_pin(pin_28);
|
||||
drive_configure_output_pin(pin_34);
|
||||
|
||||
if (0) {
|
||||
drive_change_output(drv, outp_dskchg, TRUE);
|
||||
drive_change_output(drv, outp_wrprot, TRUE);
|
||||
drive_change_output(drv, outp_trk0, TRUE);
|
||||
|
||||
floppy_init_irqs();
|
||||
|
||||
IRQx_set_prio(FLOPPY_SOFTIRQ, FLOPPY_SOFTIRQ_PRI);
|
||||
|
|
@ -329,7 +314,67 @@ void floppy_init(void)
|
|||
timer_init(&index.timer, index_assert, NULL);
|
||||
timer_init(&index.timer_deassert, index_deassert, NULL);
|
||||
|
||||
motor_chgrst_setup_exti();
|
||||
motor_chgrst_eject(drv);
|
||||
}
|
||||
}
|
||||
|
||||
void tone(int hz, int ms)
|
||||
{
|
||||
int us_delay = 1000000 / hz;
|
||||
int h = us_delay / 4;
|
||||
int l = us_delay - h;
|
||||
int n = (ms*1000) / us_delay;
|
||||
while (n--) {
|
||||
gpio_write_pin(gpiob, pin_28, O_TRUE);
|
||||
delay_us(h);
|
||||
gpio_write_pin(gpiob, pin_28, O_FALSE);
|
||||
delay_us(l);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int get_inputs(void)
|
||||
{
|
||||
unsigned int x = 0;
|
||||
x |= !gpio_read_pin(gpiob, 4); /* 32(16), side */
|
||||
x <<= 1;
|
||||
x |= !gpio_read_pin(gpiob, 9); /* 24(12), wgate */
|
||||
x <<= 1;
|
||||
x |= !gpio_read_pin(gpioa, 8); /* 22(11), wdata */
|
||||
x <<= 1;
|
||||
x |= !gpio_read_pin(gpioa, 1); /* 20(10), step */
|
||||
x <<= 1;
|
||||
x |= !gpio_read_pin(gpiob, 0); /* 18(9), dir */
|
||||
x <<= 1;
|
||||
x |= !gpio_read_pin(gpioa, 0); /* 10(5), sela */
|
||||
return x;
|
||||
}
|
||||
|
||||
int floppy_test(void)
|
||||
{
|
||||
int pins[] = { pin_02, pin_08, pin_26, pin_28, pin_rdata+16, pin_34 };
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < 10; j++) {
|
||||
for (i = 0; i < ARRAY_SIZE(pins); i++) {
|
||||
int pin = pins[i];
|
||||
GPIO _gp = (pin < 16) ? gpiob : gpioa;
|
||||
pin &= 15;
|
||||
gpio_write_pin(_gp, pin, O_TRUE);
|
||||
delay_ms(1);
|
||||
if (get_inputs() != m(i)) {
|
||||
gpio_write_pin(_gp, pin, O_FALSE);
|
||||
goto error;
|
||||
}
|
||||
gpio_write_pin(_gp, pin, O_FALSE);
|
||||
delay_ms(1);
|
||||
if (get_inputs() != 0)
|
||||
goto error;
|
||||
}}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void floppy_insert(unsigned int unit, struct slot *slot)
|
||||
|
|
@ -343,7 +388,7 @@ void floppy_insert(unsigned int unit, struct slot *slot)
|
|||
floppy_mount(slot);
|
||||
im = image;
|
||||
|
||||
if (im->write_bc_ticks < sampleclk_ns(1500))
|
||||
if (im->write_bc_ticks < sysclk_ns(1500))
|
||||
drive_change_output(drv, outp_hden, TRUE);
|
||||
|
||||
timer_dma_init();
|
||||
|
|
@ -354,7 +399,7 @@ void floppy_insert(unsigned int unit, struct slot *slot)
|
|||
drive_change_output(drv, outp_wrprot, FALSE);
|
||||
barrier();
|
||||
drv->inserted = TRUE;
|
||||
motor_chgrst_update_status(drv); /* update RDY + motor state */
|
||||
motor_chgrst_insert(drv); /* update RDY + motor state */
|
||||
if (ff_cfg.chgrst <= CHGRST_delay(15))
|
||||
timer_set(&drv->chgrst_timer, time_now() + ff_cfg.chgrst*time_ms(500));
|
||||
}
|
||||
|
|
@ -433,7 +478,8 @@ static void floppy_sync_flux(void)
|
|||
|
||||
/* If we crossed the index mark while filling the DMA buffer then we
|
||||
* need to set up the index pulse (usually done by IRQ_rdata_dma). */
|
||||
if (image_ticks_since_index(drv->image) < sampleclk_stk(sync_pos)) {
|
||||
if (image_ticks_since_index(drv->image)
|
||||
< (sync_pos*(SYSCLK_MHZ/STK_MHZ))) {
|
||||
|
||||
/* Sum all flux timings in the DMA buffer. */
|
||||
const uint16_t buf_mask = ARRAY_SIZE(dma_rd->buf) - 1;
|
||||
|
|
@ -445,7 +491,7 @@ static void floppy_sync_flux(void)
|
|||
ticks -= image_ticks_since_index(drv->image);
|
||||
|
||||
/* Calculate deadline for index timer. */
|
||||
ticks /= SAMPLECLK_MHZ/TIME_MHZ;
|
||||
ticks /= SYSCLK_MHZ/TIME_MHZ;
|
||||
timer_set(&index.timer, time_now() + ticks);
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +533,7 @@ static bool_t dma_rd_handle(struct drive *drv)
|
|||
read_start_pos %= im->stk_per_rev;
|
||||
/* Seek to the new track. */
|
||||
track = drive_calc_track(drv);
|
||||
read_start_pos *= SAMPLECLK_MHZ/STK_MHZ;
|
||||
read_start_pos *= SYSCLK_MHZ/STK_MHZ;
|
||||
if (in_da_mode(im, track>>1) && (drv->outp & m(outp_wrprot))
|
||||
&& !volume_readonly()) {
|
||||
/* Remove write-protect when driven into D-A mode. */
|
||||
|
|
@ -496,7 +542,7 @@ static bool_t dma_rd_handle(struct drive *drv)
|
|||
if (image_setup_track(im, track, &read_start_pos))
|
||||
return TRUE;
|
||||
prefetch_start_time = time_now();
|
||||
read_start_pos /= SAMPLECLK_MHZ/STK_MHZ;
|
||||
read_start_pos /= SYSCLK_MHZ/STK_MHZ;
|
||||
sync_pos = read_start_pos;
|
||||
if (!drv->index_suppressed) {
|
||||
/* Set the deadline to match existing index timing. */
|
||||
|
|
@ -629,10 +675,6 @@ static void motor_spinup_timer(void *_drv)
|
|||
struct drive *drv = _drv;
|
||||
|
||||
drv->motor.on = TRUE;
|
||||
if (drv->amiga_pin34) {
|
||||
IRQ_global_disable();
|
||||
drive_change_pin(drv, pin_34, TRUE);
|
||||
}
|
||||
drive_change_output(drv, outp_rdy, TRUE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ static struct drive {
|
|||
bool_t writing;
|
||||
bool_t sel;
|
||||
bool_t index_suppressed; /* disable IDX while writing to USB stick */
|
||||
bool_t amiga_pin34;
|
||||
uint8_t outp;
|
||||
volatile bool_t inserted;
|
||||
struct timer chgrst_timer;
|
||||
|
|
@ -252,17 +251,17 @@ static void timer_dma_init(void)
|
|||
IRQx_enable(dma_wdata_irq);
|
||||
|
||||
/* RDATA Timer setup:
|
||||
* The counter is incremented at SAMPLECLK rate.
|
||||
* The counter is incremented at full SYSCLK rate.
|
||||
*
|
||||
* Ch.2 (RDATA) is in PWM mode 1. It outputs O_TRUE for 400ns and then
|
||||
* O_FALSE until the counter reloads. By changing the ARR via DMA we alter
|
||||
* the time between (fixed-width) O_TRUE pulses, mimicking floppy drive
|
||||
* timings. */
|
||||
tim_rdata->psc = (SYSCLK_MHZ/SAMPLECLK_MHZ) - 1;
|
||||
tim_rdata->psc = 0;
|
||||
tim_rdata->ccmr1 = (TIM_CCMR1_CC2S(TIM_CCS_OUTPUT) |
|
||||
TIM_CCMR1_OC2M(TIM_OCM_PWM1));
|
||||
tim_rdata->ccer = TIM_CCER_CC2E | ((O_TRUE==0) ? TIM_CCER_CC2P : 0);
|
||||
tim_rdata->ccr2 = sampleclk_ns(400);
|
||||
tim_rdata->ccr2 = sysclk_ns(400);
|
||||
tim_rdata->dier = TIM_DIER_UDE;
|
||||
tim_rdata->cr2 = 0;
|
||||
|
||||
|
|
@ -281,13 +280,13 @@ static void timer_dma_init(void)
|
|||
DMA_CCR_EN);
|
||||
|
||||
/* WDATA Timer setup:
|
||||
* The counter runs from 0x0000-0xFFFF inclusive at SAMPLECLK rate.
|
||||
* The counter runs from 0x0000-0xFFFF inclusive at full SYSCLK rate.
|
||||
*
|
||||
* Ch.1 (WDATA) is in Input Capture mode, sampling on every clock and with
|
||||
* no input prescaling or filtering. Samples are captured on the falling
|
||||
* edge of the input (CCxP=1). DMA is used to copy the sample into a ring
|
||||
* buffer for batch processing in the DMA-completion ISR. */
|
||||
tim_wdata->psc = (SYSCLK_MHZ/SAMPLECLK_MHZ) - 1;
|
||||
tim_wdata->psc = 0;
|
||||
tim_wdata->arr = 0xffff;
|
||||
tim_wdata->ccmr1 = TIM_CCMR1_CC1S(TIM_CCS_INPUT_TI1);
|
||||
tim_wdata->dier = TIM_DIER_CC1DE;
|
||||
|
|
@ -365,7 +364,7 @@ static void wdata_stop(void)
|
|||
image->wr_prod++;
|
||||
|
||||
#if !defined(QUICKDISK)
|
||||
if (!ff_cfg.index_suppression && ff_cfg.write_drain != WDRAIN_realtime) {
|
||||
if (!ff_cfg.index_suppression) {
|
||||
/* Opportunistically insert an INDEX pulse ahead of writeback. */
|
||||
drive_change_output(drv, outp_index, TRUE);
|
||||
index.fake_fired = TRUE;
|
||||
|
|
@ -408,10 +407,10 @@ static void wdata_start(void)
|
|||
tim_wdata->ccer = TIM_CCER_CC1E | TIM_CCER_CC1P;
|
||||
tim_wdata->cr1 = TIM_CR1_CEN;
|
||||
|
||||
/* Find rotational start position of the write, in SAMPLECLK ticks. */
|
||||
/* Find rotational start position of the write, in SYSCLK ticks. */
|
||||
start_pos = max_t(int32_t, 0, time_diff(index.prev_time, time_now()));
|
||||
start_pos %= drive.image->stk_per_rev;
|
||||
start_pos *= SAMPLECLK_MHZ / STK_MHZ;
|
||||
start_pos *= SYSCLK_MHZ / STK_MHZ;
|
||||
write = get_write(image, image->wr_prod);
|
||||
write->start = start_pos;
|
||||
write->track = drive_calc_track(&drive);
|
||||
|
|
@ -636,21 +635,23 @@ static void IRQ_rdata_dma(void)
|
|||
/* Subtract current flux offset beyond the index. */
|
||||
ticks -= image_ticks_since_index(drv->image);
|
||||
/* Calculate deadline for index timer. */
|
||||
ticks /= SAMPLECLK_MHZ/TIME_MHZ;
|
||||
ticks /= SYSCLK_MHZ/TIME_MHZ;
|
||||
timer_set(&index.timer, now + ticks);
|
||||
}
|
||||
|
||||
static void IRQ_wdata_dma(void)
|
||||
{
|
||||
const uint16_t buf_mask = ARRAY_SIZE(dma_rd->buf) - 1;
|
||||
uint16_t cons, prod, prev, next;
|
||||
uint16_t cons, prod, prev, curr, next;
|
||||
uint16_t cell = image->write_bc_ticks, window;
|
||||
uint32_t bc_dat = 0, bc_prod;
|
||||
uint32_t *bc_buf = image->bufs.write_bc.p;
|
||||
unsigned int sync = image->sync;
|
||||
unsigned int bc_bufmask = (image->bufs.write_bc.len / 4) - 1;
|
||||
int curr, cell = image->write_bc_ticks;
|
||||
struct write *write = NULL;
|
||||
|
||||
window = cell + (cell >> 1);
|
||||
|
||||
/* Clear DMA peripheral interrupts. */
|
||||
dma1->ifcr = DMA_IFCR_CGIF(dma_wdata_ch);
|
||||
|
||||
|
|
@ -674,20 +675,15 @@ static void IRQ_wdata_dma(void)
|
|||
bc_dat = image->write_bc_window;
|
||||
for (cons = dma_wr->cons; cons != prod; cons = (cons+1) & buf_mask) {
|
||||
next = dma_wr->buf[cons];
|
||||
curr = (int16_t)(next - prev) - (cell >> 1);
|
||||
if (unlikely(curr < 0)) {
|
||||
/* Runt flux, much shorter than bitcell clock. Merge it forward. */
|
||||
continue;
|
||||
}
|
||||
curr = next - prev;
|
||||
prev = next;
|
||||
while ((curr -= cell) > 0) {
|
||||
while (curr > window) {
|
||||
curr -= cell;
|
||||
bc_dat <<= 1;
|
||||
bc_prod++;
|
||||
if (!(bc_prod&31))
|
||||
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_prod++;
|
||||
switch (sync) {
|
||||
|
|
|
|||
|
|
@ -84,13 +84,6 @@ static void reset_to_main_fw(void)
|
|||
system_reset();
|
||||
}
|
||||
|
||||
static bool_t main_fw_requested(void)
|
||||
{
|
||||
bool_t req = (*(volatile uint32_t *)_ebss == MAIN_FW_KEY);
|
||||
*(volatile uint32_t *)_ebss = 0;
|
||||
return req;
|
||||
}
|
||||
|
||||
static bool_t fw_update_requested(void)
|
||||
{
|
||||
bool_t requested;
|
||||
|
|
@ -378,17 +371,17 @@ int main(void)
|
|||
bool_t update_requested;
|
||||
|
||||
/* Relocate DATA. Initialise BSS. */
|
||||
if (&_sdat[0] != &_ldat[0])
|
||||
if (_sdat != _ldat)
|
||||
memcpy(_sdat, _ldat, _edat-_sdat);
|
||||
memset(_sbss, 0, _ebss-_sbss);
|
||||
|
||||
update_requested = fw_update_requested();
|
||||
|
||||
if (main_fw_requested() && !update_requested) {
|
||||
if (1) {//main_fw_requested() && !update_requested) {
|
||||
/* Check for, and jump to, the main firmware. */
|
||||
uint32_t sp = *(uint32_t *)FIRMWARE_START;
|
||||
uint32_t pc = *(uint32_t *)(FIRMWARE_START + 4);
|
||||
if (sp != ~0u) { /* only if firmware is apparently not erased */
|
||||
if (1) {//sp != ~0u) { /* only if firmware is apparently not erased */
|
||||
asm volatile (
|
||||
"mov sp,%0 ; blx %1"
|
||||
:: "r" (sp), "r" (pc));
|
||||
|
|
@ -436,6 +429,8 @@ int main(void)
|
|||
usbh_msc_init();
|
||||
usbh_msc_buffer_set(USBH_Cfg_Rx_Buffer);
|
||||
|
||||
for (;;); /* XXX */
|
||||
|
||||
/* Wait for buttons to be pressed. */
|
||||
wait_buttons(LOW);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,40 +5,41 @@
|
|||
*
|
||||
* SFRC922, SFRC922C, SFRC922D et al
|
||||
* Original LQFP64 designs, using STM or AT chips.
|
||||
* Buttons: PC6 = Select, PC7 = Right, PC8 = Left
|
||||
* Buttons: PC6 = Select, PC7 = Left, PC7 = Right
|
||||
* Rotary: PC10, PC11
|
||||
*
|
||||
* SFRC922AT3
|
||||
* LQFP48 design, missing rotary header.
|
||||
* Alternative rotary location at PA13, PA14
|
||||
* Buttons: PA5 = Select, PA4 = Right, PA3 = Left
|
||||
* Buttons: PA5 = Select, PA4 = Left, PA3 = Right
|
||||
*
|
||||
* SFRKC30AT4, SFRKC30.AT4, SFRKC30.AT4.7 (KC30 Rev 1)
|
||||
* LQFP64 designs with original rotary header and "KC30" rotary header.
|
||||
* Buttons: PA5 = Select, PA4 = Right, PA3 = Left
|
||||
* Buttons: PA5 = Select, PA4 = Left, PA3 = Right
|
||||
* Rotary: PC10, PC11
|
||||
* KC30: PF6/PH2 = Select, PA6/PA15 = Rotary
|
||||
*
|
||||
* SFRKC30AT3 (KC30 Rev 1)
|
||||
* LQFP48 design similar to SFRC922AT3 but with the "KC30" rotary header.
|
||||
* Buttons: PA5 = Select, PA4 = Right, PA3 = Left
|
||||
* Buttons: PA5 = Select, PA4 = Left, PA3 = Right
|
||||
* KC30: PF6/PH2 = Select, PA6/PA15 = Rotary
|
||||
*
|
||||
* SFRKC30.AT2 (KC30 Rev 1)
|
||||
* QFN32 design with various pin changes and features missing. There are
|
||||
* two versions; the newer version reintroduces jumper position JC.
|
||||
* QFN32 design with various pin changes and features missing:
|
||||
* Missing:
|
||||
* * Original rotary header
|
||||
* * JC jumper position (old version)
|
||||
* * JC jumper position
|
||||
* Relocated to new MCU pins:
|
||||
* * Display header is moved to PB[7:6] using I2C1 instead of I2C2
|
||||
* * KC30 header SELECT/button pin
|
||||
* * Floppy output pins 2 and 26
|
||||
* * Floppy WGATE input pin
|
||||
* * JC jumper at PA9 (new version)
|
||||
* Buttons: PA5 = Select, PA4 = Right, PA3 = Left
|
||||
* Buttons: PA5 = Select, PA4 = Left, PA3 = Right
|
||||
* KC30: PA10 = Select, PA6/PA15 = Rotary
|
||||
*
|
||||
* Future QFN32:
|
||||
* Agreed that JC will be implemented at PA9.
|
||||
*
|
||||
* SFRKC30.AT4.35 (KC30 Rev 2)
|
||||
* As SFRKC30.AT4 except PC15 is tied HIGH for identification.
|
||||
* MOTOR (pin 16) is optionally jumpered to PB12 with 1k pullup to 5v.
|
||||
|
|
@ -49,7 +50,8 @@
|
|||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
uint8_t mcu_package;
|
||||
bool_t is_32pin_mcu;
|
||||
static bool_t is_48pin_mcu;
|
||||
uint8_t has_kc30_header;
|
||||
|
||||
#if MCU == STM32F105
|
||||
|
|
@ -74,36 +76,39 @@ static void gpio_pull_up_pins(GPIO gpio, uint16_t mask)
|
|||
unsigned int board_get_buttons(void)
|
||||
{
|
||||
/* All recent Gotek revisions, regardless of MCU model or package:
|
||||
* PA5 = Select, PA4 = Right, PA3 = Left.
|
||||
* PA5 = Select, PA4 = Left, PA3 = Right.
|
||||
* Note: "Enhanced Gotek" design uses these pins so must skip them here. */
|
||||
unsigned int x = (board_id == BRDREV_Gotek_standard)
|
||||
? gpioa->idr >> 3 : -1;
|
||||
/* Earlier Gotek revisions (all of which are LQFP64):
|
||||
* PC6 = Select, PC7 = Right, PC8 = Left. */
|
||||
if (mcu_package == MCU_LQFP64)
|
||||
* PC6 = Select, PC7 = Left, PC8 = Right. */
|
||||
if (!is_48pin_mcu && !is_32pin_mcu)
|
||||
x &= _rbit32(gpioc->idr) >> 23;
|
||||
x = ~x & 7;
|
||||
if (has_kc30_header) {
|
||||
/* KC30 Select pin, Artery models only:
|
||||
* PF6/PH2 = Select; except QFN32: PA10 = Select. */
|
||||
unsigned int kc30 = (mcu_package == MCU_QFN32
|
||||
unsigned int kc30 = (is_32pin_mcu
|
||||
? gpioa->idr >> (10-2) /* PA10 */
|
||||
: kc30_sel_gpio->idr >> (kc30_sel_pin-2));
|
||||
x |= ~kc30 & 4;
|
||||
}
|
||||
return x;
|
||||
/* SLR -> SRL */
|
||||
return (x&4) | ((x&1)<<1) | ((x&2)>>1);
|
||||
}
|
||||
|
||||
unsigned int board_get_rotary(void)
|
||||
{
|
||||
unsigned int x = 3;
|
||||
if ((mcu_package != MCU_QFN32) && (ff_cfg.chgrst != CHGRST_pa14)) {
|
||||
/* Alternative location at PA13, PA14. */
|
||||
x &= gpioa->idr >> 13;
|
||||
}
|
||||
if (mcu_package == MCU_LQFP64) {
|
||||
unsigned int x;
|
||||
if (is_32pin_mcu) {
|
||||
/* No original rotary header. No alternative location. */
|
||||
x = 3;
|
||||
} else if (is_48pin_mcu) {
|
||||
/* No original rotary header. Alternative location at PA13, PA14. */
|
||||
x = (ff_cfg.chgrst != CHGRST_pa14) ? gpioa->idr >> 13 : 3;
|
||||
} else {
|
||||
/* Original rotary header at PC10, PC11. */
|
||||
x &= gpioc->idr >> 10;
|
||||
x = gpioc->idr >> 10;
|
||||
}
|
||||
if (has_kc30_header) {
|
||||
/* KC30 rotary pins PA6, PA15. */
|
||||
|
|
@ -111,31 +116,33 @@ unsigned int board_get_rotary(void)
|
|||
kc30 = ((kc30>>6)&1) | ((kc30>>(15-1))&2);
|
||||
x &= kc30;
|
||||
}
|
||||
return x;
|
||||
return x&3;
|
||||
}
|
||||
|
||||
uint32_t board_rotary_exti_mask;
|
||||
void board_setup_rotary_exti(void)
|
||||
{
|
||||
uint32_t m = 0;
|
||||
if ((mcu_package != MCU_QFN32) && (ff_cfg.chgrst != CHGRST_pa14)) {
|
||||
if (is_48pin_mcu) {
|
||||
/* Alternative location at PA13, PA14. */
|
||||
exti_route_pa(13);
|
||||
exti_route_pa(14);
|
||||
m |= m(13) | m(14);
|
||||
}
|
||||
if (mcu_package == MCU_LQFP64) {
|
||||
if (ff_cfg.chgrst != CHGRST_pa14) {
|
||||
exti_route_pa(13);
|
||||
exti_route_pa(14);
|
||||
m |= m(13) | m(14);
|
||||
}
|
||||
} else if (!is_32pin_mcu) {
|
||||
/* Original rotary header at PC10, PC11. */
|
||||
exti_route_pc(10);
|
||||
exti_route_pc(11);
|
||||
m |= m(10) | m(11);
|
||||
}
|
||||
if (((has_kc30_header == 1) && (ff_cfg.motor_delay == MOTOR_ignore))
|
||||
|| (has_kc30_header == 2) /* No conflict with motor on PB12 */) {
|
||||
if (has_kc30_header) {
|
||||
/* KC30 rotary pins PA6, PA15. */
|
||||
exti_route_pa(6);
|
||||
exti_route_pa(15);
|
||||
m |= m(6) | m(15);
|
||||
if (ff_cfg.motor_delay == MOTOR_ignore) {
|
||||
exti_route_pa(6);
|
||||
exti_route_pa(15);
|
||||
m |= m(6) | m(15);
|
||||
}
|
||||
}
|
||||
board_rotary_exti_mask = m;
|
||||
exti->rtsr |= m;
|
||||
|
|
@ -143,22 +150,9 @@ void board_setup_rotary_exti(void)
|
|||
exti->imr |= m;
|
||||
}
|
||||
|
||||
void board_jc_set_mode(unsigned int mode)
|
||||
{
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
#if !defined(NDEBUG)
|
||||
/* PA9 is used for serial tx */
|
||||
#else
|
||||
gpio_configure_pin(gpioa, 9, mode);
|
||||
#endif
|
||||
} else {
|
||||
gpio_configure_pin(gpiob, 1, mode);
|
||||
}
|
||||
}
|
||||
|
||||
bool_t board_jc_strapped(void)
|
||||
{
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
if (is_32pin_mcu) {
|
||||
#if !defined(NDEBUG)
|
||||
return FALSE; /* PA9 is used for serial tx */
|
||||
#else
|
||||
|
|
@ -201,7 +195,7 @@ void board_init(void)
|
|||
switch (dbg->mcu_idcode & 0xfff) {
|
||||
case 0x1c6: /* AT32F415KBU7-4 */
|
||||
case 0x242: /* AT32F415KCU7-4 */
|
||||
mcu_package = MCU_QFN32;
|
||||
is_32pin_mcu = TRUE;
|
||||
id = 0xf;
|
||||
break;
|
||||
}
|
||||
|
|
@ -217,7 +211,7 @@ void board_init(void)
|
|||
* MCU). */
|
||||
board_id = BRDREV_Gotek_standard;
|
||||
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
if (is_32pin_mcu) {
|
||||
|
||||
/* The sole QFN32 board is a KC30 Rev 1 design. */
|
||||
has_kc30_header = 1;
|
||||
|
|
@ -228,8 +222,7 @@ void board_init(void)
|
|||
} else {
|
||||
|
||||
/* 48-pin package has PC12 permanently LOW. */
|
||||
if (!(id & 1))
|
||||
mcu_package = MCU_LQFP48;
|
||||
is_48pin_mcu = !(id & 1);
|
||||
|
||||
/* Check for KC30 Rev 2. */
|
||||
gpio_configure_pin(gpioc, 15, GPI_pull_down);
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ static void board_floppy_init(void)
|
|||
tim2->dier = TIM_DIER_CC2IE;
|
||||
tim2->cr1 = TIM_CR1_CEN;
|
||||
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
if (is_32pin_mcu) {
|
||||
pin_02 = 16 + 14; /* PA14 */
|
||||
pin_26 = 16 + 13; /* PA13 */
|
||||
pin_wgate = 1; /* PB1 */
|
||||
|
|
@ -325,8 +325,7 @@ static void IRQ_STEP_changed(void)
|
|||
drive_change_output(drv, outp_trk0, FALSE);
|
||||
if (dma_rd != NULL) {
|
||||
rdata_stop();
|
||||
if (!ff_cfg.index_suppression
|
||||
&& ff_cfg.track_change != TRKCHG_realtime) {
|
||||
if (!ff_cfg.index_suppression) {
|
||||
/* Opportunistically insert an INDEX pulse ahead of seek op. */
|
||||
drive_change_output(drv, outp_index, TRUE);
|
||||
index.fake_fired = TRUE;
|
||||
|
|
@ -395,12 +394,6 @@ static void IRQ_WGATE_rotary(void)
|
|||
static void IRQ_MOTOR(struct drive *drv)
|
||||
{
|
||||
GPIO gpio = gotek_enhanced() ? gpioa : gpiob;
|
||||
bool_t mtr_asserted = !(gpio->idr & m(pin_motor));
|
||||
|
||||
if (drv->amiga_pin34 && (ff_cfg.motor_delay != MOTOR_ignore)) {
|
||||
IRQ_global_disable();
|
||||
drive_change_pin(drv, pin_34, !mtr_asserted);
|
||||
}
|
||||
|
||||
timer_cancel(&drv->motor.timer);
|
||||
drv->motor.on = FALSE;
|
||||
|
|
@ -412,7 +405,7 @@ static void IRQ_MOTOR(struct drive *drv)
|
|||
/* Motor signal ignored -- MOTOR ON */
|
||||
drv->motor.on = TRUE;
|
||||
drive_change_output(drv, outp_rdy, TRUE);
|
||||
} else if (!mtr_asserted) {
|
||||
} else if (gpio->idr & m(pin_motor)) {
|
||||
/* Motor signal off -- MOTOR OFF */
|
||||
drive_change_output(drv, outp_rdy, FALSE);
|
||||
} else {
|
||||
|
|
@ -461,25 +454,36 @@ static void motor_chgrst_update_status(struct drive *drv)
|
|||
IRQx_set_pending(MOTOR_CHGRST_IRQ);
|
||||
}
|
||||
|
||||
uint32_t motor_chgrst_exti_mask;
|
||||
void motor_chgrst_setup_exti(void)
|
||||
static void motor_chgrst_insert(struct drive *drv)
|
||||
{
|
||||
uint32_t m = 0;
|
||||
uint32_t imr = exti->imr;
|
||||
|
||||
if (ff_cfg.motor_delay != MOTOR_ignore) {
|
||||
_exti_route(gotek_enhanced()?0/*PA*/:1/*PB*/, pin_motor);
|
||||
m |= m(pin_motor);
|
||||
imr |= m(pin_motor);
|
||||
}
|
||||
|
||||
if (ff_cfg.chgrst == CHGRST_pa14) {
|
||||
exti_route_pa(pin_chgrst);
|
||||
m |= m(pin_chgrst);
|
||||
imr |= m(pin_chgrst);
|
||||
}
|
||||
|
||||
motor_chgrst_exti_mask = m;
|
||||
exti->imr |= m;
|
||||
exti->imr = imr;
|
||||
motor_chgrst_update_status(drv);
|
||||
}
|
||||
|
||||
motor_chgrst_update_status(&drive);
|
||||
static void motor_chgrst_eject(struct drive *drv)
|
||||
{
|
||||
uint32_t imr = exti->imr;
|
||||
|
||||
if (ff_cfg.motor_delay != MOTOR_ignore)
|
||||
imr &= ~m(pin_motor);
|
||||
|
||||
if (ff_cfg.chgrst == CHGRST_pa14)
|
||||
imr &= ~m(pin_chgrst);
|
||||
|
||||
exti->imr = imr;
|
||||
motor_chgrst_update_status(drv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ static void board_floppy_init(void)
|
|||
tim2->dier = TIM_DIER_CC2IE;
|
||||
tim2->cr1 = TIM_CR1_CEN;
|
||||
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
if (is_32pin_mcu) {
|
||||
pin_02 = 16 + 14; /* PA14 */
|
||||
pin_26 = 16 + 13; /* PA13 */
|
||||
pin_wgate = 1; /* PB1 */
|
||||
|
|
@ -183,8 +183,8 @@ static void _IRQ_MOTOR_RESET_changed(unsigned int gpioa_idr)
|
|||
|
||||
if (!off) {
|
||||
|
||||
/* 1 second to spin up the motor. */
|
||||
timer_set(&motor.timer, time_now() + time_ms(1000));
|
||||
/* 2 seconds to spin up the motor. */
|
||||
timer_set(&motor.timer, time_now() + time_ms(2000));
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -243,12 +243,6 @@ static void IRQ_rotary_changed(void)
|
|||
IRQ_rotary();
|
||||
}
|
||||
|
||||
uint32_t motor_chgrst_exti_mask;
|
||||
void motor_chgrst_setup_exti(void)
|
||||
{
|
||||
/* Quick Disk does not have configurable MOTOR and CHGRST. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
|
|
|||
|
|
@ -59,88 +59,6 @@ void speaker_pulse(void)
|
|||
timer_set(&pulse.timer, now + volume*volume*(TIME_MHZ/3));
|
||||
}
|
||||
|
||||
static void speaker_hz(unsigned int hz, unsigned int ms)
|
||||
{
|
||||
unsigned int vol = (ff_cfg.notify_volume & NOTIFY_volume_mask) + 1;
|
||||
unsigned int period = STK_MHZ * 1000000 / hz;
|
||||
unsigned int period_on = period * vol * vol / (2*400);
|
||||
unsigned int nr = hz * ms / 1000;
|
||||
while (nr--) {
|
||||
gpio_write_pin(gpio_spk, pin_spk, TRUE);
|
||||
delay_ticks(period_on);
|
||||
gpio_write_pin(gpio_spk, pin_spk, FALSE);
|
||||
delay_ticks(period - period_on);
|
||||
}
|
||||
}
|
||||
|
||||
static void speaker_lock(void)
|
||||
{
|
||||
uint32_t oldpri;
|
||||
oldpri = IRQ_save(TIMER_IRQ_PRI);
|
||||
timer_cancel(&pulse.timer);
|
||||
pulse.state = STATE_masked;
|
||||
IRQ_restore(oldpri);
|
||||
}
|
||||
|
||||
static void speaker_unlock(void)
|
||||
{
|
||||
pulse.state = STATE_idle;
|
||||
}
|
||||
|
||||
static void speaker_notify_slot(unsigned int nr)
|
||||
{
|
||||
while (nr >= 5) {
|
||||
speaker_hz(1500, 100);
|
||||
nr -= 5;
|
||||
if (nr != 0)
|
||||
delay_ms(120);
|
||||
}
|
||||
|
||||
while (nr != 0) {
|
||||
speaker_hz(1500, 40);
|
||||
nr -= 1;
|
||||
if (nr != 0)
|
||||
delay_ms(120);
|
||||
}
|
||||
}
|
||||
|
||||
void speaker_notify_insert(unsigned int slotnr)
|
||||
{
|
||||
if ((ff_cfg.notify_volume & NOTIFY_volume_mask) == 0)
|
||||
return;
|
||||
|
||||
speaker_lock();
|
||||
|
||||
speaker_hz(880, 40); /* a5 */
|
||||
delay_ms(20);
|
||||
speaker_hz(784, 40); /* g5 */
|
||||
delay_ms(20);
|
||||
speaker_hz(1046, 60); /* c6 */
|
||||
|
||||
if (ff_cfg.notify_volume & NOTIFY_slotnr) {
|
||||
delay_ms(300);
|
||||
speaker_notify_slot(slotnr);
|
||||
}
|
||||
|
||||
speaker_unlock();
|
||||
}
|
||||
|
||||
void speaker_notify_eject(void)
|
||||
{
|
||||
if ((ff_cfg.notify_volume & NOTIFY_volume_mask) == 0)
|
||||
return;
|
||||
|
||||
speaker_lock();
|
||||
|
||||
speaker_hz(932, 40); /* a#5 */
|
||||
delay_ms(20);
|
||||
speaker_hz(831, 40); /* g#5 */
|
||||
delay_ms(20);
|
||||
speaker_hz(659, 60); /* e5 */
|
||||
|
||||
speaker_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
|
|
|||
|
|
@ -39,9 +39,7 @@ static bool_t adf_open(struct image *im)
|
|||
im->nr_sides = 2;
|
||||
im->adf.nr_secs = 11;
|
||||
im->tracklen_bc = DD_TRACKLEN_BC;
|
||||
im->ticks_per_cell = ((sampleclk_stk(im->stk_per_rev) * 16u)
|
||||
/ im->tracklen_bc);
|
||||
im->write_bc_ticks = im->ticks_per_cell / 16u;
|
||||
im->ticks_per_cell = (sysclk_stk(im->stk_per_rev) * 16u) / im->tracklen_bc;
|
||||
|
||||
im->nr_cyls = f_size(&im->fp) / (2 * 11 * 512);
|
||||
|
||||
|
|
@ -68,7 +66,7 @@ static void adf_setup_track(
|
|||
{
|
||||
struct image_buf *rd = &im->bufs.read_data;
|
||||
struct image_buf *bc = &im->bufs.read_bc;
|
||||
uint32_t decode_off, sector, start_ticks = start_pos ? *start_pos : 0;
|
||||
uint32_t decode_off, sector, sys_ticks = start_pos ? *start_pos : 0;
|
||||
|
||||
if ((im->cur_track ^ track) & ~1) {
|
||||
/* New cylinder: Refresh the sector maps (ordered by sector #). */
|
||||
|
|
@ -80,7 +78,7 @@ static void adf_setup_track(
|
|||
im->adf.trk_off = track * im->adf.nr_secs * 512;
|
||||
im->cur_track = track;
|
||||
|
||||
im->cur_bc = (start_ticks * 16) / im->ticks_per_cell;
|
||||
im->cur_bc = (sys_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;
|
||||
|
|
|
|||
|
|
@ -78,12 +78,12 @@ static void da_seek_track(struct image *im, uint16_t track)
|
|||
case DA_SD_FM_CYL:
|
||||
dass->nr_sec = 4;
|
||||
im->sync = SYNC_fm;
|
||||
im->write_bc_ticks = sampleclk_us(4);
|
||||
im->write_bc_ticks = sysclk_us(4);
|
||||
break;
|
||||
default:
|
||||
dass->nr_sec = 8;
|
||||
im->sync = SYNC_mfm;
|
||||
im->write_bc_ticks = sampleclk_us(2);
|
||||
im->write_bc_ticks = sysclk_us(2);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ static void da_setup_track(
|
|||
{
|
||||
struct image_buf *rd = &im->bufs.read_data;
|
||||
struct image_buf *bc = &im->bufs.read_bc;
|
||||
uint32_t decode_off, start_ticks = start_pos ? *start_pos : 0;
|
||||
uint32_t decode_off, sys_ticks = start_pos ? *start_pos : 0;
|
||||
unsigned int nsec;
|
||||
|
||||
da_seek_track(im, track);
|
||||
|
|
@ -120,11 +120,11 @@ static void da_setup_track(
|
|||
im->tracklen_bc += im->da.idx_sz;
|
||||
im->tracklen_bc *= 16;
|
||||
|
||||
im->stk_per_rev = stk_sampleclk(im->tracklen_bc * im->write_bc_ticks);
|
||||
im->stk_per_rev = stk_sysclk(im->tracklen_bc * im->write_bc_ticks);
|
||||
|
||||
im->da.trk_sec = 0;
|
||||
|
||||
im->cur_bc = (start_ticks * 16) / im->ticks_per_cell;
|
||||
im->cur_bc = (sys_ticks * 16) / im->ticks_per_cell;
|
||||
im->cur_bc &= ~15;
|
||||
if (im->cur_bc >= im->tracklen_bc)
|
||||
im->cur_bc = 0;
|
||||
|
|
@ -157,7 +157,7 @@ static void da_setup_track(
|
|||
if (start_pos) {
|
||||
image_read_track(im);
|
||||
bc->cons = decode_off * 16;
|
||||
*start_pos = start_ticks;
|
||||
*start_pos = sys_ticks;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
188
src/image/dsk.c
188
src/image/dsk.c
|
|
@ -9,15 +9,11 @@
|
|||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
#define LOG_PREFIX "DSK"
|
||||
|
||||
#define GAP_1 50 /* Post-IAM */
|
||||
#define GAP_2 22 /* Post-IDAM */
|
||||
#define GAP_4A 80 /* Post-Index */
|
||||
#define GAP_SYNC 12
|
||||
|
||||
#define CHUNK_SIZE 1024
|
||||
|
||||
struct dib { /* disk info */
|
||||
char sig[34];
|
||||
char creator[14];
|
||||
|
|
@ -98,14 +94,14 @@ static bool_t dsk_open(struct image *im)
|
|||
|
||||
im->nr_cyls = dib->nr_tracks;
|
||||
im->nr_sides = dib->nr_sides;
|
||||
log("%u cyls, %u sides\n", im->nr_cyls, im->nr_sides);
|
||||
printk("DSK: %u cyls, %u sides\n", im->nr_cyls, im->nr_sides);
|
||||
|
||||
/* DSK data rate is fixed at 2us bitcell. Where the specified track layout
|
||||
* will not fit in regular 100k-bitcell track we simply extend the track
|
||||
* length and thus the period between index pulses. */
|
||||
im->ticks_per_cell = im->write_bc_ticks * 16;
|
||||
|
||||
volume_cache_init(im->bufs.write_data.p + 512 + CHUNK_SIZE,
|
||||
volume_cache_init(im->bufs.write_data.p + 512 + 1024,
|
||||
im->bufs.write_data.p + im->bufs.write_data.len);
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -187,7 +183,7 @@ out:
|
|||
im->dsk.gap4 = (im->tracklen_bc - tracklen) / 16;
|
||||
|
||||
/* Calculate ticks per revolution */
|
||||
im->stk_per_rev = stk_sampleclk(im->tracklen_bc * im->write_bc_ticks);
|
||||
im->stk_per_rev = stk_sysclk(im->tracklen_bc * im->write_bc_ticks);
|
||||
}
|
||||
|
||||
static uint32_t calc_start_pos(struct image *im)
|
||||
|
|
@ -228,9 +224,9 @@ static uint32_t calc_start_pos(struct image *im)
|
|||
im->dsk.decode_pos++;
|
||||
if (decode_off < data_sz(&tib->sib[i])) {
|
||||
/* Data */
|
||||
im->dsk.rd_sec_pos = decode_off / CHUNK_SIZE;
|
||||
im->dsk.rd_sec_pos = decode_off / 1024;
|
||||
im->dsk.decode_data_pos = im->dsk.rd_sec_pos;
|
||||
decode_off %= CHUNK_SIZE;
|
||||
decode_off %= 1024;
|
||||
} else {
|
||||
/* Post Data */
|
||||
decode_off -= data_sz(&tib->sib[i]);
|
||||
|
|
@ -242,8 +238,8 @@ static uint32_t calc_start_pos(struct image *im)
|
|||
} else {
|
||||
/* Pre-index track gap */
|
||||
im->dsk.decode_pos = tib->nr_secs * 4 + 1;
|
||||
im->dsk.decode_data_pos = decode_off / CHUNK_SIZE;
|
||||
decode_off %= CHUNK_SIZE;
|
||||
im->dsk.decode_data_pos = decode_off / 1024;
|
||||
decode_off %= 1024;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +251,7 @@ static void dsk_setup_track(
|
|||
{
|
||||
struct image_buf *rd = &im->bufs.read_data;
|
||||
struct image_buf *bc = &im->bufs.read_bc;
|
||||
uint32_t decode_off, start_ticks = start_pos ? *start_pos : 0;
|
||||
uint32_t decode_off, sys_ticks = start_pos ? *start_pos : 0;
|
||||
uint8_t cyl = track/2, side = track & (im->nr_sides - 1);
|
||||
|
||||
track = cyl*2 + side;
|
||||
|
|
@ -264,24 +260,22 @@ static void dsk_setup_track(
|
|||
|
||||
im->dsk.write_sector = -1;
|
||||
|
||||
im->cur_bc = (start_ticks * 16) / im->ticks_per_cell;
|
||||
im->cur_bc = (sys_ticks * 16) / im->ticks_per_cell;
|
||||
im->cur_bc &= ~15;
|
||||
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;
|
||||
|
||||
decode_off = calc_start_pos(im);
|
||||
|
||||
rd->prod = rd->cons = 0;
|
||||
bc->prod = bc->cons = 0;
|
||||
|
||||
if (start_pos) {
|
||||
decode_off = calc_start_pos(im);
|
||||
|
||||
image_read_track(im);
|
||||
bc->cons = decode_off * 16;
|
||||
*start_pos = start_ticks;
|
||||
} else {
|
||||
im->dsk.decode_pos = 0;
|
||||
*start_pos = sys_ticks;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,10 +299,10 @@ static bool_t dsk_read_track(struct image *im)
|
|||
/* Weak sector -- pick different data each revolution. */
|
||||
off += len * (im->dsk.rev % (tib->sib[i].actual_length / len));
|
||||
}
|
||||
off += im->dsk.rd_sec_pos * CHUNK_SIZE;
|
||||
len -= im->dsk.rd_sec_pos * CHUNK_SIZE;
|
||||
if (len > CHUNK_SIZE) {
|
||||
len = CHUNK_SIZE;
|
||||
off += im->dsk.rd_sec_pos * 1024;
|
||||
len -= im->dsk.rd_sec_pos * 1024;
|
||||
if (len > 1024) {
|
||||
len = 1024;
|
||||
im->dsk.rd_sec_pos++;
|
||||
} else {
|
||||
im->dsk.rd_sec_pos = 0;
|
||||
|
|
@ -352,11 +346,11 @@ static bool_t dsk_read_track(struct image *im)
|
|||
emit_byte(0x4e);
|
||||
} else if (im->dsk.decode_pos == (tib->nr_secs * 4 + 1)) {
|
||||
/* Pre-index track gap */
|
||||
uint16_t sz = im->dsk.gap4 - im->dsk.decode_data_pos * CHUNK_SIZE;
|
||||
if (bc_space < min_t(unsigned int, sz, CHUNK_SIZE))
|
||||
uint16_t sz = im->dsk.gap4 - im->dsk.decode_data_pos * 1024;
|
||||
if (bc_space < min_t(unsigned int, sz, 1024))
|
||||
return FALSE;
|
||||
if (sz > CHUNK_SIZE) {
|
||||
sz = CHUNK_SIZE;
|
||||
if (sz > 1024) {
|
||||
sz = 1024;
|
||||
im->dsk.decode_data_pos++;
|
||||
im->dsk.decode_pos--;
|
||||
} else {
|
||||
|
|
@ -408,11 +402,11 @@ static bool_t dsk_read_track(struct image *im)
|
|||
}
|
||||
case 2: /* Data */ {
|
||||
uint16_t sec_sz = data_sz(&tib->sib[sec]);
|
||||
sec_sz -= im->dsk.decode_data_pos * CHUNK_SIZE;
|
||||
if (bc_space < min_t(unsigned int, sec_sz, CHUNK_SIZE))
|
||||
sec_sz -= im->dsk.decode_data_pos * 1024;
|
||||
if (bc_space < min_t(unsigned int, sec_sz, 1024))
|
||||
return FALSE;
|
||||
if (sec_sz > CHUNK_SIZE) {
|
||||
sec_sz = CHUNK_SIZE;
|
||||
if (sec_sz > 1024) {
|
||||
sec_sz = 1024;
|
||||
im->dsk.decode_data_pos++;
|
||||
im->dsk.decode_pos--;
|
||||
} else {
|
||||
|
|
@ -466,7 +460,7 @@ static int dsk_find_first_write_sector(
|
|||
}
|
||||
|
||||
if (i >= tib->nr_secs) {
|
||||
log("Bad Wr.Off: %d\n", base);
|
||||
printk("DSK Bad Wr.Off: %d\n", base);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
|
@ -483,9 +477,10 @@ static bool_t dsk_write_track(struct image *im)
|
|||
unsigned int bufmask = (wr->len / 2) - 1;
|
||||
uint8_t *wrbuf = (uint8_t *)im->bufs.write_data.p + 512; /* skip DIB/TIB */
|
||||
uint32_t c = wr->cons / 16, p = wr->prod / 16;
|
||||
unsigned int i, off;
|
||||
unsigned int i;
|
||||
time_t t;
|
||||
uint16_t crc = im->dsk.crc;
|
||||
uint16_t crc, off;
|
||||
uint8_t x;
|
||||
|
||||
/* If we are processing final data then use the end index, rounded up. */
|
||||
barrier();
|
||||
|
|
@ -495,119 +490,94 @@ static bool_t dsk_write_track(struct image *im)
|
|||
|
||||
while ((int16_t)(p - c) > 128) {
|
||||
|
||||
if (im->dsk.decode_pos == 0) {
|
||||
uint32_t sc = c;
|
||||
|
||||
uint8_t x;
|
||||
if (be16toh(buf[c++ & bufmask]) != 0x4489)
|
||||
continue;
|
||||
if ((x = mfmtobin(buf[c & bufmask])) == 0xa1)
|
||||
continue;
|
||||
c++;
|
||||
|
||||
if (be16toh(buf[c++ & bufmask]) != 0x4489)
|
||||
continue;
|
||||
if ((x = mfmtobin(buf[c & bufmask])) == 0xa1)
|
||||
continue;
|
||||
c++;
|
||||
switch (x) {
|
||||
|
||||
switch (x) {
|
||||
|
||||
case 0xfe: /* IDAM */
|
||||
for (i = 0; i < 3; i++)
|
||||
wrbuf[i] = 0xa1;
|
||||
wrbuf[i++] = x;
|
||||
for (; i < 10; i++)
|
||||
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
||||
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;
|
||||
case 0xfe: /* IDAM */
|
||||
for (i = 0; i < 3; i++)
|
||||
wrbuf[i] = 0xa1;
|
||||
wrbuf[i++] = x;
|
||||
for (; i < 10; i++)
|
||||
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
||||
crc = crc16_ccitt(wrbuf, i, 0xffff);
|
||||
if (crc != 0) {
|
||||
printk("DSK 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) {
|
||||
printk("DSK IDAM Bad Sector: %02x\n", wrbuf[6]);
|
||||
im->dsk.write_sector = -2;
|
||||
}
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
/* Data record, shy address mark */
|
||||
unsigned int sec_sz;
|
||||
case 0xfb: /* DAM */ {
|
||||
unsigned int nr, todo, sec_sz;
|
||||
int sec_nr = im->dsk.write_sector;
|
||||
|
||||
ASSERT(im->dsk.decode_pos == 1);
|
||||
|
||||
if (sec_nr < 0) {
|
||||
if (sec_nr == -1) {
|
||||
if (sec_nr == -1)
|
||||
sec_nr = dsk_find_first_write_sector(im, write, tib);
|
||||
im->dsk.write_sector = sec_nr;
|
||||
}
|
||||
if (sec_nr < 0) {
|
||||
log("DAM Unknown\n");
|
||||
goto data_complete;
|
||||
printk("DSK DAM Unknown\n");
|
||||
goto dam_out;
|
||||
}
|
||||
}
|
||||
|
||||
sec_sz = data_sz(&tib->sib[sec_nr]);
|
||||
if ((int16_t)(p - c) < (sec_sz + 2)) {
|
||||
c = sc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
crc = MFM_DAM_CRC;
|
||||
|
||||
printk("Write %d[%02x]/%u... ",
|
||||
sec_nr, tib->sib[sec_nr].r, tib->nr_secs);
|
||||
t = time_now();
|
||||
|
||||
for (i = off = 0; i < sec_nr; i++)
|
||||
off += tib->sib[i].actual_length;
|
||||
off += im->dsk.trk_off;
|
||||
off += im->dsk.decode_data_pos;
|
||||
F_lseek(&im->fp, im->dsk.trk_off + off);
|
||||
|
||||
if (im->dsk.decode_data_pos < sec_sz) {
|
||||
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();
|
||||
for (todo = sec_sz; todo != 0; todo -= nr) {
|
||||
nr = min_t(unsigned int, todo, 1024);
|
||||
mfm_ring_to_bin(buf, bufmask, c, wrbuf, nr);
|
||||
c += nr;
|
||||
crc = crc16_ccitt(wrbuf, nr, crc);
|
||||
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");
|
||||
}
|
||||
|
||||
if (im->dsk.decode_data_pos < sec_sz)
|
||||
continue;
|
||||
printk("%u us\n", time_diff(t, time_now()) / TIME_MHZ);
|
||||
|
||||
if ((int16_t)(p - c) < 2)
|
||||
break;
|
||||
mfm_ring_to_bin(buf, bufmask, c, wrbuf, 2);
|
||||
c += 2;
|
||||
crc = crc16_ccitt(wrbuf, 2, crc);
|
||||
if (crc != 0) {
|
||||
log("Bad CRC: %04x, %d[%02x]\n",
|
||||
crc, sec_nr, tib->sib[sec_nr].r);
|
||||
printk("DSK Bad CRC: %04x, %d[%02x]\n",
|
||||
crc, sec_nr, tib->sib[sec_nr].r);
|
||||
}
|
||||
|
||||
data_complete:
|
||||
dam_out:
|
||||
im->dsk.write_sector = -2;
|
||||
im->dsk.decode_pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
im->dsk.crc = crc;
|
||||
out:
|
||||
wr->cons = c * 16;
|
||||
return flush;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ static void dummy_setup_track(
|
|||
{
|
||||
im->cur_track = track;
|
||||
im->cur_ticks = (start_pos ? *start_pos : 0) * 16;
|
||||
im->tracklen_ticks = sampleclk_stk(im->stk_per_rev) * 16;
|
||||
im->tracklen_ticks = sysclk_stk(im->stk_per_rev) * 16;
|
||||
im->ticks_since_flux = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
193
src/image/hfe.c
193
src/image/hfe.c
|
|
@ -60,13 +60,13 @@ struct track_header {
|
|||
uint16_t len;
|
||||
};
|
||||
|
||||
/* HFEv3 opcodes. Bit order is reversed to match raw HFE bit order. */
|
||||
/* HFEv3 opcodes. The 4-bit codes have their bit ordering reversed. */
|
||||
enum {
|
||||
OP_Nop = 0x0f, /* Nop */
|
||||
OP_Index = 0x8f, /* Index mark */
|
||||
OP_Bitrate = 0x4f, /* +1 byte: new bitrate */
|
||||
OP_SkipBits = 0xcf, /* +1 byte: skip 1-7 bits in following byte */
|
||||
OP_Rand = 0x2f /* Random byte (or bits, if following OP_skip) */
|
||||
OP_nop = 0, /* 0: no effect */
|
||||
OP_index = 8, /* 1: index mark */
|
||||
OP_bitrate = 4, /* 2: +1byte: new bitrate */
|
||||
OP_skip = 12, /* 3: +1byte: skip 0-8 bits in next byte */
|
||||
OP_rand = 2 /* 4: flaky byte */
|
||||
};
|
||||
|
||||
static void hfe_seek_track(struct image *im, uint16_t track);
|
||||
|
|
@ -102,15 +102,14 @@ static bool_t hfe_open(struct image *im)
|
|||
im->nr_cyls = dhdr.nr_tracks;
|
||||
im->step = im->hfe.double_step ? 2 : 1;
|
||||
im->nr_sides = dhdr.nr_sides;
|
||||
im->write_bc_ticks = sampleclk_us(500) / bitrate;
|
||||
im->write_bc_ticks = sysclk_us(500) / bitrate;
|
||||
im->ticks_per_cell = im->write_bc_ticks * 16;
|
||||
im->sync = SYNC_none;
|
||||
|
||||
ASSERT(8*512 <= im->bufs.read_data.len);
|
||||
volume_cache_init(im->bufs.read_data.p + 8*512,
|
||||
im->bufs.read_data.p + im->bufs.read_data.len);
|
||||
if (im->bufs.read_data.len < (64*1024))
|
||||
volume_cache_metadata_only(&im->fp);
|
||||
volume_cache_metadata_only(&im->fp);
|
||||
|
||||
/* Get an initial value for ticks per revolution. */
|
||||
hfe_seek_track(im, 0);
|
||||
|
|
@ -128,13 +127,7 @@ static void hfe_seek_track(struct image *im, uint16_t track)
|
|||
im->hfe.trk_off = le16toh(thdr.offset);
|
||||
im->hfe.trk_len = le16toh(thdr.len) / 2;
|
||||
im->tracklen_bc = im->hfe.trk_len * 8;
|
||||
if (im->hfe.is_v3 && im->tracklen_ticks) {
|
||||
/* Opcodes in v3 make it difficult to predict the track's length. Keep
|
||||
* the previous track's value since this isn't the first seek. */
|
||||
} else {
|
||||
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_sysclk(im->tracklen_bc * im->write_bc_ticks);
|
||||
|
||||
im->cur_track = track;
|
||||
}
|
||||
|
|
@ -144,7 +137,7 @@ static void hfe_setup_track(
|
|||
{
|
||||
struct image_buf *rd = &im->bufs.read_data;
|
||||
struct image_buf *bc = &im->bufs.read_bc;
|
||||
uint32_t start_ticks;
|
||||
uint32_t sys_ticks;
|
||||
uint8_t cyl = track >> (im->hfe.double_step ? 2 : 1);
|
||||
uint8_t side = track & (im->nr_sides - 1);
|
||||
|
||||
|
|
@ -152,40 +145,31 @@ static void hfe_setup_track(
|
|||
if (track != im->cur_track)
|
||||
hfe_seek_track(im, track);
|
||||
|
||||
start_ticks = start_pos ? *start_pos : get_write(im, im->wr_cons)->start;
|
||||
|
||||
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;
|
||||
sys_ticks = start_pos ? *start_pos : get_write(im, im->wr_cons)->start;
|
||||
im->cur_bc = (sys_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;
|
||||
|
||||
sys_ticks = im->cur_ticks / 16;
|
||||
|
||||
rd->prod = rd->cons = 0;
|
||||
bc->prod = bc->cons = 0;
|
||||
|
||||
/* Aggressively batch our reads at HD data rate, as that can be faster
|
||||
* than some USB drives will serve up a single block.*/
|
||||
im->hfe.batch_secs = (im->write_bc_ticks > sampleclk_ns(1500)) ? 2 : 8;
|
||||
im->hfe.batch_secs = (im->write_bc_ticks > sysclk_ns(1500)) ? 2 : 8;
|
||||
|
||||
if (start_pos) {
|
||||
/* Read mode. */
|
||||
im->hfe.trk_pos = (im->cur_bc/8) & ~255;
|
||||
image_read_track(im);
|
||||
bc->cons = im->cur_bc & 2047;
|
||||
*start_pos = sys_ticks;
|
||||
} else {
|
||||
/* Write mode. */
|
||||
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.wrapped = FALSE;
|
||||
im->hfe.write_batch.len = 0;
|
||||
|
|
@ -246,87 +230,74 @@ static uint16_t hfe_rdata_flux(struct image *im, uint16_t *tbuf, uint16_t nr)
|
|||
uint32_t bc_c = bc->cons, bc_p = bc->prod, bc_mask = bc->len - 1;
|
||||
uint32_t ticks = im->ticks_since_flux;
|
||||
uint32_t ticks_per_cell = im->ticks_per_cell;
|
||||
uint32_t bit_off, todo = nr;
|
||||
uint32_t y = 8, todo = nr;
|
||||
uint8_t x;
|
||||
bool_t is_v3 = im->hfe.is_v3;
|
||||
|
||||
while ((uint32_t)(bc_p - bc_c) >= 3*8) {
|
||||
|
||||
ASSERT(y == 8);
|
||||
if (im->cur_bc >= im->tracklen_bc) {
|
||||
/* Malformed HFE v3 file can trigger this assertion. Requires a
|
||||
* multi-byte opcode which extends beyond reported track length. */
|
||||
ASSERT(im->cur_bc == im->tracklen_bc);
|
||||
im->tracklen_ticks = im->cur_ticks;
|
||||
im->stk_per_rev = stk_sampleclk(im->tracklen_ticks / 16);
|
||||
im->cur_bc = im->cur_ticks = 0;
|
||||
/* Skip tail of current 256-byte block. */
|
||||
bc_c = (bc_c + 256*8-1) & ~(256*8-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
bit_off = bc_c % 8;
|
||||
x = bc_b[(bc_c/8) & bc_mask];
|
||||
bc_c += 8 - bit_off;
|
||||
im->cur_bc += 8 - bit_off;
|
||||
|
||||
if (is_v3 && ((x & 0xf) == 0xf)) {
|
||||
y = bc_c % 8;
|
||||
x = bc_b[(bc_c/8) & bc_mask] >> y;
|
||||
if (is_v3 && (y == 0) && ((x & 0xf) == 0xf)) {
|
||||
/* V3 byte-aligned opcode processing. */
|
||||
switch (x) {
|
||||
case OP_Nop:
|
||||
case OP_Index:
|
||||
switch (x >> 4) {
|
||||
case OP_nop:
|
||||
case OP_index:
|
||||
default:
|
||||
continue;
|
||||
case OP_Bitrate:
|
||||
x = _rbit32(bc_b[(bc_c/8) & bc_mask]) >> 24;
|
||||
im->ticks_per_cell = ticks_per_cell =
|
||||
(sampleclk_us(2) * 16 * x) / 72;
|
||||
im->write_bc_ticks = ticks_per_cell / 16;
|
||||
bc_c += 8;
|
||||
im->cur_bc += 8;
|
||||
y = 8;
|
||||
continue;
|
||||
case OP_SkipBits:
|
||||
x = (_rbit32(bc_b[(bc_c/8) & bc_mask]) >> 24) & 7;
|
||||
bc_c += 8 + x;
|
||||
im->cur_bc += 8 + x;
|
||||
case OP_bitrate:
|
||||
x = _rbit32(bc_b[(bc_c/8+1) & bc_mask]) >> 24;
|
||||
im->ticks_per_cell = ticks_per_cell =
|
||||
(sysclk_us(2) * 16 * x) / 72;
|
||||
bc_c += 2*8;
|
||||
im->cur_bc += 2*8;
|
||||
y = 8;
|
||||
continue;
|
||||
case OP_Rand:
|
||||
case OP_skip:
|
||||
x = (_rbit32(bc_b[(bc_c/8+1) & bc_mask]) >> 24) & 7;
|
||||
bc_c += 2*8 + x;
|
||||
im->cur_bc += 2*8 + x;
|
||||
y = x;
|
||||
x = bc_b[(bc_c/8) & bc_mask] >> y;
|
||||
break;
|
||||
case OP_rand:
|
||||
bc_c += 8;
|
||||
im->cur_bc += 8;
|
||||
x = rand();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
x >>= bit_off;
|
||||
im->cur_ticks += (8 - bit_off) * ticks_per_cell;
|
||||
while (bit_off < 8) {
|
||||
bit_off++;
|
||||
bc_c += 8 - y;
|
||||
im->cur_bc += 8 - y;
|
||||
im->cur_ticks += (8 - y) * ticks_per_cell;
|
||||
while (y < 8) {
|
||||
y++;
|
||||
ticks += ticks_per_cell;
|
||||
if (x & 1) {
|
||||
*tbuf++ = (ticks >> 4) - 1;
|
||||
ticks &= 15;
|
||||
if (!--todo) {
|
||||
bc_c -= 8 - bit_off;
|
||||
im->cur_bc -= 8 - bit_off;
|
||||
im->cur_ticks -= (8 - bit_off) * ticks_per_cell;
|
||||
if (!--todo)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
x >>= 1;
|
||||
}
|
||||
|
||||
/* Subdivide a long flux gap to avoid overflowing the 16-bit timer.
|
||||
* This mishandles long No Flux Areas slightly, by regularly emitting
|
||||
* a flux-reversal pulse every 2^14 sampleclk ticks. */
|
||||
if (unlikely((ticks >> (15+4)) != 0)) {
|
||||
*tbuf++ = (1u << 14) - 1;
|
||||
ticks -= 1u << (14+4);
|
||||
if (!--todo)
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
bc->cons = bc_c;
|
||||
bc->cons = bc_c - (8 - y);
|
||||
im->cur_bc -= 8 - y;
|
||||
im->cur_ticks -= (8 - y) * ticks_per_cell;
|
||||
im->ticks_since_flux = ticks;
|
||||
return nr - todo;
|
||||
}
|
||||
|
|
@ -341,7 +312,6 @@ static bool_t hfe_write_track(struct image *im)
|
|||
unsigned int bufmask = wr->len - 1;
|
||||
uint8_t *w, *wrbuf = im->bufs.write_data.p;
|
||||
uint32_t i, space, c = wr->cons / 8, p = wr->prod / 8;
|
||||
bool_t is_v3 = im->hfe.is_v3;
|
||||
bool_t writeback = FALSE;
|
||||
time_t t;
|
||||
|
||||
|
|
@ -393,62 +363,11 @@ static bool_t hfe_write_track(struct image *im)
|
|||
+ (im->cur_track & 1) * 256
|
||||
+ batch_off - im->hfe.write_batch.off
|
||||
+ (off & 255);
|
||||
|
||||
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;
|
||||
}
|
||||
for (i = 0; i < nr; i++)
|
||||
*w++ = _rbit32(buf[c++ & bufmask]) >> 24;
|
||||
im->hfe.write_batch.dirty = TRUE;
|
||||
|
||||
im->hfe.trk_pos += i; /* i may be larger than nr due to opcodes. */
|
||||
im->hfe.trk_pos += nr;
|
||||
if (im->hfe.trk_pos >= im->hfe.trk_len) {
|
||||
ASSERT(im->hfe.trk_pos == im->hfe.trk_len);
|
||||
im->hfe.trk_pos = 0;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ extern const struct image_handler adf_image_handler;
|
|||
extern const struct image_handler atr_image_handler;
|
||||
extern const struct image_handler hfe_image_handler;
|
||||
extern const struct image_handler img_image_handler;
|
||||
extern const struct image_handler sf7_image_handler;
|
||||
extern const struct image_handler st_image_handler;
|
||||
extern const struct image_handler d81_image_handler;
|
||||
extern const struct image_handler dsk_image_handler;
|
||||
|
|
@ -46,7 +45,6 @@ const struct image_type image_type[] = {
|
|||
{ "img", &img_image_handler },
|
||||
{ "ima", &img_image_handler },
|
||||
{ "out", &img_image_handler },
|
||||
{ "sf7", &sf7_image_handler },
|
||||
{ "st", &st_image_handler },
|
||||
{ "adl", &adfs_image_handler },
|
||||
{ "adm", &adfs_image_handler },
|
||||
|
|
@ -118,7 +116,7 @@ static bool_t try_handler(struct image *im, struct slot *slot,
|
|||
|
||||
/* Sensible defaults. */
|
||||
im->sync = SYNC_mfm;
|
||||
im->write_bc_ticks = sampleclk_us(2);
|
||||
im->write_bc_ticks = sysclk_us(2);
|
||||
im->stk_per_rev = stk_ms(200);
|
||||
|
||||
im->disk_handler = im->track_handler = handler;
|
||||
|
|
|
|||
421
src/image/img.c
421
src/image/img.c
|
|
@ -9,8 +9,6 @@
|
|||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
#define LOG_PREFIX "IMG"
|
||||
|
||||
static FSIZE_t raw_extend(struct image *im);
|
||||
static void raw_setup_track(
|
||||
struct image *im, uint16_t track, uint32_t *start_pos);
|
||||
|
|
@ -66,8 +64,6 @@ static bool_t xdf_check(const struct bpb *bpb);
|
|||
#define LAYOUT_sides_swapped (1u<<1)
|
||||
#define LAYOUT_reverse_side(x) (1u<<(2+(x)))
|
||||
|
||||
#define CHUNK_SIZE 1024
|
||||
|
||||
#define sec_sz(n) (128u << (n))
|
||||
|
||||
#define _IAM 1 /* IAM */
|
||||
|
|
@ -166,9 +162,6 @@ const static struct raw_type {
|
|||
{ 8, _S(2), _IAM, 116, 1, 3, 1, 0, 0, 0, _C(80), _R(360) }, /* HD 360RPM */
|
||||
{ 8, _S(2), _IAM, 57, 1, 2, 1, 0, 0, 0, _C(80), _R(360) }, /* DD 360RPM */
|
||||
{ 0 }
|
||||
}, sf7_type[] = {
|
||||
{ 16, _S(1), _IAM, 42, 1, 1, 1, 0, 0, 0, _C(40), _R(300) }, /* 160kB */
|
||||
{ 0 }
|
||||
}, uknc_type[] = {
|
||||
{ 10, _S(2), 0, 38, 1, 2, 1, 0, 0, 0, _C(80), _R(300) },
|
||||
{ 0 }
|
||||
|
|
@ -239,14 +232,8 @@ found:
|
|||
return raw_open(im);
|
||||
}
|
||||
|
||||
struct tag_layout {
|
||||
struct simple_layout s;
|
||||
uint16_t img_bps;
|
||||
uint8_t no[256];
|
||||
};
|
||||
|
||||
static void tag_add_layout(
|
||||
struct image *im, const struct tag_layout *layout, unsigned int trk_idx)
|
||||
struct image *im, const struct simple_layout *layout, unsigned int trk_idx)
|
||||
{
|
||||
struct raw_sec *sec;
|
||||
struct raw_trk *trk;
|
||||
|
|
@ -255,24 +242,23 @@ static void tag_add_layout(
|
|||
if (trk_idx == 0)
|
||||
init_track_map(im);
|
||||
|
||||
trk = add_track_layout(im, layout->s.nr_sectors, trk_idx);
|
||||
trk->is_fm = layout->s.is_fm;
|
||||
trk->rpm = layout->s.rpm;
|
||||
trk->has_iam = layout->s.has_iam;
|
||||
trk->gap_2 = layout->s.gap2;
|
||||
trk->gap_3 = layout->s.gap3;
|
||||
trk->gap_4a = layout->s.gap4a;
|
||||
trk->data_rate = layout->s.data_rate;
|
||||
trk->interleave = layout->s.interleave;
|
||||
trk->cskew = layout->s.cskew;
|
||||
trk->hskew = layout->s.hskew;
|
||||
trk->head = layout->s.head;
|
||||
trk->img_bps = layout->img_bps;
|
||||
trk = add_track_layout(im, layout->nr_sectors, trk_idx);
|
||||
trk->is_fm = layout->is_fm;
|
||||
trk->rpm = layout->rpm;
|
||||
trk->has_iam = layout->has_iam;
|
||||
trk->gap_2 = layout->gap2;
|
||||
trk->gap_3 = layout->gap3;
|
||||
trk->gap_4a = layout->gap4a;
|
||||
trk->data_rate = layout->data_rate;
|
||||
trk->interleave = layout->interleave;
|
||||
trk->cskew = layout->cskew;
|
||||
trk->hskew = layout->hskew;
|
||||
trk->head = layout->head;
|
||||
|
||||
sec = &im->img.sec_info_base[trk->sec_off];
|
||||
for (i = 0; i < layout->s.nr_sectors; i++) {
|
||||
sec->r = i + layout->s.base[0];
|
||||
sec->n = layout->no[i];
|
||||
for (i = 0; i < layout->nr_sectors; i++) {
|
||||
sec->r = i + layout->base[0];
|
||||
sec->n = layout->no;
|
||||
sec++;
|
||||
}
|
||||
}
|
||||
|
|
@ -286,7 +272,6 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
IMGCFG_step,
|
||||
IMGCFG_secs,
|
||||
IMGCFG_bps,
|
||||
IMGCFG_img_bps,
|
||||
IMGCFG_id,
|
||||
IMGCFG_h,
|
||||
IMGCFG_mode,
|
||||
|
|
@ -310,7 +295,6 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
[IMGCFG_step] = { "step" },
|
||||
[IMGCFG_secs] = { "secs" },
|
||||
[IMGCFG_bps] = { "bps" },
|
||||
[IMGCFG_img_bps] = { "img_bps" },
|
||||
[IMGCFG_id] = { "id" },
|
||||
[IMGCFG_h] = { "h" },
|
||||
[IMGCFG_mode] = { "mode" },
|
||||
|
|
@ -327,13 +311,12 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
};
|
||||
|
||||
int match, active, option, nr_t = 0;
|
||||
struct simple_layout t_layout, d_layout;
|
||||
struct {
|
||||
FIL file;
|
||||
struct slot slot;
|
||||
char buf[512];
|
||||
struct tag_layout t_layout;
|
||||
struct tag_layout d_layout;
|
||||
} *heap = (void *)im->bufs.write_bc.p;
|
||||
} *heap = (void *)im->bufs.read_data.p;
|
||||
struct opts opts = {
|
||||
.file = &heap->file,
|
||||
.opts = img_cfg_opts,
|
||||
|
|
@ -341,8 +324,6 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
.argmax = sizeof(heap->buf)-1
|
||||
};
|
||||
|
||||
ASSERT(sizeof(*heap) <= im->bufs.write_bc.len);
|
||||
|
||||
if (!get_img_cfg(&heap->slot))
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -356,7 +337,7 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
char *p, *q;
|
||||
/* New section: Finalise any currently-active section. */
|
||||
if (active) {
|
||||
tag_add_layout(im, &heap->t_layout, nr_t);
|
||||
tag_add_layout(im, &t_layout, nr_t);
|
||||
finalise_track_map(im);
|
||||
active = 0;
|
||||
}
|
||||
|
|
@ -387,10 +368,7 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
/* Best score so far: Process the section. */
|
||||
match = active;
|
||||
reset_all_params(im);
|
||||
heap->d_layout.s = dfl_simple_layout;
|
||||
heap->d_layout.img_bps = 0;
|
||||
memset(heap->d_layout.no, ~0, sizeof(heap->d_layout.no));
|
||||
heap->t_layout = heap->d_layout;
|
||||
d_layout = t_layout = dfl_simple_layout;
|
||||
nr_t = 0;
|
||||
} else {
|
||||
/* Mark ourselves inactive for this section. */
|
||||
|
|
@ -406,10 +384,10 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
case IMGCFG_tracks: {
|
||||
char *p = opts.arg;
|
||||
int c_s, c_e, h_s, h_e, c, h;
|
||||
tag_add_layout(im, &heap->t_layout, nr_t);
|
||||
tag_add_layout(im, &t_layout, nr_t);
|
||||
if (nr_t++ == 0)
|
||||
heap->d_layout = heap->t_layout;
|
||||
heap->t_layout = heap->d_layout;
|
||||
d_layout = t_layout;
|
||||
t_layout = d_layout;
|
||||
do {
|
||||
/* <cylinder>[-<cylinder>] */
|
||||
c_s = strtol(p, &p, 10);
|
||||
|
|
@ -437,71 +415,58 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
im->nr_sides = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_secs:
|
||||
heap->t_layout.s.nr_sectors = strtol(opts.arg, NULL, 10);
|
||||
t_layout.nr_sectors = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_step:
|
||||
im->step = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_bps: {
|
||||
char *p, *q;
|
||||
int no = ~0, i = 0;
|
||||
for (p = opts.arg; *p != '\0'; p = q) {
|
||||
int sz;
|
||||
for (q = p; *q && *q != ','; q++)
|
||||
continue;
|
||||
if (*q == ',')
|
||||
*q++ = '\0';
|
||||
sz = strtol(p, NULL, 10);
|
||||
for (no = 0; no < 8; no++)
|
||||
if ((128u<<no) == sz)
|
||||
break;
|
||||
heap->t_layout.no[i++] = no;
|
||||
}
|
||||
memset(&heap->t_layout.no[i], no, sizeof(heap->t_layout.no)-i);
|
||||
break;
|
||||
}
|
||||
case IMGCFG_img_bps:
|
||||
heap->t_layout.img_bps = strtol(opts.arg, NULL, 0);
|
||||
case IMGCFG_bps: {
|
||||
int no, sz = strtol(opts.arg, NULL, 10);
|
||||
for (no = 0; no < 8; no++)
|
||||
if ((128u<<no) == sz)
|
||||
break;
|
||||
t_layout.no = no;
|
||||
break;
|
||||
}
|
||||
case IMGCFG_id:
|
||||
heap->t_layout.s.base[0] = strtol(opts.arg, NULL, 0);
|
||||
t_layout.base[0] = strtol(opts.arg, NULL, 0);
|
||||
break;
|
||||
case IMGCFG_h:
|
||||
heap->t_layout.s.head = (*opts.arg == 'a') ? 0
|
||||
t_layout.head = (*opts.arg == 'a') ? 0
|
||||
: (strtol(opts.arg, NULL, 10) & 1) + 1;
|
||||
break;
|
||||
case IMGCFG_mode:
|
||||
heap->t_layout.s.is_fm = !strcmp(opts.arg, "fm");
|
||||
t_layout.is_fm = !strcmp(opts.arg, "fm");
|
||||
break;
|
||||
case IMGCFG_interleave:
|
||||
heap->t_layout.s.interleave = strtol(opts.arg, NULL, 10);
|
||||
t_layout.interleave = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_cskew:
|
||||
heap->t_layout.s.cskew = strtol(opts.arg, NULL, 10);
|
||||
t_layout.cskew = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_hskew:
|
||||
heap->t_layout.s.hskew = strtol(opts.arg, NULL, 10);
|
||||
t_layout.hskew = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_rpm:
|
||||
heap->t_layout.s.rpm = strtol(opts.arg, NULL, 10);
|
||||
t_layout.rpm = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_gap2:
|
||||
heap->t_layout.s.gap2 = (*opts.arg == 'a') ? -1
|
||||
t_layout.gap2 = (*opts.arg == 'a') ? -1
|
||||
: (uint8_t)strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_gap3:
|
||||
heap->t_layout.s.gap3 = (*opts.arg == 'a') ? -1
|
||||
t_layout.gap3 = (*opts.arg == 'a') ? -1
|
||||
: (uint8_t)strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_gap4a:
|
||||
heap->t_layout.s.gap4a = (*opts.arg == 'a') ? -1
|
||||
t_layout.gap4a = (*opts.arg == 'a') ? -1
|
||||
: (uint8_t)strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_iam:
|
||||
heap->t_layout.s.has_iam = !strcmp(opts.arg, "yes");
|
||||
t_layout.has_iam = !strcmp(opts.arg, "yes");
|
||||
break;
|
||||
case IMGCFG_rate:
|
||||
heap->t_layout.s.data_rate = strtol(opts.arg, NULL, 10);
|
||||
t_layout.data_rate = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
case IMGCFG_file_layout: {
|
||||
char *p, *q;
|
||||
|
|
@ -526,7 +491,7 @@ static bool_t tag_open(struct image *im, char *tag)
|
|||
}
|
||||
|
||||
if (active) {
|
||||
tag_add_layout(im, &heap->t_layout, nr_t);
|
||||
tag_add_layout(im, &t_layout, nr_t);
|
||||
finalise_track_map(im);
|
||||
}
|
||||
|
||||
|
|
@ -758,11 +723,6 @@ static bool_t d81_open(struct image *im)
|
|||
return raw_type_open(im, d81_type);
|
||||
}
|
||||
|
||||
static bool_t sf7_open(struct image *im)
|
||||
{
|
||||
return raw_type_open(im, sf7_type);
|
||||
}
|
||||
|
||||
static bool_t st_open(struct image *im)
|
||||
{
|
||||
const struct raw_type *in;
|
||||
|
|
@ -1371,13 +1331,13 @@ static bool_t xdf_open(struct image *im)
|
|||
{ /* 3.5 HD */
|
||||
/* Cyl 0, head 0:
|
||||
* 1-8,129-139 (secs=19, interleave=2)
|
||||
* Sectors 1-8 (Aux FAT): Offsets 0x1800-0x27ff
|
||||
* Sectors 129-139 (Main FAT, Pt.1): Offsets 0x0000-0x15ff */
|
||||
* Sectors 1-8 (Aux FAT): Offsets 0x1800-0x2600
|
||||
* Sectors 129-139 (Main FAT, Pt.1): Offsets 0x0000-0x1400 */
|
||||
/* Cyl 0, head 1:
|
||||
* 129-147 (secs=19, interleave=2)
|
||||
* Sector 129 (Main FAT, Pt.2): Offset 0x1600-0x17ff
|
||||
* Sectors 130-143 (RootDir): Offsets 0x2e00-0x49ff
|
||||
* Sectors 144-147 (Data): Offsets 0x5400-0x5bff */
|
||||
* Sector 129 (Main FAT, Pt.2): Offset 0x1600
|
||||
* Sectors 130-143 (RootDir): Offsets 0x2e00-0x4800
|
||||
* Sectors 144-147 (Data): Offsets 0x5400-0x5a00 */
|
||||
/* Cyl N, head 0:
|
||||
* 131(1k), 130(.5k), 132(2k), 134(8k)
|
||||
* Cyl N, head 1: Track slip of ~10k bitcells relative to head 0
|
||||
|
|
@ -1552,14 +1512,6 @@ const struct image_handler d81_image_handler = {
|
|||
.write_track = raw_write_track,
|
||||
};
|
||||
|
||||
const struct image_handler sf7_image_handler = {
|
||||
.open = sf7_open,
|
||||
.setup_track = raw_setup_track,
|
||||
.read_track = raw_read_track,
|
||||
.rdata_flux = bc_rdata_flux,
|
||||
.write_track = raw_write_track,
|
||||
};
|
||||
|
||||
const struct image_handler st_image_handler = {
|
||||
.open = st_open,
|
||||
.setup_track = raw_setup_track,
|
||||
|
|
@ -1775,14 +1727,10 @@ static void raw_seek_track(
|
|||
if (file_idx(im, i, j) >= idx)
|
||||
continue;
|
||||
trk = &im->img.trk_info[im->img.trk_map[i*im->nr_sides + j]];
|
||||
if (trk->img_bps != 0) {
|
||||
off += trk->nr_sectors * trk->img_bps;
|
||||
} else {
|
||||
sec = &im->img.sec_info_base[trk->sec_off];
|
||||
for (k = 0; k < trk->nr_sectors; k++) {
|
||||
off += sec_sz(sec->n);
|
||||
sec++;
|
||||
}
|
||||
sec = &im->img.sec_info_base[trk->sec_off];
|
||||
for (k = 0; k < trk->nr_sectors; k++) {
|
||||
off += sec_sz(sec->n);
|
||||
sec++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1832,9 +1780,9 @@ static uint32_t calc_start_pos(struct image *im)
|
|||
im->img.decode_pos++;
|
||||
if (decode_off < sec_sz(sec->n)) {
|
||||
/* Data */
|
||||
im->img.rd_sec_pos = decode_off / CHUNK_SIZE;
|
||||
im->img.rd_sec_pos = decode_off / 1024;
|
||||
im->img.decode_data_pos = im->img.rd_sec_pos;
|
||||
decode_off %= CHUNK_SIZE;
|
||||
decode_off %= 1024;
|
||||
} else {
|
||||
/* Post Data */
|
||||
decode_off -= sec_sz(sec->n);
|
||||
|
|
@ -1847,8 +1795,8 @@ static uint32_t calc_start_pos(struct image *im)
|
|||
} else {
|
||||
/* Pre-index track gap */
|
||||
im->img.decode_pos = trk->nr_sectors * 4 + 1;
|
||||
im->img.decode_data_pos = decode_off / CHUNK_SIZE;
|
||||
decode_off %= CHUNK_SIZE;
|
||||
im->img.decode_data_pos = decode_off / 1024;
|
||||
decode_off %= 1024;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1860,7 +1808,7 @@ static void raw_setup_track(
|
|||
{
|
||||
struct image_buf *rd = &im->bufs.read_data;
|
||||
struct image_buf *bc = &im->bufs.read_bc;
|
||||
uint32_t decode_off, start_ticks = start_pos ? *start_pos : 0;
|
||||
uint32_t decode_off, sys_ticks = start_pos ? *start_pos : 0;
|
||||
uint8_t cyl = track/(2*im->step), side = track & (im->nr_sides - 1);
|
||||
|
||||
track = cyl*2 + side;
|
||||
|
|
@ -1869,24 +1817,22 @@ static void raw_setup_track(
|
|||
|
||||
im->img.write_sector = -1;
|
||||
|
||||
im->cur_bc = (start_ticks * 16) / im->ticks_per_cell;
|
||||
im->cur_bc = (sys_ticks * 16) / im->ticks_per_cell;
|
||||
im->cur_bc &= ~15;
|
||||
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;
|
||||
|
||||
decode_off = calc_start_pos(im);
|
||||
|
||||
rd->prod = rd->cons = 0;
|
||||
bc->prod = bc->cons = 0;
|
||||
|
||||
if (start_pos) {
|
||||
decode_off = calc_start_pos(im);
|
||||
|
||||
image_read_track(im);
|
||||
bc->cons = decode_off * 16;
|
||||
*start_pos = start_ticks;
|
||||
} else {
|
||||
im->img.decode_pos = 0;
|
||||
*start_pos = sys_ticks;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1895,7 +1841,7 @@ static bool_t raw_open(struct image *im)
|
|||
if (im->step == 0)
|
||||
im->step = 1;
|
||||
|
||||
volume_cache_init(im->bufs.write_data.p + CHUNK_SIZE,
|
||||
volume_cache_init(im->bufs.write_data.p + 1024,
|
||||
im->img.heap_bottom);
|
||||
|
||||
/* Initialise write_bc_ticks (used by floppy_insert to set outp_hden). */
|
||||
|
|
@ -1931,9 +1877,9 @@ static int raw_find_first_write_sector(
|
|||
int32_t base;
|
||||
|
||||
base = write->start / im->ticks_per_cell; /* in data bytes */
|
||||
base -= im->img.track_delay_bc / 16;
|
||||
base -= im->img.track_delay_bc;
|
||||
if (base < 0)
|
||||
base += im->tracklen_bc / 16;
|
||||
base += im->tracklen_bc;
|
||||
|
||||
/* Convert write offset to sector number (in rotational order). */
|
||||
base -= im->img.idx_sz + im->img.idam_sz;
|
||||
|
|
@ -1946,7 +1892,7 @@ static int raw_find_first_write_sector(
|
|||
|
||||
/* Convert rotational order to logical order. */
|
||||
if (i >= trk->nr_sectors) {
|
||||
log("Bad Wr.Off: %d\n", base);
|
||||
printk("IMG Bad Wr.Off: %d\n", base);
|
||||
return -2;
|
||||
}
|
||||
return *sec_map;
|
||||
|
|
@ -1965,8 +1911,8 @@ static bool_t raw_write_track(struct image *im)
|
|||
struct raw_sec *sec;
|
||||
unsigned int i, off;
|
||||
time_t t;
|
||||
uint16_t crc = im->img.crc;
|
||||
uint8_t idam_r;
|
||||
uint16_t crc;
|
||||
uint8_t idam_r, x;
|
||||
|
||||
/* If we are processing final data then use the end index, rounded up. */
|
||||
barrier();
|
||||
|
|
@ -1976,152 +1922,124 @@ static bool_t raw_write_track(struct image *im)
|
|||
|
||||
while ((int16_t)(p - c) > 128) {
|
||||
|
||||
if (im->img.decode_pos == 0) {
|
||||
uint32_t sc = c;
|
||||
|
||||
uint8_t x;
|
||||
if (im->sync == SYNC_fm) {
|
||||
|
||||
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) {
|
||||
|
||||
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++;
|
||||
|
||||
wrbuf[0] = x;
|
||||
for (i = 1; i < 7; i++)
|
||||
wrbuf[i] = mfmtobin(buf[c++ & bufmask]);
|
||||
idam_r = wrbuf[3];
|
||||
} else { /* MFM */
|
||||
|
||||
if (be16toh(buf[c++ & bufmask]) != 0x4489)
|
||||
continue;
|
||||
if ((x = mfmtobin(buf[c & bufmask])) == 0xa1)
|
||||
continue;
|
||||
c++;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
switch (x) {
|
||||
|
||||
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;
|
||||
crc = crc16_ccitt(wrbuf, i, 0xffff);
|
||||
if (crc != 0) {
|
||||
printk("IMG 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) {
|
||||
printk("IMG IDAM Bad Sector: %02x\n", idam_r);
|
||||
im->img.write_sector = -2;
|
||||
}
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
/* Data record, shy address mark */
|
||||
unsigned int sec_sz;
|
||||
case 0xfb: /* DAM */ {
|
||||
unsigned int nr, todo, sec_sz;
|
||||
int sec_nr = im->img.write_sector;
|
||||
|
||||
ASSERT(im->img.decode_pos == 1);
|
||||
|
||||
if (sec_nr < 0) {
|
||||
if (sec_nr == -1) {
|
||||
if (sec_nr == -1)
|
||||
sec_nr = raw_find_first_write_sector(im, write, trk);
|
||||
im->img.write_sector = sec_nr;
|
||||
}
|
||||
if (sec_nr < 0) {
|
||||
log("DAM Unknown\n");
|
||||
goto data_complete;
|
||||
printk("IMG DAM Unknown\n");
|
||||
goto dam_out;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
printk("Write %u[%02x]/%u... ", sec_nr, sec->r, trk->nr_sectors);
|
||||
t = time_now();
|
||||
|
||||
if (im->img.file_sec_offsets) {
|
||||
off = im->img.file_sec_offsets[sec_nr];
|
||||
} else if (trk->img_bps != 0) {
|
||||
off = sec_nr * trk->img_bps;
|
||||
} else {
|
||||
sec = im->img.sec_info;
|
||||
for (i = off = 0; i < sec_nr; i++)
|
||||
off += sec_sz(sec++->n);
|
||||
}
|
||||
off += im->img.trk_off;
|
||||
off += im->img.decode_data_pos;
|
||||
F_lseek(&im->fp, im->img.trk_off + off);
|
||||
|
||||
if (im->img.decode_data_pos < sec_sz) {
|
||||
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();
|
||||
for (todo = sec_sz; todo != 0; todo -= nr) {
|
||||
nr = min_t(unsigned int, todo, 1024);
|
||||
mfm_ring_to_bin(buf, bufmask, c, wrbuf, nr);
|
||||
c += nr;
|
||||
crc = crc16_ccitt(wrbuf, nr, crc);
|
||||
process_data(im, wrbuf, nr);
|
||||
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");
|
||||
}
|
||||
|
||||
if (im->img.decode_data_pos < sec_sz)
|
||||
continue;
|
||||
printk("%u us\n", time_diff(t, time_now()) / TIME_MHZ);
|
||||
|
||||
if ((int16_t)(p - c) < 2)
|
||||
break;
|
||||
mfm_ring_to_bin(buf, bufmask, c, wrbuf, 2);
|
||||
c += 2;
|
||||
crc = crc16_ccitt(wrbuf, 2, crc);
|
||||
if (crc != 0) {
|
||||
log("Bad CRC: %04x, %u[%02x]\n", crc, sec_nr, sec->r);
|
||||
printk("IMG Bad CRC: %04x, %u[%02x]\n",
|
||||
crc, sec_nr, sec->r);
|
||||
}
|
||||
|
||||
data_complete:
|
||||
dam_out:
|
||||
im->img.write_sector = -2;
|
||||
im->img.decode_pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
im->img.crc = crc;
|
||||
out:
|
||||
wr->cons = c * 16;
|
||||
return flush;
|
||||
}
|
||||
|
|
@ -2147,7 +2065,7 @@ static void raw_dump_info(struct image *im)
|
|||
im->ticks_per_cell, im->write_bc_ticks, trk->has_iam);
|
||||
printk(" interleave: %u, cskew %u, hskew %u\n ",
|
||||
trk->interleave, trk->cskew, trk->hskew);
|
||||
printk(" file_layout: %x, img_bps: %u\n", im->img.layout, trk->img_bps);
|
||||
printk(" file-layout: %x\n", im->img.layout);
|
||||
for (i = 0; i < trk->nr_sectors; i++) {
|
||||
struct raw_sec *sec = &im->img.sec_info[im->img.sec_map[i]];
|
||||
int hd = trk->head ? trk->head-1 : im->cur_track&1;
|
||||
|
|
@ -2160,13 +2078,12 @@ static void raw_dump_info(struct image *im)
|
|||
static void img_fetch_data(struct image *im)
|
||||
{
|
||||
struct image_buf *rd = &im->bufs.read_data;
|
||||
struct raw_trk *trk = im->img.trk;
|
||||
uint8_t *buf = rd->p;
|
||||
struct raw_sec *sec, *s;
|
||||
uint8_t sec_i;
|
||||
uint16_t off, len;
|
||||
|
||||
if ((trk->nr_sectors == 0) || (rd->prod != rd->cons))
|
||||
if ((im->img.trk->nr_sectors == 0) || (rd->prod != rd->cons))
|
||||
return;
|
||||
|
||||
sec_i = im->img.sec_map[im->img.trk_sec];
|
||||
|
|
@ -2174,8 +2091,6 @@ static void img_fetch_data(struct image *im)
|
|||
|
||||
if (im->img.file_sec_offsets) {
|
||||
off = im->img.file_sec_offsets[sec_i];
|
||||
} else if (trk->img_bps != 0) {
|
||||
off = sec_i * trk->img_bps;
|
||||
} else {
|
||||
off = 0;
|
||||
for (s = im->img.sec_info; s != sec; s++)
|
||||
|
|
@ -2184,15 +2099,15 @@ static void img_fetch_data(struct image *im)
|
|||
|
||||
len = sec_sz(sec->n);
|
||||
|
||||
off += im->img.rd_sec_pos * CHUNK_SIZE;
|
||||
len -= im->img.rd_sec_pos * CHUNK_SIZE;
|
||||
off += im->img.rd_sec_pos * 1024;
|
||||
len -= im->img.rd_sec_pos * 1024;
|
||||
|
||||
if (len > CHUNK_SIZE) {
|
||||
len = CHUNK_SIZE;
|
||||
if (len > 1024) {
|
||||
len = 1024;
|
||||
im->img.rd_sec_pos++;
|
||||
} else {
|
||||
im->img.rd_sec_pos = 0;
|
||||
if (++im->img.trk_sec >= trk->nr_sectors)
|
||||
if (++im->img.trk_sec >= im->img.trk->nr_sectors)
|
||||
im->img.trk_sec = 0;
|
||||
}
|
||||
|
||||
|
|
@ -2211,14 +2126,14 @@ static void *align_p(void *p)
|
|||
static void check_p(void *p, struct image *im)
|
||||
{
|
||||
uint8_t *a = p, *b = (uint8_t *)im->bufs.read_data.p;
|
||||
if ((int32_t)(a-b) < CHUNK_SIZE)
|
||||
if ((int32_t)(a-b) < 1024)
|
||||
F_die(FR_BAD_IMAGE);
|
||||
im->img.heap_bottom = p;
|
||||
}
|
||||
|
||||
/* Initialise track/sector-info structures at the top of the heap.
|
||||
* In ascending address order:
|
||||
* {read,write}_data (truncated to CHUNK_SIZE bytes)
|
||||
* {read,write}_data (truncated to 1024 bytes)
|
||||
* ... [volume cache]
|
||||
* im->img.trk_info (trk_map[] points into here)
|
||||
* im->img.sec_info_base (trk_info[] + sec_map[] point into here)
|
||||
|
|
@ -2429,11 +2344,11 @@ static void mfm_prep_track(struct image *im)
|
|||
im->tracklen_bc = max_t(uint32_t, im->tracklen_bc, tracklen);
|
||||
im->tracklen_bc = (im->tracklen_bc + 31) & ~31;
|
||||
|
||||
im->ticks_per_cell = ((sampleclk_stk(im->stk_per_rev) * 16u)
|
||||
im->ticks_per_cell = ((sysclk_stk(im->stk_per_rev) * 16u)
|
||||
/ im->tracklen_bc);
|
||||
im->img.gap_4 = (im->tracklen_bc - tracklen) / 16;
|
||||
|
||||
im->write_bc_ticks = sampleclk_us(500) / trk->data_rate;
|
||||
im->write_bc_ticks = sysclk_us(500) / trk->data_rate;
|
||||
|
||||
im->sync = SYNC_mfm;
|
||||
|
||||
|
|
@ -2485,11 +2400,11 @@ static bool_t mfm_read_track(struct image *im)
|
|||
}
|
||||
} else if (im->img.decode_pos == (trk->nr_sectors * 4 + 1)) {
|
||||
/* Pre-index track gap */
|
||||
uint16_t sz = im->img.gap_4 - im->img.decode_data_pos * CHUNK_SIZE;
|
||||
if (bc_space < min_t(unsigned int, sz, CHUNK_SIZE))
|
||||
uint16_t sz = im->img.gap_4 - im->img.decode_data_pos * 1024;
|
||||
if (bc_space < min_t(unsigned int, sz, 1024))
|
||||
return FALSE;
|
||||
if (sz > CHUNK_SIZE) {
|
||||
sz = CHUNK_SIZE;
|
||||
if (sz > 1024) {
|
||||
sz = 1024;
|
||||
im->img.decode_data_pos++;
|
||||
im->img.decode_pos--;
|
||||
} else {
|
||||
|
|
@ -2537,11 +2452,11 @@ static bool_t mfm_read_track(struct image *im)
|
|||
}
|
||||
case 2: /* Data */ {
|
||||
uint16_t sec_sz = sec_sz(sec->n);
|
||||
sec_sz -= im->img.decode_data_pos * CHUNK_SIZE;
|
||||
if (bc_space < min_t(unsigned int, sec_sz, CHUNK_SIZE))
|
||||
sec_sz -= im->img.decode_data_pos * 1024;
|
||||
if (bc_space < min_t(unsigned int, sec_sz, 1024))
|
||||
return FALSE;
|
||||
if (sec_sz > CHUNK_SIZE) {
|
||||
sec_sz = CHUNK_SIZE;
|
||||
if (sec_sz > 1024) {
|
||||
sec_sz = 1024;
|
||||
im->img.decode_data_pos++;
|
||||
im->img.decode_pos--;
|
||||
} else {
|
||||
|
|
@ -2647,11 +2562,11 @@ static void fm_prep_track(struct image *im)
|
|||
im->tracklen_bc = max_t(uint32_t, im->tracklen_bc, tracklen);
|
||||
im->tracklen_bc = (im->tracklen_bc + 31) & ~31;
|
||||
|
||||
im->ticks_per_cell = ((sampleclk_stk(im->stk_per_rev) * 16u)
|
||||
im->ticks_per_cell = ((sysclk_stk(im->stk_per_rev) * 16u)
|
||||
/ im->tracklen_bc);
|
||||
im->img.gap_4 = (im->tracklen_bc - tracklen) / 16;
|
||||
|
||||
im->write_bc_ticks = sampleclk_us(500) / trk->data_rate;
|
||||
im->write_bc_ticks = sysclk_us(500) / trk->data_rate;
|
||||
|
||||
im->sync = SYNC_fm;
|
||||
|
||||
|
|
@ -2698,11 +2613,11 @@ static bool_t fm_read_track(struct image *im)
|
|||
}
|
||||
} else if (im->img.decode_pos == (trk->nr_sectors * 4 + 1)) {
|
||||
/* Pre-index track gap */
|
||||
uint16_t sz = im->img.gap_4 - im->img.decode_data_pos * CHUNK_SIZE;
|
||||
if (bc_space < min_t(unsigned int, sz, CHUNK_SIZE))
|
||||
uint16_t sz = im->img.gap_4 - im->img.decode_data_pos * 1024;
|
||||
if (bc_space < min_t(unsigned int, sz, 1024))
|
||||
return FALSE;
|
||||
if (sz > CHUNK_SIZE) {
|
||||
sz = CHUNK_SIZE;
|
||||
if (sz > 1024) {
|
||||
sz = 1024;
|
||||
im->img.decode_data_pos++;
|
||||
im->img.decode_pos--;
|
||||
} else {
|
||||
|
|
@ -2744,11 +2659,11 @@ static bool_t fm_read_track(struct image *im)
|
|||
}
|
||||
case 2: /* Data */ {
|
||||
uint16_t sec_sz = sec_sz(sec->n);
|
||||
sec_sz -= im->img.decode_data_pos * CHUNK_SIZE;
|
||||
if (bc_space < min_t(unsigned int, sec_sz, CHUNK_SIZE))
|
||||
sec_sz -= im->img.decode_data_pos * 1024;
|
||||
if (bc_space < min_t(unsigned int, sec_sz, 1024))
|
||||
return FALSE;
|
||||
if (sec_sz > CHUNK_SIZE) {
|
||||
sec_sz = CHUNK_SIZE;
|
||||
if (sec_sz > 1024) {
|
||||
sec_sz = 1024;
|
||||
im->img.decode_data_pos++;
|
||||
im->img.decode_pos--;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -33,15 +33,14 @@ static bool_t qd_open(struct image *im)
|
|||
im->qd.tb = 1;
|
||||
im->nr_cyls = 1;
|
||||
im->nr_sides = 1;
|
||||
im->write_bc_ticks = sampleclk_ns(4917); /* 4.917us */
|
||||
im->write_bc_ticks = sysclk_us(4) + 66; /* 4.917us */
|
||||
im->ticks_per_cell = im->write_bc_ticks;
|
||||
im->sync = SYNC_none;
|
||||
|
||||
ASSERT(8*512 <= im->bufs.read_data.len);
|
||||
volume_cache_init(im->bufs.read_data.p + 8*512,
|
||||
im->bufs.read_data.p + im->bufs.read_data.len);
|
||||
if (im->bufs.read_data.len < (64*1024))
|
||||
volume_cache_metadata_only(&im->fp);
|
||||
volume_cache_metadata_only(&im->fp);
|
||||
|
||||
/* There is only one track: Seek to it. */
|
||||
qd_seek_track(im, 0);
|
||||
|
|
@ -61,13 +60,11 @@ static void qd_seek_track(struct image *im, uint16_t track)
|
|||
im->qd.trk_len = le32toh(thdr.len);
|
||||
|
||||
/* Read/write window limits in STK ticks from data start. */
|
||||
im->qd.win_start = (le32toh(thdr.win_start) * im->write_bc_ticks
|
||||
* ((8 * STK_MHZ) / SAMPLECLK_MHZ));
|
||||
im->qd.win_end = (le32toh(thdr.win_end) * im->write_bc_ticks
|
||||
* ((8 * STK_MHZ) / SAMPLECLK_MHZ));
|
||||
im->qd.win_start = le32toh(thdr.win_start) * im->write_bc_ticks;
|
||||
im->qd.win_end = le32toh(thdr.win_end) * im->write_bc_ticks;
|
||||
|
||||
im->tracklen_bc = im->qd.trk_len * 8;
|
||||
im->stk_per_rev = stk_sampleclk(im->tracklen_bc * im->write_bc_ticks);
|
||||
im->stk_per_rev = stk_sysclk(im->tracklen_bc * im->write_bc_ticks);
|
||||
|
||||
im->cur_track = track;
|
||||
}
|
||||
|
|
@ -77,16 +74,16 @@ static void qd_setup_track(
|
|||
{
|
||||
struct image_buf *rd = &im->bufs.read_data;
|
||||
struct image_buf *bc = &im->bufs.read_bc;
|
||||
uint32_t start_ticks;
|
||||
uint32_t sys_ticks;
|
||||
|
||||
start_ticks = start_pos ? *start_pos : get_write(im, im->wr_cons)->start;
|
||||
im->cur_bc = start_ticks / im->ticks_per_cell;
|
||||
sys_ticks = start_pos ? *start_pos : get_write(im, im->wr_cons)->start;
|
||||
im->cur_bc = sys_ticks / 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;
|
||||
sys_ticks = im->cur_ticks;
|
||||
|
||||
rd->prod = rd->cons = 0;
|
||||
bc->prod = bc->cons = 0;
|
||||
|
|
@ -96,7 +93,7 @@ static void qd_setup_track(
|
|||
im->qd.trk_pos = (im->cur_bc/8) & ~511;
|
||||
image_read_track(im);
|
||||
bc->cons = im->cur_bc & 4095;
|
||||
*start_pos = start_ticks;
|
||||
*start_pos = sys_ticks;
|
||||
} else {
|
||||
/* Write mode. */
|
||||
im->qd.trk_pos = im->cur_bc / 8;
|
||||
|
|
@ -159,11 +156,11 @@ static uint16_t qd_rdata_flux(struct image *im, uint16_t *tbuf, uint16_t nr)
|
|||
uint32_t bc_c = bc->cons, bc_p = bc->prod, bc_mask = bc->len - 1;
|
||||
uint32_t ticks = im->ticks_since_flux;
|
||||
uint32_t ticks_per_cell = im->ticks_per_cell;
|
||||
uint32_t bit_off, todo = nr;
|
||||
uint32_t y = 8, todo = nr;
|
||||
uint8_t x;
|
||||
|
||||
while ((uint32_t)(bc_p - bc_c) >= 8) {
|
||||
|
||||
ASSERT(y == 8);
|
||||
if (im->cur_bc >= im->tracklen_bc) {
|
||||
ASSERT(im->cur_bc == im->tracklen_bc);
|
||||
im->tracklen_ticks = im->cur_ticks;
|
||||
|
|
@ -172,43 +169,28 @@ static uint16_t qd_rdata_flux(struct image *im, uint16_t *tbuf, uint16_t nr)
|
|||
bc_c = (bc_c + 512*8-1) & ~(512*8-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
bit_off = bc_c % 8;
|
||||
x = bc_b[(bc_c/8) & bc_mask] >> bit_off;
|
||||
bc_c += 8 - bit_off;
|
||||
im->cur_bc += 8 - bit_off;
|
||||
im->cur_ticks += (8 - bit_off) * ticks_per_cell;
|
||||
|
||||
while (bit_off < 8) {
|
||||
bit_off++;
|
||||
y = bc_c % 8;
|
||||
x = bc_b[(bc_c/8) & bc_mask] >> y;
|
||||
bc_c += 8 - y;
|
||||
im->cur_bc += 8 - y;
|
||||
im->cur_ticks += (8 - y) * ticks_per_cell;
|
||||
while (y < 8) {
|
||||
y++;
|
||||
ticks += ticks_per_cell;
|
||||
if (x & 1) {
|
||||
*tbuf++ = ticks - 1;
|
||||
ticks = 0;
|
||||
if (!--todo) {
|
||||
bc_c -= 8 - bit_off;
|
||||
im->cur_bc -= 8 - bit_off;
|
||||
im->cur_ticks -= (8 - bit_off) * ticks_per_cell;
|
||||
if (!--todo)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
x >>= 1;
|
||||
}
|
||||
|
||||
/* Subdivide a long flux gap to avoid overflowing the 16-bit timer.
|
||||
* This mishandles long No Flux Areas slightly, by regularly emitting
|
||||
* a flux-reversal pulse every 2^14 sampleclk ticks. */
|
||||
if (unlikely((ticks >> 15) != 0)) {
|
||||
*tbuf++ = (1u << 14) - 1;
|
||||
ticks -= 1u << 14;
|
||||
if (!--todo)
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
bc->cons = bc_c;
|
||||
bc->cons = bc_c - (8 - y);
|
||||
im->cur_bc -= 8 - y;
|
||||
im->cur_ticks -= (8 - y) * ticks_per_cell;
|
||||
im->ticks_since_flux = ticks;
|
||||
return nr - todo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ uint8_t board_id;
|
|||
#define DOWN 0x40
|
||||
#define UP 0x00
|
||||
|
||||
#define INVALID 0xff
|
||||
|
||||
static GPIO gpio(uint8_t x)
|
||||
{
|
||||
switch (x&0x30) {
|
||||
|
|
@ -44,15 +42,14 @@ static uint8_t inputs[] = {
|
|||
GPIOA | 8 | DOWN, /* 22: Write Data */
|
||||
GPIOB | 9 | DOWN, /* 24: Write Gate */
|
||||
GPIOB | 4 | DOWN, /* 32: Side Select */
|
||||
};
|
||||
#if 0 /* Buttons and encoder are handled via board.c */
|
||||
|
||||
/* Buttons and encoder inputs are switch-to-ground. So we pull them up. */
|
||||
GPIOC | 8 | UP , /* Button: Down/Left */
|
||||
GPIOC | 7 | UP , /* Button: Up/Right */
|
||||
GPIOC | 6 | UP , /* Button: Select (Jumper JA) */
|
||||
GPIOC | 10 | UP , /* Rotary CLK (J7-1) */
|
||||
GPIOC | 11 | UP , /* Rotary DAT (J7-2) */
|
||||
#endif
|
||||
};
|
||||
|
||||
static uint8_t outputs[] = {
|
||||
GPIOB | 7 , /* 2: Disk Change/Density */
|
||||
|
|
@ -69,23 +66,11 @@ static void io_test(bool_t assert)
|
|||
|
||||
uint8_t d[3] = { 0 };
|
||||
char p[20], *q = p;
|
||||
int i, b;
|
||||
int i;
|
||||
|
||||
/* 0-7 */
|
||||
for (i = 0; i < ARRAY_SIZE(inputs); i++) {
|
||||
uint8_t x = inputs[i];
|
||||
if ((x != INVALID) && gpio_read_pin(gpio(x), x&15)) {
|
||||
*q++ = char_map[i];
|
||||
d[i/7] |= 1 << (i%7);
|
||||
} else {
|
||||
*q++ = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/* 8-12 */
|
||||
b = (~board_get_buttons() & 7) | (board_get_rotary() << 3);
|
||||
for (; i < 13; i++) {
|
||||
if (b & (1<<(i-8))) {
|
||||
if (gpio_read_pin(gpio(x), x&15)) {
|
||||
*q++ = char_map[i];
|
||||
d[i/7] |= 1 << (i%7);
|
||||
} else {
|
||||
|
|
@ -129,7 +114,7 @@ int main(void)
|
|||
int i;
|
||||
|
||||
/* Relocate DATA. Initialise BSS. */
|
||||
if (&_sdat[0] != &_ldat[0])
|
||||
if (_sdat != _ldat)
|
||||
memcpy(_sdat, _ldat, _edat-_sdat);
|
||||
memset(_sbss, 0, _ebss-_sbss);
|
||||
|
||||
|
|
@ -149,26 +134,12 @@ int main(void)
|
|||
display_init();
|
||||
display_setting(TRUE);
|
||||
|
||||
if (mcu_package == MCU_QFN32) {
|
||||
inputs[6] = GPIOB | 1 | DOWN; /* wgate */
|
||||
outputs[0] = GPIOA | 14; /* pin_02, dskchg/den */
|
||||
outputs[2] = GPIOA | 13; /* pin_26, trk00 */
|
||||
}
|
||||
|
||||
if (!gotek_enhanced()) {
|
||||
inputs[1] = INVALID; /* no SELB */
|
||||
if (has_kc30_header == 2) {
|
||||
inputs[2] = GPIOB | 12 | DOWN;
|
||||
} else {
|
||||
/* Standard Gotek: optional motor signal is PB15. */
|
||||
inputs[2] = GPIOB | 15 | DOWN;
|
||||
}
|
||||
}
|
||||
/* Standard Gotek: optional motor signal is PB15. */
|
||||
if (!gotek_enhanced())
|
||||
inputs[2] |= GPIOB;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(inputs); i++) {
|
||||
uint8_t x = inputs[i];
|
||||
if (x == INVALID)
|
||||
continue;
|
||||
gpio_configure_pin(gpio(x), x&15,
|
||||
(x&DOWN) ? GPI_pull_down : GPI_pull_up);
|
||||
}
|
||||
|
|
|
|||
266
src/main.c
266
src/main.c
|
|
@ -529,10 +529,10 @@ static void button_timer_fn(void *unused)
|
|||
x >>= 1;
|
||||
}
|
||||
|
||||
if (_b[twobutton_reverse] == 0)
|
||||
if (_b[!twobutton_reverse] == 0)
|
||||
b |= twobutton_rotary ? B_LEFT|B_RIGHT : B_LEFT;
|
||||
|
||||
if (_b[!twobutton_reverse] == 0)
|
||||
if (_b[twobutton_reverse] == 0)
|
||||
b |= twobutton_rotary ? B_SELECT : B_RIGHT;
|
||||
|
||||
if (_b[2] == 0)
|
||||
|
|
@ -593,6 +593,7 @@ static void button_timer_fn(void *unused)
|
|||
b |= rb;
|
||||
rb = 0;
|
||||
|
||||
if (0) {
|
||||
switch (display_type) {
|
||||
case DT_LCD_OLED:
|
||||
b = lcd_handle_backlight(b);
|
||||
|
|
@ -600,7 +601,7 @@ static void button_timer_fn(void *unused)
|
|||
case DT_LED_7SEG:
|
||||
b = led_handle_display(b);
|
||||
break;
|
||||
}
|
||||
}}
|
||||
|
||||
/* Latch final button state and reset the timer. */
|
||||
buttons = b;
|
||||
|
|
@ -915,30 +916,6 @@ static uint8_t parse_pin_str(const char *s)
|
|||
return pin;
|
||||
}
|
||||
|
||||
static uint16_t parse_display_order(const char *p)
|
||||
{
|
||||
int sh = 0;
|
||||
uint16_t order = 0;
|
||||
|
||||
if (!strcmp(p, "default"))
|
||||
return DORD_default;
|
||||
|
||||
while (p != NULL) {
|
||||
order |= ((p[0]-'0')&7) << sh;
|
||||
if (p[1] == 'd')
|
||||
order |= DORD_double << sh;
|
||||
sh += DORD_shift;
|
||||
if ((p = strchr(p, ',')) == NULL)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (sh < 16)
|
||||
order |= 0x7777 << sh;
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
static void read_ff_cfg(void)
|
||||
{
|
||||
enum {
|
||||
|
|
@ -1208,8 +1185,6 @@ static void read_ff_cfg(void)
|
|||
ff_cfg.display_type |= DISPLAY_ztech;
|
||||
} else if (!strcmp(p, "slow")) {
|
||||
ff_cfg.display_type |= DISPLAY_slow;
|
||||
} else if (!strcmp(p, "hflip")) {
|
||||
ff_cfg.display_type |= DISPLAY_hflip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1226,17 +1201,26 @@ static void read_ff_cfg(void)
|
|||
ff_cfg.oled_contrast = strtol(opts.arg, NULL, 10);
|
||||
break;
|
||||
|
||||
case FFCFG_display_order:
|
||||
ff_cfg.display_order = parse_display_order(opts.arg);
|
||||
break;
|
||||
|
||||
case FFCFG_osd_display_order:
|
||||
ff_cfg.osd_display_order = parse_display_order(opts.arg);
|
||||
break;
|
||||
|
||||
case FFCFG_osd_columns:
|
||||
ff_cfg.osd_columns = strtol(opts.arg, NULL, 10);
|
||||
case FFCFG_display_order: {
|
||||
char *p = opts.arg;
|
||||
int sh = 0;
|
||||
ff_cfg.display_order = DORD_default;
|
||||
if (!strcmp(p, "default"))
|
||||
break;
|
||||
ff_cfg.display_order = 0;
|
||||
while (p != NULL) {
|
||||
ff_cfg.display_order |= ((p[0]-'0')&7) << sh;
|
||||
if (p[1] == 'd')
|
||||
ff_cfg.display_order |= DORD_double << sh;
|
||||
sh += DORD_shift;
|
||||
if ((p = strchr(p, ',')) == NULL)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
if (sh < 16)
|
||||
ff_cfg.display_order |= 0x7777 << sh;
|
||||
break;
|
||||
}
|
||||
|
||||
case FFCFG_display_off_secs:
|
||||
ff_cfg.display_off_secs = strtol(opts.arg, NULL, 10);
|
||||
|
|
@ -1280,25 +1264,6 @@ static void read_ff_cfg(void)
|
|||
break;
|
||||
}
|
||||
|
||||
case FFCFG_notify_volume: {
|
||||
char *p, *q;
|
||||
ff_cfg.notify_volume = 0;
|
||||
for (p = opts.arg; *p != '\0'; p = q) {
|
||||
for (q = p; *q && *q != ','; q++)
|
||||
continue;
|
||||
if (*q == ',')
|
||||
*q++ = '\0';
|
||||
if (!strcmp(p, "slotnr")) {
|
||||
ff_cfg.notify_volume |= NOTIFY_slotnr;
|
||||
} else {
|
||||
ff_cfg.notify_volume &= ~NOTIFY_volume_mask;
|
||||
ff_cfg.notify_volume |= strtol(p, NULL, 10)
|
||||
& NOTIFY_volume_mask;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FFCFG_da_report_version:
|
||||
memset(ff_cfg.da_report_version, 0,
|
||||
sizeof(ff_cfg.da_report_version));
|
||||
|
|
@ -1321,27 +1286,15 @@ static void read_ff_cfg(void)
|
|||
|
||||
static void process_ff_cfg_opts(const struct ff_cfg *old)
|
||||
{
|
||||
/* chgrst, motor-delay: Reset EXTI handlers. */
|
||||
if ((ff_cfg.motor_delay != old->motor_delay)
|
||||
|| (ff_cfg.chgrst != old->chgrst)) {
|
||||
exti->imr &= ~motor_chgrst_exti_mask;
|
||||
motor_chgrst_exti_mask = 0;
|
||||
}
|
||||
|
||||
/* rotary, chgrst, motor-delay: Inform the rotary-encoder subsystem.
|
||||
* It is harmless to reset rotary EXTI handlers unconditionally. */
|
||||
* It is harmless to notify unconditionally. */
|
||||
set_rotary_exti();
|
||||
|
||||
/* interface, pin02, pin34, chgrst, motor-delay: Inform the floppy
|
||||
* subsystem. */
|
||||
/* interface, pin02, pin34: Inform the floppy subsystem. */
|
||||
if ((ff_cfg.interface != old->interface)
|
||||
|| (ff_cfg.pin02 != old->pin02)
|
||||
|| (ff_cfg.pin34 != old->pin34)
|
||||
|| (ff_cfg.motor_delay != old->motor_delay)
|
||||
|| (ff_cfg.chgrst != old->chgrst)) {
|
||||
|| (ff_cfg.pin34 != old->pin34))
|
||||
floppy_set_fintf_mode();
|
||||
motor_chgrst_setup_exti();
|
||||
}
|
||||
|
||||
/* max-cyl: Inform the floppy subsystem. */
|
||||
if (ff_cfg.max_cyl != old->max_cyl)
|
||||
|
|
@ -2708,10 +2661,8 @@ static int floppy_main(void *unused)
|
|||
b = B_SELECT;
|
||||
} else {
|
||||
floppy_arena_teardown();
|
||||
speaker_notify_insert(cfg.slot_nr);
|
||||
fres = F_call_cancellable(run_floppy, &b);
|
||||
floppy_cancel();
|
||||
speaker_notify_eject();
|
||||
assert_volume_connected();
|
||||
if ((b != 0) && (display_type == DT_LCD_OLED)) {
|
||||
/* Immediate visual indication of button press. */
|
||||
|
|
@ -2840,24 +2791,6 @@ static bool_t main_menu_confirm(const char *op)
|
|||
return wait_twobutton_press(b) == B_SELECT;
|
||||
}
|
||||
|
||||
static void noinline mcu_info(void)
|
||||
{
|
||||
#if MCU == STM32F105
|
||||
static const char * const mcus[] = {
|
||||
"STM32F105", "AT32F415"
|
||||
};
|
||||
const char * const mcu = mcus[!!is_artery_mcu];
|
||||
#elif MCU == AT32F435
|
||||
const static char mcu[] = "AT32F435";
|
||||
#endif
|
||||
char msg[20];
|
||||
snprintf(msg, sizeof(msg), "%uMHz, %ukB", SYSCLK_MHZ, ram_kb);
|
||||
lcd_write(0, 0, -1, mcu);
|
||||
lcd_write(0, 1, -1, msg);
|
||||
while (!buttons)
|
||||
continue;
|
||||
}
|
||||
|
||||
static void factory_reset(void)
|
||||
{
|
||||
/* Inform user that factory reset is about to occur. */
|
||||
|
|
@ -2942,7 +2875,7 @@ static void ff_osd_configure(void)
|
|||
static void main_menu(void)
|
||||
{
|
||||
const static char *menu[] = {
|
||||
"MCU Info",
|
||||
"**Main Menu**",
|
||||
"Factory Reset",
|
||||
"Update Firmware",
|
||||
"Configure FF OSD",
|
||||
|
|
@ -2965,7 +2898,6 @@ static void main_menu(void)
|
|||
if (sel >= ARRAY_SIZE(menu))
|
||||
sel -= ARRAY_SIZE(menu);
|
||||
|
||||
lcd_write(0, 0, -1, "**Main Menu**");
|
||||
lcd_write(0, 1, -1, menu[sel]);
|
||||
lcd_on();
|
||||
|
||||
|
|
@ -2988,9 +2920,6 @@ static void main_menu(void)
|
|||
while (buttons)
|
||||
continue;
|
||||
switch (sel) {
|
||||
case 0: /* MCU Info */
|
||||
mcu_info();
|
||||
break;
|
||||
case 1: /* Factory Reset */
|
||||
if (main_menu_confirm("Reset"))
|
||||
factory_reset();
|
||||
|
|
@ -3002,7 +2931,7 @@ static void main_menu(void)
|
|||
case 3: /* Configure FF OSD */
|
||||
ff_osd_configure();
|
||||
break;
|
||||
case 4: /* Exit */
|
||||
case 0: case 4: /* Exit */
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
@ -3102,12 +3031,6 @@ static void maybe_show_version(void)
|
|||
if (nb)
|
||||
return;
|
||||
|
||||
led_7seg_write_string("CPU");
|
||||
delay_ms(1000);
|
||||
|
||||
led_7seg_write_decimal(SYSCLK_MHZ);
|
||||
delay_ms(1000);
|
||||
|
||||
led_7seg_write_string("RAN");
|
||||
delay_ms(1000);
|
||||
|
||||
|
|
@ -3175,6 +3098,61 @@ static void handle_errors(FRESULT fres)
|
|||
system_reset();
|
||||
}
|
||||
|
||||
static void pstr(const char *s)
|
||||
{
|
||||
switch (display_type) {
|
||||
case DT_LED_7SEG:
|
||||
led_7seg_write_string(s);
|
||||
break;
|
||||
case DT_LCD_OLED:
|
||||
lcd_write(9, 0, 0, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int test_jp(void)
|
||||
{
|
||||
gpio_configure_pin(gpioa, 5, GPI_pull_up); /* JA */
|
||||
gpio_configure_pin(gpioa, 2, GPI_pull_up); /* JB */
|
||||
gpio_configure_pin(gpiob, 1, GPI_pull_up); /* JC */
|
||||
delay_ms(1);
|
||||
if (!gpio_read_pin(gpioa, 5) ||
|
||||
!gpio_read_pin(gpioa, 2) ||
|
||||
!gpio_read_pin(gpiob, 1))
|
||||
goto error;
|
||||
|
||||
gpio_configure_pin(gpioa, 5, GPO_pushpull(_2MHz, LOW));
|
||||
delay_ms(1);
|
||||
if (!gpio_read_pin(gpioa, 2) ||
|
||||
!gpio_read_pin(gpiob, 1))
|
||||
goto error;
|
||||
gpio_configure_pin(gpioa, 5, GPI_pull_up); /* JA */
|
||||
|
||||
gpio_configure_pin(gpioa, 2, GPO_pushpull(_2MHz, LOW));
|
||||
delay_ms(1);
|
||||
if (!gpio_read_pin(gpioa, 5) ||
|
||||
!gpio_read_pin(gpiob, 1))
|
||||
goto error;
|
||||
gpio_configure_pin(gpioa, 2, GPI_pull_up); /* JB */
|
||||
|
||||
gpio_configure_pin(gpiob, 1, GPO_pushpull(_2MHz, LOW));
|
||||
delay_ms(1);
|
||||
if (!gpio_read_pin(gpioa, 5) ||
|
||||
!gpio_read_pin(gpioa, 2))
|
||||
goto error;
|
||||
gpio_configure_pin(gpiob, 1, GPI_pull_up); /* JA */
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
gpio_configure_pin(gpioa, 5, GPI_pull_up); /* JA */
|
||||
gpio_configure_pin(gpioa, 2, GPI_pull_up); /* JB */
|
||||
gpio_configure_pin(gpiob, 1, GPI_pull_up); /* JC */
|
||||
return -1;
|
||||
}
|
||||
|
||||
void tone(int hz, int ms);
|
||||
int floppy_test(void);
|
||||
int main(void)
|
||||
{
|
||||
static const char * const board_name[] = {
|
||||
|
|
@ -3184,9 +3162,10 @@ int main(void)
|
|||
};
|
||||
|
||||
FRESULT fres;
|
||||
int i = 888, b;
|
||||
|
||||
/* Relocate DATA. Initialise BSS. */
|
||||
if (&_sdat[0] != &_ldat[0])
|
||||
if (_sdat != _ldat)
|
||||
memcpy(_sdat, _ldat, _edat-_sdat);
|
||||
memset(_sbss, 0, _ebss-_sbss);
|
||||
|
||||
|
|
@ -3198,14 +3177,14 @@ int main(void)
|
|||
console_crash_on_input();
|
||||
delay_ms(200); /* 5v settle */
|
||||
|
||||
printk("\n** FlashFloppy %s\n", fw_ver);
|
||||
printk("\n** 435 Test %s\n", fw_ver);
|
||||
printk("** Keir Fraser <keir.xen@gmail.com>\n");
|
||||
printk("** github:keirf/flashfloppy\n\n");
|
||||
|
||||
printk("Build: %s %s\n", build_date, build_time);
|
||||
printk("Board: %s\n", board_name[board_id]);
|
||||
|
||||
speaker_init();
|
||||
// speaker_init();
|
||||
|
||||
flash_ff_cfg_read();
|
||||
|
||||
|
|
@ -3213,20 +3192,6 @@ int main(void)
|
|||
|
||||
display_init();
|
||||
|
||||
while (floppy_ribbon_is_reversed()) {
|
||||
printk("** Error: Ribbon cable upside down?\n");
|
||||
switch (display_type) {
|
||||
case DT_LED_7SEG:
|
||||
led_7seg_write_string("RIB");
|
||||
break;
|
||||
case DT_LCD_OLED:
|
||||
lcd_write(0, 0, -1, "Ribbon Cable May");
|
||||
lcd_write(0, 1, -1, "Be Upside Down? ");
|
||||
lcd_on();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
usbh_msc_init();
|
||||
|
||||
rotary = board_get_rotary();
|
||||
|
|
@ -3234,6 +3199,63 @@ int main(void)
|
|||
timer_init(&button_timer, button_timer_fn, NULL);
|
||||
timer_set(&button_timer, time_now());
|
||||
|
||||
switch (display_type) {
|
||||
case DT_LED_7SEG:
|
||||
led_7seg_write_string("PIN");
|
||||
break;
|
||||
case DT_LCD_OLED:
|
||||
lcd_write(0, 0, -1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
lcd_write(0, 1, -1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
lcd_write(0, 3, -1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
lcd_write(7, 0, 0, " PIN ");
|
||||
lcd_on();
|
||||
break;
|
||||
}
|
||||
|
||||
tone(2000, 200);
|
||||
if (floppy_test() != 0) {
|
||||
tone(50, 1000);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
tone(3000, 200);
|
||||
pstr("JP ");
|
||||
if (test_jp() != 0) {
|
||||
tone(50, 1000);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
tone(4000, 200);
|
||||
pstr("USB");
|
||||
|
||||
arena_init();
|
||||
usbh_msc_buffer_set(arena_alloc(512));
|
||||
while ((f_mount(&fatfs, "", 1) != FR_OK))
|
||||
usbh_msc_process();
|
||||
|
||||
tone(6000, 200);
|
||||
for (;;) {
|
||||
|
||||
switch (display_type) {
|
||||
case DT_LED_7SEG:
|
||||
led_7seg_write_decimal(i);
|
||||
break;
|
||||
case DT_LCD_OLED: {
|
||||
char msg[6];
|
||||
snprintf(msg, sizeof(msg), "%d", i);
|
||||
lcd_write(9, 0, 0, msg);
|
||||
break;
|
||||
} }
|
||||
while (!(b = buttons));
|
||||
tone(4000, 50);
|
||||
if (b & B_LEFT) i--;
|
||||
if (b & B_RIGHT) i++;
|
||||
if (b & B_SELECT) i += 100;
|
||||
if (i > 999) i -= 1000;
|
||||
if (i < 0) i += 1000;
|
||||
while (buttons) ;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
||||
banner();
|
||||
|
|
|
|||
|
|
@ -15,16 +15,10 @@ unsigned int ram_kb = 384;
|
|||
|
||||
static void clock_init(void)
|
||||
{
|
||||
/* Enable PWR interface so we can set the LDO boost. */
|
||||
rcc->apb1enr |= RCC_APB1ENR_PWREN;
|
||||
|
||||
/* Bootloader leaves MISC1 set up for USB clocked from HICK.
|
||||
* Clear MISC1 register to its reset value. */
|
||||
rcc->misc1 = 0;
|
||||
|
||||
/* 288MHz requires LDO voltage boost. */
|
||||
pwr->ldoov = PWR_LDOOV_1V3;
|
||||
|
||||
flash->divr = FLASH_DIVR_DIV_3;
|
||||
|
||||
/* Start up the external oscillator. */
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@
|
|||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
unsigned int sysclk_mhz = 72;
|
||||
unsigned int apb1_mhz = 36;
|
||||
|
||||
bool_t is_artery_mcu;
|
||||
unsigned int flash_page_size = FLASH_PAGE_SIZE;
|
||||
unsigned int ram_kb = 64;
|
||||
|
|
@ -35,15 +32,13 @@ static void identify_mcu(void)
|
|||
ram_kb = 32;
|
||||
if (flash_kb == 128)
|
||||
flash_page_size = 1024;
|
||||
sysclk_mhz = 144;
|
||||
apb1_mhz = 72;
|
||||
}
|
||||
}
|
||||
|
||||
static void clock_init(void)
|
||||
{
|
||||
/* Flash controller: reads require 2 wait states at 72MHz. */
|
||||
flash->acr = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY(sysclk_mhz/32);
|
||||
flash->acr = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY(2);
|
||||
|
||||
/* Start up the external oscillator. */
|
||||
rcc->cr |= RCC_CR_HSEON;
|
||||
|
|
@ -51,40 +46,21 @@ static void clock_init(void)
|
|||
cpu_relax();
|
||||
|
||||
/* PLLs, scalers, muxes. */
|
||||
if (is_artery_mcu) {
|
||||
uint32_t rcc_pll = *RCC_PLL;
|
||||
rcc_pll &= ~(RCC_PLL_PLLCFGEN | RCC_PLL_FREF_MASK);
|
||||
rcc_pll |= RCC_PLL_FREF_8M;
|
||||
*RCC_PLL = rcc_pll;
|
||||
rcc->cfgr = (RCC_CFGR_PLLMUL_18 | /* PLL = 18*8MHz = 144MHz */
|
||||
RCC_CFGR_USBPSC_3 | /* USB = SYSCLK/3 = 48MHz */
|
||||
RCC_CFGR_PLLSRC_PREDIV1 |
|
||||
RCC_CFGR_ADCPRE_DIV8 |
|
||||
RCC_CFGR_APB2PSC_2 | /* APB2 = SYSCLK/2 = 72MHz */
|
||||
RCC_CFGR_APB1PSC_2); /* APB1 = SYSCLK/2 = 72MHz */
|
||||
} else {
|
||||
rcc->cfgr = (RCC_CFGR_PLLMUL(9) | /* PLL = 9*8MHz = 72MHz */
|
||||
RCC_CFGR_PLLSRC_PREDIV1 |
|
||||
RCC_CFGR_ADCPRE_DIV8 |
|
||||
RCC_CFGR_APB1PSC_2); /* APB1 = SYSCLK/2 = 36MHz */
|
||||
}
|
||||
rcc->cfgr = (RCC_CFGR_PLLMUL(9) | /* PLL = 9*8MHz = 72MHz */
|
||||
RCC_CFGR_PLLSRC_PREDIV1 |
|
||||
RCC_CFGR_ADCPRE_DIV8 |
|
||||
RCC_CFGR_PPRE1_DIV2);
|
||||
|
||||
/* Enable and stabilise the PLL. */
|
||||
rcc->cr |= RCC_CR_PLLON;
|
||||
while (!(rcc->cr & RCC_CR_PLLRDY))
|
||||
cpu_relax();
|
||||
|
||||
if (is_artery_mcu)
|
||||
*RCC_MISC2 |= RCC_MISC2_AUTOSTEP_EN;
|
||||
|
||||
/* Switch to the externally-driven PLL for system clock. */
|
||||
rcc->cfgr |= RCC_CFGR_SW_PLL;
|
||||
while ((rcc->cfgr & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL)
|
||||
cpu_relax();
|
||||
|
||||
if (is_artery_mcu)
|
||||
*RCC_MISC2 &= ~RCC_MISC2_AUTOSTEP_EN;
|
||||
|
||||
/* Internal oscillator no longer needed. */
|
||||
rcc->cr &= ~RCC_CR_HSION;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#define GPI_bus GPI_floating
|
||||
#define GPO_bus GPO_pushpull(_2MHz, HIGH)
|
||||
#define GPO_rdata GPO_pushpull(_2MHz, LOW)
|
||||
#define AFO_rdata _AFO_pushpull(_2MHz,LOW)
|
||||
#define AFO_rdata (AFO_pushpull(_2MHz) | (LOW<<4))
|
||||
|
||||
/* READY-window state machine and timer handling. */
|
||||
static struct window {
|
||||
|
|
@ -121,7 +121,7 @@ void floppy_init(void)
|
|||
floppy_set_fintf_mode();
|
||||
|
||||
printk("Interface: QuickDisk, JC=%s\n",
|
||||
qd_roland_mode() ? "On (Roland)" : "Off");
|
||||
board_jc_strapped() ? "On (Roland)" : "Off");
|
||||
|
||||
board_floppy_init();
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ void floppy_insert(unsigned int unit, struct slot *slot)
|
|||
floppy_mount(slot);
|
||||
|
||||
timer_dma_init();
|
||||
tim_rdata->ccr2 = sampleclk_ns(1500); /* RD: 1.5us positive pulses */
|
||||
tim_rdata->ccr2 = sysclk_ns(1500); /* RD: 1.5us positive pulses */
|
||||
|
||||
/* Drive is ready. Set output signals appropriately. */
|
||||
write_pin(media, LOW);
|
||||
|
|
@ -248,7 +248,7 @@ static bool_t dma_rd_handle(struct drive *drv)
|
|||
case DMA_inactive: {
|
||||
time_t read_start_pos = window.paused ? window.pause_pos : 0;
|
||||
read_start_pos %= drv->image->stk_per_rev;
|
||||
read_start_pos *= SAMPLECLK_MHZ/STK_MHZ;
|
||||
read_start_pos *= SYSCLK_MHZ/STK_MHZ;
|
||||
if (image_setup_track(drv->image, 0, &read_start_pos))
|
||||
return TRUE;
|
||||
/* Change state /then/ check for race against step or side change. */
|
||||
|
|
|
|||
61
src/sd_spi.c
61
src/sd_spi.c
|
|
@ -9,10 +9,16 @@
|
|||
* See the file COPYING for more details, or visit <http://unlicense.org>.
|
||||
*/
|
||||
|
||||
#define PCLK_MHZ APB1_MHZ
|
||||
#define INIT_SPEED_KHZ 400
|
||||
#define DEFAULT_SPEED_KHZ 25000
|
||||
#if 1
|
||||
/* We can now switch to Default Speed (25MHz). Closest we can get is 36Mhz/2 =
|
||||
* 18MHz. */
|
||||
#define DEFAULT_SPEED_DIV SPI_CR1_BR_DIV2 /* 18MHz */
|
||||
#define SPI_PIN_SPEED _50MHz
|
||||
#else
|
||||
/* Best speed I can reliably achieve right now is 9Mbit/s. */
|
||||
#define DEFAULT_SPEED_DIV SPI_CR1_BR_DIV4 /* 9MHz */
|
||||
#define SPI_PIN_SPEED _10MHz
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define TRC(f, a...) printk("SD: " f, ## a)
|
||||
|
|
@ -60,13 +66,13 @@ static void spi_release(void)
|
|||
|
||||
static uint8_t wait_ready(void)
|
||||
{
|
||||
time_t start = time_now();
|
||||
stk_time_t start = stk_now();
|
||||
uint8_t res;
|
||||
|
||||
/* Wait 500ms for card to be ready. */
|
||||
do {
|
||||
res = spi_recv8(spi);
|
||||
} while ((res != 0xff) && (time_since(start) < time_ms(500)));
|
||||
} while ((res != 0xff) && (stk_timesince(start) < stk_ms(500)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -166,13 +172,13 @@ static uint8_t send_cmd(uint8_t cmd, uint32_t arg)
|
|||
static bool_t datablock_recv(BYTE *buff, uint16_t bytes)
|
||||
{
|
||||
uint8_t token, _crc[2];
|
||||
uint32_t start = stk_now();
|
||||
uint16_t todo, w, crc;
|
||||
time_t start = time_now();
|
||||
|
||||
/* Wait 100ms for data to be ready. */
|
||||
do {
|
||||
token = spi_recv8(spi);
|
||||
} while ((token == 0xff) && (time_since(start) < time_ms(100)));
|
||||
} while ((token == 0xff) && (stk_timesince(start) < stk_ms(100)));
|
||||
if (token != 0xfe) /* valid data token? */
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -264,26 +270,9 @@ static bool_t sd_inserted(void)
|
|||
return gpio_read_pin(gpioc, 9);
|
||||
}
|
||||
|
||||
static void sd_spi_set_cr(uint32_t cr1, unsigned int max_khz)
|
||||
{
|
||||
/* Set the divisor to satisfy maximum communications frequency. */
|
||||
uint32_t br = SPI_BR_DIV2;
|
||||
unsigned int khz = (PCLK_MHZ * 1000) >> 1;
|
||||
while (khz > max_khz) {
|
||||
khz >>= 1;
|
||||
br++;
|
||||
}
|
||||
|
||||
/* BR is called MDIV in AT32F435 documentation, and is extended by one
|
||||
* bit which resides in CR2. */
|
||||
spi->cr2 = (br & 8) << (8 - 3); /* CR2[8] := MDIV[3] */
|
||||
spi->cr1 = cr1 | ((br & 7) << 3); /* CR1[5:4] := MDIV[2:0] */
|
||||
}
|
||||
|
||||
static DSTATUS sd_disk_initialize(BYTE pdrv)
|
||||
{
|
||||
time_t start;
|
||||
uint32_t cr1;
|
||||
uint32_t start, cr1;
|
||||
uint16_t rcv;
|
||||
uint8_t i;
|
||||
|
||||
|
|
@ -299,24 +288,16 @@ static DSTATUS sd_disk_initialize(BYTE pdrv)
|
|||
|
||||
/* Enable external I/O pins. */
|
||||
gpio_configure_pin(gpiob, PIN_CS, GPO_pushpull(SPI_PIN_SPEED, HIGH));
|
||||
#if MCU == STM32F105
|
||||
gpio_configure_pin(gpiob, 13, AFO_pushpull(SPI_PIN_SPEED)); /* CK */
|
||||
gpio_configure_pin(gpiob, 14, GPI_pull_up); /* MISO */
|
||||
gpio_configure_pin(gpiob, 15, AFO_pushpull(SPI_PIN_SPEED)); /* MOSI */
|
||||
#elif MCU == AT32F435
|
||||
gpio_set_af(gpiob, 13, 5);
|
||||
gpio_configure_pin(gpiob, 13, AFO_pushpull(SPI_PIN_SPEED)); /* CK */
|
||||
gpio_set_af(gpiob, 14, 5);
|
||||
gpio_configure_pin(gpiob, 14, AFI(PUPD_up)); /* MISO */
|
||||
gpio_set_af(gpiob, 15, 5);
|
||||
gpio_configure_pin(gpiob, 15, AFO_pushpull(SPI_PIN_SPEED)); /* MOSI */
|
||||
#endif
|
||||
|
||||
/* Configure SPI: 8-bit mode, MSB first, CPOL Low, CPHA Leading Edge. */
|
||||
spi->cr2 = 0;
|
||||
cr1 = (SPI_CR1_MSTR | /* master */
|
||||
SPI_CR1_SSM | SPI_CR1_SSI | /* software NSS */
|
||||
SPI_CR1_SPE);
|
||||
sd_spi_set_cr(cr1, INIT_SPEED_KHZ);
|
||||
spi->cr1 = cr1 | SPI_CR1_BR_DIV128; /* ~281kHz (<400kHz) */
|
||||
|
||||
/* Drain SPI I/O. */
|
||||
spi_quiesce(spi);
|
||||
|
|
@ -347,9 +328,9 @@ static DSTATUS sd_disk_initialize(BYTE pdrv)
|
|||
}
|
||||
|
||||
/* Request SDHC/SDXC and start card initialisation. */
|
||||
start = time_now();
|
||||
start = stk_now();
|
||||
while (send_cmd(ACMD(41), 1u<<30)) {
|
||||
if (time_since(start) >= time_ms(1000))
|
||||
if (stk_timesince(start) >= stk_ms(1000))
|
||||
goto out; /* initialisation timeout */
|
||||
}
|
||||
|
||||
|
|
@ -378,9 +359,9 @@ static DSTATUS sd_disk_initialize(BYTE pdrv)
|
|||
}
|
||||
|
||||
/* Wait for card initialisation. */
|
||||
start = time_now();
|
||||
start = stk_now();
|
||||
while (send_cmd(cmd, 0)) {
|
||||
if (time_since(start) >= time_ms(1000))
|
||||
if (stk_timesince(start) >= stk_ms(1000))
|
||||
goto out; /* initialisation timeout */
|
||||
}
|
||||
|
||||
|
|
@ -398,7 +379,7 @@ out:
|
|||
|
||||
if (!(status & STA_NOINIT)) {
|
||||
delay_us(10); /* XXX small delay here stops SPI getting stuck?? */
|
||||
sd_spi_set_cr(cr1, DEFAULT_SPEED_KHZ);
|
||||
spi->cr1 = cr1 | DEFAULT_SPEED_DIV;
|
||||
printk("SD Card configured\n");
|
||||
dump_cid_info();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
|
||||
#if defined(BOOTLOADER)
|
||||
#if defined(BOOTLOADER) && (MCU == STM32F105)
|
||||
#define FLASH_BASE 0x08000000
|
||||
#define FLASH_LEN 32K
|
||||
|
||||
#elif defined(BOOTLOADER) && (MCU == AT32F435)
|
||||
#define FLASH_BASE 0x08000000
|
||||
#define FLASH_LEN 48K
|
||||
|
||||
#elif MCU == STM32F105
|
||||
#define FLASH_BASE 0x08008000
|
||||
#define FLASH_LEN 94K
|
||||
|
||||
#elif MCU == AT32F435
|
||||
#define FLASH_BASE 0x0800c000
|
||||
#define FLASH_LEN 206K
|
||||
#endif
|
||||
|
||||
/* Flash overflow is checked by scripts/check_hex.py
|
||||
* Just define a big enough value here. */
|
||||
#define FLASH_LEN 256K
|
||||
|
||||
#define RAM_BASE 0x20000000
|
||||
#define RAM_LEN 16K
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
static volatile time_t time_stamp;
|
||||
static struct timer time_stamp_timer;
|
||||
|
||||
/* Hardware systick timer overflows every 2^24 ticks. We aim to update
|
||||
/* Timestamp needs to be updated ever 2^24 systicks. We aim to update
|
||||
* the timestamp at twice that rate (2^23 systicks). */
|
||||
#define TIME_UPDATE_PERIOD time_stk(1u<<23)
|
||||
#define TIME_UPDATE_MS ((1u<<23)/(STK_MHZ*1000))
|
||||
|
||||
void delay_from(time_t t, unsigned int ticks)
|
||||
{
|
||||
|
|
@ -27,7 +27,7 @@ static void time_stamp_update(void *unused)
|
|||
{
|
||||
time_t now = time_now();
|
||||
time_stamp = ~now;
|
||||
timer_set(&time_stamp_timer, now + TIME_UPDATE_PERIOD);
|
||||
timer_set(&time_stamp_timer, now + time_ms(TIME_UPDATE_MS));
|
||||
}
|
||||
|
||||
time_t time_now(void)
|
||||
|
|
@ -45,7 +45,7 @@ void time_init(void)
|
|||
timers_init();
|
||||
time_stamp = stk_now();
|
||||
timer_init(&time_stamp_timer, time_stamp_update, NULL);
|
||||
timer_set(&time_stamp_timer, time_now() + TIME_UPDATE_PERIOD);
|
||||
timer_set(&time_stamp_timer, time_now() + time_ms(TIME_UPDATE_MS));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ static void reprogram_timer(int32_t delta)
|
|||
* fine-grained deadline. */
|
||||
tim->psc = sysclk_us(100)-1;
|
||||
tim->arr = min_t(uint32_t, 0xffffu,
|
||||
delta/time_us(100)-10); /* 1ms early */
|
||||
delta/time_us(100)-50); /* 5ms early */
|
||||
}
|
||||
tim->egr = TIM_EGR_UG; /* update CNT, PSC, ARR */
|
||||
tim->sr = 0; /* dummy write, gives hardware time to process EGR.UG=1 */
|
||||
|
|
|
|||
|
|
@ -17,47 +17,41 @@ static bool_t msc_device_connected;
|
|||
extern USB_OTG_CORE_HANDLE USB_OTG_Core;
|
||||
USBH_HOST USB_Host;
|
||||
|
||||
#if 1
|
||||
#define TRC_FUNC() printk("> %s\n", __FUNCTION__)
|
||||
#else
|
||||
#define TRC_FUNC() ((void)0)
|
||||
#endif
|
||||
|
||||
static void USBH_USR_Init(void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void USBH_USR_DeInit(void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
msc_device_connected = FALSE;
|
||||
}
|
||||
|
||||
static void USBH_USR_DeviceAttached(void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void USBH_USR_ResetDevice(void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void USBH_USR_DeviceDisconnected (void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
msc_device_connected = FALSE;
|
||||
}
|
||||
|
||||
static void USBH_USR_OverCurrentDetected (void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void USBH_USR_DeviceSpeedDetected(uint8_t DeviceSpeed)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
printk("> Device speed: %s\n",
|
||||
(DeviceSpeed == HPRT0_PRTSPD_HIGH_SPEED) ? "High" :
|
||||
(DeviceSpeed == HPRT0_PRTSPD_FULL_SPEED) ? "Full" :
|
||||
|
|
@ -67,14 +61,14 @@ static void USBH_USR_DeviceSpeedDetected(uint8_t DeviceSpeed)
|
|||
static void USBH_USR_DeviceDescAvailable(void *DeviceDesc)
|
||||
{
|
||||
USBH_DevDesc_TypeDef *hs = DeviceDesc;
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
printk(" VID : %04X\n", hs->idVendor);
|
||||
printk(" PID : %04X\n", hs->idProduct);
|
||||
}
|
||||
|
||||
static void USBH_USR_DeviceAddressAssigned(void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void USBH_USR_ConfigurationDescAvailable(
|
||||
|
|
@ -84,7 +78,7 @@ static void USBH_USR_ConfigurationDescAvailable(
|
|||
{
|
||||
USBH_InterfaceDesc_TypeDef *id = itfDesc;
|
||||
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
printk("> Class connected: %02x (%s)\n",
|
||||
id->bInterfaceClass,
|
||||
(id->bInterfaceClass == 0x08) ? "MSC" :
|
||||
|
|
@ -108,12 +102,12 @@ static void USBH_USR_SerialNumString(void *SerialNumString)
|
|||
|
||||
static void USBH_USR_EnumerationDone(void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static USBH_USR_Status USBH_USR_UserInput(void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
return USBH_USR_RESP_OK;
|
||||
}
|
||||
|
||||
|
|
@ -126,12 +120,12 @@ static int USBH_USR_UserApplication(void)
|
|||
|
||||
static void USBH_USR_DeviceNotSupported(void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void USBH_USR_UnrecoveredError (void)
|
||||
{
|
||||
TRC_FUNC();
|
||||
printk("> %s\n", __FUNCTION__);
|
||||
msc_device_connected = FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
12
src/util.c
12
src/util.c
|
|
@ -335,18 +335,6 @@ unsigned int popcount(uint32_t x)
|
|||
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:
|
||||
* mode: C
|
||||
|
|
|
|||
Loading…
Reference in a new issue