mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			102 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "lib/core/globals.h"
 | |
| #include "lib/decoders/decoders.h"
 | |
| #include "lib/encoders/encoders.h"
 | |
| #include "arch/tids990/tids990.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 <string.h>
 | |
| #include "fmt/format.h"
 | |
| 
 | |
| /* The Texas Instruments DS990 uses MFM with a scheme similar to a simplified
 | |
|  * version of the IBM record scheme (it's actually easier to parse than IBM).
 | |
|  * There are 26 sectors per track, each holding a rather weird 288 bytes.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Sector record:
 | |
|  * data:    0  1  0  1  0  1  0  1 .0  0  0  0  1  0  1  0  = 0x550a
 | |
|  * mfm:     00 01 00 01 00 01 00 01.00 10 10 10 01 00 01 00 = 0x11112a44
 | |
|  * special: 00 01 00 01 00 01 00 01.00 10 00 10 01 00 01 00 = 0x11112244
 | |
|  *                                        ^^
 | |
|  * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | |
|  * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | |
|  */
 | |
| const uint16_t SECTOR_ID = 0x550a;
 | |
| const FluxPattern SECTOR_RECORD_PATTERN(32, 0x11112244);
 | |
| 
 | |
| /*
 | |
|  * Data record:
 | |
|  * data:    0  1  0  1  0  1  0  1 .0  0  0  0  1  0  1  1  = 0x550b
 | |
|  * mfm:     00 01 00 01 00 01 00 01.00 10 10 10 01 00 01 01 = 0x11112a45
 | |
|  * special: 00 01 00 01 00 01 00 01.00 10 00 10 01 00 01 01 = 0x11112245
 | |
|  *                                        ^^
 | |
|  * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | |
|  * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | |
|  */
 | |
| const uint16_t DATA_ID = 0x550b;
 | |
| const FluxPattern DATA_RECORD_PATTERN(32, 0x11112245);
 | |
| 
 | |
| const FluxMatchers ANY_RECORD_PATTERN(
 | |
|     {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN});
 | |
| 
 | |
| class Tids990Decoder : public Decoder
 | |
| {
 | |
| public:
 | |
|     Tids990Decoder(const DecoderProto& config): Decoder(config) {}
 | |
| 
 | |
|     nanoseconds_t advanceToNextRecord() override
 | |
|     {
 | |
|         return seekToPattern(ANY_RECORD_PATTERN);
 | |
|     }
 | |
| 
 | |
|     void decodeSectorRecord() override
 | |
|     {
 | |
|         auto bits = readRawBits(TIDS990_SECTOR_RECORD_SIZE * 16);
 | |
|         auto bytes = decodeFmMfm(bits).slice(0, TIDS990_SECTOR_RECORD_SIZE);
 | |
| 
 | |
|         ByteReader br(bytes);
 | |
|         if (br.read_be16() != SECTOR_ID)
 | |
|             return;
 | |
| 
 | |
|         uint16_t gotChecksum =
 | |
|             crc16(CCITT_POLY, bytes.slice(1, TIDS990_SECTOR_RECORD_SIZE - 3));
 | |
| 
 | |
|         _sector->logicalSide = br.read_8() >> 3;
 | |
|         _sector->logicalTrack = br.read_8();
 | |
|         br.read_8(); /* number of sectors per track */
 | |
|         _sector->logicalSector = br.read_8();
 | |
|         br.read_be16(); /* sector size */
 | |
|         uint16_t wantChecksum = br.read_be16();
 | |
| 
 | |
|         if (wantChecksum == gotChecksum)
 | |
|             _sector->status =
 | |
|                 Sector::DATA_MISSING; /* correct but unintuitive */
 | |
|     }
 | |
| 
 | |
|     void decodeDataRecord() override
 | |
|     {
 | |
|         auto bits = readRawBits(TIDS990_DATA_RECORD_SIZE * 16);
 | |
|         auto bytes = decodeFmMfm(bits).slice(0, TIDS990_DATA_RECORD_SIZE);
 | |
| 
 | |
|         ByteReader br(bytes);
 | |
|         if (br.read_be16() != DATA_ID)
 | |
|             return;
 | |
| 
 | |
|         uint16_t gotChecksum =
 | |
|             crc16(CCITT_POLY, bytes.slice(1, TIDS990_DATA_RECORD_SIZE - 3));
 | |
| 
 | |
|         _sector->data = br.read(TIDS990_PAYLOAD_SIZE);
 | |
|         uint16_t wantChecksum = br.read_be16();
 | |
|         _sector->status =
 | |
|             (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | |
|     }
 | |
| };
 | |
| 
 | |
| std::unique_ptr<Decoder> createTids990Decoder(const DecoderProto& config)
 | |
| {
 | |
|     return std::unique_ptr<Decoder>(new Tids990Decoder(config));
 | |
| }
 |