mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			133 Commits
		
	
	
		
			FluxEngine
			...
			FluxEngine
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e6da85bf64 | ||
|  | cd19fcdadd | ||
|  | a737c723d3 | ||
|  | 37aa8b62b0 | ||
|  | a401173f6d | ||
|  | ce76dc4279 | ||
|  | 1025bd857b | ||
|  | 025802b2d0 | ||
|  | adbcb2cd31 | ||
|  | c47a563790 | ||
|  | 04c09d1a5b | ||
|  | 323da8272a | ||
|  | 38700c79fc | ||
|  | d504d1890a | ||
|  | d53e757cfb | ||
|  | 4983239458 | ||
|  | 376985828a | ||
|  | dce0a26820 | ||
|  | 14e0a67e7d | ||
|  | 1656947764 | ||
|  | 647862cdbd | ||
|  | 4a8d83838c | ||
|  | 8acf8e181d | ||
|  | 2df9920209 | ||
|  | 1a6c6b5420 | ||
|  | edc56d44d6 | ||
|  | ef4eff0195 | ||
|  | df8d45bf66 | ||
|  | 89a27619ff | ||
|  | 387a86969a | ||
|  | acb5059d17 | ||
|  | a4002d2617 | ||
|  | a63a90bbd0 | ||
|  | d25f96dd24 | ||
|  | e8febe6508 | ||
|  | ad3a930c6a | ||
|  | be41c1de76 | ||
|  | d528978667 | ||
|  | 827fcf69d2 | ||
|  | 711ff545e0 | ||
|  | 5befa31050 | ||
|  | 8e5c2d0ebb | ||
|  | f95fceeb3d | ||
|  | 003b20dbf0 | ||
|  | cd9bbaa4b6 | ||
|  | 71e622bf72 | ||
|  | 2a065a08df | ||
|  | 6087228378 | ||
|  | efd74e0d7b | ||
|  | b68a9dcc4f | ||
|  | 008855daa9 | ||
|  | 7a9d36de2a | ||
|  | c56e982c9a | ||
|  | 002cc171a2 | ||
|  | 32e721b47a | ||
|  | 1e82f697a9 | ||
|  | fa09631e32 | ||
|  | e06436ce1e | ||
|  | b2f443e1ad | ||
|  | 2e07be0cf7 | ||
|  | bf0b14d094 | ||
|  | c9f5803194 | ||
|  | 5293560c02 | ||
|  | c49823aa9d | ||
|  | c4ef4882ae | ||
|  | a8eca06cf0 | ||
|  | 065257b5aa | ||
|  | 29bdfc043a | ||
|  | 933ffe7ab4 | ||
|  | e517f28563 | ||
|  | 91ffcf59c3 | ||
|  | 51c618f325 | ||
|  | 9dc1067032 | ||
|  | 9e75dc3af1 | ||
|  | efa4c933b3 | ||
|  | 6af80d1e5e | ||
|  | 0c48897814 | ||
|  | 60e5e35947 | ||
|  | 86c4e959ca | ||
|  | b0c675c589 | ||
|  | d77841c3b7 | ||
|  | 4ed1fb6bac | ||
|  | bcc9e9d9a5 | ||
|  | ec327e25a4 | ||
|  | d0ed5b32f7 | ||
|  | 7c66e1b0d4 | ||
|  | 4475e9f085 | ||
|  | 5c9639ec5a | ||
|  | 792cc88192 | ||
|  | 21fe586724 | ||
|  | 5a0fb2761a | ||
|  | ef4581ed39 | ||
|  | 73419704c2 | ||
|  | a8b92d4780 | ||
|  | 98140b0646 | ||
|  | 4429ce1f84 | ||
|  | 1f50941a2c | ||
|  | a7de04848c | ||
|  | c264fec6e9 | ||
|  | 4488b2542f | ||
|  | 2f1a5189d6 | ||
|  | effaeff51e | ||
|  | 1210549f59 | ||
|  | 7200de9702 | ||
|  | 5dd5c8516a | ||
|  | f7fb2a844b | ||
|  | 20b1b2a4a8 | ||
|  | f8b8bc2295 | ||
|  | 2d4d56d09f | ||
|  | 39599b76c8 | ||
|  | c2c40ccfbb | ||
|  | ab42eb23f4 | ||
|  | 05eff0e528 | ||
|  | 23311b4b68 | ||
|  | 5e97df8d15 | ||
|  | 898e8c551c | ||
|  | ad69c6bd27 | ||
|  | 661399cc83 | ||
|  | edbb4b1daa | ||
|  | 6389e8a756 | ||
|  | c187b79d80 | ||
|  | edbe624c5a | ||
|  | 44e2334815 | ||
|  | b448ab7917 | ||
|  | 072a097003 | ||
|  | a66e704bab | ||
|  | ed0d578b18 | ||
|  | 32bb956710 | ||
|  | f436d6b582 | ||
|  | d2f8c27cb6 | ||
|  | eaa3c57425 | ||
|  | 549f12a2ab | ||
|  | aea254fbe7 | 
| @@ -15,7 +15,7 @@ install: | ||||
|  | ||||
| build_script: | ||||
|   - make | ||||
|   - zip -9 fluxengine.zip fluxengine.exe brother120tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex | ||||
|   - zip -9 fluxengine.zip fluxengine.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex | ||||
|  | ||||
| artifacts: | ||||
|   - path: fluxengine.zip | ||||
|   | ||||
							
								
								
									
										41
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| name: C/C++ CI | ||||
|  | ||||
| on: [push] | ||||
|  | ||||
| jobs: | ||||
|   build-linux: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - uses: actions/checkout@v1 | ||||
|       with: | ||||
|         fetch-depth: 1 | ||||
|     - name: apt | ||||
|       run: sudo apt update && sudo apt install libusb-1.0-0-dev libsqlite3-dev ninja-build | ||||
|     - name: make | ||||
|       run: make | ||||
|  | ||||
|   build-macos: | ||||
|     runs-on: macos-latest | ||||
|     steps: | ||||
|     - uses: actions/checkout@v1 | ||||
|       with: | ||||
|         fetch-depth: 1 | ||||
|     - name: brew | ||||
|       run: brew install sqlite pkg-config libusb ninja | ||||
|     - name: make | ||||
|       run: make | ||||
|  | ||||
| #  build-windows: | ||||
| #    runs-on: windows-latest | ||||
| #    steps: | ||||
| #    - uses: numworks/setup-msys2@v1 | ||||
| #      with: | ||||
| #        path-type: inherit | ||||
| #    - uses: actions/checkout@v1 | ||||
| #    - name: pacman | ||||
| #      run: | | ||||
| #        msys2do pacman -S --noconfirm --needed make ninja mingw-w64-i686-libusb mingw-w64-i686-sqlite3 mingw-w64-i686-zlib mingw-w64-i686-gcc zip | ||||
| #    - name: build | ||||
| #      run: | | ||||
| #        msys2do make | ||||
|  | ||||
							
								
								
									
										39
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -1,39 +0,0 @@ | ||||
| language: shell | ||||
| git: | ||||
|     depth: 1 | ||||
|  | ||||
| matrix: | ||||
|     include: | ||||
|         - | ||||
|             os: linux | ||||
|             sudo: false | ||||
|             dist: xenial | ||||
|             compiler: gcc | ||||
|             env: CXX=g++-8 | ||||
|             script: | ||||
|             - make | ||||
|         - | ||||
|             os: osx | ||||
|             osx_image: xcode10.2 | ||||
|             compiler: clang | ||||
|             env: | ||||
|             - HOMEBREW_NO_INSTALL_CLEANUP=1 | ||||
|  | ||||
| addons: | ||||
|     apt: | ||||
|         sources: | ||||
|         - llvm-toolchain-precise-3.8 | ||||
|         - ubuntu-toolchain-r-test | ||||
|         packages: | ||||
|         - ninja-build | ||||
|         - libusb-1.0-0-dev | ||||
|         - libsqlite3-dev | ||||
|         - g++-8 | ||||
|     homebrew: | ||||
|         packages: | ||||
|         - ninja | ||||
|  | ||||
| script: | ||||
| - make | ||||
|  | ||||
|  | ||||
| @@ -1,254 +1,254 @@ | ||||
| :400000000080002011000000910D0000910D0000064A08B5136843F020031360044B1A6803F53F5302331A6000F0D0FEE8460040FA46004010B5054C237833B9044B13B11C | ||||
| :400040000448AFF300800123237010BD6081FF1F0000000020310000084B10B51BB108490848AFF300800848036803B910BD074B002BFBD0BDE81040184700BF00000000F8 | ||||
| :400080006481FF1F20310000C880FF1F0000000072B6034A13680133136062B6704700BF8081FF1F0A4A0B4B516801310B40002BBEBF03F1FF3363F00F030133536051688F | ||||
| :4000C0009368994202BF024B01221A73704700BF8081FF1F0F0000800A4A0B4B916801310B40002BBEBF03F1FF3363F00F030133936091685368994202BF024B01221A7381 | ||||
| :40010000704700BF8081FF1F0F000080024B012200205A7302F030B88081FF1F10B5C4B2204601F015F80128FAD110BD70B5C4B220460E4601F014F8314605460246204623 | ||||
| :4001400001F0D0F8204601F003F80128FAD0284670BD000038B5094CA57B3DB9012001F071FF4FF47A7002F0BFF9E573236823610123A373BDE8384002F0F4B98081FF1FB9 | ||||
| :4001800038B50446C5B2284601F068FF012002F0C1F944F00200C0B201F060FF012002F0B9F9284601F05AFFBDE83840062002F09BB9000038B5044D0024285D013402F0F2 | ||||
| :4001C00059F9102CF9D138BD9481FF1F0FB400B593B014AB53F8042B402102A8019302F087FB02A801F0DBFF01F0E5FF13B05DF804EB04B07047000010B5044601780648E6 | ||||
| :40020000FFF7E4FF0420FFF789FF62782146BDE81040042000F0F4BF3231000007B50023ADF804308DF80600032301A88DF80530FFF7E2FF03B05DF804FB0000F8B5234C1D | ||||
| :400240000646FFF787FFE37B93B92148FFF7BEFF01F0FEFE18B90120FFF792FFF8E70120FFF78EFF01200023E073636202F052F93246616A1748FFF7A9FF144D0027636AD9 | ||||
| :400280009E421BD001F0E4FE28B16B6A13B11248FFF79CFF6762636A9E4205DD0020FFF76FFF6B6A013305E005DA0120FFF768FF6B6A013B6B6202F055F9E0E7322002F0F3 | ||||
| :4002C00013F9BDE8F8400548FFF780BF8081FF1F3F3100004631000063310000813100002DE9F04F9BB062B602F0A6F9BB49042002F0CAF9BA4801F0B7FEBA4801F0EAFE9E | ||||
| :40030000B94801F01BFF002001F03CFF01F046FF0221002000F0D2FEB44D0321084602F001F92E462C4602F01DF9AB7B5BB12A692B689B1A41F28832934204D9002001F022 | ||||
| :4003400081FE0023AB7300F0F1FE18B9A848FFF73DFF04E000F0F0FE0028F7D109E000F0E5FE0028FBD0A348FFF730FF032001F00DF8032000F0ECFE0128D4D19E4903208C | ||||
| :40038000FFF7D4FE94F828109C48FFF71FFF94F82830023B102B00F25F83DFE813F011005D031A005D0320005D0338005D035C005D0399015D0324035D0343035D034F0387 | ||||
| :4003C00003238DF828308DF8293008238DF82A3030E394F82A00FFF731FF894B27E3FFF7B9FE00236373637B002BFCD0002373733268637B002BFCD0336807218DF82810D2 | ||||
| :400400009B1A04218DF82910ADF82A3012E30220FFF784FE4FF000090DF1280A4FF480780027C8EB0903DA1907F80A200137402FF9D10220FFF772FE3A465146022000F0BF | ||||
| :40044000DFFEB8F10108EBD109F10109B9F1400FE4D16C4BC2E294F82A0001F019FE606AFFF7ECFE012001F093FE02F0ADF9664BDFF89C811A78002742F004021A701A78CF | ||||
| :4004800042F001021A701A7802F0FE021A701A7802F0FE021A7002F09BF90220FFF73EFE41F6FF734FF480420121022001F0F6FD84F8680001F0C4FF08F807000137102F9B | ||||
| :4004C000F8D1DFF850A100270AF15D081FFA88F90137102F14BF3A4600221AF8010F22440623127D402101F0DFFF4A4646F24B419AF8000001F0EAFF09F14009102F1FFA93 | ||||
| :4005000089F9E5D100237373637B002BFCD00027142239460AA87773DFF8F09002F0B4F940230D9338464FF0FF337760CDF83090B360377301F02CFE736896F868003344C9 | ||||
| :40054000197D01F035FF96F8680001F0F3FE012196F8680001F0C6FE636813B96B7B002BFAD0002794F82BA0A76094F80CB0BBF1000F6AD101F0F6FF6B7B43B1BAF1010A70 | ||||
| :4005800085F80DB003D160E02B7B002B5DD1A26863689A42F8D04FF0000BA3680AA808EB83135B440A93CBF140030B9300F072FA0B9B0137C3F140039B440D9B5FFA8BFB75 | ||||
| :4005C0009BBB022000F0C4FD012825D0637B002B3BD12B7B002BF4D037E000BF910000000D010000A5000000D90000008081FF1F8F310000A2310000A881FF1FAC31000041 | ||||
| :4006000024310000263100009B640040F085FF1F9481FF1F9381FF1F4022B949022000F0EFFD4023CDF830900D93BBF13F0FB4D9A268B44B01321340002BBEBF03F1FF3309 | ||||
| :4006400063F00F030133A3608FE7042194F8680001F0BAFE94F8680001F0C6FE0028F9D10AA800F04BFA0220FFF758FDDDF83480B8F1400F06D0C8F1400292B2A049022016 | ||||
| :4006800000F0BEFD0D9A32F0400203D11146022000F0B6FD0220FFF741FDFFF78BFD237B33B19948FFF792FD0220FFF7B7FD06E0964B09A81B88ADF82430FFF79DFD627B8B | ||||
| :4006C0003946237B9248CDF80080FFF77FFDC6E19048FFF77BFDE76A17F03F0701D00320BBE1012001F008FD95F82A0001F0D0FC02F06AF8884BDFF824821A7802F0FB0281 | ||||
| :400700001A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F059F8686AFFF78CFD01214FF4804341F6FF72084601F0E8FC85F8680001F082FE08F80700DE | ||||
| :400740000137102FF8D1DFF8D891002709F15D031FFA83F807930137102F14BF3A46002219F8010F22440523127D402101F09CFE414646F2484299F8000001F0A7FE08F1CB | ||||
| :400780004008102F1FFA88F8E5D10027BB46B946BA46F36A4FF0FF389B09142239460AA877600593C6F80880377302F06DF8402301200D9300F0EAFDCDF818806268514BEA | ||||
| :4007C00001321340002BBCBF03F1FF3363F00F03A168B8BF01338B4200F0A480BAF1000F07D0237B002B40F0B0806B7B002B40F0AC800B9B002B34D1B9F1000F0BD07F227B | ||||
| :400800003F495A540133402BFAD10A910B9328E0BAF1000F06D1012000F09AFC01288046F6D107E0237B002B40F08F806B7B002BF1D08AE03249FFF779FC8146304B0B90FB | ||||
| :4008400040460A9300F0A2FDB9F13F0F07F1010706DD059BDB1BD3F1000949EB030900E0C1460B9BDBB16368079A0AA802EB83120D9BC3F1400313440C9300F04EF90D9B1B | ||||
| :400880006BB96A681F4B01321340002BBEBF03F1FF3363F00F030133636040230D93A36801333FD16B680F2B3CD14FF00008C5F8088001F055FC85F80C80AB6895F86800DD | ||||
| :4008C0002B44197D01F074FD95F8680001F032FD012195F8680001F005FD85F80D80637B002BFCD04FF00008012086F80D8001F043FC404601F000FCCDF8188015E000BF6C | ||||
| :40090000F085FF1F0F000080BB31000028310000D5310000EE310000986400409481FF1F9381FF1FBAF1000F05D0237B6BB96B7B5BB94FF0010AA368069A93423FF43EAF55 | ||||
| :40094000AB680BF1010B069338E701F00FFC012001F0D2FB002001F00FFC042194F8680001F032FD94F8680001F03EFD0028F9D196F8680001F0CCFC737B327B029301235F | ||||
| :4009800003920193CDF800905B463A4605993748FFF71CFCB9F1000F16D1059BBB420ADD012000F0D5FB01288046F6D13049FFF7BDFB3F2803DC012000F0FCFC04E04046D2 | ||||
| :4009C00000F0E4FC0137E8E7FFF7F4FB2948FFF7FDFB237B0BB102203FE0274B1B8809A8ADF8243027E094F82A0001F051FB606AFFF724FC2148FFF7E9FB00236373637B8E | ||||
| :400A0000002BFCD0012001F0B7FB00237373637B002BFCD0002001F0AFFB1948FFF7D6FB184B04E00020E073FFF708FC164B1B88ADF828300AA8FFF7DFFB10E094F82A005D | ||||
| :400A400094F8B034834205D085F8B00401F09AFB0023EB730D4BEAE70120FFF7DFFB032000F094FC0A48FFF7B1FB5CE4F8310000F085FF1F283200002A3100003732000069 | ||||
| :400A8000453200002C3100002E310000303100005232000010B54268002A2ED0C368002B2BD00368048A591C01601B78013A13F0800F817C42601DBF03F0010242EA8403E3 | ||||
| :400AC0000231083114BF43F0020343EA0423817414BF03820382837C072BDCD9028A083B42FA03F38268511C81601370C368013BC360837C083B8374CDE710BD07B5827CB9 | ||||
| :400B000042B102AA002102F8011D026001224260FFF7C0FF03B05DF804FB30B543686BB3C2685AB3827C072A0CD8046890F91050611C01602178013B41EA052108320182EC | ||||
| :400B400043608274827C018AA2F108042141CBB2090608D5C3F3801363F07F03023A03F08103827402E08474002BD7D08268511C81601370C368013BC360CFE730BD00008E | ||||
| :400B8000F8B572B6644B61221A70A3F5F06301221A80192406229C7083F88022522203F5C0731A705D4B5E4A1B785E4EDBB2137040F618025C4B00251A8041F2512223F82F | ||||
| :400BC000022C33784FF4F07003F0010343EA450501F0F2FD013C05F0030521D0032DF0D1524B4FF480721A8007221A70504A002448211470917002221C705C7103F8032C9D | ||||
| :400C00004C4A4D4D1378062643F001031370424B01221A70494A137843F02003137000E0FEE706FB045300219A881868013401F02BFE072CF5D14248424D002450F8041F12 | ||||
| :400C400004F1105303F14A0221F0FF064B33C9B20B4452005B0002329A4206D012F8027C12F801EC07F806E0F5E7A8420C44E5D1354A00231360936013619361334B344950 | ||||
| :400C80001A68344B344C1A60344B1A68344B1A60344A137843F002031370137C43F002031374314B1A7842F040021A700A7842F010020A702D4A07CA03C42D49228008684A | ||||
| :400CC0002C4A28341060097911712B4A07CA03C422802A4AE83C07CA03C42280284A083407CA03C4274922800A78A4F6785442F008020A70244A01F5AA5112780C31D2B28D | ||||
| :400D000002F00700120908704A70204A442111700FCB07C42380F8BD004800400F010049A146004025420040224200400440004006400040A243004057320000E8460040A7 | ||||
| :400D4000FCFFFF4790000048007600403C0C0048C243004020760040C0510040400C00482876004003500140A0430040040C0048100C0048CB510040180C0048240C004883 | ||||
| :400D8000300C004822430040CF0100497658004008B501F04DFD03680C2B00D1FEE7FEE7084908B50B68084A1844821A802A01DC086005E001F03CFD0C2303604FF0FF33E2 | ||||
| :400DC000184608BDCC80FF1F2087FF1F80B51148114B0025C0B1A3F1100192C922460439161BB74204D051F8046F42F8046BF7E7114653F8046C8C1AA64202D041F8045B31 | ||||
| :400E0000F9E701381033E5E701F018FDFFF768FAFEE700BF0100000014340000124A134B10B51A60124A134C1368134843F4007313600023032B98BF54F823204FEA8301A4 | ||||
| :400E400088BF0E4A0133302B4250F3D10C4B1A780C4B1A700C4B084A1A60FFF791FEBDE8104001F029BA00BF0004FA050CED00E014ED00E0000000000080FF1F910D0000FB | ||||
| :400E8000BC760040C080FF1F08ED00E0F8B501F09BFC4B4A01271378022643F001031370137C484C43F001031374474B02F5E3521F700B3203F8946C1378054603F07F037D | ||||
| :400EC0001370002001F026FB2378404A03F0F90323701378384603F0DF03137023783B43237001F017FB282001F014FB384B30461A7802F07F021A701A7802F0BF021A70E7 | ||||
| :400F000023783343237001F005FB2378314A43F0040323700023137053702F4AFF2199540133092BFBD1284601F052FC0721172001F038FB2949172001F026FB07211820CB | ||||
| :400F400001F030FB2649182001F01EFB0721152001F028FB2349152001F016FB0721032001F020FB2049032001F00EFB0721042001F018FB1D49042001F006FB072105209A | ||||
| :400F800001F010FB1A49052001F0FEFA0721062001F008FB1749062001F0F6FA0021162001F000FB1449162001F0EEFA07210C2001F0F8FABDE8F84010490C2001F0E4BA44 | ||||
| :400FC000A5430040944300409D60004012600040F8510040846000406186FF1F5B18000095160000591800008D170000B9170000E91700002118000061180000D51800006F | ||||
| :40100000214B224A10B5187000231370204A40201370204A0F2413701F4A13701F4A13701F4A13701F4A13701F4B4FF400021A604FF080721A604FF400121A6008221A6081 | ||||
| :4010400010221A6020221A601860184804704FF480001860164B1A70933B19B91A7802F0FE0202E01A7842F001021A70114B03221A70802203F8202C012001F09DFB0E4B48 | ||||
| :4010800004221A7010BD00BF7C86FF1F8286FF1F8086FF1F8186FF1F7D86FF1F6C86FF1F7F86FF1FF486FF1F00E100E09E6000409C600040286000401260004070B5074C4C | ||||
| :4010C000054623780E461BB9FFF7E0FE0123237031462846BDE87040FFF792BF3186FF1F0A4A002313700A4A13700A4A13700A4A13700A4A13700A4A13700A4A13700A4BA8 | ||||
| :4011000003221A70802203F8202C70478286FF1F8086FF1F8186FF1F7D86FF1F6C86FF1F7F86FF1FF486FF1F28600040014B1878704700BF8186FF1F044B1A7802F0FF00F4 | ||||
| :401140001AB118780022C0B21A7070478086FF1F024A0C2303FB0020407870478886FF1F431E072B0CD8074A064B00010344805C5B7800F00F0043EA0020023880B2704768 | ||||
| :4011800000207047FC5F00401A4A38B50C2303FB00231B79090C13F0800F00F1FF35044619BF8AB24FF480438BB24FF48042032D18D8DFE805F002070C110021084601F0B4 | ||||
| :4011C00057F80DE00021084601F036F808E00021084601F015F803E00021084600F0F4FF054B1855EDB2072D03D801F029F9034B185538BD8886FF1F5886FF1F6186FF1F40 | ||||
| :40120000431E072B2DE9F0470446894615465CD82F4F0C2202FB0072D388DFF8B8A09BB2C3F500739D424FF00C0303FB007388BFD588DB7884BFC5F50075ADB2254A43EA07 | ||||
| :4012400015230601B354B244EBB28AF80130224B1A5C9846FF2A01D1FFF796FF0C2303FB047200215170B9F1000F28D03DB31B4F385D01F04DF811232946FE2218F8040069 | ||||
| :4012800001F012F906F5C04278321FFA89F118F8040001F01BF9124D18F80410385D01F087F80121385D01F01DF8735D43F002037355735D03F0FD037355BDE8F08703FB25 | ||||
| :4012C00004746379DBB28AF80230BDE8F08700BF8886FF1FFC5F00406186FF1F5886FF1F706000402DE9F047044615468846002940D0431E072B3FD8FFF732FFA84203D21D | ||||
| :401300002046FFF72DFF05461D4E335DFF2B03D141462046FFF738FFDFF868A027011AF8040000F0F5FF1223FE222946305D01F0BBF807F5C0411FFA88F27831305D01F01A | ||||
| :40134000C5F8DFF84490315D1AF8040001F030F801211AF8040000F0C5FF17F8093043F0020307F8093017F8093003F0FD0307F8093002E00D4600E000252846BDE8F0876D | ||||
| :401380006186FF1F5886FF1F70600040431E072B0AD8064A0C2303FB002300225A705A79034BD2B200011A54704700BF8886FF1FFE5F0040431E072B9FBF024B000108225F | ||||
| :4013C0001A547047FE5F004030B51A4A1A491B4D0878138803449BB21380194A00231488D8B2A4B27CB1082B0CD050680078C0B2E85450680133013050601088013880B2E9 | ||||
| :401400001080ECE718460B780E4C082B0E4A00D040B10E4D2B7883F080032B700F232370022301E0022323701370094B1870087030BD00BFF886FF1FF486FF1F0060004059 | ||||
| :401440007086FF1F6D86FF1F8286FF1F7E86FF1FF586FF1F074B02221A70074B80221A70064B0F221A70064A00231370054A0120137070478286FF1F7E86FF1F6D86FF1FE3 | ||||
| :40148000F486FF1FF586FF1F30B5164B16491B780A8803F00F03023BDBB21A4492B20A80124C134A0020118889B279B173B15568215C013BC9B229705168DBB20131516086 | ||||
| :4014C00011880130013989B21180ECE7094A1370094A137883F080031370084B0B221A7030BD00BF29600040F886FF1F006000407086FF1FF586FF1F7E86FF1F6D86FF1F81 | ||||
| :40150000064A06231370064A01201370054B80221A70054B00221A70704700BF8286FF1F6D86FF1F7E86FF1FF586FF1F054B9A683AB19A68044910709A6809885180002249 | ||||
| :401540009A6070477086FF1FF886FF1F08B5124B1A78D2B21A701B78DBB21A0602D50F4A137008BD0220FFF7E1FF0D4B1B7803F06003202B05D0402B06D043B900F012FC04 | ||||
| :4015800004E001F029F901E000F046FD10B9034B03221A7008BD00BF286000406D86FF1F0060004008B5084A084B0120197813880B449BB21380064B00221A70FFF7B6FFD7 | ||||
| :4015C000044B03221A7008BDF886FF1FF486FF1F8286FF1F6D86FF1F08B50C4B1B78DBB2042B07D0062B09D0022B0DD1BDE80840FFF7D8BFBDE80840FFF746BF0320FFF7F3 | ||||
| :4016000095FF034B03221A7008BD00BF8286FF1F6D86FF1F08B5054B002201201A70FFF785FF034B03221A7008BD00BF8286FF1F6D86FF1F08B50A4B1A7832B11A780949E7 | ||||
| :4016400042F080020A7000221A70074B002201201A70FFF76BFF054B03221A7008BD00BF6C86FF1F086000408286FF1F6D86FF1F074B1B78DBB2042B05D0062B05D0022BF6 | ||||
| :4016800005D1FFF7A1BEFFF7C5BFFFF7D3BF70478286FF1F38B51D4C2378DBB2DD0634D518060AD503F00F03012B2ED1FFF74EFF174B1B78190609D538BD5A0602D5FFF732 | ||||
| :4016C000D7FF03E09D0620D5FFF786FF23781B061BD4104B1A78104B1B7813430F4A13701278934211D10A4A0849154613782078DBB2000605D41378DBB20B700B7803F08D | ||||
| :401700000F0328788342F1D138BD38BD286000406D86FF1F7E86FF1FF586FF1F29600040054A00231380054A916819B191680B7092685380704700BFF886FF1F7086FF1FAB | ||||
| :401740000E4808B503889BB213B9FFF783FE13E00B4B02221A700B4B00221A70FFF7E0FF094AD1799379028843EA012392B2934238BF0380FFF728FE012008BD7086FF1F40 | ||||
| :401780008286FF1F7E86FF1F00600040084B01221A700F3B9B7C074B1A7B02F00302012A1EBFDA7B82F08002DA7301225A7370470B6000408886FF1F094B02221A700F3B9A | ||||
| :4017C00093F82230074B1A7E02F00302012A1EBFDA7E82F08002DA7601225A76704700BF0B6000408886FF1F0B4B04221A700F3B93F83230094B93F8242002F00302012AC5 | ||||
| :401800001EBF93F8272082F0800283F82720012283F82520704700BF0B6000408886FF1F0B4B08221A700F3B93F84230094B93F8302002F00302012A1EBF93F8332082F044 | ||||
| :40184000800283F83320012283F83120704700BF0B6000408886FF1F7047FFF741BC0000F0B5184B184E19780C27C9B201234FF0000C31B3CA0720D5144A4FEA031E7244FE | ||||
| :40188000947850782040C5070DD507FB03652C79240608D5147804F0FE0414706D790C4CEDB204F80E50840706D507FB036425792D0658BF84F801C090700133DBB24908ED | ||||
| :4018C000D7E7F0BD9F6000408886FF1F70600040FE5F004000F0E8BC70B50446184B88B003AA03F11006154618685968083303C5B3422A46F7D11B782B70FCB12223237091 | ||||
| :4019000001AD03232846637000F0C6FE002220461146AB5C08AC04EB131414F8144C03F00F03847008AC234413F8143C0132082AC1700371417100F10400EAD108B070BD02 | ||||
| :40194000813200002DE9F0431C4D01222E460C201F274FF0800E4FF0080C194B00FB02581401234418705F70164998F805902144B9F1000F07D098F8044024064CBF8870D3 | ||||
| :4019800081F802C001E081F802E000FB0261CC880132E4B29C71CC88092AC4F30724DC71CC88E4B21C71C988C1F307215971D4D1054BFF221A70BDE8F08300BF8886FF1F61 | ||||
| :4019C00070600040FC5F00400A600040064B074A1B7802EBC30253681A7C824286BF03EBC0035869002070477C86FF1FD03200002DE9F84F424B1A78002A7ED01878414DD4 | ||||
| :401A00000138C0B2FFF7E2FFA8463F4AC3681478007ADFF800C1E4B203EBC0000C2600274FF0010E834268D01A78A24263D11CF80420597891425ED19A7893F8039002F025 | ||||
| :401A40007F0206FB02FA05EB0A01CF7093F802B009F0030981F804B093F803B005F80AB0B3F804A0A1F808A093F902A0BAF1000F0BDAB9F1010F0CBF4FF007094FF00D09C4 | ||||
| :401A800081F8059081F801E009E0B9F1010F0CBF4FF005094FF0090981F805904F704FEA02191A4906FB0282494481F802E0B2F808A0CAF3072A81F800A0B2F808A05FFABD | ||||
| :401AC0008AFA81F801A0B2F806A011495FFA8AFA494481F806A0B2F80690C9F3072981F80790B2F806905FFA89F981F80490D288C2F307224A71083394E7BDE8F88F00BF1D | ||||
| :401B00008186FF1F8886FF1F7D86FF1FFC5F0040706000406E86FF1F08B5064B18780138C0B2FFF753FF20B143681B7900EBC300406908BD8186FF1F00212DE9F84F0B46C5 | ||||
| :401B40004E4E0C2707FB01F401313219092933554FF000059370494CD3701381937253705371EFD118B1464B1D70464B1D70464B1A78002A7FD0187801250138C0B2FFF771 | ||||
| :401B800025FFA8464368DFF8F8E0DB790C2713F0400F3E4B4FF0000C1A7814BF42F0010202F0FE021A70027AD20007FB0541C36803EB02094B4531D093F802A00AF07F06FF | ||||
| :401BC000AE4229D10E89B3F804B0B6B25E4538BFA1F808B01E7893F801B01EF80660B3451AD181F804A0DE780E7093F902A0DE78BAF1000F06F0030607DA012E0CBF07264B | ||||
| :401C00000D264E7181F8018006E0012E0CBF052609264E7181F801C00833CBE70135092DC3D1C1680A328B1C0A440C200833934209D013F8081C13F80A5C01F07F0100FB1D | ||||
| :401C400001418D72F2E7FFF767FF114B0121186000230C2000FB0142D3801289013113449BB203F00102134409299BB2F2D1BDE8F84FFFF767BEBDE8F88F00BF8886FF1FFA | ||||
| :401C80006E86FF1FF686FF1F8186FF1F7F86FF1F8486FF1F114B1B7903F07F035A1E072A19D80F490C2202FB031291781B0141F0010191700021D170517841F002015170F8 | ||||
| :401CC000127912F0800F074A1A4414BF8D2389239370FFF715BC0020704700BF006000408886FF1FFC5F004030B4194B1A7902F07F02531E072B27D8164B0C2404FB02336E | ||||
| :401D00009978154D01F0FE0199700021D97029461201505D114400F07F0050555A7802F0FD025A701A795B78120605D5012B01D18C7006E00D2303E0012B0CBF082309230F | ||||
| :401D40008B7030BCFFF7DCBB002030BC704700BF006000408886FF1FFC5F004010B50D4B0D4C21791878C9B20138C0B2FFF72EFE43681B798B4201D2012909D8074A084893 | ||||
| :401D8000535CDBB24354A3780120DBB2535410BD002010BD8186FF1F006000406E86FF1FF686FF1F38B58A4A8A4C13780021DBB221801806517840F18D800A2900F2058174 | ||||
| :401DC000DFE811F05D00030103010301030103010B0003017E0003018200D3787C49012B09D17D4B1A787D4B03EBC2035B685B686360122310E0CB78022B12D18878FFF7F5 | ||||
| :401E0000E5FD002800F0E180436863606368DA7863689B7843EA02232380BDE83840FFF78FBCCB78032B26D16D4B00228878D5B2854209D3664A91786A4AEE2908BF13467B | ||||
| :401E4000634A917881B106E0187801320028F1D018780344EAE764499278097C914203D16248FFF739FD614B1A78002A00F0AD801A78228018E0BDE8384000F0ADBC13F05D | ||||
| :401E8000030313D0022B40F0A0802380504B0C211B7903F07F02564B01FB02339A78554BD2B21A7000225A706360B6E702222280514A11784F4AC9B2117053706260ACE7D4 | ||||
| :401EC000012323804D4BEFE70123238013794C4A1344E9E701390A2977D8DFE801F037764F76067676760A7620009378454ADBB25AE0937803F0FF0153B9404B1A78914254 | ||||
| :401F00005FD01970404B01201870FFF715FE58E0481EC0B2FFF75AFD0028EED155E0FFF71DFF002851D02A4A384913791279DBB2D2B20A70364A3249D25CCB5C9A4240D005 | ||||
| :401F4000314B01221A70FFF753FD3AE003F00303012B2BD009D3022B37D11D4B9B78002B33D1BDE83840FFF7BFBE194B9B78012B2BD1214A137803F0FD0315E003F00303F7 | ||||
| :401F8000012B13D008D3022B1FD1114B9B78E3B9BDE83840FFF77EBE0D4B9B78012B14D1154A137843F0020313700AE0084B1A795AB998781B791749DBB2CA5C22EA0002F7 | ||||
| :401FC000CA54BDE83840FFF79BBA002038BD00BF006000407086FF1F7C86FF1FD032000034330000BC320000A7330000FA86FF1F8886FF1F3286FF1F7F86FF1F8186FF1F9A | ||||
| :402000006E86FF1F6C86FF1F8086FF1F7D86FF1FF686FF1F8386FF1F074B1A78120609D55B78012B06D1054B054A5A6012781A80FFF786BB00207047006000407086FF1F89 | ||||
| :4020400094320000014B1870704700BF77650040014B1878704700BF69650040014B1870704700BF7D640040074A0223136002F688321268E0215064044A11706FF44071BC | ||||
| :402080000A441360704700BF80E100E001E400E0014B1870704700BF7764004073B515461E460B4C04230022019200920A4601461846237000F0A4F932462946207800F04E | ||||
| :4020C0005FF90221207800F049F9207802B070BDD080FF1F064A0123136002F688321268E0211064034A1170A2F540721360704780E100E000E400E0014B1870704700BF9E | ||||
| :402100007B64004073B515461E460B4C05230022019200920A4601461846237000F070F932462946207800F02BF90221207800F015F9207802B070BDD180FF1F064A042349 | ||||
| :40214000136002F688321268E0219064034A1170A2F202321360704780E100E002E400E0014B04221A60704700E100E0014B04221A60704780E100E0014B1870704700BF72 | ||||
| :402180007E640040014B1870704700BF76640040014B1870704700BF7C640040704738B505460078012428B100F0AEFA285D0134E4B2F8E738BD08B50D2000F0A5FABDE8F0 | ||||
| :4021C00008400A2000F0A0BAF7B516461F460B4C00230325019300930A4601462846257000F00EF93A463146207800F0C9F80221207800F0B3F8207803B0F0BDE080FF1F50 | ||||
| :40220000F7B516461F460B4C00230225019300930A4601462846257000F0F2F83A463146207800F0ADF82946207800F097F8207803B0F0BDE180FF1FF7B516461F460B4C10 | ||||
| :4022400000230125019300930A4601462846257000F0D6F83A463146207800F091F80221207800F07BF8207803B0F0BDE280FF1F73B515461E460B4C0023019300930A4620 | ||||
| :4022800001461846237000F0BBF832462946207800F076F80221207800F060F8207802B070BD00BFE380FF1F024B1878C0F38010704700BF8F450040074A7F2380211370EB | ||||
| :4022C0005170064A013BDBB202F80839002BF9D1034A1370704700BFE480FF1FF87B00400078004017280FD8084B0001C25C11B142F0200201E002F0DF02C254C25C42F0D9 | ||||
| :402300000102C25400207047012070471070004017280BD8064B0001C25C02F0FE02C254C25C02F0DF02C25400207047012070471070004017280DD8074900010B460344F8 | ||||
| :402340001A7942F004021A71435C43F00103435400207047012070471070004017280BD8064A0001835C490003F0F10301F00E011943815400207047012070471070004009 | ||||
| :4023800041F6FF73994208BF4FF400519A4208BF4FF4005217289FBFC00000F1804000F5EC4081809ABFC280002001207047000017289FBF034B00011954002088BF012062 | ||||
| :4023C000704700BF1970004017289FBF054B00011A5C01F007019DBF1143195400200120704700BF1470004017289FBF034B0001185C00F0070088BFFF2070471470004071 | ||||
| :40240000172810B51AD8C00001F07F0100F1804441EAC21204F5EC44D2B222709DF8082003F00F0343EA0213DBB263709DF80C30002003F00F03A370E07010BD012010BD0A | ||||
| :4024400010B500F0C1F90A4A5378182B0AD91478013B5370E30003F1804303F5F0431B78137000E0FF2400F0B3F9204610BD00BFE480FF1F030610B5044611D400F0A4F9A5 | ||||
| :40248000084AE300117803F1804303F5F04319705378147001335370BDE8104000F098B910BD00BFE480FF1F30B504060CD411F4704509D1C40004F1804404F5F0442180BB | ||||
| :4024C000A270E370284630BD012030BD03065FBFC00000F1804000F5F04081805ABFC280002001207047000038B50446084DB4F5004F05D9286800F05FF9A4F50044F6E709 | ||||
| :40250000034B58686043BDE8384000F055B900BFEC80FF1F024B1B7A584300F04DB900BFEC80FF1F0E4B00F003001A78490102F0FC02104318701A7801F0600142F080023F | ||||
| :402540001A701A7802F07F021A701A7802F09F020A431A701A7842F010021A70704700BF83430040014B01221A70704784430040044B00F00F021B6853F8220043F8221006 | ||||
| :40258000704700BF08ED00E0054A00F01F00126800F1100352F8230042F82310704700BF08ED00E000F01F0000F16040490100F56440C9B2017070470F4B10B50F4900240E | ||||
| :4025C0000F205C609C60DC601C615C61FFF7D0FF0B4A136843F0040313600A4B4FF47A72DB68B3FBF2F3084A1360084B4FF400421C60C3F8E82010BD3486FF1F65260000D6 | ||||
| :4026000010E000E0EC80FF1F14E000E018E000E0024A136843F002031360704710E000E008B5FFF7F5FF034A136843F00103136008BD00BF10E000E010B5054CA3691BB938 | ||||
| :40264000FFF7BAFF0123A361BDE81040FFF7E8BF3486FF1F024B1868C0F30040704700BF10E000E038B5FFF7F5FF012808D1054D002455F8243003B198470134052CF8D161 | ||||
| :4026800038BD00BF3886FF1F024B03EB80035868596070473486FF1F134B144A1B78DBB20360127843EA0223114A0360127843EA0243104A0360127843EA026303600E4B5A | ||||
| :4026C0000E4A1B78DBB24360127843EA02230C4A4360127843EA02430A4A4360127843EA02634360704700BF0301004904010049EC460040020100490101004900010049D4 | ||||
| :402700000501004906010049FEB5494652465B460EB40746244909688A46244A12682448022100F071F8030020480068C018204900F06AF8143883460121C9430C460125D1 | ||||
| :40274000002600F041F8814651460B7823400B705846013000F030F83800F04028400B78234003430B70584600F026F80136072EF2D9002001300138013001200B78234048 | ||||
| :4027800003430B705846043000F016F8484600F01FF800BF00BF00BF0EBC894692469B46FEBD00BFAFF30080D480FF1FF880FF1F00C20100000000000230800803D000BFB1 | ||||
| :4027C00001380046FCD17047EFF3108072B6704780F31088704700BF094A137803F00303012B0AD0022B09D113790C2103F07F02044B01FB02339B7A00E01379002070471B | ||||
| :40280000006000408886FF1F002902D0B0FBF1F0704708B14FF0FF3000F008B80029F8D00246B0FBF1F000FB11217047704700BF014B1868704700BF5C81FF1F0E4B70B5DD | ||||
| :402840001E460E4C0025E41AA410A54204D056F8253098470135F8E700F0C2FD084B094C1E46E41AA4100025A54204D056F8253098470135F8E770BDEC330000EC33000022 | ||||
| :40288000EC330000F433000003460244934202D003F8011BFAE7704730B5141E05469BB0184604DA8B232B604FF0FF301DE04FF40273ADF80C300CBF234604F1FF330293D7 | ||||
| :4028C00005934FF6FF7300910491ADF80E3002461E9B6946284600F073F8431CBCBF8B232B6014B1009B00221A701BB030BD000007B5009313460A46014603480068FFF748 | ||||
| :40290000CBFF03B05DF804FB5C81FF1F2DE9F0478E6882469E420C46914698463ED88A8912F4906F3AD02568096902236F1A656905EB450595FBF3F57B1C43449D4238BF80 | ||||
| :402940001D4653050FD5294600F04AFB064698B13A46216900F0D2FAA38923F4906343F08003A38113E02A4600F098FB064670B92169504600F0E8FA0C23CAF80030A3890F | ||||
| :402980004FF0FF3043F04003A381BDE8F08726613E44266046466561ED1BA560464528BF464649463246206800F0B3FAA36800209B1BA36023681E442660BDE8F087000068 | ||||
| :4029C0002DE9F04F9DB003938B8980461C060D4616460DD50B695BB9402100F001FB2860286118B90C23C8F80030CDE040236B610023099320238DF82930DFF89CB1302309 | ||||
| :402A00008DF82A3037463C4614F8013B1BB9B7EB060910D003E0252BF9D02746F3E74B46324629464046FFF771FF013000F0A780099B4B4409933B78002B00F0A08000233C | ||||
| :402A40004FF0FF3204930793059206938DF853301A930126052221784E4800F041FA671C049B38B14B4A3C46801A06FA00F018430490EFE7D90644BF20228DF853201A077A | ||||
| :402A800044BF2B228DF8532022782A2A03D0079A00210A200BE0039A111D12680391002A10DA524243F00200079204900BE027463B780134303B092B03D800FB0232012148 | ||||
| :402AC000F5E701B107923B782E2B1ED17B782A2B0AD1039B02371A1D1B680392002BB8BF4FF0FF33059310E0002319460593781C0A2407463A780130303A092A03D804FB4D | ||||
| :402B000001210123F5E703B1059103223978224800F0E6F940B14023CBEB000003FA00F0049B013718430490397806221B487E1C8DF8281000F0D4F988B1194B33B9039BE6 | ||||
| :402B4000073323F007030833039314E003AB00932A46144B04A94046AFF3008007E003AB00932A460F4B04A9404600F093F8B0F1FF3F824603D0099B5344099342E7AB8986 | ||||
| :402B80005B0601D4099801E04FF0FF301DB0BDE8F08F00BFBB330000C1330000C5330000000000000D2900002DE9F04791461F460A698B6806469342B8BF1346C9F800305E | ||||
| :402BC00091F843200C46DDF8208012B10133C9F800302368990642BFD9F800300233C9F80030256815F0060510D104F1190A07E00123524639463046C04701301AD0013562 | ||||
| :402C0000E368D9F800209B1A9D42F1DB94F843302268003318BF012392060FD5E118302081F843005A1C94F845102244023382F8431003E04FF0FF30BDE8F08704F143025A | ||||
| :402C400039463046C0470130F4D02268D9F80050E36802F00602042A08BF5D1B2269A3680CBF25EAE57500259342C4BF9B1AED184FF000091A344D4509D0012322463946F9 | ||||
| :402C80003046C0470130D5D009F10109F3E70020BDE8F0872DE9F04317460A7E85B06E2A984606460C460C9B01F1430E00F0AE8011D8632A22D009D8002A00F0BB80582A08 | ||||
| :402CC00040F0CA8081F84520834955E0642A1ED0692A1CD0C0E0732A00F0B08009D86F2A2ED0702A40F0B8800A6842F020020A603EE0752A24D0782A3AD0ADE01A6801F11B | ||||
| :402D00004205111D1960136884F84230A8E021681A6811F0800F02D0111D196008E011F0400F02F10401196002D0B2F9003000E01368002B3CDA2D225B4284F8432037E0CC | ||||
| :402D400021681A6811F0800F02D0111D196007E011F0400F02F10401196001D0138800E01368227E5C496F2A14BF0A2208221BE078225A4984F845202268186812F0800F15 | ||||
| :402D800000F104051D6003D1550601D5038800E00368D00744BF42F0200222601BB9226822F0200222601022002084F8430001E049490A226568002DA56008DB206820F0D3 | ||||
| :402DC000040020602BB9002D7DD175460CE0002B79D07546B3FBF2F002FB1033CB5C05F8013D03460028F5D1082A0BD12368DA0708D5236962689A42DEBF302305F8013CFE | ||||
| :402E000005F1FF35C5EB0E0323612EE008681A6810F0800F496903D0101D1860136808E010F0400F02F104001860136801D0198000E0196000232361754616E01A68111D03 | ||||
| :402E40001960156800216268284600F049F808B1401B6060636804E004F1420584F8422001232361002384F84330CDF800803B4603AA21463046FFF797FE013002D14FF05D | ||||
| :402E8000FF3026E023692A4639463046C0470130F5D023689B0710D5002504F1190907E001234A4639463046C0470130E7D00135E368039A9B1A9D42F2DBE068039B9842E3 | ||||
| :402EC000B8BF184605E00B7804F1420584F842308AE705B0BDE8F08381320000CC33000010B5C9B202449042034605D01C7801308C42F8D1184610BD002010BD10B5431E6B | ||||
| :402F00000A44914204D011F8014B03F8014FF8E710BD884210B501EB020301D8421E0BE09842FBD28118D21AD34204D013F8014D01F8014DF8E710BD994204D011F8014B47 | ||||
| :402F400002F8014FF8E710BD38B50546002944D051F8043C0C1F002BB8BFE41800F0D4F81E4A1368114613B96360146030E0A3420DD92268A018834201BF18685B6812188C | ||||
| :402F8000226063600C6023E0A24203D813465A68002AF9D118681918A1420BD12168014458188242196013D110685268014419605A600DE002D90C232B6009E021686018AA | ||||
| :402FC000824201BF106852680918216062605C602846BDE8384000F098B838BD5486FF1F70B5CD1C25F0030508350C2D38BF0C25002D064601DBA94202D90C23336046E077 | ||||
| :4030000000F082F8234B1C681A462146A1B10B685B1B0ED40B2B03D90B60CC18CD501EE08C420BBF63684B681360636018BF0C4615E00C464968E9E7174C23681BB930465F | ||||
| :4030400000F052F820602946304600F04DF8431C18D0C41C24F00304A0420DD12560304600F053F804F10B00231D20F00700C31A0ED05A42E25070BD211A304600F034F86A | ||||
| :403080000130EBD10C233360304600F03EF8002070BD00BF5486FF1F5086FF1FF8B5074615460E4621B91146BDE8F840FFF798BF1AB9FFF749FF2846F8BD00F027F88542BF | ||||
| :4030C0000ED929463846FFF78BFF044650B131462A46FFF713FF31463846FFF735FF01E03046F8BD2046F8BD38B5064C0023054608462360FDF754FE431C02D1236803B1C7 | ||||
| :403100002B6038BD1C87FF1F7047704751F8040C0028BEBF091851F8043CC0180438704700000000050209020B020D020F02110213027265706C79203078253032780068AB | ||||
| :403140006F6D696E6700626567696E6E696E67207365656B2066726F6D20256420746F20256400756E65787065637465646C7920646574656374656420747261636B203092 | ||||
| :403180000066696E6973686564207365656B0057616974696E6720666F72205553422E2E2E0055534220726561647900636F6D6D616E642030782530327800756E6465724C | ||||
| :4031C00072756E206166746572202564207061636B65747300636F756E743D256420693D256420643D2564207A7A3D256400636D645F777269746500703D25642063723D0C | ||||
| :4032000025642063773D256420663D256420773D256420696E6465783D256420756E64657272756E3D25640077726974652066696E6973686564007374617274206572612A | ||||
| :4032400073696E670073746F702065726173696E670069646C650000510040100030510040400000000140001000140140000800400140000A004C01400002005001402015 | ||||
| :40328000003031323334353637383941424344454600000028000000000104000100000000000000000157494E5553420000303030303100000000000000000012034D0012 | ||||
| :4032C0005300460054003100300030000100000001000000D832000001000000A7330000000000000000000001000000F03200000100000079330000040000001233000050 | ||||
| :4033000000000000000000000000000010330000FF00000001024000FF00000082024000FF00000003034000FF00000084034000FF00020304030904160346006C007500E2 | ||||
| :40334000780045006E00670069006E0065002A0343006F0077006C00610072006B00200054006500630068006E006F006C006F0067006900650073000009022E0001010040 | ||||
| :4033800080320904000004FF00000107050102400000070582024000000705030340000A0705840340000A12010002FF0001080912006E0100020180014300232D302B20B9 | ||||
| :4033C00000686C4C00656667454647003031323334353637383961626364656600000000F8B500BFF8BC08BC9E467047590000001D0E0000F8B500BFF8BC08BC9E467047C5 | ||||
| :403400003500000018340000C880FF1F98000000C005000000000000000000002087FF1FFFFF0000675000400C00000007000000FFFFFFFF7F8000003F0000000000007DC4 | ||||
| :4034400000FA0000400000000090D0030000000000000000000000000000000000000000000000000000000000000000B933000000000000000000000000000000000000C3 | ||||
| :403480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FC80FF1F0000000000000000000000000000000072 | ||||
| :4034C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000CC | ||||
| :40350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008B | ||||
| :40354000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004B | ||||
| :40358000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B | ||||
| :4035C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000CB | ||||
| :40360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008A | ||||
| :40364000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004A | ||||
| :40368000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A | ||||
| :4036C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000CA | ||||
| :403700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089 | ||||
| :403740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000049 | ||||
| :403780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009 | ||||
| :4037C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C9 | ||||
| :403800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000088 | ||||
| :403840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000048 | ||||
| :403880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008 | ||||
| :4038C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C8 | ||||
| :403900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087 | ||||
| :403940000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047 | ||||
| :403980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007 | ||||
| :4039C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C7 | ||||
| :403A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086 | ||||
| :403A40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046 | ||||
| :403A80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006 | ||||
| :403AC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C6 | ||||
| :403B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000085 | ||||
| :403B40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045 | ||||
| :403B80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005 | ||||
| :403BC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C5 | ||||
| :403C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084 | ||||
| :403C40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044 | ||||
| :403C80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004 | ||||
| :403CC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C4 | ||||
| :403D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083 | ||||
| :403D40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043 | ||||
| :403D80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 | ||||
| :403DC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C3 | ||||
| :403E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082 | ||||
| :403E40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042 | ||||
| :403E80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002 | ||||
| :4000000000800020110000006512000065120000064A08B5136843F020031360044B1A6803F53F5302331A6001F03AF9E8460040FA46004010B5054C237833B9044B13B104 | ||||
| :400040000448AFF300800123237010BD6881FF1F00000000E03A0000084B10B51BB108490848AFF300800848036803B910BD074B002BFBD0BDE81040184700BF0000000027 | ||||
| :400080006C81FF1FE03A0000C880FF1F000000000A4A0B4B116801310B40002BBEBF03F1FF3363F03F030133136011685368994202BF024B01221A72704700BF8881FF1FA2 | ||||
| :4000C0003F0000800A4A0B4B516801310B40002BBEBF03F1FF3363F03F030133536051681368994202BF024B01221A72704700BF8881FF1F3F000080024B012200205A7293 | ||||
| :4001000002F074BA8881FF1F10B5C4B2204601F089FA0128FAD110BD08B572B60F4B0F49DA680132DA601A690132C82A08BF00221A615A6918690132A72A08BF00224A6174 | ||||
| :400140005B69002B0CBF02230023002814BF184643F0010002F0B2FF62B608BD8881FF1F38B50446C5B2284602F0E2F9062002F0FFFB44F00200C0B202F0DAF9062002F0C9 | ||||
| :40018000F7FB284602F0D4F9BDE83840062002F0D9BB10B5642402F0C5F930B90120FFF7DFFF013CF7D1204610BD012010BD70B5C4B220460E4601F03DFA314605460246CF | ||||
| :4001C000204601F0F9FA204601F02CFA0128FAD0284670BD38B5044D0024285D013402F077FB402CF9D138BDA081FF1F08B502F091FD002002F09AFD02F0ACFD02F0B6FD9A | ||||
| :4002000080B208BD10B50446012002F0A9F9642002F098FBFFF7EAFF2080002002F0A0F9642002F08FFBFFF7E1FF608010BD08B502F09CFE002002F0A5FE02F0B7FE02F0B6 | ||||
| :40024000C1FE80B208BD10B50446FFF7A2FF322002F078FBFFF7EBFF20800020FFF780FF322002F06FFBFFF7E2FF608010BD0FB400B593B014AB53F8042B402102A8019391 | ||||
| :4002800003F016F802A802F0B8F902F0C2F913B05DF804EB04B0704710B5044601780648FFF7E5FF0420FFF72FFF62782146BDE81040042001F00EBAF43A000007B50023B9 | ||||
| :4002C000ADF804308DF80600032301A88DF80530FFF7E2FF03B05DF804FB000010B5074C94F8583043B1002002F016F9002002F0A9FE002384F8583010BD00BF8881FF1F5F | ||||
| :4003000038B5104D837895F85B2004469A4204D0FFF7E4FF002385F85E302368C5F859302279094B1A71A378002B14BF0220012002F088FEE07802F07FFE2079BDE83840D3 | ||||
| :4003400002F0B6BE8881FF1FE181FF1F38B50D4C94F8585065B904F15900FFF7D1FF012002F0DAF84FF47A7002F0ECFA84F85E50E3682366012384F85830BDE8384002F0A5 | ||||
| :400380001FBB00BF8881FF1FF8B51E4C0646FFF7DDFF94F85E3003B15EB91B48FFF767FFFFF7F7FE0120002384F85E00636602F0DFFA3246616E1548FFF759FF114D002790 | ||||
| :4003C000636E9E4216D002F0ADF800B16F66636E9E4205DD0020FFF7C3FE6B6E013305E005DA0120FFF7BCFE6B6E013B6B6602F0E7FAE5E7322002F0A5FABDE8F8400448AC | ||||
| :40040000FFF735BF8881FF1F013B0000083B0000253B00002DE9F04F9BB062B602F03AFB9C49042002F05EFB9B4802F087F89B4802F02AFE9A4802F0BBF802F00BFD02F0D5 | ||||
| :40044000DDFB0020974C02F0FDFD02F0D5F80221002001F09DF8002384F85B30FFF776FFFFF797FE84F86800FFF738FF012384F85B30FFF76BFFFFF78CFE84F86900FFF716 | ||||
| :400480002DFF894B94F86800884994F869202546002A14BF0A461A46002808BF19468448FFF7E5FE0321084602F06AFAA24602F087FA94F8583043B12A6EEB689B1A41F259 | ||||
| :4004C0008832934201D9FFF709FF01F099F818B97848FFF7CCFE04E001F098F80028F7D10BE001F08DF810B902F06AFAF9E77248FFF7BDFE032001F0B3F9032001F092F844 | ||||
| :400500000128D4D16D48FFF7FBFE6D490320FFF74EFE94F86A106B48FFF7A9FE94F86A30023B142B00F27684DFE813F0150074041E00740424007404480074046B0074041E | ||||
| :40054000D8007404FE017404AC037404CC037404D3037404ED0303238DF828308DF829300C238DF82A30CAE394F86C00FFF70CFF554BC1E3FFF7EAFE00236372E068627A35 | ||||
| :4005800002F0FF0132B9EB681B1AB3F57A7FF6DD0B460AE04BB100228AF80920DAF80C10627A12B9EB685B1AFAE707228DF8282004228DF82920ADF82A30A0E30220FFF79C | ||||
| :4005C000A3FD00270DF1280902F0FAF94FF480780026C8EB07039A1906F809200136402EF9D10220FFF790FD32464946022001F071F8B8F10108EBD10137402FE4D1334B49 | ||||
| :4006000042E04FF00109002702F0DAF94FF00008012001F025F9012001F004F80128FAD10DF1280B4022594601F0C6F8012000F0F9FF0028FAD1064608EB07030593059B8C | ||||
| :400640001BF806203344DBB2934209D08DE80C003946334642461E48FFF709FE4FF000090136402EEBD108F10108B8F5807FCFD10137402FC8D149461648FFF7F8FDB9F172 | ||||
| :40068000000F00F05981144B1B8809A8ADF8243036E300BF19010000F900000091000000C50000008881FF1F373B0000333B00003A3B0000523B0000653B0000E181FF1F4B | ||||
| :4006C000F281FF1F6F3B0000E43A0000E63A00007E3B00009A3B0000E83A000094F86C0001F03EFF606EFFF74FFE02F04DFD934B934F1A78002602F0FB021A701A7842F0A9 | ||||
| :4007000001021A701A7802F0FE021A701A7802F0FE021A7002F03CFD0220FFF7F5FC41F6FF734FF480420121022002F091FC84F8AA0002F0B3F8B8550136402EF9D1DFF855 | ||||
| :400740002082002608F1990B1FFA8BF70136402E14BF3246002218F8010F22440623127E402102F0CFF83A4646F2434198F8000002F0DAF84037402EBFB2E7D19AF86D3041 | ||||
| :4007800043B100238AF80930637A002BFCD000238AF80930182200210AA802F055FD694B4FF0FF320C9340230D930023236062602372236894F8AA002344197E02F026F8D2 | ||||
| :4007C00094F8AA0001F0E4FF012194F8AA0001F0B7FF2368002BFCD000239946CAF80430DAF80C200127059202F0EAF8059AE3689B1AB4F86E2093420ED36FB1042195F884 | ||||
| :40080000AA0002F00FF894F8AA0002F01BF80028F9D107468AF80800237A03F0FF08002B48D16A682B689A4202D1002FDCD141E063680AA80BEB831343440A93C8F14003FC | ||||
| :400840000B9300F001FB0B9B09F10109C3F1400398440D9B5FFA88F8E3B93B4E0220FFF753FCA6F1400EBEE80F000FC6BEE80F000FC6BEE80F000FC69EE80F0086E80F00CF | ||||
| :40088000A6F130014022022000F024FF703E40230C960D93B8F13F0FCAD962682B4B01321340002BBEBF03F1FF3363F03F030133636099E70AA8267A00F01CFB0220FFF7DB | ||||
| :4008C00023FC0D9BF6B2402B07D0022040221E4900F000FF0220FFF717FC0D9B022033F040021DBFC3F1400292B21749114600F0F1FE0220FFF708FCFFF76CFC36B11448AA | ||||
| :40090000FFF7B5FC0220FFF7D9FC06E0114B09A81B88ADF82430FFF7BFFC627A4946237A0D48FFF7A4FC78E20C48FFF7A0FCD4F86E6016F03F0615D003206CE2936400403E | ||||
| :40094000A081FF1F3892FF1F7892FF1F3F000080A43B0000EA3A0000BE3B0000D13B00009F81FF1F012001F001FE95F86C0001F0F7FD02F009FCB94BB94F1A7842F0040267 | ||||
| :400980001A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F0F9FB686EFFF7F2FC01214FF4804341F6FF72084601F0E2FD85F8AA0001F070FFB8550136E7 | ||||
| :4009C000402EF9D1DFF8B882002708F199039EB207930137402F14BF3A46002218F8010F22440523127E402101F08CFF314646F2475298F8000001F097FF4036402FB6B225 | ||||
| :400A0000E7D1DAF86E3000269B09182231464FF0FF3B0AA8CAF800600593CAF804B0B1468AF80860B04602F00FFC0D973746012000F016FF069601F0C3FFB8F1000F0AD1BB | ||||
| :400A40004EB9012000F0EEFD012804D14022854900F0B2FE06462268834B01321340002BBCBF03F1FF3363F03F036168B8BF01338B4200F09080069B3BB1237A002B40F054 | ||||
| :400A80009B806B7A002B40F097800B9BBBBBB8F1000F09D0754A7F2199540133402BFBD1724A0B930A922AE04EB3012000F0BAFD28BBDFF8B8E13F2E0EF1400CBCE80F00D9 | ||||
| :400AC000AEE80F00BCE80F00AEE80F00BCE80F00AEE80F009CE80F008EE80F00AEF130030A9307F101070B9607DD059BBB4204D0012000F0B5FE464601E04FF001080B9B05 | ||||
| :400B0000DBB12368079A0AA802EB83120D9BC3F1400313440C9300F0FCF90D9B6BB92A68514B01321340002BBEBF03F1FF3363F03F030133236040230D93636801332AD1B8 | ||||
| :400B40002B683F2B27D14FF0000BC5F804B001F041FD85F808B06B6895F8AA002B44197E01F054FE95F8AA0001F012FE012195F8AA0001F0E5FD85F809B0637A002BFCD0A0 | ||||
| :400B80004FF0000B01208AF809B001F02FFD584601F0ECFC01E0069B2BB1237A63B96B7A53B90123069363685B453FF444AF09F10109D5F804B03EE761682D482268FFF73D | ||||
| :400BC00056FB01F00DFD012001F0D0FC002001F00DFD042194F8AA0001F024FE94F8AA0001F030FE0028F9D19AF8AA0001F0BEFD9AF809309AF808200293012303920193AC | ||||
| :400C0000CDF800804B463A4605991A48FFF72FFBB8F1000F16D1059BBB420AD0012000F001FD01280646F6D10E49FFF7C0FA3F2803DC012000F028FE04E0304600F010FE01 | ||||
| :400C40000137E8E7FFF7C6FA0B48FFF710FB237A0BB10220DFE0094B16E500BF97650040A081FF1F7892FF1F3F0000803892FF1FDB3B0000E63B0000163C0000EC3A000022 | ||||
| :400C80009F81FF1F94F86C0001F06AFC606EFFF77BFB6648FFF7EBFA00236372637A002BFCD0012001F0A2FC00238AF80930637A002BFCD0002001F099FC5D48FFF7D7FAA4 | ||||
| :400CC0005C4B19E0002084F85E00FFF75DFB5A4B12E094F8683023B195F869200AB985F86C2094F869201AB113B9012385F86C305248FFF705FB524B1B88ADF828300AA833 | ||||
| :400D0000FFF7CAFA89E0FFF7E9FA02F021F9002002F0C4F82A2601F0EFFF002001F092FF324600210AA802F08FFA17238DF828308DF8296001F044FE002001F0EDFB0020D5 | ||||
| :400D400002F080F9C82001F0FDFD0DEB0600FFF759FA0DF13E00FFF776FA01F031FE012002F070F9322001F0EDFD0DF12E00FFF749FA0DF14200FFF766FA012001F0CCFBAF | ||||
| :400D80004FF4967001F0DEFD01F01AFE0DF13600FFF738FA0DF14A00FFF755FA002001F0BBFB4FF4967001F0CDFD01F009FE022002F048F9322001F0C5FD0DF13200FFF7E9 | ||||
| :400DC00021FA0DF14600FFF73EFA012001F0A4FB4FF4967001F0B6FD01F0F2FD0DF13A00FFF710FA0DF14E00FFF72DFA002001F093FB4FF4967001F0A5FD01F0E1FD0020DD | ||||
| :400E000002F020F9002384F85E3002F023F801F0F5FE74E70120FFF751FA032000F020FD0848FFF724FAFFF742BB00BF253C0000333C0000EE3A0000F03A0000F281FF1FD3 | ||||
| :400E4000F23A0000403C000070B5002401254268002A4ED0C368002B4BD00368013A591C01601B784260802B01D145752FE013F0800F467D0269017D12D036B1D20042F0F6 | ||||
| :400E800004020331026101754475026903F00103D20042F004021A43037D0261033315E046B13F2B06D9D20042F004020331026101754475026943EA0223427D036112B1DC | ||||
| :400EC00043F0C0030361037D447508330375037D072BBCD90269083B22FA03F38268511C81601370C368013BC360037D083B0375ADE770BD07B5027D42B102AA002102F86F | ||||
| :400F0000011D026001224260FFF79EFF03B05DF804FBF0B5012100244368002B43D0C268002A40D0427D4AB183685A1C8260827D1A70C3684475013BC360EDE7027D072A4D | ||||
| :400F40000BD806680769751C05603578013B45EA07250832056143600275027D0369A2F10805EB40DBB203F0C006802E07D0C02E0ED103F03F0383754175802308E0C3F34A | ||||
| :400F8000401363F07F03033A03F08103027502E00575002BC0D08268551C85601370C368013BC360B8E7F0BD2DE9F04172B6884B61221A70A3F5F06301221A801924854A2B | ||||
| :400FC0009C7092E803008033062283F8002283E80300522203F580731A707F4B7F4A1B787F4EDBB2137040F618027E4B00251A8041F2512223F8022C33784FF4F07003F08E | ||||
| :40100000010343EA450502F0B7F8013C05F003052ED0032DF0D1744B4FF480721A8007221A70724A002548211570917002221D705D7103F8032C0422DA716D4A6D4C137845 | ||||
| :401040006D4E43F00103137012F8013C062743F0030302F8013C2378012243F0800323705B4B1A70654A137843F02003137000E0FEE707FB056300219A881868013502F0B3 | ||||
| :40108000E3F8072DF5D15E485E4E002550F8041F05F1105303F1520221F0FF075333C9B20B4452005B0002329A4206D012F802EC12F801CC0EF807C0F5E7B0420D44E5D16D | ||||
| :4010C000514A002313609360136193614F4B504F1A68504BDFF888811A604F4B1A684F4B1A604F4A137843F002031370137C43F0020313742378A2F5863243F04003237064 | ||||
| :40110000413A137843F010031370464A464B07CA03C31A80454A2833106843F8250C127903F8212C424A07CA03C31A80414AE83B07CA03C31A80404A083307CA03C31A805B | ||||
| :401140003E4A3F4BA2F5616203CBC2F8100EC2F8141E1378042043F008031370394B02F5AA521B783D78DBB298F80060EDB203F007010C321B091170F6B2537045F00303A2 | ||||
| :401180003B7046F0030388F800302F4B48221A702E4A402313702E49937013729372082382F81F3220220A7048710A72294A0A20137001F0DDFB284B88F8006044223D7092 | ||||
| :4011C000264D1A7094E80F0007C52B80BDE8F081004800404C0F00480F010049A146004025420040224200400440004006400040A2430040A0430040453C0000E8460040A3 | ||||
| :40120000FCFFFF47A000004800760040540F0048F846004020760040580F004828760040035001400C0F0048C0510040180F0048200F00482C0F0048380F00483251004040 | ||||
| :40124000440F0048CF0100491D51004001590040235B0040585B004076580040B0430040F946004008B501F0C3FF03680C2B00D1FEE7FEE7084908B50B68084A1844821A89 | ||||
| :40128000802A01DC086005E001F0B2FF0C2303604FF0FF33184608BDCC80FF1FC893FF1F80B51148114B0025C0B1A3F1100192C922460439161BB74204D051F8046F42F896 | ||||
| :4012C000046BF7E7114653F8046C8C1AA64202D041F8045BF9E701381033E5E701F08EFFFFF798F8FEE700BF01000000143E0000124A134B10B51A60124A134C13681348EA | ||||
| :4013000043F4007313600023032B98BF54F823204FEA830188BF0E4A0133302B4250F3D10C4B1A780C4B1A700C4B084A1A60FFF73BFEBDE8104001F0EDB900BF0004FA05AE | ||||
| :401340000CED00E014ED00E0000000000080FF1F65120000BC760040C080FF1F08ED00E0F8B501F011FF4B4A01271378022643F001031370137C484C43F001031374474BAE | ||||
| :4013800002F5E3521F700B3203F8946C1378054603F07F031370002001F0EAFA2378404A03F0F90323701378384603F0DF03137023783B43237001F0DBFA282001F0D8FAF2 | ||||
| :4013C000384B30461A7802F07F021A701A7802F0BF021A7023783343237001F0C9FA2378314A43F0040323700023137053702F4AFF2199540133092BFBD1284601F0C8FE13 | ||||
| :401400000721172001F0FCFA2949172001F0EAFA0721182001F0F4FA2649182001F0E2FA0721152001F0ECFA2349152001F0DAFA0721052001F0E4FA2049052001F0D2FA34 | ||||
| :401440000721062001F0DCFA1D49062001F0CAFA0721084601F0D4FA1A49072001F0C2FA0721082001F0CCFA1749082001F0BAFA0021162001F0C4FA1449162001F0B2FA40 | ||||
| :4014800007210C2001F0BCFABDE8F84010490C2001F0A8BAA5430040944300409D60004012600040F851004084600040ED92FF1F2F1D0000691B00002D1D0000611C00006D | ||||
| :4014C0008D1C0000BD1C0000F51C0000351D0000A91D0000214B224A10B5187000231370204A40201370204A0F2413701F4A13701F4A13701F4A13701F4A13701F4B4FF4AC | ||||
| :4015000000021A604FF080721A604FF400121A6020221A601860802018604FF480701860174804704FF480001860164B1A70933B19B91A7802F0FE0202E01A7842F00102F8 | ||||
| :401540001A70114B03221A70802203F8202C012001F012FE0D4B04221A7010BD0893FF1F0E93FF1F0C93FF1F0D93FF1F0993FF1FF892FF1F0B93FF1F8093FF1F00E100E0F3 | ||||
| :401580009E6000409C600040286000401260004070B5074C054623780E461BB9FFF7E0FE0123237031462846BDE87040FFF792BFB892FF1F0A4A002313700A4A13700A4A18 | ||||
| :4015C00013700A4A13700A4A13700A4A13700A4A13700A4B03221A70802203F8202C70470E93FF1F0C93FF1F0D93FF1F0993FF1FF892FF1F0B93FF1F8093FF1F2860004017 | ||||
| :40160000014B1878704700BF0D93FF1F044B1A7802F0FF001AB118780022C0B21A7070470C93FF1F024A0C2303FB0020407870471493FF1F431E072B0CD8074A064B0001F4 | ||||
| :401640000344805C5B7800F00F0043EA0020023880B2704700207047FC5F00401A4A38B50C2303FB00231B79090C13F0800F00F1FF35044619BF8AB24FF480438BB24FF4AE | ||||
| :401680008042032D18D8DFE805F002070C110021084601F01BF80DE00021084600F0FAFF08E00021084600F0D9FF03E00021084600F0B8FF054B1855EDB2072D03D801F03A | ||||
| :4016C000EDF8034B185538BD1493FF1FE492FF1FED92FF1F431E072B2DE9F0470446894615465CD82F4F0C2202FB0072D388DFF8B8A09BB2C3F500739D424FF00C0303FB8F | ||||
| :40170000007388BFD588DB7884BFC5F50075ADB2254A43EA15230601B354B244EBB28AF80130224B1A5C9846FF2A01D1FFF796FF0C2303FB047200215170B9F1000F28D0C9 | ||||
| :401740003DB31B4F385D01F011F811232946FE2218F8040001F0D6F806F5C04278321FFA89F118F8040001F0DFF8124D18F80410385D01F04BF80121385D00F0E1FF735D31 | ||||
| :4017800043F002037355735D03F0FD037355BDE8F08703FB04746379DBB28AF80230BDE8F08700BF1493FF1FFC5F0040ED92FF1FE492FF1F706000402DE9F0470446154681 | ||||
| :4017C0008846002940D0431E072B3FD8FFF732FFA84203D22046FFF72DFF05461D4E335DFF2B03D141462046FFF738FFDFF868A027011AF8040000F0B9FF1223FE222946E3 | ||||
| :40180000305D01F07FF807F5C0411FFA88F27831305D01F089F8DFF84490315D1AF8040000F0F4FF01211AF8040000F089FF17F8093043F0020307F8093017F8093003F0A6 | ||||
| :40184000FD0307F8093002E00D4600E000252846BDE8F087ED92FF1FE492FF1F70600040431E072B0AD8064A0C2303FB002300225A705A79034BD2B200011A54704700BFA0 | ||||
| :401880001493FF1FFE5F0040431E072B9FBF024B000108221A547047FE5F004030B51A4A1A491B4D0878138803449BB21380194A00231488D8B2A4B27CB1082B0CD050684F | ||||
| :4018C0000078C0B2E85450680133013050601088013880B21080ECE718460B780E4C082B0E4A00D040B10E4D2B7883F080032B700F232370022301E0022323701370094B1F | ||||
| :401900001870087030BD00BF8493FF1F8093FF1F00600040FC92FF1FF992FF1F0E93FF1F0A93FF1F8193FF1F074B02221A70074B80221A70064B0F221A70064A0023137074 | ||||
| :40194000054A0120137070470E93FF1F0A93FF1FF992FF1F8093FF1F8193FF1F30B5164B16491B780A8803F00F03023BDBB21A4492B20A80124C134A0020118889B279B199 | ||||
| :4019800073B15568215C013BC9B229705168DBB20131516011880130013989B21180ECE7094A1370094A137883F080031370084B0B221A7030BD00BF296000408493FF1FCC | ||||
| :4019C00000600040FC92FF1F8193FF1F0A93FF1FF992FF1F064A06231370064A01201370054B80221A70054B00221A70704700BF0E93FF1FF992FF1F0A93FF1F8193FF1FD2 | ||||
| :401A0000054B9A683AB19A68044910709A680988518000229A607047FC92FF1F8493FF1F08B5124B1A78D2B21A701B78DBB21A0602D50F4A137008BD0220FFF7E1FF0D4BC0 | ||||
| :401A40001B7803F06003202B05D0402B06D043B900F012FC04E001F09FFB01E000F046FD10B9034B03221A7008BD00BF28600040F992FF1F0060004008B5084A084B0120C1 | ||||
| :401A8000197813880B449BB21380064B00221A70FFF7B6FF044B03221A7008BD8493FF1F8093FF1F0E93FF1FF992FF1F08B50C4B1B78DBB2042B07D0062B09D0022B0DD143 | ||||
| :401AC000BDE80840FFF7D8BFBDE80840FFF746BF0320FFF795FF034B03221A7008BD00BF0E93FF1FF992FF1F08B5054B002201201A70FFF785FF034B03221A7008BD00BF19 | ||||
| :401B00000E93FF1FF992FF1F08B50A4B1A7832B11A78094942F080020A7000221A70074B002201201A70FFF76BFF054B03221A7008BD00BFF892FF1F086000400E93FF1FE7 | ||||
| :401B4000F992FF1F074B1B78DBB2042B05D0062B05D0022B05D1FFF7A1BEFFF7C5BFFFF7D3BF70470E93FF1F38B51D4C2378DBB2DD0634D518060AD503F00F03012B2ED1D9 | ||||
| :401B8000FFF74EFF174B1B78190609D538BD5A0602D5FFF7D7FF03E09D0620D5FFF786FF23781B061BD4104B1A78104B1B7813430F4A13701278934211D10A4A0849154609 | ||||
| :401BC00013782078DBB2000605D41378DBB20B700B7803F00F0328788342F1D138BD38BD28600040F992FF1F0A93FF1F8193FF1F29600040054A00231380054A916819B1EC | ||||
| :401C000091680B7092685380704700BF8493FF1FFC92FF1F0E4808B503889BB213B9FFF783FE13E00B4B02221A700B4B00221A70FFF7E0FF094AD1799379028843EA01238C | ||||
| :401C400092B2934238BF0380FFF728FE012008BDFC92FF1F0E93FF1F0A93FF1F00600040084B01221A700F3B9B7C074B1A7B02F00302012A1EBFDA7B82F08002DA73012209 | ||||
| :401C80005A7370470B6000401493FF1F094B02221A700F3B93F82230074B1A7E02F00302012A1EBFDA7E82F08002DA7601225A76704700BF0B6000401493FF1F0B4B04222D | ||||
| :401CC0001A700F3B93F83230094B93F8242002F00302012A1EBF93F8272082F0800283F82720012283F82520704700BF0B6000401493FF1F0B4B08221A700F3B93F842305F | ||||
| :401D0000094B93F8302002F00302012A1EBF93F8332082F0800283F83320012283F83120704700BF0B6000401493FF1F7047FFF741BC0000F0B5184B184E19780C27C9B2A9 | ||||
| :401D400001234FF0000C31B3CA0720D5144A4FEA031E7244947850782040C5070DD507FB03652C79240608D5147804F0FE0414706D790C4CEDB204F80E50840706D507FB3F | ||||
| :401D8000036425792D0658BF84F801C090700133DBB24908D7E7F0BD9F6000401493FF1F70600040FE5F004000F0ACBC70B50446184B88B003AA03F11006154618685968B4 | ||||
| :401DC000083303C5B3422A46F7D11B782B70FCB12223237001AD03232846637000F08AFE002220461146AB5C08AC04EB131414F8144C03F00F03847008AC234413F8143CE8 | ||||
| :401E00000132082AC1700371417100F10400EAD108B070BD6F3C00002DE9F0431C4D01222E460C201F274FF0800E4FF0080C194B00FB02581401234418705F70164998F850 | ||||
| :401E400005902144B9F1000F07D098F8044024064CBF887081F802C001E081F802E000FB0261CC880132E4B29C71CC88092AC4F30724DC71CC88E4B21C71C988C1F307217E | ||||
| :401E80005971D4D1054BFF221A70BDE8F08300BF1493FF1F70600040FC5F00400A600040064B074A1B7802EBC30253681A7C824286BF03EBC0035869002070470893FF1F84 | ||||
| :401EC000D03C00002DE9F84F424B1A78002A7ED01878414D0138C0B2FFF7E2FFA8463F4AC3681478007ADFF800C1E4B203EBC0000C2600274FF0010E834268D01A78A242A4 | ||||
| :401F000063D11CF80420597891425ED19A7893F8039002F07F0206FB02FA05EB0A01CF7093F802B009F0030981F804B093F803B005F80AB0B3F804A0A1F808A093F902A066 | ||||
| :401F4000BAF1000F0BDAB9F1010F0CBF4FF007094FF00D0981F8059081F801E009E0B9F1010F0CBF4FF005094FF0090981F805904F704FEA02191A4906FB0282494481F816 | ||||
| :401F800002E0B2F808A0CAF3072A81F800A0B2F808A05FFA8AFA81F801A0B2F806A011495FFA8AFA494481F806A0B2F80690C9F3072981F80790B2F806905FFA89F981F89A | ||||
| :401FC0000490D288C2F307224A71083394E7BDE8F88F00BF0D93FF1F1493FF1F0993FF1FFC5F004070600040FA92FF1F08B5064B18780138C0B2FFF753FF20B143681B7986 | ||||
| :4020000000EBC300406908BD0D93FF1F00212DE9F84F0B464E4E0C2707FB01F401313219092933554FF000059370494CD3701381937253705371EFD118B1464B1D70464B83 | ||||
| :402040001D70464B1A78002A7FD0187801250138C0B2FFF725FFA8464368DFF8F8E0DB790C2713F0400F3E4B4FF0000C1A7814BF42F0010202F0FE021A70027AD20007FB61 | ||||
| :402080000541C36803EB02094B4531D093F802A00AF07F06AE4229D10E89B3F804B0B6B25E4538BFA1F808B01E7893F801B01EF80660B3451AD181F804A0DE780E7093F998 | ||||
| :4020C00002A0DE78BAF1000F06F0030607DA012E0CBF07260D264E7181F8018006E0012E0CBF052609264E7181F801C00833CBE70135092DC3D1C1680A328B1C0A440C2095 | ||||
| :402100000833934209D013F8081C13F80A5C01F07F0100FB01418D72F2E7FFF767FF114B0121186000230C2000FB0142D3801289013113449BB203F00102134409299BB221 | ||||
| :40214000F2D1BDE8F84FFFF767BEBDE8F88F00BF1493FF1FFA92FF1F8293FF1F0D93FF1F0B93FF1F1093FF1F114B1B7903F07F035A1E072A19D80F490C2202FB031291782D | ||||
| :402180001B0141F0010191700021D170517841F002015170127912F0800F074A1A4414BF8D2389239370FFF715BC0020704700BF006000401493FF1FFC5F004030B4194B0D | ||||
| :4021C0001A7902F07F02531E072B27D8164B0C2404FB02339978154D01F0FE0199700021D97029461201505D114400F07F0050555A7802F0FD025A701A795B78120605D51F | ||||
| :40220000012B01D18C7006E00D2303E0012B0CBF082309238B7030BCFFF7DCBB002030BC704700BF006000401493FF1FFC5F004010B50D4B0D4C21791878C9B20138C0B2A1 | ||||
| :40224000FFF72EFE43681B798B4201D2012909D8074A0848535CDBB24354A3780120DBB2535410BD002010BD0D93FF1F00600040FA92FF1F8293FF1F38B58A4A8A4C137857 | ||||
| :402280000021DBB221801806517840F18D800A2900F20581DFE811F05D00030103010301030103010B0003017E0003018200D3787C49012B09D17D4B1A787D4B03EBC203C8 | ||||
| :4022C0005B685B686360122310E0CB78022B12D18878FFF7E5FD002800F0E180436863606368DA7863689B7843EA02232380BDE83840FFF78FBCCB78032B26D16D4B0022CE | ||||
| :402300008878D5B2854209D3664A91786A4AEE2908BF1346634A917881B106E0187801320028F1D018780344EAE764499278097C914203D16248FFF739FD614B1A78002A8C | ||||
| :4023400000F0AD801A78228018E0BDE8384000F023BF13F0030313D0022B40F0A0802380504B0C211B7903F07F02564B01FB02339A78554BD2B21A7000225A706360B6E76B | ||||
| :4023800002222280514A11784F4AC9B2117053706260ACE7012323804D4BEFE70123238013794C4A1344E9E701390A2977D8DFE801F037764F76067676760A762000937848 | ||||
| :4023C000454ADBB25AE0937803F0FF0153B9404B1A7891425FD01970404B01201870FFF715FE58E0481EC0B2FFF75AFD0028EED155E0FFF71DFF002851D02A4A3849137943 | ||||
| :402400001279DBB2D2B20A70364A3249D25CCB5C9A4240D0314B01221A70FFF753FD3AE003F00303012B2BD009D3022B37D11D4B9B78002B33D1BDE83840FFF7BFBE194BF2 | ||||
| :402440009B78012B2BD1214A137803F0FD0315E003F00303012B13D008D3022B1FD1114B9B78E3B9BDE83840FFF77EBE0D4B9B78012B14D1154A137843F0020313700AE0DE | ||||
| :40248000084B1A795AB998781B791749DBB2CA5C22EA0002CA54BDE83840FFF79BBA002038BD00BF00600040FC92FF1F0893FF1FD03C0000343D0000BC3C0000A73D0000A6 | ||||
| :4024C000A093FF1F1493FF1FB992FF1F0B93FF1F0D93FF1FFA92FF1FF892FF1F0C93FF1F0993FF1F8293FF1F0F93FF1F074B1A78120609D55B78012B06D1054B054A5A601E | ||||
| :4025000012781A80FFF786BB0020704700600040FC92FF1F943C0000014B1870704700BF7F640040014B1878704700BF69640040014B1870704700BF78650040064A0123A6 | ||||
| :40254000136002F688321268E0211064034A1170A2F540721360704780E100E000E400E0014B1870704700BF72640040014B1870704700BF7665004073B515461E460B4CFE | ||||
| :4025800005230022019200920A4601461846237000F064F932462946207800F01FF90221207800F009F9207802B070BDD080FF1F064A0423136002F688321268E0219064B3 | ||||
| :4025C000034A1170A2F202321360704780E100E002E400E0014B04221A60704700E100E0014B04221A60704780E100E0014B1870704700BF78640040704738B505460078FF | ||||
| :40260000012428B100F060FD285D0134E4B2F8E738BD08B50D2000F057FDBDE808400A2000F052BDF7B516461F460B4C00230325019300930A4601462846257000F00EF920 | ||||
| :402640003A463146207800F0C9F80221207800F0B3F8207803B0F0BDE080FF1FF7B516461F460B4C00230225019300930A4601462846257000F0F2F83A463146207800F026 | ||||
| :40268000ADF82946207800F097F8207803B0F0BDE180FF1FF7B516461F460B4C00230125019300930A4601462846257000F0D6F83A463146207800F091F80221207800F039 | ||||
| :4026C0007BF8207803B0F0BDE280FF1F73B515461E460B4C0023019300930A4601461846237000F0BBF832462946207800F076F80221207800F060F8207802B070BD00BF26 | ||||
| :40270000E380FF1F024B1878C0F38010704700BF8F450040074A7F23802113705170064A013BDBB202F80839002BF9D1034A1370704700BFE480FF1FF87B0040007800401A | ||||
| :4027400017280FD8084B0001C25C11B142F0200201E002F0DF02C254C25C42F00102C25400207047012070471070004017280BD8064B0001C25C02F0FE02C254C25C02F05F | ||||
| :40278000DF02C25400207047012070471070004017280DD8074900010B4603441A7942F004021A71435C43F00103435400207047012070471070004017280BD8064A000101 | ||||
| :4027C000835C490003F0F10301F00E011943815400207047012070471070004041F6FF73994208BF4FF400519A4208BF4FF4005217289FBFC00000F1804000F5EC408180E3 | ||||
| :402800009ABFC280002001207047000017289FBF034B00011954002088BF0120704700BF1970004017289FBF054B00011A5C01F007019DBF1143195400200120704700BFB4 | ||||
| :402840001470004017289FBF034B0001185C00F0070088BFFF20704714700040172810B51AD8C00001F07F0100F1804441EAC21204F5EC44D2B222709DF8082003F00F0380 | ||||
| :4028800043EA0213DBB263709DF80C30002003F00F03A370E07010BD012010BD10B500F073FC0A4A5378182B0AD91478013B5370E30003F1804303F5F0431B78137000E0B3 | ||||
| :4028C000FF2400F065FC204610BD00BFE480FF1F030610B5044611D400F056FC084AE300117803F1804303F5F04319705378147001335370BDE8104000F04ABC10BD00BFCB | ||||
| :40290000E480FF1F30B504060CD411F4704509D1C40004F1804404F5F0442180A270E370284630BD012030BD03065FBFC00000F1804000F5F04081805ABFC280002001203F | ||||
| :402940007047000038B50446084DB4F5004F05D9286800F011FCA4F50044F6E7034B58686043BDE8384000F007BC00BFEC80FF1F024B1B7A584300F0FFBB00BFEC80FF1FBD | ||||
| :402980000E4B00F003001A78490102F0FC02104318701A7801F0600142F080021A701A7802F07F021A701A7802F09F020A431A701A7842F010021A70704700BF834300409B | ||||
| :4029C000014B01221A70704784430040044B00F00F021B6853F8220043F82210704700BF08ED00E0054A00F01F00126800F1100352F8230042F82310704700BF08ED00E027 | ||||
| :402A000000F01F0000F16040490100F56440C9B2017070470F4B10B50F4900240F205C609C60DC601C615C61FFF7D0FF0B4A136843F0040313600A4B4FF47A72DB68B3FBC1 | ||||
| :402A4000F2F3084A1360084B4FF400421C60C3F8E82010BDBC92FF1FC12A000010E000E0EC80FF1F14E000E018E000E0024A136843F002031360704710E000E008B5FFF7BF | ||||
| :402A8000F5FF034A136843F00103136008BD00BF10E000E010B5054CA3691BB9FFF7BAFF0123A361BDE81040FFF7E8BFBC92FF1F024B1868C0F30040704700BF10E000E08B | ||||
| :402AC00038B5FFF7F5FF012808D1054D002455F8243003B198470134052CF8D138BD00BFC092FF1F024B03EB8003586859607047BC92FF1F134B144A1B78DBB203601278DD | ||||
| :402B000043EA0223114A0360127843EA0243104A0360127843EA026303600E4B0E4A1B78DBB24360127843EA02230C4A4360127843EA02430A4A4360127843EA0263436052 | ||||
| :402B4000704700BF0301004904010049EC460040020100490101004900010049050100490601004910B500F00FFB204A044613780A2043F002031370137C43F00203137421 | ||||
| :402B800012F80A3C43F0010302F80A3C937943F00103937102F5AB52137843F003031370134B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2296 | ||||
| :402BC00003F8062CA3F597530222183B1A70094A137843F008031370FFF7CAFE064B10222046BDE810401A6000F0D2BAAB4300400E5900402F5B004080E200E008B500F066 | ||||
| :402C0000C3FA0F4A137803F0FE031370A2F5AA521D3A137803F0FD031370137C03F0FD03137412F80A3C03F0FE0302F80A3C937903F0FE039371BDE8084000F0A9BA00BF01 | ||||
| :402C400008590040044A137803F03F0343EA8010C0B21070704700BF08590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF10 | ||||
| :402C800033F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B1A8070470A590040803C00008A93FF1F8C93FF1F9093FF1F08B5102069 | ||||
| :402CC00000F0A6F907210420FFF79AFE07490420FFF788FE064A0C20137843F006031370FFF7BCFF034B00221A8008BDB52D0000095900408893FF1F10B5054C23781BB9F3 | ||||
| :402D0000FFF7DCFF01232370BDE81040FFF72ABFD892FF1F044B1A7802F0FB021A701A7842F001021A7070470859004010B5084B1C7814F0010403D10028F9D0002404E02A | ||||
| :402D40002046FFF715FE024B1B78204610BD00BF09590040034A044B1B881088181A00B2704700BF9093FF1FA25B00400E4A13881BB223B111880A2309B2594301E00B4BD9 | ||||
| :402D800019680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B270478A93FF1F8C93FF1F8893FF1F7047000010B500F0E5F9214ADE | ||||
| :402DC000044613780A2043F001031370137C43F00103137412F80A3C43F0020302F80A3C937943F00203937102F5AA521832137843F003031370144B18221A7013F8012CDE | ||||
| :402E000042F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8062CA3F597530222123B1A70094A137843F008031370FFF79FFD074B08222046BDE810401A6000F09A | ||||
| :402E4000A7B900BFAB43004006590040275B004080E200E008B500F097F90F4A137803F0FE031370A2F5AA52153A137803F0FE031370137C03F0FE03137412F80A3C03F099 | ||||
| :402E8000FD0302F80A3C937903F0FD039371BDE8084000F07DB900BF00590040044A137803F03F0343EA8010C0B21070704700BF00590040082804D00A280CBF8223C2230D | ||||
| :402EC00000E0422308380E4AC0B20428137098BF0C4B4FF0000298BF33F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B1A807047E8 | ||||
| :402F0000025900408A3C00009693FF1F9C93FF1F9493FF1F08B5102000F084F807210320FFF76EFD07490320FFF75CFD064A0C20137843F006031370FFF7BCFF034B0022A9 | ||||
| :402F40001A8008BD0D300000015900409893FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040FFF728BFD992FF1F044B1A7802F0FB021A701A7842F001021A70704708 | ||||
| :402F80000059004010B5084B1C7814F0010403D10028F9D0002404E02046FFF7E9FC024B1B78204610BD00BF01590040034A044B1B881088181A00B2704700BF9493FF1FD3 | ||||
| :402FC000A05B00400E4A13881BB223B111880A2309B2594301E00B4B19680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B27047DF | ||||
| :403000009693FF1F9C93FF1F9893FF1F70470000034A00F0F800137803431370704700BF02410040034A00F0F800137803431370704700BF06410040014B1870704700BFAA | ||||
| :4030400076640040014B1870704700BF7C64004073B515461E460B4C04230022019200920A46014618462370FFF7F8FB324629462078FFF7B3FB02212078FFF79DFB2078AB | ||||
| :4030800002B070BDFC80FF1F074A0223136002F688321268E0215064044A11706FF440710A441360704700BF80E100E001E400E0014B1870704700BF74650040014B187076 | ||||
| :4030C000704700BF77640040FEB5494652465B460EB40746244909688A46244A12682448022100F071F8030020480068C018204900F06AF8143883460121C9430C46012516 | ||||
| :40310000002600F041F8814651460B7823400B705846013000F030F83800F04028400B78234003430B70584600F026F80136072EF2D9002001300138013001200B7823407E | ||||
| :4031400003430B705846043000F016F8484600F01FF800BF00BF00BF0EBC894692469B46FEBD00BFAFF30080D480FF1FF880FF1F00C20100000000000230800803D000BFE7 | ||||
| :4031800001380046FCD17047EFF3108072B6704780F31088704700BF094A137803F00303012B0AD0022B09D113790C2103F07F02044B01FB02339B7A00E013790020704751 | ||||
| :4031C000006000401493FF1F002902D0B0FBF1F0704708B14FF0FF3000F008B80029F8D00246B0FBF1F000FB11217047704700BF014B1868704700BF6081FF1F0E4B70B577 | ||||
| :403200001E460E4C0025E41AA410A54204D056F8253098470135F8E700F0E2FD084B094C1E46E41AA4100025A54204D056F8253098470135F8E770BDEC3D0000EC3D000024 | ||||
| :40324000EC3D0000F43D000003460244934202D003F8011BFAE7704730B5141E05469BB0184604DA8B232B604FF0FF301DE04FF40273ADF80C300CBF234604F1FF330293F9 | ||||
| :4032800005934FF6FF7300910491ADF80E3002461E9B6946284600F073F8431CBCBF8B232B6014B1009B00221A701BB030BD000007B5009313460A46014603480068FFF77E | ||||
| :4032C000CBFF03B05DF804FB6081FF1F2DE9F0478E6882469E420C46914698463ED88A8912F4906F3AD02568096902236F1A656905EB450595FBF3F57B1C43449D4238BFB3 | ||||
| :403300001D4653050FD5294600F04AFB064698B13A46216900F0D2FAA38923F4906343F08003A38113E02A4600F098FB064670B92169504600F0E8FA0C23CAF80030A38945 | ||||
| :403340004FF0FF3043F04003A381BDE8F08726613E44266046466561ED1BA560464528BF464649463246206800F0B3FAA36800209B1BA36023681E442660BDE8F08700009E | ||||
| :403380002DE9F04F9DB003938B8980461C060D4616460DD50B695BB9402100F001FB2860286118B90C23C8F80030CDE040236B610023099320238DF82930DFF89CB130233F | ||||
| :4033C0008DF82A3037463C4614F8013B1BB9B7EB060910D003E0252BF9D02746F3E74B46324629464046FFF771FF013000F0A780099B4B4409933B78002B00F0A080002373 | ||||
| :403400004FF0FF3204930793059206938DF853301A930126052221784E4800F041FA671C049B38B14B4A3C46801A06FA00F018430490EFE7D90644BF20228DF853201A07B0 | ||||
| :4034400044BF2B228DF8532022782A2A03D0079A00210A200BE0039A111D12680391002A10DA524243F00200079204900BE027463B780134303B092B03D800FB023201217E | ||||
| :40348000F5E701B107923B782E2B1ED17B782A2B0AD1039B02371A1D1B680392002BB8BF4FF0FF33059310E0002319460593781C0A2407463A780130303A092A03D804FB83 | ||||
| :4034C00001210123F5E703B1059103223978224800F0E6F940B14023CBEB000003FA00F0049B013718430490397806221B487E1C8DF8281000F0D4F988B1194B33B9039B1D | ||||
| :40350000073323F007030833039314E003AB00932A46144B04A94046AFF3008007E003AB00932A460F4B04A9404600F093F8B0F1FF3F824603D0099B5344099342E7AB89BC | ||||
| :403540005B0601D4099801E04FF0FF301DB0BDE8F08F00BFBB3D0000C13D0000C53D000000000000CD3200002DE9F04791461F460A698B6806469342B8BF1346C9F80030AD | ||||
| :4035800091F843200C46DDF8208012B10133C9F800302368990642BFD9F800300233C9F80030256815F0060510D104F1190A07E00123524639463046C04701301AD0013598 | ||||
| :4035C000E368D9F800209B1A9D42F1DB94F843302268003318BF012392060FD5E118302081F843005A1C94F845102244023382F8431003E04FF0FF30BDE8F08704F1430291 | ||||
| :4036000039463046C0470130F4D02268D9F80050E36802F00602042A08BF5D1B2269A3680CBF25EAE57500259342C4BF9B1AED184FF000091A344D4509D00123224639462F | ||||
| :403640003046C0470130D5D009F10109F3E70020BDE8F0872DE9F04317460A7E85B06E2A984606460C460C9B01F1430E00F0AE8011D8632A22D009D8002A00F0BB80582A3E | ||||
| :4036800040F0CA8081F84520834955E0642A1ED0692A1CD0C0E0732A00F0B08009D86F2A2ED0702A40F0B8800A6842F020020A603EE0752A24D0782A3AD0ADE01A6801F151 | ||||
| :4036C0004205111D1960136884F84230A8E021681A6811F0800F02D0111D196008E011F0400F02F10401196002D0B2F9003000E01368002B3CDA2D225B4284F8432037E003 | ||||
| :4037000021681A6811F0800F02D0111D196007E011F0400F02F10401196001D0138800E01368227E5C496F2A14BF0A2208221BE078225A4984F845202268186812F0800F4B | ||||
| :4037400000F104051D6003D1550601D5038800E00368D00744BF42F0200222601BB9226822F0200222601022002084F8430001E049490A226568002DA56008DB206820F009 | ||||
| :40378000040020602BB9002D7DD175460CE0002B79D07546B3FBF2F002FB1033CB5C05F8013D03460028F5D1082A0BD12368DA0708D5236962689A42DEBF302305F8013C34 | ||||
| :4037C00005F1FF35C5EB0E0323612EE008681A6810F0800F496903D0101D1860136808E010F0400F02F104001860136801D0198000E0196000232361754616E01A68111D3A | ||||
| :403800001960156800216268284600F049F808B1401B6060636804E004F1420584F8422001232361002384F84330CDF800803B4603AA21463046FFF797FE013002D14FF093 | ||||
| :40384000FF3026E023692A4639463046C0470130F5D023689B0710D5002504F1190907E001234A4639463046C0470130E7D00135E368039A9B1A9D42F2DBE068039B984219 | ||||
| :40388000B8BF184605E00B7804F1420584F842308AE705B0BDE8F0836F3C0000CC3D000010B5C9B202449042034605D01C7801308C42F8D1184610BD002010BD10B5431E9F | ||||
| :4038C0000A44914204D011F8014B03F8014FF8E710BD884210B501EB020301D8421E0BE09842FBD28118D21AD34204D013F8014D01F8014DF8E710BD994204D011F8014B7E | ||||
| :4039000002F8014FF8E710BD38B50546002944D051F8043C0C1F002BB8BFE41800F0D4F81E4A1368114613B96360146030E0A3420DD92268A018834201BF18685B681218C2 | ||||
| :40394000226063600C6023E0A24203D813465A68002AF9D118681918A1420BD12168014458188242196013D110685268014419605A600DE002D90C232B6009E021686018E0 | ||||
| :40398000824201BF106852680918216062605C602846BDE8384000F098B838BDE092FF1F70B5CD1C25F0030508350C2D38BF0C25002D064601DBA94202D90C23336046E015 | ||||
| :4039C00000F082F8234B1C681A462146A1B10B685B1B0ED40B2B03D90B60CC18CD501EE08C420BBF63684B681360636018BF0C4615E00C464968E9E7174C23681BB9304696 | ||||
| :403A000000F052F820602946304600F04DF8431C18D0C41C24F00304A0420DD12560304600F053F804F10B00231D20F00700C31A0ED05A42E25070BD211A304600F034F8A0 | ||||
| :403A40000130EBD10C233360304600F03EF8002070BD00BFE092FF1FDC92FF1FF8B5074615460E4621B91146BDE8F840FFF798BF1AB9FFF749FF2846F8BD00F027F88542C5 | ||||
| :403A80000ED929463846FFF78BFF044650B131462A46FFF713FF31463846FFF735FF01E03046F8BD2046F8BD38B5064C0023054608462360FDF7DEFB431C02D1236803B176 | ||||
| :403AC0002B6038BDC493FF1F7047704751F8040C0028BEBF091851F8043CC0180438704700000000050209020B020D020F021102130215027265706C79203078253032787F | ||||
| :403B000000686F6D696E6700626567696E6E696E67207365656B2066726F6D20256420746F2025640066696E6973686564207365656B00796573006E6F00647269766520E7 | ||||
| :403B4000303A20257320647269766520313A2025730057616974696E6720666F72205553422E2E2E0055534220726561647900636F6D6D616E64203078253032780066614C | ||||
| :403B8000696C2025642B25642B2564203D3D2025642C206E6F74202564007061737365643D256400756E64657272756E206166746572202564207061636B65747300636F25 | ||||
| :403BC000756E743D256420693D256420643D256400636D645F777269746500646F6E6520256420256400703D25642063723D25642063773D256420663D256420773D2564FF | ||||
| :403C000020696E6465783D256420756E64657272756E3D25640077726974652066696E69736865640073746172742065726173696E670073746F702065726173696E670092 | ||||
| :403C400069646C650000510040100040510040300000000140001000140140000800400140000A004C014000020050014020003031323334353637383941424344454600E9 | ||||
| :403C8000000100000004000000100001000000040000001028000000000104000100000000000000000157494E5553420000303030303100000000000000000012034D0080 | ||||
| :403CC0005300460054003100300030000100000001000000D83C000001000000A73D0000000000000000000001000000F03C000001000000793D000004000000123D000014 | ||||
| :403D0000000000000000000000000000103D0000FF00000001024000FF00000082024000FF00000003034000FF00000084034000FF00020304030904160346006C007500CE | ||||
| :403D4000780045006E00670069006E0065002A0343006F0077006C00610072006B00200054006500630068006E006F006C006F0067006900650073000009022E0001010036 | ||||
| :403D800080320904000004FF00000107050102400000070582024000000705030340000A0705840340000A12010002FF0001080912006E0100020180014300232D302B20AF | ||||
| :403DC00000686C4C00656667454647003031323334353637383961626364656600000000F8B500BFF8BC08BC9E46704759000000F1120000F8B500BFF8BC08BC9E467047E3 | ||||
| :403E000035000000183E0000C880FF1FA0000000601200000000000000000000C893FF1FFF000000675000400C00000007000000FFFFFFFF7F8000003F0000000000007D46 | ||||
| :403E400000FA0000400000000090D003FF0000000000000000000000000000000000000000000000000000000000000000000000B93D0000000000000000000000000000B0 | ||||
| :403E80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081FF1F00000000000000000000000063 | ||||
| :403EC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C2 | ||||
| :403F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081 | ||||
| :403F40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041 | ||||
| @@ -4098,68 +4098,68 @@ | ||||
| :40FF80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041 | ||||
| :40FFC0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 | ||||
| :0200000480007A | ||||
| :40000000014500400752004003640040030101400A0301400D050140480601404907014054080140660901405D0A0140530B01404F0C0140530D0140560E0140380F0140F6 | ||||
| :400040000D1501404E160140521701404E18014059190140461A01404E1B01400A4001400D4101400D420140074301400444014009450140064601400F4701400648014029 | ||||
| :4000800008490140154C0140064D014007500140035101407E020841090210801180601461117C402B802E0A3B7E80208940E201861087018E019D40A021AC01E203E40803 | ||||
| :4000C000E6C0EE0888028D808E2098409B019D40A021A201A610AC40E241E402EE080021024E030405030602080F09100A100E010F03100E12701308140E1503182E19037F | ||||
| :400100001A411D031E0822042301247F27022A0E2B032D032E01307F310F35103E013F10580459045B045C905F01800F8220830F840F85088610890F8C018D088E32910891 | ||||
| :400140009702980199089A069D08A308A404A504A609A903AB0CAD01AE0FB038B407B70FBA20BF40D804D904DB04DC09DF010004024003020490050806880A040D090E0A99 | ||||
| :400180001020120114401510162017401A041B021D01200124402612278028882A042B012D902E022F203080310832113501360437A0398A3A203C013D203E884040410141 | ||||
| :4001C00068026DA08201834886808A418B108C088D448E048F409440984099889A209B019D40A021A201A402A612A908B440B602C0FDC2F2C4F5CAFFCCFFCEFFE207EE0C7B | ||||
| :40020000000F0210060F09C30B3C0C020E340F02134814801701180219501A051BAD212F23D0240F26202B842C012ECA30383240331F3407368037E039083A203E403F4047 | ||||
| :40024000400545E0470C481249FF4AFF4BFF50045601580459045A045B045C995D095F0162C081018210842085018A048B048D018E02900193019409980999019E089F01D2 | ||||
| :40028000A009A101A501A809A901AC60AF02B018B107B207B440B507B620B922BA02BE40D804D904DC99DF01009604400502071008800A580D080E0810041242140615200F | ||||
| :4002C0001708180519491AB31B051C401D081E0A1FD0211123C0271129042A012B0A2D022F04300231103340340136043710388039063B103C203D804E825608642067206F | ||||
| :400300006C476D0D6E206F087484759476977740788079407B018310878088148A848B088C448E1090109248931494A1955796A6978898529A409CA09D429E3F9FD1A010DB | ||||
| :40034000A170A20AA302A426A503A6A1A73DA901AA04AC08B001B210B310B680B780C0BFC26FC4ABCAAFCCEDCE3FD210E271E690E844EC100004011C030304020502080260 | ||||
| :4003800009020C020F02100311021502160319021A021C011D031F042002210224022502280229082B012C022D103203331F340436043E443F04580459045C095F018301E2 | ||||
| :4003C000854087308B028D488F109149940295019B049C019D49A301A548A720AB49AD01B002B140B307B401B538BB08BE11C032C106C204C604C7E0C824C9FFCAFFCBFF96 | ||||
| :40040000CD20CEF0CF01D020D110D608D804D904DA04DB04DC90DD99DF01E108E440E520E680E708E840E920EB08EE40EFA801040241030808040A660C800E10100211016D | ||||
| :40044000121418101A091D011F1023102444260E29402BA42C042E0A2F0230103102324834813628380839023A203B803C453F20450847114D10540157405EA0640A6C01E7 | ||||
| :400480006E406F02864088808EC090089210930494A3954596E3978898519A409CA69D429EA59FD0A010A178A424A501A605A76DAB10AC01B404B640C00FC2AFC40FCAFF09 | ||||
| :4004C000CCFFCEFFD0E0D220D630D830E241E480E640EC010003020C030204800708088009030D031010130314031503167418101A401B041C801D032201230324022701EA | ||||
| :40050000281929032A622C102D032E28327F33033480350F368038083AF03F0452015610580459045B045C995D905F018001810F850886028A208B028D088E08907F91047F | ||||
| :400540009508967F9A3F9B0F9E3F9F08A03FA108A508A610A903AA04AB0CAC3FAE40AF01B23FB440B50FBE14BF10D804D904DB04DF010008010802010348041005020720DA | ||||
| :400580000AA60C200D880F801001110512041380142016021711181019201C221D181E042220240825302610272829082A812B042C042E802F603120320133483481362037 | ||||
| :4005C000370838823A243D0A3E605850599069806A106D806F01814085408A038B048C04930494A595449640978099809A409C039D709EA0A184A310A510A615A705AB50DA | ||||
| :40060000AE04C07FC2FFC4FFCAFFCCFFCEFFE210E408E6C0EA04EE01010104020A010B501010151019D01C01210D240827052804290A2DA030083103320333C034103530DB | ||||
| :400640003604370C3E5140644502480149FF4AFF4BFF4D204EF0511056085804590B5A045B045C995D995F01610862406340648066406740810782018308840385568608C8 | ||||
| :400680008721880189068A0C8B788D7F8E019001911192069326940697029A029B049E069F01A006A140A306A406A701A806A906AA01AC07AD06B37FB60FBE40BF04D8048C | ||||
| :4006C000D904DF01001002100485051008400A820C010E2A10201110154016A8185019841B101D80221523052504284029042A502D042EA02F40321434013550360438209C | ||||
| :400700003B013D203E483F0A4040482049205B5062506A807802830189108C20C0F6C2F9C4F6CAFFCCF6CEF5D001D204D60CD80CDE01E080830486028C088F209C089E02BB | ||||
| :40074000A304A720AD20B102B440E404E6080080048009060A030B010C300D040F01103D110412C014A915011702180C19081A401C8020802108245628802C8033083507CF | ||||
| :4007800036FF3B083E40580459045C905F018004810882098302840F85058610880189108A328C018D058E06910592C0952C970299059C409D059E80A00FA220A305A5059E | ||||
| :4007C000A60FA913AB20AD0FAF10B007B238B440B53FB680B8A0BA02BE50BF10D608D804D904DB04DC09DD90DF010006030A04900508078009400A400C010D080E0A124090 | ||||
| :4008000013081448162219A21B0A1F8022202404250826102734288129042A202F803080310832113620370539993F9059105B40614063086A4081108350840189808A10EE | ||||
| :400840008B2090D0919992229310940498C0990C9A609B899D409E029F20A081A140A205A340A508A720A890AD11AF01B104B204B4C0B614C0FFC2F9C4FCCA8FCCEFCE3F53 | ||||
| :40088000D60CD80CE004E202E685EA0EEE090201037F0401070208010B3F0C010D3F0E021001113F12021401173F1A011B041C011D3F20012308240127102A012B202C0123 | ||||
| :4008C0002D012F403340353F36033E403F14580459045F018132821D841D85028710880189328A308C0C8D1F8E228F40901D91339304941D953299329A079C1D9D029F603C | ||||
| :40090000A001A208A332A41DA532A81DA933AB0CAD01AE1DAF38B10FB43CB570B603BE50BF11D804D904DB04DF01014802080382040205100610070209400AA40E620F08D3 | ||||
| :4009400010111122138015051601172018011B101C02208023082620272028112B842D052E802F09312132083340359136083702380839403A223C083E113F404A014B4035 | ||||
| :4009800058408220851089529082912592D19344942095109708985099D99AD19B809D029E20A004A130A218A38EA441A503A620A730A904AA40AC02AF80B0A1B401B5108D | ||||
| :4009C000B740C0FFC2FFC4FFCAFFCCFFCEFFD608E080E4A0E605EA52EC20EE900101020204010710093F0A040C010F081001113F1608172018081B021D3F1E012010230488 | ||||
| :400A00002601273F2A012B3F2C012F3F3218333F34073A203F045608580459045B045C095D905F01803F830186028701883F8D018E089101923F962097029A3F9B019D0833 | ||||
| :400A40009E3FA001A304A501A610A83FAD01AE04B107B308B63FB707BB82BE40BF04D804D904DB04DC90DF01002103220480051106100A910B040D020E210F08100512503A | ||||
| :400A80001524168118281A141B201F802020240225032762280429402A012B242C012E082F80300131103240330835103680370A388039043A103B023E413F0858805C40D5 | ||||
| :400AC0005F2062808040872088808C018E489081912492C1930694289604980199519AD19B089F40A210A30EA503A720B304B612C0FFC2FFC4FFCADFCCFFCEDFD638D808A8 | ||||
| :400B0000E240E8C01A801F0832403308358037083880C630CCF0CE10302037203B023D10810889808F0894809D809F08CC30CE60E2805108804086408F01948095109702C2 | ||||
| :400B40009F20A108A420D420E280E44080209F20A420A640AD10E280EE1014808F20C404E408670887048E409B20A740A880AB40D801E602821096409B20A220A740AA20DE | ||||
| :400B80000A400B010E100F048301910496509A209B20A220A740AA20B104C20FE80426408B02A640AF20C820EA4073407F029340A302AF40DC80DE20EE40041008080C1038 | ||||
| :400BC0000F80522056205B205D048018880291049A209B20A220A740AF04C001C20DD407D601E401740288109810A002DE04E20401010B010D010F0111011B011D0100BF9C | ||||
| :400C0000012A1105BF0000A09F001F000000000000000000100000004000000000000000C0000000FF0000B84700470000010000800000008000800000000000000400007C | ||||
| :400C4000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F | ||||
| :400C80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034 | ||||
| :400CC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F4 | ||||
| :400D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B3 | ||||
| :400D40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000073 | ||||
| :400D80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033 | ||||
| :400DC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F3 | ||||
| :400E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B2 | ||||
| :400E40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000072 | ||||
| :400E80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032 | ||||
| :400EC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F2 | ||||
| :400F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B1 | ||||
| :400F40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071 | ||||
| :400000000145004008520040015B004001650040010101404D0201403D0301404C0401404D0501404D060140500701404B0801404B0901404B0A0140500B0140470C0140CB | ||||
| :40004000500D0140520E0140350F014046140140541501404B160140561701404718014044190140591A0140571B01400A400140104101400E4201400943014004440140BE | ||||
| :400080000D4501400A4601400F470140094801400F4901401B4C0140084D014008500140045101407E0208440905108011821801600C610A7C4027212A0A8C8000010109B1 | ||||
| :4000C0000202040805090808090F0B100C080D010F02100F1120140416011709180819101B0E1D011E01210422082301240829092A0E2C0D320F331F35203B083E043F1020 | ||||
| :400100005608580459045B045C905D905F01850287018C01900F9401960898249A089E07A008A101A222A302AA08AE10B01FB101B302B420B90ABE10BF05C202C70EC810AC | ||||
| :40014000C9FFCAFFCBFFCF83D804D904DA04DB04DC09DD09DF01030204A10620074008010A060B200C800D100E400F2010421110150416821720180419011E10202021010F | ||||
| :40018000262027202A012C042E023508376138083E583F0240045208588859215A025D4060026108621265806F0180068140874088408A088E209880C0F1C2FFC4FBCAA1EC | ||||
| :4001C000CCF0CEF2D004D61FD81FE20CE6C5EE82010D04020601070109080C010D080E0E100F130E150F161019081C201D082101220F2302240125042604270128012908CA | ||||
| :400200002A082C012F08301F3220330F3E043F045608580459045B045C095D905F01810182088302840885028A108B018C088D038F049102920194049701982099029A1FB5 | ||||
| :400240009C089D02A202A302A408A501A704A808A902AC1FAD03AE20B107B43FBF01D804D904DB04DC09DF0100400108048006A0070809880A400C810E080F20100511082C | ||||
| :40028000130115251740185019011B011E081F20210827402AA02B902C052D022F20308031213208350136803728388039243B013D083E4A3F2158405C105D806180851076 | ||||
| :4002C00087029102938094A195349644972099809B209C0C9D089EBAA480A602A713A908AC03B010B520B601C0F5C2FDC4FFCAFFCCFFCEFFD638D808E20AE648E880EA03A0 | ||||
| :40030000EE820003010D050506010801090C0B020C010D0D1001111012021602170D1801190D1C011D0D2201230D2401250D280129092C012D012E022F02310C3510360355 | ||||
| :4003400037033E403F51580459045B045F0180208102820F8404860A882F89028D028EA09204948095039640970C98049A099E10A020A102A20FA480A802AC01AD0AAF0550 | ||||
| :40038000B060B108B21FB306B480B501B61FBE10BF01D804D904DB04DC99DF01000902080302048A0708082209880C800D100F9011501305158016A01710180919041A08AD | ||||
| :4003C0001BD21D80210923042440254026102B422C042D012E402F20310836843721380239803A103D203E083F825D015F0169506AA06F0178017B807D027F8080048604BE | ||||
| :4004000089108A028F01938094A19525964497219B209C0D9D0A9EA89F08A321A480A520A68AA790AD01B040B210C0FFC2FFC4FFCAF9CCF2CEFDE242E401EA01000103027E | ||||
| :4004400004E0050108010A080B020CE00F02100F1280130814481602170218201B021E071F02200422482302261027022A082B042F10311F34E0361F382039023F015804DF | ||||
| :4004800059045B045C095F0180038109840387318A018B098C038F06900391129309940395099712980399409E02A003A309A603A709A803A909AC03AD49AF24B338B40349 | ||||
| :4004C000B540B707BB88BE10D804D904DB04DC90DF010080012002800320048A052008180A010B400C020D080E0610021325172918081E061F802002215423252480284155 | ||||
| :4005000029202B202C872D202F203108321233013448350137A0380239883B103C803E043F115A806E408340860287048A0690029289935094019704981A99019B889C84CD | ||||
| :400540009D209F20A0C2A108A280A328A401AB10B204C0FFC2FFC47FCAFFCCF7CEFFD608E080E620EA85EE2002800404050D064808200A400C0111011210144816021A07E2 | ||||
| :400580001B051C401E202608280129102A082C0F2D0A3020310C32C03303341F362037103A083E413F4056085804590B5B045C995D905F01822083018607870F88218A0825 | ||||
| :4005C0008B018C218F019210930E9428964297059AC89B039F01A02FA280A301A444A628A709A90FAA20AD0FB105B21FB4E0B503B709BA20BF51D804D904DC09DF010001EA | ||||
| :400600000184030805A4078009090A060D080E881006121015141701180219811A051B481D041E081F20210422412501264027082B052C822F2432113408350137A03908B7 | ||||
| :400640003C823D043F144410450858805B10630A64086610780284018601911092289358950896019704980A9B819D249F20A0C2A108A280A401A761A840AF11B040B504F1 | ||||
| :40068000B702C0FFC27FC477CAFCCCF5CEF2D60CD80CDE01E202E640E880EA10EE4002080349077F08010A280B090C2F0F091001117F1408160217091A071B091E401F2962 | ||||
| :4006C000221023722709280429782A282B042F19310732603348341F352837183F55580459045B045C095F01802081048440850186A088418A088C4F8E808F04920794041B | ||||
| :40070000966898689A029B019C41A208A610AA40AD02B01FB304B503B6E0BA80BF04D608D804D904DB04DC99DD90DF010128024003010521070109040A810B080D080E0633 | ||||
| :400740000F80128013181608170218821A801D081E041F14221423102601271A2B012D042E012F253210341036843721380239083A403C023D1A3E0A3F54584060026240FE | ||||
| :4007800068026B016F0A831886408B048C018D089342951496019714980899019B809C109D209E0A9F21A0C0A284A402A509A74AB308B504C0DFC2FFC45ECAF8CCF4CEFBE6 | ||||
| :4007C000D608D808E010E280E644EE820002012F020103800402060107070A060B200C020E010FC81002120114071528174218021A011B101C021E012121220523082544DD | ||||
| :400800002607272829212A012C0731E03207331F3B023E04580459045C905F0182698502861988198E198F119019924493049419962298229A199B089C19A20EA306A61923 | ||||
| :40084000A702A910AA19AB01AD01AE19AF10B070B208B301B407B510B607B70EB928BAA2BB80BE04BF14D804D904DB04DC99DF010082012402400521060207200810094941 | ||||
| :400880000B200C020D090E010F04104213141514164017801A201C821D011E281F012010210423C025442680270829202A082B402C802F1A30803108329034483614378162 | ||||
| :4008C000390A3B503D403F046D408C10C0FFC2FFC4FFCAF7CCA6CE5FE210010E04080508060409080C0D0E020F08110812091504180819081A021D081E04200423012702A7 | ||||
| :4009000029082D08300C320C330F34033A0A3F045608580459045B045C095D905F01801382048402871088028B1F8C088E018F1F901991019202951F96099A089B049C0273 | ||||
| :400940009D1FA001A20CA308A602A720A802AB02AC1BAD1FB210B40FB73FBB80BE14D804D904DC90DF010108021104020540060807200A040B810D110F2211021405161004 | ||||
| :400980001702190A1A041E201F20210425402680270229442A212C802E202F2130803120320433113545371039163A803B033D843F2058806002680D6A508101821084A1C0 | ||||
| :4009C000880289028B048E5090029134922893859508980599459AA99B219C229D0AA080A121A311A40CA690AA88AD80AF10B111B504B648C0F5C2FBC4F8CAFFCCFFCE7FAE | ||||
| :400A0000D608D808E248E401E602E809EE030001062008010A7E0D010E08107F167F1A041E1020022101247E26012A402C7F3501367F3B303E40580459045B045C905F0179 | ||||
| :400A4000804484118708881189078C078E088F109211941195A5974298119B429C119F21A011A307A433A5C6A644A721A878AA02AC20AD84AE02B3E0B51FB67FB71FB9A0BC | ||||
| :400A8000BE40C004C5E0C6C0C80AC9FFCAFFCBFFD004D601D804D904DA04DB04DC90DD09DF01E2C001160201030204020540071409A80B400C810D200F2010041141130440 | ||||
| :400AC00015A016A019801F80214023152510270428222B402F8030083250384039083B103D8041014B025210688069756B116C016E406F02705071E972A07348810A8204C4 | ||||
| :400B00008404850487048A108C509040910292A8938094A295A496409733980199049B209C269D0A9EB89F18A141A351A484A530A68CA808B210B540C0FFC2FFC4FFCA8B79 | ||||
| :400B4000CC0ECE1ED001E003E208E402EA40EE060601083109100D0C0E080F021040130116021702180319011A101E0420382304240325082608290A2B042C022E2130400E | ||||
| :400B8000310F3207351036383A803E013F10580459045B045C995F018001830C8401870188018A028B078C018F019001930194019701980199079E019F01A001A108A302BA | ||||
| :400BC000A601A701A801AB01AC01AE02AF01B507B603B708BE40BF50D804D904DF0100820201032A05480608081909800B400D080E461002128013241501174818011D4E2B | ||||
| :400C00001E01218022102408260228082BA22C082E022F103011328436063710380239A83D103F806D5080048280850186058C208D01900291A89248934494019620981A26 | ||||
| :400C40009A029B609C809D20A043A284A328AB80B604C0EFC2FFC4BFCAEFCCEFCE3FE080E451E8C0EE02000801010201050108040B010C010D010E081101130217011901F5 | ||||
| :400C80001A011D01210123022401250129012A022D01300332043303340836083A023E543F0440434502480149FF4AFF4BFF4D204EF05110580459045A045C095D095F017F | ||||
| :400CC0006108624063406480664067408004840885CC86018722881F8C048D01900493119401961E9722980499F19C019E10A004A344A588A604A824A9AAAA19AB44AC0134 | ||||
| :400D0000AE22B020B30FB50EB61FB7F0BE41BF10D804D90BDC90DF01002001020301058907080B040C200D090E011010120816801764181019221A0A1B801D021E0222083E | ||||
| :400D400025602711280929022B202C082E022F10301232843606371039A83A013D884010410248107C0283408520881089088B308C088D448F4091EA920193049602972033 | ||||
| :400D8000981B99819A839B0C9D209F10A022A108A286A320A408A601A7C0A904AB04AD01AE01B080B18AB608B708C0FBC2F2C4F6CAEFCCEFCE5FD003DE80E0A0E240E47094 | ||||
| :400DC000E602E890ECC01B011F0231203302368037083B40C630CCF0CE103088364037043A023C2088108F0893809F08A520AE80AF41B340CCF0CE60EE4053405640840897 | ||||
| :400E00008C8093809A409E029F04A488A520A6C0B2C0D460E2408E0292029E02A520A6C0AB04AE01EA80EE4015027B02C404DC015940670882108E4191029720AF10B7020E | ||||
| :400E4000D401D801E008E602EC021A4085408D049102966097289D40A201C608E60209440F4191029420962097299C409D40A201A544A810AB01B040C20FEA0126809202EF | ||||
| :400E8000A320A520A680AE40B720C820EE405280572079407E01828085208D409202A320A520D460DC80DE20E210E62004200A200C400F401F1050805B405E025F8083408D | ||||
| :400EC000894091029420962097209C409D40A201AF40B304C001C20DC601D405D605E001E801850188809102A480B3C0E401EA04EC04010109010B010D010F0111011B01BF | ||||
| :400F00001D0100FF01AB020211050000BF0000A09F001F000000000000000000100000004000000000000000C0000000FF0000B847004700000100008000000282008200D5 | ||||
| :400F400000000000000303000300000027001801270018010004000000050000000000000000000000000000000000000000000000000000000000000000000000000000DF | ||||
| :400F80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031 | ||||
| :400FC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F1 | ||||
| :4010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0 | ||||
| @@ -4615,12 +4615,12 @@ | ||||
| :0200000490105A | ||||
| :04000000BC90ACAF55 | ||||
| :0200000490303A | ||||
| :0200000037A225 | ||||
| :0200000009CD28 | ||||
| :0200000490402A | ||||
| :4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0 | ||||
| :400040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080 | ||||
| :400080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 | ||||
| :4000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | ||||
| :0200000490501A | ||||
| :0C00000000012E16106900002E2D480B88 | ||||
| :0C00000000012E16106900002E321A3686 | ||||
| :00000001FF | ||||
							
								
								
									
										27
									
								
								FluxEngine.cydsn/FIFOin/API/c.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								FluxEngine.cydsn/FIFOin/API/c.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #include "cyfitter_cfg.h" | ||||
| #include "cydevice_trm.h" | ||||
| #include "cyfitter.h" | ||||
| #include "`$INSTANCE_NAME`_h.h" | ||||
|  | ||||
| void `$INSTANCE_NAME`_Start() | ||||
| { | ||||
|    `$INSTANCE_NAME`_Init(); | ||||
| }     | ||||
|  | ||||
| void `$INSTANCE_NAME`_Stop() | ||||
| { | ||||
|     `$INSTANCE_NAME`_Disable(); | ||||
| } | ||||
|  | ||||
| void `$INSTANCE_NAME`_Init() | ||||
| {     | ||||
|     `$INSTANCE_NAME`_Enable(); | ||||
|      | ||||
| } | ||||
| void `$INSTANCE_NAME`_Enable() | ||||
| { | ||||
| } | ||||
|  | ||||
| void `$INSTANCE_NAME`_Disable() | ||||
| { | ||||
| } | ||||
							
								
								
									
										50
									
								
								FluxEngine.cydsn/FIFOin/API/h.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								FluxEngine.cydsn/FIFOin/API/h.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| #if !defined(`$INSTANCE_NAME`_H) | ||||
| #define `$INSTANCE_NAME`_H | ||||
|  | ||||
| #include "cytypes.h" | ||||
| #include "cyfitter.h" | ||||
| #include "CyLib.h"  | ||||
|  | ||||
| #define `$INSTANCE_NAME`_FIFO_PTR	         ((reg8 *) `$INSTANCE_NAME`_dp__F0_REG) | ||||
|  | ||||
|     /* Macros to clear DP FIFOs.*/ | ||||
| #define `$INSTANCE_NAME`_CLEAR do { \ | ||||
|     CY_SET_XTND_REG8(\ | ||||
|         ((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG), 0x01u | \ | ||||
|         CY_GET_XTND_REG8(((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG)));\ | ||||
|     CY_SET_XTND_REG8(\ | ||||
|         ((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG), 0xfeu & \ | ||||
|         CY_GET_XTND_REG8(((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG)));\ | ||||
|     } while(0) | ||||
|  | ||||
| /* Macros to set FIFO level mode. See the TRM for details */ | ||||
| #define `$INSTANCE_NAME`_SET_LEVEL_NORMAL \ | ||||
|     CY_SET_XTND_REG8(\ | ||||
|         ((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG), 0xfbu & \ | ||||
|         CY_GET_XTND_REG8(((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG))) | ||||
| #define `$INSTANCE_NAME`_SET_LEVEL_MID \ | ||||
|     CY_SET_XTND_REG8(\ | ||||
|         ((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG), 0x04u | \ | ||||
|         CY_GET_XTND_REG8(((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG))) | ||||
|  | ||||
| /* Macros to set FIFO to single-buffer mode. */ | ||||
| #define `$INSTANCE_NAME`_SINGLE_BUFFER_SET \ | ||||
|     CY_SET_XTND_REG8(\ | ||||
|         ((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG), 0x01u | \ | ||||
|         CY_GET_XTND_REG8(((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG))) | ||||
|  | ||||
| /* Macros to return the FIFO to normal mode. */ | ||||
| #define `$INSTANCE_NAME`_SINGLE_BUFFER_UNSET \ | ||||
|     CY_SET_XTND_REG8(\ | ||||
|         ((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG), 0xfeu & \ | ||||
|         CY_GET_XTND_REG8(((reg8 *) `$INSTANCE_NAME`_dp__DP_AUX_CTL_REG))) | ||||
|      | ||||
| void `$INSTANCE_NAME`_Enable(); | ||||
| void `$INSTANCE_NAME`_Disable(); | ||||
| void `$INSTANCE_NAME`_Start(); | ||||
| void `$INSTANCE_NAME`_Stop(); | ||||
| void `$INSTANCE_NAME`_Init(); | ||||
|  | ||||
| #endif | ||||
|  | ||||
| /* [] END OF FILE */ | ||||
							
								
								
									
										
											BIN
										
									
								
								FluxEngine.cydsn/FIFOin/FIFOin.cysym
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								FluxEngine.cydsn/FIFOin/FIFOin.cysym
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										128
									
								
								FluxEngine.cydsn/FIFOin/FIFOin.v
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								FluxEngine.cydsn/FIFOin/FIFOin.v
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
|  | ||||
| //`#start header` -- edit after this line, do not edit this line | ||||
| `include "cypress.v" | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
|  | ||||
| /* Ultra-simple FIFO in component: a byte is shifted in every clock when req | ||||
|  * is high. */ | ||||
|   | ||||
| module FIFOin (drq, clk, d, req); | ||||
| 	output  drq; | ||||
| 	input   clk; | ||||
| 	input  [7:0] d; | ||||
| 	input  req; | ||||
|  | ||||
| //`#start body` -- edit after this line, do not edit this line | ||||
|  | ||||
| wire [7:0] pi; | ||||
| assign pi = d; | ||||
|  | ||||
| wire load; | ||||
| assign load = req; | ||||
|  | ||||
| cy_psoc3_dp #(.cy_dpconfig( | ||||
| { | ||||
| 	`CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
| 	`CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
| 	`CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| 	`CS_CMP_SEL_CFGA, /*CFGRAM0:    */ | ||||
| 	`CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
| 	`CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
| 	`CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| 	`CS_CMP_SEL_CFGA, /*CFGRAM1:     */ | ||||
| 	`CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
| 	`CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
| 	`CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| 	`CS_CMP_SEL_CFGA, /*CFGRAM2:     */ | ||||
| 	`CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
| 	`CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
| 	`CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| 	`CS_CMP_SEL_CFGA, /*CFGRAM3:     */ | ||||
| 	`CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
| 	`CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
| 	`CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| 	`CS_CMP_SEL_CFGA, /*CFGRAM4:     */ | ||||
| 	`CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
| 	`CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
| 	`CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| 	`CS_CMP_SEL_CFGA, /*CFGRAM5:     */ | ||||
| 	`CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
| 	`CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
| 	`CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| 	`CS_CMP_SEL_CFGA, /*CFGRAM6:     */ | ||||
| 	`CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
| 	`CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
| 	`CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| 	`CS_CMP_SEL_CFGA, /*CFGRAM7:     */ | ||||
| 	8'hFF, 8'h00,	/*CFG9:     */ | ||||
| 	8'hFF, 8'hFF,	/*CFG11-10:     */ | ||||
| 	`SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH, | ||||
| 	`SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL, | ||||
| 	`SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI, | ||||
| 	`SC_SI_A_DEFSI, /*CFG13-12:     */ | ||||
| 	`SC_A0_SRC_PIN, `SC_SHIFT_SL, 1'h0, | ||||
| 	1'h0, `SC_FIFO1_BUS, `SC_FIFO0_ALU, | ||||
| 	`SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN, | ||||
| 	`SC_FB_NOCHN, `SC_CMP1_NOCHN, | ||||
| 	`SC_CMP0_NOCHN, /*CFG15-14:     */ | ||||
| 	10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX, | ||||
| 	`SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL, | ||||
| 	`SC_WRK16CAT_DSBL /*CFG17-16:     */ | ||||
| } | ||||
| )) dp( | ||||
| 	/* input          */ .clk(clk), | ||||
| 	/* input [02:00]  */ .cs_addr(3'b0),    // Program counter | ||||
| 	/* input          */ .route_si(1'b0),   // Shift in | ||||
| 	/* input          */ .route_ci(1'b0),   // Carry in | ||||
| 	/* input          */ .f0_load(load),    // Load FIFO 0 | ||||
| 	/* input          */ .f1_load(1'b0), 	// Load FIFO 1 | ||||
| 	/* input          */ .d0_load(1'b0), 	// Load Data Register 0 | ||||
| 	/* input          */ .d1_load(1'b0), 	// Load Data Register 1 | ||||
| 	/* output         */ .ce0(), 			// Accumulator 0 = Data register 0 | ||||
| 	/* output         */ .cl0(), 			// Accumulator 0 < Data register 0 | ||||
| 	/* output         */ .z0(), 			// Accumulator 0 = 0 | ||||
| 	/* output         */ .ff0(), 			// Accumulator 0 = FF | ||||
| 	/* output         */ .ce1(), 			// Accumulator [0|1] = Data register 1 | ||||
| 	/* output         */ .cl1(), 			// Accumulator [0|1] < Data register 1 | ||||
| 	/* output         */ .z1(), 			// Accumulator 1 = 0 | ||||
| 	/* output         */ .ff1(), 			// Accumulator 1 = FF | ||||
| 	/* output         */ .ov_msb(), 		// Operation over flow | ||||
| 	/* output         */ .co_msb(), 		// Carry out | ||||
| 	/* output         */ .cmsb(), 			// Carry out | ||||
| 	/* output         */ .so(), 			// Shift out | ||||
|     /* output         */ .f0_bus_stat(drq), // not empty | ||||
| 	/* output         */ .f0_blk_stat(full),// full | ||||
| 	/* output         */ .f1_bus_stat(), 	// FIFO 1 status to uP | ||||
| 	/* output         */ .f1_blk_stat(), 	// FIFO 1 status to DP | ||||
| 	/* input          */ .ci(1'b0), 		// Carry in from previous stage | ||||
| 	/* output         */ .co(), 			// Carry out to next stage | ||||
| 	/* input          */ .sir(1'b0), 		// Shift in from right side | ||||
| 	/* output         */ .sor(), 			// Shift out to right side | ||||
| 	/* input          */ .sil(1'b0), 		// Shift in from left side | ||||
| 	/* output         */ .sol(), 			// Shift out to left side | ||||
| 	/* input          */ .msbi(1'b0), 		// MSB chain in | ||||
| 	/* output         */ .msbo(), 			// MSB chain out | ||||
| 	/* input [01:00]  */ .cei(2'b0),        // Compare equal in from prev stage | ||||
| 	/* output [01:00] */ .ceo(),            // Compare equal out to next stage | ||||
| 	/* input [01:00]  */ .cli(2'b0), 	    // Compare less than in from prv stage | ||||
| 	/* output [01:00] */ .clo(),            // Compare less than out to next stage | ||||
| 	/* input [01:00]  */ .zi(2'b0),         // Zero detect in from previous stage | ||||
| 	/* output [01:00] */ .zo(),             // Zero detect out to next stage | ||||
| 	/* input [01:00]  */ .fi(2'b0), 		// 0xFF detect in from previous stage | ||||
| 	/* output [01:00] */ .fo(), 	        // 0xFF detect out to next stage | ||||
| 	/* input [01:00]  */ .capi(2'b0),	    // Capture in from previous stage | ||||
| 	/* output [01:00] */ .capo(),		    // Capture out to next stage | ||||
| 	/* input          */ .cfbi(1'b0), 		// CRC Feedback in from previous stage | ||||
| 	/* output         */ .cfbo(), 			// CRC Feedback out to next stage | ||||
| 	/* input [07:00]  */ .pi(pi), 		    // Parallel data port | ||||
| 	/* output [07:00] */ .po()              // Parallel data port | ||||
| ); | ||||
|  | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
| endmodule | ||||
| //`#start footer` -- edit after this line, do not edit this line | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -25,5 +25,3 @@ void `$INSTANCE_NAME`_Enable() | ||||
| void `$INSTANCE_NAME`_Disable() | ||||
| { | ||||
| } | ||||
|  | ||||
| /* [] END OF FILE */ | ||||
|   | ||||
| @@ -20,33 +20,34 @@ module FIFOout ( | ||||
| wire [7:0] po; | ||||
| assign d = po; | ||||
|  | ||||
| localparam STATE_WAITFORREQ    = 1'b0; | ||||
| localparam STATE_READ          = 1'b1; | ||||
| localparam STATE_WAITFORREQ = 0; | ||||
| localparam STATE_READFROMFIFO = 1; | ||||
| localparam STATE_WAITFORNREQ = 2; | ||||
|  | ||||
| reg state; | ||||
| reg oldreq; | ||||
| reg [1:0] state; | ||||
| wire readfromfifo; | ||||
|  | ||||
| assign ack = (state != STATE_READ); | ||||
| assign ack = (state == STATE_WAITFORNREQ); | ||||
| assign readfromfifo = (state == STATE_READFROMFIFO); | ||||
|  | ||||
| always @(posedge clk) | ||||
| begin | ||||
|     case (state) | ||||
|         /* opcode is not valid; req is low; wait for req to go high. */ | ||||
|         STATE_WAITFORREQ: | ||||
|         begin | ||||
|             if (!empty) | ||||
|             begin | ||||
|                 if (req && !oldreq) | ||||
|                 begin | ||||
|                     state <= STATE_READ; | ||||
|                 end | ||||
|                 oldreq <= req; | ||||
|             end | ||||
|             if (!empty && req) | ||||
|                 state <= STATE_READFROMFIFO; | ||||
|         end | ||||
|          | ||||
|         STATE_READ: | ||||
|         begin | ||||
|             state <= STATE_WAITFORREQ; | ||||
|         end | ||||
|         /* Fetch a single value from the FIFO. */ | ||||
|         STATE_READFROMFIFO: | ||||
|             state <= STATE_WAITFORNREQ; | ||||
|              | ||||
|         /* opcode is valid; ack is high. Wait for req to go low. */ | ||||
|         STATE_WAITFORNREQ: | ||||
|             if (!req) | ||||
|                 state <= STATE_WAITFORREQ; | ||||
|     endcase | ||||
| end | ||||
|              | ||||
| @@ -55,11 +56,11 @@ cy_psoc3_dp #(.cy_dpconfig( | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM0: STATE_WAITFORREQ*/ | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM0: idle */ | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC___F0, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM1: STATE_LOAD*/ | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM1: read from fifo */ | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
| @@ -102,7 +103,7 @@ cy_psoc3_dp #(.cy_dpconfig( | ||||
| )) dp( | ||||
|         /*  input                   */  .reset(1'b0), | ||||
|         /*  input                   */  .clk(clk), | ||||
|         /*  input   [02:00]         */  .cs_addr({2'b0, state}), | ||||
|         /*  input   [02:00]         */  .cs_addr({2'b0, readfromfifo}), | ||||
|         /*  input                   */  .route_si(1'b0), | ||||
|         /*  input                   */  .route_ci(1'b0), | ||||
|         /*  input                   */  .f0_load(1'b0), | ||||
|   | ||||
| @@ -52,6 +52,30 @@ | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="3f3708ae-fb62-4012-919b-9a3b9a1dfbc2"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
|         <Data key="derive_type" value="NAMED_DIVIDER" /> | ||||
|         <Data key="desired_freq" value="0" /> | ||||
|         <Data key="desired_unit" value="15" /> | ||||
|         <Data key="divider" value="0" /> | ||||
|         <Data key="domain" value="DIGITAL" /> | ||||
|         <Data key="enabled" value="True" /> | ||||
|         <Data key="minus_accuracy" value="0.25" /> | ||||
|         <Data key="minus_tolerance" value="5" /> | ||||
|         <Data key="name" value="Clock_8" /> | ||||
|         <Data key="named_src_direct_connect" value="True" /> | ||||
|         <Data key="netlist_name" value="Clock_8" /> | ||||
|         <Data key="placement" value="AUTO" /> | ||||
|         <Data key="plus_accuracy" value="0.25" /> | ||||
|         <Data key="plus_tolerance" value="5" /> | ||||
|         <Data key="scope" value="LOCAL" /> | ||||
|         <Data key="src_clk_id" value="75C2148C-3656-4d8a-846D-0CAE99AB6FF7" /> | ||||
|         <Data key="src_clk_name" value="BUS_CLK" /> | ||||
|         <Data key="start_on_reset" value="True" /> | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="4eef02b9-8ad1-43c4-85f1-b3335faa5fc4"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
| @@ -171,6 +195,54 @@ | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="71bc291d-84a7-40a8-b7b2-1c8a34326a31"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
|         <Data key="derive_type" value="NAMED_FREQ" /> | ||||
|         <Data key="desired_freq" value="300" /> | ||||
|         <Data key="desired_unit" value="0" /> | ||||
|         <Data key="divider" value="65536" /> | ||||
|         <Data key="domain" value="DIGITAL" /> | ||||
|         <Data key="enabled" value="True" /> | ||||
|         <Data key="minus_accuracy" value="0.25" /> | ||||
|         <Data key="minus_tolerance" value="5" /> | ||||
|         <Data key="name" value="CLOCK300" /> | ||||
|         <Data key="named_src_direct_connect" value="False" /> | ||||
|         <Data key="netlist_name" value="CLOCK300" /> | ||||
|         <Data key="placement" value="AUTO" /> | ||||
|         <Data key="plus_accuracy" value="0.25" /> | ||||
|         <Data key="plus_tolerance" value="5" /> | ||||
|         <Data key="scope" value="LOCAL" /> | ||||
|         <Data key="src_clk_id" value="CEF43CFB-0213-49b9-B980-2FFAB81C5B47" /> | ||||
|         <Data key="src_clk_name" value="IMO" /> | ||||
|         <Data key="start_on_reset" value="True" /> | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="90ce0c72-9f10-44ef-a049-f0f525d59bea"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
|         <Data key="derive_type" value="NAMED_FREQ" /> | ||||
|         <Data key="desired_freq" value="128" /> | ||||
|         <Data key="desired_unit" value="0" /> | ||||
|         <Data key="divider" value="65536" /> | ||||
|         <Data key="domain" value="DIGITAL" /> | ||||
|         <Data key="enabled" value="True" /> | ||||
|         <Data key="minus_accuracy" value="0.25" /> | ||||
|         <Data key="minus_tolerance" value="5" /> | ||||
|         <Data key="name" value="CLOCK8" /> | ||||
|         <Data key="named_src_direct_connect" value="False" /> | ||||
|         <Data key="netlist_name" value="CLOCK8" /> | ||||
|         <Data key="placement" value="AUTO" /> | ||||
|         <Data key="plus_accuracy" value="0.25" /> | ||||
|         <Data key="plus_tolerance" value="5" /> | ||||
|         <Data key="scope" value="LOCAL" /> | ||||
|         <Data key="src_clk_id" value="CEF43CFB-0213-49b9-B980-2FFAB81C5B47" /> | ||||
|         <Data key="src_clk_name" value="IMO" /> | ||||
|         <Data key="start_on_reset" value="True" /> | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="349ffa20-8576-4ac3-9a6f-34ef606de6cf"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
| @@ -194,6 +266,29 @@ | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="4033c29d-f4bc-4e94-ac95-aa587e869f88/696a0979-21fc-4185-bf38-6c79febcde7a"> | ||||
|         <Data key="check_tolerance" value="False" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
|         <Data key="derive_type" value="AUTO" /> | ||||
|         <Data key="desired_freq" value="1600000" /> | ||||
|         <Data key="desired_unit" value="0" /> | ||||
|         <Data key="divider" value="40" /> | ||||
|         <Data key="domain" value="DIGITAL" /> | ||||
|         <Data key="enabled" value="True" /> | ||||
|         <Data key="minus_accuracy" value="0.25" /> | ||||
|         <Data key="minus_tolerance" value="5" /> | ||||
|         <Data key="name" value="OUTPUT_VOLTAGE_ADC_theACLK" /> | ||||
|         <Data key="netlist_name" value="\OUTPUT_VOLTAGE_ADC:theACLK\" /> | ||||
|         <Data key="placement" value="AUTO" /> | ||||
|         <Data key="plus_accuracy" value="0.25" /> | ||||
|         <Data key="plus_tolerance" value="5" /> | ||||
|         <Data key="scope" value="LOCAL" /> | ||||
|         <Data key="src_clk_id" value="61737EF6-3B74-48f9-8B91-F7473A442AE7" /> | ||||
|         <Data key="src_clk_name" value="MASTER_CLK" /> | ||||
|         <Data key="start_on_reset" value="True" /> | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="6616e828-6611-4893-a674-66c861d79d6c"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
| @@ -265,6 +360,53 @@ | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="09974428-e912-491f-8d2f-361ba50e7599"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
|         <Data key="derive_type" value="NAMED_DIVIDER" /> | ||||
|         <Data key="desired_freq" value="0" /> | ||||
|         <Data key="desired_unit" value="15" /> | ||||
|         <Data key="divider" value="0" /> | ||||
|         <Data key="domain" value="DIGITAL" /> | ||||
|         <Data key="enabled" value="True" /> | ||||
|         <Data key="minus_accuracy" value="0.25" /> | ||||
|         <Data key="minus_tolerance" value="5" /> | ||||
|         <Data key="name" value="Clock_6" /> | ||||
|         <Data key="named_src_direct_connect" value="True" /> | ||||
|         <Data key="netlist_name" value="Clock_6" /> | ||||
|         <Data key="placement" value="AUTO" /> | ||||
|         <Data key="plus_accuracy" value="0.25" /> | ||||
|         <Data key="plus_tolerance" value="5" /> | ||||
|         <Data key="scope" value="LOCAL" /> | ||||
|         <Data key="src_clk_id" value="75C2148C-3656-4d8a-846D-0CAE99AB6FF7" /> | ||||
|         <Data key="src_clk_name" value="BUS_CLK" /> | ||||
|         <Data key="start_on_reset" value="True" /> | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="a5825a94-fa18-4e4f-a843-bc687cacbd56/696a0979-21fc-4185-bf38-6c79febcde7a"> | ||||
|         <Data key="check_tolerance" value="False" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
|         <Data key="derive_type" value="AUTO" /> | ||||
|         <Data key="desired_freq" value="1600000" /> | ||||
|         <Data key="desired_unit" value="0" /> | ||||
|         <Data key="divider" value="40" /> | ||||
|         <Data key="domain" value="DIGITAL" /> | ||||
|         <Data key="enabled" value="True" /> | ||||
|         <Data key="minus_accuracy" value="0.25" /> | ||||
|         <Data key="minus_tolerance" value="5" /> | ||||
|         <Data key="name" value="INPUT_VOLTAGE_ADC_theACLK" /> | ||||
|         <Data key="netlist_name" value="\INPUT_VOLTAGE_ADC:theACLK\" /> | ||||
|         <Data key="placement" value="AUTO" /> | ||||
|         <Data key="plus_accuracy" value="0.25" /> | ||||
|         <Data key="plus_tolerance" value="5" /> | ||||
|         <Data key="scope" value="LOCAL" /> | ||||
|         <Data key="src_clk_id" value="61737EF6-3B74-48f9-8B91-F7473A442AE7" /> | ||||
|         <Data key="src_clk_name" value="MASTER_CLK" /> | ||||
|         <Data key="start_on_reset" value="True" /> | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="b762c287-7f87-4b21-982e-84be01dc5115"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
| @@ -312,6 +454,30 @@ | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="b722443b-8f81-46dc-bf9b-c95eb62bc181"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
|         <Data key="derive_type" value="NAMED_DIVIDER" /> | ||||
|         <Data key="desired_freq" value="0" /> | ||||
|         <Data key="desired_unit" value="15" /> | ||||
|         <Data key="divider" value="0" /> | ||||
|         <Data key="domain" value="DIGITAL" /> | ||||
|         <Data key="enabled" value="True" /> | ||||
|         <Data key="minus_accuracy" value="0.25" /> | ||||
|         <Data key="minus_tolerance" value="5" /> | ||||
|         <Data key="name" value="Clock_1" /> | ||||
|         <Data key="named_src_direct_connect" value="True" /> | ||||
|         <Data key="netlist_name" value="Clock_1" /> | ||||
|         <Data key="placement" value="AUTO" /> | ||||
|         <Data key="plus_accuracy" value="0.25" /> | ||||
|         <Data key="plus_tolerance" value="5" /> | ||||
|         <Data key="scope" value="LOCAL" /> | ||||
|         <Data key="src_clk_id" value="75C2148C-3656-4d8a-846D-0CAE99AB6FF7" /> | ||||
|         <Data key="src_clk_name" value="BUS_CLK" /> | ||||
|         <Data key="start_on_reset" value="True" /> | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="cb7e877c-9fb4-4fc1-a708-f1e48eb5a68c"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
| @@ -336,6 +502,30 @@ | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="d3075dc6-05c8-4dc9-9959-cf7014c0e66f"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
|         <Data key="derive_type" value="NAMED_DIVIDER" /> | ||||
|         <Data key="desired_freq" value="0" /> | ||||
|         <Data key="desired_unit" value="15" /> | ||||
|         <Data key="divider" value="0" /> | ||||
|         <Data key="domain" value="DIGITAL" /> | ||||
|         <Data key="enabled" value="True" /> | ||||
|         <Data key="minus_accuracy" value="0.25" /> | ||||
|         <Data key="minus_tolerance" value="5" /> | ||||
|         <Data key="name" value="Clock_7" /> | ||||
|         <Data key="named_src_direct_connect" value="True" /> | ||||
|         <Data key="netlist_name" value="Clock_7" /> | ||||
|         <Data key="placement" value="AUTO" /> | ||||
|         <Data key="plus_accuracy" value="0.25" /> | ||||
|         <Data key="plus_tolerance" value="5" /> | ||||
|         <Data key="scope" value="LOCAL" /> | ||||
|         <Data key="src_clk_id" value="75C2148C-3656-4d8a-846D-0CAE99AB6FF7" /> | ||||
|         <Data key="src_clk_name" value="BUS_CLK" /> | ||||
|         <Data key="start_on_reset" value="True" /> | ||||
|         <Data key="sync_with_bus_clk" value="True" /> | ||||
|         <Data key="user_set_domain" value="False" /> | ||||
|       </Group> | ||||
|       <Group key="e4a53a4c-40e1-4747-a72a-10193ffdf31c"> | ||||
|         <Data key="check_tolerance" value="True" /> | ||||
|         <Data key="clock_version" value="v1" /> | ||||
| @@ -634,18 +824,26 @@ | ||||
|     <Group key="Clock"> | ||||
|       <Data key="0b2f9bbb-00ce-4115-a788-ffb9d046a9e5" value="Clock_4" /> | ||||
|       <Data key="1a7e8637-3b6b-4e84-839c-0dfc18fdaf5b" value="Clock_5" /> | ||||
|       <Data key="3f3708ae-fb62-4012-919b-9a3b9a1dfbc2" value="Clock_8" /> | ||||
|       <Data key="4eef02b9-8ad1-43c4-85f1-b3335faa5fc4" value="Clock_3" /> | ||||
|       <Data key="06c4d5d4-f15f-4b29-a1d0-c24b2e38b1ec" value="CounterClock" /> | ||||
|       <Data key="24cd38f7-f472-4403-837f-86807c8f5333" value="PULSE_CLOCK" /> | ||||
|       <Data key="63ed4137-0b09-4256-8a27-35c9a2653f1a" value="Clock_2" /> | ||||
|       <Data key="66f14071-bddd-4b4d-a9aa-a129cceaa7b6" value="Clock_3" /> | ||||
|       <Data key="71bc291d-84a7-40a8-b7b2-1c8a34326a31" value="CLOCK300" /> | ||||
|       <Data key="90ce0c72-9f10-44ef-a049-f0f525d59bea" value="CLOCK8" /> | ||||
|       <Data key="349ffa20-8576-4ac3-9a6f-34ef606de6cf" value="Clock_1" /> | ||||
|       <Data key="4033c29d-f4bc-4e94-ac95-aa587e869f88/696a0979-21fc-4185-bf38-6c79febcde7a" value="OUTPUT_VOLTAGE_ADC_theACLK" /> | ||||
|       <Data key="6616e828-6611-4893-a674-66c861d79d6c" value="SignalSamplingClock" /> | ||||
|       <Data key="12664fc6-9d70-44b1-8a49-887a292e1b7f" value="Clock_3" /> | ||||
|       <Data key="75187c05-9501-4450-b306-6ccdd3bb77db" value="Clock_5" /> | ||||
|       <Data key="09974428-e912-491f-8d2f-361ba50e7599" value="Clock_6" /> | ||||
|       <Data key="a5825a94-fa18-4e4f-a843-bc687cacbd56/696a0979-21fc-4185-bf38-6c79febcde7a" value="INPUT_VOLTAGE_ADC_theACLK" /> | ||||
|       <Data key="b762c287-7f87-4b21-982e-84be01dc5115" value="Clock_2" /> | ||||
|       <Data key="b0162966-0060-4af5-82d1-fcb491ad7619/be0a0e37-ad17-42ca-b5a1-1a654d736358" value="UART_IntClock" /> | ||||
|       <Data key="b722443b-8f81-46dc-bf9b-c95eb62bc181" value="Clock_1" /> | ||||
|       <Data key="cb7e877c-9fb4-4fc1-a708-f1e48eb5a68c" value="CounterClock" /> | ||||
|       <Data key="d3075dc6-05c8-4dc9-9959-cf7014c0e66f" value="Clock_7" /> | ||||
|       <Data key="e4a53a4c-40e1-4747-a72a-10193ffdf31c" value="Clock_1" /> | ||||
|       <Data key="efd5f185-0c32-4824-ba72-3ceb5356f5a7" value="Clock_1" /> | ||||
|     </Group> | ||||
| @@ -653,6 +851,7 @@ | ||||
|       <Data key="4a398466-709f-4228-9500-96178658e13e" value="RDATA" /> | ||||
|       <Data key="5a3407c1-b434-4438-a7b4-b9dfd2280495" value="MOTEA" /> | ||||
|       <Data key="8d318d8b-cf7b-4b6b-b02c-ab1c5c49d0ba" value="SW1" /> | ||||
|       <Data key="8fc20a4f-e4d1-44b3-a5d4-546e8628d61e" value="LED" /> | ||||
|       <Data key="12e00eac-69b5-4717-85c8-25ef6b224d4c" value="DEBUG_PINS" /> | ||||
|       <Data key="41e2d8ed-5494-4d8c-8ff7-f4f789cece51" value="REDWC" /> | ||||
|       <Data key="264be2d3-9481-494b-8d9c-c1905a45e9cc" value="FDD" /> | ||||
| @@ -670,10 +869,11 @@ | ||||
|       <Data key="c5367cde-21d5-4866-9a32-d16abfea0c61" value="WPT" /> | ||||
|       <Data key="d19368c5-6855-41bb-a9ff-808938abef00" value="INDEX" /> | ||||
|       <Data key="e9f14b5a-b2bf-49b8-98f3-d7b5a43ace8d" value="DRVSB" /> | ||||
|       <Data key="e851a3b9-efb8-48be-bbb8-b303b216c393" value="LED_PIN" /> | ||||
|       <Data key="e851a3b9-efb8-48be-bbb8-b303b216c393" value="INDEX300" /> | ||||
|       <Data key="e51063a9-4fad-40c7-a06b-7cc4b137dc18" value="DSKCHG" /> | ||||
|       <Data key="ea7ee228-8b3f-426c-8bb8-cd7a81937769" value="DIR" /> | ||||
|       <Data key="ed092b9b-d398-4703-be89-cebf998501f6" value="UartTx" /> | ||||
|       <Data key="f9a7371a-8a7d-4144-8b08-69e3d2a3a663" value="INDEX360" /> | ||||
|       <Data key="fbd1f839-40f9-498e-a48b-5f3048ea5c3d/52f31aa9-2f0a-497d-9a1f-1424095e13e6" value="UART_tx" /> | ||||
|       <Data key="fede1767-f3fd-4021-b3d7-8f9d88f36f9b" value="DRVSA" /> | ||||
|       <Data key="fff78075-035e-43d7-8577-bc5be4d21926" value="WGATE" /> | ||||
| @@ -3778,6 +3978,11 @@ | ||||
|         <Data key="Port Format" value="2,2" /> | ||||
|       </Group> | ||||
|     </Group> | ||||
|     <Group key="8fc20a4f-e4d1-44b3-a5d4-546e8628d61e"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="2,1" /> | ||||
|       </Group> | ||||
|     </Group> | ||||
|     <Group key="12e00eac-69b5-4717-85c8-25ef6b224d4c"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="2,2" /> | ||||
| @@ -3946,7 +4151,7 @@ | ||||
|     </Group> | ||||
|     <Group key="e851a3b9-efb8-48be-bbb8-b303b216c393"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="2,1" /> | ||||
|         <Data key="Port Format" value="3,0" /> | ||||
|       </Group> | ||||
|     </Group> | ||||
|     <Group key="e51063a9-4fad-40c7-a06b-7cc4b137dc18"> | ||||
| @@ -3964,6 +4169,11 @@ | ||||
|         <Data key="Port Format" value="12,7" /> | ||||
|       </Group> | ||||
|     </Group> | ||||
|     <Group key="f9a7371a-8a7d-4144-8b08-69e3d2a3a663"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="3,1" /> | ||||
|       </Group> | ||||
|     </Group> | ||||
|     <Group key="fbd1f839-40f9-498e-a48b-5f3048ea5c3d/52f31aa9-2f0a-497d-9a1f-1424095e13e6"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="12,7" /> | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										111
									
								
								FluxEngine.cydsn/Sampler/Sampler.v
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								FluxEngine.cydsn/Sampler/Sampler.v
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
|  | ||||
| //`#start header` -- edit after this line, do not edit this line | ||||
| `include "cypress.v" | ||||
| `include "../SuperCounter/SuperCounter.v" | ||||
|  | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
| // Generated on 12/11/2019 at 21:18 | ||||
| // Component: Sampler | ||||
| module Sampler ( | ||||
| 	output [2:0] debug_state, | ||||
| 	output reg [7:0] opcode, | ||||
| 	output  req, | ||||
| 	input   clock, | ||||
| 	input   index, | ||||
| 	input   rdata, | ||||
| 	input   reset, | ||||
| 	input   sampleclock | ||||
| ); | ||||
|  | ||||
| //`#start body` -- edit after this line, do not edit this line | ||||
|  | ||||
| localparam STATE_RESET = 0; | ||||
| localparam STATE_WAITING = 1; | ||||
| localparam STATE_OPCODE = 2; | ||||
|  | ||||
| reg [1:0] state; | ||||
| reg [6:0] counter; | ||||
|  | ||||
| reg oldsampleclock; | ||||
| wire sampleclocked; | ||||
| assign sampleclocked = !oldsampleclock && sampleclock; | ||||
|  | ||||
| reg oldindex; | ||||
| wire indexed; | ||||
| assign indexed = !oldindex && index; | ||||
|  | ||||
| wire rdataed; | ||||
| reg oldrdata; | ||||
| assign rdataed = !oldrdata && rdata; | ||||
|  | ||||
| assign req = (state == STATE_OPCODE); | ||||
|  | ||||
| always @(posedge clock) | ||||
| begin | ||||
|     if (reset) | ||||
|     begin | ||||
|         state <= STATE_RESET; | ||||
|         opcode <= 0; | ||||
|         oldsampleclock <= 0; | ||||
|         oldindex <= 0; | ||||
|         oldrdata <= 0; | ||||
|         counter <= 0; | ||||
|     end | ||||
|     else | ||||
|         case (state) | ||||
|             STATE_RESET: | ||||
|                 state <= STATE_WAITING; | ||||
|              | ||||
|             STATE_WAITING: | ||||
|             begin | ||||
|                 /* If something has happened, emit any necessary interval byte. */ | ||||
|                 if ((rdataed || indexed) && (counter != 0)) | ||||
|                 begin | ||||
|                     opcode <= {0, counter}; | ||||
|                     state <= STATE_OPCODE; | ||||
|                 end | ||||
|                 else if (indexed) | ||||
|                 begin | ||||
|                     oldindex <= 1; | ||||
|                     opcode <= 8'h81; | ||||
|                     state <= STATE_OPCODE; | ||||
|                 end | ||||
|                 else if (rdataed) | ||||
|                 begin | ||||
|                     oldrdata <= 1; | ||||
|                     opcode <= 8'h80; | ||||
|                     state <= STATE_OPCODE; | ||||
|                 end | ||||
|                 else if (sampleclocked) | ||||
|                 begin | ||||
|                     oldsampleclock <= 1; | ||||
|                     if (counter == 7'h7f) | ||||
|                     begin | ||||
|                         opcode <= {0, counter}; | ||||
|                         state <= STATE_OPCODE; | ||||
|                     end | ||||
|                     counter <= counter + 1; | ||||
|                 end | ||||
|                  | ||||
|                 /* Reset state once we've done the thing. */ | ||||
|                  | ||||
|                 if (oldrdata && !rdata) | ||||
|                     oldrdata <= 0; | ||||
|                 if (oldindex && !index) | ||||
|                     oldindex <= 0; | ||||
|                 if (oldsampleclock && !sampleclock) | ||||
|                     oldsampleclock <= 0; | ||||
|             end | ||||
|              | ||||
|             STATE_OPCODE: /* opcode or interval byte sent here */ | ||||
|             begin | ||||
|                 state <= STATE_WAITING; | ||||
|                 counter <= 0; | ||||
|             end | ||||
|         endcase | ||||
| end | ||||
|  | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
| endmodule | ||||
| //`#start footer` -- edit after this line, do not edit this line | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
| @@ -18,19 +18,18 @@ module Sequencer ( | ||||
|  | ||||
| //`#start body` -- edit after this line, do not edit this line | ||||
|  | ||||
| localparam STATE_IDLE = 0; | ||||
| localparam STATE_LOAD = 1; | ||||
| localparam STATE_WAITING = 2; | ||||
| localparam STATE_PULSING = 3; | ||||
| localparam STATE_INDEXING = 4; | ||||
| localparam STATE_LOAD = 0; | ||||
| localparam STATE_WAITING = 1; | ||||
| localparam STATE_PULSING = 2; | ||||
| localparam STATE_INDEXING = 3; | ||||
|  | ||||
| localparam OPCODE_PULSE = 8'h80; | ||||
| localparam OPCODE_INDEX = 8'h81; | ||||
|  | ||||
| reg [2:0] state; | ||||
| reg [1:0] state; | ||||
| reg [6:0] countdown; | ||||
|  | ||||
| assign req = (state == STATE_LOAD); | ||||
| assign req = (!reset && (state == STATE_LOAD)); | ||||
| assign wdata = (state == STATE_PULSING); | ||||
| assign debug_state = state; | ||||
|  | ||||
| @@ -40,9 +39,7 @@ always @(posedge clock) olddataclock <= dataclock; | ||||
| assign dataclocked = !olddataclock && dataclock; | ||||
|  | ||||
| reg oldsampleclock; | ||||
| wire sampleclocked; | ||||
| always @(posedge clock) oldsampleclock <= sampleclock; | ||||
| assign sampleclocked = !oldsampleclock && sampleclock; | ||||
| reg sampleclocked; | ||||
|  | ||||
| reg oldindex; | ||||
| wire indexed; | ||||
| @@ -53,15 +50,19 @@ always @(posedge clock) | ||||
| begin | ||||
|     if (reset) | ||||
|     begin | ||||
|         state <= STATE_IDLE; | ||||
|         state <= STATE_LOAD; | ||||
|         countdown <= 0; | ||||
|     end | ||||
|     else | ||||
|     begin | ||||
|         if (!oldsampleclock && sampleclock) | ||||
|             sampleclocked <= 1; | ||||
|         oldsampleclock <= sampleclock; | ||||
|          | ||||
|         case (state) | ||||
|             STATE_IDLE: | ||||
|                 state <= STATE_LOAD; | ||||
|              | ||||
|             STATE_LOAD: | ||||
|                 /* Wait for a posedge on dataclocked, indicating an opcode has | ||||
|                  * arrived. */ | ||||
|                 if (dataclocked) | ||||
|                     case (opcode) | ||||
|                         OPCODE_PULSE: | ||||
| @@ -80,10 +81,12 @@ begin | ||||
|             STATE_WAITING: | ||||
|                 if (sampleclocked) | ||||
|                 begin | ||||
|                     if (countdown == 0) | ||||
|                     sampleclocked <= 0; | ||||
|                     countdown <= countdown - 1; | ||||
|                     /* Nasty fudge factor here to account for one to two | ||||
|                      * sample ticks lost per pulse. */ | ||||
|                     if (countdown <= 2) | ||||
|                         state <= STATE_LOAD; | ||||
|                     else | ||||
|                         countdown <= countdown - 1; | ||||
|                 end | ||||
|              | ||||
|             STATE_PULSING: | ||||
| @@ -93,6 +96,7 @@ begin | ||||
|                 if (indexed) | ||||
|                     state <= STATE_LOAD; | ||||
|         endcase | ||||
|     end | ||||
| end | ||||
|  | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								FluxEngine.cydsn/SuperCounter/SuperCounter.cysym
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								FluxEngine.cydsn/SuperCounter/SuperCounter.cysym
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										156
									
								
								FluxEngine.cydsn/SuperCounter/SuperCounter.v
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								FluxEngine.cydsn/SuperCounter/SuperCounter.v
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
|  | ||||
| //`#start header` -- edit after this line, do not edit this line | ||||
| `include "cypress.v" | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
| // Generated on 11/16/2017 at 15:44 | ||||
| // Component: FIFOout | ||||
| module SuperCounter ( | ||||
| 	input clk, | ||||
|     input reset, | ||||
|     input count, | ||||
|     output [7:0] d, | ||||
| 	output drq, | ||||
| 	output empty, | ||||
|     output ack | ||||
| ); | ||||
|  | ||||
| //`#start body` -- edit after this line, do not edit this line | ||||
|  | ||||
| parameter ResetValue = 0; | ||||
| parameter Delta = 1; | ||||
|      | ||||
| wire [7:0] po; | ||||
| assign d = po; | ||||
|  | ||||
| localparam STATE_RESET = 0; | ||||
| localparam STATE_WAIT = 1; | ||||
| localparam STATE_ADD = 2; | ||||
|  | ||||
| reg oldcount; | ||||
| wire counted; | ||||
| assign counted = count && !oldcount; | ||||
|  | ||||
| always @(posedge clk) oldcount <= count; | ||||
|  | ||||
| wire [2:0] cs; | ||||
| assign cs = reset ? STATE_RESET : (counted ? STATE_ADD : STATE_WAIT); | ||||
|              | ||||
| cy_psoc3_dp #(.d0_init(ResetValue), .d1_init(Delta),  | ||||
| .cy_dpconfig( | ||||
| { | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC___D0, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM0:  STATE_RESET*/ | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM1:  STATE_WAIT*/ | ||||
|     `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D1, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM2:  STATE_ADD*/ | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM3:             */ | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM4:             */ | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM5:             */ | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM6:             */ | ||||
|     `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, | ||||
|     `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, | ||||
|     `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, | ||||
|     `CS_CMP_SEL_CFGA, /*CFGRAM7:             */ | ||||
|     8'hFF, 8'h00,  /*CFG9:             */ | ||||
|     8'hFF, 8'hFF,  /*CFG11-10:             */ | ||||
|     `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH, | ||||
|     `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL, | ||||
|     `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI, | ||||
|     `SC_SI_A_DEFSI, /*CFG13-12:             */ | ||||
|     `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0, | ||||
|     1'h0, `SC_FIFO1_BUS, `SC_FIFO0_BUS, | ||||
|     `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN, | ||||
|     `SC_FB_NOCHN, `SC_CMP1_NOCHN, | ||||
|     `SC_CMP0_NOCHN, /*CFG15-14:             */ | ||||
|     10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX, | ||||
|     `SC_FIFO_LEVEL,`SC_FIFO_ASYNC,`SC_EXTCRC_DSBL, | ||||
|     `SC_WRK16CAT_DSBL /*CFG17-16:             */ | ||||
| } | ||||
| )) dp( | ||||
|         /*  input                   */  .reset(1'b0), | ||||
|         /*  input                   */  .clk(clk), | ||||
|         /*  input   [02:00]         */  .cs_addr(cs), | ||||
|         /*  input                   */  .route_si(1'b0), | ||||
|         /*  input                   */  .route_ci(1'b0), | ||||
|         /*  input                   */  .f0_load(1'b0), | ||||
|         /*  input                   */  .f1_load(1'b0), | ||||
|         /*  input                   */  .d0_load(1'b0), | ||||
|         /*  input                   */  .d1_load(1'b0), | ||||
|         /*  output                  */  .ce0(), | ||||
|         /*  output                  */  .cl0(), | ||||
|         /*  output                  */  .z0(), | ||||
|         /*  output                  */  .ff0(), | ||||
|         /*  output                  */  .ce1(), | ||||
|         /*  output                  */  .cl1(), | ||||
|         /*  output                  */  .z1(), | ||||
|         /*  output                  */  .ff1(), | ||||
|         /*  output                  */  .ov_msb(), | ||||
|         /*  output                  */  .co_msb(), | ||||
|         /*  output                  */  .cmsb(), | ||||
|         /*  output                  */  .so(), | ||||
|         /*  output                  */  .f0_bus_stat(), | ||||
|         /*  output                  */  .f0_blk_stat(), | ||||
|         /*  output                  */  .f1_bus_stat(), | ||||
|         /*  output                  */  .f1_blk_stat(), | ||||
|          | ||||
|         /* input                    */  .ci(1'b0),     // Carry in from previous stage | ||||
|         /* output                   */  .co(),// Carry out to next stage | ||||
|         /* input                    */  .sir(1'b0),    // Shift in from right side | ||||
|         /* output                   */  .sor(),        // Shift out to right side | ||||
|         /* input                    */  .sil(1'b0),    // Shift in from left side | ||||
|         /* output                   */  .sol(),        // Shift out to left side | ||||
|         /* input                    */  .msbi(1'b0),   // MSB chain in | ||||
|         /* output                   */  .msbo(),       // MSB chain out | ||||
|         /* input [01:00]            */  .cei(2'b0),    // Compare equal in from prev stage | ||||
|         /* output [01:00]           */  .ceo(),        // Compare equal out to next stage | ||||
|         /* input [01:00]            */  .cli(2'b0),    // Compare less than in from prv stage | ||||
|         /* output [01:00]           */  .clo(),        // Compare less than out to next stage | ||||
|         /* input [01:00]            */  .zi(2'b0),     // Zero detect in from previous stage | ||||
|         /* output [01:00]           */  .zo(),         // Zero detect out to next stage | ||||
|         /* input [01:00]            */  .fi(2'b0),     // 0xFF detect in from previous stage | ||||
|         /* output [01:00]           */  .fo(),         // 0xFF detect out to next stage | ||||
|         /* input [01:00]            */  .capi(2'b0),   // Software capture from previous stage | ||||
|         /* output [01:00]           */  .capo(),       // Software capture to next stage | ||||
|         /* input                    */  .cfbi(1'b0),   // CRC Feedback in from previous stage | ||||
|         /* output                   */  .cfbo(),       // CRC Feedback out to next stage | ||||
|         /* input [07:00]            */  .pi(8'b0),     // Parallel data port | ||||
|         /* output [07:00]           */  .po(po)       // Parallel data port | ||||
| ); | ||||
|  | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
| endmodule | ||||
| //`#start footer` -- edit after this line, do not edit this line | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -17,20 +17,24 @@ | ||||
| #define STEP_TOWARDS0 1 | ||||
| #define STEP_AWAYFROM0 0 | ||||
|  | ||||
| static volatile uint32_t clock = 0; | ||||
| static bool drive0_present; | ||||
| static bool drive1_present; | ||||
|  | ||||
| static volatile uint32_t clock = 0; /* ms */ | ||||
| static volatile bool index_irq = false; | ||||
|  | ||||
| static bool motor_on = false; | ||||
| static uint32_t motor_on_time = 0; | ||||
| static bool homed = false; | ||||
| static int current_track = 0; | ||||
| static uint8_t current_drive_flags = 0; | ||||
| static struct set_drive_frame current_drive_flags; | ||||
|  | ||||
| #define BUFFER_COUNT 16 | ||||
| #define BUFFER_COUNT 64 /* the maximum */ | ||||
| #define BUFFER_SIZE 64 | ||||
| static uint8_t td[BUFFER_COUNT]; | ||||
| static uint8_t dma_buffer[BUFFER_COUNT][BUFFER_SIZE] __attribute__((aligned())); | ||||
| static uint8_t usb_buffer[BUFFER_SIZE] __attribute__((aligned())); | ||||
| static uint8_t xfer_buffer[BUFFER_SIZE] __attribute__((aligned())); | ||||
| static uint8_t dma_channel; | ||||
| #define NEXT_BUFFER(b) (((b)+1) % BUFFER_COUNT) | ||||
|  | ||||
| @@ -41,10 +45,27 @@ static volatile bool dma_underrun = false; | ||||
| #define DECLARE_REPLY_FRAME(STRUCT, TYPE) \ | ||||
|     STRUCT r = {.f = { .type = TYPE, .size = sizeof(STRUCT) }} | ||||
|  | ||||
| static void stop_motor(void); | ||||
|  | ||||
| static void system_timer_cb(void) | ||||
| { | ||||
|     CyGlobalIntDisable; | ||||
|     clock++; | ||||
|      | ||||
|     static int counter300rpm = 0; | ||||
|     counter300rpm++; | ||||
|     if (counter300rpm == 200) | ||||
|         counter300rpm = 0; | ||||
|      | ||||
|     static int counter360rpm = 0; | ||||
|     counter360rpm++; | ||||
|     if (counter360rpm == 167) | ||||
|         counter360rpm = 0; | ||||
|      | ||||
|     FAKE_INDEX_GENERATOR_REG_Write( | ||||
|         ((counter300rpm == 0) ? 1 : 0) | ||||
|         | ((counter360rpm == 0) ? 2 : 0)); | ||||
|      | ||||
|     CyGlobalIntEnable; | ||||
| } | ||||
|  | ||||
| @@ -85,10 +106,25 @@ static void print(const char* msg, ...) | ||||
|     UART_PutCRLF(); | ||||
| } | ||||
|  | ||||
| static void set_drive_flags(struct set_drive_frame* flags) | ||||
| { | ||||
|     if (current_drive_flags.drive != flags->drive) | ||||
|     { | ||||
|         stop_motor(); | ||||
|         homed = false; | ||||
|     } | ||||
|      | ||||
|     current_drive_flags = *flags; | ||||
|     DRIVESELECT_REG_Write(flags->drive ? 2 : 1); /* select drive 1 or 0 */ | ||||
|     DENSITY_REG_Write(flags->high_density); /* density bit */ | ||||
|     INDEX_REG_Write(flags->index_mode); | ||||
| } | ||||
|  | ||||
| static void start_motor(void) | ||||
| { | ||||
|     if (!motor_on) | ||||
|     { | ||||
|         set_drive_flags(¤t_drive_flags); | ||||
|         MOTOR_REG_Write(1); | ||||
|         CyDelay(1000); | ||||
|         homed = false; | ||||
| @@ -99,6 +135,16 @@ static void start_motor(void) | ||||
|     CyWdtClear(); | ||||
| } | ||||
|  | ||||
| static void stop_motor(void) | ||||
| { | ||||
|     if (motor_on) | ||||
|     { | ||||
|         MOTOR_REG_Write(0); | ||||
|         DRIVESELECT_REG_Write(0); /* deselect all drives */ | ||||
|         motor_on = false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void wait_until_writeable(int ep) | ||||
| { | ||||
|     while (USBFS_GetEPState(ep) != USBFS_IN_BUFFER_EMPTY) | ||||
| @@ -138,25 +184,36 @@ static void cmd_get_version(struct any_frame* f) | ||||
|  | ||||
| static void step(int dir) | ||||
| { | ||||
|     STEP_REG_Write(dir); | ||||
|     CyDelayUs(1); | ||||
|     STEP_REG_Write(dir | 2); | ||||
|     CyDelayUs(1); | ||||
|     STEP_REG_Write(dir); | ||||
|     STEP_REG_Write(dir); /* step high */ | ||||
|     CyDelayUs(6); | ||||
|     STEP_REG_Write(dir | 2); /* step low */ | ||||
|     CyDelayUs(6); | ||||
|     STEP_REG_Write(dir); /* step high again, drive moves now */ | ||||
|     CyDelay(STEP_INTERVAL_TIME); | ||||
| } | ||||
|  | ||||
| /* returns true if it looks like a drive is attached */ | ||||
| static bool home(void) | ||||
| { | ||||
|     for (int i=0; i<100; i++) | ||||
|     { | ||||
|         /* Don't keep stepping forever, because if a drive's | ||||
|          * not connected bad things happen. */ | ||||
|         if (TRACK0_REG_Read()) | ||||
|             return true; | ||||
|         step(STEP_TOWARDS0); | ||||
|     } | ||||
|      | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| static void seek_to(int track) | ||||
| { | ||||
|     start_motor(); | ||||
|     if (!homed) | ||||
|     if (!homed || (track == 0)) | ||||
|     { | ||||
|         print("homing"); | ||||
|         while (!TRACK0_REG_Read()) | ||||
|             step(STEP_TOWARDS0); | ||||
|              | ||||
|         /* Step to -1, which should be a nop, to reset the disk on disk change. */ | ||||
|         step(STEP_TOWARDS0); | ||||
|         home(); | ||||
|          | ||||
|         homed = true; | ||||
|         current_track = 0; | ||||
| @@ -167,11 +224,7 @@ static void seek_to(int track) | ||||
|     while (track != current_track) | ||||
|     { | ||||
|         if (TRACK0_REG_Read()) | ||||
|         { | ||||
|             if (current_track != 0) | ||||
|                 print("unexpectedly detected track 0"); | ||||
|             current_track = 0; | ||||
|         } | ||||
|          | ||||
|         if (track > current_track) | ||||
|         { | ||||
| @@ -208,26 +261,40 @@ static void cmd_measure_speed(struct any_frame* f) | ||||
| { | ||||
|     start_motor(); | ||||
|      | ||||
|     index_irq = false; | ||||
|     while (!index_irq) | ||||
|         ; | ||||
|     index_irq = false; | ||||
|     int start_clock = clock; | ||||
|     int elapsed = 0; | ||||
|     while (!index_irq) | ||||
|         ; | ||||
|     int end_clock = clock; | ||||
|     { | ||||
|         elapsed = clock - start_clock; | ||||
|         if (elapsed > 1000) | ||||
|         { | ||||
|             elapsed = 0; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (elapsed != 0) | ||||
|     { | ||||
|         index_irq = false; | ||||
|         start_clock = clock; | ||||
|         while (!index_irq) | ||||
|             elapsed = clock - start_clock; | ||||
|     } | ||||
|      | ||||
|     DECLARE_REPLY_FRAME(struct speed_frame, F_FRAME_MEASURE_SPEED_REPLY); | ||||
|     r.period_ms = end_clock - start_clock; | ||||
|     r.period_ms = elapsed; | ||||
|     send_reply((struct any_frame*) &r);     | ||||
| } | ||||
|  | ||||
| static void cmd_bulk_test(struct any_frame* f) | ||||
| static void cmd_bulk_write_test(struct any_frame* f) | ||||
| { | ||||
|     uint8_t buffer[64]; | ||||
|      | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     for (int x=0; x<64; x++) | ||||
|     { | ||||
|         CyWdtClear(); | ||||
|         for (int y=0; y<256; y++) | ||||
|         { | ||||
|             for (unsigned z=0; z<sizeof(buffer); z++) | ||||
| @@ -236,11 +303,50 @@ static void cmd_bulk_test(struct any_frame* f) | ||||
|             wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|             USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, buffer, sizeof(buffer)); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_BULK_TEST_REPLY); | ||||
|     DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_BULK_WRITE_TEST_REPLY); | ||||
|     send_reply(&r); | ||||
| } | ||||
|  | ||||
| static void cmd_bulk_read_test(struct any_frame* f) | ||||
| { | ||||
|     uint8_t buffer[64]; | ||||
|      | ||||
|     bool passed = true; | ||||
|     for (int x=0; x<64; x++) | ||||
|     { | ||||
|         CyWdtClear(); | ||||
|         for (int y=0; y<256; y++) | ||||
|         { | ||||
|             USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|             while (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) != USBFS_OUT_BUFFER_FULL) | ||||
|                 ; | ||||
|             USBFS_ReadOutEP(FLUXENGINE_DATA_OUT_EP_NUM, buffer, sizeof(buffer)); | ||||
|             while (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) != USBFS_OUT_BUFFER_EMPTY) | ||||
|                 ; | ||||
|              | ||||
|             for (unsigned z=0; z<sizeof(buffer); z++) | ||||
|             { | ||||
|                 if (buffer[z] != (uint8)(x+y+z)) | ||||
|                 { | ||||
|                     print("fail %d+%d+%d == %d, not %d", x, y, z, buffer[z], (uint8)(x+y+z)); | ||||
|                     passed = false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     print("passed=%d", passed); | ||||
|     if (passed) | ||||
|     { | ||||
|         DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_BULK_READ_TEST_REPLY); | ||||
|         send_reply(&r); | ||||
|     } | ||||
|     else | ||||
|         send_error(F_ERROR_INVALID_VALUE); | ||||
| } | ||||
|  | ||||
| static void deinit_dma(void) | ||||
| { | ||||
|     for (int i=0; i<BUFFER_COUNT; i++) | ||||
| @@ -249,7 +355,7 @@ static void deinit_dma(void) | ||||
|  | ||||
| static void init_capture_dma(void) | ||||
| { | ||||
|     dma_channel = CAPTURE_DMA_DmaInitialize( | ||||
|     dma_channel = SAMPLER_DMA_DmaInitialize( | ||||
|         2 /* bytes */, | ||||
|         true /* request per burst */,  | ||||
|         HI16(CYDEV_PERIPH_BASE), | ||||
| @@ -264,8 +370,8 @@ static void init_capture_dma(void) | ||||
|             nexti = 0; | ||||
|  | ||||
|         CyDmaTdSetConfiguration(td[i], BUFFER_SIZE, td[nexti],    | ||||
|             CY_DMA_TD_INC_DST_ADR | CAPTURE_DMA__TD_TERMOUT_EN); | ||||
|         CyDmaTdSetAddress(td[i], LO16((uint32)&SAMPLER_DATAPATH_F0_REG), LO16((uint32)&dma_buffer[i])); | ||||
|             CY_DMA_TD_INC_DST_ADR | SAMPLER_DMA__TD_TERMOUT_EN); | ||||
|         CyDmaTdSetAddress(td[i], LO16((uint32)SAMPLER_FIFO_FIFO_PTR), LO16((uint32)&dma_buffer[i])); | ||||
|     }     | ||||
| } | ||||
|  | ||||
| @@ -276,35 +382,35 @@ static void cmd_read(struct read_frame* f) | ||||
|      | ||||
|     /* Do slow setup *before* we go into the real-time bit. */ | ||||
|      | ||||
|     SAMPLER_CONTROL_Write(1); /* reset */ | ||||
|      | ||||
|     { | ||||
|         uint8_t i = CyEnterCriticalSection(); | ||||
|         SAMPLER_DATAPATH_F0_SET_LEVEL_MID; | ||||
|         SAMPLER_DATAPATH_F0_CLEAR; | ||||
|         SAMPLER_DATAPATH_F0_SINGLE_BUFFER_UNSET; | ||||
|         SAMPLER_FIFO_SET_LEVEL_NORMAL; | ||||
|         SAMPLER_FIFO_CLEAR; | ||||
|         SAMPLER_FIFO_SINGLE_BUFFER_UNSET; | ||||
|         CyExitCriticalSection(i); | ||||
|     } | ||||
|      | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     init_capture_dma(); | ||||
|  | ||||
|     /* Wait for the beginning of a rotation. */ | ||||
|     /* Wait for the beginning of a rotation, if requested. */ | ||||
|          | ||||
|     index_irq = false; | ||||
|     while (!index_irq) | ||||
|         ; | ||||
|     index_irq = false; | ||||
|     if (f->synced) | ||||
|     { | ||||
|         index_irq = false; | ||||
|         while (!index_irq) | ||||
|             ; | ||||
|         index_irq = false; | ||||
|     } | ||||
|      | ||||
|     crunch_state_t cs = {}; | ||||
|     cs.outputptr = usb_buffer; | ||||
|     cs.outputptr = xfer_buffer; | ||||
|     cs.outputlen = BUFFER_SIZE; | ||||
|      | ||||
|     dma_writing_to_td = 0; | ||||
|     dma_reading_from_td = -1; | ||||
|     dma_underrun = false; | ||||
|     int count = 0; | ||||
|     SAMPLER_CONTROL_Write(0); /* !reset */ | ||||
|     CyDmaChSetInitialTd(dma_channel, td[dma_writing_to_td]); | ||||
|     CyDmaClearPendingDrq(dma_channel); | ||||
|     CyDmaChEnable(dma_channel, 1); | ||||
| @@ -312,73 +418,100 @@ static void cmd_read(struct read_frame* f) | ||||
|     /* Wait for the first DMA transfer to complete, after which we can start the | ||||
|      * USB transfer. */ | ||||
|  | ||||
|     while ((dma_writing_to_td == 0) && !index_irq) | ||||
|     while (dma_writing_to_td == 0) | ||||
|         ; | ||||
|     dma_reading_from_td = 0; | ||||
|     bool dma_running = true; | ||||
|      | ||||
|     /* Start transferring. */ | ||||
|  | ||||
|     int revolutions = f->revolutions; | ||||
|     while (!dma_underrun) | ||||
|     uint32_t start_time = clock; | ||||
|     for (;;) | ||||
|     { | ||||
|         CyWdtClear(); | ||||
|  | ||||
|         /* Have we reached the index pulse? */ | ||||
|         if (index_irq) | ||||
|         { | ||||
|             index_irq = false; | ||||
|             revolutions--; | ||||
|             if (revolutions == 0) | ||||
|                 break; | ||||
|         } | ||||
|         /* If the sample session is over, stop reading but continue processing until | ||||
|          * the DMA chain is empty. */ | ||||
|          | ||||
|         /* Wait for the next block to be read. */ | ||||
|         while (dma_reading_from_td == dma_writing_to_td) | ||||
|         if ((clock - start_time) >= f->milliseconds) | ||||
|         { | ||||
|             /* On an underrun, give up immediately. */ | ||||
|             if (dma_underrun) | ||||
|                 goto abort; | ||||
|         } | ||||
|  | ||||
|         uint8_t dma_buffer_usage = 0; | ||||
|         while (dma_buffer_usage < BUFFER_SIZE) | ||||
|         { | ||||
|             cs.inputptr = dma_buffer[dma_reading_from_td] + dma_buffer_usage; | ||||
|             cs.inputlen = BUFFER_SIZE - dma_buffer_usage; | ||||
|             crunch(&cs); | ||||
|             dma_buffer_usage += BUFFER_SIZE - cs.inputlen; | ||||
|             count++; | ||||
|             if (cs.outputlen == 0) | ||||
|             if (dma_running) | ||||
|             { | ||||
|                 while (USBFS_GetEPState(FLUXENGINE_DATA_IN_EP_NUM) != USBFS_IN_BUFFER_EMPTY) | ||||
|                 { | ||||
|                     if (index_irq || dma_underrun) | ||||
|                         goto abort; | ||||
|                 } | ||||
|  | ||||
|                 USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); | ||||
|                 cs.outputptr = usb_buffer; | ||||
|                 cs.outputlen = BUFFER_SIZE; | ||||
|                 CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN); | ||||
|                 while (CyDmaChGetRequest(dma_channel)) | ||||
|                     ; | ||||
|                 dma_running = false; | ||||
|                 dma_underrun = false; | ||||
|             } | ||||
|         } | ||||
|         dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td); | ||||
|          | ||||
|         /* If there's an underrun event, stop immediately. */ | ||||
|          | ||||
|         if (dma_underrun) | ||||
|             goto abort; | ||||
|          | ||||
|         /* If there are no more blocks to be read, check to see if we've finished. */ | ||||
|          | ||||
|         if (dma_reading_from_td == dma_writing_to_td) | ||||
|         { | ||||
|             /* Also if we've run out of blocks to send. */ | ||||
|              | ||||
|             if (!dma_running) | ||||
|                 goto abort; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             /* Otherwise, there's a block waiting, so attempt to send it. */ | ||||
|              | ||||
|             uint8_t dma_buffer_usage = 0; | ||||
|             while (dma_buffer_usage < BUFFER_SIZE) | ||||
|             { | ||||
|                 cs.inputptr = dma_buffer[dma_reading_from_td] + dma_buffer_usage; | ||||
|                 cs.inputlen = BUFFER_SIZE - dma_buffer_usage; | ||||
|                 crunch(&cs); | ||||
|                 dma_buffer_usage += BUFFER_SIZE - cs.inputlen; | ||||
|                 count++; | ||||
|                  | ||||
|                 /* If there is no available space in the output buffer, flush the buffer via | ||||
|                  * USB and go again. */ | ||||
|                 if (cs.outputlen == 0) | ||||
|                 { | ||||
|                     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|                     memcpy(usb_buffer, xfer_buffer, FRAME_SIZE); | ||||
|                     USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); | ||||
|                      | ||||
|                     cs.outputptr = xfer_buffer; | ||||
|                     cs.outputlen = BUFFER_SIZE; | ||||
|                 } | ||||
|             } | ||||
|             dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td); | ||||
|         } | ||||
|     } | ||||
| abort:; | ||||
|     CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN); | ||||
|     while (CyDmaChGetRequest(dma_channel)) | ||||
|         ; | ||||
|     bool saved_dma_underrun = dma_underrun; | ||||
|  | ||||
|     donecrunch(&cs); | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     unsigned zz = cs.outputlen; | ||||
|     /* If there's a complete packet waiting, send it. */ | ||||
|     if (cs.outputlen != BUFFER_SIZE) | ||||
|     { | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); | ||||
|         wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     } | ||||
|     if ((cs.outputlen != 0) && (cs.outputlen != BUFFER_SIZE)) | ||||
|     { | ||||
|         /* If there's a partial packet waiting, send it; this will also terminate the transfer. */ | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE-cs.outputlen); | ||||
|     if ((cs.outputlen == BUFFER_SIZE) || (cs.outputlen == 0)) | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         /* Otherwise just terminate the transfer. */ | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0); | ||||
|     } | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     deinit_dma(); | ||||
|  | ||||
|     if (dma_underrun) | ||||
|     if (saved_dma_underrun) | ||||
|     { | ||||
|         print("underrun after %d packets"); | ||||
|         send_error(F_ERROR_UNDERRUN); | ||||
| @@ -388,7 +521,7 @@ abort:; | ||||
|         DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_READ_REPLY); | ||||
|         send_reply(&r); | ||||
|     } | ||||
|     print("count=%d i=%d d=%d zz=%d", count, index_irq, dma_underrun, zz); | ||||
|     print("count=%d i=%d d=%d", count, index_irq, dma_underrun); | ||||
| } | ||||
|  | ||||
| static void init_replay_dma(void) | ||||
| @@ -428,7 +561,7 @@ static void cmd_write(struct write_frame* f) | ||||
|     SIDE_REG_Write(f->side); | ||||
|     { | ||||
|         uint8_t i = CyEnterCriticalSection();         | ||||
|         REPLAY_FIFO_SET_LEVEL_NORMAL; | ||||
|         REPLAY_FIFO_SET_LEVEL_MID; | ||||
|         REPLAY_FIFO_CLEAR; | ||||
|         REPLAY_FIFO_SINGLE_BUFFER_UNSET; | ||||
|         CyExitCriticalSection(i); | ||||
| @@ -441,6 +574,7 @@ static void cmd_write(struct write_frame* f) | ||||
|     int packets = f->bytes_to_write / FRAME_SIZE; | ||||
|     int count_written = 0; | ||||
|     int count_read = 0; | ||||
|     int packetwaiting = 0; | ||||
|     dma_writing_to_td = 0; | ||||
|     dma_reading_from_td = -1; | ||||
|     dma_underrun = false; | ||||
| @@ -452,6 +586,22 @@ static void cmd_write(struct write_frame* f) | ||||
|     int old_reading_from_td = -1; | ||||
|     for (;;) | ||||
|     { | ||||
|         CyWdtClear(); | ||||
|  | ||||
|         /* Make sure that we always have a USB read in progress whenever possible. */ | ||||
|          | ||||
|         if (!finished && !packetwaiting) | ||||
|         { | ||||
|             /* There is no read in progress; has data arrived in the external USB buffer? */ | ||||
|              | ||||
|             if (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL) | ||||
|             { | ||||
|                 /* Yes, data has arrived, so initiate the copy. */ | ||||
|                  | ||||
|                 packetwaiting = USBFS_ReadOutEP(FLUXENGINE_DATA_OUT_EP_NUM, usb_buffer, FRAME_SIZE); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /* Read data from USB into the buffers. */ | ||||
|          | ||||
|         if (NEXT_BUFFER(dma_writing_to_td) != dma_reading_from_td) | ||||
| @@ -468,26 +618,33 @@ static void cmd_write(struct write_frame* f) | ||||
|                     /* There's no more data to read, so fake some. */ | ||||
|                      | ||||
|                     for (int i=0; i<BUFFER_SIZE; i++) | ||||
|                         usb_buffer[i+0] = 0x7f; | ||||
|                     cs.inputptr = usb_buffer; | ||||
|                         xfer_buffer[i+0] = 0x7f; | ||||
|                     cs.inputptr = xfer_buffer; | ||||
|                     cs.inputlen = BUFFER_SIZE; | ||||
|                 } | ||||
|                 else | ||||
|                 else if (packetwaiting) | ||||
|                 { | ||||
|                     while (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) != USBFS_OUT_BUFFER_FULL) | ||||
|                     /* There's a USB read into usb_buffer in progress, so check if it's finished. */ | ||||
|                      | ||||
|                     if (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) == USBFS_OUT_BUFFER_EMPTY) | ||||
|                     { | ||||
|                         if (writing && (dma_underrun || index_irq)) | ||||
|                             goto abort; | ||||
|                         /* It's done, so copy out the data. */ | ||||
|                          | ||||
|                         memcpy(xfer_buffer, usb_buffer, FRAME_SIZE); | ||||
|                         cs.inputptr = xfer_buffer; | ||||
|                         cs.inputlen = packetwaiting; | ||||
|  | ||||
|                         count_read++; | ||||
|                         if ((packetwaiting < FRAME_SIZE) || (count_read == packets)) | ||||
|                             finished = true; | ||||
|                         else | ||||
|                         { | ||||
|                             /* Wait for more USB data to show up. */ | ||||
|                              | ||||
|                             packetwaiting = 0; | ||||
|                             USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     int length = usb_read(FLUXENGINE_DATA_OUT_EP_NUM, usb_buffer); | ||||
|                     cs.inputptr = usb_buffer; | ||||
|                     cs.inputlen = length; | ||||
|                     USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|  | ||||
|                     count_read++; | ||||
|                     if ((length < FRAME_SIZE) || (count_read == packets)) | ||||
|                         finished = true; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
| @@ -506,7 +663,8 @@ static void cmd_write(struct write_frame* f) | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             /* If we have a full buffer, start writing. */ | ||||
|             /* Once all the buffers are full, start writing. */ | ||||
|              | ||||
|             if ((dma_reading_from_td == -1) && (dma_writing_to_td == BUFFER_COUNT-1)) | ||||
|             { | ||||
|                 dma_reading_from_td = old_reading_from_td = 0; | ||||
| @@ -521,7 +679,7 @@ static void cmd_write(struct write_frame* f) | ||||
|  | ||||
|                 /* Wait for the index marker. While this happens, the DMA engine | ||||
|                  * will prime the FIFO. */ | ||||
|                  | ||||
|  | ||||
|                 index_irq = false; | ||||
|                 while (!index_irq) | ||||
|                     ; | ||||
| @@ -532,7 +690,7 @@ static void cmd_write(struct write_frame* f) | ||||
|                 SEQUENCER_CONTROL_Write(0); /* start writing! */ | ||||
|             } | ||||
|         } | ||||
|          | ||||
|  | ||||
|         if (writing && (dma_underrun || index_irq)) | ||||
|             goto abort; | ||||
|  | ||||
| @@ -543,6 +701,7 @@ static void cmd_write(struct write_frame* f) | ||||
|         } | ||||
|     } | ||||
| abort: | ||||
|     print("done %d %d", dma_reading_from_td, dma_writing_to_td); | ||||
|     SEQUENCER_DMA_FINISHED_IRQ_Disable(); | ||||
|  | ||||
|     SEQUENCER_CONTROL_Write(1); /* reset */ | ||||
| @@ -558,7 +717,9 @@ abort: | ||||
|     print("p=%d cr=%d cw=%d f=%d w=%d index=%d underrun=%d", packets, count_read, count_written, finished, writing, index_irq, dma_underrun); | ||||
|     if (!finished) | ||||
|     { | ||||
|         while (count_read < packets) | ||||
|         /* There's still some data to read, so just read and blackhole it --- | ||||
|          * easier than trying to terminate the connection. */ | ||||
|         while (count_read != packets) | ||||
|         { | ||||
|             if (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL) | ||||
|             { | ||||
| @@ -608,17 +769,105 @@ static void cmd_erase(struct erase_frame* f) | ||||
|  | ||||
| static void cmd_set_drive(struct set_drive_frame* f) | ||||
| { | ||||
|     if (current_drive_flags != f->drive_flags) | ||||
|     { | ||||
|         current_drive_flags = f->drive_flags; | ||||
|         DRIVE_REG_Write(current_drive_flags); | ||||
|         homed = false; | ||||
|     } | ||||
|     if (drive0_present && !drive1_present) | ||||
|         f->drive = 0; | ||||
|     if (drive1_present && !drive0_present) | ||||
|         f->drive = 1; | ||||
|     set_drive_flags(f); | ||||
|      | ||||
|     DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_SET_DRIVE_REPLY); | ||||
|     send_reply((struct any_frame*) &r); | ||||
| } | ||||
|     | ||||
|  | ||||
| static uint16_t read_output_voltage_mv(void) | ||||
| { | ||||
|     OUTPUT_VOLTAGE_ADC_StartConvert(); | ||||
|     OUTPUT_VOLTAGE_ADC_IsEndConversion(OUTPUT_VOLTAGE_ADC_WAIT_FOR_RESULT); | ||||
|     uint16_t samples = OUTPUT_VOLTAGE_ADC_GetResult16(); | ||||
|     return OUTPUT_VOLTAGE_ADC_CountsTo_mVolts(samples); | ||||
| } | ||||
|  | ||||
| static void read_output_voltages(struct voltages* v) | ||||
| { | ||||
|     SIDE_REG_Write(1); /* set DIR to low (remember this is inverted) */ | ||||
|     CyDelay(100); | ||||
|     v->logic0_mv = read_output_voltage_mv(); | ||||
|  | ||||
|     SIDE_REG_Write(0); | ||||
|     CyDelay(100); | ||||
|     v->logic1_mv = read_output_voltage_mv(); | ||||
| } | ||||
|  | ||||
| static uint16_t read_input_voltage_mv(void) | ||||
| { | ||||
|     INPUT_VOLTAGE_ADC_StartConvert(); | ||||
|     INPUT_VOLTAGE_ADC_IsEndConversion(INPUT_VOLTAGE_ADC_WAIT_FOR_RESULT); | ||||
|     uint16_t samples = INPUT_VOLTAGE_ADC_GetResult16(); | ||||
|     return INPUT_VOLTAGE_ADC_CountsTo_mVolts(samples); | ||||
| } | ||||
|  | ||||
| static void read_input_voltages(struct voltages* v) | ||||
| { | ||||
|     home(); | ||||
|     CyDelay(50); | ||||
|     v->logic0_mv = read_input_voltage_mv(); | ||||
|      | ||||
|     step(STEP_AWAYFROM0); | ||||
|     CyDelay(50); | ||||
|     v->logic1_mv = read_input_voltage_mv(); | ||||
| } | ||||
|  | ||||
| static void cmd_measure_voltages(void) | ||||
| { | ||||
|     stop_motor(); | ||||
|     INPUT_VOLTAGE_ADC_Start(); | ||||
|     INPUT_VOLTAGE_ADC_SetPower(INPUT_VOLTAGE_ADC__HIGHPOWER); | ||||
|     OUTPUT_VOLTAGE_ADC_Start(); | ||||
|     OUTPUT_VOLTAGE_ADC_SetPower(OUTPUT_VOLTAGE_ADC__HIGHPOWER); | ||||
|      | ||||
|     DECLARE_REPLY_FRAME(struct voltages_frame, F_FRAME_MEASURE_VOLTAGES_REPLY); | ||||
|      | ||||
|     CyWdtClear(); | ||||
|     MOTOR_REG_Write(0); /* should be ignored anyway */ | ||||
|     DRIVESELECT_REG_Write(0); /* deselect both drives */ | ||||
|     CyDelay(200); /* wait for things to settle */ | ||||
|     read_output_voltages(&r.output_both_off); | ||||
|     read_input_voltages(&r.input_both_off); | ||||
|  | ||||
|     CyWdtClear(); | ||||
|     DRIVESELECT_REG_Write(1); /* select drive 0 */ | ||||
|     CyDelay(50); | ||||
|     read_output_voltages(&r.output_drive_0_selected); | ||||
|     read_input_voltages(&r.input_drive_0_selected); | ||||
|     MOTOR_REG_Write(1); | ||||
|     CyDelay(300); | ||||
|     CyWdtClear(); | ||||
|     read_output_voltages(&r.output_drive_0_running); | ||||
|     read_input_voltages(&r.input_drive_0_running); | ||||
|     MOTOR_REG_Write(0); | ||||
|     CyDelay(300); | ||||
|      | ||||
|     CyWdtClear(); | ||||
|     DRIVESELECT_REG_Write(2); /* select drive 1 */ | ||||
|     CyDelay(50); | ||||
|     read_output_voltages(&r.output_drive_1_selected); | ||||
|     read_input_voltages(&r.input_drive_1_selected); | ||||
|     MOTOR_REG_Write(1); | ||||
|     CyDelay(300); | ||||
|     CyWdtClear(); | ||||
|     read_output_voltages(&r.output_drive_1_running); | ||||
|     read_input_voltages(&r.input_drive_1_running); | ||||
|     MOTOR_REG_Write(0); | ||||
|     CyDelay(300); | ||||
|  | ||||
|     CyWdtClear(); | ||||
|     DRIVESELECT_REG_Write(0); | ||||
|     homed = false; | ||||
|     INPUT_VOLTAGE_ADC_Stop(); | ||||
|     OUTPUT_VOLTAGE_ADC_Stop(); | ||||
|     send_reply((struct any_frame*) &r); | ||||
| } | ||||
|  | ||||
| static void handle_command(void) | ||||
| { | ||||
|     static uint8_t input_buffer[FRAME_SIZE]; | ||||
| @@ -640,8 +889,12 @@ static void handle_command(void) | ||||
|             cmd_measure_speed(f); | ||||
|             break; | ||||
|              | ||||
|         case F_FRAME_BULK_TEST_CMD: | ||||
|             cmd_bulk_test(f); | ||||
|         case F_FRAME_BULK_WRITE_TEST_CMD: | ||||
|             cmd_bulk_write_test(f); | ||||
|             break; | ||||
|              | ||||
|         case F_FRAME_BULK_READ_TEST_CMD: | ||||
|             cmd_bulk_read_test(f); | ||||
|             break; | ||||
|              | ||||
|         case F_FRAME_READ_CMD: | ||||
| @@ -663,28 +916,48 @@ static void handle_command(void) | ||||
|         case F_FRAME_SET_DRIVE_CMD: | ||||
|             cmd_set_drive((struct set_drive_frame*) f); | ||||
|             break; | ||||
|          | ||||
|         case F_FRAME_MEASURE_VOLTAGES_CMD: | ||||
|             cmd_measure_voltages(); | ||||
|             break; | ||||
|              | ||||
|         default: | ||||
|             send_error(F_ERROR_BAD_COMMAND); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void detect_drives(void) | ||||
| { | ||||
|     current_drive_flags.drive = 0; | ||||
|     start_motor(); | ||||
|     drive0_present = home(); | ||||
|     stop_motor(); | ||||
|      | ||||
|     current_drive_flags.drive = 1; | ||||
|     start_motor(); | ||||
|     drive1_present = home(); | ||||
|     stop_motor(); | ||||
|      | ||||
|     print("drive 0: %s drive 1: %s", drive0_present ? "yes" : "no", drive1_present ? "yes" : "no"); | ||||
| } | ||||
|  | ||||
| int main(void) | ||||
| { | ||||
|     CyGlobalIntEnable; | ||||
|     CySysTickStart(); | ||||
|     CySysTickSetCallback(4, system_timer_cb); | ||||
|     INDEX_IRQ_StartEx(&index_irq_cb); | ||||
|     CAPTURE_DMA_FINISHED_IRQ_StartEx(&capture_dma_finished_irq_cb); | ||||
|     SAMPLER_DMA_FINISHED_IRQ_StartEx(&capture_dma_finished_irq_cb); | ||||
|     SEQUENCER_DMA_FINISHED_IRQ_StartEx(&replay_dma_finished_irq_cb); | ||||
|     DRIVE_REG_Write(0); | ||||
|     INPUT_VOLTAGE_ADC_Stop(); | ||||
|     OUTPUT_VOLTAGE_ADC_Stop(); | ||||
|     DRIVESELECT_REG_Write(0); | ||||
|     UART_Start(); | ||||
|     USBFS_Start(0, USBFS_DWR_VDDD_OPERATION); | ||||
|      | ||||
|     detect_drives(); | ||||
|     CyWdtStart(CYWDT_1024_TICKS, CYWDT_LPMODE_DISABLED); | ||||
|      | ||||
|     /* UART_PutString("GO\r"); */ | ||||
|  | ||||
|     for (;;) | ||||
|     { | ||||
|         CyWdtClear(); | ||||
| @@ -693,23 +966,21 @@ int main(void) | ||||
|         { | ||||
|             uint32_t time_on = clock - motor_on_time; | ||||
|             if (time_on > MOTOR_ON_TIME) | ||||
|             { | ||||
|                 MOTOR_REG_Write(0); | ||||
|                 motor_on = false; | ||||
|             } | ||||
|                 stop_motor(); | ||||
|         } | ||||
|          | ||||
|         if (!USBFS_GetConfiguration() || USBFS_IsConfigurationChanged()) | ||||
|         { | ||||
|             print("Waiting for USB..."); | ||||
|             while (!USBFS_GetConfiguration()) | ||||
|                 ; | ||||
|                 CyWdtClear(); | ||||
|             print("USB ready"); | ||||
|             USBFS_EnableOutEP(FLUXENGINE_CMD_OUT_EP_NUM); | ||||
|         } | ||||
|          | ||||
|         if (USBFS_GetEPState(FLUXENGINE_CMD_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL) | ||||
|         { | ||||
|             set_drive_flags(¤t_drive_flags); | ||||
|             handle_command(); | ||||
|             USBFS_EnableOutEP(FLUXENGINE_CMD_OUT_EP_NUM); | ||||
|             print("idle"); | ||||
|   | ||||
							
								
								
									
										18
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,8 +1,13 @@ | ||||
| PACKAGES = zlib sqlite3 libusb-1.0 | ||||
|  | ||||
| export CFLAGS = -Os -g --std=c++14 \ | ||||
| 	-ffunction-sections -fdata-sections | ||||
| export LDFLAGS = -Os | ||||
| export CFLAGS = --std=c++14 -ffunction-sections -fdata-sections | ||||
| export LDFLAGS = | ||||
|  | ||||
| export COPTFLAGS = -Os | ||||
| export LDOPTFLAGS = -Os -s | ||||
|  | ||||
| export CDBGFLAGS = -O0 -g | ||||
| export LDDBGFLAGS = -O0 -g | ||||
|  | ||||
| ifeq ($(OS), Windows_NT) | ||||
| export CXX = /mingw32/bin/g++ | ||||
| @@ -13,6 +18,13 @@ export LDFLAGS += | ||||
| export LIBS = -static -lz -lsqlite3 -lusb-1.0 | ||||
| export EXTENSION = .exe | ||||
| else | ||||
|  | ||||
| packages-exist = $(shell pkg-config --exists $(PACKAGES) && echo yes) | ||||
| ifneq ($(packages-exist),yes) | ||||
| $(warning These pkg-config packages are installed: $(shell pkg-config --list-all | sort | awk '{print $$1}')) | ||||
| $(error You must have these pkg-config packages installed: $(PACKAGES)) | ||||
| endif | ||||
|  | ||||
| export CXX = g++ | ||||
| export AR = ar rcs | ||||
| export STRIP = strip | ||||
|   | ||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							| @@ -79,20 +79,24 @@ people who've had it work). | ||||
|  | ||||
| | Format                                   | Read? | Write? | Notes | | ||||
| |:-----------------------------------------|:-----:|:------:|-------| | ||||
| | IBM PC compatible                        |  🦄   |        | and compatibles (like the Atari ST) | | ||||
| | [Acorn ADFS](doc/disk-acornadfs.md)      |  🦄   |        | single- and double- sided           | | ||||
| | [Acorn DFS](doc/disk-acorndfs.md)        |  🦄   |        |                                     | | ||||
| | [Ampro Little Board](doc/disk-ampro.md)  |  🦖   |        |                                     | | ||||
| | [IBM PC compatible](doc/disk-ibm.md)     |  🦄   |   🦄   | and compatibles (like the Atari ST) | | ||||
| | [Acorn ADFS](doc/disk-acornadfs.md)      |  🦄   |   🦖*  | single- and double- sided           | | ||||
| | [Acorn DFS](doc/disk-acorndfs.md)        |  🦄   |   🦖*  |                                     | | ||||
| | [Ampro Little Board](doc/disk-ampro.md)  |  🦖   |   🦖*   |                                     | | ||||
| | [Apple II DOS 3.3](doc/disk-apple2.md)   |  🦄   |        | doesn't do logical sector remapping | | ||||
| | [Amiga](doc/disk-amiga.md)               |  🦄   |        |                                     | | ||||
| | [Commodore 64 1541](doc/disk-c64.md)     |  🦖   |        | and probably the other GCR formats  | | ||||
| | [Brother 120kB](doc/disk-brother.md)     |  🦄   |        |                                     | | ||||
| | [Brother 240kB](doc/disk-brother.md)     |  🦄   |   🦄   |                                     | | ||||
| | [Brother FB-100](doc/disk-fb100.md)      |  🦖   |        | Tandy Model 100, Husky Hunter, knitting machines | | ||||
| | [Macintosh 800kB](doc/disk-macintosh.md) |  🦄   |        | and probably the 400kB too          | | ||||
| | [TRS-80](doc/disk-trs80.md)              |  🦖   |        | a minor variation of the IBM scheme | | ||||
| | [Macintosh 800kB](doc/disk-macintosh.md) |  🦖   |        | and probably the 400kB too          | | ||||
| | [TRS-80](doc/disk-trs80.md)              |  🦖   |   🦖*  | a minor variation of the IBM scheme | | ||||
| {: .datatable } | ||||
|  | ||||
| `*`: these formats are variations of the generic IBM format, and since the | ||||
| IBM writer is completely generic, it should be configurable for these | ||||
| formats... theoretically. I don't have the hardware to try it. | ||||
|  | ||||
| ### Even older disk formats | ||||
|  | ||||
| These formats are for particularly old, weird architectures, even by the | ||||
|   | ||||
							
								
								
									
										101
									
								
								arch/amiga/amiga.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								arch/amiga/amiga.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| #include "globals.h" | ||||
| #include "record.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "amiga.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| uint32_t amigaChecksum(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; | ||||
| } | ||||
|  | ||||
| static uint8_t everyother(uint16_t x) | ||||
| { | ||||
| 	                  /* aabb ccdd eeff gghh */ | ||||
| 	x &= 0x6666;      /* 0ab0 0cd0 0ef0 0gh0 */ | ||||
| 	x >>= 1;          /* 00ab 00cd 00ef 00gh */ | ||||
| 	x |= x << 2;      /* abab cdcd efef ghgh */ | ||||
| 	x &= 0x3c3c;      /* 00ab cd00 00ef gh00 */ | ||||
| 	x >>= 2;          /* 0000 abcd 0000 efgh */ | ||||
| 	x |= x >> 4;      /* 0000 abcd abcd efgh */ | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| Bytes amigaInterleave(const Bytes& input) | ||||
| { | ||||
| 	Bytes output; | ||||
| 	ByteWriter bw(output); | ||||
|  | ||||
| 	/* Write all odd bits. (Numbering starts at 0...) */ | ||||
|  | ||||
| 	{ | ||||
| 		ByteReader br(input); | ||||
| 		while (!br.eof()) | ||||
| 		{ | ||||
| 			uint16_t x = br.read_be16(); | ||||
| 			x &= 0xaaaa;       /* a0b0 c0d0 e0f0 g0h0 */ | ||||
| 			x |= x >> 1;       /* aabb ccdd eeff gghh */ | ||||
| 			x = everyother(x); /* 0000 0000 abcd efgh */ | ||||
| 			bw.write_8(x); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Write all even bits. */ | ||||
|  | ||||
| 	{ | ||||
| 		ByteReader br(input); | ||||
| 		while (!br.eof()) | ||||
| 		{ | ||||
| 			uint16_t x = br.read_be16(); | ||||
| 			x &= 0x5555;       /* 0a0b 0c0d 0e0f 0g0h */ | ||||
| 			x |= x << 1;       /* aabb ccdd eeff gghh */ | ||||
| 			x = everyother(x); /* 0000 0000 abcd efgh */ | ||||
| 			bw.write_8(x); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return output; | ||||
| } | ||||
|  | ||||
| Bytes amigaDeinterleave(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; | ||||
| } | ||||
|  | ||||
| Bytes amigaDeinterleave(const Bytes& input) | ||||
| { | ||||
| 	const uint8_t* ptr = input.cbegin(); | ||||
| 	return amigaDeinterleave(ptr, input.size()); | ||||
| } | ||||
| @@ -1,12 +1,17 @@ | ||||
| #ifndef AMIGA_H | ||||
| #define AMIGA_H | ||||
|  | ||||
| #include "encoders/encoders.h" | ||||
|  | ||||
| #define AMIGA_SECTOR_RECORD 0xaaaa44894489LL | ||||
|  | ||||
| #define AMIGA_TRACKS_PER_DISK 80 | ||||
| #define AMIGA_SECTORS_PER_TRACK 11 | ||||
| #define AMIGA_RECORD_SIZE 0x21f | ||||
|  | ||||
| class Sector; | ||||
| class Fluxmap; | ||||
| class SectorSet; | ||||
|  | ||||
| class AmigaDecoder : public AbstractDecoder | ||||
| { | ||||
| @@ -15,6 +20,24 @@ public: | ||||
|  | ||||
|     RecordType advanceToNextRecord(); | ||||
|     void decodeSectorRecord(); | ||||
|  | ||||
| 	std::set<unsigned> requiredSectors(Track& track) const; | ||||
| }; | ||||
|  | ||||
| class AmigaEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	virtual ~AmigaEncoder() {} | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
| }; | ||||
|  | ||||
| extern FlagGroup amigaEncoderFlags; | ||||
|  | ||||
| extern uint32_t amigaChecksum(const Bytes& bytes); | ||||
| extern Bytes amigaInterleave(const Bytes& input); | ||||
| extern Bytes amigaDeinterleave(const uint8_t*& input, size_t len); | ||||
| extern Bytes amigaDeinterleave(const Bytes& input); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -21,47 +21,6 @@ | ||||
|           | ||||
| 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); | ||||
| @@ -78,22 +37,29 @@ void AmigaDecoder::decodeSectorRecord() | ||||
|  | ||||
|     const uint8_t* ptr = bytes.begin() + 3; | ||||
|  | ||||
|     Bytes header = deinterleave(ptr, 4); | ||||
|     Bytes recoveryinfo = deinterleave(ptr, 16); | ||||
|     Bytes header = amigaDeinterleave(ptr, 4); | ||||
|     Bytes recoveryinfo = amigaDeinterleave(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)); | ||||
|     uint32_t wantedheaderchecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); | ||||
|     uint32_t gotheaderchecksum = amigaChecksum(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)); | ||||
|     uint32_t wanteddatachecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); | ||||
|     uint32_t gotdatachecksum = amigaChecksum(rawbytes.slice(62, 1024)); | ||||
|  | ||||
|     _sector->data.clear(); | ||||
|     _sector->data.writer().append(deinterleave(ptr, 512)).append(recoveryinfo); | ||||
|     _sector->data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo); | ||||
|     _sector->status = (gotdatachecksum == wanteddatachecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| } | ||||
|  | ||||
| std::set<unsigned> AmigaDecoder::requiredSectors(Track& track) const | ||||
| { | ||||
| 	static std::set<unsigned> sectors = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | ||||
| 	return sectors; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										129
									
								
								arch/amiga/encoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								arch/amiga/encoder.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | ||||
| #include "globals.h" | ||||
| #include "record.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "amiga.h" | ||||
| #include "crc.h" | ||||
| #include "sectorset.h" | ||||
| #include "writer.h" | ||||
|  | ||||
| FlagGroup amigaEncoderFlags; | ||||
|  | ||||
| static DoubleFlag clockRateUs( | ||||
| 	{ "--clock-rate" }, | ||||
| 	"Encoded data clock rate (microseconds).", | ||||
| 	2.00); | ||||
|  | ||||
| static DoubleFlag postIndexGapMs( | ||||
| 	{ "--post-index-gap" }, | ||||
| 	"Post-index gap before first sector header (milliseconds).", | ||||
| 	0.5); | ||||
|  | ||||
| static bool lastBit; | ||||
|  | ||||
| static int charToInt(char c) | ||||
| { | ||||
| 	if (isdigit(c)) | ||||
| 		return c - '0'; | ||||
| 	return 10 + tolower(c) - 'a'; | ||||
| } | ||||
|  | ||||
| static void write_bits(std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src) | ||||
| { | ||||
| 	for (bool bit : src) | ||||
| 	{ | ||||
| 		if (cursor < bits.size()) | ||||
| 			bits[cursor++] = bit; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width) | ||||
| { | ||||
| 	cursor += width; | ||||
| 	for (int i=0; i<width; i++) | ||||
| 	{ | ||||
| 		unsigned pos = cursor - i - 1; | ||||
| 		if (pos < bits.size()) | ||||
| 			bits[pos] = data & 1; | ||||
| 		data >>= 1; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void write_interleaved_bytes(std::vector<bool>& bits, unsigned& cursor, const Bytes& bytes) | ||||
| { | ||||
| 	assert(!(bytes.size() & 3)); | ||||
| 	Bytes interleaved = amigaInterleave(bytes); | ||||
| 	encodeMfm(bits, cursor, interleaved, lastBit); | ||||
| } | ||||
|  | ||||
| static void write_interleaved_bytes(std::vector<bool>& bits, unsigned& cursor, uint32_t data) | ||||
| { | ||||
| 	Bytes b(4); | ||||
| 	ByteWriter bw(b); | ||||
| 	bw.write_be32(data); | ||||
| 	write_interleaved_bytes(bits, cursor, b); | ||||
| } | ||||
|  | ||||
| static void write_sector(std::vector<bool>& bits, unsigned& cursor, const Sector* sector) | ||||
| { | ||||
| 	if ((sector->data.size() != 512) && (sector->data.size() != 528)) | ||||
| 		Error() << "unsupported sector size --- you must pick 512 or 528"; | ||||
|  | ||||
|     write_bits(bits, cursor, AMIGA_SECTOR_RECORD, 6*8); | ||||
|  | ||||
| 	std::vector<bool> headerBits(20*16); | ||||
| 	unsigned headerCursor = 0; | ||||
|  | ||||
| 	Bytes header =  | ||||
| 		{ | ||||
| 			0xff, /* Amiga 1.0 format byte */ | ||||
| 			(uint8_t) ((sector->logicalTrack<<1) | sector->logicalSide), | ||||
| 			(uint8_t) sector->logicalSector, | ||||
| 			(uint8_t) (AMIGA_SECTORS_PER_TRACK - sector->logicalSector) | ||||
| 		}; | ||||
| 	write_interleaved_bytes(headerBits, headerCursor, header); | ||||
| 	Bytes recoveryInfo(16); | ||||
| 	if (sector->data.size() == 528) | ||||
| 		recoveryInfo = sector->data.slice(512, 16); | ||||
| 	write_interleaved_bytes(headerBits, headerCursor, recoveryInfo); | ||||
|  | ||||
| 	std::vector<bool> dataBits(512*16); | ||||
| 	unsigned dataCursor = 0; | ||||
| 	write_interleaved_bytes(dataBits, dataCursor, sector->data); | ||||
|  | ||||
| 	write_bits(bits, cursor, headerBits); | ||||
| 	uint32_t headerChecksum = amigaChecksum(toBytes(headerBits)); | ||||
| 	write_interleaved_bytes(bits, cursor, headerChecksum); | ||||
| 	uint32_t dataChecksum = amigaChecksum(toBytes(dataBits)); | ||||
| 	write_interleaved_bytes(bits, cursor, dataChecksum); | ||||
| 	write_bits(bits, cursor, dataBits); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> AmigaEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| { | ||||
| 	if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK)) | ||||
| 		return std::unique_ptr<Fluxmap>(); | ||||
|  | ||||
| 	int bitsPerRevolution = 200000.0 / clockRateUs; | ||||
| 	std::vector<bool> bits(bitsPerRevolution); | ||||
| 	unsigned cursor = 0; | ||||
|  | ||||
|     fillBitmapTo(bits, cursor, postIndexGapMs * 1000 / clockRateUs, { true, false }); | ||||
| 	lastBit = false; | ||||
|  | ||||
| 	for (int sectorId=0; sectorId<AMIGA_SECTORS_PER_TRACK; sectorId++) | ||||
| 	{ | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); | ||||
| 		write_sector(bits, cursor, sectorData); | ||||
|     } | ||||
|  | ||||
| 	if (cursor >= bits.size()) | ||||
| 		Error() << "track data overrun"; | ||||
| 	fillBitmapTo(bits, cursor, bits.size(), { true, false }); | ||||
|  | ||||
| 	std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| 	fluxmap->appendBits(bits, clockRateUs*1e3); | ||||
| 	return fluxmap; | ||||
| } | ||||
|  | ||||
| @@ -154,7 +154,7 @@ std::unique_ptr<Fluxmap> BrotherEncoder::encode( | ||||
| 		write_sector_data(bits, cursor, sectorData->data); | ||||
| 	} | ||||
|  | ||||
| 	if (cursor > bits.size()) | ||||
| 	if (cursor >= bits.size()) | ||||
| 		Error() << "track data overrun"; | ||||
| 	fillBitmapTo(bits, cursor, bits.size(), { true, false }); | ||||
|  | ||||
|   | ||||
| @@ -73,8 +73,10 @@ const FluxPattern FM_TRS80DAM2_PATTERN(16, 0xf56c); | ||||
|  * encoding (you can't do 10 00). So this can't be spoofed by user data. | ||||
|  *  | ||||
|  * shifted: 10 00 10 01 00 01 00 1 | ||||
|  *  | ||||
|  * It's repeated three times. | ||||
|  */ | ||||
| const FluxPattern MFM_PATTERN(16, 0x4489); | ||||
| const FluxPattern MFM_PATTERN(48, 0x448944894489LL); | ||||
|  | ||||
| const FluxMatchers ANY_RECORD_PATTERN( | ||||
|     { | ||||
| @@ -100,7 +102,8 @@ AbstractDecoder::RecordType IbmDecoder::advanceToNextRecord() | ||||
|     if (_currentHeaderLength > 0) | ||||
|         readRawBits(_currentHeaderLength*16); | ||||
|     auto idbits = readRawBits(16); | ||||
|     uint8_t id = decodeFmMfm(idbits).slice(0, 1)[0]; | ||||
|     const Bytes idbytes = decodeFmMfm(idbits); | ||||
|     uint8_t id = idbytes.slice(0, 1)[0]; | ||||
|     seek(here); | ||||
|      | ||||
|     switch (id) | ||||
|   | ||||
							
								
								
									
										235
									
								
								arch/ibm/encoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								arch/ibm/encoder.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| #include "globals.h" | ||||
| #include "record.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "ibm.h" | ||||
| #include "crc.h" | ||||
| #include "sectorset.h" | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include <ctype.h> | ||||
|  | ||||
| /* IAM record separator: | ||||
|  * 0xC2 is: | ||||
|  * data:    1  1  0  0  0  0  1  0  = 0xc2 | ||||
|  * mfm:     01 01 00 10 10 10 01 00 = 0x5254 | ||||
|  * special: 01 01 00 10 00 10 01 00 = 0x5224 | ||||
|  */ | ||||
| #define MFM_IAM_SEPARATOR 0x5224 | ||||
|  | ||||
| /* FM IAM record: | ||||
|  * flux:   XXXX-XXX-XXXX-X- = 0xf77a | ||||
|  * clock:  X X - X - X X X  = 0xd7 | ||||
|  * data:    X X X X X X - - = 0xfc | ||||
|  */ | ||||
| #define FM_IAM_RECORD 0xf77a | ||||
|  | ||||
| /* MFM IAM record: | ||||
|  * data:   1  1  1  1  1  1  0  0  = 0xfc | ||||
|  * flux:   01 01 01 01 01 01 00 10 = 0x5552 | ||||
|  */ | ||||
| #define MFM_IAM_RECORD 0x5552 | ||||
|  | ||||
| /* MFM record separator: | ||||
|  * 0xA1 is: | ||||
|  * data:    1  0  1  0  0  0  0  1  = 0xa1 | ||||
|  * mfm:     01 00 01 00 10 10 10 01 = 0x44a9 | ||||
|  * special: 01 00 01 00 10 00 10 01 = 0x4489 | ||||
|  *                       ^^^^^ | ||||
|  * 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. | ||||
|  *  | ||||
|  * shifted: 10 00 10 01 00 01 00 1 | ||||
|  *  | ||||
|  * It's repeated three times. | ||||
|  */ | ||||
| #define MFM_RECORD_SEPARATOR 0x4489 | ||||
| #define MFM_RECORD_SEPARATOR_BYTE 0xa1 | ||||
|  | ||||
| /* MFM IDAM byte: | ||||
|  * data:    1  1  1  1  1  1  1  0  = 0xfe | ||||
|  * mfm:     01 01 01 01 01 01 01 00 = 0x5554 | ||||
|  */ | ||||
|  | ||||
| /* MFM DAM byte: | ||||
|  * data:    1  1  1  1  1  0  1  1  = 0xfb | ||||
|  * mfm:     01 01 01 01 01 00 01 01 = 0x5545 | ||||
|  */ | ||||
|  | ||||
| static int charToInt(char c) | ||||
| { | ||||
| 	if (isdigit(c)) | ||||
| 		return c - '0'; | ||||
| 	return 10 + tolower(c) - 'a'; | ||||
| } | ||||
|  | ||||
| void IbmEncoder::writeRawBits(uint32_t data, int width) | ||||
| { | ||||
| 	_cursor += width; | ||||
| 	_lastBit = data & 1; | ||||
| 	for (int i=0; i<width; i++) | ||||
| 	{ | ||||
| 		unsigned pos = _cursor - i - 1; | ||||
| 		if (pos < _bits.size()) | ||||
| 			_bits[pos] = data & 1; | ||||
| 		data >>= 1; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void IbmEncoder::writeBytes(const Bytes& bytes) | ||||
| { | ||||
| 	if (_parameters.useFm) | ||||
| 		encodeFm(_bits, _cursor, bytes); | ||||
| 	else | ||||
| 		encodeMfm(_bits, _cursor, bytes, _lastBit); | ||||
| } | ||||
|  | ||||
| void IbmEncoder::writeBytes(int count, uint8_t byte) | ||||
| { | ||||
| 	Bytes bytes = { byte }; | ||||
| 	for (int i=0; i<count; i++) | ||||
| 		writeBytes(bytes); | ||||
| } | ||||
|  | ||||
| static uint8_t decodeUint16(uint16_t raw) | ||||
| { | ||||
| 	Bytes b; | ||||
| 	ByteWriter bw(b); | ||||
| 	bw.write_be16(raw); | ||||
| 	return decodeFmMfm(b.toBits())[0]; | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> IbmEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| { | ||||
| 	double clockRateUs = 1e3 / _parameters.clockRateKhz; | ||||
| 	if (!_parameters.useFm) | ||||
| 		clockRateUs /= 2.0; | ||||
| 	int bitsPerRevolution = (_parameters.trackLengthMs * 1000.0) / clockRateUs; | ||||
| 	_bits.resize(bitsPerRevolution); | ||||
| 	_cursor = 0; | ||||
|  | ||||
| 	uint8_t idamUnencoded = decodeUint16(_parameters.idamByte); | ||||
| 	uint8_t damUnencoded = decodeUint16(_parameters.damByte); | ||||
|  | ||||
| 	uint8_t sectorSize = 0; | ||||
| 	{ | ||||
| 		int s = _parameters.sectorSize >> 7; | ||||
| 		while (s > 1) | ||||
| 		{ | ||||
| 			s >>= 1; | ||||
| 			sectorSize += 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	uint8_t gapFill = _parameters.useFm ? 0x00 : 0x4e; | ||||
|  | ||||
| 	writeBytes(_parameters.gap0, gapFill); | ||||
| 	if (_parameters.emitIam) | ||||
| 	{ | ||||
| 		writeBytes(_parameters.useFm ? 6 : 12, 0x00); | ||||
| 		if (!_parameters.useFm) | ||||
| 		{ | ||||
| 			for (int i=0; i<3; i++) | ||||
| 				writeRawBits(MFM_IAM_SEPARATOR, 16); | ||||
| 		} | ||||
| 		writeRawBits(_parameters.useFm ? FM_IAM_RECORD : MFM_IAM_RECORD, 16); | ||||
| 		writeBytes(_parameters.gap1, gapFill); | ||||
| 	} | ||||
|  | ||||
| 	bool first = true; | ||||
| 	for (char sectorChar : _parameters.sectorSkew) | ||||
| 	{ | ||||
| 		int sectorId = charToInt(sectorChar); | ||||
| 		if (!first) | ||||
| 			writeBytes(_parameters.gap3, gapFill); | ||||
| 		first = false; | ||||
|  | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); | ||||
| 		if (!sectorData) | ||||
| 			Error() << fmt::format("format tried to find sector {} which wasn't in the input file", sectorId); | ||||
|  | ||||
| 		/* Writing the sector and data records are fantastically annoying. | ||||
| 		 * The CRC is calculated from the *very start* of the record, and | ||||
| 		 * include the malformed marker bytes. Our encoder doesn't know | ||||
| 		 * about this, of course, with the result that we have to construct | ||||
| 		 * the unencoded header, calculate the checksum, and then use the | ||||
| 		 * same logic to emit the bytes which require special encoding | ||||
| 		 * before encoding the rest of the header normally. */ | ||||
|  | ||||
| 		{ | ||||
| 			Bytes header; | ||||
| 			ByteWriter bw(header); | ||||
|  | ||||
| 			writeBytes(_parameters.useFm ? 6 : 12, 0x00); | ||||
| 			if (!_parameters.useFm) | ||||
| 			{ | ||||
| 				for (int i=0; i<3; i++) | ||||
| 					bw.write_8(MFM_RECORD_SEPARATOR_BYTE); | ||||
| 			} | ||||
| 			bw.write_8(idamUnencoded); | ||||
| 			bw.write_8(sectorData->logicalTrack); | ||||
| 			bw.write_8(sectorData->logicalSide); | ||||
| 			bw.write_8(sectorData->logicalSector + _parameters.startSectorId); | ||||
| 			bw.write_8(sectorSize); | ||||
| 			uint16_t crc = crc16(CCITT_POLY, header); | ||||
| 			bw.write_be16(crc); | ||||
|  | ||||
| 			int conventionalHeaderStart = 0; | ||||
| 			if (!_parameters.useFm) | ||||
| 			{ | ||||
| 				for (int i=0; i<3; i++) | ||||
| 					writeRawBits(MFM_RECORD_SEPARATOR, 16); | ||||
| 				conventionalHeaderStart += 3; | ||||
|  | ||||
| 			} | ||||
| 			writeRawBits(_parameters.idamByte, 16); | ||||
| 			conventionalHeaderStart += 1; | ||||
|  | ||||
| 			writeBytes(header.slice(conventionalHeaderStart)); | ||||
| 		} | ||||
|  | ||||
| 		writeBytes(_parameters.gap2, gapFill); | ||||
|  | ||||
| 		{ | ||||
| 			Bytes data; | ||||
| 			ByteWriter bw(data); | ||||
|  | ||||
| 			writeBytes(_parameters.useFm ? 6 : 12, 0x00); | ||||
| 			if (!_parameters.useFm) | ||||
| 			{ | ||||
| 				for (int i=0; i<3; i++) | ||||
| 					bw.write_8(MFM_RECORD_SEPARATOR_BYTE); | ||||
| 			} | ||||
| 			bw.write_8(damUnencoded); | ||||
|  | ||||
| 			Bytes truncatedData = sectorData->data.slice(0, _parameters.sectorSize); | ||||
| 			bw += truncatedData; | ||||
| 			uint16_t crc = crc16(CCITT_POLY, data); | ||||
| 			bw.write_be16(crc); | ||||
|  | ||||
| 			int conventionalHeaderStart = 0; | ||||
| 			if (!_parameters.useFm) | ||||
| 			{ | ||||
| 				for (int i=0; i<3; i++) | ||||
| 					writeRawBits(MFM_RECORD_SEPARATOR, 16); | ||||
| 				conventionalHeaderStart += 3; | ||||
|  | ||||
| 			} | ||||
| 			writeRawBits(_parameters.damByte, 16); | ||||
| 			conventionalHeaderStart += 1; | ||||
|  | ||||
| 			writeBytes(data.slice(conventionalHeaderStart)); | ||||
| 		} | ||||
|     } | ||||
|  | ||||
| 	if (_cursor >= _bits.size()) | ||||
| 		Error() << "track data overrun"; | ||||
| 	while (_cursor < _bits.size()) | ||||
| 		writeBytes(1, gapFill); | ||||
|  | ||||
| 	std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| 	fluxmap->appendBits(_bits, clockRateUs*1e3); | ||||
| 	return fluxmap; | ||||
| } | ||||
|  | ||||
| @@ -2,6 +2,7 @@ | ||||
| #define IBM_H | ||||
|  | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
|  | ||||
| /* IBM format (i.e. ordinary PC floppies). */ | ||||
|  | ||||
| @@ -31,68 +32,68 @@ struct IbmIdam | ||||
| class IbmDecoder : public AbstractDecoder | ||||
| { | ||||
| public: | ||||
|     IbmDecoder(unsigned sectorBase, bool ignoreSideByte=false): | ||||
|     IbmDecoder(unsigned sectorBase, bool ignoreSideByte=false, | ||||
| 			const std::set<unsigned> requiredSectors=std::set<unsigned>()): | ||||
|         _sectorBase(sectorBase), | ||||
|         _ignoreSideByte(ignoreSideByte) | ||||
|         _ignoreSideByte(ignoreSideByte), | ||||
| 		_requiredSectors(requiredSectors) | ||||
|     {} | ||||
|  | ||||
|     RecordType advanceToNextRecord(); | ||||
|     void decodeSectorRecord(); | ||||
|     void decodeDataRecord(); | ||||
|  | ||||
| 	std::set<unsigned> requiredSectors(Track& track) const | ||||
| 	{ return _requiredSectors; } | ||||
|  | ||||
| private: | ||||
|     unsigned _sectorBase; | ||||
|     bool _ignoreSideByte; | ||||
| 	std::set<unsigned> _requiredSectors; | ||||
|     unsigned _currentSectorSize; | ||||
|     unsigned _currentHeaderLength; | ||||
| }; | ||||
|  | ||||
| #if 0 | ||||
| class AbstractIbmDecoder : public AbstractSoftSectorDecoder | ||||
| struct IbmParameters | ||||
| { | ||||
| 	int trackLengthMs; | ||||
| 	int sectorSize; | ||||
| 	bool emitIam; | ||||
| 	int startSectorId; | ||||
| 	int clockRateKhz; | ||||
| 	bool useFm; | ||||
| 	uint16_t idamByte; | ||||
| 	uint16_t damByte; | ||||
| 	int gap0; | ||||
| 	int gap1; | ||||
| 	int gap2; | ||||
| 	int gap3; | ||||
| 	std::string sectorSkew; | ||||
| }; | ||||
|  | ||||
| class IbmEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
|     AbstractIbmDecoder(unsigned sectorIdBase): | ||||
|         _sectorIdBase(sectorIdBase) | ||||
|     {} | ||||
|     virtual ~AbstractIbmDecoder() {} | ||||
| 	IbmEncoder(const IbmParameters& parameters): | ||||
| 		_parameters(parameters) | ||||
| 	{} | ||||
|  | ||||
|     SectorVector decodeToSectors(const RawRecordVector& rawRecords, unsigned physicalTrack, unsigned physicalSide); | ||||
| 	virtual ~IbmEncoder() {} | ||||
|  | ||||
| protected: | ||||
|     virtual int skipHeaderBytes() const = 0; | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
|  | ||||
| private: | ||||
|     unsigned _sectorIdBase; | ||||
| 	void writeRawBits(uint32_t data, int width); | ||||
| 	void writeBytes(const Bytes& bytes); | ||||
| 	void writeBytes(int count, uint8_t value); | ||||
| 	void writeSync(); | ||||
| 	 | ||||
| private: | ||||
| 	IbmParameters _parameters; | ||||
| 	std::vector<bool> _bits; | ||||
| 	unsigned _cursor; | ||||
| 	bool _lastBit; | ||||
| }; | ||||
|  | ||||
| class IbmFmDecoder : public AbstractIbmDecoder | ||||
| { | ||||
| public: | ||||
|     IbmFmDecoder(unsigned sectorIdBase): | ||||
|         AbstractIbmDecoder(sectorIdBase) | ||||
|     {} | ||||
|  | ||||
|     int recordMatcher(uint64_t fifo) const; | ||||
|  | ||||
| protected: | ||||
|     int skipHeaderBytes() const | ||||
|     { return 0; } | ||||
| }; | ||||
|  | ||||
| class IbmMfmDecoder : public AbstractIbmDecoder | ||||
| { | ||||
| public: | ||||
|     IbmMfmDecoder(unsigned sectorIdBase): | ||||
|         AbstractIbmDecoder(sectorIdBase) | ||||
|     {} | ||||
|  | ||||
|     nanoseconds_t guessClock(Fluxmap& fluxmap) const; | ||||
|     int recordMatcher(uint64_t fifo) const; | ||||
|  | ||||
| protected: | ||||
|     int skipHeaderBytes() const | ||||
|     { return 3; } | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -184,3 +184,25 @@ void MacintoshDecoder::decodeDataRecord() | ||||
|     _sector->data.clear(); | ||||
|     _sector->data.writer().append(userData.slice(12, 512)).append(userData.slice(0, 12)); | ||||
| } | ||||
|  | ||||
| std::set<unsigned> MacintoshDecoder::requiredSectors(Track& track) const | ||||
| { | ||||
| 	int count; | ||||
| 	if (track.physicalTrack < 16) | ||||
| 		count = 12; | ||||
| 	else if (track.physicalTrack < 32) | ||||
| 		count = 11; | ||||
| 	else if (track.physicalTrack < 48) | ||||
| 		count = 10; | ||||
| 	else if (track.physicalTrack < 64) | ||||
| 		count = 9; | ||||
| 	else | ||||
| 		count = 8; | ||||
|  | ||||
| 	std::set<unsigned> sectors; | ||||
| 	while (count--) | ||||
| 		sectors.insert(count); | ||||
| 	return sectors; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,8 @@ public: | ||||
|     RecordType advanceToNextRecord(); | ||||
|     void decodeSectorRecord(); | ||||
|     void decodeDataRecord(); | ||||
|  | ||||
| 	std::set<unsigned> requiredSectors(Track& track) const; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								doc/Index_sensor_mod_FDD_1.1.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/Index_sensor_mod_FDD_1.1.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										184
									
								
								doc/building.md
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								doc/building.md
									
									
									
									
									
								
							| @@ -25,6 +25,8 @@ This is the physical stuff you'll need. | ||||
|     connector](https://eu.mouser.com/ProductDetail/Amphenol-FCI/86130342114345E1LF?qs=%2Fha2pyFadug%252BpMTyxmFhglPPVKuWXYuFpPNgq%252BsrzhDnXxo8B28k7UCGc7F%2FXjsi) | ||||
|     (or one of the other myriad compatible connectors; there's a billion). | ||||
|  | ||||
|   - A floppy drive cable, preferably one with two connectors and a twist. | ||||
|  | ||||
|   - A suitable power supply. 3.5" floppy drives use 5V at about an amp | ||||
|     (usually less) --- sadly, too much to power from USB. 5.25" floppy drives | ||||
|     also require 12V. An old but decent quality PC power supply is ideal, as | ||||
| @@ -48,7 +50,7 @@ All you need to do is attach your chosen connector to the board. You'll need | ||||
| to make sure that pin 2 on the cable is connected to pin 2.7 on the board, | ||||
| and pin 34 to pin 1.7 on the board (and of course all the ones in between). | ||||
| Apart from grounding the board (see below), this is literally all there is to | ||||
| it. | ||||
| it. The actual pinout is described in detail below. | ||||
|  | ||||
| The pads are small, but soldering them isn't too bad with a needle-nosed | ||||
| soldering iron tip. | ||||
| @@ -173,6 +175,7 @@ pattern. Press and hold the little button near the light for five seconds | ||||
| until the light stays solidly on. Now you should be able to acquire | ||||
| the port and proceed normally. | ||||
|  | ||||
|  | ||||
| ## Building the client | ||||
|  | ||||
| The client software is where the intelligence, such as it is, is. It's pretty | ||||
| @@ -181,12 +184,12 @@ well, although on Windows it'll need MSYS2 and mingw32. You'll need to | ||||
| install some support packages. | ||||
|  | ||||
|   - For Linux (this is Ubuntu, but this should apply to Debian too): | ||||
|   `ninja-build`, `libusb-1.0-0-dev`, `libsqlite3-dev`. | ||||
|   - For OSX with Homebrew: `ninja`. | ||||
| 	`ninja-build`, `libusb-1.0-0-dev`, `libsqlite3-dev`. | ||||
|   - For OSX with Homebrew: `ninja`, `libusb`, `pkg-config`, `sqlite`. | ||||
|   - For Windows with MSYS2: `make`, `ninja`, `mingw-w64-i686-libusb`, | ||||
|   `mingw-w64-i686-sqlite3`, `mingw-w64-i686-zlib`, `mingw-w64-i686-gcc`. | ||||
| 	`mingw-w64-i686-sqlite3`, `mingw-w64-i686-zlib`, `mingw-w64-i686-gcc`. | ||||
|  | ||||
| These lists are not necessarily exhaustive --- plaese [get in | ||||
| These lists are not necessarily exhaustive --- please [get in | ||||
| touch](https://github.com/davidgiven/fluxengine/issues/new) if I've missed | ||||
| anything. | ||||
|  | ||||
| @@ -197,11 +200,176 @@ dependencies and you should be able to put it anywhere. | ||||
| If it doesn't build, please [get in | ||||
| touch](https://github.com/davidgiven/fluxengine/issues/new). | ||||
|  | ||||
|  | ||||
| ## Connecting it up | ||||
|  | ||||
| You should now have a working board, so it's time to test it. | ||||
|  | ||||
|   1. Plug the motherboard end of your floppy disk cable into the FluxEngine. | ||||
|       | ||||
|      The **red stripe goes on the right**. The **lower set of | ||||
|      holes connect to the board**. See the pinout below. | ||||
|  | ||||
|      If you're using header pins, the upper row of holes in the connector | ||||
|      should overhang the edge of the board. If you're using a floppy drive | ||||
|      motherboard connector, you're golden, of course (unless you have one of | ||||
|      those annoying unkeyed cables, or have accidentally soldered the | ||||
|      connector on in the wrong place --- don't laugh, I've done it.) | ||||
|  | ||||
|   2. Plug the drive end of your floppy disk cable into the drive (or drives). | ||||
|  | ||||
|      Floppy disk cables typically have [two pairs of floppy disk drive | ||||
|      connectors with a twist between | ||||
|      them](http://www.nullmodem.com/Floppy.htm). (Each pair has one connector | ||||
|      for a 3.5" drive and a different one for a 5.25" drive.) (Some cables | ||||
|      are cheap and just have the 3.5" connectors. Some are _very_ cheap and | ||||
|      have a single 3.5" connector, after the twist.) | ||||
|       | ||||
|      If you have **two** drives, plug them into both connectors. FluxEngine, | ||||
|      sadly, non-standard disk numbering (there are reasons). Drive 0 is the | ||||
|      one nearest the motherboard; that is, before the twist. Drive 1 is the | ||||
|      one at the end of the cable; that is, after the twist. Drive 0 is the | ||||
|      default. You can tell the client to select drive 1 by using `-s :d=1`. | ||||
|  | ||||
|      If you have **one** drive, you may plug it into _either_ connector. | ||||
|      FluxEngine will autodetect it and treat it as drive 0. However, you'll | ||||
|      get the most reliable electrical signal if you plug it in at the end of | ||||
|      the cable. | ||||
|  | ||||
|      **A note on termination:** some 5.25" drives require jumper configuration | ||||
|      to tell them whether they're at the end of the cable or in the middle of | ||||
|      the cable. 3.5" drives don't, and my 5.25" drives don't, so I can't | ||||
|      advise there. Consult your drive datasheet for details. | ||||
|  | ||||
|   3. **Important.** Make sure that no disk you care about is in the drive. | ||||
| 	 (Because if your wiring is wrong and a disk is inserted, you'll corrupt | ||||
| 	 it.) | ||||
|  | ||||
|   4. Connect the floppy drive to power. Nothing should happen. If you've | ||||
| 	 connected something in backwards, you'll see the drive light up, the motor | ||||
| 	 start, and if you didn't take the disk out, one track has just been wiped. | ||||
| 	 If this happens, check your wiring. | ||||
|  | ||||
|   5. Strip off the little piece of protective plastic on the USB socket on the | ||||
| 	 board --- the little socket at the end, not the big programmer plug. | ||||
|  | ||||
|   6. Connect the FluxEngine to your PC via USB. | ||||
|  | ||||
|   7. Insert a scratch disk and do `fluxengine rpm` from the shell. The motor | ||||
|      should work and it'll tell you that the disk is spinning at about 300 | ||||
|      rpm for a 3.5" disk, or 360 rpm for a 5.25" disk. If it doesn't, please | ||||
|      [get in touch](https://github.com/davidgiven/fluxengine/issues/new). | ||||
|  | ||||
|   8. Do `fluxengine test bandwidth` from the shell. It'll measure your USB | ||||
| 	 bandwidth. Ideally you should be getting above 900kB/s in both directions. | ||||
| 	 FluxEngine needs about 400kB/s for a DD disk and about 850kB/s for a HD | ||||
| 	 disk, so if you're getting less than this, try a different USB port. | ||||
|  | ||||
|   9. Insert a standard PC formatted floppy disk into the drive (probably a good | ||||
|      idea to remove the old disk first). Then do `fluxengine read ibm`. It | ||||
|      should read the disk, emitting copious diagnostics, and spit out an | ||||
|      `ibm.img` file containing the decoded disk image (either 1440kB or 720kB | ||||
|      depending). | ||||
|  | ||||
|  10. Profit! | ||||
|  | ||||
| ## Technical details | ||||
|  | ||||
| The board pinout and the way it's connected to the floppy bus is described | ||||
| below. | ||||
|  | ||||
| ```ditaa | ||||
| :-E -s 0.75 | ||||
|                  +-----+ | ||||
|                  ||||||| | ||||
|             +----+-----+----+ | ||||
|             +cAAA           + | ||||
|             +  Debug board  + | ||||
|             +----+-----+----+ | ||||
|             + GND|cDDD | VDD+   | ||||
|             +----+     +----+ | ||||
| INDEX300 ---+ 3.0|     | GND+--------------------------+ | ||||
|             +----+     +----+                 +--+--+  | | ||||
| INDEX360 ---+ 3.1|     | 1.7+------ DISKCHG --+34+33+--+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.2|     | 1.6+------- SIDE1 ---+32+31+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.3|     | 1.5+------- RDATA ---+30+29+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.4|     | 1.4+-------- WPT ----+28+27+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.5|     | 1.3+------- TRK00 ---+26+25+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.6|     | 1.2+------- WGATE ---+24+23+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.7|     | 1.1+------- WDATA ---+22+21+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.0|     | 1.0+------- STEP ----+20+19+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.1|     |12.0+-------- DIR ----+18+17+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.2|     |12.1+------- MOTEB ---+16+15+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.3|     |12.2+------- DRVSA ---+14+13+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.4|     |12.3+------- DRVSB ---+12+11+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.5|     |12.4+------- MOTEA ---+10+9 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.0|     |12.5+------- INDEX ---+8 +7 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.1|     |12.6+-------- n/c ----+6 +5 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.2|     |12.7+- TX --- n/c ----+4 +3 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.3|     | 2.7+------- REDWC ---+2 +1 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.4|     | 2.6+   | ||||
|             +----+     +----+                FDD socket | ||||
|             + 0.5|     | 2.5+   | ||||
|             +----+     +----+ | ||||
|             + 0.6|     | 2.4+    TX: debug UART from board | ||||
|             +----+     +----+ | ||||
|             + 0.7|     | 2.3+ | ||||
|             +----+     +----+ | ||||
|             + RST|     | 2.2+   | ||||
|             +----+     +----+ | ||||
|             + GND|     | 2.1+   | ||||
|             +----+ USB +----+ | ||||
|             + VDD+-----+ 2.0+   | ||||
|             +----+-----+----+ | ||||
|                PSoC5 board | ||||
| ``` | ||||
|  | ||||
| Notes: | ||||
|  | ||||
|   - `TX` is the debug UART port. It's on pin 12.7 because the board routes it | ||||
|   to the USB serial port on the programmer, so you can get debug information | ||||
|   from the FluxEngine by just plugging the programming end into a USB port | ||||
|   and using a serial terminal at 115200 baud. If you solder a floppy drive | ||||
|   connector on, then it'll end up connected to pin 4 of the floppy drive bus, | ||||
|   which is usually not connected. It's possible that some floppy drives do, | ||||
|   in fact, use this pin. You may wish to remove pin 4 from the floppy drive | ||||
|   socket before attaching it to the FluxEngine to make sure that this pin is | ||||
|   not connected; however, so far I have not found any drives for which this | ||||
|   is necessary. If you do find one, _please_ [get in | ||||
|   touch](https://github.com/davidgiven/fluxengine/issues/new) so I can | ||||
|   document it. | ||||
|  | ||||
|   - The `GND` pin only really needs to be connected to one of the floppy bus | ||||
|   ground pins; pin 33 is the closest. For extra safety, you can bridge all | ||||
|   the odd numbered pins together and ground them all if you like. | ||||
|  | ||||
|   - `INDEX300` and `INDEX360` are optional output pins which generate fake | ||||
|   timing pulses for 300 and 360 RPM drives. These are useful for certain | ||||
|   rather exotic things. See the section on flippy disks [in the FAQ](faq.md) | ||||
|   for more details; you can normally ignore these. | ||||
|  | ||||
| ## Next steps | ||||
|  | ||||
| The board's now assembled and programmed. Plug it into your drive, strip the | ||||
| plastic off the little USB connector and plug that into your computer, and | ||||
| you're ready to start using it. | ||||
| You should now be ready to go. You'll want to read [the client | ||||
| documentation](using.md) for information about how to actually do interesting | ||||
| things. | ||||
|  | ||||
| I _do_ make updates to the firmware whenever necessary, so you may need to | ||||
| reprogram it at intervals; you may want to take this into account if you | ||||
|   | ||||
| @@ -10,7 +10,7 @@ Bizarrely, the data in each sector is stored with all the odd bits first, and | ||||
| then all the even bits. This is tied into the checksum algorithm, which is | ||||
| distinctly subpar and not particularly good at detecting errors. | ||||
|  | ||||
| Reading discs | ||||
| Reading disks | ||||
| ------------- | ||||
|  | ||||
| Just do: | ||||
| @@ -34,6 +34,28 @@ You will end up with a 929280 byte long image which you probably _can't_ use | ||||
| in an emulator; each sector will contain the 512 bytes of user payload | ||||
| followed by the 16 bytes of metadata. | ||||
|  | ||||
| Writing disks | ||||
| ------------- | ||||
|  | ||||
| Just do: | ||||
|  | ||||
| ``` | ||||
| fluxengine write amiga -i amiga.adf | ||||
| ``` | ||||
|  | ||||
| This will rake a normal 901120 byte long ADF file and write it to a DD disk. | ||||
| Note that writing to an HD disk will probably not work (this will depend on | ||||
| your drive and disk and potential FluxEngine bugs I'm still working on --- | ||||
| please [get in touch](https://github.com/davidgiven/fluxengine/issues/new) if | ||||
| you have any insight here). | ||||
|  | ||||
| If you want to write the metadata as well, specify a 528 byte sector size for | ||||
| the output image and supply a 929280 byte long file as described above. | ||||
|  | ||||
| ``` | ||||
| fluxengine write amiga -i amiga.adf:b=528 | ||||
| ``` | ||||
|  | ||||
| Useful references | ||||
| ----------------- | ||||
|  | ||||
|   | ||||
| @@ -14,10 +14,12 @@ Apparently about 20% of Brother word processors have alignment issues which | ||||
| means that the disks can't be read by FluxEngine (because the tracks on the | ||||
| disk don't line up with the position of the head in a PC drive). The word | ||||
| processors themselves solved this by microstepping until they found where the | ||||
| real track is, but normal PC drives aren't capable of doing this. | ||||
| Particularly with the 120kB disks, you might want to fiddle with the start | ||||
| track (e.g. `:t=0-79x2`) to get a clean read. Keep an eye on the bad sector | ||||
| map that's dumped at the end of a read. | ||||
| real track is, but normal PC drives aren't capable of doing this.  Particularly | ||||
| with the 120kB disks, you might want to fiddle with the start track (e.g. | ||||
| `:t=0-79x2`) to get a clean read. Keep an eye on the bad sector map that's | ||||
| dumped at the end of a read. My word processor likes to put logical track 0 on | ||||
| physical track 3, which means that logical track 77 is on physical track 80; | ||||
| luckily my PC drive can access track 80. | ||||
|  | ||||
| Using FluxEngine to *write* disks isn't a problem, so the | ||||
| simplest solution is to use FluxEngine to create a new disk, with the tracks | ||||
| @@ -30,7 +32,7 @@ If you find one of these misaligned disks then *please* [get in | ||||
| touch](https://github.com/davidgiven/fluxengine/issues/new); I want to | ||||
| investigate. | ||||
|  | ||||
| Reading discs | ||||
| Reading disks | ||||
| ------------- | ||||
|  | ||||
| Just do: | ||||
| @@ -41,7 +43,7 @@ fluxengine read brother | ||||
|  | ||||
| You should end up with a `brother.img` which is 239616 bytes long. | ||||
|  | ||||
| Writing discs | ||||
| Writing disks | ||||
| ------------- | ||||
|  | ||||
| Just do: | ||||
| @@ -53,6 +55,27 @@ fluxengine write brother | ||||
| ...and it'll write a `brother.img` file which is 239616 bytes long to the | ||||
| disk. (Use `-i` to specify a different input filename.) | ||||
|  | ||||
| Dealing with misaligned disks | ||||
| ----------------------------- | ||||
|  | ||||
| While FluxEngine can't read misaligned disks directly, Brother word processors | ||||
| _can_. If you have access to a compatible word processor, there's a fairly | ||||
| simple workaround to allow you to extract the data: | ||||
|  | ||||
|   1. Format a disk using FluxEngine (by simply writing a blank filesystem image | ||||
| 	 to a disk). This will have the correct alignment to work on a PC drive. | ||||
|  | ||||
|   2. Use a word processor to copy the misaligned disk to the newly formatted | ||||
| 	 disk. The machine will happily adjust itself to both sets of alignments. | ||||
|  | ||||
|   3. Use FluxEngine to read the data off the correctly aligned disk. | ||||
|  | ||||
| I realise this is rather unsatisfactory, as the Brother hardware is becoming | ||||
| rarer and they cope rather badly with damaged disks, but this is a limitation | ||||
| of the hardware of normal PC drives. (It _is_ possible to deliberately misalign | ||||
| a drive to make it match up with a bad disk, but this is for experts only --- I | ||||
| wouldn't dare.) | ||||
|  | ||||
| Low level format | ||||
| ---------------- | ||||
|  | ||||
| @@ -60,14 +83,6 @@ The drive is a single-sided 3.5" drive spinning at not 300 rpm (I don't know | ||||
| the precise speed yet but FluxEngine doesn't care). The 240kB disks have 78 | ||||
| tracks and the 120kB disks have 39. | ||||
|  | ||||
| The Brother drive alignment is kinda variable; when you put the disk in the | ||||
| drive it seeks all the way to physical track 0 and then starts searching for | ||||
| something which looks like data. My machine likes to put logical track 0 on | ||||
| physical track 3. FluxEngine puts logical track 0 on physical track 0 for | ||||
| simplicity, which works fine (at least on my machine). If this doesn't work | ||||
| for you, [get in touch](https://github.com/davidgiven/fluxengine/issues/new); | ||||
| there are potential workarounds. | ||||
|  | ||||
| Each track has 12 256-byte sectors. The drive ignores the index hole so they're | ||||
| lined up all anyhow. As FluxEngine can only read from index to index, it | ||||
| actually reads two complete revolutions and reassembles the sectors from that. | ||||
| @@ -138,7 +153,8 @@ mcopy -i brother.img ::brother.doc linux.doc | ||||
| ``` | ||||
|  | ||||
| The word processor checks the media byte, unfortunately, so you'll need to | ||||
| change it back to 0x58 before writing an image to disk. | ||||
| change it back to 0x58 before writing an image to disk. Just run | ||||
| `brother240tool` on the image again and it will flip it back. | ||||
|  | ||||
| The file format is not WP-1, and currently remains completely unknown, | ||||
| although it's probably related. If anyone knows anything about this, please | ||||
|   | ||||
							
								
								
									
										152
									
								
								doc/disk-ibm.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								doc/disk-ibm.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| Disk: Generic IBM | ||||
| ================= | ||||
|  | ||||
| IBM scheme disks are _the_ most common disk format, ever. They're used by a | ||||
| huge variety of different systems, and they come in a huge variety of different | ||||
| forms, but they're all fundamentally the same: either FM or MFM, either single | ||||
| or double sided, with distinct sector header and data records and no sector | ||||
| metadata. Systems which use IBM scheme disks include but are not limited to: | ||||
|  | ||||
|   - IBM PCs (naturally) | ||||
|   - Atari ST | ||||
|   - late era Apple machines | ||||
|   - Acorn machines | ||||
|   - the TRS-80 | ||||
|   - late era Commodore machines (the 1571 and so on) | ||||
|   - most CP/M machines | ||||
|   - etc | ||||
|  | ||||
| FluxEngine supports reading these. However, some variants are more peculiar | ||||
| than others, and as a result there are specific decoders which set the defaults | ||||
| correctly for certain formats (for example: on PC disks the sector numbers | ||||
| start from 1, but on [Acorn](disk-acorndfs.md) disks they start from 0). The | ||||
| IBM decoder described here is the generic one, and is suited for 'conventional' | ||||
| PC disks. While you can read all the variant formats with it if you use the | ||||
| right set of arguments, it's easier to use the specific decoder. | ||||
|  | ||||
| The generic decoder is mostly self-configuring, and will detect the format of | ||||
| your disk for you. | ||||
|  | ||||
|  | ||||
| Reading disks | ||||
| ------------- | ||||
|  | ||||
| Just do: | ||||
|  | ||||
|     fluxengine read ibm | ||||
|  | ||||
| ...and you'll end up with an `ibm.img` file. This should work on most PC disks | ||||
| (including FM 360kB disks, 3.5" 1440kB disks, 5.25" 1200kB disks, etc.) The size | ||||
| of the disk image will vary depending on the format. | ||||
|  | ||||
| Configuration options you'll want include: | ||||
|  | ||||
|   - `--ibm-sector-id-base=N`: specifies the ID of the first sector; this defaults | ||||
| 	to 1. Some formats (like the Acorn ones) start at 0. This can't be | ||||
| 	autodetected because FluxEngine can't distinguish between a disk which | ||||
| 	starts at sector 1 and a disk which starts at sector 0 but all the sector | ||||
| 	0s are missing. | ||||
|  | ||||
|   - `--ibm-ignore-side-byte=true|false`: each sector header describes the location of the | ||||
| 	sector: sector ID, track and side. Some formats use the wrong side ID, so | ||||
| 	the sectors on side 1 are labelled as belonging to side 0. This causes | ||||
| 	FluxEngine to see duplicate sectors (as it can't distinguish between the | ||||
| 	two sides). This option tells FluxEngine to ignore the side byte completely | ||||
| 	and use the physical side instead. | ||||
|  | ||||
|   - `--ibm-required-sectors=range`: if you know how many sectors to expect per | ||||
| 	track, you can improve reads by telling FluxEngine what to expect here. If | ||||
| 	a track is read and a sector on this list is _not_ present, then FluxEngine | ||||
| 	assumes the read failed and will retry. This avoids the situation where | ||||
| 	FluxEngine can't tell the difference between a sector missing because it's | ||||
| 	bad or a sector missing because it was never written in the first place. If | ||||
| 	sectors are seen outside the range here, it will still be read. You can use | ||||
| 	the same syntax as for track specifiers: e.g. `0-9`, `0,1,2,3`, etc. | ||||
|  | ||||
|  | ||||
| Writing disks | ||||
| ------------- | ||||
|  | ||||
| FluxEngine can also write IBM scheme disks. Unfortunately the format is | ||||
| incredibly flexible and you need to specify every single parameter, which | ||||
| makes things slightly awkward. | ||||
|  | ||||
| The syntax is: | ||||
|  | ||||
|     fluxengine write ibm -i input.img <options> | ||||
|  | ||||
| The format of `input.img` will vary depending on the kind of disk you're | ||||
| writing, which is configured by the options. There are some presets, which | ||||
| you will almost certainly want to use if possible: | ||||
|  | ||||
|   - `--ibm-preset-720`: a standard 720kB DS DD 3.5" disk, with 80 cylinders, | ||||
|   2 sides, and 9 sectors per track. | ||||
|   - `--ibm-preset-1440`: a standard 1440kB DS HD 3.5" disk, with 80 | ||||
|   cylinders, 2 sides, and 18 sectors per track. | ||||
|  | ||||
| These options simply preset the following, lower-level options. Note that | ||||
| options are processed left to right, so it's possible to use a preset and | ||||
| then change some settings. To see the values for a preset, simply append | ||||
| `--help`. | ||||
|  | ||||
|   - `--ibm-track-length-ms=N`: one disk rotation, in milliseconds. This is used | ||||
|   to determine whether all the data will fit on a track or not. `fluxengine | ||||
|   rpm` will tell you this; it'll be 200 for a normal 3.5" drive and 166 for a | ||||
|   normal 5.25" drive. | ||||
|   - `--ibm-sector-size=N`: the size of a sector, in bytes. Must be a power of | ||||
|   two. | ||||
|   - `--ibm-emit-iam=true|false`: whether to emit the IAM record at the top of | ||||
|   the track. The standard format requires it, but it's ignored by absolutely | ||||
|   everyone and you can fit a bit more data on the disk without it. | ||||
|   - `--ibm-start-sector-id=N`: the sector ID of the first sector. Normally 1, | ||||
|   except for non-standard formats like Acorn's, which use 0. | ||||
|   - `--ibm-use-fm=true|false`: uses FM rather than MFM. | ||||
|   - `--ibm-idam-byte=N`: the sixteen-bit raw bit pattern used for the IDAM ID | ||||
|   byte. Big-endian, clock bit first. | ||||
|   - `--ibm-dam-byte-N`: the sixteen-bit raw bit pattern used for the DAM ID | ||||
|   byte. Big-endian, clock bit first. | ||||
|   - `--ibm-gap0-bytes=N`: the size of gap 0 in bytes (between the start of | ||||
|   the track and the IAM record). | ||||
|   - `--ibm-gap1-bytes=N`: the size of gap 1 in bytes (between the IAM record | ||||
|   and the first sector record). | ||||
|   - `--ibm-gap2-bytes=N`: the size of gap 2 in bytes (between each sector | ||||
|   record and the data record). | ||||
|   - `--ibm-gap3-bytes=N`: the size of gap 3 in bytes (between the data record | ||||
|   and the next sector record). | ||||
|   - `--ibm-sector-skew=0123...`: a string representing the order in which to | ||||
|   write sectors: each character represents on sector, with `0` being the | ||||
|   first (always, regardless of `--ibm-start-sector-id` above). Sectors 10 and | ||||
|   above are represented as latters from `A` up. | ||||
|  | ||||
| Mixed-format disks | ||||
| ------------------ | ||||
|  | ||||
| Some disks, usually those belonging to early CP/M machines, have more than one | ||||
| format on the disk at once. Typically, the first few tracks will be low-density | ||||
| FM encoded and will be read by the machine's ROM; those tracks contain new | ||||
| floppy drive handling code capable of coping with MFM data, and so the rest of | ||||
| the disk will use that, allowing them to store more data. | ||||
|  | ||||
| FluxEngine copes with these fine, but the disk images are a bit weird. If track | ||||
| 0 is FM and contains five sectors, but track 1 is MFM with nine sectors (MFM is | ||||
| more efficient and the sectors are physically smaller, allowing you to get more | ||||
| on), then the resulting image will have nine sectors per track... but track 0 | ||||
| will only contain data in the first five. | ||||
|  | ||||
| This is typically what you want as it makes locating the sectors in the image | ||||
| easier, but emulators will typically require a different format. Please [get | ||||
| in touch](https://github.com/davidgiven/fluxengine/issues/new) if you have | ||||
| specific requirements (nothing's come up yet). Alternatively, you can tell | ||||
| FluxEngine to write a [`.ldbs` | ||||
| file](http://www.seasip.info/Unix/LibDsk/ldbs.html) and then use | ||||
| [libdsk](http://www.seasip.info/Unix/LibDsk/) to convert it to something | ||||
| useful. | ||||
|  | ||||
| One easy option when reading these is to simply read the two sections of the | ||||
| disk into two different image files. | ||||
|  | ||||
| FluxEngine can write these too, but in two different passes with different | ||||
| options. It's possible to assemble a flux file by judicious use of `-D | ||||
| something.flux --merge`, which can then be written in a single pass with | ||||
| `fluxengine writeflux`, but it's usually not worth the bother: just write the | ||||
| boot tracks, then write the data tracks, possibly with a script for automation. | ||||
| @@ -28,8 +28,16 @@ for example the Commodore 64 1541 drive, changed bitrate this way. | ||||
| But Macintosh disks used a constant bitrate and changed the speed that the | ||||
| disk spun instead to achieve the same effect... | ||||
|  | ||||
| _Anyway_: FluxEngine will read them fine on a conventional drive. Because | ||||
| it's clever. | ||||
| _Anyway_: FluxEngine will read them fine on conventional drives. | ||||
| Because it's clever. | ||||
|  | ||||
| **Big note.** Apparently --- and I'm still getting to the bottom of this --- | ||||
| some drives work and some don't. My drives produce about 90% good reads of | ||||
| known good disks. One rumour I've heard is that drives sometimes include | ||||
| filters which damage the signals at very particular intervals which Mac disks | ||||
| use, but frankly this seems unlikely; it could be a software issue at my end | ||||
| and I'm investigating. If you have any insight, please [get in | ||||
| touch](https://github.com/davidgiven/fluxengine/issues/new). | ||||
|  | ||||
| Reading discs | ||||
| ------------- | ||||
|   | ||||
							
								
								
									
										20
									
								
								doc/faq.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								doc/faq.md
									
									
									
									
									
								
							| @@ -48,7 +48,7 @@ haven't had the chance to try it end-for-end. I really need a hard-sectored | ||||
|  | ||||
| **Q.** Does it work with flippy disks? | ||||
|  | ||||
| Uhhh... probably not. | ||||
| Uhhh... maybe? | ||||
|  | ||||
| So the problem with flippy disks (5.25" single-sided disks which could be | ||||
| inserted upside down to read the second side) is the index hole. Trouble is, | ||||
| @@ -79,16 +79,26 @@ the other. But a flippy disk has both sets of tracks in the same place, | ||||
| because they're both accessed using the side 0 head... | ||||
|  | ||||
| The only real way round this is to modify a 5.25" drive. That's _seriously_ | ||||
| not in FluxEngine's remit. Sorry. | ||||
| not in FluxEngine's remit, but I've had some [excellent documentation | ||||
| contributed](Index_sensor_mod_FDD_1.1.pdf) on how to do this. I've never done | ||||
| it myself; if you try this and it works/doesn't work, as always, [get in | ||||
| touch](https://github.com/davidgiven/fluxengine/issues/new). | ||||
|  | ||||
| **Q.** Is this like KryoFlux / Catweasel / DiskFerret? Do you support KryoFlux | ||||
| Another option is to fake the index signal to the drive completely. The | ||||
| FluxEngine emits suitable pulses for a 300RPM drive on pin 3[0] and the | ||||
| equivalent pulses for a 360RPM drive on pin 3[1]. Disclaimer: I have never used | ||||
| these. | ||||
|  | ||||
| **Q.** Is this like Supercard Pro / KryoFlux / Catweasel / DiskFerret? Do you | ||||
| *support KryoFlux | ||||
| stream files? | ||||
|  | ||||
| **A.** It's very like all of these; the idea's old, and lots of people have | ||||
| tried it (you can get away with any sufficiently fast microcontroller and | ||||
| enough RAM). FluxEngine can read from KryoFlux stream files natively, and | ||||
| there's a tool which will let you convert at least one kind of Catweasel file | ||||
| to FluxEngine's native flux file format. | ||||
| there's a tool which will let you convert at least one kind of Catweasel | ||||
| files and Supercard Pro files to and from FluxEngine's native flux file | ||||
| format. | ||||
|  | ||||
| **Q.** Can I use this to make exact copies of disks? | ||||
|  | ||||
|   | ||||
| @@ -59,53 +59,42 @@ Some useful and/or interesting numbers: | ||||
|  | ||||
| ## Why don't I use an Arduino / STM32 / ESP32 / Raspberry Pi / etc? | ||||
|  | ||||
| I've got a _lot_ of questions on this, and multiple Github issues of people | ||||
| -I've got a _lot_ of questions on this, and multiple Github issues of people | ||||
| debating it. It's complicated, but it's essentially a tradeoff between speed | ||||
| and complexity. | ||||
| and complexity.- | ||||
|  | ||||
| FluxEngine's read process involves generating a lot of data using a fairly | ||||
| brute force sampling approach --- about 150kB per disk revolution, and | ||||
| sometimes it needs to record multiple revolutions. Most microcontrollers | ||||
| don't have enough RAM to buffer this, so instead I have to stream it over USB | ||||
| back to the host PC in real time. The disk won't wait, so I need to stream data faster | ||||
| than the disk is producing it: the total is about 800kB/s. | ||||
| **Update as of 2020-01-08:** | ||||
|  | ||||
| Handling USB is pretty CPU-hungry, so my candidate microntroller has to be | ||||
| able to cope with the ruinously strict real-time requirements of the | ||||
| sampler's 12MHz clock as well as keeping up with 13,000 USB interrupts a | ||||
| second (one for each 64-byte frame) in order to transfer the data. | ||||
| Right. Well. | ||||
|  | ||||
| The Atmels and STM32s I found were perfectly capable of doing the real-time | ||||
| sampling, using hand-tool assembly, but I very much doubt whether they could | ||||
| do the USB streaming as well (although I want to move away from the Cypress | ||||
| onto something less proprietary and easier to source, so I'd like to be | ||||
| proven wrong here). | ||||
| This section used to have a long explanation as to why these other platforms | ||||
| were unsuitable --- essentially, they're generally missing out on either the | ||||
| realtimeness to sample the data correctly (Raspberry Pi) or enough CPU to | ||||
| stream the data over USB while also sampling it (Arduino). | ||||
|  | ||||
| The Raspberry Pi easily has enough processing power and memory, but it's also | ||||
| got terrible GPIO pin read performance --- [about | ||||
| 1kHz](https://raspberrypi.stackexchange.com/questions/9646/how-fast-is-gpiodma-multi-i2s-input/10197#10197). | ||||
| That's a long way from the 12MHz I need. | ||||
| This is correct, but it turns out that the STM32 has some built-in features | ||||
| which support the FluxEngine's use case almost exactly: you can configure the | ||||
| DMA engine to sample the interval between pulses and write them directly into | ||||
| memory, and you can configure the PWM engine the read samples from memory and | ||||
| use them to time pulses to the output. There's a bit less functionality, so you | ||||
| can't do things like measure the signal voltages, and they're less convenient | ||||
| as you need an adapter cable or board, but this will allow you to replicate the | ||||
| FluxEngine hardware on a $2 Blue Pill. | ||||
|  | ||||
| The PSoC5LP part I'm using has enough CPU to handle the USB side of things, | ||||
| and it _also_ has a whole set of FPGA-like soft programmable features, | ||||
| including 24 mini-ALU systems that are ideally suited to exactly this kind of | ||||
| sampling. I can read the disk and generate the byte stream describing the | ||||
| flux pattern entirely in 'hardware', without involving the main CPU at all. | ||||
| This is then DMAed directly into a set of ring buffers read for the USB | ||||
| system to pick up and relay back to the PC. It's incredibly simple and works | ||||
| well. (The same applies to writing flux back onto the disk.) | ||||
| I am _not_ planning on replacing the PSoC5 with a Blue Pill, because someone | ||||
| already has: [the GreaseWeazle](https://github.com/keirf/Greaseweazle/wiki) is | ||||
| a completely open source firmware package which will read and write Supercard | ||||
| Pro files via a standard Blue Pill. The GreaseWeazle's USB protocol is | ||||
| different from the FluxEngine's so they're not directly interchangeable. You | ||||
| can, however, read a Supercard Pro file with a GreaseWeazle and then use the | ||||
| FluxEngine client to decode it. It should work the other way around, too, but | ||||
| FluxEngine's SCP export [is curently | ||||
| broken](https://github.com/davidgiven/fluxengine/issues/134). | ||||
|  | ||||
| The development board I'm using, the | ||||
| [CY8CKIT-059](https://www.cypress.com/documentation/development-kitsboards/cy8ckit-059-psoc-5lp-prototyping-kit-onboard-programmer-and), | ||||
| also has another big advantage: it's the right shape. It's got 17 holes in a | ||||
| row connected to GPIO pins, and it's a native 5V part, which means I can just | ||||
| connect a floppy drive connector directly to the board without needing to | ||||
| build any hardware. No adapter board, no level shifting, no special cable, | ||||
| nothing. This makes the FluxEngine hardware incredibly easy to assemble, | ||||
| which therefore means cheap. | ||||
| I _am_ considering adding direct support for the GreaseWeazle to the FluxEngine | ||||
| client, which will let you just plug one in and make it go as a direct | ||||
| replacement to the FluxEngine hardware. | ||||
|  | ||||
| Speaking of which, the CY8CKIT-059 is $10. (Before shipping, which is | ||||
| admittedly expensive.) | ||||
|  | ||||
| ### Some useful links | ||||
|  | ||||
|   | ||||
							
								
								
									
										219
									
								
								doc/using.md
									
									
									
									
									
								
							
							
						
						
									
										219
									
								
								doc/using.md
									
									
									
									
									
								
							| @@ -1,68 +1,8 @@ | ||||
| Using a FluxEngine | ||||
| ================== | ||||
|  | ||||
| So you've [built the hardware](building.md)! What now? | ||||
|  | ||||
| ## Connecting it up | ||||
|  | ||||
| In order to do anything useful, you have to plug it in to a floppy disk drive (or two). | ||||
|  | ||||
|   1. Plug the motherboard end of your floppy disk cable into the FluxEngine. | ||||
|       | ||||
|      The **red stripe goes on the right**. The **lower set of | ||||
|      holes connect to the board**. (Pin 2 of the connector needs to connect | ||||
|      to pin 2.7 on the board.) | ||||
|  | ||||
|      If you're using header pins, the upper row of holes in the connector | ||||
|      should overhang the edge of the board. If you're using a floppy drive | ||||
|      motherboard connector, you're golden, of course (unless you have one of | ||||
|      those annoying unkeyed cables, or have accidentally soldered the | ||||
|      connector on in the wrong place --- don't laugh, I've done it.) | ||||
|  | ||||
|   2. Plug the drive end of your floppy disk cable into the drive (or drives). | ||||
|  | ||||
|      Floppy disk cables typically have [two pairs of floppy disk drive | ||||
|      connectors with a twist between | ||||
|      them](http://www.nullmodem.com/Floppy.htm). (Each pair has one connector | ||||
|      for a 3.5" drive and a different one for a 5.25" drive.) (Some cables | ||||
|      are cheap and just have the 3.5" connectors. Some are _very_ cheap and | ||||
|      have a single 3.5" connector, after the twist.) | ||||
|       | ||||
|      FluxEngine uses, sadly, non-standard disk numbering (there are reasons). | ||||
|      Drive 0 is the one nearest the motherboard; that is, before the twist. | ||||
|      Drive 1 is the one at the end of the cable; that is, after the twist. | ||||
|      Drive 0 is the default. If you only have one drive, remember to plug the | ||||
|      drive into the connector _before_ the twist. (Or use `-s :d=1` to select | ||||
|      drive 1 when working with disks.) | ||||
|  | ||||
|   3. **Important.** Make sure that no disk you care about is in the drive. | ||||
|      (Because if your wiring is wrong and a disk is inserted, you'll corrupt it.) | ||||
|  | ||||
|   4. Connect the floppy drive to power. Nothing should happen. If you've | ||||
|      connected something in backwards, you'll see the drive light up, the | ||||
|      motor start, and if you didn't take the disk out, one track has just | ||||
|      been wiped. If this happens, check your wiring. | ||||
|  | ||||
|   5. Connect the FluxEngine to your PC via USB --- using the little socket on | ||||
|      the board, not the big programmer plug. | ||||
|  | ||||
|   6. Insert a scratch disk and do `fluxengine rpm` from the shell. The motor | ||||
|      should work and it'll tell you that the disk is spinning at about 300 | ||||
|      rpm for a 3.5" disk, or 360 rpm for a 5.25" disk. If it doesn't, please | ||||
|      [get in touch](https://github.com/davidgiven/fluxengine/issues/new). | ||||
|  | ||||
|   7. Do `fluxengine testbulktransport` from the shell. It'll measure your USB | ||||
|      bandwidth. Ideally you should be getting above 900kB/s. FluxEngine needs | ||||
|      about 850kB/s, so if you're getting less than this, try a different USB | ||||
|      port. | ||||
|  | ||||
|   8. Insert a standard PC formatted floppy disk into the drive (probably a good | ||||
|      idea to remove the old disk first). Then do `fluxengine read ibm`. It | ||||
|      should read the disk, emitting copious diagnostics, and spit out an | ||||
|      `ibm.img` file containing the decoded disk image (either 1440kB or 720kB | ||||
|      depending). | ||||
|  | ||||
|   9. Profit! | ||||
| So you've [built the hardware](building.md), programmed and tested it! What | ||||
| now? | ||||
|  | ||||
| ## The programs | ||||
|  | ||||
| @@ -71,10 +11,33 @@ moving too quickly for the documentation to keep up. It does respond to | ||||
| `--help` or `help` depending on context. There are some common properties, | ||||
| described below. | ||||
|  | ||||
| ### Core concepts | ||||
|  | ||||
| FluxEngine fundamentally takes file system images and puts them on disk; or | ||||
| reads the disk and produces a file system image. | ||||
|  | ||||
| A file system image typically has the extension `.img`. It contains a | ||||
| sector-by-sector record of the _decoded_ data on the disk. For example, on a | ||||
| disk with 512 byte sectors, one sector will occupy 512 bytes. These are | ||||
| typically what you want in everyday life. | ||||
|  | ||||
| FluxEngine can also record the raw magnetic data on the disk into a file, which | ||||
| we call a _flux file_. This contains all the low-level data which the drive | ||||
| produced as the disk rotated. These are continuous streams of samples from the | ||||
| disk and are completely useless in day-to-day life. FluxEngine uses its own | ||||
| format for this, `.flux`, although it's capable of limited interchange with | ||||
| Kryoflux, Supercard Pro and Catweasel files. A flux file will typically contain | ||||
| from 80 to 150 kilobytes of data per track. | ||||
|  | ||||
| In general, FluxEngine can use either a real disk or a flux file | ||||
| interchangeably: you can specify either at (very nearly) any time. A very | ||||
| common workflow is to read a disk to a flux file, and then reread from the flux | ||||
| file while changing the decoder options, to save disk wear. It's also much faster. | ||||
|  | ||||
| ### Source and destination specifiers | ||||
|  | ||||
| When reading from or writing to _a disk_ (or a file pretending to be a disk), | ||||
| use the `--source` (`-s`) and `--dest` (`-d`) options to tell FluxEngine | ||||
| When reading from or writing _flux_ (either from or to a real disk, or a flux | ||||
| file), use the `--source` (`-s`) and `--dest` (`-d`) options to tell FluxEngine | ||||
| which bits of the disk you want to access. These use a common syntax: | ||||
|  | ||||
| ``` | ||||
| @@ -84,7 +47,7 @@ fluxengine read ibm -s fakedisk.flux:t=0-79:s=0 | ||||
|   - To access a real disk, leave out the filename (so `:t=0-79:s=0`). | ||||
|  | ||||
|   - To access only some tracks, use the `t=` modifier. To access only some | ||||
|     sides, use the `s=` modifier. To change drives, use `d=`. | ||||
|     sides, use the `s=` modifier. | ||||
|  | ||||
|   - Inside a modifier, you can use a comma separated list of ranges. So | ||||
|     `:t=0-3` and `:t=0,1,2,3` are equivalent. | ||||
| @@ -110,18 +73,15 @@ If you _don't_ specify a modifier, you'll get the default, which should be | ||||
| sensible for the command you're using. | ||||
|  | ||||
| **Important note:** FluxEngine _always_ uses zero-based units (even if the | ||||
| *disk format says otherwise). | ||||
| disk format says otherwise). | ||||
|  | ||||
| ### Input and output specifiers | ||||
|  | ||||
| These use a very similar syntax to the source and destination specifiers | ||||
| (because they're based on the same microformat library!) but are used for | ||||
| input and output _images_: i.e. nicely lined up arrays of sectors which you | ||||
| can actually do something with. | ||||
|  | ||||
| Use `--input` (`-i`) or `--output` (`-o`) as appropriate to tell FluxEngine | ||||
| where you want to read from or write to. The actual format is autodetected | ||||
| based on the extension: | ||||
| When reading or writing _file system images_, use the `--input` (`-i`) and | ||||
| `--output` (`-o`) options to specify the file and file format. These use a very | ||||
| similar syntax to the source and destination specifiers (because they're based | ||||
| on the same microformat library!) but with different specifiers. Also, the | ||||
| exact format varies according to the extension: | ||||
|  | ||||
|   - `.img` or `.adf`: raw sector images in CHS order. Append | ||||
|     `:c=80:h=2:s=9:b=512` to set the geometry; that specifies 80 cylinders, 2 | ||||
| @@ -176,6 +136,29 @@ case, and reading the disk label is much more reliable. | ||||
| [Lots more information on high density vs double density disks can be found | ||||
| here.](http://www.retrotechnology.com/herbs_stuff/guzis.html) | ||||
|  | ||||
| ### Other important flags | ||||
|  | ||||
| These flags apply to many operations and are useful for modifying the overall | ||||
| behaviour. | ||||
|  | ||||
|   - `--revolutions=X`: when reading, spin the disk X times. X can be a floating | ||||
| 	point number. The default is usually 1.25. Some formats default to 1. | ||||
| 	Increasing the number will sample more data, and can be useful on dubious | ||||
| 	disks to try and get a better read. | ||||
|  | ||||
|   - `--sync-with-index=true|false`: wait for an index pulse before starting to | ||||
| 	read the disk. (Ignored for write operations.) By default FluxEngine | ||||
| 	doesn't, as it makes reads faster, but when diagnosing disk problems it's | ||||
| 	helpful to have all your data start at the same place each time. | ||||
|  | ||||
|   - `--index-source=X`, `--write-index-source=X`: set the source of index | ||||
| 	pulses when reading or writing respectively. This is for use with drives | ||||
| 	which don't produce index pulse data. Use 0 to get index pulses from the | ||||
| 	drive, 1 to fake 300RPM pulses, or 2 to fake 360RPM pulses. Note this has | ||||
| 	no effect on the _drive_, so it doesn't help with flippy disks, but is | ||||
| 	useful for using very old drives with FluxEngine itself. If you use this | ||||
| 	option, then any index marks in the sampled flux are, of course, garbage. | ||||
|  | ||||
| ### The commands | ||||
|  | ||||
| The FluxEngine client software is a largely undocumented set of small tools. | ||||
| @@ -184,56 +167,62 @@ installed anywhere and after building you'll find them in the `.obj` | ||||
| directory. | ||||
|  | ||||
|   - `fluxengine erase`: wipes (all or part of) a disk --- erases it without | ||||
|   writing a pulsetrain. | ||||
| 	writing a pulsetrain. | ||||
|  | ||||
|   - `fluxengine inspect`: dumps the raw pulsetrain / bitstream to stdout. | ||||
|   Mainly useful for debugging. | ||||
| 	Mainly useful for debugging. | ||||
|  | ||||
|   - `fluxengine read*`: reads various formats of disk. See the per-format | ||||
|   documentation linked from the table above. These all take an optional | ||||
|   `--write-flux` option which will cause the raw flux to be written to the | ||||
|   specified file. | ||||
|   - `fluxengine read *`: reads various formats of disk. See the per-format | ||||
| 	documentation linked from the table [in the index page](../README.md). | ||||
| 	These all take an optional `--write-flux` option which will cause the raw | ||||
| 	flux to be written to the specified file as well as the normal decode. | ||||
| 	There are various `--dump` options for showing raw data during the decode | ||||
| 	process, and `--write-csv` will write a copious CSV report of the state of | ||||
| 	every sector in the file in machine-readable format. | ||||
|  | ||||
|   - `fluxengine write*`: writes various formats of disk. Again, see the | ||||
|   per-format documentation above. | ||||
|   - `fluxengine write *`: writes various formats of disk. Again, see the | ||||
| 	per-format documentation [in the index page](../README.md). | ||||
|  | ||||
|   - `fluxengine writeflux`: writes raw flux files. This is much less useful | ||||
|   than you might think: you can't write flux files read from a disk to | ||||
|   another disk. (See the [FAQ](faq.md) for more information.) It's mainly | ||||
|   useful for flux files synthesised by the other `fluxengine write` commands. | ||||
| 	than you might think: you can't reliably write flux files read from a disk | ||||
| 	to another disk. (See the [FAQ](faq.md) for more information.) It's mainly | ||||
| 	useful for flux files synthesised by the other `fluxengine write` commands. | ||||
|  | ||||
|   - `fluxengine writetestpattern`: writes regular pulses (at a configurable | ||||
|   interval) to the disk. Useful for testing drive jitter, erasing disks in a | ||||
|   more secure fashion, or simply debugging. Goes well with `fluxengine | ||||
|   inspect`. | ||||
| 	interval) to the disk. Useful for testing drive jitter, erasing disks in a | ||||
| 	more secure fashion, or simply debugging. Goes well with `fluxengine | ||||
| 	inspect`. | ||||
|  | ||||
|   - `fluxengine rpm`: measures the RPM of the drive (requires a disk in the | ||||
|   drive). Mainly useful for testing. | ||||
| 	drive). Mainly useful for testing. | ||||
|  | ||||
|   - `fluxengine seek`: moves the head. Mainly useful for finding out whether | ||||
|   your drive can seek to track 82. (Mine can't.) | ||||
| 	your drive can seek to track 82. (Mine can't.) | ||||
|  | ||||
|   - `fluxengine testbulktransport`: measures your USB throughput. You need | ||||
|   about 600kB/s for FluxEngine to work. You don't need a disk in the drive | ||||
|   for this one. | ||||
|   - `fluxengine test bandwidth`: measures your USB throughput.  You don't need | ||||
| 	a disk in the drive for this one. | ||||
|  | ||||
|   - `fluxengine upgradefluxfile`: occasionally I need to upgrade the flux | ||||
|   file format in a non-backwards-compatible way; this tool will upgrade flux | ||||
|   files to the new format. | ||||
|   - `fluxengine test voltages`: measures your FDD bus signal voltages, which is | ||||
| 	useful for testing for termination issues. | ||||
|  | ||||
|   - `fluxengine upgradefluxfile`: occasionally I need to upgrade the flux file | ||||
| 	format in a non-backwards-compatible way; this tool will upgrade flux files | ||||
| 	to the new format. | ||||
|  | ||||
|   - `fluxengine convert`: converts flux files from various formats to various | ||||
|   other formats. You can use this to convert Catweasel flux files to | ||||
|   FluxEngine's native format, FluxEngine flux files to various other formats | ||||
|   useful for debugging (including VCD which can be loaded into | ||||
|   [sigrok](http://sigrok.org)), and bidirectional conversion to and from | ||||
|   Supercard Pro `.scp` format. | ||||
| 	other formats. You can use this to convert Catweasel flux files to | ||||
| 	FluxEngine's native format, FluxEngine flux files to various other formats | ||||
| 	useful for debugging (including VCD which can be loaded into | ||||
| 	[sigrok](http://sigrok.org)), and bidirectional conversion to and from | ||||
| 	Supercard Pro `.scp` format. | ||||
|  | ||||
|   **Important SCP note:** import (`fluxengine convert scptoflux`) should be | ||||
|   fairly robust, but export (`fluxengine convert fluxtoscp`) should only be | ||||
|   done with great caution as FluxEngine files contain features which can't be | ||||
|   represented very well in `.scp` format and they're probably pretty dubious. | ||||
|   As ever, please [get in | ||||
|   touch](https://github.com/davidgiven/fluxengine/issues/new) with any reports. | ||||
| 	**Important SCP note:** import (`fluxengine convert scptoflux`) should be | ||||
| 	fairly robust, but export (`fluxengine convert fluxtoscp`) should only be | ||||
| 	done with great caution as FluxEngine files contain features which can't be | ||||
| 	represented very well in `.scp` format and they're probably pretty dubious. | ||||
| 	As ever, please [get in | ||||
| 	touch](https://github.com/davidgiven/fluxengine/issues/new) with any | ||||
| 	reports. | ||||
|  | ||||
| Commands which normally take `--source` or `--dest` get a sensible default if | ||||
| left unspecified. `fluxengine read ibm` on its own will read drive 0 and | ||||
| @@ -259,8 +248,10 @@ disk). For a 5.25" disk, use `--visualiser-period=166`. | ||||
| Supplied with FluxEngine, but not part of FluxEngine, are some little tools I | ||||
| wrote to do useful things. These are built alongside FluxEngine. | ||||
|  | ||||
|   - `brother120tool`: extracts files from a 120kB Brother filesystem image. | ||||
|  | ||||
|   - `brother120tool`, `brother240tool`: does things to Brother word processor | ||||
| 	disks. These are [documented on the Brother disk format | ||||
| 	page](disk-brother.md). | ||||
|    | ||||
| ## The recommended workflow | ||||
|  | ||||
| So you've just received, say, a huge pile of old Brother word processor disks | ||||
| @@ -269,13 +260,13 @@ containing valuable historical data, and you want to read them. | ||||
| Typically I do this: | ||||
|  | ||||
| ``` | ||||
| $ fluxengine read brother -s :d=0 -o brother.img --write-flux=brother.flux --write-svg=brother.svg | ||||
| $ fluxengine read brother -s :d=0 -o brother.img --write-flux=brother.flux --overwrite --write-svg=brother.svg | ||||
| ``` | ||||
|  | ||||
| This will read the disk in drive 0 and write out a filesystem image. It'll | ||||
| also copy the flux to brother.flux and write out an SVG visualisation. If I | ||||
| then need to tweak the settings, I can rerun the decode without having to | ||||
| physically touch the disk like this: | ||||
| This will read the disk in drive 0 and write out a filesystem image. It'll also | ||||
| copy the flux to `brother.flux` (replacing any old one) and write out an SVG | ||||
| visualisation. If I then need to tweak the settings, I can rerun the decode | ||||
| without having to physically touch the disk like this: | ||||
|  | ||||
| ``` | ||||
| $ fluxengine read brother -s brother.flux -o brother.img --write-svg=brother.svg | ||||
|   | ||||
							
								
								
									
										22
									
								
								lib/bytes.cc
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								lib/bytes.cc
									
									
									
									
									
								
							| @@ -147,6 +147,28 @@ Bytes Bytes::slice(unsigned start, unsigned len) const | ||||
|     } | ||||
| } | ||||
|  | ||||
| Bytes Bytes::slice(unsigned start) const | ||||
| { | ||||
| 	int len = 0; | ||||
| 	if (start < size()) | ||||
| 		len = size() - start; | ||||
| 	return slice(start, len); | ||||
| } | ||||
|  | ||||
| std::vector<bool> Bytes::toBits() const | ||||
| { | ||||
| 	std::vector<bool> bits; | ||||
| 	for (uint8_t byte : *this) | ||||
| 	{ | ||||
| 		for (int i=0; i<8; i++) | ||||
| 		{ | ||||
| 			bits.push_back(byte & 0x80); | ||||
| 			byte <<= 1; | ||||
| 		} | ||||
| 	} | ||||
| 	return bits; | ||||
| } | ||||
|  | ||||
| uint8_t toByte( | ||||
|     std::vector<bool>::const_iterator start, | ||||
|     std::vector<bool>::const_iterator end) | ||||
|   | ||||
| @@ -47,11 +47,13 @@ public: | ||||
|     { resize(0); return *this; } | ||||
|  | ||||
|     Bytes slice(unsigned start, unsigned len) const; | ||||
|     Bytes slice(unsigned start) const; | ||||
|     Bytes swab() const; | ||||
|     Bytes compress() const; | ||||
|     Bytes decompress() const; | ||||
|     Bytes crunch() const; | ||||
|     Bytes uncrunch() const; | ||||
| 	std::vector<bool> toBits() const; | ||||
|  | ||||
|     ByteReader reader() const; | ||||
|     ByteWriter writer(); | ||||
|   | ||||
| @@ -9,14 +9,37 @@ void crunch(crunch_state_t* state) | ||||
|         uint8_t data = *state->inputptr++; | ||||
|         state->inputlen--; | ||||
|  | ||||
|         if (data & 0x80) | ||||
| 		if (data == 0x80) | ||||
| 		{ | ||||
| 			/* Multiple 0x80s in a row get swallowed as they're | ||||
| 			 * meaningless. */ | ||||
| 			state->haspending = true; | ||||
| 		} | ||||
|         else if (data & 0x80) | ||||
|         { | ||||
|             state->fifo = (state->fifo << 2) | 2 | (data & 1); | ||||
|             state->fifolen += 2; | ||||
| 			if (state->haspending) | ||||
| 			{ | ||||
| 				state->fifo = (state->fifo << 3) | 4; | ||||
| 				state->fifolen += 3; | ||||
| 				state->haspending = false; | ||||
| 			} | ||||
|  | ||||
|             state->fifo = (state->fifo << 3) | 4 | (data & 1); | ||||
|             state->fifolen += 3; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             state->fifo = (state->fifo << 8) | data; | ||||
| 			if (state->haspending && (data >= 0x40)) | ||||
| 			{ | ||||
| 				state->fifo = (state->fifo << 3) | 4; | ||||
| 				state->fifolen += 3; | ||||
| 				state->haspending = false; | ||||
| 			} | ||||
| 				 | ||||
| 			state->fifo = (state->fifo << 8) | data; | ||||
| 			if (state->haspending) | ||||
| 				state->fifo |= 0xc0; | ||||
| 			state->haspending = false; | ||||
|             state->fifolen += 8; | ||||
|         } | ||||
|  | ||||
| @@ -45,6 +68,14 @@ void uncrunch(crunch_state_t* state) | ||||
| { | ||||
|     while (state->inputlen && state->outputlen) | ||||
|     { | ||||
| 		if (state->haspending) | ||||
| 		{ | ||||
| 			*state->outputptr++ = state->pendingbyte; | ||||
| 			state->outputlen--; | ||||
| 			state->haspending = false; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
|         if (state->fifolen < 8) | ||||
|         { | ||||
|             if (state->inputlen) | ||||
| @@ -58,13 +89,21 @@ void uncrunch(crunch_state_t* state) | ||||
|         } | ||||
|  | ||||
|         uint8_t data = state->fifo >> (state->fifolen - 8); | ||||
|         if (data & 0x80) | ||||
|         { | ||||
|             data = ((data >> 6) & 0x01) | 0x80; | ||||
|             state->fifolen -= 2; | ||||
|         } | ||||
|         else | ||||
|             state->fifolen -= 8; | ||||
| 		switch (data & 0xc0) | ||||
| 		{ | ||||
| 			case 0x80: | ||||
| 				data = ((data >> 5) & 0x01) | 0x80; | ||||
| 				state->fifolen -= 3; | ||||
| 				break; | ||||
|  | ||||
| 			case 0xc0: | ||||
| 				state->haspending = true; | ||||
| 				state->pendingbyte = data & 0x3f; | ||||
| 				data = 0x80; | ||||
| 				/* fall through */ | ||||
| 			default: | ||||
| 				state->fifolen -= 8; | ||||
| 		} | ||||
|  | ||||
|         if (data) | ||||
|         { | ||||
|   | ||||
| @@ -11,7 +11,8 @@ extern "C" { | ||||
|  * sending it over USB. The encoding used is: | ||||
|  *  | ||||
|  * 0nnn.nnnn: value 0x00..0x7f | ||||
|  * 1n       : value 0x80|n | ||||
|  * 11nn.nnnn: value 0x80 then 0x00..0x3f | ||||
|  * 10n      : value 0x80|n | ||||
|  * | ||||
|  * The end of the buffer is terminated with zeroes, which are ignored | ||||
|  * (not written to the output). | ||||
| @@ -25,8 +26,10 @@ typedef struct crunch_state_t | ||||
|     uint32_t inputlen; | ||||
|     uint8_t* outputptr; | ||||
|     uint32_t outputlen; | ||||
|     uint16_t fifo; | ||||
|     uint32_t fifo; | ||||
|     uint8_t fifolen; | ||||
| 	bool haspending; | ||||
| 	uint8_t pendingbyte; | ||||
| } | ||||
| crunch_state_t; | ||||
|  | ||||
|   | ||||
| @@ -15,34 +15,31 @@ std::vector<std::string> DataSpec::split( | ||||
| { | ||||
|     std::vector<std::string> ret; | ||||
|  | ||||
|     size_t start = 0; | ||||
|     size_t end = 0; | ||||
|     size_t len = 0; | ||||
|     do | ||||
|     { | ||||
|         end = s.find(delimiter,start);  | ||||
|         len = end - start; | ||||
|         std::string token = s.substr(start, len); | ||||
|         ret.emplace_back( token ); | ||||
|         start += len + delimiter.length(); | ||||
|     } | ||||
|     while (end != std::string::npos); | ||||
| 	if (!s.empty()) | ||||
| 	{ | ||||
| 		size_t start = 0; | ||||
| 		size_t end = 0; | ||||
| 		size_t len = 0; | ||||
| 		do | ||||
| 		{ | ||||
| 			end = s.find(delimiter,start);  | ||||
| 			len = end - start; | ||||
| 			std::string token = s.substr(start, len); | ||||
| 			ret.emplace_back( token ); | ||||
| 			start += len + delimiter.length(); | ||||
| 		} | ||||
| 		while (end != std::string::npos); | ||||
| 	} | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| DataSpec::Modifier DataSpec::parseMod(const std::string& spec) | ||||
| std::set<unsigned> DataSpec::parseRange(const std::string& data) | ||||
| { | ||||
|     static const std::regex MOD_REGEX("([a-z]*)=([-x+0-9,]*)"); | ||||
|     static const std::regex DATA_REGEX("([0-9]+)(?:(?:-([0-9]+))|(?:\\+([0-9]+)))?(?:x([0-9]+))?"); | ||||
| 	static const std::regex DATA_REGEX("([0-9]+)(?:(?:-([0-9]+))|(?:\\+([0-9]+)))?(?:x([0-9]+))?"); | ||||
|  | ||||
|     std::smatch match; | ||||
|     if (!std::regex_match(spec, match, MOD_REGEX)) | ||||
|         Error() << "invalid data modifier syntax '" << spec << "'"; | ||||
|      | ||||
|     Modifier m; | ||||
|     m.name = match[1]; | ||||
|     m.source = spec; | ||||
|     for (auto& data : split(match[2], ",")) | ||||
| 	std::set<unsigned> result; | ||||
|     for (auto& data : split(data, ",")) | ||||
|     { | ||||
|         int start = 0; | ||||
|         int count = 1; | ||||
| @@ -64,9 +61,24 @@ DataSpec::Modifier DataSpec::parseMod(const std::string& spec) | ||||
|             Error() << "mod '" << data << "' specifies an illegal quantity"; | ||||
|  | ||||
|         for (int i = start; i < (start+count); i += step) | ||||
|             m.data.insert(i); | ||||
|             result.insert(i); | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| DataSpec::Modifier DataSpec::parseMod(const std::string& spec) | ||||
| { | ||||
| 	static const std::regex MOD_REGEX("([a-z]*)=([-x+0-9,]*)"); | ||||
|  | ||||
|     std::smatch match; | ||||
|     if (!std::regex_match(spec, match, MOD_REGEX)) | ||||
|         Error() << "invalid data modifier syntax '" << spec << "'"; | ||||
|      | ||||
|     Modifier m; | ||||
|     m.name = match[1]; | ||||
|     m.source = spec; | ||||
| 	m.data = parseRange(match[2]); | ||||
|     return m; | ||||
| } | ||||
|  | ||||
| @@ -74,7 +86,7 @@ void DataSpec::set(const std::string& spec) | ||||
| { | ||||
|     std::vector<std::string> words = split(spec, ":"); | ||||
|     if (words.size() == 0) | ||||
|         Error() << "empty data specification (you have to specify *something*)"; | ||||
| 		return; | ||||
|  | ||||
|     filename = words[0]; | ||||
|     if (words.size() > 1) | ||||
|   | ||||
| @@ -34,6 +34,8 @@ public: | ||||
| public: | ||||
|     static std::vector<std::string> split( | ||||
|         const std::string& s, const std::string& delimiter); | ||||
| 	static std::set<unsigned> parseRange(const std::string& spec); | ||||
|  | ||||
|     static Modifier parseMod(const std::string& spec); | ||||
|  | ||||
| public: | ||||
| @@ -117,4 +119,34 @@ private: | ||||
|     DataSpec _value; | ||||
| }; | ||||
|  | ||||
| class RangeFlag : public Flag | ||||
| { | ||||
| public: | ||||
|     RangeFlag(const std::vector<std::string>& names, const std::string helptext, | ||||
|             const std::string& defaultValue): | ||||
|         Flag(names, helptext), | ||||
| 		_stringValue(defaultValue), | ||||
|         _value(DataSpec::parseRange(defaultValue)) | ||||
|     {} | ||||
|  | ||||
|     const std::set<unsigned>& get() const | ||||
|     { checkInitialised(); return _value; } | ||||
|  | ||||
|     operator const std::set<unsigned>& () const | ||||
|     { return get(); } | ||||
|  | ||||
|     bool hasArgument() const { return true; } | ||||
|     const std::string defaultValueAsString() const { return _stringValue; } | ||||
|  | ||||
|     void set(const std::string& value) | ||||
| 	{ | ||||
| 		_stringValue = value; | ||||
| 		_value = DataSpec::parseRange(value); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	std::string _stringValue; | ||||
|     std::set<unsigned> _value; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -25,7 +25,7 @@ void AbstractDecoder::decodeToSectors(Track& track) | ||||
|     beginTrack(); | ||||
|     for (;;) | ||||
|     { | ||||
|         Fluxmap::Position recordStart = sector.position = fmr.tell(); | ||||
|         Fluxmap::Position recordStart = fmr.tell(); | ||||
|         sector.clock = 0; | ||||
|         sector.status = Sector::MISSING; | ||||
|         sector.data.clear(); | ||||
| @@ -41,7 +41,7 @@ void AbstractDecoder::decodeToSectors(Track& track) | ||||
|  | ||||
|         /* Read the sector record. */ | ||||
|  | ||||
|         recordStart = fmr.tell(); | ||||
|         sector.position = recordStart = fmr.tell(); | ||||
|         decodeSectorRecord(); | ||||
|         Fluxmap::Position recordEnd = fmr.tell(); | ||||
|         pushRecord(recordStart, recordEnd); | ||||
| @@ -51,14 +51,19 @@ void AbstractDecoder::decodeToSectors(Track& track) | ||||
|  | ||||
|             sector.headerStartTime = recordStart.ns(); | ||||
|             sector.headerEndTime = recordEnd.ns(); | ||||
|             r = advanceToNextRecord(); | ||||
| 			for (;;) | ||||
| 			{ | ||||
| 				r = advanceToNextRecord(); | ||||
| 				if (r != UNKNOWN_RECORD) | ||||
| 					break; | ||||
| 				if (fmr.readNextMatchingOpcode(F_OP_PULSE) == 0) | ||||
|                     break; | ||||
| 			} | ||||
|             recordStart = fmr.tell(); | ||||
|             if (r == DATA_RECORD) | ||||
|             { | ||||
|                 recordStart = fmr.tell(); | ||||
|                 decodeDataRecord(); | ||||
|                 recordEnd = fmr.tell(); | ||||
|                 pushRecord(recordStart, recordEnd); | ||||
|             } | ||||
|             recordEnd = fmr.tell(); | ||||
|             pushRecord(recordStart, recordEnd); | ||||
|         } | ||||
|         sector.dataStartTime = recordStart.ns(); | ||||
|         sector.dataEndTime = recordEnd.ns(); | ||||
| @@ -83,3 +88,10 @@ void AbstractDecoder::pushRecord(const Fluxmap::Position& start, const Fluxmap:: | ||||
|     _track->rawrecords.push_back(record); | ||||
|     _fmr->seek(here); | ||||
| } | ||||
|  | ||||
| std::set<unsigned> AbstractDecoder::requiredSectors(Track& track) const | ||||
| { | ||||
| 	static std::set<unsigned> empty; | ||||
| 	return empty; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -20,6 +20,8 @@ extern void setDecoderManualClockRate(double clockrate_us); | ||||
|  | ||||
| extern Bytes decodeFmMfm(std::vector<bool>::const_iterator start, | ||||
|     std::vector<bool>::const_iterator end); | ||||
| extern void encodeMfm(std::vector<bool>& bits, unsigned& cursor, const Bytes& input, bool& lastBit); | ||||
| extern void encodeFm(std::vector<bool>& bits, unsigned& cursor, const Bytes& input); | ||||
|  | ||||
| static inline Bytes decodeFmMfm(const std::vector<bool> bits) | ||||
| { return decodeFmMfm(bits.begin(), bits.end()); } | ||||
| @@ -50,6 +52,11 @@ public: | ||||
|     void seek(const Fluxmap::Position& pos) | ||||
|     { return _fmr->seek(pos); }  | ||||
|  | ||||
| 	/* Returns a set of sectors required to exist on this track. If the reader | ||||
| 	 * sees any missing, it will consider this to be an error and will retry | ||||
| 	 * the read. */ | ||||
| 	virtual std::set<unsigned> requiredSectors(Track& track) const; | ||||
|  | ||||
| protected: | ||||
|     virtual void beginTrack() {}; | ||||
|     virtual RecordType advanceToNextRecord() = 0; | ||||
|   | ||||
| @@ -18,13 +18,18 @@ DoubleFlag pulseDebounceThreshold( | ||||
| static DoubleFlag clockDecodeThreshold( | ||||
|     { "--bit-error-threshold" }, | ||||
|     "Amount of error to tolerate in pulse timing, in fractions of a clock.", | ||||
|     0.20); | ||||
|     0.40); | ||||
|  | ||||
| static DoubleFlag clockIntervalBias( | ||||
|     { "--clock-interval-bias" }, | ||||
|     "Adjust intervals between pulses by this many clocks before decoding.", | ||||
|     -0.02); | ||||
|  | ||||
| static DoubleFlag minimumClockUs( | ||||
|     { "--minimum-clock-us" }, | ||||
|     "Refuse to detect clocks shorter than this, to avoid false positives.", | ||||
|     0.75); | ||||
|  | ||||
| int FluxmapReader::readOpcode(unsigned& ticks) | ||||
| { | ||||
|     ticks = 0; | ||||
| @@ -222,7 +227,9 @@ nanoseconds_t FluxmapReader::seekToPattern(const FluxMatcher& pattern, const Flu | ||||
|             seek(positions[intervalCount-match.intervals]); | ||||
|             _pos.zeroes = match.zeroes; | ||||
|             matching = match.matcher; | ||||
|             return match.clock * NS_PER_TICK; | ||||
|             nanoseconds_t detectedClock = match.clock * NS_PER_TICK; | ||||
|             if (detectedClock > (minimumClockUs*1000)) | ||||
|                 return match.clock * NS_PER_TICK; | ||||
|         } | ||||
|  | ||||
|         for (unsigned i=0; i<intervalCount; i++) | ||||
|   | ||||
| @@ -51,3 +51,48 @@ Bytes decodeFmMfm( | ||||
|  | ||||
|     return bytes; | ||||
| } | ||||
|  | ||||
| void encodeFm(std::vector<bool>& bits, unsigned& cursor, const Bytes& input) | ||||
| { | ||||
| 	if (bits.size() == 0) | ||||
| 		return; | ||||
|     unsigned len = bits.size()-1; | ||||
|  | ||||
|     for (uint8_t b : input) | ||||
|     { | ||||
|         for (int i=0; i<8; i++) | ||||
|         { | ||||
|             bool bit = b & 0x80; | ||||
|             b <<= 1; | ||||
|  | ||||
|             if (cursor >= len) | ||||
|                 return; | ||||
|              | ||||
|             bits[cursor++] = true; | ||||
|             bits[cursor++] = bit; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void encodeMfm(std::vector<bool>& bits, unsigned& cursor, const Bytes& input, bool& lastBit) | ||||
| { | ||||
| 	if (bits.size() == 0) | ||||
| 		return; | ||||
|     unsigned len = bits.size()-1; | ||||
|  | ||||
|     for (uint8_t b : input) | ||||
|     { | ||||
|         for (int i=0; i<8; i++) | ||||
|         { | ||||
|             bool bit = b & 0x80; | ||||
|             b <<= 1; | ||||
|  | ||||
|             if (cursor >= len) | ||||
|                 return; | ||||
|              | ||||
|             bits[cursor++] = !lastBit && !bit; | ||||
|             bits[cursor++] = bit; | ||||
|             lastBit = bit; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| static FlagGroup* currentFlagGroup; | ||||
| static std::vector<Flag*> all_flags; | ||||
| @@ -157,6 +158,8 @@ Flag::Flag(const std::vector<std::string>& names, const std::string helptext): | ||||
|     _names(names), | ||||
|     _helptext(helptext) | ||||
| { | ||||
|     if (!currentFlagGroup) | ||||
|         Error() << "no flag group defined for " << *names.begin(); | ||||
|     _group.addFlag(this); | ||||
| } | ||||
|  | ||||
| @@ -170,6 +173,11 @@ void BoolFlag::set(const std::string& value) | ||||
| 		Error() << "can't parse '" << value << "'; try 'true' or 'false'"; | ||||
| } | ||||
|  | ||||
| const std::string HexIntFlag::defaultValueAsString() const | ||||
| { | ||||
| 	return fmt::format("0x{:x}", _defaultValue); | ||||
| } | ||||
|  | ||||
| static void doHelp() | ||||
| { | ||||
|     std::cout << "FluxEngine options:" << std::endl; | ||||
|   | ||||
							
								
								
									
										13
									
								
								lib/flags.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								lib/flags.h
									
									
									
									
									
								
							| @@ -135,6 +135,17 @@ public: | ||||
|     void set(const std::string& value) { _value = std::stoi(value); } | ||||
| }; | ||||
|  | ||||
| class HexIntFlag : public IntFlag | ||||
| { | ||||
| public: | ||||
|     HexIntFlag(const std::vector<std::string>& names, const std::string helptext, | ||||
|             int defaultValue = 0): | ||||
|         IntFlag(names, helptext, defaultValue) | ||||
|     {} | ||||
|  | ||||
|     const std::string defaultValueAsString() const; | ||||
| }; | ||||
|  | ||||
| class DoubleFlag : public ValueFlag<double> | ||||
| { | ||||
| public: | ||||
| @@ -147,7 +158,7 @@ public: | ||||
|     void set(const std::string& value) { _value = std::stod(value); } | ||||
| }; | ||||
|  | ||||
| class BoolFlag : public ValueFlag<double> | ||||
| class BoolFlag : public ValueFlag<bool> | ||||
| { | ||||
| public: | ||||
|     BoolFlag(const std::vector<std::string>& names, const std::string helptext, | ||||
|   | ||||
| @@ -1,6 +1,11 @@ | ||||
| #ifndef FLUXSINK_H | ||||
| #define FLUXSINK_H | ||||
|  | ||||
| #include "flags.h" | ||||
|  | ||||
| extern FlagGroup hardwareFluxSinkFlags; | ||||
| extern FlagGroup sqliteFluxSinkFlags; | ||||
|  | ||||
| class Fluxmap; | ||||
| class FluxSpec; | ||||
|  | ||||
| @@ -9,11 +14,9 @@ class FluxSink | ||||
| public: | ||||
|     virtual ~FluxSink() {} | ||||
|  | ||||
| private: | ||||
|     static std::unique_ptr<FluxSink> createSqliteFluxSink(const std::string& filename); | ||||
|     static std::unique_ptr<FluxSink> createHardwareFluxSink(unsigned drive); | ||||
|  | ||||
| public: | ||||
|     static std::unique_ptr<FluxSink> create(const FluxSpec& spec); | ||||
|  | ||||
| public: | ||||
|   | ||||
| @@ -4,8 +4,15 @@ | ||||
| #include "usb.h" | ||||
| #include "fluxsink/fluxsink.h" | ||||
|  | ||||
| FlagGroup hardwareFluxSinkFlags; | ||||
|  | ||||
| static bool high_density = false; | ||||
|  | ||||
| static IntFlag indexMode( | ||||
|     { "--write-index-mode" }, | ||||
|     "index pulse source (0=drive, 1=300 RPM fake source, 2=360 RPM fake source", | ||||
|     0); | ||||
|  | ||||
| void setHardwareFluxSinkDensity(bool high_density) | ||||
| { | ||||
| 	::high_density = high_density; | ||||
| @@ -26,7 +33,7 @@ public: | ||||
| public: | ||||
|     void writeFlux(int track, int side, Fluxmap& fluxmap) | ||||
|     { | ||||
|         usbSetDrive(_drive, high_density); | ||||
|         usbSetDrive(_drive, high_density, indexMode); | ||||
|         usbSeek(track); | ||||
|  | ||||
|         Bytes crunched = fluxmap.rawBytes().crunch(); | ||||
|   | ||||
| @@ -2,14 +2,37 @@ | ||||
| #include "fluxmap.h" | ||||
| #include "sql.h" | ||||
| #include "fluxsink/fluxsink.h" | ||||
| #include "flags.h" | ||||
| #include "fmt/format.h" | ||||
| #include <unistd.h> | ||||
|  | ||||
| FlagGroup sqliteFluxSinkFlags; | ||||
|  | ||||
| static SettableFlag mergeFlag( | ||||
| 	{ "--merge" }, | ||||
| 	"merge new data into existing flux file"); | ||||
|  | ||||
| static SettableFlag overwriteFlag( | ||||
| 	{ "--overwrite" }, | ||||
| 	"overwrite existing flux file"); | ||||
|  | ||||
| class SqliteFluxSink : public FluxSink | ||||
| { | ||||
| public: | ||||
|     SqliteFluxSink(const std::string& filename) | ||||
|     { | ||||
| 		if (mergeFlag && overwriteFlag) | ||||
| 			Error() << "you can't specify --merge and --overwrite"; | ||||
|  | ||||
| 		if (!mergeFlag) | ||||
| 		{ | ||||
| 			if (!overwriteFlag && (access(filename.c_str(), F_OK) == 0)) | ||||
| 				Error() << "cowardly refusing to overwrite flux file without --merge or --overwrite specified"; | ||||
| 			if ((access(filename.c_str(), F_OK) == 0) && (remove(filename.c_str()) != 0)) | ||||
| 				Error() << fmt::format("failed to overwrite flux file"); | ||||
| 		} | ||||
| 		_outdb = sqlOpen(filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); | ||||
|  | ||||
| 		int oldVersion = sqlReadIntProperty(_outdb, "version"); | ||||
| 		if ((oldVersion != 0) && (oldVersion != FLUX_VERSION_CURRENT)) | ||||
|             Error() << fmt::format("that flux file is version {}, but this client is for version {}", | ||||
|   | ||||
| @@ -27,8 +27,9 @@ public: | ||||
|     virtual bool retryable() { return false; } | ||||
| }; | ||||
|  | ||||
| extern void setHardwareFluxSourceRevolutions(int revolutions); | ||||
| extern void setHardwareFluxSourceRevolutions(double revolutions); | ||||
| extern void setHardwareFluxSourceDensity(bool high_density); | ||||
| extern void setHardwareFluxSourceSynced(bool synced); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -3,13 +3,24 @@ | ||||
| #include "fluxmap.h" | ||||
| #include "usb.h" | ||||
| #include "fluxsource/fluxsource.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| FlagGroup hardwareFluxSourceFlags; | ||||
|  | ||||
| static IntFlag revolutions( | ||||
| static DoubleFlag revolutions( | ||||
|     { "--revolutions" }, | ||||
|     "read this many revolutions of the disk", | ||||
|     1); | ||||
|     1.25); | ||||
|  | ||||
| static BoolFlag synced( | ||||
|     { "--sync-with-index" }, | ||||
|     "whether to wait for an index pulse before started to read", | ||||
|     false); | ||||
|  | ||||
| static IntFlag indexMode( | ||||
|     { "--index-mode" }, | ||||
|     "index pulse source (0=drive, 1=300 RPM fake source, 2=360 RPM fake source", | ||||
|     0); | ||||
|  | ||||
| static bool high_density = false; | ||||
|  | ||||
| @@ -24,6 +35,10 @@ public: | ||||
|     HardwareFluxSource(unsigned drive): | ||||
|         _drive(drive) | ||||
|     { | ||||
|         usbSetDrive(_drive, high_density, indexMode); | ||||
|         std::cerr << "Measuring rotational speed... " << std::flush; | ||||
|         _oneRevolution = usbGetRotationalPeriod(); | ||||
|         std::cerr << fmt::format("{}ms\n", _oneRevolution / 1e6); | ||||
|     } | ||||
|  | ||||
|     ~HardwareFluxSource() | ||||
| @@ -33,9 +48,9 @@ public: | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> readFlux(int track, int side) | ||||
|     { | ||||
|         usbSetDrive(_drive, high_density); | ||||
|         usbSetDrive(_drive, high_density, indexMode); | ||||
|         usbSeek(track); | ||||
|         Bytes crunched = usbRead(side, revolutions); | ||||
|         Bytes crunched = usbRead(side, synced, revolutions * _oneRevolution); | ||||
|         auto fluxmap = std::make_unique<Fluxmap>(); | ||||
|         fluxmap->appendBytes(crunched.uncrunch()); | ||||
|         return fluxmap; | ||||
| @@ -54,13 +69,19 @@ public: | ||||
| private: | ||||
|     unsigned _drive; | ||||
|     unsigned _revolutions; | ||||
|     nanoseconds_t _oneRevolution; | ||||
| }; | ||||
|  | ||||
| void setHardwareFluxSourceRevolutions(int revolutions) | ||||
| void setHardwareFluxSourceRevolutions(double revolutions) | ||||
| { | ||||
|     ::revolutions.setDefaultValue(revolutions); | ||||
| } | ||||
|  | ||||
| void setHardwareFluxSourceSynced(bool synced) | ||||
| { | ||||
|     ::synced.setDefaultValue(synced); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<FluxSource> FluxSource::createHardwareFluxSource(unsigned drive) | ||||
| { | ||||
|     return std::unique_ptr<FluxSource>(new HardwareFluxSource(drive)); | ||||
|   | ||||
							
								
								
									
										25
									
								
								lib/image.cc
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								lib/image.cc
									
									
									
									
									
								
							| @@ -1,25 +0,0 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "fmt/format.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| SectorSet readSectorsFromFile(const ImageSpec& spec) | ||||
| { | ||||
| 	return ImageReader::create(spec)->readImage(); | ||||
| } | ||||
|  | ||||
| void writeSectorsToFile(const SectorSet& sectors, const ImageSpec& spec) | ||||
| { | ||||
| 	std::unique_ptr<ImageWriter> writer(ImageWriter::create(sectors, spec)); | ||||
| 	writer->adjustGeometry(); | ||||
| 	writer->printMap(); | ||||
| 	writer->writeImage(); | ||||
| } | ||||
							
								
								
									
										14
									
								
								lib/image.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								lib/image.h
									
									
									
									
									
								
							| @@ -1,14 +0,0 @@ | ||||
| #ifndef IMAGE_H | ||||
| #define IMAGE_H | ||||
|  | ||||
| class SectorSet; | ||||
| class ImageSpec; | ||||
|  | ||||
| extern SectorSet readSectorsFromFile( | ||||
| 	const ImageSpec& filename); | ||||
|  | ||||
| extern void writeSectorsToFile( | ||||
| 	const SectorSet& sectors, | ||||
| 	const ImageSpec& filename); | ||||
|  | ||||
| #endif | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "fmt/format.h" | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| std::map<std::string, ImageWriter::Constructor> ImageWriter::formats = | ||||
| { | ||||
| @@ -63,6 +64,56 @@ void ImageWriter::adjustGeometry() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ImageWriter::writeCsv(const std::string& filename) | ||||
| { | ||||
| 	std::ofstream f(filename, std::ios::out); | ||||
| 	if (!f.is_open()) | ||||
| 		Error() << "cannot open CSV report file"; | ||||
|  | ||||
| 	f << "\"Physical track\"," | ||||
| 		"\"Physical side\"," | ||||
| 		"\"Logical track\"," | ||||
| 		"\"Logical side\"," | ||||
| 		"\"Logical sector\"," | ||||
| 		"\"Clock (ns)\"," | ||||
| 		"\"Header start (ns)\"," | ||||
| 		"\"Header end (ns)\"," | ||||
| 		"\"Data start (ns)\"," | ||||
| 		"\"Data end (ns)\"," | ||||
| 		"\"Raw data address (bytes)\"," | ||||
| 		"\"User payload length (bytes)\"," | ||||
| 		"\"Status\"" | ||||
| 		"\n"; | ||||
|  | ||||
| 	for (int track = 0; track < spec.cylinders; track++) | ||||
| 	{ | ||||
| 		for (int head = 0; head < spec.heads; head++) | ||||
| 		{ | ||||
| 			for (int sectorId = 0; sectorId < spec.sectors; sectorId++) | ||||
| 			{ | ||||
| 				f << fmt::format("{},{},", track, head); | ||||
| 				const auto& sector = sectors.get(track, head, sectorId); | ||||
| 				if (!sector) | ||||
| 					f << fmt::format(",,{},,,,,,,,MISSING\n", sectorId); | ||||
| 				else | ||||
| 					f << fmt::format("{},{},{},{},{},{},{},{},{},{},{}\n", | ||||
| 						sector->logicalTrack, | ||||
| 						sector->logicalSide, | ||||
| 						sector->logicalSector, | ||||
| 						sector->clock, | ||||
| 						sector->headerStartTime, | ||||
| 						sector->headerEndTime, | ||||
| 						sector->dataStartTime, | ||||
| 						sector->dataEndTime, | ||||
| 						sector->position.bytes, | ||||
| 						sector->data.size(), | ||||
| 						Sector::statusToString(sector->status) | ||||
| 					); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ImageWriter::printMap() | ||||
| { | ||||
| 	int badSectors = 0; | ||||
|   | ||||
| @@ -35,6 +35,7 @@ private: | ||||
| public: | ||||
| 	virtual void adjustGeometry(); | ||||
| 	void printMap(); | ||||
| 	void writeCsv(const std::string& filename); | ||||
| 	virtual void writeImage() = 0; | ||||
|  | ||||
| protected: | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| #include "flags.h" | ||||
| #include "usb.h" | ||||
| #include "fluxsource/fluxsource.h" | ||||
| #include "fluxsink/fluxsink.h" | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "sql.h" | ||||
| @@ -11,14 +12,21 @@ | ||||
| #include "sectorset.h" | ||||
| #include "visualiser.h" | ||||
| #include "record.h" | ||||
| #include "image.h" | ||||
| #include "bytes.h" | ||||
| #include "decoders/rawbits.h" | ||||
| #include "track.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "fmt/format.h" | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| FlagGroup readerFlags { &hardwareFluxSourceFlags, &fluxmapReaderFlags, &visualiserFlags }; | ||||
| FlagGroup readerFlags | ||||
| { | ||||
| 	&hardwareFluxSourceFlags, | ||||
| 	&sqliteFluxSinkFlags, | ||||
| 	&fluxmapReaderFlags, | ||||
| 	&visualiserFlags | ||||
| }; | ||||
|  | ||||
| static DataSpecFlag source( | ||||
|     { "--source", "-s" }, | ||||
| @@ -46,7 +54,11 @@ static SettableFlag justRead( | ||||
|  | ||||
| static SettableFlag dumpRecords( | ||||
| 	{ "--dump-records" }, | ||||
| 	"Dump the parsed records."); | ||||
| 	"Dump the parsed but undecoded records."); | ||||
|  | ||||
| static SettableFlag dumpSectors( | ||||
| 	{ "--dump-sectors" }, | ||||
| 	"Dump the decoded sectors."); | ||||
|  | ||||
| static IntFlag retries( | ||||
| 	{ "--retries" }, | ||||
| @@ -57,7 +69,12 @@ static SettableFlag highDensityFlag( | ||||
| 	{ "--high-density", "--hd" }, | ||||
| 	"set the drive to high density mode"); | ||||
|  | ||||
| static sqlite3* outdb; | ||||
| static StringFlag csvFile( | ||||
| 	{ "--write-csv" }, | ||||
| 	"write a CSV report of the disk state", | ||||
| 	""); | ||||
|  | ||||
| static std::unique_ptr<FluxSink> outputFluxSink; | ||||
|  | ||||
| void setReaderDefaultSource(const std::string& source) | ||||
| { | ||||
| @@ -74,6 +91,16 @@ void setReaderRevolutions(int revolutions) | ||||
| 	setHardwareFluxSourceRevolutions(revolutions); | ||||
| } | ||||
|  | ||||
| static void writeSectorsToFile(const SectorSet& sectors, const ImageSpec& spec) | ||||
| { | ||||
| 	std::unique_ptr<ImageWriter> writer(ImageWriter::create(sectors, spec)); | ||||
| 	writer->adjustGeometry(); | ||||
| 	writer->printMap(); | ||||
| 	if (!csvFile.get().empty()) | ||||
| 		writer->writeCsv(csvFile.get()); | ||||
| 	writer->writeImage(); | ||||
| } | ||||
|  | ||||
| void Track::readFluxmap() | ||||
| { | ||||
| 	std::cout << fmt::format("{0:>3}.{1}: ", physicalTrack, physicalSide) << std::flush; | ||||
| @@ -82,8 +109,8 @@ void Track::readFluxmap() | ||||
| 		"{0} ms in {1} bytes\n", | ||||
|             int(fluxmap->duration()/1e6), | ||||
|             fluxmap->bytes()); | ||||
| 	if (outdb) | ||||
| 		sqlWriteFlux(outdb, physicalTrack, physicalSide, *fluxmap); | ||||
| 	if (outputFluxSink) | ||||
| 		outputFluxSink->writeFlux(physicalTrack, physicalSide, *fluxmap); | ||||
| } | ||||
|  | ||||
| std::vector<std::unique_ptr<Track>> readTracks() | ||||
| @@ -96,17 +123,8 @@ std::vector<std::unique_ptr<Track>> readTracks() | ||||
|  | ||||
| 	if (!destination.get().empty()) | ||||
| 	{ | ||||
| 		outdb = sqlOpen(destination, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); | ||||
| 		std::cout << "Writing a copy of the flux to " << destination.get() << std::endl; | ||||
| 		sqlPrepareFlux(outdb); | ||||
| 		sqlStmt(outdb, "BEGIN;"); | ||||
|         sqlWriteIntProperty(outdb, "version", FLUX_VERSION_CURRENT); | ||||
| 		atexit([]() | ||||
| 			{ | ||||
| 				sqlStmt(outdb, "COMMIT;"); | ||||
| 				sqlClose(outdb); | ||||
| 			} | ||||
| 		); | ||||
| 		outputFluxSink = FluxSink::createSqliteFluxSink(destination.get()); | ||||
| 	} | ||||
|  | ||||
| 	std::shared_ptr<FluxSource> fluxSource = FluxSource::create(spec); | ||||
| @@ -174,8 +192,6 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
| 			decoder.decodeToSectors(*track); | ||||
|  | ||||
| 			std::cout << "       "; | ||||
| 			if (!track->sectors.empty()) | ||||
| 			{ | ||||
| 				std::cout << fmt::format("{} records, {} sectors; ", | ||||
| 					track->rawrecords.size(), | ||||
| 					track->sectors.size()); | ||||
| @@ -191,9 +207,12 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
| 				} | ||||
|  | ||||
| 				bool hasBadSectors = false; | ||||
| 				std::set<unsigned> requiredSectors = decoder.requiredSectors(*track); | ||||
| 				for (const auto& i : readSectors) | ||||
| 				{ | ||||
| 					const auto& sector = i.second; | ||||
| 					requiredSectors.erase(sector->logicalSector); | ||||
|  | ||||
| 					if (sector->status != Sector::OK) | ||||
| 					{ | ||||
| 						std::cout << std::endl | ||||
| @@ -202,6 +221,12 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
| 						hasBadSectors = true; | ||||
| 					} | ||||
| 				} | ||||
| 				for (unsigned logicalSector : requiredSectors) | ||||
| 				{ | ||||
| 					std::cout << "\n" | ||||
| 					          << "       Required sector " << logicalSector << " missing; "; | ||||
| 					hasBadSectors = true; | ||||
| 				} | ||||
|  | ||||
| 				if (hasBadSectors) | ||||
| 					failures = false; | ||||
| @@ -211,7 +236,6 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
|  | ||||
| 				if (!hasBadSectors) | ||||
| 					break; | ||||
| 			} | ||||
|  | ||||
| 			if (!track->fluxsource->retryable()) | ||||
| 				break; | ||||
| @@ -219,10 +243,7 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
|                 std::cout << "giving up" << std::endl | ||||
|                           << "       "; | ||||
|             else | ||||
|             { | ||||
| 				std::cout << retry << " retries remaining" << std::endl; | ||||
|                 track->fluxsource->recalibrate(); | ||||
|             } | ||||
| 		} | ||||
|  | ||||
| 		if (dumpRecords) | ||||
| @@ -230,13 +251,27 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
| 			std::cout << "\nRaw (undecoded) records follow:\n\n"; | ||||
| 			for (auto& record : track->rawrecords) | ||||
| 			{ | ||||
| 				std::cout << fmt::format("I+{:.2f}us", record.position.ns() / 1000.0) | ||||
| 						<< std::endl; | ||||
| 				std::cout << fmt::format("I+{:.2f}us with {:.2f}us clock\n", | ||||
|                             record.position.ns() / 1000.0, record.clock / 1000.0); | ||||
| 				hexdump(std::cout, record.data); | ||||
| 				std::cout << std::endl; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|         if (dumpSectors) | ||||
|         { | ||||
|             std::cout << "\nDecoded sectors follow:\n\n"; | ||||
|             for (auto& i : readSectors) | ||||
|             { | ||||
|                 auto& sector = i.second; | ||||
| 				std::cout << fmt::format("{}.{:02}.{:02}: I+{:.2f}us with {:.2f}us clock\n", | ||||
|                             sector->logicalTrack, sector->logicalSide, sector->logicalSector, | ||||
|                             sector->position.ns() / 1000.0, sector->clock / 1000.0); | ||||
| 				hexdump(std::cout, sector->data); | ||||
| 				std::cout << std::endl; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         int size = 0; | ||||
| 		bool printedTrack = false; | ||||
|         for (auto& i : readSectors) | ||||
| @@ -261,7 +296,7 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
|  | ||||
| 	if (!visualise.get().empty()) | ||||
| 		visualiseSectorsToFile(allSectors, visualise.get()); | ||||
|  | ||||
| 	 | ||||
|     writeSectorsToFile(allSectors, outputSpec); | ||||
| 	if (failures) | ||||
| 		std::cerr << "Warning: some sectors could not be decoded." << std::endl; | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
|  | ||||
|   | ||||
							
								
								
									
										100
									
								
								lib/usb.cc
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								lib/usb.cc
									
									
									
									
									
								
							| @@ -44,6 +44,10 @@ static void usb_init() | ||||
|     if (i < 0) | ||||
|         Error() << "could not claim interface: " << usberror(i); | ||||
|  | ||||
| 	i = libusb_reset_device(device); | ||||
| 	if (i < 0) | ||||
| 		Error() << "could not reset device: " << usberror(i); | ||||
|  | ||||
|     int version = usbGetVersion(); | ||||
|     if (version != FLUXENGINE_VERSION) | ||||
|         Error() << "your FluxEngine firmware is at version " << version | ||||
| @@ -149,7 +153,7 @@ nanoseconds_t usbGetRotationalPeriod(void) | ||||
|     usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
|     auto r = await_reply<struct speed_frame>(F_FRAME_MEASURE_SPEED_REPLY); | ||||
|     return r->period_ms * 1000; | ||||
|     return r->period_ms * 1000000; | ||||
| } | ||||
|  | ||||
| static int large_bulk_transfer(int ep, Bytes& bytes) | ||||
| @@ -161,11 +165,11 @@ static int large_bulk_transfer(int ep, Bytes& bytes) | ||||
|     return len; | ||||
| } | ||||
|  | ||||
| void usbTestBulkTransport() | ||||
| void usbTestBulkWrite() | ||||
| { | ||||
|     usb_init(); | ||||
|  | ||||
|     struct any_frame f = { .f = {.type = F_FRAME_BULK_TEST_CMD, .size = sizeof(f)} }; | ||||
|     struct any_frame f = { .f = {.type = F_FRAME_BULK_WRITE_TEST_CMD, .size = sizeof(f)} }; | ||||
|     usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
|     /* These must match the device. */ | ||||
| @@ -180,9 +184,9 @@ void usbTestBulkTransport() | ||||
|  | ||||
|     std::cout << "Transferred " | ||||
|               << bulk_buffer.size() | ||||
|               << " bytes in " | ||||
|               << " bytes from FluxEngine -> PC in " | ||||
|               << int(elapsed_time * 1000.0) | ||||
|               << " (" | ||||
|               << " ms (" | ||||
|               << int((bulk_buffer.size() / 1024.0) / elapsed_time) | ||||
|               << " kB/s)" | ||||
|               << std::endl; | ||||
| @@ -199,16 +203,56 @@ void usbTestBulkTransport() | ||||
|                             << x << '.' << y << '.' << z << '.'; | ||||
|             } | ||||
|  | ||||
|     await_reply<struct any_frame>(F_FRAME_BULK_TEST_REPLY); | ||||
|     await_reply<struct any_frame>(F_FRAME_BULK_WRITE_TEST_REPLY); | ||||
| } | ||||
|  | ||||
| Bytes usbRead(int side, int revolutions) | ||||
| void usbTestBulkRead() | ||||
| { | ||||
|     usb_init(); | ||||
|  | ||||
|     struct any_frame f = { .f = {.type = F_FRAME_BULK_READ_TEST_CMD, .size = sizeof(f)} }; | ||||
|     usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
|     /* These must match the device. */ | ||||
|     const int XSIZE = 64; | ||||
|     const int YSIZE = 256; | ||||
|     const int ZSIZE = 64; | ||||
|  | ||||
|     Bytes bulk_buffer(XSIZE*YSIZE*ZSIZE); | ||||
|     for (int x=0; x<XSIZE; x++) | ||||
|         for (int y=0; y<YSIZE; y++) | ||||
|             for (int z=0; z<ZSIZE; z++) | ||||
|             { | ||||
|                 int offset = x*XSIZE*YSIZE + y*ZSIZE + z; | ||||
|                 bulk_buffer[offset] = uint8_t(x+y+z); | ||||
|             } | ||||
|  | ||||
|     double start_time = getCurrentTime(); | ||||
|     large_bulk_transfer(FLUXENGINE_DATA_OUT_EP, bulk_buffer); | ||||
|     double elapsed_time = getCurrentTime() - start_time; | ||||
|  | ||||
|     std::cout << "Transferred " | ||||
|               << bulk_buffer.size() | ||||
|               << " bytes from PC -> FluxEngine in " | ||||
|               << int(elapsed_time * 1000.0) | ||||
|               << " ms (" | ||||
|               << int((bulk_buffer.size() / 1024.0) / elapsed_time) | ||||
|               << " kB/s)" | ||||
|               << std::endl; | ||||
|  | ||||
|     await_reply<struct any_frame>(F_FRAME_BULK_READ_TEST_REPLY); | ||||
| } | ||||
|  | ||||
| Bytes usbRead(int side, bool synced, nanoseconds_t readTime) | ||||
| { | ||||
|     struct read_frame f = { | ||||
|         .f = { .type = F_FRAME_READ_CMD, .size = sizeof(f) }, | ||||
|         .side = (uint8_t) side, | ||||
|         .revolutions = (uint8_t) revolutions | ||||
|         .synced = (uint8_t) synced | ||||
|     }; | ||||
|     uint16_t milliseconds = readTime / 1e6; | ||||
|     ((uint8_t*)&f.milliseconds)[0] = milliseconds; | ||||
|     ((uint8_t*)&f.milliseconds)[1] = milliseconds >> 8; | ||||
|     usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
|     auto fluxmap = std::unique_ptr<Fluxmap>(new Fluxmap); | ||||
| @@ -253,15 +297,51 @@ void usbErase(int side) | ||||
|     await_reply<struct any_frame>(F_FRAME_ERASE_REPLY); | ||||
| } | ||||
|  | ||||
| void usbSetDrive(int drive, bool high_density) | ||||
| void usbSetDrive(int drive, bool high_density, int index_mode) | ||||
| { | ||||
|     usb_init(); | ||||
|  | ||||
|     struct set_drive_frame f = { | ||||
|         { .type = F_FRAME_SET_DRIVE_CMD, .size = sizeof(f) }, | ||||
|         .drive_flags = (uint8_t)((drive ? DRIVE_1 : DRIVE_0) | (high_density ? DRIVE_HD : DRIVE_DD)), | ||||
|         .drive = (uint8_t) drive, | ||||
|         .high_density = high_density, | ||||
|         .index_mode = (uint8_t) index_mode | ||||
|     }; | ||||
|     usb_cmd_send(&f, f.f.size); | ||||
|     await_reply<struct any_frame>(F_FRAME_SET_DRIVE_REPLY); | ||||
| } | ||||
|  | ||||
| /* Hacky: the board always operates in little-endian mode. */ | ||||
| static uint16_t read_short_from_usb(uint16_t usb) | ||||
| { | ||||
|     uint8_t* p = (uint8_t*)&usb; | ||||
|     return p[0] | (p[1] << 8); | ||||
| } | ||||
|  | ||||
| static void convert_voltages_from_usb(const struct voltages& vin, struct voltages& vout) | ||||
| { | ||||
|     vout.logic0_mv = read_short_from_usb(vin.logic0_mv); | ||||
|     vout.logic1_mv = read_short_from_usb(vin.logic1_mv); | ||||
| } | ||||
|  | ||||
| void usbMeasureVoltages(struct voltages_frame* voltages) | ||||
| { | ||||
|     usb_init(); | ||||
|  | ||||
|     struct any_frame f = { | ||||
|         { .type = F_FRAME_MEASURE_VOLTAGES_CMD, .size = sizeof(f) }, | ||||
|     }; | ||||
|     usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
|     struct voltages_frame* r = await_reply<struct voltages_frame>(F_FRAME_MEASURE_VOLTAGES_REPLY); | ||||
|     convert_voltages_from_usb(r->input_both_off, voltages->input_both_off); | ||||
|     convert_voltages_from_usb(r->input_drive_0_selected, voltages->input_drive_0_selected); | ||||
|     convert_voltages_from_usb(r->input_drive_1_selected, voltages->input_drive_1_selected); | ||||
|     convert_voltages_from_usb(r->input_drive_0_running, voltages->input_drive_0_running); | ||||
|     convert_voltages_from_usb(r->input_drive_1_running, voltages->input_drive_1_running); | ||||
|     convert_voltages_from_usb(r->output_both_off, voltages->output_both_off); | ||||
|     convert_voltages_from_usb(r->output_drive_0_selected, voltages->output_drive_0_selected); | ||||
|     convert_voltages_from_usb(r->output_drive_1_selected, voltages->output_drive_1_selected); | ||||
|     convert_voltages_from_usb(r->output_drive_0_running, voltages->output_drive_0_running); | ||||
|     convert_voltages_from_usb(r->output_drive_1_running, voltages->output_drive_1_running); | ||||
| } | ||||
|   | ||||
| @@ -8,10 +8,12 @@ extern int usbGetVersion(); | ||||
| extern void usbRecalibrate(); | ||||
| extern void usbSeek(int track); | ||||
| extern nanoseconds_t usbGetRotationalPeriod(); | ||||
| extern void usbTestBulkTransport(); | ||||
| extern Bytes usbRead(int side, int revolutions); | ||||
| extern void usbTestBulkWrite(); | ||||
| extern void usbTestBulkRead(); | ||||
| extern Bytes usbRead(int side, bool synced, nanoseconds_t readTime); | ||||
| extern void usbWrite(int side, const Bytes& bytes); | ||||
| extern void usbErase(int side); | ||||
| extern void usbSetDrive(int drive, bool high_density); | ||||
| extern void usbSetDrive(int drive, bool high_density, int index_mode); | ||||
| extern void usbMeasureVoltages(struct voltages_frame* voltages); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| #define _USE_MATH_DEFINES | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "visualiser.h" | ||||
|   | ||||
| @@ -9,13 +9,13 @@ | ||||
| #include "encoders/encoders.h" | ||||
| #include "fluxsource/fluxsource.h" | ||||
| #include "fluxsink/fluxsink.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "fmt/format.h" | ||||
| #include "record.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
|  | ||||
| FlagGroup writerFlags { &hardwareFluxSourceFlags }; | ||||
| FlagGroup writerFlags { &hardwareFluxSourceFlags, &hardwareFluxSinkFlags }; | ||||
|  | ||||
| static DataSpecFlag dest( | ||||
|     { "--dest", "-d" }, | ||||
| @@ -43,6 +43,11 @@ void setWriterDefaultInput(const std::string& input) | ||||
|     ::input.set(input); | ||||
| } | ||||
|  | ||||
| static SectorSet readSectorsFromFile(const ImageSpec& spec) | ||||
| { | ||||
| 	return ImageReader::create(spec)->readImage(); | ||||
| } | ||||
|  | ||||
| void writeTracks( | ||||
| 	const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer) | ||||
| { | ||||
| @@ -84,7 +89,9 @@ void writeTracks( | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2); | ||||
|             /* Precompensation actually seems to make things worse, so let's leave | ||||
|              * it disabled for now. */ | ||||
|             //fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2); | ||||
|             if (outdb) | ||||
|                 sqlWriteFlux(outdb, location.track, location.side, *fluxmap); | ||||
|             else | ||||
|   | ||||
							
								
								
									
										48
									
								
								mkninja.sh
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								mkninja.sh
									
									
									
									
									
								
							| @@ -44,18 +44,27 @@ buildlibrary() { | ||||
|         esac | ||||
|     done | ||||
|  | ||||
|     local objs | ||||
|     objs= | ||||
|     local oobjs | ||||
| 	local dobjs | ||||
|     oobjs= | ||||
| 	dobjs= | ||||
|     for src in "$@"; do | ||||
|         local obj | ||||
|         obj="$OBJDIR/${src%%.c*}.o" | ||||
|         objs="$objs $obj" | ||||
|         obj="$OBJDIR/opt/${src%%.c*}.o" | ||||
|         oobjs="$oobjs $obj" | ||||
|  | ||||
|         echo build $obj : cxx $src | ||||
|         echo "    flags=$flags" | ||||
|         echo "    flags=$flags $COPTFLAGS" | ||||
|  | ||||
|         obj="$OBJDIR/dbg/${src%%.c*}.o" | ||||
|         dobjs="$dobjs $obj" | ||||
|  | ||||
|         echo build $obj : cxx $src | ||||
|         echo "    flags=$flags $CDBGFLAGS" | ||||
|     done | ||||
|  | ||||
|     echo build $OBJDIR/$lib : library $objs | ||||
|     echo build $OBJDIR/opt/$lib : library $oobjs | ||||
|     echo build $OBJDIR/dbg/$lib : library $dobjs | ||||
| } | ||||
|  | ||||
| buildprogram() { | ||||
| @@ -77,16 +86,21 @@ buildprogram() { | ||||
|         esac | ||||
|     done | ||||
|  | ||||
|     local objs | ||||
|     objs= | ||||
|     local oobjs | ||||
| 	local dobjs | ||||
|     oobjs= | ||||
| 	dobjs= | ||||
|     for src in "$@"; do | ||||
|         objs="$objs $OBJDIR/$src" | ||||
|         oobjs="$oobjs $OBJDIR/opt/$src" | ||||
|         dobjs="$dobjs $OBJDIR/dbg/$src" | ||||
|     done | ||||
|  | ||||
|     echo build $prog-debug$EXTENSION : link $objs | ||||
|     echo "    flags=$flags" | ||||
|     echo build $prog-debug$EXTENSION : link $dobjs | ||||
|     echo "    flags=$flags $LDDBGFLAGS" | ||||
|  | ||||
|     echo build $prog$EXTENSION : link $oobjs | ||||
|     echo "    flags=$flags $LDOPTFLAGS" | ||||
|  | ||||
|     echo build $prog$EXTENSION : strip $prog-debug$EXTENSION | ||||
| } | ||||
|  | ||||
| buildsimpleprogram() { | ||||
| @@ -145,6 +159,8 @@ buildlibrary libbackend.a \ | ||||
| 	lib/imagewriter/ldbsimagewriter.cc \ | ||||
|     arch/aeslanier/decoder.cc \ | ||||
|     arch/amiga/decoder.cc \ | ||||
|     arch/amiga/encoder.cc \ | ||||
|     arch/amiga/amiga.cc \ | ||||
|     arch/apple2/decoder.cc \ | ||||
|     arch/brother/decoder.cc \ | ||||
|     arch/brother/encoder.cc \ | ||||
| @@ -152,6 +168,7 @@ buildlibrary libbackend.a \ | ||||
|     arch/f85/decoder.cc \ | ||||
|     arch/fb100/decoder.cc \ | ||||
|     arch/ibm/decoder.cc \ | ||||
|     arch/ibm/encoder.cc \ | ||||
|     arch/macintosh/decoder.cc \ | ||||
|     arch/mx/decoder.cc \ | ||||
|     arch/victor9k/decoder.cc \ | ||||
| @@ -176,7 +193,6 @@ buildlibrary libbackend.a \ | ||||
|     lib/fluxsource/streamfluxsource.cc \ | ||||
|     lib/globals.cc \ | ||||
|     lib/hexdump.cc \ | ||||
|     lib/image.cc \ | ||||
|     lib/ldbs.cc \ | ||||
|     lib/reader.cc \ | ||||
|     lib/sector.cc \ | ||||
| @@ -211,9 +227,12 @@ buildlibrary libfrontend.a \ | ||||
|     src/fe-rpm.cc \ | ||||
|     src/fe-scptoflux.cc \ | ||||
|     src/fe-seek.cc \ | ||||
|     src/fe-testbulktransport.cc \ | ||||
|     src/fe-testbandwidth.cc \ | ||||
|     src/fe-testvoltages.cc \ | ||||
|     src/fe-upgradefluxfile.cc \ | ||||
|     src/fe-writeamiga.cc \ | ||||
|     src/fe-writebrother.cc \ | ||||
|     src/fe-writeibm.cc \ | ||||
|     src/fe-writeflux.cc \ | ||||
|     src/fe-writetestpattern.cc \ | ||||
|     src/fluxengine.cc \ | ||||
| @@ -250,3 +269,4 @@ runtest fluxpattern-test    tests/fluxpattern.cc | ||||
| runtest fmmfm-test          tests/fmmfm.cc | ||||
| runtest kryoflux-test       tests/kryoflux.cc | ||||
| runtest ldbs-test           tests/ldbs.cc | ||||
| runtest amiga-test          tests/amiga.cc | ||||
|   | ||||
							
								
								
									
										45
									
								
								protocol.h
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								protocol.h
									
									
									
									
									
								
							| @@ -3,7 +3,7 @@ | ||||
|  | ||||
| enum  | ||||
| { | ||||
|     FLUXENGINE_VERSION = 8, | ||||
|     FLUXENGINE_VERSION = 12, | ||||
|  | ||||
|     FLUXENGINE_VID = 0x1209, | ||||
|     FLUXENGINE_PID = 0x6e00, | ||||
| @@ -50,8 +50,10 @@ enum | ||||
|     F_FRAME_SEEK_REPLY,           /* any_frame */ | ||||
|     F_FRAME_MEASURE_SPEED_CMD,    /* any_frame */ | ||||
|     F_FRAME_MEASURE_SPEED_REPLY,  /* speed_frame */ | ||||
|     F_FRAME_BULK_TEST_CMD,        /* any_frame */ | ||||
|     F_FRAME_BULK_TEST_REPLY,      /* any_frame */ | ||||
|     F_FRAME_BULK_WRITE_TEST_CMD,   /* any_frame */ | ||||
|     F_FRAME_BULK_WRITE_TEST_REPLY, /* any_frame */ | ||||
|     F_FRAME_BULK_READ_TEST_CMD,   /* any_frame */ | ||||
|     F_FRAME_BULK_READ_TEST_REPLY, /* any_frame */ | ||||
|     F_FRAME_READ_CMD,             /* read_frame */ | ||||
|     F_FRAME_READ_REPLY,           /* any_frame */ | ||||
|     F_FRAME_WRITE_CMD,            /* write_frame */ | ||||
| @@ -62,6 +64,8 @@ enum | ||||
|     F_FRAME_RECALIBRATE_REPLY,    /* any_frame */ | ||||
|     F_FRAME_SET_DRIVE_CMD,        /* setdrive_frame */ | ||||
|     F_FRAME_SET_DRIVE_REPLY,      /* any_frame */ | ||||
|     F_FRAME_MEASURE_VOLTAGES_CMD, /* any_frame */ | ||||
|     F_FRAME_MEASURE_VOLTAGES_REPLY, /* voltages_frame */ | ||||
| }; | ||||
|  | ||||
| enum | ||||
| @@ -73,6 +77,13 @@ enum | ||||
|     F_ERROR_INTERNAL, | ||||
| }; | ||||
|  | ||||
| enum | ||||
| { | ||||
|     F_INDEX_REAL, | ||||
|     F_INDEX_300, | ||||
|     F_INDEX_360 | ||||
| }; | ||||
|  | ||||
| enum | ||||
| { | ||||
|     F_OP_PULSE = 0x80, | ||||
| @@ -124,7 +135,8 @@ struct read_frame | ||||
| { | ||||
|     struct frame_header f; | ||||
|     uint8_t side; | ||||
|     uint8_t revolutions; | ||||
|     uint8_t synced; | ||||
|     uint16_t milliseconds; | ||||
| }; | ||||
|  | ||||
| struct write_frame | ||||
| @@ -143,7 +155,30 @@ struct erase_frame | ||||
| struct set_drive_frame | ||||
| { | ||||
|     struct frame_header f; | ||||
|     uint8_t drive_flags; | ||||
|     uint8_t drive; | ||||
|     uint8_t high_density; | ||||
|     uint8_t index_mode; | ||||
| }; | ||||
|  | ||||
| struct voltages | ||||
| { | ||||
|     uint16_t logic0_mv; | ||||
|     uint16_t logic1_mv; | ||||
| }; | ||||
|  | ||||
| struct voltages_frame | ||||
| { | ||||
|     struct frame_header f; | ||||
|     struct voltages output_both_off; | ||||
|     struct voltages output_drive_0_selected; | ||||
|     struct voltages output_drive_1_selected; | ||||
|     struct voltages output_drive_0_running; | ||||
|     struct voltages output_drive_1_running; | ||||
|     struct voltages input_both_off; | ||||
|     struct voltages input_drive_0_selected; | ||||
|     struct voltages input_drive_1_selected; | ||||
|     struct voltages input_drive_0_running; | ||||
|     struct voltages input_drive_1_running; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -85,7 +85,7 @@ int mainConvertFluxToScp(int argc, const char* argv[]) | ||||
|     fileheader.file_id[0] = 'S'; | ||||
|     fileheader.file_id[1] = 'C'; | ||||
|     fileheader.file_id[2] = 'P'; | ||||
|     fileheader.file_id[3] = 0x18; /* Version 1.8 of the spec */ | ||||
|     fileheader.version = 0x18; /* Version 1.8 of the spec */ | ||||
|     fileheader.type = diskType; | ||||
|     fileheader.revolutions = 5; | ||||
|     fileheader.start_track = 0; | ||||
|   | ||||
| @@ -4,7 +4,6 @@ | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/rawbits.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
| @@ -12,11 +11,6 @@ | ||||
|  | ||||
| static FlagGroup flags { &readerFlags }; | ||||
|  | ||||
| static StringFlag outputFilename( | ||||
|     { "--output", "-o" }, | ||||
|     "The output image file to write to.", | ||||
|     "aeslanier.img"); | ||||
|  | ||||
| int mainReadAESLanier(int argc, const char* argv[]) | ||||
| { | ||||
| 	setReaderDefaultSource(":t=0-79:s=0"); | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "amiga/amiga.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "apple2/apple2.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| #include "brother/brother.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "c64/c64.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "f85/f85.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -3,32 +3,37 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
| #include "dataspec.h" | ||||
| #include "ibm/ibm.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| static FlagGroup flags { &readerFlags }; | ||||
|  | ||||
| static IntFlag sectorIdBase( | ||||
| 	{ "--sector-id-base" }, | ||||
| 	{ "--ibm-sector-id-base" }, | ||||
| 	"Sector ID of the first sector.", | ||||
| 	1); | ||||
|  | ||||
| static BoolFlag ignoreSideByte( | ||||
| 	{ "--ignore-side-byte" }, | ||||
| 	{ "--ibm-ignore-side-byte" }, | ||||
| 	"Ignore the side byte in the sector ID, and use the physical side instead.", | ||||
| 	false); | ||||
|  | ||||
| static RangeFlag requiredSectors( | ||||
| 	{ "--ibm-required-sectors" }, | ||||
| 	"A comma seperated list or range of sectors which must be on each track.", | ||||
| 	""); | ||||
|  | ||||
| int mainReadIBM(int argc, const char* argv[]) | ||||
| { | ||||
| 	setReaderDefaultSource(":t=0-79:s=0-1"); | ||||
| 	setReaderDefaultOutput("ibm.img"); | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
| 	IbmDecoder decoder(sectorIdBase, ignoreSideByte); | ||||
| 	IbmDecoder decoder(sectorIdBase, ignoreSideByte, requiredSectors); | ||||
| 	readDiskCommand(decoder); | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "macintosh/macintosh.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -4,11 +4,9 @@ | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "mx/mx.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
| #include <fmt/format.h> | ||||
|  | ||||
| static FlagGroup flags { &readerFlags }; | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "victor9k/victor9k.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| #include "flags.h" | ||||
| #include "usb.h" | ||||
| #include "dataspec.h" | ||||
| #include "protocol.h" | ||||
|  | ||||
| static FlagGroup flags; | ||||
|  | ||||
| @@ -15,9 +16,18 @@ int mainRpm(int argc, const char* argv[]) | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
|     FluxSpec spec(source); | ||||
|     usbSetDrive(spec.drive, false); | ||||
|     usbSetDrive(spec.drive, false, F_INDEX_REAL); | ||||
|     nanoseconds_t period = usbGetRotationalPeriod(); | ||||
|     std::cout << "Rotational period is " << period/1000 << " ms (" << 60e6/period << " rpm)" << std::endl; | ||||
|     if (period != 0) | ||||
|         std::cout << "Rotational period is " << period/1000000 << " ms (" << 60e9/period << " rpm)" << std::endl; | ||||
|     else | ||||
|     { | ||||
|         std::cout << "No index pulses detected from the disk. Common causes of this are:\n" | ||||
|                      "  - no drive is connected\n" | ||||
|                      "  - the drive doesn't have an index sensor (e.g. BBC Micro drives)\n" | ||||
|                      "  - the disk has no index holes (e.g. reversed flippy disks)\n" | ||||
|                      "  - (most common) no disk is inserted in the drive!\n"; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "usb.h" | ||||
| #include "protocol.h" | ||||
|  | ||||
| static FlagGroup flags; | ||||
|  | ||||
| @@ -18,7 +19,7 @@ int mainSeek(int argc, const char* argv[]) | ||||
| { | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
|     usbSetDrive(drive, false); | ||||
|     usbSetDrive(drive, false, F_INDEX_REAL); | ||||
|     usbSeek(track); | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -4,9 +4,10 @@ | ||||
| 
 | ||||
| static FlagGroup flags; | ||||
| 
 | ||||
| int mainTestBulkTransport(int argc, const char* argv[]) | ||||
| int mainTestBandwidth(int argc, const char* argv[]) | ||||
| { | ||||
|     flags.parseFlags(argc, argv); | ||||
|     usbTestBulkTransport(); | ||||
|     usbTestBulkWrite(); | ||||
|     usbTestBulkRead(); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										47
									
								
								src/fe-testvoltages.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/fe-testvoltages.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "usb.h" | ||||
| #include "protocol.h" | ||||
| #include <fmt/format.h> | ||||
|  | ||||
| static FlagGroup flags; | ||||
|  | ||||
| static std::string display_voltages(struct voltages& v) | ||||
| { | ||||
|     return fmt::format( | ||||
|         "      Logic 1 / 0:  {:.2f}V / {:.2f}V\n", | ||||
|         v.logic0_mv / 1000.0, | ||||
|         v.logic1_mv / 1000.0); | ||||
| } | ||||
|  | ||||
| int mainTestVoltages(int argc, const char* argv[]) | ||||
| { | ||||
|     flags.parseFlags(argc, argv); | ||||
|     struct voltages_frame f; | ||||
|     usbMeasureVoltages(&f); | ||||
|  | ||||
|     std::cout << "Output voltages:\n" | ||||
|               << "  Both drives deselected\n" | ||||
|               << display_voltages(f.output_both_off) | ||||
|               << "  Drive 0 selected\n" | ||||
|               << display_voltages(f.output_drive_0_selected) | ||||
|               << "  Drive 1 selected\n" | ||||
|               << display_voltages(f.output_drive_1_selected) | ||||
|               << "  Drive 0 running\n" | ||||
|               << display_voltages(f.output_drive_0_running) | ||||
|               << "  Drive 1 running\n" | ||||
|               << display_voltages(f.output_drive_1_running) | ||||
|               << "Input voltages:\n" | ||||
|               << "  Both drives deselected\n" | ||||
|               << display_voltages(f.input_both_off) | ||||
|               << "  Drive 0 selected\n" | ||||
|               << display_voltages(f.input_drive_0_selected) | ||||
|               << "  Drive 1 selected\n" | ||||
|               << display_voltages(f.input_drive_1_selected) | ||||
|               << "  Drive 0 running\n" | ||||
|               << display_voltages(f.input_drive_0_running) | ||||
|               << "  Drive 1 running\n" | ||||
|               << display_voltages(f.input_drive_1_running); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										22
									
								
								src/fe-writeamiga.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/fe-writeamiga.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "amiga/amiga.h" | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|  | ||||
| static FlagGroup flags { &writerFlags, &amigaEncoderFlags }; | ||||
|  | ||||
| int mainWriteAmiga(int argc, const char* argv[]) | ||||
| { | ||||
|     setWriterDefaultInput(":c=80:h=2:s=11:b=512"); | ||||
|     setWriterDefaultDest(":d=0:t=0-79:s=0-1"); | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
| 	AmigaEncoder encoder; | ||||
| 	writeDiskCommand(encoder); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @@ -5,7 +5,6 @@ | ||||
| #include "brother/brother.h" | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include "image.h" | ||||
| #include <fstream> | ||||
|  | ||||
| static FlagGroup flags { &writerFlags, &brotherEncoderFlags }; | ||||
|   | ||||
							
								
								
									
										138
									
								
								src/fe-writeibm.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/fe-writeibm.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "ibm/ibm.h" | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|  | ||||
| static FlagGroup flags { &writerFlags }; | ||||
|  | ||||
| static IntFlag trackLengthMs( | ||||
| 	{ "--ibm-track-length-ms" }, | ||||
| 	"Length of a track in milliseconds.", | ||||
| 	0); | ||||
|  | ||||
| static IntFlag sectorSize( | ||||
| 	{ "--ibm-sector-size" }, | ||||
| 	"Size of the sectors to write (bytes).", | ||||
| 	0); | ||||
|  | ||||
| static BoolFlag emitIam( | ||||
| 	{ "--ibm-emit-iam" }, | ||||
| 	"Whether to emit an IAM record at the start of the track.", | ||||
| 	false); | ||||
|  | ||||
| static IntFlag startSectorId( | ||||
| 	{ "--ibm-start-sector-id" }, | ||||
| 	"Sector ID of first sector.", | ||||
| 	1); | ||||
|  | ||||
| static IntFlag clockRateKhz( | ||||
| 	{ "--ibm-clock-rate-khz" }, | ||||
| 	"Clock rate of data to write.", | ||||
| 	0); | ||||
|  | ||||
| static BoolFlag useFm( | ||||
| 	{ "--ibm-use-fm" }, | ||||
| 	"Write in FM mode, rather than MFM.", | ||||
| 	false); | ||||
|  | ||||
| static HexIntFlag idamByte( | ||||
| 	{ "--ibm-idam-byte" }, | ||||
| 	"16-bit RAW bit pattern to use for the IDAM ID byte", | ||||
| 	0); | ||||
|  | ||||
| static HexIntFlag damByte( | ||||
| 	{ "--ibm-dam-byte" }, | ||||
| 	"16-bit RAW bit pattern to use for the DAM ID byte", | ||||
| 	0); | ||||
|  | ||||
| static IntFlag gap0( | ||||
| 	{ "--ibm-gap0-bytes" }, | ||||
| 	"Size of gap 0 (the pre-index gap)", | ||||
| 	0); | ||||
|  | ||||
| static IntFlag gap1( | ||||
| 	{ "--ibm-gap1-bytes" }, | ||||
| 	"Size of gap 1 (the post-index gap).", | ||||
| 	0); | ||||
|  | ||||
| static IntFlag gap2( | ||||
| 	{ "--ibm-gap2-bytes" }, | ||||
| 	"Size of gap 2 (the post-ID gap).", | ||||
| 	0); | ||||
|  | ||||
| static IntFlag gap3( | ||||
| 	{ "--ibm-gap3-bytes" }, | ||||
| 	"Size of gap 3 (the post-data or format gap).", | ||||
| 	0); | ||||
|  | ||||
| static StringFlag sectorSkew( | ||||
| 	{ "--ibm-sector-skew" }, | ||||
| 	"Order to emit sectors.", | ||||
| 	""); | ||||
|  | ||||
| static ActionFlag preset1440( | ||||
| 	{ "--ibm-preset-1440" }, | ||||
| 	"Preset parameters to a 3.5\" 1440kB disk.", | ||||
| 	[] { | ||||
| 		setWriterDefaultInput(":c=80:h=2:s=18:b=512"); | ||||
| 		trackLengthMs.setDefaultValue(200); | ||||
| 		sectorSize.setDefaultValue(512); | ||||
| 		emitIam.setDefaultValue(true); | ||||
| 		clockRateKhz.setDefaultValue(500); | ||||
| 		idamByte.setDefaultValue(0x5554); | ||||
| 		damByte.setDefaultValue(0x5545); | ||||
| 		gap0.setDefaultValue(80); | ||||
| 		gap1.setDefaultValue(50); | ||||
| 		gap2.setDefaultValue(22); | ||||
| 		gap3.setDefaultValue(108); | ||||
| 		sectorSkew.setDefaultValue("0123456789abcdefgh"); | ||||
| 	}); | ||||
|  | ||||
| static ActionFlag preset720( | ||||
| 	{ "--ibm-preset-720" }, | ||||
| 	"Preset parameters to a 3.5\" 720kB disk.", | ||||
| 	[] { | ||||
| 		setWriterDefaultInput(":c=80:h=2:s=9:b=512"); | ||||
| 		trackLengthMs.setDefaultValue(200); | ||||
| 		sectorSize.setDefaultValue(512); | ||||
| 		emitIam.setDefaultValue(true); | ||||
| 		clockRateKhz.setDefaultValue(250); | ||||
| 		idamByte.setDefaultValue(0x5554); | ||||
| 		damByte.setDefaultValue(0x5545); | ||||
| 		gap0.setDefaultValue(80); | ||||
| 		gap1.setDefaultValue(50); | ||||
| 		gap2.setDefaultValue(22); | ||||
| 		gap3.setDefaultValue(80); | ||||
| 		sectorSkew.setDefaultValue("012345678"); | ||||
| 	}); | ||||
|  | ||||
| int mainWriteIbm(int argc, const char* argv[]) | ||||
| { | ||||
| 	setWriterDefaultDest(":d=0:t=0-79:s=0-1"); | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
| 	IbmParameters parameters; | ||||
| 	parameters.trackLengthMs = trackLengthMs; | ||||
| 	parameters.sectorSize = sectorSize; | ||||
| 	parameters.emitIam = emitIam; | ||||
| 	parameters.startSectorId = startSectorId; | ||||
| 	parameters.clockRateKhz = clockRateKhz; | ||||
| 	parameters.useFm = useFm; | ||||
| 	parameters.idamByte = idamByte; | ||||
| 	parameters.damByte = damByte; | ||||
| 	parameters.gap0 = gap0; | ||||
| 	parameters.gap1 = gap1; | ||||
| 	parameters.gap2 = gap2; | ||||
| 	parameters.gap3 = gap3; | ||||
| 	parameters.sectorSkew = sectorSkew; | ||||
|  | ||||
| 	IbmEncoder encoder(parameters); | ||||
| 	writeDiskCommand(encoder); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @@ -26,9 +26,12 @@ extern command_cb mainReadVictor9K; | ||||
| extern command_cb mainReadZilogMCZ; | ||||
| extern command_cb mainRpm; | ||||
| extern command_cb mainSeek; | ||||
| extern command_cb mainTestBulkTransport; | ||||
| extern command_cb mainTestBandwidth; | ||||
| extern command_cb mainTestVoltages; | ||||
| extern command_cb mainUpgradeFluxFile; | ||||
| extern command_cb mainWriteAmiga; | ||||
| extern command_cb mainWriteBrother; | ||||
| extern command_cb mainWriteIbm; | ||||
| extern command_cb mainWriteFlux; | ||||
| extern command_cb mainWriteTestPattern; | ||||
|  | ||||
| @@ -42,6 +45,7 @@ struct Command | ||||
| static command_cb mainRead; | ||||
| static command_cb mainWrite; | ||||
| static command_cb mainConvert; | ||||
| static command_cb mainTest; | ||||
|  | ||||
| static std::vector<Command> commands = | ||||
| { | ||||
| @@ -51,7 +55,7 @@ static std::vector<Command> commands = | ||||
|     { "read",              mainRead,              "Reads a disk, producing a sector image.", }, | ||||
|     { "rpm",               mainRpm,               "Measures the disk rotational speed.", }, | ||||
|     { "seek",              mainSeek,              "Moves the disk head.", }, | ||||
|     { "testbulktransport", mainTestBulkTransport, "Measures your USB bandwidth.", }, | ||||
|     { "test",              mainTest,              "Various testing commands.", }, | ||||
|     { "upgradefluxfile",   mainUpgradeFluxFile,   "Upgrades a flux file from a previous version of this software.", }, | ||||
|     { "write",             mainWrite,             "Writes a sector image to a disk.", }, | ||||
|     { "writeflux",         mainWriteFlux,         "Writes a raw flux file. Warning: you can't use this to copy disks.", }, | ||||
| @@ -79,7 +83,9 @@ static std::vector<Command> readables = | ||||
|  | ||||
| static std::vector<Command> writeables = | ||||
| { | ||||
|     { "amiga",         mainWriteAmiga,    "Writes Amiga disks.", }, | ||||
|     { "brother",       mainWriteBrother,  "Writes 120kB and 240kB Brother word processor disks.", }, | ||||
|     { "ibm",           mainWriteIbm,      "Writes the ubiquitous IBM format disks.", }, | ||||
| }; | ||||
|  | ||||
| static std::vector<Command> convertables = | ||||
| @@ -91,6 +97,12 @@ static std::vector<Command> convertables = | ||||
|     { "fluxtovcd",     mainConvertFluxToVcd, "Converts (one track of a) flux file to a VCD file.", }, | ||||
| }; | ||||
|  | ||||
| static std::vector<Command> testables = | ||||
| { | ||||
|     { "bandwidth",     mainTestBandwidth, "Measures your USB bandwidth.", }, | ||||
|     { "voltages",      mainTestVoltages,  "Measures the FDD bus voltages.", }, | ||||
| }; | ||||
|  | ||||
| static void extendedHelp(std::vector<Command>& subcommands, const std::string& command) | ||||
| { | ||||
|     std::cout << "fluxengine: syntax: fluxengine " << command << " <format> [<flags>...]\n" | ||||
| @@ -131,6 +143,9 @@ static int mainWrite(int argc, const char* argv[]) | ||||
| static int mainConvert(int argc, const char* argv[]) | ||||
| { return mainExtended(convertables, "convert", argc, argv); } | ||||
|  | ||||
| static int mainTest(int argc, const char* argv[]) | ||||
| { return mainExtended(testables, "test", argc, argv); } | ||||
|  | ||||
| static void help() | ||||
| { | ||||
|     std::cout << "fluxengine: syntax: fluxengine <command> [<flags>...]\n" | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user