mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 98a28225d6 | ||
|  | d041b538bb | 
| @@ -1,9 +1,19 @@ | |||||||
| #ifndef AESLANIER_H | #ifndef AESLANIER_H | ||||||
| #define AESLANIER_H | #define AESLANIER_H | ||||||
|  |  | ||||||
|  | /* MFM: | ||||||
|  |  *  | ||||||
|  |  * Raw bits: | ||||||
|  |  *    5    5    5    5    5    1    2    2 | ||||||
|  |  * 0101 0101 0101 0101 0101 0001 0010 0010 | ||||||
|  |  * 0 0  0 0  0 0  0 0  0 0  0 0  0 1  0 1 | ||||||
|  |  *        0         0         0         5 | ||||||
|  |  * Decoded bits. | ||||||
|  |  */ | ||||||
|  |  | ||||||
| #define AESLANIER_RECORD_SEPARATOR 0x55555122 | #define AESLANIER_RECORD_SEPARATOR 0x55555122 | ||||||
| #define AESLANIER_SECTOR_LENGTH 256 | #define AESLANIER_SECTOR_LENGTH 256 | ||||||
| #define AESLANIER_RECORD_SIZE (AESLANIER_SECTOR_LENGTH + 5) | #define AESLANIER_RECORD_SIZE (AESLANIER_SECTOR_LENGTH + 4) | ||||||
|  |  | ||||||
| extern std::unique_ptr<Decoder> createAesLanierDecoder( | extern std::unique_ptr<Decoder> createAesLanierDecoder( | ||||||
|     const DecoderProto& config); |     const DecoderProto& config); | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| syntax = "proto2"; | syntax = "proto2"; | ||||||
|  |  | ||||||
| message AesLanierDecoderProto {} | message AesLanier5DecoderProto {} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								arch/aeslanier5/aeslanier5.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								arch/aeslanier5/aeslanier5.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | #ifndef AESLANIER5_H | ||||||
|  | #define AESLANIER5_H | ||||||
|  |  | ||||||
|  | /* Format is FM: | ||||||
|  |  * | ||||||
|  |  *    a    a    a    a    f    b    e    f | ||||||
|  |  * 1010 1010 1010 1010 1111 1011 1110 1111 | ||||||
|  |  *  0 0  0 0  0 0  0 0  1 1  0 1  1 0  1 1 | ||||||
|  |  *         0         0         d         b | ||||||
|  |  *  | ||||||
|  |  * However, note that this pattern is _not_ reversed... | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #define AESLANIER5_RECORD_SEPARATOR 0xaaaaaaaaaaaafbefLL | ||||||
|  | #define AESLANIER5_SECTOR_LENGTH 151 | ||||||
|  | #define AESLANIER5_RECORD_SIZE (AESLANIER5_SECTOR_LENGTH + 3) | ||||||
|  |  | ||||||
|  | extern std::unique_ptr<Decoder> createAesLanier5Decoder( | ||||||
|  |     const DecoderProto& config); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										4
									
								
								arch/aeslanier5/aeslanier5.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								arch/aeslanier5/aeslanier5.proto
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | syntax = "proto2"; | ||||||
|  |  | ||||||
|  | message AesLanierDecoderProto {} | ||||||
|  |  | ||||||
							
								
								
									
										78
									
								
								arch/aeslanier5/decoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								arch/aeslanier5/decoder.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | |||||||
|  | #include "lib/core/globals.h" | ||||||
|  | #include "lib/decoders/decoders.h" | ||||||
|  | #include "aeslanier5.h" | ||||||
|  | #include "lib/core/crc.h" | ||||||
|  | #include "lib/data/fluxmap.h" | ||||||
|  | #include "lib/data/fluxmapreader.h" | ||||||
|  | #include "lib/data/fluxpattern.h" | ||||||
|  | #include "lib/data/sector.h" | ||||||
|  | #include "lib/core/bytes.h" | ||||||
|  | #include "fmt/format.h" | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | static const FluxPattern SECTOR_PATTERN(32, AESLANIER5_RECORD_SEPARATOR); | ||||||
|  |  | ||||||
|  | /* This is actually FM, rather than MFM, but it our MFM/FM decoder copes fine | ||||||
|  |  * with it. */ | ||||||
|  |  | ||||||
|  | class AesLanier5Decoder : public Decoder | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     AesLanier5Decoder(const DecoderProto& config): Decoder(config) {} | ||||||
|  |  | ||||||
|  |     nanoseconds_t advanceToNextRecord() override | ||||||
|  |     { | ||||||
|  |         return seekToPattern(SECTOR_PATTERN); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void decodeSectorRecord() override | ||||||
|  |     { | ||||||
|  |         /* Skip ID mark (we know it's a AESLANIER5_RECORD_SEPARATOR). */ | ||||||
|  |  | ||||||
|  |         readRawBits(SECTOR_PATTERN.length()); | ||||||
|  |  | ||||||
|  |         const auto& rawbits = readRawBits(AESLANIER5_RECORD_SIZE * 16); | ||||||
|  |         const auto& bytes = | ||||||
|  |             decodeFmMfm(rawbits).slice(0, AESLANIER5_RECORD_SIZE); | ||||||
|  |         const auto& reversed = bytes.reverseBits(); | ||||||
|  |  | ||||||
|  |         uint8_t encodedTrack = reversed[0]; | ||||||
|  |         uint8_t encodedSector = reversed[1]; | ||||||
|  |  | ||||||
|  |         _sector->logicalTrack = encodedTrack >> 1; | ||||||
|  |         _sector->logicalSide = 0; | ||||||
|  |         _sector->logicalSector = encodedSector; | ||||||
|  |  | ||||||
|  |         /* Check header 'checksum' (which seems far too simple to mean much). */ | ||||||
|  |  | ||||||
|  |         { | ||||||
|  |             uint8_t wanted = reversed[2]; | ||||||
|  |             uint8_t got = reversed[0] + reversed[1]; | ||||||
|  |             if (wanted != got) | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* Check data checksum, which also includes the header and is | ||||||
|  |          * significantly better. */ | ||||||
|  |  | ||||||
|  |         _sector->data = reversed.slice(3, AESLANIER5_SECTOR_LENGTH); | ||||||
|  |         uint8_t wanted, got; | ||||||
|  |         ByteReader br(_sector->data); | ||||||
|  |         if ((encodedSector == 0) || (encodedSector == 8)) | ||||||
|  |         { | ||||||
|  |             wanted = br.seek(17).read_8() + br.seek(150).read_8(); | ||||||
|  |             got = sumBytes(_sector->data.slice(0, 17)) + sumBytes(_sector->data.slice(18, 132)); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             wanted = br.seek(150).read_8(); | ||||||
|  |             got = sumBytes(_sector->data.slice(0, AESLANIER5_SECTOR_LENGTH-1)); | ||||||
|  |         } | ||||||
|  |         _sector->status = (wanted == got) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | std::unique_ptr<Decoder> createAesLanier5Decoder(const DecoderProto& config) | ||||||
|  | { | ||||||
|  |     return std::unique_ptr<Decoder>(new AesLanier5Decoder(config)); | ||||||
|  | } | ||||||
| @@ -4,6 +4,7 @@ | |||||||
| #include "lib/config/config.h" | #include "lib/config/config.h" | ||||||
| #include "arch/agat/agat.h" | #include "arch/agat/agat.h" | ||||||
| #include "arch/aeslanier/aeslanier.h" | #include "arch/aeslanier/aeslanier.h" | ||||||
|  | #include "arch/aeslanier5/aeslanier5.h" | ||||||
| #include "arch/amiga/amiga.h" | #include "arch/amiga/amiga.h" | ||||||
| #include "arch/apple2/apple2.h" | #include "arch/apple2/apple2.h" | ||||||
| #include "arch/brother/brother.h" | #include "arch/brother/brother.h" | ||||||
| @@ -70,6 +71,7 @@ std::unique_ptr<Decoder> Arch::createDecoder(const DecoderProto& config) | |||||||
|         decoders = { |         decoders = { | ||||||
|             {DecoderProto::kAgat,       createAgatDecoder       }, |             {DecoderProto::kAgat,       createAgatDecoder       }, | ||||||
|             {DecoderProto::kAeslanier,  createAesLanierDecoder  }, |             {DecoderProto::kAeslanier,  createAesLanierDecoder  }, | ||||||
|  |             {DecoderProto::kAeslanier5, createAesLanier5Decoder  }, | ||||||
|             {DecoderProto::kAmiga,      createAmigaDecoder      }, |             {DecoderProto::kAmiga,      createAmigaDecoder      }, | ||||||
|             {DecoderProto::kApple2,     createApple2Decoder     }, |             {DecoderProto::kApple2,     createApple2Decoder     }, | ||||||
|             {DecoderProto::kBrother,    createBrotherDecoder    }, |             {DecoderProto::kBrother,    createBrotherDecoder    }, | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ proto( | |||||||
|     name="proto", |     name="proto", | ||||||
|     srcs=[ |     srcs=[ | ||||||
|         "./aeslanier/aeslanier.proto", |         "./aeslanier/aeslanier.proto", | ||||||
|  |         "./aeslanier5/aeslanier5.proto", | ||||||
|         "./agat/agat.proto", |         "./agat/agat.proto", | ||||||
|         "./amiga/amiga.proto", |         "./amiga/amiga.proto", | ||||||
|         "./apple2/apple2.proto", |         "./apple2/apple2.proto", | ||||||
| @@ -36,6 +37,7 @@ cxxlibrary( | |||||||
|     srcs=[ |     srcs=[ | ||||||
|         "./arch.cc", |         "./arch.cc", | ||||||
|         "./aeslanier/decoder.cc", |         "./aeslanier/decoder.cc", | ||||||
|  |         "./aeslanier5/decoder.cc", | ||||||
|         "./agat/agat.cc", |         "./agat/agat.cc", | ||||||
|         "./agat/decoder.cc", |         "./agat/decoder.cc", | ||||||
|         "./agat/encoder.cc", |         "./agat/encoder.cc", | ||||||
| @@ -83,6 +85,7 @@ cxxlibrary( | |||||||
|         "arch/f85/f85.h": "./f85/f85.h", |         "arch/f85/f85.h": "./f85/f85.h", | ||||||
|         "arch/mx/mx.h": "./mx/mx.h", |         "arch/mx/mx.h": "./mx/mx.h", | ||||||
|         "arch/aeslanier/aeslanier.h": "./aeslanier/aeslanier.h", |         "arch/aeslanier/aeslanier.h": "./aeslanier/aeslanier.h", | ||||||
|  |         "arch/aeslanier5/aeslanier5.h": "./aeslanier5/aeslanier5.h", | ||||||
|         "arch/northstar/northstar.h": "./northstar/northstar.h", |         "arch/northstar/northstar.h": "./northstar/northstar.h", | ||||||
|         "arch/brother/data_gcr.h": "./brother/data_gcr.h", |         "arch/brother/data_gcr.h": "./brother/data_gcr.h", | ||||||
|         "arch/brother/brother.h": "./brother/brother.h", |         "arch/brother/brother.h": "./brother/brother.h", | ||||||
|   | |||||||
| @@ -31,13 +31,16 @@ based on what looks right. If anyone knows _anything_ about these disks, | |||||||
|  |  | ||||||
| ## Options | ## Options | ||||||
|  |  | ||||||
| (no options) |   - Format variants: | ||||||
|  |       - `8`: use the format found on 8" disks | ||||||
|  |       - `5`: use the format found on 5.25" disks | ||||||
|  |  | ||||||
| ## Examples | ## Examples | ||||||
|  |  | ||||||
| To read: | To read: | ||||||
|  |  | ||||||
|   - `fluxengine read aeslanier -s drive:0 -o aeslanier.img` |   - `fluxengine read aeslanier --8 -s drive:0 -o aeslanier.img` | ||||||
|  |   - `fluxengine read aeslanier --5 -s drive:0 -o aeslanier.img` | ||||||
|  |  | ||||||
| ## References | ## References | ||||||
|  |  | ||||||
|   | |||||||
| @@ -33,6 +33,11 @@ public: | |||||||
|  |  | ||||||
|     bool matches(const unsigned* intervals, FluxMatch& match) const override; |     bool matches(const unsigned* intervals, FluxMatch& match) const override; | ||||||
|  |  | ||||||
|  |     unsigned length() const | ||||||
|  |     { | ||||||
|  |         return _bits; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     unsigned intervals() const override |     unsigned intervals() const override | ||||||
|     { |     { | ||||||
|         return _intervals.size(); |         return _intervals.size(); | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ syntax = "proto2"; | |||||||
|  |  | ||||||
| import "arch/agat/agat.proto"; | import "arch/agat/agat.proto"; | ||||||
| import "arch/aeslanier/aeslanier.proto"; | import "arch/aeslanier/aeslanier.proto"; | ||||||
|  | import "arch/aeslanier5/aeslanier5.proto"; | ||||||
| import "arch/amiga/amiga.proto"; | import "arch/amiga/amiga.proto"; | ||||||
| import "arch/apple2/apple2.proto"; | import "arch/apple2/apple2.proto"; | ||||||
| import "arch/brother/brother.proto"; | import "arch/brother/brother.proto"; | ||||||
| @@ -22,7 +23,7 @@ import "arch/zilogmcz/zilogmcz.proto"; | |||||||
| import "lib/fluxsink/fluxsink.proto"; | import "lib/fluxsink/fluxsink.proto"; | ||||||
| import "lib/config/common.proto"; | import "lib/config/common.proto"; | ||||||
|  |  | ||||||
| //NEXT: 33 | //NEXT: 34 | ||||||
| message DecoderProto { | message DecoderProto { | ||||||
| 	optional double pulse_debounce_threshold = 1 [default = 0.30, | 	optional double pulse_debounce_threshold = 1 [default = 0.30, | ||||||
| 		(help) = "ignore pulses with intervals shorter than this, in fractions of a clock"]; | 		(help) = "ignore pulses with intervals shorter than this, in fractions of a clock"]; | ||||||
| @@ -37,6 +38,7 @@ message DecoderProto { | |||||||
|  |  | ||||||
| 	oneof format { | 	oneof format { | ||||||
| 		AesLanierDecoderProto aeslanier = 7; | 		AesLanierDecoderProto aeslanier = 7; | ||||||
|  | 		AesLanier5DecoderProto aeslanier5 = 33; | ||||||
| 		AgatDecoderProto agat = 28; | 		AgatDecoderProto agat = 28; | ||||||
| 		AmigaDecoderProto amiga = 8; | 		AmigaDecoderProto amiga = 8; | ||||||
| 		Apple2DecoderProto apple2 = 13; | 		Apple2DecoderProto apple2 = 13; | ||||||
|   | |||||||
| @@ -14,6 +14,8 @@ of nearly £50,000 in 2018!). | |||||||
| processing software off twin 5.25" drive units, but apparently other software | processing software off twin 5.25" drive units, but apparently other software | ||||||
| was available. | was available. | ||||||
|  |  | ||||||
|  | **Note:** the following is wrong and needs to be updated. | ||||||
|  |  | ||||||
| The disk format is exceptionally weird. They used 77 track, 32 sector, single-sided | The disk format is exceptionally weird. They used 77 track, 32 sector, single-sided | ||||||
| _hard_ sectored disks, where there were multiple index holes, | _hard_ sectored disks, where there were multiple index holes, | ||||||
| indicating to the hardware where the sectors start. The encoding scheme | indicating to the hardware where the sectors start. The encoding scheme | ||||||
| @@ -46,21 +48,56 @@ image_writer { | |||||||
| 	type: IMAGETYPE_IMG | 	type: IMAGETYPE_IMG | ||||||
| } | } | ||||||
|  |  | ||||||
| decoder { | option_group { | ||||||
| 	aeslanier {} | 	comment: "$formats" | ||||||
| } |  | ||||||
|  |  | ||||||
| layout { | 	option { | ||||||
| 	format_type: FORMATTYPE_80TRACK | 		name: '8' | ||||||
| 	tracks: 77 | 		comment: 'use the format found on 8" disks' | ||||||
| 	sides: 1 | 		set_by_default: true | ||||||
| 	layoutdata { |  | ||||||
| 		sector_size: 256 | 		config { | ||||||
| 		physical { | 			decoder { | ||||||
| 			start_sector: 0 | 				aeslanier {} | ||||||
| 			count: 32 | 			} | ||||||
|  |  | ||||||
|  | 			layout { | ||||||
|  | 				format_type: FORMATTYPE_80TRACK | ||||||
|  | 				tracks: 77 | ||||||
|  | 				sides: 1 | ||||||
|  | 				layoutdata { | ||||||
|  | 					sector_size: 256 | ||||||
|  | 					physical { | ||||||
|  | 						start_sector: 0 | ||||||
|  | 						count: 32 | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	option { | ||||||
|  | 		name: '83' | ||||||
|  | 		comment: '83kB 5.25" 35-track 16-sector SSSD' | ||||||
|  |  | ||||||
|  | 		config { | ||||||
|  | 			decoder { | ||||||
|  | 				aeslanier5 {} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			layout { | ||||||
|  | 				format_type: FORMATTYPE_40TRACK | ||||||
|  | 				tracks: 35 | ||||||
|  | 				sides: 1 | ||||||
|  | 				layoutdata { | ||||||
|  | 					sector_size: 150 | ||||||
|  | 					physical { | ||||||
|  | 						start_sector: 0 | ||||||
|  | 						count: 16 | ||||||
|  | 						skew: 3 | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -246,12 +246,13 @@ void FluxViewerControl::OnPaint(wxPaintEvent&) | |||||||
|             dc.SetTextForeground(*wxBLACK); |             dc.SetTextForeground(*wxBLACK); | ||||||
|             for (auto& sector : trackdata->sectors) |             for (auto& sector : trackdata->sectors) | ||||||
|             { |             { | ||||||
|                 nanoseconds_t sr = sector->dataEndTime; |                 nanoseconds_t tl = sector->headerStartTime; | ||||||
|                 if (!sr) |                 nanoseconds_t tr = sector->dataEndTime; | ||||||
|                     sr = sector->headerEndTime; |                 if (!tl && !sector->headerEndTime) | ||||||
|  |                     tl = sector->dataStartTime; | ||||||
|  |  | ||||||
|                 int sp = sector->headerStartTime / _nanosecondsPerPixel; |                 int sp = tl / _nanosecondsPerPixel; | ||||||
|                 int sw = (sr - sector->headerStartTime) / _nanosecondsPerPixel; |                 int sw = (tr - tl) / _nanosecondsPerPixel; | ||||||
|  |  | ||||||
|                 wxRect rect = {x + sp, t1y - ch2, sw, ch}; |                 wxRect rect = {x + sp, t1y - ch2, sw, ch}; | ||||||
|                 bool hovered = rect.Contains(_mouseX, _mouseY); |                 bool hovered = rect.Contains(_mouseX, _mouseY); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user