mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			98 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "globals.h"
 | |
| #include "fluxmap.h"
 | |
| #include "decoders/fluxmapreader.h"
 | |
| #include "protocol.h"
 | |
| #include "record.h"
 | |
| #include "decoders/decoders.h"
 | |
| #include "sector.h"
 | |
| #include "amiga.h"
 | |
| #include "bytes.h"
 | |
| #include "fmt/format.h"
 | |
| #include <string.h>
 | |
| #include <algorithm>
 | |
| 
 | |
| /* 
 | |
|  * Amiga disks use MFM but it's not quite the same as IBM MFM. They only use
 | |
|  * a single type of record with a different marker byte.
 | |
|  * 
 | |
|  * See the big comment in the IBM MFM decoder for the gruesome details of how
 | |
|  * MFM works.
 | |
|  */
 | |
|          
 | |
| static const FluxPattern SECTOR_PATTERN(48, AMIGA_SECTOR_RECORD);
 | |
| 
 | |
| static Bytes deinterleave(const uint8_t*& input, size_t len)
 | |
| {
 | |
|     assert(!(len & 1));
 | |
|     const uint8_t* odds = &input[0];
 | |
|     const uint8_t* evens = &input[len/2];
 | |
|     Bytes output;
 | |
|     ByteWriter bw(output);
 | |
| 
 | |
|     for (size_t i=0; i<len/2; i++)
 | |
|     {
 | |
|         uint8_t o = *odds++;
 | |
|         uint8_t e = *evens++;
 | |
| 
 | |
|         /* This is the 'Interleave bits with 64-bit multiply' technique from
 | |
|          * http://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN
 | |
|          */
 | |
|         uint16_t result =
 | |
|             (((e * 0x0101010101010101ULL & 0x8040201008040201ULL)
 | |
|                 * 0x0102040810204081ULL >> 49) & 0x5555) |
 | |
|             (((o * 0x0101010101010101ULL & 0x8040201008040201ULL)
 | |
|                 * 0x0102040810204081ULL >> 48) & 0xAAAA);
 | |
|         
 | |
|         bw.write_be16(result);
 | |
|     }
 | |
| 
 | |
|     input += len;
 | |
|     return output;
 | |
| }
 | |
| 
 | |
| static uint32_t checksum(const Bytes& bytes)
 | |
| {
 | |
|     ByteReader br(bytes);
 | |
|     uint32_t checksum = 0;
 | |
| 
 | |
|     assert((bytes.size() & 3) == 0);
 | |
|     while (!br.eof())
 | |
|         checksum ^= br.read_be32();
 | |
| 
 | |
|     return checksum & 0x55555555;
 | |
| }
 | |
| 
 | |
| AbstractDecoder::RecordType AmigaDecoder::advanceToNextRecord()
 | |
| {
 | |
|     _sector->clock = _fmr->seekToPattern(SECTOR_PATTERN);
 | |
|     if (_fmr->eof() || !_sector->clock)
 | |
|         return UNKNOWN_RECORD;
 | |
|     return SECTOR_RECORD;
 | |
| }
 | |
| 
 | |
| void AmigaDecoder::decodeSectorRecord()
 | |
| {
 | |
|     const auto& rawbits = readRawBits(AMIGA_RECORD_SIZE*16);
 | |
|     const auto& rawbytes = toBytes(rawbits).slice(0, AMIGA_RECORD_SIZE*2);
 | |
|     const auto& bytes = decodeFmMfm(rawbits).slice(0, AMIGA_RECORD_SIZE);
 | |
| 
 | |
|     const uint8_t* ptr = bytes.begin() + 3;
 | |
| 
 | |
|     Bytes header = deinterleave(ptr, 4);
 | |
|     Bytes recoveryinfo = deinterleave(ptr, 16);
 | |
| 
 | |
|     _sector->logicalTrack = header[1] >> 1;
 | |
|     _sector->logicalSide = header[1] & 1;
 | |
|     _sector->logicalSector = header[2];
 | |
| 
 | |
|     uint32_t wantedheaderchecksum = deinterleave(ptr, 4).reader().read_be32();
 | |
|     uint32_t gotheaderchecksum = checksum(rawbytes.slice(6, 40));
 | |
|     if (gotheaderchecksum != wantedheaderchecksum)
 | |
|         return;
 | |
| 
 | |
|     uint32_t wanteddatachecksum = deinterleave(ptr, 4).reader().read_be32();
 | |
|     uint32_t gotdatachecksum = checksum(rawbytes.slice(62, 1024));
 | |
|     _sector->data = deinterleave(ptr, 512);
 | |
|     _sector->status = (gotdatachecksum == wanteddatachecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | |
| }
 |