mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Merge pull request #751 from davidgiven/tartu
Add support for the Tartu Palivere.
This commit is contained in:
		
							
								
								
									
										79
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								README.md
									
									
									
									
									
								
							| @@ -103,45 +103,46 @@ particular filesystem and can read (and sometimes write, support varies) files | ||||
| directly from disks, flux files or disk images. Some formats have multiple | ||||
| choices because they can store multiple types of file system. | ||||
|  | ||||
| <!-- FORMATSSTART --> | ||||
| <!-- This section is automatically generated. Do not edit. --> | ||||
|  | ||||
| | Profile | Format | Read? | Write? | Filesystem? | | ||||
| |:--------|:-------|:-----:|:------:|:------------| | ||||
| | [`acornadfs`](doc/disk-acornadfs.md) | Acorn ADFS: BBC Micro, Archimedes | 🦖 |  |  | | ||||
| | [`acorndfs`](doc/disk-acorndfs.md) | Acorn DFS: Acorn Atom, BBC Micro series | 🦄 |  | ACORNDFS  | | ||||
| | [`aeslanier`](doc/disk-aeslanier.md) | AES Lanier "No Problem": 616kB 5.25" 77-track SSDD hard sectored | 🦖 |  |  | | ||||
| | [`agat`](doc/disk-agat.md) | Agat: 840kB 5.25" 80-track DS | 🦖 | 🦖 |  | | ||||
| | [`amiga`](doc/disk-amiga.md) | Amiga: 880kB 3.5" DSDD | 🦄 | 🦄 | AMIGAFFS  | | ||||
| | [`ampro`](doc/disk-ampro.md) | Ampro Little Board: CP/M | 🦖 |  | CPMFS  | | ||||
| | [`apple2`](doc/disk-apple2.md) | Apple II: Prodos, Appledos, and CP/M | 🦄 | 🦄 | APPLEDOS CPMFS PRODOS  | | ||||
| | [`atarist`](doc/disk-atarist.md) | Atari ST: Almost PC compatible | 🦄 | 🦄 |  | | ||||
| | [`bk`](doc/disk-bk.md) | BK: 800kB 5.25"/3.5" 80-track 10-sector DSDD | 🦖 | 🦖 |  | | ||||
| | [`brother`](doc/disk-brother.md) | Brother word processors: GCR family | 🦄 | 🦄 | BROTHER120 FATFS  | | ||||
| | [`commodore`](doc/disk-commodore.md) | Commodore: 1541, 1581, 8050 and variations | 🦄 | 🦄 | CBMFS  | | ||||
| | [`eco1`](doc/disk-eco1.md) | VDS Eco1: CP/M; 1210kB 77-track mixed format DSHD | 🦖 |  | CPMFS  | | ||||
| | [`epsonpf10`](doc/disk-epsonpf10.md) | Epson PF-10: CP/M; 3.5" 40-track DSDD | 🦖 |  | CPMFS  | | ||||
| | [`f85`](doc/disk-f85.md) | Durango F85: 461kB 5.25" 77-track SS | 🦖 |  |  | | ||||
| | [`fb100`](doc/disk-fb100.md) | Brother FB-100: 100kB 3.5" 40-track SSSD | 🦖 |  |  | | ||||
| | [`hplif`](doc/disk-hplif.md) | Hewlett-Packard LIF: a variety of disk formats used by HP | 🦄 | 🦄 | LIF  | | ||||
| | [`ibm`](doc/disk-ibm.md) | IBM PC: Generic PC 3.5"/5.25" disks | 🦄 | 🦄 | FATFS  | | ||||
| | [`icl30`](doc/disk-icl30.md) | ICL Model 30: CP/M; 263kB 35-track DSSD | 🦖 |  | CPMFS  | | ||||
| | [`mac`](doc/disk-mac.md) | Macintosh: 400kB/800kB 3.5" GCR | 🦄 | 🦄 | MACHFS  | | ||||
| | [`micropolis`](doc/disk-micropolis.md) | Micropolis: 100tpi MetaFloppy disks | 🦄 | 🦄 |  | | ||||
| | [`ms2000`](doc/disk-ms2000.md) | : MS2000 Microdisk Development System |  |  | MICRODOS  | | ||||
| | [`mx`](doc/disk-mx.md) | DVK MX: Soviet-era PDP-11 clone | 🦖 |  |  | | ||||
| | [`n88basic`](doc/disk-n88basic.md) | N88-BASIC: PC8800/PC98 5.25" 77-track 26-sector DSHD | 🦄 | 🦄 |  | | ||||
| | [`northstar`](doc/disk-northstar.md) | Northstar: 5.25" hard sectored | 🦄 | 🦄 |  | | ||||
| | [`psos`](doc/disk-psos.md) | pSOS: 800kB DSDD with PHILE | 🦄 | 🦄 | PHILE  | | ||||
| | [`rolandd20`](doc/disk-rolandd20.md) | Roland D20: 3.5" electronic synthesiser disks | 🦄 | 🦖 | ROLAND  | | ||||
| | [`rx50`](doc/disk-rx50.md) | Digital RX50: 400kB 5.25" 80-track 10-sector SSDD | 🦖 | 🦖 |  | | ||||
| | [`smaky6`](doc/disk-smaky6.md) | Smaky 6: 308kB 5.25" 77-track 16-sector SSDD, hard sectored | 🦖 |  | SMAKY6  | | ||||
| | [`tids990`](doc/disk-tids990.md) | Texas Instruments DS990: 1126kB 8" DSSD | 🦖 | 🦖 |  | | ||||
| | [`tiki`](doc/disk-tiki.md) | Tiki 100: CP/M |  |  | CPMFS  | | ||||
| | [`victor9k`](doc/disk-victor9k.md) | Victor 9000 / Sirius One: 1224kB 5.25" DSDD GCR | 🦖 | 🦖 |  | | ||||
| | [`zilogmcz`](doc/disk-zilogmcz.md) | Zilog MCZ: 320kB 8" 77-track SSSD hard-sectored | 🦖 |  | ZDOS  | | ||||
| {: .datatable } | ||||
|  | ||||
| <!-- FORMATSSTART --> | ||||
| <!-- This section is automatically generated. Do not edit. --> | ||||
|  | ||||
| | Profile | Format | Read? | Write? | Filesystem? | | ||||
| |:--------|:-------|:-----:|:------:|:------------| | ||||
| | [`acornadfs`](doc/disk-acornadfs.md) | Acorn ADFS: BBC Micro, Archimedes | 🦖 |  |  | | ||||
| | [`acorndfs`](doc/disk-acorndfs.md) | Acorn DFS: Acorn Atom, BBC Micro series | 🦄 |  | ACORNDFS  | | ||||
| | [`aeslanier`](doc/disk-aeslanier.md) | AES Lanier "No Problem": 616kB 5.25" 77-track SSDD hard sectored | 🦖 |  |  | | ||||
| | [`agat`](doc/disk-agat.md) | Agat: 840kB 5.25" 80-track DS | 🦖 | 🦖 |  | | ||||
| | [`amiga`](doc/disk-amiga.md) | Amiga: 880kB 3.5" DSDD | 🦄 | 🦄 | AMIGAFFS  | | ||||
| | [`ampro`](doc/disk-ampro.md) | Ampro Little Board: CP/M | 🦖 |  | CPMFS  | | ||||
| | [`apple2`](doc/disk-apple2.md) | Apple II: Prodos, Appledos, and CP/M | 🦄 | 🦄 | APPLEDOS CPMFS PRODOS  | | ||||
| | [`atarist`](doc/disk-atarist.md) | Atari ST: Almost PC compatible | 🦄 | 🦄 |  | | ||||
| | [`bk`](doc/disk-bk.md) | BK: 800kB 5.25"/3.5" 80-track 10-sector DSDD | 🦖 | 🦖 |  | | ||||
| | [`brother`](doc/disk-brother.md) | Brother word processors: GCR family | 🦄 | 🦄 | BROTHER120 FATFS  | | ||||
| | [`commodore`](doc/disk-commodore.md) | Commodore: 1541, 1581, 8050 and variations | 🦄 | 🦄 | CBMFS  | | ||||
| | [`eco1`](doc/disk-eco1.md) | VDS Eco1: CP/M; 1210kB 77-track mixed format DSHD | 🦖 |  | CPMFS  | | ||||
| | [`epsonpf10`](doc/disk-epsonpf10.md) | Epson PF-10: CP/M; 3.5" 40-track DSDD | 🦖 |  | CPMFS  | | ||||
| | [`f85`](doc/disk-f85.md) | Durango F85: 461kB 5.25" 77-track SS | 🦖 |  |  | | ||||
| | [`fb100`](doc/disk-fb100.md) | Brother FB-100: 100kB 3.5" 40-track SSSD | 🦖 |  |  | | ||||
| | [`hplif`](doc/disk-hplif.md) | Hewlett-Packard LIF: a variety of disk formats used by HP | 🦄 | 🦄 | LIF  | | ||||
| | [`ibm`](doc/disk-ibm.md) | IBM PC: Generic PC 3.5"/5.25" disks | 🦄 | 🦄 | FATFS  | | ||||
| | [`icl30`](doc/disk-icl30.md) | ICL Model 30: CP/M; 263kB 35-track DSSD | 🦖 |  | CPMFS  | | ||||
| | [`mac`](doc/disk-mac.md) | Macintosh: 400kB/800kB 3.5" GCR | 🦄 | 🦄 | MACHFS  | | ||||
| | [`micropolis`](doc/disk-micropolis.md) | Micropolis: 100tpi MetaFloppy disks | 🦄 | 🦄 |  | | ||||
| | [`ms2000`](doc/disk-ms2000.md) | : MS2000 Microdisk Development System |  |  | MICRODOS  | | ||||
| | [`mx`](doc/disk-mx.md) | DVK MX: Soviet-era PDP-11 clone | 🦖 |  |  | | ||||
| | [`n88basic`](doc/disk-n88basic.md) | N88-BASIC: PC8800/PC98 5.25" 77-track 26-sector DSHD | 🦄 | 🦄 |  | | ||||
| | [`northstar`](doc/disk-northstar.md) | Northstar: 5.25" hard sectored | 🦄 | 🦄 |  | | ||||
| | [`psos`](doc/disk-psos.md) | pSOS: 800kB DSDD with PHILE | 🦄 | 🦄 | PHILE  | | ||||
| | [`rolandd20`](doc/disk-rolandd20.md) | Roland D20: 3.5" electronic synthesiser disks | 🦄 | 🦖 | ROLAND  | | ||||
| | [`rx50`](doc/disk-rx50.md) | Digital RX50: 400kB 5.25" 80-track 10-sector SSDD | 🦖 | 🦖 |  | | ||||
| | [`smaky6`](doc/disk-smaky6.md) | Smaky 6: 308kB 5.25" 77-track 16-sector SSDD, hard sectored | 🦖 |  | SMAKY6  | | ||||
| | [`tartu`](doc/disk-tartu.md) | Tartu: The Palivere and variations | 🦄 |  | CPMFS  | | ||||
| | [`tids990`](doc/disk-tids990.md) | Texas Instruments DS990: 1126kB 8" DSSD | 🦖 | 🦖 |  | | ||||
| | [`tiki`](doc/disk-tiki.md) | Tiki 100: CP/M |  |  | CPMFS  | | ||||
| | [`victor9k`](doc/disk-victor9k.md) | Victor 9000 / Sirius One: 1224kB 5.25" DSDD GCR | 🦖 | 🦖 |  | | ||||
| | [`zilogmcz`](doc/disk-zilogmcz.md) | Zilog MCZ: 320kB 8" 77-track SSSD hard-sectored | 🦖 |  | ZDOS  | | ||||
| {: .datatable } | ||||
|  | ||||
| <!-- FORMATSEND --> | ||||
|  | ||||
| ### Notes | ||||
|   | ||||
| @@ -19,6 +19,7 @@ proto( | ||||
|         "./northstar/northstar.proto", | ||||
|         "./rolandd20/rolandd20.proto", | ||||
|         "./smaky6/smaky6.proto", | ||||
|         "./tartu/tartu.proto", | ||||
|         "./tids990/tids990.proto", | ||||
|         "./victor9k/victor9k.proto", | ||||
|         "./zilogmcz/zilogmcz.proto", | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| syntax = "proto2"; | ||||
|  | ||||
| import "lib/common.proto"; | ||||
|  | ||||
| message Smaky6DecoderProto {} | ||||
|  | ||||
|   | ||||
							
								
								
									
										84
									
								
								arch/tartu/decoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								arch/tartu/decoder.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "arch/tartu/tartu.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include <string.h> | ||||
|  | ||||
| constexpr uint64_t HEADER_BITS = 0xaaaaaaaa44895554LL; | ||||
| constexpr uint64_t DATA_BITS =   0xaaaaaaaa44895545LL; | ||||
|  | ||||
| static const FluxPattern HEADER_PATTERN(64, HEADER_BITS); | ||||
| static const FluxPattern DATA_PATTERN(64, DATA_BITS); | ||||
|  | ||||
| const FluxMatchers ANY_RECORD_PATTERN { | ||||
|     &HEADER_PATTERN, | ||||
|     &DATA_PATTERN | ||||
| }; | ||||
|  | ||||
| class TartuDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     TartuDecoder(const DecoderProto& config): | ||||
|         Decoder(config), | ||||
|         _config(config.tartu()) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void beginTrack() override | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(ANY_RECORD_PATTERN); | ||||
|     } | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         if (readRaw64() != HEADER_BITS) | ||||
|             return; | ||||
|  | ||||
|         auto bits = readRawBits(16 * 8); | ||||
|         auto bytes = decodeFmMfm(bits).slice(0, 8); | ||||
|          | ||||
|         ByteReader br(bytes); | ||||
|         uint8_t track = br.read_8(); | ||||
|         _sector->logicalTrack = track >> 1; | ||||
|         _sector->logicalSide = track & 1; | ||||
|         br.skip(1); /* seems always to be 1 */ | ||||
|         _sector->logicalSector = br.read_8(); | ||||
|         uint8_t wantChecksum = br.read_8(); | ||||
|         uint8_t gotChecksum = ~sumBytes(bytes.slice(0, 3)); | ||||
|          | ||||
|         if (wantChecksum == gotChecksum) | ||||
|             _sector->status = Sector::DATA_MISSING; | ||||
|  | ||||
|         _sector->status = Sector::DATA_MISSING; | ||||
|     } | ||||
|  | ||||
|     void decodeDataRecord() override | ||||
|     { | ||||
|         if (readRaw64() != DATA_BITS) | ||||
|             return; | ||||
|      | ||||
|         const auto& bits = readRawBits(129 * 16); | ||||
|         const auto& bytes = decodeFmMfm(bits).slice(0, 129); | ||||
|         _sector->data = bytes.slice(0, 128); | ||||
|  | ||||
|         uint8_t wantChecksum = bytes.reader().seek(128).read_8(); | ||||
|         uint8_t gotChecksum = ~sumBytes(_sector->data); | ||||
|         _sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const TartuDecoderProto& _config; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createTartuDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new TartuDecoder(config)); | ||||
| } | ||||
|  | ||||
							
								
								
									
										7
									
								
								arch/tartu/tartu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								arch/tartu/tartu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #ifndef TARTU_H | ||||
| #define TARTU_H | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createTartuDecoder(const DecoderProto& config); | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										4
									
								
								arch/tartu/tartu.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								arch/tartu/tartu.proto
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| syntax = "proto2"; | ||||
|  | ||||
| message TartuDecoderProto {} | ||||
|  | ||||
							
								
								
									
										2
									
								
								build.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								build.py
									
									
									
									
									
								
							| @@ -143,6 +143,7 @@ cxxlibrary( | ||||
|         "./arch/northstar/encoder.cc", | ||||
|         "./arch/rolandd20/decoder.cc", | ||||
|         "./arch/smaky6/decoder.cc", | ||||
|         "./arch/tartu/decoder.cc", | ||||
|         "./arch/tids990/decoder.cc", | ||||
|         "./arch/tids990/encoder.cc", | ||||
|         "./arch/victor9k/decoder.cc", | ||||
| @@ -175,6 +176,7 @@ cxxlibrary( | ||||
|         "arch/micropolis/micropolis.h": "./arch/micropolis/micropolis.h", | ||||
|         "arch/c64/data_gcr.h": "./arch/c64/data_gcr.h", | ||||
|         "arch/c64/c64.h": "./arch/c64/c64.h", | ||||
|         "arch/tartu/tartu.h": "./arch/tartu/tartu.h", | ||||
|         "lib/a2r.h": "./lib/a2r.h", | ||||
|         "lib/bitmap.h": "./lib/bitmap.h", | ||||
|         "lib/bytes.h": "./lib/bytes.h", | ||||
|   | ||||
							
								
								
									
										43
									
								
								doc/disk-tartu.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								doc/disk-tartu.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| tartu | ||||
| ==== | ||||
| ## The Palivere and variations | ||||
| <!-- This file is automatically generated. Do not edit. --> | ||||
|  | ||||
| The Tartu Palivere is a 1988 Z80-based computer from Estonia. It is a CP/M | ||||
| machine with 64kB of RAM, running off a 2MHz ꃣ0e30 | ||||
| clone; it operated off punched tape, cassette, external hard drive or floppy, and was notable as being the first ever computer with an Estonian keyboard. | ||||
|  | ||||
| <div style="text-align: center"> | ||||
| <img src="tartu.jpg" alt="The Tartu computer's developer Leo Humal working with one."/> | ||||
| </div> | ||||
|  | ||||
| From a floppy disk perspective, it is interesting because the floppy drive | ||||
| interface is almost entirely handled in software --- necessary at the time as | ||||
| the usual floppy disk interface chip at the time, the ⎲fba5 | ||||
| of the WD1793), was hard to find. Instead, the floppy controller board was | ||||
| implemented entirely using TTL logic. Despite this, the encoding is fairly high | ||||
| density, using MFM and with up to 780kB on a double-sided 80 track disk. | ||||
|  | ||||
| <div style="text-align: center"> | ||||
| <img src="tartu-fdc.jpg" alt="The Tartu FDC with Soviet TTL logic chips."/> | ||||
| </div> | ||||
|  | ||||
| FluxEngine supports reading Tartu disks with CP/M filesystem access. | ||||
|  | ||||
| ## Options | ||||
|  | ||||
|   - Format variants: | ||||
|       - `390`: 390kB 5.25" 40-track DSDD | ||||
|       - `780`: 780kB 5.25" 80-track DSDD | ||||
|  | ||||
| ## Examples | ||||
|  | ||||
| To read: | ||||
|  | ||||
|   - `fluxengine read tartu --390 -s drive:0 -o tartu.img` | ||||
|   - `fluxengine read tartu --780 -s drive:0 -o tartu.img` | ||||
|  | ||||
| ## References | ||||
|  | ||||
|   - [The Estonia Museum of Electronics](https://www.elektroonikamuuseum.ee/tartu_arvuti_lugu.html) | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								doc/tartu-fdc.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/tartu-fdc.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 165 KiB | 
							
								
								
									
										
											BIN
										
									
								
								doc/tartu.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/tartu.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 86 KiB | 
| @@ -18,6 +18,7 @@ | ||||
| #include "arch/northstar/northstar.h" | ||||
| #include "arch/rolandd20/rolandd20.h" | ||||
| #include "arch/smaky6/smaky6.h" | ||||
| #include "arch/tartu/tartu.h" | ||||
| #include "arch/tids990/tids990.h" | ||||
| #include "arch/victor9k/victor9k.h" | ||||
| #include "arch/zilogmcz/zilogmcz.h" | ||||
| @@ -51,6 +52,7 @@ std::unique_ptr<Decoder> Decoder::create(const DecoderProto& config) | ||||
|             {DecoderProto::kNorthstar,  createNorthstarDecoder  }, | ||||
|             {DecoderProto::kRolandd20,  createRolandD20Decoder  }, | ||||
|             {DecoderProto::kSmaky6,     createSmaky6Decoder     }, | ||||
|             {DecoderProto::kTartu,      createTartuDecoder      }, | ||||
|             {DecoderProto::kTids990,    createTids990Decoder    }, | ||||
|             {DecoderProto::kVictor9K,   createVictor9kDecoder   }, | ||||
|             {DecoderProto::kZilogmcz,   createZilogMczDecoder   }, | ||||
| @@ -89,7 +91,7 @@ std::shared_ptr<TrackDataFlux> Decoder::decodeToSectors( | ||||
|         Fluxmap::Position recordStart = fmr.tell(); | ||||
|         _sector->clock = advanceToNextRecord(); | ||||
|         if (fmr.eof() || !_sector->clock) | ||||
|             return _trackdata; | ||||
|             break; | ||||
|  | ||||
|         /* Read the sector record. */ | ||||
|  | ||||
| @@ -108,28 +110,26 @@ std::shared_ptr<TrackDataFlux> Decoder::decodeToSectors( | ||||
|         { | ||||
|             /* The data is in a separate record. */ | ||||
|  | ||||
|             for (;;) | ||||
|             _sector->headerStartTime = before.ns(); | ||||
|             _sector->headerEndTime = after.ns(); | ||||
|  | ||||
|             _sector->clock = advanceToNextRecord(); | ||||
|             if (fmr.eof() || !_sector->clock) | ||||
|                 break; | ||||
|  | ||||
|             before = fmr.tell(); | ||||
|             decodeDataRecord(); | ||||
|             after = fmr.tell(); | ||||
|  | ||||
|             if (_sector->status != Sector::DATA_MISSING) | ||||
|             { | ||||
|                 _sector->position = before.bytes; | ||||
|                 _sector->dataStartTime = before.ns(); | ||||
|                 _sector->dataEndTime = after.ns(); | ||||
|                 pushRecord(before, after); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 _sector->headerStartTime = before.ns(); | ||||
|                 _sector->headerEndTime = after.ns(); | ||||
|  | ||||
|                 _sector->clock = advanceToNextRecord(); | ||||
|                 if (fmr.eof() || !_sector->clock) | ||||
|                     break; | ||||
|  | ||||
|                 before = fmr.tell(); | ||||
|                 decodeDataRecord(); | ||||
|                 after = fmr.tell(); | ||||
|  | ||||
|                 if (_sector->status != Sector::DATA_MISSING) | ||||
|                 { | ||||
|                     _sector->position = before.bytes; | ||||
|                     _sector->dataStartTime = before.ns(); | ||||
|                     _sector->dataEndTime = after.ns(); | ||||
|                     pushRecord(before, after); | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 fmr.skipToEvent(F_BIT_PULSE); | ||||
|                 resetFluxDecoder(); | ||||
|             } | ||||
| @@ -142,6 +142,8 @@ std::shared_ptr<TrackDataFlux> Decoder::decodeToSectors( | ||||
|             _trackdata->sectors.push_back(_sector); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return _trackdata; | ||||
| } | ||||
|  | ||||
| void Decoder::pushRecord( | ||||
|   | ||||
| @@ -15,13 +15,14 @@ import "arch/mx/mx.proto"; | ||||
| import "arch/northstar/northstar.proto"; | ||||
| import "arch/rolandd20/rolandd20.proto"; | ||||
| import "arch/smaky6/smaky6.proto"; | ||||
| import "arch/tartu/tartu.proto"; | ||||
| import "arch/tids990/tids990.proto"; | ||||
| import "arch/victor9k/victor9k.proto"; | ||||
| import "arch/zilogmcz/zilogmcz.proto"; | ||||
| import "lib/fluxsink/fluxsink.proto"; | ||||
| import "lib/common.proto"; | ||||
|  | ||||
| //NEXT: 32 | ||||
| //NEXT: 33 | ||||
| message DecoderProto { | ||||
| 	optional double pulse_debounce_threshold = 1 [default = 0.30, | ||||
| 		(help) = "ignore pulses with intervals shorter than this, in fractions of a clock"]; | ||||
| @@ -50,6 +51,7 @@ message DecoderProto { | ||||
| 		NorthstarDecoderProto northstar = 24; | ||||
| 		RolandD20DecoderProto rolandd20 = 31; | ||||
| 		Smaky6DecoderProto smaky6 = 30; | ||||
| 		TartuDecoderProto tartu = 32; | ||||
| 		Tids990DecoderProto tids990 = 16; | ||||
| 		Victor9kDecoderProto victor9k = 17; | ||||
| 		ZilogMczDecoderProto zilogmcz = 18; | ||||
|   | ||||
| @@ -34,6 +34,7 @@ formats = [ | ||||
|     "rx50", | ||||
|     "shugart_drive", | ||||
|     "smaky6", | ||||
|     "tartu", | ||||
|     "tids990", | ||||
|     "tiki", | ||||
|     "victor9k", | ||||
|   | ||||
							
								
								
									
										100
									
								
								src/formats/tartu.textpb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/formats/tartu.textpb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| shortname: 'Tartu' | ||||
| comment: 'The Palivere and variations' | ||||
| read_support_status: UNICORN | ||||
|  | ||||
| documentation: | ||||
| <<< | ||||
| The Tartu Palivere is a 1988 Z80-based computer from Estonia. It is a CP/M | ||||
| machine with 64kB of RAM, running off a 2MHz КP580ВМ80А, a Soviet Union 8080 | ||||
| clone; it operated off punched tape, cassette, external hard drive or floppy, and was notable as being the first ever computer with an Estonian keyboard. | ||||
|  | ||||
| <div style="text-align: center"> | ||||
| <img src="tartu.jpg" alt="The Tartu computer's developer Leo Humal working with one."/> | ||||
| </div> | ||||
|  | ||||
| From a floppy disk perspective, it is interesting because the floppy drive | ||||
| interface is almost entirely handled in software --- necessary at the time as | ||||
| the usual floppy disk interface chip at the time, the КR1818VG93 (a Soviet clone | ||||
| of the WD1793), was hard to find. Instead, the floppy controller board was | ||||
| implemented entirely using TTL logic. Despite this, the encoding is fairly high | ||||
| density, using MFM and with up to 780kB on a double-sided 80 track disk. | ||||
|  | ||||
| <div style="text-align: center"> | ||||
| <img src="tartu-fdc.jpg" alt="The Tartu FDC with Soviet TTL logic chips."/> | ||||
| </div> | ||||
|  | ||||
| FluxEngine supports reading Tartu disks with CP/M filesystem access. | ||||
| >>> | ||||
|  | ||||
| documentation: | ||||
| <<< | ||||
| ## References | ||||
|  | ||||
|   - [The Estonia Museum of Electronics](https://www.elektroonikamuuseum.ee/tartu_arvuti_lugu.html) | ||||
| >>> | ||||
|  | ||||
| image_writer { | ||||
| 	filename: "tartu.img" | ||||
| 	type: IMAGETYPE_IMG | ||||
| } | ||||
|  | ||||
| layout { | ||||
| 	layoutdata { | ||||
| 		sector_size: 128 | ||||
| 		physical { | ||||
| 			start_sector: 1 | ||||
| 			count: 39 | ||||
| 		} | ||||
|  | ||||
| 		filesystem { | ||||
| 			start_sector: 1 | ||||
| 			count: 39 | ||||
| 			skew: 3 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| decoder { | ||||
| 	tartu {} | ||||
| } | ||||
|  | ||||
| option_group { | ||||
| 	comment: "$formats" | ||||
|  | ||||
| 	option { | ||||
| 		name: "390" | ||||
| 		comment: '390kB 5.25" 40-track DSDD' | ||||
|  | ||||
| 		config { | ||||
| 			layout { | ||||
| 				format_type: FORMATTYPE_40TRACK | ||||
| 				tracks: 40 | ||||
| 				sides: 2 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	option { | ||||
| 		name: "780" | ||||
| 		comment: '780kB 5.25" 80-track DSDD' | ||||
|  | ||||
| 		config { | ||||
| 			layout { | ||||
| 				format_type: FORMATTYPE_80TRACK | ||||
| 				tracks: 80 | ||||
| 				sides: 2 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| filesystem { | ||||
| 	type: CPMFS | ||||
| 	cpmfs { | ||||
| 		filesystem_start { | ||||
| 			track: 1 | ||||
| 		} | ||||
| 		block_size: 2048 | ||||
| 		dir_entries: 128 | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user