1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-04-25 11:17:26 +00:00

Compare commits

...

1634 Commits

Author SHA1 Message Date
Thomas Harte 4be5ee5b35 Fix value interactions. 2025-11-17 23:25:47 -05:00
Thomas Harte 92e6dc64d4 Merge branch 'master' into QueueDelegate 2025-11-17 23:21:24 -05:00
Thomas Harte a9d945d6d2 Merge pull request #1639 from TomHarte/CommodoreNew6502s
Adapt all Commodore machines to 6502Mk2.
2025-11-17 23:16:17 -05:00
Thomas Harte 5e465f1ff4 Avoid function specialisation. 2025-11-17 23:04:33 -05:00
Thomas Harte 5359964fef Make minor style improvements, fix cursor keys. 2025-11-17 22:55:18 -05:00
Thomas Harte fa8be26f9f Fix read-only bit. 2025-11-17 22:20:20 -05:00
Thomas Harte aabfe7c284 Observe that there is an attempt to output data. 2025-11-17 21:15:42 -05:00
Thomas Harte d011b10b5d Update comments, add note-to-self on write mode. 2025-11-17 17:54:09 -05:00
Thomas Harte 332b37063f Adjust for style. 2025-11-17 17:15:26 -05:00
Thomas Harte b3a9e39be3 Transfer C1540, ensure Plus 4 bus always holds _something_. 2025-11-17 14:39:35 -05:00
Thomas Harte 67590cf06b Adapt Vic-20 to the newer 6502. 2025-11-17 14:23:05 -05:00
Thomas Harte 236fdacb36 Adapt Plus 4 to the newer 6502. 2025-11-17 14:14:25 -05:00
Thomas Harte f422cda553 Adapt the Enterprise, accepting possible need for HalfCycles. 2025-11-16 08:04:47 -05:00
Thomas Harte 2c44d3a7d3 Adapt the Plus 4. 2025-11-15 22:31:17 -05:00
Thomas Harte 051ce98ecb Adapt Vic-20. 2025-11-15 22:18:46 -05:00
Thomas Harte 33ae24c961 Attempt to shrink repetition even further. 2025-11-15 21:41:34 -05:00
Thomas Harte 4247d0ef40 Adapt Atari 2600. 2025-11-14 22:58:41 -05:00
Thomas Harte ffababdb45 With the Electron as a test bed, start to simplify audio class groups. 2025-11-14 22:39:53 -05:00
Thomas Harte 176bda9eb8 Merge pull request #1637 from TomHarte/Voice3Off
SID: support the voice 3 disable bit.
2025-11-14 19:35:05 -05:00
Thomas Harte 9f0a0443a8 SID: support the voice 3 disable bit. 2025-11-14 15:38:54 -05:00
Thomas Harte fd1a7e78c5 Merge pull request #1636 from TomHarte/BiquadAttribution
Record references for the SID and biquad filter.
2025-11-14 13:29:55 -05:00
Thomas Harte 909fa57b27 Record references for the SID and biquad filter. 2025-11-14 13:29:15 -05:00
Thomas Harte 5630b1c351 Merge pull request #1634 from TomHarte/BeebSID
Investigate the SID via BeebSID.
2025-11-13 20:38:34 -05:00
Thomas Harte c4fe38a61f Allow potentometer inputs to be set; disable SID by default. 2025-11-13 18:05:13 -05:00
Thomas Harte 5b4f303e35 Mention memory barrier. 2025-11-13 18:02:41 -05:00
Thomas Harte c9c1bde6e2 Switch to spinning on SID thread synchronisation. 2025-11-13 17:59:24 -05:00
Thomas Harte d01e1f3bb1 Block and synchronise threads for voice 3 readback. 2025-11-13 17:34:57 -05:00
Thomas Harte fd32e63459 Clean up: pull out noise generation, remove code from header. 2025-11-13 13:44:53 -05:00
Thomas Harte dbbb1d60fc Add commentary, use filter reconfiguration to retain sample history. 2025-11-13 13:27:55 -05:00
Thomas Harte 1ce013bcf7 Simplify, update noise tap. 2025-11-13 11:59:56 -05:00
Thomas Harte 86bf019aac Attempt further to improve filter precision. 2025-11-13 11:54:37 -05:00
Thomas Harte d00546dd77 Add post hoc filter, attempt to juice precision. 2025-11-13 07:31:59 -05:00
Thomas Harte cf33e17688 Attempt to use biquad filter; fix signs. 2025-11-12 23:08:35 -05:00
Thomas Harte c5c6c5ff72 Add textbook filter construction. 2025-11-12 22:06:48 -05:00
Thomas Harte fa0835abd8 Capture all filter parameters. 2025-11-12 17:47:49 -05:00
Thomas Harte f232b179ed Partition channels into filtered and unfiltered, and apply no-op biquad. 2025-11-12 17:40:14 -05:00
Thomas Harte a4a0026cab Reintroduce decay stage; flip pulse meaning. 2025-11-11 21:38:27 -05:00
Thomas Harte eac7493180 Support master volume. 2025-11-11 21:04:07 -05:00
Thomas Harte 989fb32fba Fix clocking, do a linear attack phase. 2025-11-11 20:53:54 -05:00
Thomas Harte 735afcfabb Adopt painful pulse test, temporarily (?). 2025-11-11 18:26:00 -05:00
Thomas Harte 37152a1fad Start testing; I'm now unsure about pulses. 2025-11-11 17:54:31 -05:00
Thomas Harte 4e86184955 Add local hack to ensure good flushing. 2025-11-11 14:40:13 -05:00
Thomas Harte d23dbb96c2 Support system volume, avoid clipping. 2025-11-11 14:40:04 -05:00
Thomas Harte 4586e4b4c1 Apply envelope. 2025-11-11 14:26:53 -05:00
Thomas Harte de5cdbf18c Make a complete attempt at ADSR. 2025-11-11 14:25:36 -05:00
Thomas Harte 8c2294fc0d Treat sustain as a volume; start second prescaler table. 2025-11-11 12:43:48 -05:00
Thomas Harte b0b82782ad Build in initial prescaler. 2025-11-11 12:21:49 -05:00
Thomas Harte b9f5802c89 Return whatever was written last if read. 2025-11-11 09:19:01 -05:00
Thomas Harte 29235f1276 Adjust noise clocking, make it reactive to the test bit. 2025-11-11 09:16:43 -05:00
Thomas Harte 8c74e2a323 Implement LFSR. 2025-11-10 22:44:00 -05:00
Thomas Harte ae2936b9c3 Correct clock rate, triangle wave. 2025-11-10 22:35:13 -05:00
Thomas Harte 0d295a6338 Don't capture a reference to parameters. 2025-11-10 22:10:28 -05:00
Thomas Harte 3ebd6c6871 Rejig oscillators, output some vague noise. 2025-11-10 21:52:10 -05:00
Thomas Harte 6e2cd0ace6 Divide state, start adding waveforms. 2025-11-10 17:27:32 -05:00
Thomas Harte af82a0bcda Add ADSR TODO. 2025-11-10 14:18:24 -05:00
Thomas Harte 6fe208ae77 Honour test and sync bits. 2025-11-10 14:17:54 -05:00
Thomas Harte f569b86c90 Merge branch 'master' into BeebSID 2025-11-10 14:10:33 -05:00
Thomas Harte b622cc9536 Merge pull request #1635 from TomHarte/CleanerQueue
Enforce perform_automatically, start_immediately; relax Boolean access order.
2025-11-10 14:09:31 -05:00
Thomas Harte 7dfd5ea0d0 Add phase accumulation, rename to pitch. 2025-11-10 13:27:43 -05:00
Thomas Harte a81309433c Switch to lambda form. 2025-11-09 21:09:57 -05:00
Thomas Harte 902f388cb1 Enforce perform_automatically, start_immediately; relax Boolean access order. 2025-11-09 00:17:39 -05:00
Thomas Harte 0cc5a9d74f Move thread. 2025-11-08 23:02:54 -05:00
Thomas Harte 5e98e6502d Attempt some basic voice details. 2025-11-08 21:54:41 -05:00
Thomas Harte fe7a206fc5 Add an empty vessel of a SID. 2025-11-07 22:51:28 -05:00
Thomas Harte c5704aaaff Merge pull request #1633 from TomHarte/TubeBrevity
Move point of templature to tube processors.
2025-11-07 18:05:19 -05:00
Thomas Harte e115f09f51 Merge pull request #1632 from TomHarte/6845DeadState
Remove dead state.
2025-11-07 17:54:13 -05:00
Thomas Harte 32cd142629 Move point of templature to tube processors. 2025-11-07 17:27:52 -05:00
Thomas Harte b00be303aa Remove dead state. 2025-11-07 13:08:12 -05:00
Thomas Harte 273e23bd98 Merge pull request #1631 from TomHarte/SecondProcessorScreenshot
Substitute a screenshot of Second Processor Elite.
2025-11-07 12:54:16 -05:00
Thomas Harte 5063e6943d Substitute a screenshot of Second Processor Elite. 2025-11-07 12:53:09 -05:00
Thomas Harte ce32747973 Record new version number. 2025-11-07 12:39:46 -05:00
Thomas Harte a8ef8dfb21 Merge pull request #1630 from TomHarte/DNFS
Add DFS 0.9 to ROM catalogue; restrict CRTC pointer size.
2025-11-07 11:19:21 -05:00
Thomas Harte 7658edca62 Remove unused enum. 2025-11-07 10:49:26 -05:00
Thomas Harte 056028e07b Put bit restriction on register pointer. 2025-11-07 10:43:14 -05:00
Thomas Harte 34992126a8 Allow installation of smaller ROMs. 2025-11-07 09:12:47 -05:00
Thomas Harte d30d4e8f89 Add DFS 0.9 to the ROM catalogue. 2025-11-07 09:08:16 -05:00
Thomas Harte f562deca48 Record new version number. 2025-11-05 20:56:13 -05:00
Thomas Harte b2b7aa221b Merge pull request #1629 from TomHarte/6502SecondAnalyser
Automatically add a 65c02 second processor if seemingly helpful.
2025-11-05 20:51:44 -05:00
Thomas Harte b98a9a8487 Add automatic test for 6502 second processor. 2025-11-05 20:40:29 -05:00
Thomas Harte 7f36a8a746 Merge pull request #1628 from TomHarte/TubeResetLater
Give Tube ULA full ownership of parasite IRQ/NMI/reset.
2025-11-05 15:41:50 -05:00
Thomas Harte 2fe6e9c7fc Reformulate to give ULA full IRQ/NMI/reset signalling duties. 2025-11-05 15:27:11 -05:00
Thomas Harte 62919e77d4 Reset at end. 2025-11-05 15:11:49 -05:00
Thomas Harte 871b724290 Merge pull request #1627 from TomHarte/TubeReset
Propagate system reset to the tube.
2025-11-04 23:24:20 -05:00
Thomas Harte ca23c04ba1 Propagate system reset to the tube. 2025-11-04 23:18:18 -05:00
Thomas Harte 44b8f75611 Merge pull request #1626 from TomHarte/TubeSelection
Detect CP/M discs and route to the Z80 second processor.
2025-11-04 23:11:31 -05:00
Thomas Harte 301df785fe Fix weird Os for 0s substitution. 2025-11-04 23:11:06 -05:00
Thomas Harte 9657109471 Correct comment. 2025-11-04 23:10:14 -05:00
Thomas Harte 139569e291 Detect CP/M discs and route to the Z80 second processor. 2025-11-04 22:46:15 -05:00
Thomas Harte 1383c1dad4 Merge pull request #1625 from TomHarte/TubeZ80
Add Z80 second processor.
2025-11-04 22:35:26 -05:00
Thomas Harte 1d2cdd85a3 Explain size limit. 2025-11-04 22:27:05 -05:00
Thomas Harte 76082b1271 Allow DSD discs to be twice as large. 2025-11-04 22:20:06 -05:00
Thomas Harte 25dcbf918d Ensure Z80 interrupts end. 2025-11-04 22:04:41 -05:00
Thomas Harte 6c72c1842b Change interrupt vector. 2025-11-04 21:57:20 -05:00
Thomas Harte 4e4388dc35 Adjust reset logic, 6502 tube paging. 2025-11-04 21:34:45 -05:00
Thomas Harte 54bff80ecc Fix: it's the PC going above 0x8000 that ends ROM visibility. 2025-11-04 18:21:00 -05:00
Thomas Harte 78073aaa11 Add Z80 tube ROM. 2025-11-04 17:45:27 -05:00
Thomas Harte 4df01a7e0d Ensure Z80 processes. 2025-11-04 17:38:46 -05:00
Thomas Harte f4d15d0640 Mostly wire in a Z80 second processor. 2025-11-04 17:36:30 -05:00
Thomas Harte 64842d4de2 Merge pull request #1621 from TomHarte/Tube
Introduce experimental 6502 tube processor support.
2025-11-04 13:53:35 -05:00
Thomas Harte f52315ac92 Further annotate. 2025-11-04 12:48:49 -05:00
Thomas Harte cc88877109 Move tube holder out of line. 2025-11-04 12:46:15 -05:00
Thomas Harte d7568e57c3 Make other layout edits. 2025-11-04 09:27:04 -05:00
Thomas Harte d49b301fca Improve commentary. 2025-11-04 09:22:17 -05:00
Thomas Harte 0113bcbea7 Include tube storage only when needed. 2025-11-04 09:20:28 -05:00
Thomas Harte 0332bb4f12 Merge pull request #1624 from TomHarte/ArchimedesVideoTiming
Pull clock divider inside the loop.
2025-11-03 21:32:11 -05:00
Thomas Harte 82a5d5116a Expose processor option to macOS users, too. 2025-11-03 21:31:44 -05:00
Thomas Harte 62a6797ef3 The second processor appears to be a 65c02. 2025-11-03 21:06:34 -05:00
Thomas Harte bb66033682 Fix interrupting inward FIFO. 2025-11-03 21:02:14 -05:00
Thomas Harte d4aa0799a9 Take a swing at reset. 2025-11-03 20:50:47 -05:00
Thomas Harte fba2d37714 Correct flags, out-of-bounds writes. 2025-11-03 20:32:08 -05:00
Thomas Harte e891697f88 Attempt full wiring. 2025-11-03 20:19:31 -05:00
Thomas Harte ee6ac3b4a9 Restore build. 2025-11-03 17:47:22 -05:00
Thomas Harte c8130f9d6f Begin FIFO wiring. 2025-11-03 17:27:48 -05:00
Thomas Harte 8abd837c8b Ths host is now possibly awaiting tube activity. 2025-11-03 13:33:26 -05:00
Thomas Harte 02ad080bb8 Apply clock multiplier. 2025-11-03 13:20:51 -05:00
Thomas Harte 5887e3e580 Provide ROM to second processor. 2025-11-03 13:17:35 -05:00
Thomas Harte 1994b2dc9f Pay for a second processor, even if disconnected. 2025-11-03 13:12:19 -05:00
Thomas Harte d7a82d00b1 Pull clock divider inside the loop. 2025-11-03 12:49:53 -05:00
Thomas Harte 0017bd6d0f Pull clock divider inside the loop. 2025-11-03 12:49:30 -05:00
Thomas Harte 15f30995b1 Promote tube processor to template parameter. 2025-11-03 09:26:31 -05:00
Thomas Harte 37ca0e4f81 Introduce one-directional FIFO. 2025-11-02 23:18:56 -05:00
Thomas Harte e400aa200c Slightly clean-up spacing. 2025-11-02 23:18:56 -05:00
Thomas Harte e168298aa0 Add Tube boot ROM. 2025-11-02 23:18:56 -05:00
Thomas Harte c4afbf8f2e Recast middle button as tertiary. 2025-11-02 23:12:38 -05:00
Thomas Harte 112aff9887 SDL: change mouse button indices. 2025-11-02 23:12:38 -05:00
Thomas Harte a8207ded4f Regularise mouse-event clock. 2025-11-02 23:12:38 -05:00
Thomas Harte bafef023a5 Remove danglng misuses of previous_posted_rect_. 2025-10-31 19:36:18 -04:00
Thomas Harte 9b39eebc2d Attempt to keep dynamic framing going permanently, for smooth transitions. 2025-10-31 15:58:09 -04:00
Thomas Harte 02fdcd6ece Merge pull request #1619 from TomHarte/OptionalFullFrame
Make dynamic cropping optional for the Amstrad CPC and BBC Micro.
2025-10-30 20:46:03 -04:00
Thomas Harte 49601e0a78 Introduce dynamic crop option to the BBC. 2025-10-30 09:09:53 -04:00
Thomas Harte cf10abff5b Attempt to smooth framing transitions. 2025-10-29 21:47:05 -04:00
Thomas Harte e75c27cb66 Add macOS UI to dynamic cropping option, apply at runtime to CPC. 2025-10-29 21:21:21 -04:00
Thomas Harte d27f0e3633 Declare that dynamic crop is an option. 2025-10-29 17:43:19 -04:00
Thomas Harte e19bd0d517 Alphabetise; mark override. 2025-10-29 17:43:05 -04:00
Thomas Harte 3427120b3f Expose dynamic crop option from the CPC. 2025-10-29 17:37:58 -04:00
Thomas Harte ecc623cd6c Improve option naming, add one for dynamic crop. 2025-10-29 17:19:15 -04:00
Thomas Harte 3ef615f508 Merge pull request #1618 from TomHarte/FurtherWarnings
Localise shorthand `Storage`; note that labels may be unused.
2025-10-29 12:39:50 -04:00
Thomas Harte 1c4c3a6cae Avoid VLA extension. 2025-10-29 12:29:15 -04:00
Thomas Harte fd7142f6a1 Comment out unused storage. 2025-10-29 12:28:09 -04:00
Thomas Harte b30fda3c36 Localise shorthand Storage; note that labels may be unused. 2025-10-29 12:19:25 -04:00
Thomas Harte 7e43b40415 Merge pull request #1617 from TomHarte/NoWarnings
Resolve x86-related build warnings plus various whitespace deficiencies.
2025-10-29 12:16:53 -04:00
Thomas Harte 53501a9443 Merge pull request #1616 from TomHarte/BBCNew6502
Adapt the BBC Micro to use the new 6502.
2025-10-29 12:16:16 -04:00
Thomas Harte c5dc65fc61 Resolve various whitespace errors. 2025-10-29 11:50:56 -04:00
Thomas Harte b389889e1f Limit sizes to pointer size. 2025-10-29 09:19:04 -04:00
Thomas Harte 02a29056b7 Resolve IP size imbalance. 2025-10-29 09:16:30 -04:00
Thomas Harte 5e789b4b0c Grab last PC operation address; ensure power-on reset is predictable. 2025-10-29 09:03:35 -04:00
Thomas Harte 9ff09a45be Allow is-1mhz decision to observe shortened addresses. 2025-10-28 21:32:09 -04:00
Thomas Harte fc02a3d34b Merge branch 'master' into BBCNew6502 2025-10-28 21:22:30 -04:00
Thomas Harte 48f983c040 Merge pull request #1613 from TomHarte/Turbo6502
Introduce alternative 6502 implementation.
2025-10-28 21:21:47 -04:00
Thomas Harte dd25d387fe Allow for __COUNTER__ potentially not starting at 0. 2025-10-28 21:07:03 -04:00
Thomas Harte 80a503f317 Adjust formatting. 2025-10-28 20:54:05 -04:00
Thomas Harte 5aa9168dd6 Make overflow private. 2025-10-28 20:49:59 -04:00
Thomas Harte b3f01fe314 Move carry into private storage. 2025-10-28 20:43:57 -04:00
Thomas Harte e688d87c22 Move negative and zero into private storage. 2025-10-28 18:23:16 -04:00
Thomas Harte 332fb2f384 Make decimal flag private. 2025-10-28 17:34:31 -04:00
Thomas Harte 5332bcd6b4 Clarify set/get difference; make interrupt flag storage private. 2025-10-28 17:32:10 -04:00
Thomas Harte 55c59e6164 Start hiding Flags implementation. 2025-10-28 17:24:53 -04:00
Thomas Harte 80bfa1859f Merge branch 'Turbo6502' into BBCNew6502 2025-10-27 22:22:11 -04:00
Thomas Harte 58e1880773 Eliminate 'addr' side effects. 2025-10-27 22:14:48 -04:00
Thomas Harte c8c4c99f09 Incorporate IRQ timing test; accept that it must be tested within the access macro. 2025-10-27 21:32:52 -04:00
Thomas Harte 350f424055 Merge branch 'Turbo6502' into BBCNew6502 2025-10-27 17:27:04 -04:00
Thomas Harte bc5b7a6725 Unpublish WriteableReader. 2025-10-27 17:01:29 -04:00
Thomas Harte 7b4e71e6dd Just use the preprocessor then. Yuck. 2025-10-27 13:10:24 -04:00
Thomas Harte a32202ab72 Be more overt in trying to avoid "use of undeclared identifier". 2025-10-27 12:52:57 -04:00
Thomas Harte 193c027c8b To simplify debugging, add non-constructing path.
This won't have any effect on generated code.
2025-10-27 12:42:00 -04:00
Thomas Harte 3dd07b6ac1 To simplify debugging, add non-constructing path.
This won't have any effect on generated code.
2025-10-27 12:41:17 -04:00
Thomas Harte 12d912b627 Add insurance against bus handler not writing. 2025-10-27 12:37:38 -04:00
Thomas Harte f847a72696 Add insurance against bus handler not writing. 2025-10-27 12:37:14 -04:00
Thomas Harte 967c3f6dba Ensure NMI isn't perpetual. 2025-10-26 21:56:35 -04:00
Thomas Harte 6cf87e3aa9 Ensure reads always achieve something. 2025-10-26 21:56:13 -04:00
Thomas Harte cbc6477431 Ensure NMI isn't perpetual. 2025-10-26 21:55:09 -04:00
Thomas Harte 45d0f101a7 Switch the BBC Micro to 6502Mk2. 2025-10-26 21:04:59 -04:00
Thomas Harte cba96aee37 Honour interrupt flag. 2025-10-25 17:02:48 -04:00
Thomas Harte 17325834b5 Implement is_resetting. 2025-10-25 17:02:27 -04:00
Thomas Harte 3673144a44 Enable all tests. 2025-10-25 09:00:55 -04:00
Thomas Harte 4df49d9f18 Round out interrupt signalling. 2025-10-25 08:54:25 -04:00
Thomas Harte 8b04608d68 Implement STP and WAI. 2025-10-24 23:47:30 -04:00
Thomas Harte 2bac276870 Populate type_of. 2025-10-24 23:42:40 -04:00
Thomas Harte 213f9850e7 Add WDC65C02 decoder. 2025-10-24 23:41:55 -04:00
Thomas Harte 378bffbf84 Implement BBR/BBS. 2025-10-24 23:37:18 -04:00
Thomas Harte c291d5313d Fix PLX. 2025-10-24 22:22:05 -04:00
Thomas Harte 1f6f665639 Exclude all 65c02 NOPs from timing checks. 2025-10-24 22:19:15 -04:00
Thomas Harte e81233c586 Implement JMP (abs,x). 2025-10-24 22:16:36 -04:00
Thomas Harte b946029394 Correct 65c02 JMPAbsoluteIndirect. 2025-10-24 21:57:53 -04:00
Thomas Harte 6095936354 Exclude tests I believe faulty. 2025-10-24 21:54:23 -04:00
Thomas Harte fe79a1231d Add extra cycle to immediate decimal arithmetic. 2025-10-24 21:39:14 -04:00
Thomas Harte 76a5872d17 Install extra cycle for 65c02 decimal arithmetic. 2025-10-24 21:24:05 -04:00
Thomas Harte 0d72c75e15 Give modify stalls to fast NOPs. 2025-10-24 16:51:07 -04:00
Thomas Harte 2e0e89c494 Implement fast modify path; fix more NOPs. 2025-10-24 16:43:57 -04:00
Thomas Harte 7d6b7a5874 Adjust 0x?b NOPs. 2025-10-24 15:57:54 -04:00
Thomas Harte 48f8ddf53a 65c02: make AbsoluteIndexed modify cycle harmless. 2025-10-24 15:55:45 -04:00
Thomas Harte 9aae07b737 Implement zero indirect addressing mode. 2025-10-24 15:53:55 -04:00
Thomas Harte d7abdc8017 Transfer ownership of final PC increment, to accomodate 65c02 misreads. 2025-10-24 15:49:17 -04:00
Thomas Harte cb81156835 65c02: distinguish 'fast' NOPs from regular. 2025-10-24 13:52:32 -04:00
Thomas Harte 1fd8d94e2e Import further NOPs. 2025-10-24 13:33:10 -04:00
Thomas Harte e4fe127444 Fix 65c02 modify cycles: read/read/write, not read/write/write. 2025-10-24 13:30:10 -04:00
Thomas Harte aeabd5f113 Patch in TSB and TRB. 2025-10-24 12:33:13 -04:00
Thomas Harte 58f7d4065c 65c02: support single-cycle NOP. 2025-10-24 12:29:53 -04:00
Thomas Harte 60f25a3ba4 Add some of the easier overrides. 2025-10-24 12:21:53 -04:00
Thomas Harte d267571dc6 Add spot to fill in Synertek mappings. 2025-10-24 12:13:10 -04:00
Thomas Harte 3c34aa6696 Setup to test 65c02s. 2025-10-24 12:07:40 -04:00
Thomas Harte 5dc00a2092 Update #undef list. 2025-10-24 12:00:22 -04:00
Thomas Harte b20d489bf0 Remove SHA/SHX/etc. 2025-10-24 11:58:55 -04:00
Thomas Harte df39870587 Factor out index decision. 2025-10-24 11:53:55 -04:00
Thomas Harte f742eab4be Reduce to a generic case. 2025-10-23 21:54:50 -04:00
Thomas Harte e9c8c61dcf Reformulate to be slightly more conditional, but substantially deduplicate code. 2025-10-23 21:52:31 -04:00
Thomas Harte e5f09002e9 Extract bit operators. 2025-10-23 20:47:55 -04:00
Thomas Harte d42f005e17 Improve consistency. 2025-10-23 20:43:15 -04:00
Thomas Harte 24e060abee Elide ADC logic. 2025-10-23 19:54:07 -04:00
Thomas Harte 8b6d763442 Reduce duplication within ARR. 2025-10-23 19:42:36 -04:00
Thomas Harte e239745f63 Fix typo. 2025-10-23 19:35:40 -04:00
Thomas Harte cfef2b4e19 Eliminate 16-bit arithmetic from SBX. 2025-10-23 19:32:50 -04:00
Thomas Harte cf93c39881 Pull out overflow logic, remove 16-bit arithmetic from ADC. 2025-10-23 18:23:09 -04:00
Thomas Harte 5d223bce4c Pull out and simplify compare. 2025-10-23 17:47:15 -04:00
Thomas Harte b454ebc1c9 Extricate further operations. 2025-10-23 17:41:13 -04:00
Thomas Harte 7cf9910cae Pull ADC, SBC and some others out.
This resolves the wacky control flow somewhat.
2025-10-23 17:15:21 -04:00
Thomas Harte 79ab1d8cb1 Implement final SHA. 2025-10-23 13:42:23 -04:00
Thomas Harte 7cd20f5d12 Add all absolute-indexed oddities. 2025-10-23 13:39:03 -04:00
Thomas Harte 5396d751e1 Support SHX and a SHA. 2025-10-23 13:27:55 -04:00
Thomas Harte d23e715650 Decision: these five have weird addressing, so that counts as weird addressing modes. 2025-10-23 13:13:01 -04:00
Thomas Harte 0791bce338 Fix everything other than the oddball SHA/SHX/SHY/SHS. 2025-10-22 22:12:32 -04:00
Thomas Harte 2bcb74072a Add trqnsfers, correct a STA. 2025-10-22 21:20:11 -04:00
Thomas Harte c5f2f17f33 Further populate perform.
First failing test is now 0x8a.
2025-10-22 21:13:57 -04:00
Thomas Harte 62a8bf4261 Add missing RTS cycle. 2025-10-22 17:56:11 -04:00
Thomas Harte ebda18b44e Implement the two JMPs. 2025-10-22 17:52:55 -04:00
Thomas Harte a8f41b9017 Implement RTI and RTS. 2025-10-22 17:48:19 -04:00
Thomas Harte 410c19a7da Fix pull. 2025-10-22 17:43:08 -04:00
Thomas Harte a346e2e04b Transcribe bit logic. 2025-10-22 17:40:03 -04:00
Thomas Harte 2d114b6677 Implement JSR. 2025-10-22 17:37:01 -04:00
Thomas Harte 02e74ca1f4 Add absolute-indexed addressing. 2025-10-22 17:18:54 -04:00
Thomas Harte 69122cdec4 Swing at zero-indexed addressing. 2025-10-22 17:12:23 -04:00
Thomas Harte d730168631 Remove dead label. 2025-10-22 13:30:24 -04:00
Thomas Harte 2f210ebe3b Fix IndexedIndirect/IndirectIndexed confusion, proceed to test 0x14. 2025-10-22 13:29:45 -04:00
Thomas Harte 693b53baa2 Proceed through absolute addressing to test 0x10. 2025-10-22 13:05:46 -04:00
Thomas Harte 77554879a5 Add missing 0x?e group. 2025-10-22 13:00:36 -04:00
Thomas Harte 45363922b5 Adds rolls and shifts, and zero-page addressing. 2025-10-22 12:56:07 -04:00
Thomas Harte 0463c1ceda Reduce repetition. 2025-10-21 23:21:11 -04:00
Thomas Harte b35a55a658 Implement jamming. 2025-10-21 23:16:59 -04:00
Thomas Harte 4da68c9fa8 Implement IndirectIndexedRead. 2025-10-21 23:01:41 -04:00
Thomas Harte 72f133f31b Do enough work to verify BRK. 2025-10-21 22:07:35 -04:00
Thomas Harte af4a8f6d9c Add enough to attempt to run processor tests. 2025-10-21 21:30:42 -04:00
Thomas Harte b5899a2e42 Implement simplest operations. 2025-10-21 17:33:36 -04:00
Thomas Harte 4ee8f8564e Catch unimplemented. 2025-10-21 13:40:23 -04:00
Thomas Harte ff08c03bc5 Coral into building. 2025-10-21 13:31:48 -04:00
Thomas Harte 95dd430b0d Shoehorn in an invocation. 2025-10-21 13:12:58 -04:00
Thomas Harte 20eb8b1442 Move RDY inline. 2025-10-21 12:59:16 -04:00
Thomas Harte 2d6a0b3ed0 Add a branch to nowhere. 2025-10-20 23:08:04 -04:00
Thomas Harte 80f0ce78e0 Eliminate unused enum. 2025-10-20 22:51:12 -04:00
Thomas Harte fde0e2434e Attempt to transcribe base 6502 instruction set. 2025-10-20 22:50:14 -04:00
Thomas Harte fe2da7fd95 Merge branch 'master' into Turbo6502 2025-10-20 13:56:58 -04:00
Thomas Harte 25e783ff2f Merge pull request #1614 from TomHarte/6845Reading
Return 0 for write-only and nonexistent registers.
2025-10-20 13:56:27 -04:00
Thomas Harte 2eb94f1b66 Return 0 for write-only and nonexistent registers. 2025-10-20 13:26:22 -04:00
Thomas Harte 2cdf6ac8f9 Add interrupt, RDY and instruction fetch logic. 2025-10-20 13:16:03 -04:00
Thomas Harte 309c58a93d Include in CI builds; start implementation. 2025-10-19 23:29:27 -04:00
Thomas Harte 700bd0ddd4 Merge branch 'master' into Turbo6502 2025-10-19 22:21:19 -04:00
Thomas Harte bd5a2f240d Record version number. 2025-10-19 19:51:06 -04:00
Thomas Harte 73054d971c Merge pull request #1612 from TomHarte/NoCounter
Eliminate CompileTimeCounter.
2025-10-19 19:45:52 -04:00
Thomas Harte 8c7f2491d7 Eliminate CompileTimeCounter. 2025-10-19 19:36:36 -04:00
Thomas Harte 24fcbea6f2 Add TODO. 2025-10-19 19:28:38 -04:00
Thomas Harte fddc9c8c48 Add base classes, reshuffle. 2025-10-18 22:45:09 -04:00
Thomas Harte 294893b7da Start transferring 6502 precepts. 2025-10-18 22:31:00 -04:00
Thomas Harte 564542420b Merge pull request #1609 from TomHarte/BBCAdvancedDiscToolkit
BBC Micro: add ADT ROM if available.
2025-10-18 21:03:07 -04:00
Thomas Harte 3f7e3e6d75 Use the ADT ROM if available. 2025-10-18 09:33:55 -04:00
Thomas Harte 6521d7d02b Add ADT 1.40 to ROM catalogue. 2025-10-18 09:15:17 -04:00
Thomas Harte ad162a4e4a Merge pull request #1607 from TomHarte/MacAudio
Correct Mac audio buffering
2025-10-17 21:58:57 -04:00
Thomas Harte 676b1f6fdc Adopt brackets, as is now a macro. 2025-10-17 21:38:12 -04:00
Thomas Harte 406ef4e16c Record new version number. 2025-10-17 21:00:11 -04:00
Thomas Harte 217976350b Merge pull request #1606 from TomHarte/CPCAnalyser
Improve file-selection logic.
2025-10-17 18:38:33 -04:00
Thomas Harte e8f860d6fe Improve file-selection logic. 2025-10-17 18:25:44 -04:00
Thomas Harte 859e6e2396 Merge pull request #1605 from TomHarte/CompiletimeCounter
Add compile-time counter; switch 1770 to using it for sequence points.
2025-10-17 17:44:13 -04:00
Thomas Harte 51186e615f Add warning. 2025-10-17 16:10:23 -04:00
Thomas Harte bd8287fda3 Resolve obstructive warning. 2025-10-17 15:21:47 -04:00
Thomas Harte 287ff99bbc Use Numeric::Counter. 2025-10-17 15:06:05 -04:00
Thomas Harte 0bbfcedabb Alphabetise includes. 2025-10-17 15:05:52 -04:00
Thomas Harte 812e1e637d Eliminate magic constant. 2025-10-17 11:22:02 -04:00
Thomas Harte f20fd38940 Introduce a compile-time counter; use it for 1770 sequencing. 2025-10-17 11:19:21 -04:00
Thomas Harte b4cfabc005 Merge pull request #1604 from TomHarte/CPCBrightness
Apply outputMultiplier in direct RGB output.
2025-10-16 23:42:43 -04:00
Thomas Harte c49e160501 Apply outputMultiplier in direct RGB output. 2025-10-16 22:44:40 -04:00
Thomas Harte a0a24902d5 Merge pull request #1603 from TomHarte/JoystickDirection
Provide joystick up/down as down = positive again.
2025-10-16 21:58:22 -04:00
Thomas Harte 1047bc8a80 Provide up/down in down = positive again. 2025-10-16 21:30:49 -04:00
Thomas Harte 0eed49c4cb Merge pull request #1599 from TomHarte/AutoClip
Automatically select and zoom to 'interesting' content.
2025-10-16 21:04:23 -04:00
Thomas Harte e7f09e2ece Fix first reading. 2025-10-16 20:51:39 -04:00
Thomas Harte 89678f1ea7 Tweak decision process, add maximum scale parameter. 2025-10-16 16:26:16 -04:00
Thomas Harte e43ec7d549 Correct bias to the left. 2025-10-16 11:50:32 -04:00
Thomas Harte 95395132f0 Make stability threshold modal. 2025-10-16 11:29:41 -04:00
Thomas Harte 89293d8481 Add stability as a prefilter. 2025-10-16 11:26:07 -04:00
Thomas Harte e6de24557f Set appropriate BBC bounds. 2025-10-15 23:39:55 -04:00
Thomas Harte 66d76dc36a Adjust dynamic semantics again. 2025-10-15 23:30:25 -04:00
Thomas Harte 06629def62 Restore some fixed areas, work on API. 2025-10-14 22:51:36 -04:00
Thomas Harte 97aeb5e930 Merge branch 'AutoClip' of github.com:TomHarte/CLK into AutoClip 2025-10-14 22:23:12 -04:00
Thomas Harte bf45b6e20b Merge branch 'master' into AutoClip 2025-10-14 22:23:06 -04:00
Thomas Harte 6ad41326b0 Remove errant space. 2025-10-13 23:13:45 -04:00
Thomas Harte 2bbca3c169 Slightly beef up 8272 logging. 2025-10-13 23:09:10 -04:00
Thomas Harte ae903b0712 Increase consts. 2025-10-13 22:53:52 -04:00
Thomas Harte a2a7f82716 Merge branch 'master' into AutoClip 2025-10-13 22:51:21 -04:00
Thomas Harte 00456c891a Merge pull request #1601 from TomHarte/EvenShorterText
Even shorter text
2025-10-13 22:50:53 -04:00
Thomas Harte afd5faaab1 Tweak constraints again. 2025-10-13 13:29:31 -04:00
Thomas Harte bb33cf0f8d Shorten text even further. 2025-10-13 13:26:49 -04:00
Thomas Harte edc510572a Reorder constraints. 2025-10-13 10:55:23 -04:00
Thomas Harte bc6cffa95c Enable full dynamic selection again for the CPC. 2025-10-13 08:54:33 -04:00
Thomas Harte 48ed2912b0 Reenable dynamic framing. 2025-10-12 22:30:37 -04:00
Thomas Harte a8af262c41 Avoid shadowing, use normal instance suffix. 2025-10-12 21:41:22 -04:00
Thomas Harte dcf49933bc Merge branch 'master' into AutoClip 2025-10-12 21:32:22 -04:00
Thomas Harte 9c014001da Merge pull request #1600 from TomHarte/ShorterOpenDialogue
macOS: shorten prompt to File -> Open...
2025-10-12 21:27:07 -04:00
Thomas Harte 4f410088dd Improve constraints. 2025-10-12 21:17:07 -04:00
Thomas Harte e1c1b66dc5 Shorten footer text. 2025-10-12 20:55:29 -04:00
Thomas Harte 23c3a1fa99 Lean further overtly towards a state machine. 2025-10-12 08:59:07 -04:00
Thomas Harte ef6e1b2f74 Unpublish enum, simplify function names. 2025-10-11 15:07:09 -04:00
Thomas Harte e130ae0a8a Merge branch 'AutoClip' of github.com:TomHarte/CLK into AutoClip 2025-10-10 22:27:47 -04:00
Thomas Harte 1a1e3281e4 Avoid overlong line; add consts. 2025-10-10 22:27:29 -04:00
Thomas Harte a4e55c9362 Avoid overlong line. 2025-10-10 22:25:16 -04:00
Thomas Harte 0b4c51eebd Scale interesting rects once only. 2025-10-10 22:23:22 -04:00
Thomas Harte 1107f0d9a3 For relevant machines: pick different amounts of border to show. 2025-10-10 21:58:03 -04:00
Thomas Harte 775819432b Apply warm-up for the Apple II and ZX Spectrum. 2025-10-10 21:37:31 -04:00
Thomas Harte a71a60937f Prewarm Macintosh; mark RAM as const. 2025-10-10 18:02:46 -04:00
Thomas Harte 5e661fe96b Add prewarming to the Oric. 2025-10-10 18:00:54 -04:00
Thomas Harte a9f5b17fcb Eliminate frame_is_complete_, add prewalming loop. 2025-10-10 17:59:10 -04:00
Thomas Harte b0c2b55fc9 Fix initial bounds, slightly update breathing space. 2025-10-10 15:44:54 -04:00
Thomas Harte 925832aac5 Include tolerance for interlacing. 2025-10-10 14:29:40 -04:00
Thomas Harte 994131e2ea Use stability as test for initial frame. 2025-10-10 14:18:25 -04:00
Thomas Harte f8d27d0ae0 Remove explicit visible area declarations. 2025-10-09 22:17:02 -04:00
Thomas Harte fc50af0e17 Adjust vertical sync test. 2025-10-09 22:16:43 -04:00
Thomas Harte 087d3535f6 Start focussing on getting a good crop for 'static' machines. 2025-10-09 18:01:46 -04:00
Thomas Harte e9d310962f Support an asymmetric 90%. 2025-10-09 14:01:52 -04:00
Thomas Harte 0f9c89d259 Limit to 90%. 2025-10-09 13:59:03 -04:00
Thomas Harte 258c37685b Fix axis. 2025-10-09 13:53:35 -04:00
Thomas Harte 56f092a0c3 Try a rolling average of 250 frames, subject to thresholding. 2025-10-09 13:51:19 -04:00
Thomas Harte 6c3048ffbf Relax flywheel response rate again. 2025-10-08 22:12:58 -04:00
Thomas Harte c58eba61de Extend required stability window. 2025-10-08 22:00:32 -04:00
Thomas Harte 8a54773f1b Reduce Metal buffer thrashing. 2025-10-08 21:19:31 -04:00
Thomas Harte 2c483e7b97 Avoid nullptr dereference if there is no activity observer. 2025-10-08 17:42:57 -04:00
Thomas Harte 1027e9ffdc Add but abandon first attempt at sane limits. 2025-10-08 17:34:54 -04:00
Thomas Harte 85d6957e03 Attempt to do better at startup. 2025-10-08 14:33:49 -04:00
Thomas Harte c3609b66a9 Attempt a quick snap at startup. 2025-10-08 14:13:34 -04:00
Thomas Harte 605f4a92d7 Use animation curve, try to be fooled less at startup. 2025-10-08 12:58:12 -04:00
Thomas Harte d395e2bc75 Introduce animated crop. 2025-10-08 12:18:04 -04:00
Thomas Harte e6ccdc5a97 Edge towards animations. 2025-10-07 23:00:36 -04:00
Thomas Harte a68c7aa45f Use filter, attempt to be intelligent about the border. 2025-10-07 22:56:51 -04:00
Thomas Harte 66e959ab65 Temporarily exclude borders. 2025-10-07 22:42:26 -04:00
Thomas Harte d68b172a40 Introduce preliminary output frame filtering. 2025-10-07 22:36:36 -04:00
Thomas Harte d3ee778265 Eliminate common black border -> blank mapping.
Will move this inside the CRT.
2025-10-07 22:10:14 -04:00
Thomas Harte da96df7df7 Ensure OpenGL appropriately letterboxes or pillarboxes. 2025-10-07 21:37:22 -04:00
Thomas Harte 4ea82581ec Factor out zoom logic, start trying to knock OpenGL into shape. 2025-10-07 13:29:21 -04:00
Thomas Harte 4473d3400e Reformat slightly. 2025-10-07 12:52:55 -04:00
Thomas Harte 2f1f843e48 Correct origin.y minification. 2025-10-07 12:44:03 -04:00
Thomas Harte 53a3d9042e Switch to multiline strings, shorter comments. 2025-10-06 22:58:50 -04:00
Thomas Harte 6eb32f98b2 Fix rectangle union. 2025-10-06 22:50:29 -04:00
Thomas Harte 0fad97ed48 Apply different axis scales. 2025-10-06 22:36:19 -04:00
Thomas Harte 27246247a2 OpenGL: fix centring. 2025-10-06 20:58:42 -04:00
Thomas Harte cbc96e2223 Reformat in proximity. 2025-10-06 20:45:20 -04:00
Thomas Harte 8fdf32cde8 Avoid OpenGL churn. 2025-10-06 20:43:12 -04:00
Thomas Harte 03a94e59e2 Merge branch 'master' into AutoClip 2025-10-06 20:29:08 -04:00
Thomas Harte 2c0610fef8 Accumulate union of all pixel-bearing scans. 2025-10-06 20:26:15 -04:00
Thomas Harte 60b3c51085 Merge pull request #1598 from TomHarte/DynamicViewArea
Begin move towards automatic cropping.
2025-10-06 19:07:20 -04:00
Thomas Harte d7b5a45417 Adopt even more aggressive mixing, avoid negative. 2025-10-06 16:20:54 -04:00
Thomas Harte e11060bde8 Further improve asserting. 2025-10-06 16:16:06 -04:00
Thomas Harte 4653de9161 Pull out and comment on mix, improve asserts. 2025-10-06 16:11:59 -04:00
Thomas Harte 1926ad9215 Normalise and slightly reformat flywheel interface. 2025-10-06 14:53:08 -04:00
Thomas Harte 33d047c703 Add a const. 2025-10-06 14:38:40 -04:00
Thomas Harte fadda00246 Eliminate flywheel 'get's, hence normalise CRT line lengths. 2025-10-06 14:36:39 -04:00
Thomas Harte a3fed788d8 Reduce repetition. 2025-10-06 14:27:57 -04:00
Thomas Harte dde31e8687 Reformat inner loop. 2025-10-06 14:26:03 -04:00
Thomas Harte 190fb009bc Clean up CRT.hpp for formatting. Switch pointer to reference. 2025-10-06 13:55:03 -04:00
Thomas Harte 62574d04c6 Avoid some redundant parameter names. 2025-10-06 13:32:28 -04:00
Thomas Harte 2496257bcf Adopt normative public-then-private ordering. 2025-10-06 13:28:04 -04:00
Thomas Harte ab73b4de6b Split off the mismatch warner. 2025-10-06 13:27:10 -04:00
Thomas Harte 6c1c32baca Move flywheels local. 2025-10-04 22:42:56 -04:00
Thomas Harte 239cc15c8f Introduce cubic timing function. 2025-10-04 22:26:09 -04:00
Thomas Harte 6b437c3907 Merge pull request #1597 from TomHarte/NewShaker
Ensure CPCShakerTests is runnable.
2025-10-03 22:33:52 -04:00
Thomas Harte 4756f63169 Ensure CPCShakerTests is runnable. 2025-10-03 22:25:16 -04:00
Thomas Harte 7229acb34f Merge pull request #1596 from TomHarte/FaultyLineLength
Correct collation test, to ensure no accidental buffer mixing.
2025-10-03 18:06:34 -04:00
Thomas Harte 43cb91760a Update SAA5050 row counter only in teletext mode. 2025-10-03 18:05:36 -04:00
Thomas Harte 7bb4d052d1 Correct collation test, to ensure no accidental buffer mixing. 2025-10-03 17:29:45 -04:00
Thomas Harte 5885bdf0f8 Merge pull request #1595 from TomHarte/BBCSaving
Ensure 1770 doesn't get stuck when writing.
2025-10-03 16:51:24 -04:00
Thomas Harte 05042b1859 Remove unnecessary log. 2025-10-03 16:42:04 -04:00
Thomas Harte 3ca2f72184 Merge pull request #1594 from TomHarte/CompoundingTyper
Simplify typer logic.
2025-10-03 16:41:43 -04:00
Thomas Harte b076450b73 Ensure 1770 doesn't get stuck when writing. 2025-10-03 16:39:27 -04:00
Thomas Harte 7a90662c06 Merge branch 'master' into CompoundingTyper 2025-10-03 16:06:47 -04:00
Thomas Harte eb31aaeb7d Merge pull request #1593 from TomHarte/FakeLightpen
Support CB2 output strobe as triggering lightpen capture.
2025-10-03 16:05:11 -04:00
Thomas Harte ebfb215246 Support CB2 output strobe as triggering lightpen capture. 2025-10-03 15:39:16 -04:00
Thomas Harte eb97e4e518 Reserve entire FF page; simplify logic. 2025-10-03 13:10:45 -04:00
Thomas Harte 61d3e65c05 Merge pull request #1591 from TomHarte/BetterTyper
BBC typer: properly support lowercase input.
2025-10-03 12:27:32 -04:00
Thomas Harte 0ac5681d13 Confirmed: 'capslock' has yet to become a single word. 2025-10-03 11:37:39 -04:00
Thomas Harte 1e27c5759b Add missing const. 2025-10-03 09:26:53 -04:00
Thomas Harte 5e71aedc99 Support lowercase typing into the BBC. 2025-10-03 09:25:58 -04:00
Thomas Harte d0d8c2316b Bump version number. 2025-10-02 22:55:50 -04:00
Thomas Harte 8f0a5b2191 Merge pull request #1589 from TomHarte/6522PB7
Expose PB7 timer regardless.
2025-10-02 22:48:31 -04:00
Thomas Harte 242b180862 Expose PB7 timer regardless. 2025-10-02 22:40:36 -04:00
Thomas Harte feb4766d7b Merge pull request #1587 from TomHarte/BetterAnalogue
Improve mapping of digital inputs to analogue joysticks.
2025-10-02 21:22:21 -04:00
Thomas Harte a224eea077 Merge pull request #1586 from TomHarte/SAA5050Split
Make centre row the thick one.
2025-10-02 20:59:55 -04:00
Thomas Harte ecefbc23ae Resolve ability of analogue joysticks to get stuck with digital input. 2025-10-02 20:52:16 -04:00
Thomas Harte e5e0cbfc53 Make centre row the thick one. 2025-10-02 20:35:53 -04:00
Thomas Harte 38781c9395 Merge pull request #1585 from TomHarte/BBCJoystick
Add BBC joysticks.
2025-10-02 20:21:31 -04:00
Thomas Harte e70d72b614 Merge pull request #1584 from TomHarte/CursorMask
Variously tweak and improve BBC graphics infrastructure.
2025-10-02 17:44:10 -04:00
Thomas Harte fcf648bbb2 Flip axes, maximise range. 2025-10-02 17:43:33 -04:00
Thomas Harte a8325b6bce Add BBC joysticks. 2025-10-02 17:10:27 -04:00
Thomas Harte 22554a9ba4 Incorporate a one-column delay into CPC output. 2025-10-02 15:22:01 -04:00
Thomas Harte 02a10ef651 Fall in line with nonsense. 2025-10-02 15:11:01 -04:00
Thomas Harte e3ca44f3ca Reseparate pixels. 2025-10-02 13:24:00 -04:00
Thomas Harte a9abc0dd5f Document a little further. 2025-10-02 09:30:33 -04:00
Thomas Harte cbcc7c718e SAA: smooth output just in time. 2025-10-02 09:20:58 -04:00
Thomas Harte 4377c79068 Switch blink rates. 2025-10-02 09:10:12 -04:00
Thomas Harte 514993bc2e Pull out cursor mask as a separate concern. 2025-10-02 07:56:07 -04:00
Thomas Harte c182176134 Merge pull request #1583 from TomHarte/SizedInt
Rename SizedCounter.
2025-10-01 22:23:51 -04:00
Thomas Harte abd1f10395 Ensure <=> is implemented. 2025-10-01 22:01:35 -04:00
Thomas Harte f279bebc1a Reduce redundant masking. 2025-10-01 21:59:40 -04:00
Thomas Harte 4e3fa5a6ff Use std::popcount. 2025-10-01 21:25:12 -04:00
Thomas Harte 01d355a247 Rename SizedCounter. 2025-10-01 20:58:34 -04:00
Thomas Harte 009f71a186 Update version number. 2025-09-30 21:52:53 -04:00
Thomas Harte de5c311d84 Merge pull request #1582 from TomHarte/SAAFlash
Switch to asymmetric SAA flash interval.
2025-09-30 21:48:16 -04:00
Thomas Harte eefe34f99e Merge branch 'master' into SAAFlash 2025-09-30 21:43:32 -04:00
Thomas Harte 82e3c870b3 Merge pull request #1581 from TomHarte/BetterKeyboardMap
BBC Micro: add character mapper, other improvements.
2025-09-30 21:43:15 -04:00
Thomas Harte d44a1d9761 Give SAA flashing an asymmetric appearance. 2025-09-30 21:33:37 -04:00
Thomas Harte e6fd54c14b Correct forward slash key. 2025-09-30 21:33:15 -04:00
Thomas Harte ccb8e90110 Improve naming. 2025-09-30 21:27:34 -04:00
Thomas Harte a4e66f291a Avoid ambiguity with new DelaySlot 'key'. 2025-09-30 21:23:30 -04:00
Thomas Harte 3ab3f34bef If there's only one BASIC file, CHAIN that. 2025-09-30 21:13:38 -04:00
Thomas Harte 99da8c4424 Avoid assuming 0 is not a valid key. 2025-09-30 21:07:02 -04:00
Thomas Harte 9a1bf1cf74 Reduce delay. 2025-09-30 21:06:56 -04:00
Thomas Harte 2256e99157 Attempt to add a typer. 2025-09-30 20:57:28 -04:00
Thomas Harte 3a5f8b4987 Fill in rest of character mapper. 2025-09-29 23:02:51 -04:00
Thomas Harte 6de5fcc980 Simplify test. 2025-09-29 22:52:56 -04:00
Thomas Harte a454d0d4b7 Begin work on character mapper. 2025-09-29 22:52:48 -04:00
Thomas Harte 67339754e3 Resolve potential crash at startup. 2025-09-29 16:13:56 -04:00
Thomas Harte 7316fe00ee Support native blink speeds. 2025-09-29 16:13:39 -04:00
Thomas Harte feb4a7021c Add enum of BBC key names. 2025-09-29 15:00:56 -04:00
Thomas Harte 5e84b671b6 Merge pull request #1580 from TomHarte/BBCReadme
Add BBC Micro to README.
2025-09-28 22:32:20 -04:00
Thomas Harte bcefef62f9 Add BBC Micro to README. 2025-09-28 22:30:06 -04:00
Thomas Harte cc953dda34 Merge pull request #1579 from TomHarte/EliteInterrupts
6522: avoid handshaking with register F.
2025-09-28 22:25:41 -04:00
Thomas Harte f9e5b0f0c7 6522: avoid handshaking with register F. 2025-09-28 22:12:53 -04:00
Thomas Harte 578654411e Merge pull request #1578 from TomHarte/CapsLock
Add meta as a synonym of control, option as caps lock.
2025-09-27 22:38:43 -04:00
Thomas Harte 247e92cfa2 Correct mapping of F5. 2025-09-27 22:27:57 -04:00
Thomas Harte 66f605de0f Add meta as a synonym of control, option as caps lock. 2025-09-27 22:03:27 -04:00
Thomas Harte 709b0efc9b Merge pull request #1577 from TomHarte/BBCAnalyser
Poke around trying to find a way to discern BBC and Electron software.
2025-09-27 08:17:57 -04:00
Thomas Harte 622679f4c2 Slow flash rate (though it's probably asymmetrical?) 2025-09-27 07:58:11 -04:00
Thomas Harte fdeb421513 Prefer the BBC for DFS media. 2025-09-27 07:49:42 -04:00
Thomas Harte 8fe25cde8d Add search for 'MODE7'. 2025-09-27 07:41:21 -04:00
Thomas Harte fbd71451f1 Enable sideways RAM by default. 2025-09-26 22:00:40 -04:00
Thomas Harte 0d91ce8e6a Add some Electron addresses. 2025-09-26 21:29:49 -04:00
Thomas Harte d71796c88a Support automatic disk starting. 2025-09-26 15:55:04 -04:00
Thomas Harte 277748c8f5 Install a basic search for CRTC/etc addresses. 2025-09-26 15:52:20 -04:00
Thomas Harte 8c1358ace9 Generate a BBC target, even though not yet exposed. 2025-09-26 15:37:32 -04:00
Thomas Harte 1254916058 Merge pull request #1576 from TomHarte/ReadmitBBC
Permit the BBC to appear in release builds.
2025-09-26 13:51:16 -04:00
Thomas Harte f228bee4b8 Permit the BBC to appear in release builds. 2025-09-26 13:49:19 -04:00
Thomas Harte 8094477b09 Merge pull request #1575 from TomHarte/CropFactor
Introduce a crop, centred on the pixel area.
2025-09-26 12:42:43 -04:00
Thomas Harte 32a5bf76cd Introduce a crop, centred on the pixel area. 2025-09-26 12:06:44 -04:00
Thomas Harte 0375d000e6 Merge pull request #1574 from TomHarte/SAA5050
Add SAA5050 and hence BBC Mode 7.
2025-09-25 23:12:28 -04:00
Thomas Harte 141d43d3e5 Further express smoothing in terms of pixel patterns. 2025-09-25 23:02:33 -04:00
Thomas Harte 823f7b1d2e Attempt held graphics. 2025-09-25 22:47:13 -04:00
Thomas Harte 6579f011d0 Support flash and conceal. 2025-09-25 22:37:38 -04:00
Thomas Harte 93f768af9b Bump control codes up in the roster. 2025-09-25 22:18:52 -04:00
Thomas Harte f8c11bf217 Rejig to ensure SAA output ends. 2025-09-25 21:31:21 -04:00
Thomas Harte 26ccd930c3 Begin tidying. 2025-09-25 17:53:54 -04:00
Thomas Harte 82211c7312 Add some 'graphics' support. 2025-09-25 17:50:26 -04:00
Thomas Harte 2015c154fe Correctly clear double-height flags. 2025-09-25 13:28:22 -04:00
Thomas Harte ef17d116a8 Don't permit single-height text on a lower double-height row. 2025-09-25 13:22:25 -04:00
Thomas Harte 46fddc44bf Support double-height text. 2025-09-25 13:21:49 -04:00
Thomas Harte 0214a77cd7 Add TODO. 2025-09-25 13:10:52 -04:00
Thomas Harte 425ed658f1 Support colour control codes, clarify SAA5050 signalling. 2025-09-25 13:03:55 -04:00
Thomas Harte a53adb561e Erase TODO, continue to update state without target. 2025-09-25 09:25:46 -04:00
Thomas Harte 3c3c55090a Port forward ElectrEm's font smoothing. 2025-09-25 09:22:16 -04:00
Thomas Harte ebc04c6520 Eliminate warning. 2025-09-24 22:58:50 -04:00
Thomas Harte 8b0e8f5b13 Move all work [near] definitively into the SAA5050. 2025-09-24 22:55:49 -04:00
Thomas Harte 16132a007e Remove silly call. 2025-09-24 22:26:37 -04:00
Thomas Harte b6e41ceea7 Hack in low-resolution Mode 7. 2025-09-24 22:25:43 -04:00
Thomas Harte 7015e46227 Put together enough of an interface to expect to see some pixels. 2025-09-24 22:08:04 -04:00
Thomas Harte cce2607c80 Add file for SAA5050 logic. 2025-09-24 21:43:25 -04:00
Thomas Harte 9dd2ec8bda Merge pull request #1573 from TomHarte/New6845
Improve 6845.
2025-09-24 21:36:16 -04:00
Thomas Harte 068726e0ab Add TODO. 2025-09-24 21:26:04 -04:00
Thomas Harte 89e86ad9bd Delay publication of the refresh address. 2025-09-24 21:20:20 -04:00
Thomas Harte 2e49bc2044 Add teletext pixel route, albeit without proper selection. 2025-09-24 20:33:07 -04:00
Thomas Harte 174c8dafbf Resolve potential out-of-phase line counter. 2025-09-24 17:26:40 -04:00
Thomas Harte 90a96293de Implement interlace-dependent row addressing. 2025-09-24 17:20:04 -04:00
Thomas Harte 84877c4fec Reenable the cursor; good enough for now. 2025-09-24 14:37:52 -04:00
Thomas Harte a7cceb5fa9 Avoid circular state dependency. 2025-09-24 14:30:37 -04:00
Thomas Harte ca6359a597 Reintroduce pixels, proving myself to be off-by-one. 2025-09-24 14:29:25 -04:00
Thomas Harte b7c3667be1 Work out inadvertent discrepancies. 2025-09-24 14:11:06 -04:00
Thomas Harte b6dea59db3 This tests lines, not rows. 2025-09-24 13:56:16 -04:00
Thomas Harte aa51f13743 Reorder to avoid dependencies upon values that mutate. 2025-09-24 13:54:09 -04:00
Thomas Harte f34ec03ff0 Attempt to fix off-by-one; adopt fixed pixel pattern. 2025-09-24 13:42:17 -04:00
Thomas Harte 1363be59b7 Formalise field size. 2025-09-24 11:17:47 -04:00
Thomas Harte 622c24ef24 This indicates a line, not a row. 2025-09-23 22:36:56 -04:00
Thomas Harte 539b0e49d4 Start in mode 7, reallow interlaced modes. 2025-09-23 14:45:32 -04:00
Thomas Harte 0c42976312 Add notes to self. 2025-09-23 14:42:16 -04:00
Thomas Harte 3f6b3a4fa0 Don't allow a state to be permanently accumulated. 2025-09-23 14:41:59 -04:00
Thomas Harte 67e1773495 This flag covers rows, not lines. 2025-09-23 14:29:00 -04:00
Thomas Harte a199b64aa0 Clarify naming, attempt better to conform to FPGA precedent. 2025-09-23 14:27:21 -04:00
Thomas Harte ebf09aceb2 Further extend. This is becoming more of a SizedInt. 2025-09-23 14:26:58 -04:00
Thomas Harte ca226e4295 Merge branch 'master' into New6845 2025-09-22 13:28:33 -04:00
Thomas Harte 9261939f62 Switch to working PC for testing. 2025-09-22 13:24:35 -04:00
Thomas Harte 0349931953 Shuffle declare order. 2025-09-22 13:21:48 -04:00
Thomas Harte d612a385d2 Dig in further on types. 2025-09-22 13:20:10 -04:00
Thomas Harte ed4f299d55 Start formalising types. 2025-09-22 13:09:30 -04:00
Thomas Harte 7cef789d41 Merge branch 'master' into New6845 2025-09-22 12:47:32 -04:00
Thomas Harte 66bfb86d42 Introduce SizedCounter as start of CRTC reworking. 2025-09-22 12:46:39 -04:00
Thomas Harte c4a5bc12ef Merge pull request #1572 from TomHarte/BBCADFS
Support ADFS, sideways RAM.
2025-09-20 23:27:15 -04:00
Thomas Harte 557631f6ba Support ADFS, sideways RAM. 2025-09-20 22:33:08 -04:00
Thomas Harte 362ffaff7f Merge pull request #1571 from TomHarte/RandomPauses
Correct uPD7002 interrupt wiring and behaviour.
2025-09-20 22:08:13 -04:00
Thomas Harte fb5ef200fb Correct uPD7002 interrupt wiring. 2025-09-20 21:51:19 -04:00
Thomas Harte 5e78ac3af5 Adjust keyboard map slightly. 2025-09-20 21:35:01 -04:00
Thomas Harte 719a090b34 Retain bit 2. 2025-09-20 20:06:28 -04:00
Thomas Harte 3af85da6e0 Adjust conversion bits in status. 2025-09-20 19:52:47 -04:00
Thomas Harte 8fd62aa525 Disable interrupt at start of conversion. 2025-09-20 19:49:16 -04:00
Thomas Harte 40747f51bd Disable ADC interrupt, experimentally. 2025-09-20 17:41:22 -04:00
Thomas Harte f3cef6bd73 Merge pull request #1570 from TomHarte/BBCCursor
Add BBC cursor.
2025-09-20 08:42:53 -04:00
Thomas Harte eef0ee8180 Support cursor to end of row. 2025-09-20 08:27:58 -04:00
Thomas Harte 503e974375 Restrict cursor to visible area, fix width. 2025-09-20 08:15:02 -04:00
Thomas Harte c959f2fee5 Attempt to show the hardware cursor. 2025-09-20 07:54:37 -04:00
Thomas Harte 7d5e434cba Merge pull request #1569 from TomHarte/BBCActivityIndicators
Add activity indicators.
2025-09-19 23:51:18 -04:00
Thomas Harte 2720bcdf18 Retrench to static inline const. 2025-09-19 23:40:30 -04:00
Thomas Harte c513b7262b Hit up two further strings for constexpr. 2025-09-19 23:37:11 -04:00
Thomas Harte 57a795df96 Add keyboard LEDs. 2025-09-19 23:34:51 -04:00
Thomas Harte 6bdd9e4543 Add drive activity indicators. 2025-09-19 23:26:50 -04:00
Thomas Harte ede3def37f Merge pull request #1568 from TomHarte/BBC1770
Add 1770 DFS support.
2025-09-19 23:20:29 -04:00
Thomas Harte 87d9022280 Collapse operations. 2025-09-19 23:03:11 -04:00
Thomas Harte ff0ba7d48b Reduce logging again. 2025-09-19 22:59:58 -04:00
Thomas Harte b49c47425f Set I flag on NMI and reset. 2025-09-19 22:59:37 -04:00
Thomas Harte 3916ba1a42 This intermittently succeeds. Doubling down on investigation. 2025-09-19 20:33:02 -04:00
Thomas Harte 0b3d22b97c Take a swing and a miss at alternative documentation interpretations. 2025-09-19 19:59:12 -04:00
Thomas Harte 9b8b0f2023 Attempt to introduce a DFS ROM and WD1770. 2025-09-19 10:38:22 -04:00
Thomas Harte 06e0d17be0 Merge pull request #1567 from TomHarte/AllPixelModes
Perform proper pixel generation in all bitmap modes.
2025-09-18 21:54:24 -04:00
Thomas Harte 239c485f3c An underclock will do. 2025-09-18 21:35:08 -04:00
Thomas Harte 5e5fdda0ca Correct audio. 2025-09-18 21:33:25 -04:00
Thomas Harte 4b2dddf3c6 Remove stale TODO. 2025-09-18 21:21:51 -04:00
Thomas Harte c99ec745ca Remove dead logging. 2025-09-18 21:20:27 -04:00
Thomas Harte 1ec2e455ec Support flash, mixed modes. 2025-09-18 21:19:33 -04:00
Thomas Harte 69304737c6 Switch red and blue. 2025-09-18 17:53:58 -04:00
Thomas Harte fe91670127 Pull count outside loop, simplify state machine. 2025-09-18 17:50:46 -04:00
Thomas Harte 7a59f94f3d Install more realistic pixel pipeline. 2025-09-18 17:46:09 -04:00
Thomas Harte 4efe3a333d Merge pull request #1566 from TomHarte/BBCADC
Add the BBC's ADC.
2025-09-18 12:39:34 -04:00
Thomas Harte 421bf28582 Add comments, correct address decoding. 2025-09-18 12:27:13 -04:00
Thomas Harte 4c49ffe3d1 Attmept full ADC implementation. 2025-09-18 12:21:25 -04:00
Thomas Harte 26b1ef247b Add calls to ADB. 2025-09-17 23:11:48 -04:00
Thomas Harte 3aafba707a Use more efficient means for blank lines. 2025-09-17 22:33:59 -04:00
Thomas Harte ae774e88fa Add header for ADC. 2025-09-17 21:42:42 -04:00
Thomas Harte ff56dd53cf Remove dead code. 2025-09-17 21:42:33 -04:00
Thomas Harte 12f063c178 Hack in a stable sync. 2025-09-17 21:35:41 -04:00
Thomas Harte 888148d282 Reduce chatter. 2025-09-17 21:35:34 -04:00
Thomas Harte 7bba0b82ef Correct video address generation. 2025-09-17 21:26:13 -04:00
Thomas Harte 41196a862d Merge pull request #1565 from TomHarte/BBCKeyboard 2025-09-17 18:22:47 -04:00
Thomas Harte a99ed0e557 Add break key. 2025-09-17 17:26:28 -04:00
Thomas Harte 654981fb03 Clean up. 2025-09-17 17:24:08 -04:00
Thomas Harte c473c36d46 Add comma, etc. 2025-09-17 11:48:33 -04:00
Thomas Harte e863e61af8 Remove dead code. 2025-09-17 11:46:53 -04:00
Thomas Harte efb486dd1b Fill in much more of key map. 2025-09-17 11:46:29 -04:00
Thomas Harte 25b15fcdd1 Switch to map-based mapping. 2025-09-17 11:34:55 -04:00
Thomas Harte 1106fbb5ef Implement circular scan. 2025-09-17 10:44:53 -04:00
Thomas Harte 9e1a29f0ff Merge branch 'master' into BBCKeyboard 2025-09-16 23:16:03 -04:00
Thomas Harte b3c057f911 Increase logging, play about more. 2025-09-16 23:14:05 -04:00
Thomas Harte 1c33e9ead9 Attempt row scanning. 2025-09-16 23:03:25 -04:00
Thomas Harte d78f35b940 Take a swing at scanning versus not. 2025-09-16 22:29:00 -04:00
Thomas Harte 506236a5ed Merge pull request #1564 from TomHarte/BBCPixels
Hard-code Mode 0 but hence get some pixels.
2025-09-16 21:52:16 -04:00
Thomas Harte 18b32dbba3 Attempt keyboard input. 2025-09-16 21:51:25 -04:00
Thomas Harte 26e40564dc Establish keyboard state. 2025-09-16 21:11:27 -04:00
Thomas Harte b6e8421a0a Hard-code Mode 0 but hence get some pixels. 2025-09-16 20:57:21 -04:00
Thomas Harte 03c5a3b325 Merge pull request #1563 from TomHarte/BBCACIA
BBC: Add ACIA.
2025-09-16 20:38:43 -04:00
Thomas Harte a1f33d3fc6 Redisable test code. 2025-09-16 17:54:42 -04:00
Thomas Harte b8fca7db80 Merge branch 'master' into BBCACIA 2025-09-16 17:54:17 -04:00
Thomas Harte 6ea70cd245 Merge pull request #1562 from TomHarte/BBCCRTC
Add some degree of a CRTC.
2025-09-16 17:53:49 -04:00
Thomas Harte 683fea675e Add ACIA.
Probably with incorrect clock, and connected to nothing.
2025-09-16 17:50:54 -04:00
Thomas Harte 811a010a60 Fix: keys are now unpressed.
Some sort of text is now 'output' (though not yet displayed by the emulator) and then an endless loop on the ACIA begins.

So the next PR will need to add that.
2025-09-16 17:25:13 -04:00
Thomas Harte 019526332d Declare no tube, optimistically watch for characters. 2025-09-16 16:25:41 -04:00
Thomas Harte 1e90387198 Add extra curly brackets. 2025-09-16 16:25:29 -04:00
Thomas Harte 84d6bb47ea Log more. 2025-09-16 15:32:42 -04:00
Thomas Harte 512179d92a Handle clock-rate change correctly in onward signalling. 2025-09-16 13:04:03 -04:00
Thomas Harte 04344a3723 The OS isn't writeable. 2025-09-16 12:47:55 -04:00
Thomas Harte d032207473 Made some attempt at 1Mhz CRTC clocking. 2025-09-16 12:46:44 -04:00
Thomas Harte b33dc2779d Correct RAM visibility. 2025-09-16 12:24:48 -04:00
Thomas Harte 28699a1af5 Correct clock selection bit. 2025-09-16 09:15:08 -04:00
Thomas Harte ff3fe135a3 Convince myself that this isn't a case of present but invisible content. 2025-09-16 07:36:59 -04:00
Thomas Harte ff69709926 Disable interlace support. 2025-09-15 23:53:36 -04:00
Thomas Harte 2162822cec Eliminate C++23 extension. 2025-09-15 23:42:57 -04:00
Thomas Harte 34330baaa0 Add comment on keyboard. 2025-09-15 23:42:47 -04:00
Thomas Harte 28d8aab7e5 Forward Port A correctly. 2025-09-15 23:36:07 -04:00
Thomas Harte 6a91c89126 Introduce a colour burst. 2025-09-15 23:32:20 -04:00
Thomas Harte c350f6fe5e Fix interrupting sync. 2025-09-15 23:28:38 -04:00
Thomas Harte 493bf0a666 Proceed to a solid blank display. 2025-09-15 23:27:04 -04:00
Thomas Harte 0305203e61 Wire up vertical sync interrupt. 2025-09-15 23:21:06 -04:00
Thomas Harte 71d7b1dfad Add a ticking-but-diconnected CRTC. 2025-09-15 23:16:42 -04:00
Thomas Harte 69748a1f1b Merge pull request #1561 from TomHarte/BBC6522s
BBC Micro: add 6522s.
2025-09-15 22:39:08 -04:00
Thomas Harte 39c2db38b7 Improve logged IO detail. 2025-09-15 22:29:22 -04:00
Thomas Harte f499de3622 Add sideways ROM paging. 2025-09-15 22:26:02 -04:00
Thomas Harte e8a16a8fce Attempt to incorporate SN76489. 2025-09-15 22:17:40 -04:00
Thomas Harte 81f2952c97 Log just enough to see that this looks like an SN76489 write. 2025-09-15 22:03:37 -04:00
Thomas Harte dcf9de1a01 Add IO access to the 6522s. 2025-09-15 21:26:36 -04:00
Thomas Harte 95f57f4eeb Add VIA instances, flesh out 1Mhz space. 2025-09-15 21:23:34 -04:00
Thomas Harte 7a794b8b6e Merge pull request #1559 from TomHarte/BBCMicro
Add BBC Micro skeleton.
2025-09-15 20:00:57 -04:00
Thomas Harte cbaf841f13 Add 1Mhz bus transitions. 2025-09-15 20:00:29 -04:00
Thomas Harte 6fdca9e89c Hide BBC Micro until complete. 2025-09-15 19:50:26 -04:00
Thomas Harte 8c3b3d98f6 Add error output. 2025-09-15 17:53:41 -04:00
Thomas Harte 6dd2abfb61 Fix BBC Micro path. 2025-09-15 17:53:32 -04:00
Thomas Harte 32defde397 Exit after the first filename that works. 2025-09-15 17:53:12 -04:00
Thomas Harte b1969c9528 Add BBC Micro. 2025-09-15 17:52:57 -04:00
Thomas Harte b6d5af81b5 Attempt to flesh out the 6502 space. 2025-09-15 17:44:07 -04:00
Thomas Harte 0358853d5a Permit 6502 to spin forever, doing nothing. 2025-09-15 17:14:17 -04:00
Thomas Harte eb60f63223 Remove redundant state. 2025-09-15 17:12:13 -04:00
Thomas Harte fdbb06436d Merge branch 'master' into BBCMicro 2025-09-15 14:54:46 -04:00
Thomas Harte bceaa073cd Merge pull request #1560 from TomHarte/OpenMultiple
macOS: Allow the same software to be open multiple times.
2025-09-15 14:54:25 -04:00
Thomas Harte ccace48d5a Declare clock rate, at least. 2025-09-15 14:54:10 -04:00
Thomas Harte 193203bbf7 Wire up enough Mac GUI to get to an empty husk. 2025-09-15 14:53:19 -04:00
Thomas Harte d0cc4e1557 Allow multiple copies of a program to be open. 2025-09-15 14:39:05 -04:00
Thomas Harte d52ae8c662 Eliminate macro. 2025-09-14 22:13:51 -04:00
Thomas Harte 6afd40cb39 Add to further project files. 2025-09-14 21:59:00 -04:00
Thomas Harte 6713baf86b Add BBC Micro class 2025-09-14 21:57:09 -04:00
Thomas Harte 365145e7c0 Allow updated version string. 2025-09-13 22:31:51 -04:00
Thomas Harte 0413af79e9 Merge pull request #1557 from TomHarte/BBCROMs
Add BBC MOS ROM to catalogue and move BASIC to a machine-neutral folder.
2025-09-13 21:38:20 -04:00
Thomas Harte 868c498e28 Separate BBC BASIC ROM from the Electron. 2025-09-12 23:25:21 -04:00
Thomas Harte c5fbbe8a69 Add BBC MOS; alphabetise. 2025-09-12 22:24:37 -04:00
Thomas Harte b698850ce8 Merge pull request #1556 from TomHarte/StaticConstexpr
Further prefer `static constexpr`.
2025-09-12 22:16:01 -04:00
Thomas Harte 0d1fe03369 Further prefer static constexpr. 2025-09-12 21:40:08 -04:00
Thomas Harte 98b900e886 Merge pull request #1555 from TomHarte/NoLoggingStorage
Definitively eliminate per-logger state.
2025-09-12 12:03:38 -04:00
Thomas Harte 8210da9e34 Modify xcodebuild overtly to download Metal toolchain. 2025-09-12 11:42:25 -04:00
Thomas Harte fac3d99f64 Switch to no-instance logging. 2025-09-12 07:17:23 -04:00
Thomas Harte d3c216374f Add #include for std::fill. 2025-09-12 07:17:17 -04:00
Thomas Harte 105272630e Definitively eliminate per-logger state. 2025-09-11 23:29:47 -04:00
Thomas Harte 53cc8ecaf0 Merge pull request #1554 from TomHarte/Keyboard
Tweak logging to emphasise only floppy & keyboard errors.
2025-09-11 23:06:20 -04:00
Thomas Harte fb8e8b4b3a Restore old logic, to reinstate working XT. 2025-09-11 22:47:26 -04:00
Thomas Harte 035713b4d3 Remove logging. 2025-09-10 23:00:42 -04:00
Thomas Harte 54b7dc56b5 Resolve risk of acknowledged interrupt refiring. 2025-09-10 22:59:57 -04:00
Thomas Harte 7fd39f44d0 Add some logging, take a stab at returning requests. 2025-09-10 21:46:58 -04:00
Thomas Harte 691292501a Promote constexprs to static. 2025-09-10 21:46:44 -04:00
Thomas Harte a58158ae08 Add PIT and PIC. 2025-09-10 21:45:51 -04:00
Thomas Harte ef09b971fa Watch software interrupt flags.
Now tracking: issue seems to be reaching TEST4.ASM:D11 with an interrupt that it believes to be software-originating.
2025-09-10 15:47:19 -04:00
Thomas Harte e07dee380d Experiment with further delays. 2025-09-10 14:18:30 -04:00
Thomas Harte 125bc5baa6 Install communication delay. 2025-09-10 13:48:51 -04:00
Thomas Harte 995444b11b Add TODO on what seems to be the current issue. 2025-09-10 11:33:38 -04:00
Thomas Harte 8f2384dbfc Fix log entry interleaving. 2025-09-10 09:52:55 -04:00
Thomas Harte 0cdd1c23ce Guess at another ID.
Cf. https://stanislavs.org/helppc/keyboard_commands.html
2025-09-09 23:40:55 -04:00
Thomas Harte 4765a39759 New guess: writing to the keyboard implicitly enables communications. 2025-09-09 23:38:21 -04:00
Thomas Harte 7f4047772c Continue naming things. 2025-09-09 15:36:02 -04:00
Thomas Harte 45c4ca6bec Attempt further to elide storage. 2025-09-09 13:58:37 -04:00
Thomas Harte 4a573a5aae Clarify one magic constant. 2025-09-09 13:44:31 -04:00
Thomas Harte 5125ff6a8c Combine enables, silence port 61 for now. 2025-09-09 11:16:42 -04:00
Thomas Harte 482d3301ce Avoid faulty sector access. 2025-09-08 23:14:50 -04:00
Thomas Harte cdeec8ac47 Take various more failed swings at which bits do what. 2025-09-08 22:54:10 -04:00
Thomas Harte 3cef12b53b Reintroduce proper ordering of log comments. 2025-09-08 22:27:40 -04:00
Thomas Harte dd098a16a8 Log more. 2025-09-08 21:54:56 -04:00
Thomas Harte 61a175e84a Merge branch 'master' into Keyboard 2025-09-08 21:43:25 -04:00
Thomas Harte a5bcd38fe8 Slightly reformat. 2025-09-08 21:43:18 -04:00
Thomas Harte cad42beef4 Roll in some random style improvements. 2025-09-08 20:38:50 -04:00
Thomas Harte 5a57958639 Reduce log repetition. 2025-09-08 17:22:53 -04:00
Thomas Harte 260336c1e5 Adopt phase as communicative of whether more bytes are expected. 2025-09-08 17:13:27 -04:00
Thomas Harte 889cb9c78f Attempt a dual-queue solution to enabling/disabling keyboard. 2025-09-08 14:40:08 -04:00
Thomas Harte b90e8f5af3 Further tweak reporting. 2025-09-06 23:16:10 -04:00
Thomas Harte 12361d2854 Adopt proper error/info distinction. 2025-09-06 23:13:33 -04:00
Thomas Harte d307ddfa8e Merge branch 'master' into Keyboard 2025-09-05 23:21:41 -04:00
Thomas Harte 96fd0b7892 Merge pull request #1553 from TomHarte/IndentationSomeMore
Further reduce indentation.
2025-09-05 23:20:19 -04:00
Thomas Harte 6f1db15d7c Further reduce indentation. 2025-09-05 23:07:45 -04:00
Thomas Harte 1854296ee8 Merge pull request #1552 from TomHarte/ElectronIDE
Reduce code duplication within the ROM catalogue.
2025-09-05 22:45:55 -04:00
Thomas Harte 515cc5f326 Correct spelling. 2025-09-05 22:09:38 -04:00
Thomas Harte 091be7eafe Remove unused header. 2025-09-05 22:03:45 -04:00
Thomas Harte 27a19ea417 Eliminate line-length violations. 2025-09-05 22:03:19 -04:00
Thomas Harte 9a5e9af67c Standardise layout. 2025-09-05 22:00:42 -04:00
Thomas Harte 3a493f2428 Merge pull request #1551 from TomHarte/LogLevels
Allow logging of errors but not info.
2025-09-05 21:04:56 -04:00
Thomas Harte ca6e34f4b4 Fix dangling OpenGL accesses. 2025-09-05 19:30:33 -04:00
Thomas Harte e1e68312c4 Transcribe remaining catalogue entries. 2025-09-05 17:23:38 -04:00
Thomas Harte c7ff2cece4 Head in search of a more-compact form. 2025-09-05 16:55:00 -04:00
Thomas Harte 8e6f4fa36f Fix NDEBUG route. 2025-09-05 14:34:08 -04:00
Thomas Harte 4d302da9fa Allow logging of errors but not info. 2025-09-05 14:25:56 -04:00
Thomas Harte e0917dc734 Switch focus back to keyboard. 2025-09-04 22:21:05 -04:00
Thomas Harte 26f82e8143 Merge pull request #1550 from TomHarte/SpaceshipOperator
Adopt spaceship.
2025-09-04 22:08:35 -04:00
Thomas Harte 6518f08bc7 Adopt spaceship. 2025-09-04 21:25:12 -04:00
Thomas Harte 8599123b30 Merge pull request #1549 from TomHarte/MoreFDC
Implement further FDC commands.
2025-09-04 19:25:32 -04:00
Thomas Harte f934a1aa10 Ensure std::hash is known. 2025-09-04 17:53:18 -04:00
Thomas Harte 81be5f809f Fix logged statement. 2025-09-04 17:48:50 -04:00
Thomas Harte 8bb94804d4 Attempt to bluster to something for read ID. 2025-09-04 17:45:41 -04:00
Thomas Harte c3f64e85ce Support unordered maps; use spaceship operator. 2025-09-04 17:39:09 -04:00
Thomas Harte 53057aff5d Reduce type redundancy. 2025-09-04 17:29:34 -04:00
Thomas Harte 8cad5ac7e9 Reduce repetitive array references. 2025-09-04 17:00:10 -04:00
Thomas Harte b4f643f3dd Merge pull request #1541 from TomHarte/Spelling
Adopt my native spelling: 'licence' is a noun.
2025-09-04 16:01:11 -04:00
Thomas Harte 2d659289e8 Merge pull request #1546 from TomHarte/SomeIDE
Add some IDE/ATA structure.
2025-09-04 15:58:26 -04:00
Thomas Harte 9883640b63 Better record scope of incomplete work. 2025-09-04 15:22:04 -04:00
Thomas Harte bc3a0c3c91 Fix stqtic declaration. 2025-09-04 15:17:24 -04:00
Thomas Harte 4e822347a5 Finally crack case of controller failure. 2025-09-04 15:16:48 -04:00
Thomas Harte d5650da8c0 Avoid strict aliasing violation. 2025-09-04 14:23:29 -04:00
Thomas Harte d3c77523c3 Report normal terminations, usually. 2025-09-04 11:41:29 -04:00
Thomas Harte 787a5ce568 Reduce speed multiplier. 2025-09-03 22:22:12 -04:00
Thomas Harte 91dfd405d1 Adjust logging. 2025-09-03 13:44:30 -04:00
Thomas Harte 08c615c493 Improve ready flag. 2025-09-03 13:31:06 -04:00
Thomas Harte 5483102276 Add missing #includes. 2025-09-02 21:29:49 -04:00
Thomas Harte 32686d898b Fix again for concurrent seeks. 2025-09-02 21:18:35 -04:00
Thomas Harte 4b50c8d96c Toy with sense interrupt status being directly seek-linked. 2025-09-02 17:50:59 -04:00
Thomas Harte c1780ee26b Add some form of sense drive status. 2025-09-02 15:21:11 -04:00
Thomas Harte 46b2db00bc Establish that the AT actually wants SenseDriveStatus. 2025-09-02 12:52:04 -04:00
Thomas Harte 7042e457ab Fix OUT sizes. 2025-09-02 12:32:27 -04:00
Thomas Harte faeec1701f Add logging, reduce template specialisation. 2025-09-02 12:31:16 -04:00
Thomas Harte 2a75a1f9f2 Add IDE logging. 2025-09-02 12:21:01 -04:00
Thomas Harte 8c65dccc53 Support 16-bit IO access. 2025-09-01 23:31:31 -04:00
Thomas Harte de7c3ba92f Mostly kick IDE accesses down the road. 2025-09-01 00:02:16 -04:00
Thomas Harte ac204aadd2 Clean up, better constify SCSI innards. 2025-08-31 10:56:01 -04:00
Thomas Harte 46fc0d677f Merge branch 'master' into SomeIDE 2025-08-30 23:52:58 -04:00
Thomas Harte 2d4f4b0036 Merge pull request #1545 from TomHarte/SomeConsts
Improve `const` arguments.
2025-08-30 23:36:49 -04:00
Thomas Harte c1de00bf9d Improve const arguments. 2025-08-30 23:25:19 -04:00
Thomas Harte 4639e1c47c Merge pull request #1544 from TomHarte/Macros
Further reduce historical dependence on macros.
2025-08-30 14:19:17 -04:00
Thomas Harte 5d2c156bc9 Use popcount. 2025-08-30 10:44:00 -04:00
Thomas Harte 357f98f015 Remove macros, shorten line lengths. 2025-08-30 10:41:28 -04:00
Thomas Harte 62f23ac27c Commute macros. 2025-08-30 10:34:49 -04:00
Thomas Harte 0936646ef9 Eliminate macros. 2025-08-30 10:29:53 -04:00
Thomas Harte 856c12f46f Eliminate macro. 2025-08-30 10:24:27 -04:00
Thomas Harte 7489783837 Eliminate macros. 2025-08-30 10:22:21 -04:00
Thomas Harte a4f0a4c310 Merge pull request #1543 from TomHarte/MinorTidies
Perform further tidying steps.
2025-08-30 10:00:41 -04:00
Thomas Harte bb1ef114f1 Fix header declaration. 2025-08-30 09:40:06 -04:00
Thomas Harte f1610b6407 Fix Qt speaker delegation. 2025-08-30 00:13:47 -04:00
Thomas Harte 5e48a4c724 Fix SDL speaker sample receipt. 2025-08-30 00:10:17 -04:00
Thomas Harte d825c03372 Prefer references for delegate protocols. 2025-08-30 00:09:38 -04:00
Thomas Harte d177549dd6 Reduce more indentation. 2025-08-29 23:56:35 -04:00
Thomas Harte 9d1543401f Merge pull request #1542 from TomHarte/VHD
Sketch out VHD support.
2025-08-29 23:47:01 -04:00
Thomas Harte 094eb7e252 Resolve Github build breakage. 2025-08-29 23:09:13 -04:00
Thomas Harte 95e6726468 Reduce indentation. 2025-08-29 23:02:34 -04:00
Thomas Harte 8fded8f210 Add consts, remove get_s. 2025-08-29 22:55:50 -04:00
Thomas Harte 19c4940abd Extend and constify MassStorageDevice. 2025-08-29 22:17:01 -04:00
Thomas Harte 7b1f6b3c53 Add negative asserts. 2025-08-29 22:02:54 -04:00
Thomas Harte 43042c3737 Parse a little further. 2025-08-29 21:55:21 -04:00
Thomas Harte 30b50b8a1b Add missing header, CMake file. 2025-08-28 21:56:03 -04:00
Thomas Harte 095be3072b Distinguish when to include the trailing NULL. 2025-08-28 21:53:52 -04:00
Thomas Harte 91831200d6 Eliminate runtime strlen. 2025-08-28 18:45:04 -04:00
Thomas Harte 8295d4511b Improve whence type safety. 2025-08-28 17:41:58 -04:00
Thomas Harte df589d9588 Test image type. 2025-08-28 17:29:26 -04:00
Thomas Harte b826e1c661 Do some small measure of header parsing. 2025-08-28 17:20:29 -04:00
Thomas Harte 6727e2fe73 Add shell of a class for VHD files. 2025-08-27 17:09:52 -04:00
Thomas Harte ecdcee8d4e Adopt my native spelling: 'licence' is a noun. 2025-08-26 23:48:00 -04:00
Thomas Harte 8b4a4369c1 Add a target for IDE activity. 2025-08-26 23:47:39 -04:00
Thomas Harte eeb06de916 Merge pull request #1540 from TomHarte/KeyboardAgain
Be more rigorous about `static constexpr`
2025-08-26 23:22:19 -04:00
Thomas Harte 5018d7d577 Be more rigorous about static constexpr. 2025-08-26 22:54:39 -04:00
Thomas Harte 1ca279d99d Add keyboard command lookaside; dummy IDE read. 2025-08-25 22:49:32 -04:00
Thomas Harte 8a149a188c Store keyboard command until enabled. 2025-08-25 22:44:22 -04:00
Thomas Harte 076334bc4e Take first stab at separating keyboard & controller. 2025-08-25 22:14:51 -04:00
Thomas Harte e6b45c978c Merge pull request #1539 from TomHarte/KeyboardAgain
Name keyoard commands, implement a couple more.
2025-08-25 22:12:00 -04:00
Thomas Harte a07615445f Uncover likely issue: commands directly to keyboard. 2025-08-23 22:51:09 -04:00
Thomas Harte 41d30c2835 More formally designate the resets. 2025-08-23 22:41:58 -04:00
Thomas Harte 71f1635e23 Name commands, implement a couple more. 2025-08-23 22:33:19 -04:00
Thomas Harte 57df6d9bf7 Merge pull request #1538 from TomHarte/LessMemory
Reduce AT to 640kb RAM.
2025-08-23 22:02:28 -04:00
Thomas Harte fd670d5175 Reduce AT to 640kb RAM.
This substantially speeds up the boot process, clearing the way for other experimentation.
2025-08-23 21:51:48 -04:00
Thomas Harte 39d4c315c8 Merge pull request #1537 from TomHarte/FloppyExists
Increase floppy logging, adjust sense interrupt.
2025-08-23 21:33:22 -04:00
Thomas Harte 6487086354 Increase floppy logging, adjust sense interrupt. 2025-08-23 21:21:16 -04:00
Thomas Harte 7d6e24b8ed Merge pull request #1536 from TomHarte/8042Redo
Rejig 8042; extend logger for common conditional use case.
2025-08-21 23:23:59 -04:00
Thomas Harte 4922073300 Reestablish pre-AT keyboard link. 2025-08-21 16:48:05 -04:00
Thomas Harte 778a02324e Add enabled flag. 2025-08-20 22:56:04 -04:00
Thomas Harte 8e89aa97a0 Switch status bit 3; fix reading of is_tested_; guess at it self-setting. 2025-08-20 22:09:08 -04:00
Thomas Harte dfd521e938 Attempt to reformulate keyboard controller. 2025-08-20 17:17:54 -04:00
Thomas Harte d47332adf5 Reduce need for scopes. 2025-08-20 17:17:27 -04:00
Thomas Harte 14e7ba8fab Merge pull request #1535 from TomHarte/MDAStatus
Add MDA status register.
2025-08-19 16:39:03 -04:00
Thomas Harte e68a356fd0 Adjust AT switches input. 2025-08-18 23:26:58 -04:00
Thomas Harte 6e77b8659c Add various missing enum -> string mappings. 2025-08-18 14:59:58 -04:00
Thomas Harte 00fad7e424 Merge pull request #1534 from TomHarte/PCBASIC
Add PC BASIC ROM to the PC AT.
2025-08-14 22:28:48 -04:00
Thomas Harte 0a65248bf7 Add MDA status register, various notes. 2025-08-14 22:28:22 -04:00
Thomas Harte 9cff26b163 Install BASIC ROM. 2025-08-13 23:36:07 -04:00
Thomas Harte 9309d8c3f2 Add ROM BIOS to the ROM catalogue. 2025-08-13 22:18:16 -04:00
Thomas Harte 07e96c10d2 Merge pull request #1533 from TomHarte/MultifacetedCall
Further implement the 80286
2025-08-13 19:05:52 -04:00
Thomas Harte d95abc99d9 Slightly increase logging. 2025-08-13 16:44:53 -04:00
Thomas Harte b83c2615de Limit LSL types. 2025-08-13 13:53:02 -04:00
Thomas Harte 78a2b27e65 Attempt LSL, LAR. 2025-08-13 13:43:19 -04:00
Thomas Harte bae594e34c Fix ARPL flag. 2025-08-12 21:32:20 -04:00
Thomas Harte 4ded6fceea Fix VERR/VERW. 2025-08-12 21:20:01 -04:00
Thomas Harte 0e498829f7 Attempt VERR, VERW.
Without complete success; IBM's third invocation (which I think is a VERR) doesn't give the result that BIOS is looking for.
2025-08-12 17:22:14 -04:00
Thomas Harte ddd090d581 Implement STR. 2025-08-12 16:21:23 -04:00
Thomas Harte 4cd979e5fb Take a shot at LTR. 2025-08-12 13:49:59 -04:00
Thomas Harte 2f7a6bb242 Establish a specialised validate_call. 2025-08-11 17:10:58 -04:00
Thomas Harte 3b3b2e61b0 Overtly separate call authorisation. 2025-08-11 13:24:51 -04:00
Thomas Harte ab4fde9bd7 Slightly clean up. 2025-08-11 09:41:31 -04:00
Thomas Harte a9996f0b81 Add consts. 2025-08-11 09:34:17 -04:00
Thomas Harte 246d34e072 Merge pull request #1532 from TomHarte/SimplerDescriptors
Boil down descriptor attributes.
2025-08-10 20:49:44 -04:00
Thomas Harte d35efe3f32 Boil down descriptor attributes. 2025-08-09 23:10:26 -04:00
Thomas Harte ebd1a6b47c Merge pull request #1531 from TomHarte/286DecodingTests
Resolve majority of 286 test case failures.
2025-08-08 15:04:58 -04:00
Thomas Harte 83980678a0 Add additional known bad.
38 failures left.
2025-08-08 12:06:48 -04:00
Thomas Harte 201393f87d Start discounting test cases that look broken.
39 failures remaining.
2025-08-08 12:00:58 -04:00
Thomas Harte 055eb3873e Switch far jump to piece-by-piece authorisation.
43 failures.
2025-08-08 11:30:51 -04:00
Thomas Harte dc94d58148 Switch CALL to access-by-access validation.
47 failures remaining.
2025-08-08 11:28:32 -04:00
Thomas Harte 0adaec1665 Allow ENTER to write partially.
51 failures left.
2025-08-08 11:18:14 -04:00
Thomas Harte 4ee30dc36f Correct stack validation, fixing POPA.
71 failures.
2025-08-08 11:05:01 -04:00
Thomas Harte 54ff2fa01f Fix new LES/etc failures.
Remaining: 72.
2025-08-08 09:55:31 -04:00
Thomas Harte 03c70b49ba Throw GPF for overlong instructions; fix BOUND validation.
79 failures outstanding.
2025-08-08 09:43:16 -04:00
Thomas Harte 4b2d8e13d1 Add consts, TODO. 2025-08-08 07:39:34 -04:00
Thomas Harte a0c50f0521 Support 286-style DAS.
321 failures to go.
2025-08-07 19:49:41 -04:00
Thomas Harte b15a865c88 Add extra MOV sanity check.
Failures still standing: 406.
2025-08-07 17:40:13 -04:00
Thomas Harte 8e5bbbbc71 Implement 80286 INS/OUTS oddities.
795 failures outstanding.
2025-08-07 15:31:07 -04:00
Thomas Harte 615ebaf711 Correct RCL overflow when shift count is 0.
1,013 failures remaining.
2025-08-07 15:23:11 -04:00
Thomas Harte 0882d2b7ce Correct LEAVE authorisation.
Failures: 1,207.
2025-08-07 15:16:12 -04:00
Thomas Harte 900195efac Correct HLT IP comparison.
Failures: 1,425.
2025-08-07 15:01:22 -04:00
Thomas Harte b58b962ccf Apply 80286 LODS craziness.
2,425 errors remaining.
2025-08-07 14:53:16 -04:00
Thomas Harte 5255499445 Implement 286 weirdness for SCAS.
2,690 failures.
2025-08-07 14:50:59 -04:00
Thomas Harte d9a2be4250 Avoid upfront testing for POPA.
Failures: 2,966.
2025-08-07 14:41:01 -04:00
Thomas Harte 256e14a8a6 Decline upfront validation for PUSHA.
Total failures remaining: 3,239.
2025-08-07 14:36:11 -04:00
Thomas Harte 1ab26d4a2f Determine 80286 CMPS rules.
Remaining: 3,521 failures.
2025-08-07 12:28:50 -04:00
Thomas Harte 91b2c751af Determine 80286 logic for MOVS.
4,043 failures left.
2025-08-07 12:17:52 -04:00
Thomas Harte edf7617d1e Fix is_address.
Failures: 4,568.
2025-08-07 09:25:23 -04:00
Thomas Harte 32666d304f Filter out some illegal JMP/CALL fars.
Failure count now: 5,966.
2025-08-07 09:18:23 -04:00
Thomas Harte b65f7b4a6a Restrict BOUNDS checks to 80286. 2025-08-06 22:32:50 -04:00
Thomas Harte 7c4df23c1c Fix BOUND.
7085 remaining failures.
2025-08-06 22:19:35 -04:00
Thomas Harte a8e60163e1 Commute Overflow from fault to trap.
9,331 failures remaining.
2025-08-06 21:30:08 -04:00
Thomas Harte 02ec1b5da6 Fix SHR overflow flag.
Failing: 11,802.
2025-08-06 21:14:15 -04:00
Thomas Harte a9a6aba862 Correct RCR overflow.
Now: 14,097 failures.
2025-08-06 17:46:05 -04:00
Thomas Harte 03c6a60f68 Avoid extra judgment on LEAVE.
Failures remaining: 16,295.
2025-08-06 17:19:20 -04:00
Thomas Harte 8ab688687e Decode .6 as SAL.
Amazingly: now 20,814 failures outstanding.
2025-08-06 16:30:55 -04:00
Thomas Harte bdec32722e Include failures/file. 2025-08-06 16:07:54 -04:00
Thomas Harte ad50e5c754 Ensure an invalid instruction is generated upon length limit. 2025-08-06 15:59:24 -04:00
Thomas Harte 9c48e44e9e Fix fast-path selection.
50,814 failures.
2025-08-06 15:33:51 -04:00
Thomas Harte 76284eb462 Fix 8088 assumption about unused flags; 80286 PUSHF now passes amongst others.
51,091 failures still to fix though.
2025-08-06 15:31:03 -04:00
Thomas Harte 0745c5128a Avoid expensive path for 8088; pull out allow list. 2025-08-06 15:21:54 -04:00
Thomas Harte 01fbe2d3de Support 808286 STOS oddities. 2025-08-06 13:37:34 -04:00
Thomas Harte 9e14c22259 Take another run at ENTER. 2025-08-06 12:55:37 -04:00
Thomas Harte dff0111cd5 Overtly capture decoding failures. 2025-08-05 13:03:54 -04:00
Thomas Harte e7452b0ea1 Continue accepting F7.2 as TEST. 2025-08-04 21:45:14 -04:00
Thomas Harte 61a0f892c4 Fix PUSH immediate. 2025-08-04 21:23:27 -04:00
Thomas Harte 4ceab01ed4 Fix result of IMUL_3. 2025-08-04 21:05:14 -04:00
Thomas Harte 9908969eea Diagnose, correct AAA and AAS. 2025-08-04 17:49:07 -04:00
Thomas Harte 19a78ef1ac Correct for 286+ PUSH SP. 2025-08-04 17:23:02 -04:00
Thomas Harte 4785c1ae84 Grab new punchlist. 2025-08-04 17:19:11 -04:00
Thomas Harte ef03841efa Deal with potential reason for wrong top-of-flags. 2025-08-04 17:14:16 -04:00
Thomas Harte 4747a70ce7 Correct for accesses right at segment end. 2025-08-04 17:08:01 -04:00
Thomas Harte cd986cc2dc Ensure tests get the default IDT. 2025-08-04 12:47:52 -04:00
Thomas Harte c29d5ca4a8 Catch address wraparound out-of-bounds access. 2025-08-04 09:32:35 -04:00
Thomas Harte 56b49011d6 Shorten reports. 2025-08-04 09:21:49 -04:00
Thomas Harte 48c55211e6 Fix descriptor bounds test. 2025-08-04 09:16:33 -04:00
Thomas Harte 72f68f3b0b Include hash in error record. 2025-08-03 20:11:35 -04:00
Thomas Harte 7b6dddc994 Include number. 2025-08-03 17:57:26 -04:00
Thomas Harte 51fbe4e8c5 Consume 286 HLT. 2025-08-03 17:41:02 -04:00
Thomas Harte c148d9ee6c Ensure ENTER can execute. 2025-08-03 17:30:02 -04:00
Thomas Harte 9dfe59a104 Take a swing at three-operand IMUL. 2025-08-02 22:23:34 -04:00
Thomas Harte b6aae65afd Clean up, separate. 2025-08-02 21:45:01 -04:00
Thomas Harte 9fed93a771 Use 286 test suite for decoding tests too. 2025-08-02 21:31:04 -04:00
Thomas Harte cdfb68f261 Merge pull request #1530 from TomHarte/FullerTests
Utilise 80286 real-mode tests.
2025-08-02 19:00:47 -04:00
Thomas Harte 46450bd080 Use proper perform in tests. 2025-08-02 18:47:06 -04:00
Thomas Harte 9a25d601f1 Fully transfer faulting logic. 2025-08-02 18:37:56 -04:00
Thomas Harte fe0834ecda Fix type difference. 2025-08-02 18:32:23 -04:00
Thomas Harte 846f745e2c Attempt to transfer ownership of fault. 2025-08-02 18:26:00 -04:00
Thomas Harte 30d40e6f9b Add TODO. 2025-08-01 20:58:12 -04:00
Thomas Harte f7501b10f7 Move ExecutionSupport to heap. 2025-08-01 20:11:26 -04:00
Thomas Harte 379c513f8a Add const getter, mode getter; further template. 2025-08-01 19:56:57 -04:00
Thomas Harte 5a6d77e958 Generalise, towards using 80286 tests. 2025-08-01 15:59:40 -04:00
Thomas Harte 6646039ffe Templatise to allow beyond-8086 execution. 2025-07-31 21:26:29 -04:00
Thomas Harte 5e0994270f Merge pull request #1529 from TomHarte/StatusFlagsMask
Correct metadata observation.
2025-07-31 19:52:16 -04:00
Thomas Harte 44fc801720 Correct metadata observation. 2025-07-31 15:47:07 -04:00
Thomas Harte 405c61f53d Merge pull request #1528 from TomHarte/ZX81Typer
ZX80/81: Reduce typing speed.
2025-07-31 15:16:43 -04:00
Thomas Harte c40acb9406 Reduce typing speed. 2025-07-29 21:55:56 -04:00
Thomas Harte 7778d2a47e Merge pull request #1527 from TomHarte/8088TestFailures
Restore proper register and memory contents.
2025-07-29 21:36:12 -04:00
Thomas Harte 96afb245a5 Fix test suite memory state. 2025-07-29 21:25:15 -04:00
Thomas Harte cf0677c30b Avoid spurious register comparison failures. 2025-07-28 17:44:32 -04:00
Thomas Harte 667614d9de Merge pull request #1525 from TomHarte/x86Tests
Revive x86 JSON tests
2025-07-27 22:23:27 -04:00
Thomas Harte 652ede57b3 Further clone FlowController. 2025-07-27 22:00:54 -04:00
Thomas Harte 09a34f880e Start trying to return preauthorisation testability. 2025-07-27 21:17:54 -04:00
Thomas Harte a9f9be330d Allow SegmentedMemory to take different LinearMemorys. 2025-07-26 08:18:16 -04:00
Thomas Harte 39568d2464 Run headfirst into a LinearMemory substitution brick wall. 2025-07-25 21:43:54 -04:00
Thomas Harte 10e07a9966 Add missing concept requirement. 2025-07-25 21:27:51 -04:00
Thomas Harte fe00a69136 Start transitioning to PCCompatible::Segments. 2025-07-25 16:58:07 -04:00
Thomas Harte 9d0c2cd67f Switch to a parasitic use of PCCompatible::LinearMemory. 2025-07-25 16:47:08 -04:00
Thomas Harte b5aab442f8 Template immediate-read Segments; continue fixing 8088Tests. 2025-07-24 22:24:53 -04:00
Thomas Harte 7c010bd1ef Relocate validation logic, such as it is. 2025-07-22 22:42:01 -04:00
Thomas Harte 1bf898405f Generalise 'Registers'. 2025-07-21 21:17:54 -04:00
Thomas Harte c490166b35 Fully apply line length limit. 2025-07-21 17:09:07 -04:00
Thomas Harte e6862364ed Correct syntax to the point of failing only concepts. 2025-07-21 17:06:17 -04:00
Thomas Harte cf20c84edd Merge pull request #1523 from TomHarte/MacintoshIMGStyle
Use <algorithm>, and otherwise reduce.
2025-07-19 21:56:50 -04:00
Thomas Harte 88e776ad5b Use <algorithm>, and otherwise reduce. 2025-07-19 21:37:03 -04:00
Thomas Harte e79a60f5cd Merge pull request #1522 from TomHarte/MacintoshIMGStyle
Make minor style improvements.
2025-07-16 22:47:46 -04:00
Thomas Harte fd4a91ba72 Make minor style improvements. 2025-07-16 22:31:41 -04:00
Thomas Harte 5705ece2a3 Merge pull request #1521 from atsampson/includes
Add some missing <cstdint> includes
2025-07-10 21:20:28 -04:00
Thomas Harte c723f20f39 Merge pull request #1520 from TomHarte/ElectronTiming
Electron: move CPU slots to first half of each 1Mhz window.
2025-07-10 19:06:06 -04:00
Adam Sampson 0f7447d539 Add some missing <cstdint> includes. 2025-07-10 23:58:12 +01:00
Thomas Harte 1a08944854 std::tuple is defined in utility, not tuple. 2025-07-09 09:26:16 -04:00
Thomas Harte 7b0b06f6df Adhere to line length limit. 2025-07-09 13:27:53 +08:00
Thomas Harte d2ad227a24 Relocate CPU activity to start of each 1Mhz slot. 2025-07-09 13:18:54 +08:00
Thomas Harte 71d7982d14 Tweak ownership of lookahead logic. 2025-07-09 12:55:53 +08:00
Thomas Harte a94dcc12ef Reformat, consider CPU slot repositioning. 2025-07-09 10:41:03 +08:00
Thomas Harte b7bfcfa1e3 Add note to future self. 2025-07-07 17:41:11 +08:00
Thomas Harte 416ae0ca04 Separate location tests from loop. 2025-07-07 17:37:31 +08:00
Thomas Harte 8d66cd4874 Merge pull request #1519 from TomHarte/ElectronTiming
Deduplicate Electron palette work.
2025-06-25 16:47:15 +07:00
Thomas Harte a701ba8030 Switch to requires. 2025-06-25 16:28:26 +07:00
Thomas Harte 0160908522 Further deduplicate palette actions. 2025-06-25 16:23:25 +07:00
Thomas Harte cdd0d6d127 Add consts. 2025-06-23 14:40:48 +07:00
Thomas Harte 65ee745d6e Avoid repetition of palette data. 2025-06-23 14:35:31 +07:00
Thomas Harte 4141dfc353 Merge pull request #1518 from TomHarte/ElectronColoursEtc
Correct Electron 1bpp palette G/B confusion.
2025-06-22 05:18:29 -04:00
Thomas Harte fb6cd105c3 Overtly name type. 2025-06-22 16:03:50 +07:00
Thomas Harte 6ff9168146 Correct G/B 1bpp mismapping. 2025-06-22 15:58:16 +07:00
Thomas Harte 7b5e08aab6 Slightly improve palette semantics. 2025-06-22 15:25:20 +07:00
Thomas Harte c7dd4526c1 Merge pull request #1516 from TomHarte/JFDFiles
Add elementary JFD support.
2025-06-01 22:48:00 -04:00
Thomas Harte 066036ccdd Add to CMake. 2025-05-31 21:28:02 -04:00
Thomas Harte 7c164453a5 Correct overrun test. 2025-05-30 22:33:27 -04:00
Thomas Harte 8b31cfeafb Correct offset into track table. 2025-05-30 21:47:16 -04:00
Thomas Harte 2ddaf0afa3 Attempt preliminary track building. 2025-05-30 21:25:07 -04:00
Thomas Harte a8a97b4606 Get as far as printing sector stats. 2025-05-29 22:37:10 -04:00
Thomas Harte a55b63a210 Add skeleton for JFD support. 2025-05-29 09:27:13 -04:00
Thomas Harte 2e4f7cd667 Merge pull request #1511 from TomHarte/PrivilegeLevels
Implement some of the missing 80286 operations.
2025-05-28 22:39:05 -04:00
Thomas Harte bf257a8d9e Adjust ownership for segment load detection. 2025-05-28 22:08:43 -04:00
Thomas Harte c4e66f7a35 Merge branch 'master' into PrivilegeLevels 2025-05-28 21:05:36 -04:00
Thomas Harte efff433aa0 Merge pull request #1515 from TomHarte/BitwiseAF
x86: clear auxiliary carry on AND, OR, XOR and TEST.
2025-05-27 11:37:03 -04:00
Thomas Harte ee60e36a16 x86: clear auxiliary carry on AND, OR, XOR and TEST. 2025-05-27 11:23:17 -04:00
Thomas Harte 841fc3cfaf Accept version-number increase. 2025-05-26 22:49:35 -04:00
Thomas Harte 2a44caea6c Merge pull request #1514 from TomHarte/ElectronChangeObsevrer
Add Electron to `MediaChangeObserver` gang.
2025-05-26 22:45:45 -04:00
Thomas Harte 0f661928ae Add Electron to MediaChangeObserver gang. 2025-05-26 22:35:08 -04:00
Thomas Harte 0961e5cc2e Add TSS deserialiser. 2025-05-20 21:56:58 -04:00
Thomas Harte df621a8205 Add real and protected callbacks. 2025-05-18 23:35:49 -04:00
Thomas Harte bfa416ca99 Fix #include. 2025-05-18 22:30:20 -04:00
Thomas Harte 8041b87317 Introduce segment preauthorisation. 2025-05-18 22:11:23 -04:00
Thomas Harte b3000f6350 Made mode knowable; factor out main part of far jump. 2025-05-17 23:08:07 -04:00
Thomas Harte 947baab269 Add TODO. 2025-05-14 22:12:59 -04:00
Thomas Harte a41ea90ca7 Implement CLTS. 2025-05-14 21:08:26 -04:00
Thomas Harte 8b3f0d8fd6 Implement ARPL. 2025-05-14 21:01:48 -04:00
Thomas Harte bd9740a9a4 Add additional informative static asserts. 2025-05-13 22:54:05 -04:00
Thomas Harte 3f735e44f1 Merge pull request #1510 from TomHarte/LLDT
Begin LDT support.
2025-05-13 22:41:53 -04:00
Thomas Harte 9e5235fd30 Descriptor tables are always at most 64kb. 2025-05-13 14:07:28 -04:00
Thomas Harte 159f3cb780 Add SLDT. 2025-05-12 23:17:34 -04:00
Thomas Harte 61469f8e09 Reindent to avoid many false warnings. 2025-05-12 21:36:49 -04:00
Thomas Harte 71343b5131 Add additional possible exception causes. 2025-05-12 21:34:59 -04:00
Thomas Harte 82caee6d7d Add potential LLDT exceptions. 2025-05-12 17:31:56 -04:00
Thomas Harte 275e75980c Take initial swing at LLDT. 2025-05-12 17:22:11 -04:00
Thomas Harte 2572da872a Improve consts, use concepts, reduce indentation. 2025-05-12 09:13:27 -04:00
Thomas Harte 6934618589 Add note to self. 2025-05-11 22:53:28 -04:00
Thomas Harte 01fd07c372 Merge pull request #1509 from TomHarte/GPFs
Implement per-access GPF checks.
2025-05-11 22:34:09 -04:00
Thomas Harte 02f9cf0318 Add basic partial GPF testing. 2025-05-11 22:24:21 -04:00
Thomas Harte 6bc586025a Attempt per-access part of GPF test. 2025-05-11 22:05:33 -04:00
Thomas Harte 0d34960d60 Properly place ownership of linear authorisation. 2025-05-11 21:36:36 -04:00
Thomas Harte 99b94a31ea Give descriptors knowledge of their indices. 2025-05-11 21:32:00 -04:00
Thomas Harte b0d4bcd26c Route all authorisation messages to a common receiver. 2025-05-11 21:08:02 -04:00
Thomas Harte 248ea52e06 Merge pull request #1508 from TomHarte/ExceptionBackfill
Improve IDT support.
2025-05-11 20:40:32 -04:00
Thomas Harte 9b51fe3db4 Take a shot at IDT dispatch. 2025-05-10 21:34:43 -04:00
Thomas Harte 5f95696815 Remove done TODO. 2025-05-05 22:56:24 -04:00
Thomas Harte 8c9df5556d Generalise support for multiple speeds. 2025-05-05 22:55:23 -04:00
Thomas Harte 32495f47b3 Bifurcate descriptor types. 2025-05-05 17:26:39 -04:00
Thomas Harte 23bc561524 Add note to self. 2025-05-04 22:21:37 -04:00
Thomas Harte fa2cc0f62e Proceed as far as believing I probably need a gate descriptor type. 2025-05-04 22:11:53 -04:00
Thomas Harte a686a167cc Factor out 'read descriptor'. 2025-05-04 21:03:17 -04:00
Thomas Harte 8a2468a4fb Apply IDT reset condition, factor in to real-mode interrupts. 2025-05-04 16:57:14 -04:00
Thomas Harte 4cc21a2c20 Include descriptor table and MSW requirements. 2025-05-03 23:01:31 -04:00
Thomas Harte 5350e41da1 Switch to mildly-more-modern template form. 2025-05-02 13:50:06 -04:00
Thomas Harte e07e6b6954 Merge pull request #1507 from TomHarte/Morex86Exceptions
Reformulate x86 exceptions.
2025-05-02 10:42:11 -04:00
Thomas Harte 0a60e38d82 Abandon Interrupt naming. 2025-05-02 10:23:20 -04:00
Thomas Harte f53b40e127 Focus on an Exception as the interrupt token. 2025-05-01 22:36:58 -04:00
Thomas Harte 4df51a00ed Try to be a bit more rigorous in exception generation syntax. 2025-05-01 17:17:29 -04:00
Thomas Harte 3981c4d101 Merge pull request #1506 from TomHarte/x86Concepts
Apply concepts to x86 interface.
2025-04-30 22:07:50 -04:00
Thomas Harte fc3e8f7cef Add memory subsystem requirements. 2025-04-30 21:30:36 -04:00
Thomas Harte f4d67ec5e6 Eliminate bad #include. 2025-04-29 22:32:29 -04:00
Thomas Harte 59aafa6c1e Add linear memory concept. 2025-04-29 22:28:23 -04:00
Thomas Harte 75da46dac5 Add CPU control concept. 2025-04-29 22:24:06 -04:00
Thomas Harte 1f1d380e26 Fill in flow-controller requirements. 2025-04-29 22:09:59 -04:00
Thomas Harte 35b3e425be Spell out registers requirements. 2025-04-29 22:06:59 -04:00
Thomas Harte b4535c489d Wrangle test for segments interface. 2025-04-29 21:55:17 -04:00
Thomas Harte f6bb502e87 Start bashing out an attempt at is_context. 2025-04-27 23:40:40 -04:00
Thomas Harte 6cf825d3d8 Lock down Intruction type. 2025-04-27 21:43:46 -04:00
Thomas Harte f766841fad Add usage-hint concepts. 2025-04-27 14:51:34 -04:00
Thomas Harte 10e4e7f6c6 Limit integer types. 2025-04-27 14:47:56 -04:00
Thomas Harte 1277e56435 Limit integers that can be the subject of accessors. 2025-04-27 14:44:07 -04:00
Thomas Harte 4089532f81 Merge pull request #1505 from TomHarte/OtherC++20Improvements
Make other scattered C++20 improvements.
2025-04-25 23:54:31 -04:00
Thomas Harte 9790b4d2e9 Throw in some consts. 2025-04-25 23:17:00 -04:00
Thomas Harte ad37c0d2ac Use std::rotr. 2025-04-25 23:10:09 -04:00
Thomas Harte b7a1fd4f8f Autodetect whether shift count could be a register. 2025-04-25 23:01:04 -04:00
Thomas Harte be5362e393 Eliminate builtin. 2025-04-25 23:00:36 -04:00
Thomas Harte 4977c9bc4c Further use rotl/r. 2025-04-25 22:53:11 -04:00
Thomas Harte e13dbc03da Make elementary use of rotl and rotr. 2025-04-25 22:37:43 -04:00
Thomas Harte 16fec0679b Use std::popcount further. 2025-04-25 22:24:00 -04:00
Thomas Harte 55361b8552 Remove unused popcount. 2025-04-25 22:18:39 -04:00
Thomas Harte cc67993621 Temporarily disable, in lieu of splitting memory. 2025-04-25 22:18:25 -04:00
Thomas Harte 49ba4998d6 Use std::popcount for parity. 2025-04-25 22:18:05 -04:00
Thomas Harte 03eb381b3b Adopt std::ranges::copy where it is trivial to do so. 2025-04-25 22:17:07 -04:00
Thomas Harte e5161faa43 Merge pull request #1504 from TomHarte/M_PI
Eliminate all references to M_PI.
2025-04-25 21:43:06 -04:00
Thomas Harte de78fb7a1c Eliminate all references to M_PI. 2025-04-24 21:57:29 -04:00
Thomas Harte a9ceb5e21a Merge pull request #1503 from TomHarte/C++20
Bump to C++20.
2025-04-24 21:52:01 -04:00
Thomas Harte e62b41f615 Avoid implicit capture of 'this' via '='. 2025-04-24 21:27:23 -04:00
Thomas Harte 592e339b70 Resolve syntax error, fix line lengths. 2025-04-24 21:12:17 -04:00
Thomas Harte 84a9138df7 Bump to C++20. 2025-04-24 20:56:15 -04:00
Thomas Harte 6db7c4a8eb Merge pull request #1502 from TomHarte/LocalFilesystemAccess
Make style corrections to the Enterprise and CPC.
2025-04-23 12:38:36 -04:00
Thomas Harte 213bd09a9c Remove test trap. 2025-04-23 11:36:29 -04:00
Thomas Harte 8eb246cdec Improve consts, line lengths. 2025-04-23 11:01:23 -04:00
Thomas Harte caacf8e373 Eliminate macros. 2025-04-23 10:51:49 -04:00
Thomas Harte c53d42a578 Eliminate macro. 2025-04-23 10:38:42 -04:00
Thomas Harte cfc5ef4a3c Eliminate risk of overrun. 2025-04-22 22:50:38 -04:00
Thomas Harte e78c1bbec9 Improve consts, indentation. 2025-04-22 22:42:13 -04:00
Thomas Harte b1582d33c0 Adjust indentation, remove one macro. 2025-04-22 21:45:36 -04:00
Thomas Harte 5abcf28a0e Merge pull request #1498 from TomHarte/Descriptors
Edge further along on x86 descriptors.
2025-04-22 21:23:17 -04:00
Thomas Harte 4cd57856ce Take ownership of 32-bit assumption. 2025-04-22 21:10:20 -04:00
Thomas Harte a826fd5c0e Add return. 2025-04-21 23:14:28 -04:00
Thomas Harte 7de23ec2aa Be specific about types. 2025-04-21 23:03:57 -04:00
Thomas Harte d7d2957319 Avoid fallthrough warning. 2025-04-21 22:57:07 -04:00
Thomas Harte fbd81b9930 Merge branch 'master' into Descriptors 2025-04-21 22:43:30 -04:00
Thomas Harte dacb52403a Merge pull request #1501 from TomHarte/NoVLAs
Eliminate VLAs, resolve some fallthrough warnings, reduce macros.
2025-04-21 15:24:40 -04:00
Thomas Harte e008a02b99 Shuffle further to avoid optics of a fallthrough. 2025-04-21 15:13:10 -04:00
Thomas Harte 9363453720 Reduce macros. 2025-04-21 15:00:49 -04:00
Thomas Harte 9c70615fd1 Trim maximum line length. 2025-04-21 15:00:02 -04:00
Thomas Harte 1c78c65816 Add missing constraint. 2025-04-21 09:19:36 -04:00
Thomas Harte 2a9a68ca53 Annotate further fallthroughs. 2025-04-21 09:15:55 -04:00
Thomas Harte fb16baab99 Add further fallthrough. 2025-04-20 23:39:26 -04:00
Thomas Harte 54f509c210 Enforce size restriction. 2025-04-20 23:27:44 -04:00
Thomas Harte 5be8e5eff3 Avoid improper fallthroughs. 2025-04-20 22:55:03 -04:00
Thomas Harte 29b9f129f6 Improve constness, line lengths, eliminate macros. 2025-04-20 22:33:44 -04:00
Thomas Harte f41629daae Add compiler-calming fallthroughs. 2025-04-20 22:19:11 -04:00
Thomas Harte feea6023f4 Eliminate macro. 2025-04-20 12:37:14 -07:00
Thomas Harte 262d8cd0d9 Enable further warnings. 2025-04-20 12:31:57 -07:00
Thomas Harte fbbec04f8c Update version check. 2025-04-20 12:29:03 -07:00
Thomas Harte 3e4eaee96b Overtly cast. 2025-04-20 12:27:38 -07:00
Thomas Harte 5f99a2240d Shorten lines; apply minor style fixes. 2025-04-20 12:26:37 -07:00
Thomas Harte 5937387e94 Overtly note fallthrough. 2025-04-20 11:55:07 -07:00
Thomas Harte b3099d8e71 Eliminate use of VLAs. 2025-04-12 14:34:57 -04:00
Thomas Harte 7721f74200 Further flesh out descriptors: decode all bits, add printf warnings. 2025-04-10 17:07:45 -04:00
Thomas Harte fa58cc05f3 Attempt to avoid type punning. 2025-04-06 22:48:22 -04:00
Thomas Harte c61a9e47b2 Slightly tweak constness. 2025-04-06 22:40:29 -04:00
Thomas Harte 148ee266ed Extend operator== path. 2025-04-06 22:37:59 -04:00
Thomas Harte 8ccec81cc6 Disable awaiting_eoi_. 2025-04-06 22:24:25 -04:00
Thomas Harte 668901f71d Fix comparison. 2025-04-06 22:24:09 -04:00
Thomas Harte ad6ad144a5 Don't regress PC for external interrupts. 2025-04-05 21:39:37 -04:00
Thomas Harte d5997a30b2 Reset output on latch write in applicable modes. 2025-04-04 12:30:08 -04:00
Thomas Harte ecc7501377 Avoid explicit instantiation, precedence error. 2025-04-03 22:09:49 -04:00
Thomas Harte 45262a1a46 Copy reload value to latch. 2025-04-03 21:59:26 -04:00
Thomas Harte 3c04e08df2 Ensure 16-bit ins and outs always occur as two 8-bit operations.
Advances the AT to system error 108, something about timer 2.
2025-04-03 19:52:40 -04:00
Thomas Harte 7c7675179e Restrict shift operand size, causing text output at last. 2025-04-03 17:42:15 -04:00
Thomas Harte 88ed49a833 Enable A20 at reset; fully propagate return to real mode. 2025-04-03 16:14:49 -04:00
Thomas Harte 0c88e62815 Add various caveman debugging comments. 2025-04-02 23:28:20 -04:00
Thomas Harte 88d34012c4 Continue trying to flesh out exceptions. 2025-04-02 23:27:43 -04:00
Thomas Harte 3be8de6fb0 Enforce set-only nature of protected mode bit. 2025-04-02 23:26:21 -04:00
Thomas Harte 804fbf5d5f Add [S/L]MSW. 2025-04-02 23:24:28 -04:00
Thomas Harte 1a68dcbc14 PUSH always pushes a word. 2025-04-02 23:24:00 -04:00
Thomas Harte a9a72a767d Improve fault pathways. 2025-04-01 09:13:41 -04:00
Thomas Harte afc3a8d373 Correct header path. 2025-03-31 09:54:11 -04:00
Thomas Harte da00e6588c Consolidate on class. 2025-03-31 09:34:17 -04:00
Thomas Harte d6376d0ddf Remove improper header. 2025-03-31 09:33:30 -04:00
Thomas Harte 1cca711560 Name MSW bits. 2025-03-30 14:04:43 -04:00
Thomas Harte 552f9196af Convert INTO, AAM; map which instructions post their IP. 2025-03-30 13:39:52 -04:00
Thomas Harte c6fa72cd83 Bring bound inside new orthodoxy. 2025-03-30 13:31:39 -04:00
Thomas Harte 42edc46887 Add invalid-opcode exception; transcribe has-code table. 2025-03-30 13:29:20 -04:00
Thomas Harte ec7e343673 Start to establish throw/catch of 80286 exceptions. 2025-03-30 13:23:36 -04:00
Thomas Harte 69d4d8acb0 Switch to construct and copy. 2025-03-29 17:27:29 -04:00
Thomas Harte a7eab8df22 Add getter for local descriptor table. 2025-03-29 17:24:30 -04:00
Thomas Harte 4247da9118 Add notes to self on exceptions. 2025-03-27 18:08:09 -04:00
Thomas Harte cfba8aeb89 Make style improvements. 2025-03-27 18:07:52 -04:00
Thomas Harte db26a26926 Fix decoding of PUSH immediate. 2025-03-27 13:07:13 -04:00
Thomas Harte 1551fbeb1f Make some stab at descriptor fetch. 2025-03-27 12:50:50 -04:00
Thomas Harte d5c53ca624 Set A20 line properly. 2025-03-26 21:51:43 -04:00
Thomas Harte b34702e370 Set an initial A20 state. 2025-03-26 07:35:17 -04:00
Thomas Harte 8b1543d9c9 Fuzz memory, setup FS and GS. 2025-03-25 17:16:36 -04:00
Thomas Harte e264375a97 Attempt to reintroduce 80286 support (as was). 2025-03-25 09:24:55 -04:00
Thomas Harte fd31d07f41 Begin division of memory into linear and segmented mappings. 2025-03-24 22:58:19 -04:00
Thomas Harte fac15f5539 Introduce a linear-memory holder. 2025-03-24 21:23:08 -04:00
Thomas Harte 6ad88101f1 Saunter up to a circular issue: segments needs memory access. 2025-03-24 17:31:17 -04:00
Thomas Harte 2768b66d10 Propagate mode change. 2025-03-22 23:00:51 -04:00
Thomas Harte d10164be26 Merge branch 'Descriptors' of github.com:TomHarte/CLK into Descriptors 2025-03-22 22:09:50 -04:00
Thomas Harte ce7ff13bbe Proceed to a local assert on LMSW. 2025-03-22 21:57:56 -04:00
Thomas Harte c1d2c159f3 Reenable backdoor AT. 2025-03-21 11:22:09 -04:00
Thomas Harte d3dbdb153c Use indexed descriptors. 2025-03-21 11:20:33 -04:00
Thomas Harte e7218c0321 Add means for indexed segment access. 2025-03-21 11:16:25 -04:00
Thomas Harte 48d8fdb875 Adopt descriptors in memory handling. 2025-03-21 10:18:26 -04:00
Thomas Harte b387ca921a Merge branch 'master' into Descriptors 2025-03-20 21:09:09 -04:00
Thomas Harte 53c1a322ed Increase version number. 2025-03-20 15:39:42 -04:00
Thomas Harte 0c502fc9cf Adopt more consistent 'Pointer' naming; eliminate size warning. 2025-03-20 15:33:07 -04:00
Thomas Harte 5d1e3b6c93 Create a home for descriptors. 2025-03-19 14:20:50 -04:00
Thomas Harte 7fc16fa2c8 Merge pull request #1495 from TomHarte/286StatusWord
Add extra 80286 registers.
2025-03-19 14:12:56 -04:00
Thomas Harte fe6a88c5df Install [L/S][I/G]DT wiring. 2025-03-18 22:11:28 -04:00
Thomas Harte 7b14df82e0 Merge branch 'master' into 286StatusWord 2025-03-18 21:47:32 -04:00
Thomas Harte 966b41313d Merge pull request #1497 from TomHarte/LargeWindowMousing
Correct potential SCSI crash; tweak macOS mouse behaviour.
2025-03-18 21:46:41 -04:00
Thomas Harte 91f1c3322c Ensure tracking areas are updated. 2025-03-18 21:12:48 -04:00
Thomas Harte 0b276c5a76 Remove focus rings. 2025-03-18 20:38:09 -04:00
Thomas Harte b654c2e170 Avoid potential out-of-bounds access. 2025-03-18 20:23:31 -04:00
Thomas Harte 32c88da6c4 Iterate towards LGDT/LIDT.
Specifically: add a means to get just an indirect address; add an enum for descriptor tables; add an `ldt` function for the global and interrupt tables, which currently just authorises the access and then stops.
2025-03-18 18:22:04 -04:00
Thomas Harte 3d19d0816b Do something for SMSW. 2025-03-16 22:05:14 -04:00
Thomas Harte 15da707324 Merge pull request #1494 from TomHarte/MoreAT
AT: adjust reported RAM refresh timing.
2025-03-16 15:54:27 -04:00
Thomas Harte 387e8b04f9 Adjust reported refresh timing. 2025-03-16 15:44:05 -04:00
Thomas Harte 4ca47be8a8 Add const. 2025-03-15 22:21:35 -04:00
Thomas Harte f9d9dc68b7 Factor out BIOS installation. 2025-03-15 22:19:26 -04:00
Thomas Harte 14a8f4511c Merge pull request #1492 from TomHarte/ATBIOS
Support real IBM BIOS, either in odd/even or complete form.
2025-03-15 22:12:54 -04:00
Thomas Harte 97d237eed0 Support real IBM BIOS, either in odd/even or complete form. 2025-03-15 21:13:31 -04:00
Thomas Harte 20d0406a24 Merge pull request #1491 from TomHarte/PUSHA
Fix PUSHA register list; add illegal asserts.
2025-03-14 22:27:19 -04:00
Thomas Harte 73e843abd3 Assert on some hopefully unreachables. 2025-03-12 22:03:12 -04:00
Thomas Harte 8d956da65b Correct final thing written to stack by PUSHA. 2025-03-12 21:40:03 -04:00
Thomas Harte 9b9cdfe937 Merge pull request #1489 from TomHarte/MinorExtraStrings
Slightly improve x86 instruction to string lexicon.
2025-03-12 21:34:18 -04:00
Thomas Harte 3dcba9362c Add a couple of missing Operation:: mappings. 2025-03-12 13:51:38 -04:00
Thomas Harte 2d3a3ada57 Add AccessType to string conversion. 2025-03-12 13:51:17 -04:00
Thomas Harte 143d1d5e35 Merge pull request #1488 from TomHarte/ATKeyboard
Implement some proportion of the AT keyboard controller.
2025-03-12 13:19:15 -04:00
Thomas Harte 13b32b269c Force the AT in debug mode only. 2025-03-12 12:47:04 -04:00
Thomas Harte 592cea6a27 Tweak timing to once again pass BIOS controller test. 2025-03-12 12:31:29 -04:00
Thomas Harte e76ca304e6 Attempt to support 60 and c0. 2025-03-11 22:54:54 -04:00
Thomas Harte d77d8df1ac Add closer-to-real keyboard command loop. 2025-03-11 22:35:13 -04:00
Thomas Harte 4f35d5dabd Log A20 line. 2025-03-09 23:09:58 -04:00
Thomas Harte e927feb2d6 Reintroduce is-tested flag. 2025-03-08 21:59:40 -05:00
Thomas Harte 98f20c57c1 Attempt to support reset-by-8042, resulting in boot loop. 2025-03-08 00:47:56 -05:00
Thomas Harte 7a88d31fd9 Add include for strlen. 2025-03-07 23:47:34 -05:00
Thomas Harte 96326411bf Move explicit specialization to namespace scope. 2025-03-07 23:41:56 -05:00
Thomas Harte 4e882e7d4d Accept uint8_ts only. 2025-03-07 23:36:47 -05:00
Thomas Harte bff10c1714 Resolve newfound log ambiguity. 2025-03-07 23:34:12 -05:00
Thomas Harte cee2484108 Flip input/output, perform commands instantly. 2025-03-07 23:32:07 -05:00
Thomas Harte 93078abe87 Buffer lines prior to output. 2025-03-07 23:25:22 -05:00
Thomas Harte 8caa1a9664 Experiment with dialogue. 2025-03-07 14:24:08 -05:00
Thomas Harte d7b46ee03c Adopt compact form. 2025-03-07 14:23:50 -05:00
Thomas Harte e07b3da983 Add commentary; start fleshing out AT keyboard controller. 2025-03-07 14:01:59 -05:00
Thomas Harte 0f166cee48 Merge pull request #1487 from TomHarte/PCSeparate
Separate the speaker, and keyboard and floppy controllers.
2025-03-07 14:01:19 -05:00
Thomas Harte 08df42d05b Just 'POST' is fine. 2025-03-07 13:46:07 -05:00
Thomas Harte 2c165c3873 Avoid repetition of 'PC'. 2025-03-07 13:44:49 -05:00
Thomas Harte 9135402d9e Extract keyboard controller. 2025-03-07 13:43:21 -05:00
Thomas Harte 53135ec2c0 Extract floppy controller, speaker. 2025-03-07 13:39:45 -05:00
Thomas Harte 4eb8c8dea9 Merge pull request #1485 from TomHarte/FurtherATDMA
Add second PIC and DMA controllers.
2025-03-06 22:46:55 -05:00
Thomas Harte f318bec53c Reduce indentation, improve constness. 2025-03-06 22:33:58 -05:00
Thomas Harte 7d84d6909e Add TODO. 2025-03-06 22:16:51 -05:00
Thomas Harte 9224645473 Add second PIC. 2025-03-06 22:15:58 -05:00
Thomas Harte 6717771f9a Rejig doubling of DMA controllers. 2025-03-05 23:02:08 -05:00
Thomas Harte 99e0902b74 Reconnect speaker. 2025-03-05 21:51:50 -05:00
Thomas Harte c7f2805b05 Install the AT keyboard controller. 2025-03-05 21:28:22 -05:00
Thomas Harte 6e1909647b Reformat; hatch separate AT keyboard controller; print POST codes. 2025-03-05 21:08:53 -05:00
Thomas Harte 0c7db56e15 Merge branch 'master' into FurtherATDMA 2025-03-05 16:34:50 -05:00
Thomas Harte 3287ca449e Update macOS version number. 2025-03-05 16:23:23 -05:00
Thomas Harte 53a8f65ecc Merge branch 'master' into FurtherATDMA 2025-03-05 16:03:46 -05:00
Thomas Harte 113035b374 Merge pull request #1486 from TomHarte/macOSCrashes
macOS: Don't crash if mouse exits window while picking machine.
2025-03-05 16:03:04 -05:00
Thomas Harte c6e64837c3 Don't crash if mouse moves while picking machine. 2025-03-05 15:51:31 -05:00
Thomas Harte 82419e6df1 Revoke 'ForceAT', **again**. 2025-03-05 14:34:44 -05:00
Thomas Harte faa76ee017 Not quite accurate, but segment out keyboard writes for the AT. 2025-03-05 14:33:55 -05:00
Thomas Harte ffdefb4106 Don't crash if mouse moves while picking machine. 2025-03-05 14:27:33 -05:00
Thomas Harte ba7b1c47b9 Improve constness, reduce trips to system clock. 2025-03-05 14:17:31 -05:00
Thomas Harte 342b8105c4 Improve constness. 2025-03-04 22:53:26 -05:00
Thomas Harte 367c2b568a Attempt to offer expanded DMA top bytes. 2025-03-04 22:51:17 -05:00
Thomas Harte 0eef2c0d04 Merge pull request #1484 from TomHarte/286Decoding
Repair 286 decoding and `perform`.
2025-03-04 21:21:16 -05:00
Thomas Harte c9a065107b Further tweak ENTER. 2025-03-04 21:08:59 -05:00
Thomas Harte cacacc00f6 Undo ForceAT. 2025-03-04 20:56:38 -05:00
Thomas Harte 1b94cfc72c Add nullptr backstop. 2025-03-04 20:46:10 -05:00
Thomas Harte 89fd41124f Template various bits of hardware on machine type. 2025-03-04 17:08:49 -05:00
Thomas Harte 4e3b0ae3c1 Resolve type warnings in ENTER, spurious new lines in PC. 2025-03-04 14:10:28 -05:00
Thomas Harte 9df6d535e2 Patch up enough to get an 80286 performer compilable. 2025-03-04 13:52:02 -05:00
Thomas Harte d545cce276 Merge pull request #1483 from TomHarte/PC-AT
Tee up for an AT-class PC.
2025-03-04 11:57:09 -05:00
Thomas Harte 71b481d3be Bake PC model into template. 2025-03-04 11:45:56 -05:00
Thomas Harte 2710acaae6 Avoid repeating CPU model, normalise member names. 2025-03-04 11:35:11 -05:00
Thomas Harte d79135ea01 Eliminate non-functional workaround. 2025-03-04 11:30:43 -05:00
Thomas Harte 1464011f6f Try throwing some externs at it. 2025-03-04 11:23:55 -05:00
Thomas Harte 409c8a6859 Keep poking at this. 2025-03-04 11:10:35 -05:00
Thomas Harte 805ce36592 Fix spelling, namespace. 2025-03-04 11:01:07 -05:00
Thomas Harte 07fa56c53d Get heavier with GCC workarounds. 2025-03-04 10:56:45 -05:00
Thomas Harte 28fca80023 Attempt lighter GCC workaround. 2025-03-04 10:46:14 -05:00
Thomas Harte 08c0ee9ca8 Fix further speed reference; eliminate Decoder8086 entirely. 2025-03-04 10:35:16 -05:00
Thomas Harte 2878ab1578 Update Qt UI. 2025-03-04 10:25:27 -05:00
Thomas Harte 16f850cbcc Attempt to eliminate Decoder8086. 2025-03-04 10:13:57 -05:00
Thomas Harte b9177e50d3 Commute 'speed' to 'model approximation'. 2025-03-04 09:57:34 -05:00
Thomas Harte c3258551d7 Merge pull request #1481 from TomHarte/x86Macros
Reduce macros in x86 decoder.
2025-03-03 23:27:39 -05:00
Thomas Harte ea0799c546 Transition off printf. 2025-03-03 23:17:52 -05:00
Thomas Harte 4843b7f7b8 Update name expectations. 2025-03-01 22:35:15 -05:00
Thomas Harte 61694c625e Merge branch 'master' into x86Macros 2025-02-28 22:53:19 -05:00
Thomas Harte 64b4b99d48 Shave icon. 2025-02-28 22:24:06 -05:00
Thomas Harte dad966b551 Merge pull request #1482 from TomHarte/IconAndReadme
Update README icon, mention Plus 4.
2025-02-28 22:10:51 -05:00
Thomas Harte e46f503641 Try icon below title. 2025-02-28 22:09:21 -05:00
Thomas Harte fc4a1e6ace Revert "See whether this affects title underlining."
This reverts commit 02b9a20c11.
2025-02-28 22:07:21 -05:00
Thomas Harte 02b9a20c11 See whether this affects title underlining. 2025-02-28 22:07:00 -05:00
Thomas Harte 1db4e4caed Try for on-left with wrapping. 2025-02-28 22:06:14 -05:00
Thomas Harte 991e176c85 Try as raw HTML. 2025-02-28 22:05:30 -05:00
Thomas Harte 4a41a6bb85 Try right alignment. 2025-02-28 22:04:30 -05:00
Thomas Harte 6229e1049b Move icon to other side of text. 2025-02-28 22:03:25 -05:00
Thomas Harte 3cfd6ed109 Experiment with top-line layout. 2025-02-28 22:02:41 -05:00
Thomas Harte ad70180edd Update README icon, mention Plus 4. 2025-02-28 22:01:29 -05:00
Thomas Harte efd4a83bd2 Remove dead #undefs. 2025-02-28 21:55:52 -05:00
Thomas Harte e13b4ab7c9 Reduce reliance upon macros. 2025-02-28 21:51:44 -05:00
Thomas Harte fee89cbaad Switch to absolute include paths. 2025-02-28 14:53:48 -05:00
Thomas Harte 2bdcba437c Fix include path. 2025-02-28 13:27:36 -05:00
Thomas Harte 2c2216afae Further eliminate file-relative includes. 2025-02-28 13:18:48 -05:00
Thomas Harte 0823fc32fe Eliminate file-relative paths. 2025-02-28 12:30:25 -05:00
Thomas Harte 091d19caf5 Qt: overtly add project home as include path. 2025-02-28 11:34:27 -05:00
Thomas Harte 00a7381f08 Add top-level base for includes. 2025-02-28 11:32:44 -05:00
Thomas Harte d494d1e3ee Add SConstruct top-level include path. 2025-02-28 11:30:08 -05:00
Thomas Harte b1c331a1df Add a canary for include paths. 2025-02-28 11:26:43 -05:00
Thomas Harte b1a4fd085b Permit project-relative includes. 2025-02-27 18:37:33 -05:00
Thomas Harte 511ab2afe9 Merge pull request #1478 from TomHarte/C++23SDL
Bump macOS SDL target to C++23; fix incompatibilities.
2025-02-27 18:36:23 -05:00
Thomas Harte 30387ad654 Merge branch 'master' into C++23SDL 2025-02-27 18:34:01 -05:00
Thomas Harte 5d528ee1f3 Merge pull request #1479 from TomHarte/x86Documentation
Improve x86 `const`ness.
2025-02-27 18:33:20 -05:00
Thomas Harte 96bb4d50ba Promote macOS SDL target to C++23 as a testing chamber; resolve issues. 2025-02-27 18:13:35 -05:00
Thomas Harte 45f850adae Improve constness. 2025-02-27 15:47:06 -05:00
Thomas Harte 09341ddbe9 Merge pull request #1477 from TomHarte/C++20Deprecations
Resolve two immediate warnings in a C++20 test build.
2025-02-27 15:29:41 -05:00
Thomas Harte eab4274737 Capture 'this' by reference. 2025-02-27 11:56:51 -05:00
Thomas Harte 49fec1bc10 Remove meaningless 'volatile'. 2025-02-27 11:56:24 -05:00
Thomas Harte de164469c4 Update version, copyright string. 2025-02-26 21:30:41 -05:00
Thomas Harte f595871cd9 Merge pull request #1476 from TomHarte/MoreChangeEffects
Widen media change observation.
2025-02-26 21:23:19 -05:00
Thomas Harte ff86cbd48e Remove more get_s. 2025-02-26 20:26:06 -05:00
Thomas Harte 47bd4dade5 Avoid direct cstdio where meaningful. 2025-02-26 18:04:13 -05:00
Thomas Harte ff8180920f Simplify extension finder, 80/81 file grabbing. 2025-02-26 17:17:24 -05:00
Thomas Harte d4f08f0006 Remove get_. 2025-02-26 17:09:47 -05:00
Thomas Harte 1db756063b Further remove type info from function naming. 2025-02-26 16:00:34 -05:00
Thomas Harte b44ea31bbf Deal with default sizes delcaratively. 2025-02-26 11:33:38 -05:00
Thomas Harte ddccb946ff Fix precedence error in put_le. 2025-02-25 23:24:11 -05:00
Thomas Harte 1f6f30ae9e Implement MediaChangeObserver for the consoles. 2025-02-25 23:03:45 -05:00
Thomas Harte 4b19a3f4ed Split interface, make const. 2025-02-25 22:58:36 -05:00
Thomas Harte c39d0ce2f7 Add note to self. 2025-02-25 22:37:12 -05:00
Thomas Harte cbdf1a941c Merge pull request #1475 from TomHarte/FileDidChange
macOS: Reinsert media and/or restart machines upon underlying file changes.
2025-02-24 23:12:17 -05:00
Thomas Harte a340635de5 Fix lost audio, race condition. 2025-02-24 23:04:41 -05:00
Thomas Harte d62362db1a Reduce copy and paste. 2025-02-24 22:50:56 -05:00
Thomas Harte a0aba69306 Resolve lost options. 2025-02-24 22:46:44 -05:00
Thomas Harte 765683cd34 Copy and paste to a mostly working substitution. 2025-02-24 22:44:10 -05:00
Thomas Harte 93ddf4f0ba Ensure ZX Spectrum, at least, returns correct indication. 2025-02-24 22:34:15 -05:00
Thomas Harte 8dcccf11bf Improve constness, remove unnecessary virtuals. 2025-02-24 18:18:12 -05:00
Thomas Harte 43353ce892 Confirm and wire through semantics. 2025-02-24 15:36:18 -05:00
Thomas Harte a698fea078 Spell out some options. 2025-02-23 18:15:14 -05:00
Thomas Harte 390d9b0fe1 Add further note to self. 2025-02-22 23:12:41 -05:00
Thomas Harte fd3ff05b17 Avoid undefined behaviour on left shift. 2025-02-22 23:06:40 -05:00
Thomas Harte a5e4c9dd7b Add pure file-content change observer. 2025-02-22 22:40:15 -05:00
Thomas Harte 37f07dcc5a Add note to self on intentions. 2025-02-21 17:51:14 -05:00
Thomas Harte 75bae9a59c Merge pull request #1474 from TomHarte/LighterMouseovers
Adjust macOS UI to show options/volume only when _directly_ mouseovered.
2025-02-21 12:42:15 -05:00
Thomas Harte 1684d88a3b Don't hide mouse cursor if over an interesting subview. 2025-02-21 11:43:47 -05:00
Thomas Harte 50acbb70da Rename protocol method. 2025-02-21 11:37:37 -05:00
Thomas Harte 4de1025468 Avoid potential MSX 2 crash at startup. 2025-02-21 11:37:24 -05:00
Thomas Harte c2506dd115 Show controls immediately at startup. 2025-02-21 11:31:13 -05:00
Thomas Harte f8c9aa8e6c Require mouseover near the volume/controls to activate. 2025-02-21 11:28:53 -05:00
Thomas Harte e19dc1f067 Make scan target the window's native view. 2025-02-21 10:43:56 -05:00
Thomas Harte 84776bced1 Merge pull request #1473 from TomHarte/BetterBitReader
Slim FileHolder; improve and extract BitSerialiser.
2025-02-20 23:03:39 -05:00
Thomas Harte 9162c86e21 Test, improve BitStream. 2025-02-20 22:42:02 -05:00
Thomas Harte 88ffcbc62b Work in terms of the number of bits to be handled. 2025-02-19 22:04:51 -05:00
Thomas Harte 6aff0b74cd Reduce redundant types. 2025-02-19 00:09:57 -05:00
Thomas Harte 79671890c5 Generalise and improve BitStream. 2025-02-18 23:17:39 -05:00
Thomas Harte edd4ed307f Template away repetition. 2025-02-18 22:48:47 -05:00
Thomas Harte f786f8a970 Merge pull request #1472 from TomHarte/FastPRGs
Withdraw PRG support for the Plus 4.
2025-02-18 21:57:32 -05:00
Thomas Harte a1d10adaa3 Support only the Vic-20 for PRGs for now. 2025-02-18 20:46:43 -05:00
Thomas Harte 7f480e8e56 Swing desperately at fast tape loading. 2025-02-11 21:49:58 -05:00
Thomas Harte 94b972aaf4 Improve style. 2025-02-11 21:48:56 -05:00
Thomas Harte 9470775292 Avoid race condition on input/output frequencies. 2025-02-11 21:48:23 -05:00
Thomas Harte 93eb63d930 Add interrupt register to TED check set. 2025-02-11 21:47:36 -05:00
Thomas Harte ea81096a43 Reinstall debugging temporariness. 2025-02-07 18:09:33 -05:00
Thomas Harte 594045b4e7 Merge pull request #1471 from TomHarte/CRCInterface
Remove need for a CRC generator instance.
2025-02-05 22:18:59 -05:00
Thomas Harte 1449330ed3 Use updated interface. 2025-02-04 23:14:49 -05:00
Thomas Harte 07493a6b18 Remove need for a CRC generator instance. 2025-02-04 22:54:39 -05:00
Thomas Harte 0310db5f24 Merge pull request #1470 from TomHarte/SimplerReverse
Unify and simplify bit reversal functions.
2025-02-04 21:49:57 -05:00
Thomas Harte ed6d5a7d38 Correct test target. 2025-02-04 00:05:09 -05:00
Thomas Harte ca7c1bc631 Remove redundant inlines. 2025-02-04 00:00:12 -05:00
Thomas Harte 259070c658 Unify reverse functions. 2025-02-03 23:58:41 -05:00
Thomas Harte e1a7dd9b24 Implement recursive reverse. 2025-02-03 23:50:15 -05:00
Thomas Harte e5945fbb3d Merge pull request #1469 from TomHarte/AllWarnings
Resolve all current compiler warnings.
2025-02-03 22:08:12 -05:00
Thomas Harte 247f636988 Reinstate ZRLE support. 2025-02-03 21:56:12 -05:00
Thomas Harte c58a2ee624 Remove redundant moves. 2025-02-03 21:44:30 -05:00
Thomas Harte 35a1b44c21 Remove unused elements. 2025-02-03 21:42:07 -05:00
Thomas Harte fd09f06507 Merge pull request #1468 from TomHarte/Qt6CI
Reinstate Xcode CI.
2025-02-03 21:34:36 -05:00
Thomas Harte d66b501a99 Request latest Xcode. 2025-02-03 21:27:53 -05:00
Thomas Harte 349f6766ac Switch to array. 2025-02-03 21:24:05 -05:00
Thomas Harte cd55ed1514 Persevere. 2025-02-03 21:22:50 -05:00
Thomas Harte 14d4c8accc Disable Qt 6; try to reenable Xcode. 2025-02-03 21:21:25 -05:00
Thomas Harte 37bca96bde Strip back. 2025-02-03 21:17:19 -05:00
Thomas Harte b0e6ae58c4 Try 6.7. 2025-02-03 21:00:40 -05:00
Thomas Harte 0375e47359 Accept any 6.8. 2025-02-03 20:48:56 -05:00
Thomas Harte 8450ad2856 Add Qt 6 CI. 2025-02-03 20:28:46 -05:00
Thomas Harte 015a1fbd53 Merge branch 'master' into Plus4PRGs 2025-02-03 00:06:14 -05:00
Thomas Harte 318b61b4d7 Merge pull request #1467 from TomHarte/QtCI
Add Qt to CI set.
2025-02-03 00:05:54 -05:00
Thomas Harte 60640517ca Remove crutch. 2025-02-02 23:58:25 -05:00
Thomas Harte 051e38f034 Reformat. 2025-02-02 23:48:20 -05:00
Thomas Harte 300054b9f7 Attempt a full make. 2025-02-02 23:46:26 -05:00
Thomas Harte 4f9e1e3a6b Add 'icu'. 2025-02-02 23:41:47 -05:00
Thomas Harte 856bc27bf1 Must specify qtbase, at least. 2025-02-02 23:36:15 -05:00
Thomas Harte 408b774b42 Switch to archives. 2025-02-02 23:29:59 -05:00
Thomas Harte f82ef5aad4 Apply one of those architectures. 2025-02-02 23:23:34 -05:00
Thomas Harte a92df41eb5 List architectures, hopefully. 2025-02-02 22:58:32 -05:00
Thomas Harte 605990929d Hit and hope. 2025-02-02 22:47:23 -05:00
Thomas Harte 925ca28659 Try without architecture. 2025-02-02 22:38:31 -05:00
Thomas Harte 41e3fa7aa7 Retreat. 2025-02-02 22:24:37 -05:00
Thomas Harte 5fa27448f8 Try to coax module names. 2025-02-02 22:19:44 -05:00
Thomas Harte c3428bdaed Try without prefixes. 2025-02-02 22:11:32 -05:00
Thomas Harte 0539de9c4e Take a guess at modules. 2025-02-02 22:05:36 -05:00
Thomas Harte eed87164b1 Attempt a Qt build action. 2025-02-02 22:00:21 -05:00
Thomas Harte 0fe726c503 Avoid overlong line. 2025-02-02 21:50:30 -05:00
Thomas Harte f7f2113f1c Merge pull request #1465 from TomHarte/Plus4FastLoad
Edge towards fast loading in the Plus 4.
2025-02-02 21:49:22 -05:00
Thomas Harte 49d931f5cc Disable Mac job for now. 2025-02-02 21:41:37 -05:00
Thomas Harte 4dbd63de08 Attempt version rebump. 2025-01-31 12:33:21 -05:00
Thomas Harte 3a53c349a0 Abandon attempts to build on older macOS for now. 2025-01-31 11:45:43 -05:00
Thomas Harte a9fe5d5c87 Manually revert Xcode project version. 2025-01-30 22:48:11 -05:00
Thomas Harte 9cecccf5da Correct TAP type check. 2025-01-30 21:04:36 -05:00
Thomas Harte 6cb3bbaa2d Ensure tape ending != infinite loop. 2025-01-29 23:30:16 -05:00
Thomas Harte 0ff6a0bb53 Slightly simplify template arguments. 2025-01-29 22:51:02 -05:00
Thomas Harte 8ba57dec03 Take another stab at read_dipole. 2025-01-29 22:07:17 -05:00
Thomas Harte d749c305ed Merge branch 'master' into Plus4FastLoad 2025-01-28 20:20:21 -05:00
Thomas Harte f46ac2d0ed Merge pull request #1464 from TomHarte/AheadOfTimeCRCTables
Grab bag: calculate CRC tables ahead of time; improve carry typing.
2025-01-28 20:16:03 -05:00
Thomas Harte d7b7152315 Apply const liberally. 2025-01-28 18:26:34 -05:00
Thomas Harte da1d52033b Use contractions. 2025-01-28 18:19:31 -05:00
Thomas Harte 01ddc24c02 Require overt acknowledgement of meaning. 2025-01-28 17:42:26 -05:00
Thomas Harte 53a3e88d16 Shunt CRC XOR table generation to compile time. 2025-01-28 17:36:32 -05:00
Thomas Harte bc8d1cc384 Merge pull request #1463 from TomHarte/AcornAnalyserStyle
Tweak Acorn analyser style.
2025-01-26 21:58:50 -05:00
Thomas Harte ed2ba63a5f Adjust style. 2025-01-26 21:42:38 -05:00
Thomas Harte 8a2c009653 Reduce copies, size()s, code duplication. 2025-01-26 21:34:01 -05:00
Thomas Harte 55690a4c7f Merge branch 'master' into Plus4FastLoad 2025-01-22 19:49:23 -05:00
Thomas Harte 161ad4b143 Merge pull request #1462 from TomHarte/VIAPortTemplate
Reduce repetitive dynamic work in 6522 usages.
2025-01-22 19:48:24 -05:00
Thomas Harte d701990df4 Simplify ownership of the shift value. 2025-01-22 16:12:45 -05:00
Thomas Harte 95a2d1013c Remove unused dynamic dispatcher. 2025-01-22 16:06:09 -05:00
Thomas Harte 5d4f3c0b3e Remove already-done TODO. 2025-01-22 16:04:17 -05:00
Thomas Harte f8e4023307 Reduce repetitive dynamic work in 6522 usages. 2025-01-22 15:57:03 -05:00
Thomas Harte 609aba7c73 Made various additional style improvements. 2025-01-22 13:47:25 -05:00
Thomas Harte bc7ab0eba1 Extend parser, accelerate headers. 2025-01-21 22:37:10 -05:00
Thomas Harte 56f271c8ad Continue failing. This is the story of my life. 2025-01-21 17:24:12 -05:00
Thomas Harte 11190cff1d Eject zero-cost execution in favour of faulty HLE. 2025-01-21 16:45:05 -05:00
Thomas Harte 348a593dc1 Flail in attempt to implement fast loading. 2025-01-21 14:13:42 -05:00
Thomas Harte b67bb50f4a Merge pull request #1461 from TomHarte/Vic20Confidence
Include VIC hits in Vic-20 confidence selection.
2025-01-20 23:21:19 -05:00
Thomas Harte 1174f651ab Switch to logger, ignore 0xfdfx. 2025-01-20 22:47:54 -05:00
Thomas Harte dad9777c3e Merge pull request #1460 from TomHarte/Plus4DriveSelection
Add C1541 button to mac UI; respect Target setting.
2025-01-20 22:45:49 -05:00
Thomas Harte 4f6285a8e7 Include VIC hits in Vic-20 confidence selection. 2025-01-20 22:25:24 -05:00
Thomas Harte 20cecf4702 Add C1541 button to mac UI; respect Target setting. 2025-01-20 22:02:35 -05:00
Thomas Harte 5763eabff4 Merge pull request #1459 from TomHarte/UnitTestUpdates
Repair lagging unit tests.
2025-01-20 21:41:15 -05:00
Thomas Harte 0fc753949d Repair lagging unit tests. 2025-01-20 21:36:25 -05:00
Thomas Harte 083c1b7ca7 Merge pull request #1458 from TomHarte/Plus4PRGs
Introdice alternative tape timings for the +4.
2025-01-20 20:59:33 -05:00
Thomas Harte 8f6b1b11e5 Fix member name. 2025-01-20 20:35:14 -05:00
Thomas Harte 53b7d19c10 Ensure tape images proper destruct. 2025-01-20 20:33:17 -05:00
Thomas Harte b0b4f5e51a Add Plus 4 to Qt UI. 2025-01-20 20:31:12 -05:00
Thomas Harte b7414aa59c Improve logging. 2025-01-20 16:19:02 -05:00
Thomas Harte f449045118 Add some basic attempts at dynamic analysis. 2025-01-20 16:15:53 -05:00
Thomas Harte 1e9ddada37 Retain tapes and disks. 2025-01-20 15:51:01 -05:00
Thomas Harte 55d59a1854 Separate chunk parsing. 2025-01-19 18:16:33 -05:00
Thomas Harte beb9f38514 Eliminate std::shared_ptr. 2025-01-18 23:25:08 -05:00
Thomas Harte 00b1865fc8 Fix boundary condition. 2025-01-17 21:46:43 -05:00
Thomas Harte 0f545608c4 Fix serialiser ownership, Commodore analyser. 2025-01-17 21:43:11 -05:00
Thomas Harte bde2047184 Provide target platform where serialiser will accept it. 2025-01-17 17:09:47 -05:00
Thomas Harte 0a22d8fb9e Add TODO on final dangling issue. 2025-01-17 17:06:03 -05:00
Thomas Harte 1bef37d504 Test data only once. 2025-01-17 17:04:25 -05:00
Thomas Harte 7f5d290b66 Promote validation. 2025-01-17 17:01:09 -05:00
Thomas Harte 9461e6f285 Move validation up a level. 2025-01-17 16:59:30 -05:00
Thomas Harte 3f59a03f29 Parse Commodore .tap header only once. 2025-01-17 16:54:54 -05:00
Thomas Harte 062b581b55 Move .cas and ZX .tap initial parsing out of serialiser. 2025-01-17 16:45:09 -05:00
Thomas Harte 58d3fdc1c2 Separate stateful serialisation from tapes. 2025-01-17 16:39:21 -05:00
Thomas Harte 2f546842a7 Wire TAPs and similar directly to their targets. 2025-01-16 21:21:15 -05:00
Thomas Harte f089a85908 Zoom out to a more likely TV cropping. 2025-01-15 22:52:20 -05:00
Thomas Harte a6e453a452 Introdice alternative tape timings for the +4. 2025-01-15 22:11:26 -05:00
Thomas Harte 3adf3dc547 Merge pull request #1457 from TomHarte/BadlinePriority
Give priority to initial bad lines.
2025-01-13 20:40:17 -05:00
Thomas Harte 1d0ea96ae9 This hasn't been true for a while. 2025-01-13 17:38:29 -05:00
Thomas Harte a4cb17a1cb First bad lines take priority over second ones. 2025-01-13 17:31:18 -05:00
Thomas Harte 733da3161b Merge pull request #1456 from TomHarte/CounterSets
Correct shift on hcount write.
2025-01-12 22:32:46 -05:00
Thomas Harte 1b1a0f553d Keep three least bits. 2025-01-12 22:07:56 -05:00
Thomas Harte 972619c1fe Correct shift on hcount write. 2025-01-12 21:59:22 -05:00
Thomas Harte 61086d5360 Merge pull request #1455 from TomHarte/MatchBefore
Restructure loop to perform events AT time, not upon reaching it.
2025-01-12 19:18:32 -05:00
Thomas Harte 37513d726c Restructure loop to perform events AT time, not upon reaching it. 2025-01-12 19:06:42 -05:00
Thomas Harte 6510bee327 Merge pull request #1454 from TomHarte/VideoTweaks
Restrict counter sizes; invert written horizontal counter.
2025-01-11 23:42:58 -05:00
Thomas Harte cd36f3f096 Restrict counter sizes; invert written horizontal counter. 2025-01-11 23:19:01 -05:00
Thomas Harte 407a6f5e31 Merge pull request #1453 from TomHarte/AbsentBits
Correct status unset-bit masks.
2025-01-11 22:58:42 -05:00
Thomas Harte 2b28df280e Correct status unset-bit masks. 2025-01-11 22:47:56 -05:00
Thomas Harte eb763ed82c Merge pull request #1452 from TomHarte/TapeMotorAgain
Ensure tape motor is a combination of programmed state and button.
2025-01-10 21:04:19 -05:00
Thomas Harte 755f53cce0 Ensure tape motor is a combination of programmed state and button. 2025-01-10 16:59:09 -05:00
Thomas Harte c190ab40b0 Merge pull request #1451 from TomHarte/Plus4Joystick
Add joystick input.
2025-01-09 17:12:37 -05:00
Thomas Harte a3ad82de42 Add joystick input. 2025-01-09 17:01:20 -05:00
Thomas Harte 0f6cd6904d Separate keyboard and joystick masks.
Based on aside in https://plus4world.powweb.com/forum/6867#6868 ; I don't yet know what the joystick bits are.
2025-01-09 16:41:21 -05:00
Thomas Harte 79c89af6ea Merge pull request #1450 from TomHarte/LatestWarnings
Resolve GCC ubuntu-latest build warnings.
2025-01-09 16:32:50 -05:00
Thomas Harte 56f10a9a52 Adjust ownership to avoid passing reference to uninitialised object. 2025-01-09 16:27:19 -05:00
Thomas Harte c679e2c067 line_number is now unused. 2025-01-09 16:14:16 -05:00
Thomas Harte 0677987320 Ensure all paths return a value. 2025-01-08 22:30:32 -05:00
Thomas Harte 5fb6e6780c Eliminate unused variable (at least temporarily). 2025-01-08 22:30:17 -05:00
Thomas Harte 58ef91a7b1 Merge pull request #1449 from TomHarte/FullerAudio
Switch to full-clock PWM audio implementation, with noise generator.
2025-01-08 22:28:01 -05:00
Thomas Harte e1ae65b6d1 Switch to PWM implementation, with noise. 2025-01-08 22:09:42 -05:00
Thomas Harte 65307186dc Provide full clock to audio. 2025-01-08 21:17:48 -05:00
Thomas Harte 6fa29c204b Extend PAL/NTSC selection to audio. 2025-01-08 20:27:37 -05:00
Thomas Harte 8219beeb1a Merge pull request #1448 from TomHarte/6502Macros
Eliminate macros from 6502 bus operation actions.
2025-01-08 20:19:09 -05:00
Thomas Harte ace7e24dfb Eliminate Objective-C-style naming. 2025-01-07 22:55:19 -05:00
Thomas Harte 828c2a6883 Convert macros to functions. 2025-01-07 22:51:52 -05:00
Thomas Harte f195dc313d Strongly type BusOperation. 2025-01-07 22:48:17 -05:00
Thomas Harte 5b8a005f41 Merge pull request #1447 from TomHarte/CounterAccess
Add programmatic access to video counters.
2025-01-07 22:33:28 -05:00
Thomas Harte 9feb75e645 Force high unwriteable bytes. 2025-01-07 22:21:42 -05:00
Thomas Harte 7f8e90bd29 Add video counter writes. 2025-01-07 21:56:04 -05:00
Thomas Harte 2fd34b649d Add missing video counter reads. 2025-01-07 21:40:20 -05:00
Thomas Harte 104054ed1a Merge pull request #1446 from TomHarte/Plus4VideoOptions
Add selectable display type.
2025-01-07 20:15:21 -05:00
Thomas Harte 457b28c22c Merge branch 'master' into Plus4VideoOptions 2025-01-07 20:08:54 -05:00
Thomas Harte 095c8dcd0c Merge pull request #1445 from TomHarte/Plus4Tapes
Improve support for C16 TAP files.
2025-01-07 20:07:38 -05:00
Thomas Harte 8463e9ed94 Add selectable display type. 2025-01-07 17:41:43 -05:00
Thomas Harte b6278c6144 Remove debugging cruft. 2025-01-06 22:17:53 -05:00
Thomas Harte 1c1e1eee47 Double clock for all non-C16s. 2025-01-06 22:04:57 -05:00
Thomas Harte b37ed9ec60 Take yet another stab at wave/half-waves. 2025-01-06 21:40:46 -05:00
Thomas Harte 45f3ef6920 Guess that all C16-style files are 'half wave'. 2025-01-06 17:26:51 -05:00
Thomas Harte 2cd6c4238b Quieten logging. 2025-01-05 22:52:40 -05:00
Thomas Harte f6ed0b33eb Diagnose current scrolling colour fault; hack in graphics-mode fix. 2025-01-05 22:48:16 -05:00
Thomas Harte c4f4ca3f90 Add asserts. 2025-01-05 22:45:09 -05:00
Thomas Harte 9a6780616b Close unpainted gaps. 2025-01-05 22:25:35 -05:00
Thomas Harte db4eca0a42 Hack forward to a woring Mad Rally. 2025-01-05 22:08:20 -05:00
Thomas Harte 6d674edb48 Merge remote-tracking branch 'origin/master' into Plus4Tapes 2025-01-05 22:07:26 -05:00
Thomas Harte c0469a044b Add missing address warnings. 2025-01-05 21:10:23 -05:00
Thomas Harte b9b64eba9a Map all missing registers. 2025-01-05 21:06:46 -05:00
Thomas Harte 2d74387a00 Extend TAP support for C16. 2025-01-05 20:37:39 -05:00
Thomas Harte f66b6fc20c Attempt support for C16 TAPs. 2025-01-05 08:51:20 -05:00
Thomas Harte f0711a9fbc Use detection for play button; allow computer to set motor. 2025-01-04 22:54:13 -05:00
Thomas Harte 83a8c7215a Merge pull request #1444 from TomHarte/AudioQueueTransients
Treat kAudioQueueErr_CannotStart as ephemeral.
2025-01-04 22:39:56 -05:00
Thomas Harte a86f966cb4 Treat kAudioQueueErr_CannotStart as ephemeral. 2025-01-04 22:24:34 -05:00
Thomas Harte 74db978b81 Fix automatic tape motor control. 2025-01-04 22:23:46 -05:00
Thomas Harte 1300546a52 Merge pull request #1443 from TomHarte/TypingSpeed
Improve +4 typing speed.
2025-01-04 19:15:55 -05:00
Thomas Harte 3aeb0bba71 Improve +4 typing speed. 2025-01-04 15:14:25 -05:00
Thomas Harte 03d3efa323 Merge pull request #1442 from TomHarte/38columns
Progress shifter outside of painted pixels.
2025-01-04 07:20:56 -05:00
Thomas Harte f9c220bee0 Progress shifter outside of painted pixels. 2025-01-04 07:15:20 -05:00
Thomas Harte 114c2e2636 Merge pull request #1441 from TomHarte/OSSGuardNoMacro
Remove macros from CoreAudio handler.
2025-01-03 23:38:35 -05:00
Thomas Harte 75a0e622ad Remove macros from CoreAudio handler. 2025-01-03 23:25:38 -05:00
Thomas Harte 8e2de4ee30 Merge pull request #1440 from TomHarte/MenuTweak
Improve menu wording.
2025-01-03 23:23:50 -05:00
Thomas Harte b1602261cf Remove redundant adjective. 2025-01-03 23:23:02 -05:00
Thomas Harte e5ed11f8ec Take another swing at menu item naming. 2025-01-03 23:21:55 -05:00
Thomas Harte c1ecfd289e Merge pull request #1438 from TomHarte/Plus4UI
Add Plus 4 to Mac UI.
2025-01-03 23:10:45 -05:00
Thomas Harte c5cca15b4e Extend window size. 2025-01-03 23:01:33 -05:00
Thomas Harte fa978315e6 Add Plus 4 option to Mac UI. 2025-01-03 22:59:39 -05:00
Thomas Harte c5bffc38f4 Switch typedefs to usings. 2025-01-03 21:35:34 -05:00
Thomas Harte 88b5f6b148 Merge pull request #1437 from TomHarte/Plus4Typer
Add TED typer.
2025-01-03 21:31:56 -05:00
Thomas Harte fc04742151 Pull input from the typer. 2025-01-03 21:03:56 -05:00
Thomas Harte c618d18d46 Allow typers to be attached. 2025-01-03 20:29:19 -05:00
Thomas Harte 33bc7c00df Eliminate long-ago use of typedef. 2025-01-03 20:29:05 -05:00
Thomas Harte 1ed550d7f9 Merge pull request #1434 from TomHarte/Plus4Startup
Add a simulacrum of C16+4 emulation.
2025-01-03 20:11:08 -05:00
Thomas Harte 18b87f2c80 Keep a little more state outside the main loop. 2025-01-03 20:05:43 -05:00
Thomas Harte fad503ca80 Use correct source for bitmap address. 2025-01-03 17:31:27 -05:00
Thomas Harte 37ec3e4605 Simplify flash/inversion handling. 2025-01-03 17:27:43 -05:00
Thomas Harte 70e3d23f26 Add note to self. 2025-01-02 23:10:17 -05:00
Thomas Harte 6ebf415a52 Improve invert and flash support. 2025-01-02 23:04:35 -05:00
Thomas Harte 5c31104d0e Simplify control flow, half-obey 256-character flag. 2025-01-02 22:39:23 -05:00
Thomas Harte aed8b65e2b Mark extra constexprs. 2025-01-02 22:01:51 -05:00
Thomas Harte 906e8aa2b2 Move nullptr check to bottom of pipeline. 2025-01-02 21:02:11 -05:00
Thomas Harte d0703f95af Normalise adjective/noun. 2025-01-02 16:01:47 -05:00
Thomas Harte 538b00797d Flatten structure. 2025-01-02 16:00:47 -05:00
Thomas Harte 985c555518 Support multicolour text. 2025-01-02 15:56:39 -05:00
Thomas Harte 5ef26a25ee Fix shift timing. 2025-01-02 15:52:20 -05:00
Thomas Harte 3db0e30d12 Factor out 1bpp and 2bpp pixel generation. 2025-01-02 15:39:45 -05:00
Thomas Harte a666cabae9 Support extended colour text mode. 2025-01-02 15:32:44 -05:00
Thomas Harte 2e8d9018ef Add other address modes. 2025-01-02 15:09:37 -05:00
Thomas Harte ae49505e67 Attempt multicolour bitmap mode. 2025-01-02 15:07:22 -05:00
Thomas Harte 09bd5503b4 Fetch pixels earlier for a mostly-working high-resolution output. 2025-01-02 14:42:49 -05:00
Thomas Harte dbe733524c Reintroduce RDY control. 2025-01-02 13:49:24 -05:00
Thomas Harte 1625f5c0f9 Take a stab at high-resolution bitmap mode. 2025-01-02 13:46:35 -05:00
Thomas Harte 7cd49d07f2 Collapse to a single function. 2025-01-02 13:39:50 -05:00
Thomas Harte a542345456 Iterate towards supporting all video modes. 2025-01-01 22:34:47 -05:00
Thomas Harte 0b98f21443 Enable extra functionality. 2025-01-01 22:34:30 -05:00
Thomas Harte c42e231e99 Attempt fully to support x scroll. 2025-01-01 21:47:59 -05:00
Thomas Harte ab653af4b3 Introduce pixel-level shifter. 2025-01-01 20:58:06 -05:00
Thomas Harte 8653f572c8 Move static_assert. 2025-01-01 15:06:00 -05:00
Thomas Harte 39b431fb19 Rejig marginally. 2024-12-31 22:14:02 -05:00
Thomas Harte e158c5bc30 Extend shifting to final column of screen. 2024-12-31 20:33:27 -05:00
Thomas Harte d0fdfda4cb Set volume peak, count up rather than down. 2024-12-31 11:45:32 -05:00
Thomas Harte 668a5ca041 Make a real attempt at some degree of audio. 2024-12-31 10:25:11 -05:00
Thomas Harte 5e3947b8bc Evaluate address lazily. 2024-12-31 08:28:42 -05:00
Thomas Harte 233a627c9f Correct longstanding confusion over character fetch. 2024-12-31 08:25:05 -05:00
Thomas Harte 6197486d49 Use increment_video_counter_ to trigger fetch. 2024-12-31 08:06:04 -05:00
Thomas Harte 60856b974b Add wiring for audio. 2024-12-30 22:56:29 -05:00
Thomas Harte d1eca5dc21 Expand mask. 2024-12-30 21:29:36 -05:00
Thomas Harte 24b281d625 Use namespace; attempt to avoid false characters. 2024-12-30 09:14:27 -05:00
Thomas Harte b0d1dee38b Add missing header. 2024-12-29 22:36:14 -05:00
Thomas Harte 0751c51803 Dispatch warning. 2024-12-29 22:34:32 -05:00
Thomas Harte 0005229c1e Improve header. 2024-12-29 22:21:38 -05:00
Thomas Harte 33c2353107 Alter motor control detection. 2024-12-29 22:21:02 -05:00
Thomas Harte cb98297bb5 Add consts. 2024-12-29 22:14:48 -05:00
Thomas Harte 0e663e1da8 Add C1541 activity indicator. 2024-12-29 21:30:53 -05:00
Thomas Harte 918a8c5f8b Fix 1541 clocking, invert levels again. 2024-12-29 08:41:37 -05:00
Thomas Harte 34938e8c62 Fully connect serial port. 2024-12-28 23:07:01 -05:00
Thomas Harte da6efe52ff Accept implicit bool, eliminate rom name repetition. 2024-12-28 22:22:28 -05:00
Thomas Harte 570f1caa8f Attempt also to integrate a C1541. 2024-12-28 21:49:04 -05:00
Thomas Harte 6f638805f7 Further eliminate std::shared_ptr connections. 2024-12-28 20:52:31 -05:00
Thomas Harte c92b0dc886 Start normalising Commodore serial bus interface. 2024-12-28 20:11:27 -05:00
Thomas Harte b4b216de84 Attempt press-play feedback. 2024-12-27 21:43:41 -05:00
Thomas Harte 80f5d7c735 Attempt full tape input. 2024-12-27 21:19:41 -05:00
Thomas Harte 01aeb46664 Bump version. 2024-12-27 20:59:24 -05:00
Thomas Harte 2cfd2ff624 Start adding tape player. 2024-12-27 20:59:07 -05:00
Thomas Harte ff12bbbdb6 Simplify delay state. 2024-12-27 17:10:25 -05:00
Thomas Harte e19fe5d0e2 Reintroduce colour burst. 2024-12-27 09:25:36 -05:00
Thomas Harte 9670d5f4de Add cursor, proving things generally to be off by one. 2024-12-27 09:20:12 -05:00
Thomas Harte 863b09c39b Increase key bindings. 2024-12-27 09:14:23 -05:00
Thomas Harte 6b90de539e Add data delays. 2024-12-26 22:39:16 -05:00
Thomas Harte 4bb53ed6ba Start trending towards an FPGA-inspired implementation. 2024-12-26 22:33:09 -05:00
Thomas Harte e6523f3ec1 Shuffle colour conversion moment; move ownership of clock rate. 2024-12-20 09:17:40 -05:00
Thomas Harte c8ad8c79bd Factor in x_scroll_. 2024-12-18 22:14:57 -05:00
Thomas Harte b08cc9cb49 Use attributes, attempt real cursor. 2024-12-18 22:07:37 -05:00
Thomas Harte 4f93dc0adf Support attribute bytes. 2024-12-18 22:02:05 -05:00
Thomas Harte 096f48be33 Fix top line of cursor, add pretend cursor, page video separately. 2024-12-18 21:48:03 -05:00
Thomas Harte 81398d58a2 Improve get_rect_for_area, use in C16. 2024-12-18 20:53:03 -05:00
Thomas Harte 7466da5651 Add Keyboard. 2024-12-18 07:04:17 -05:00
Thomas Harte c8fdde4c5e Clarify clock rates. 2024-12-17 07:08:04 -05:00
Thomas Harte 15583e7975 Avoid risk of unbounded memory consumption. 2024-12-16 22:29:23 -05:00
Thomas Harte 5acdf39566 Use a normative, unique_ptr-based cache. 2024-12-16 22:12:12 -05:00
Thomas Harte 2240ada5db Avoid going out of bounds below. 2024-12-16 22:11:49 -05:00
Thomas Harte 9d5c10d440 Edge towards realistic video collection. 2024-12-16 22:11:06 -05:00
Thomas Harte 709f350d60 Begin usage of RDY. 2024-12-16 07:18:07 -05:00
Thomas Harte 3d7e016b42 Name horizontal events. 2024-12-15 08:46:07 -05:00
Thomas Harte b76104d145 Start edging towards proper video timing. 2024-12-14 22:06:18 -05:00
Thomas Harte 702b6d6567 Add extra note to self. 2024-12-14 11:56:13 -05:00
Thomas Harte 3e93004db6 Double nominal clock, to hit normative values. 2024-12-14 11:55:10 -05:00
Thomas Harte 589903c43c Add safety rail. 2024-12-13 23:14:00 -05:00
Thomas Harte f41b54de21 Make a close-enough guess at chrominances. 2024-12-13 22:25:23 -05:00
Thomas Harte 700b848f26 Add overt nils to aid with debugging. 2024-12-13 21:25:01 -05:00
Thomas Harte a1f6e93e22 Add most of the keyboard. 2024-12-13 21:24:11 -05:00
Thomas Harte 1628af2ffc Provide a stuck down key 'a'. 2024-12-13 17:56:47 -05:00
Thomas Harte 1b5d446635 Fix: writes to interrupt status _clear_. 2024-12-13 17:22:05 -05:00
Thomas Harte 83a9ef772a Add TODO explaining all currently-unhandled writes. 2024-12-13 14:02:33 -05:00
Thomas Harte 1d9c3fb827 Hack in some text output. 2024-12-13 13:56:12 -05:00
Thomas Harte ff92bdb324 Add buffer for pixels, output _something_. 2024-12-13 13:31:15 -05:00
Thomas Harte 363ad7342a Add memory fuzzing, some text output. 2024-12-12 22:59:20 -05:00
Thomas Harte 663acd3810 Map initial border colour, white and black. 2024-12-12 22:35:50 -05:00
Thomas Harte c2fc26089e Add background colour reading, fix writing. 2024-12-12 22:15:15 -05:00
Thomas Harte 58b464bdfc Attempt to add interrupts. 2024-12-12 22:07:51 -05:00
Thomas Harte ed766c74e6 Add some paging. 2024-12-12 21:17:28 -05:00
Thomas Harte 1d07b8238c Add a crop rectangle. 2024-12-12 17:36:44 -05:00
Thomas Harte 41c6ed7c5a Further restrict 'active' area of the display. 2024-12-12 17:33:11 -05:00
Thomas Harte f7750af3d0 Provide bus visibility to video; mark vertical portion of display. 2024-12-11 22:32:14 -05:00
Thomas Harte 8854ffddee Include possible clock divider. 2024-12-11 21:57:31 -05:00
Thomas Harte a487619578 Track basic frame events. 2024-12-11 21:54:03 -05:00
Thomas Harte 0eab6146fc Introduce a CRT. 2024-12-11 21:38:32 -05:00
Thomas Harte 389ba95e5a Template out the usual repetitive stuff of segment finding. 2024-12-11 21:30:58 -05:00
Thomas Harte 84d178c0ca Transcribe event times into [mostly] non-action. 2024-12-11 17:32:51 -05:00
Thomas Harte aed8f8efa8 Transcribe some timing numbers. 2024-12-10 22:56:14 -05:00
Thomas Harte 38325741de Forward address information to a video stub. 2024-12-10 21:29:17 -05:00
Thomas Harte 891d5c2066 Separate out TED calls, to aid with logging. 2024-12-10 18:07:07 -05:00
Thomas Harte 6b7edac6e4 Add timers. 2024-12-10 18:04:10 -05:00
Thomas Harte ab2a576e1b Merge branch 'master' into Plus4Startup 2024-12-09 22:23:24 -05:00
Thomas Harte 5a3e4dd47b Merge pull request #1431 from TomHarte/UniqueSectors
Eliminate use of std::shared_ptr for tracks on both sides of DiskImageHolder.
2024-12-09 22:23:01 -05:00
Thomas Harte 064c4b4312 Add some logging. 2024-12-09 22:22:20 -05:00
Thomas Harte cbde504057 Add a memory map of sorts and a 6502. 2024-12-09 17:46:31 -05:00
Thomas Harte 949cfcfa69 Load ROMs. 2024-12-09 17:31:00 -05:00
Thomas Harte 06a005321e Merge pull request #1433 from TomHarte/DeclareFieldsAfresh
Use `std::once` in preference to home-rolled solution.
2024-12-08 22:46:21 -05:00
Thomas Harte d3587f595f Merge pull request #1432 from TomHarte/Plus4ROMs
Add definitions for some of the Plus 4 ROMs.
2024-12-08 22:42:02 -05:00
Thomas Harte b0158ed7ce Use std::once in preference to home-rolled solution. 2024-12-08 22:35:41 -05:00
Thomas Harte e5f4300e54 Add definitions for some of the Plus 4 ROMs. 2024-12-08 22:03:44 -05:00
Thomas Harte 7cc6f8604e Eliminate std::shared_ptr outside of DiskImageHolder. 2024-12-08 21:49:34 -05:00
Thomas Harte 657960e7d0 Eliminate use of std::shared_ptr at DiskImage and below. 2024-12-08 21:26:03 -05:00
Thomas Harte aecd7f9283 Merge pull request #1427 from TomHarte/CommodoreAnalyser
Improve analysis of Commodore BASIC
2024-12-08 18:59:03 -06:00
Thomas Harte 6f1b30cd24 Include Plus 4 in test target. 2024-12-07 11:56:16 -06:00
Thomas Harte a6ba549b67 Don't repeat constant. 2024-12-07 11:55:38 -06:00
Thomas Harte 84ea04f61d Improve comments. 2024-12-07 11:54:55 -06:00
Thomas Harte 0d52cf5f97 Improve constiness. 2024-12-07 11:50:18 -06:00
Thomas Harte b15a083a15 Switch to a non-macro route for startup declarations. 2024-12-07 10:15:38 -06:00
Thomas Harte a128247ef5 Improve comments. 2024-12-07 09:32:45 -06:00
Thomas Harte 590bd934c0 Use built-in paralel for. 2024-12-07 09:32:32 -06:00
Thomas Harte e9826d2e7e Use launch-time declarations. 2024-12-06 16:03:46 -05:00
Thomas Harte 58ed63cd18 Consciously uglify. These shouldn't look like functions. 2024-12-06 16:03:24 -05:00
Thomas Harte fd1bd3032f Attempt to move towards at-launch field declaration.
This avoids any need for overt thread safety in mutations.
2024-12-06 16:00:03 -05:00
Thomas Harte d7206096ea Attempt to parallelise. 2024-12-06 15:59:47 -05:00
Thomas Harte f43e594eca Improve style: indentation, constness, names. 2024-12-06 15:29:49 -05:00
Thomas Harte ea4fe5e809 Propagate Plus 4 to other project files. 2024-12-06 15:20:58 -05:00
Thomas Harte 9fcb634510 Route +4 software into a non-functional +4. 2024-12-06 15:17:49 -05:00
Thomas Harte c14a4515ce Add consts widely. 2024-12-06 15:08:21 -05:00
Thomas Harte 8e71180cd2 Add an empty shell of a C16+4 class. 2024-12-06 13:53:08 -05:00
Thomas Harte 08f98aa32f Decrease indentation. 2024-12-06 13:52:42 -05:00
Thomas Harte e8aa9b9eb2 Avoid overrun on empty file. 2024-12-06 13:37:06 -05:00
Thomas Harte 19f815eeff Infer more from first file starting address; reduce reallocations. 2024-12-06 13:34:35 -05:00
Thomas Harte a508f7a463 Process all files if provided with a disk or tape. 2024-12-06 13:24:15 -05:00
Thomas Harte e58d3ee060 Remove file. 2024-12-05 22:13:02 -05:00
Thomas Harte 268842681a Adjust move semantics. 2024-12-05 22:09:07 -05:00
Thomas Harte 9b357a9fbf Reduce copying. 2024-12-05 22:05:03 -05:00
Thomas Harte 6f80018b6e Reintroduce argument. 2024-12-05 22:04:39 -05:00
Thomas Harte 7a1153be65 Improve loop detection. 2024-12-05 17:30:30 -05:00
Thomas Harte 85d4c24aba Restore parameter name. 2024-12-05 17:29:05 -05:00
Thomas Harte 48c0ae8fe4 Avoid being thrown by looping BASIC. 2024-12-05 17:28:47 -05:00
Thomas Harte e835b2c68c Merge branch 'master' into CommodoreAnalyser 2024-12-04 22:56:05 -05:00
Thomas Harte 10d20f5d09 Merge pull request #1429 from TomHarte/FarewellMacOS12
Remove deprecated macos-12 from CI; add macos-15.
2024-12-04 22:55:06 -05:00
Thomas Harte 88b31ea940 Merge pull request #1428 from TomHarte/MoreIndentation
Adjust more dangling indentation changes.
2024-12-04 22:40:30 -05:00
Thomas Harte 9cb28d23a3 Remove deprecated macos-12; add macos-15. 2024-12-04 22:39:29 -05:00
Thomas Harte ce5aae3f7d Adjust more dangling indentation changes. 2024-12-04 22:29:08 -05:00
Thomas Harte e7f0eb6746 Avoid invalid accesses. 2024-12-04 22:04:00 -05:00
Thomas Harte 65a118d1f3 Attempt to locate and disassemble machine code. 2024-12-04 21:41:05 -05:00
Thomas Harte 3d2eefc7e7 Merge pull request #1426 from TomHarte/C16Plus4Analysis
Begin Plus 4 analyser work, triggering clean-up of tape file classes.
2024-12-03 23:16:10 -05:00
Thomas Harte f804c32eee Opportunistically const. 2024-12-03 22:57:38 -05:00
Thomas Harte b89ecadc3a Improve interface. 2024-12-03 22:54:29 -05:00
Thomas Harte 6d4ff0b89a Finally eliminate all that virtual_ nonsense. 2024-12-03 22:28:57 -05:00
Thomas Harte 598003ea39 Continue marking override. 2024-12-03 21:18:26 -05:00
Thomas Harte 6ef63790a9 Mark overrides, improve constiness. 2024-12-03 17:33:09 -05:00
Thomas Harte 3ffd986a1c Start building Commodore analyser tests. 2024-12-03 09:25:58 -05:00
Thomas Harte 0b5cd4c665 Lock all tape classes down to read-only. 2024-12-03 09:21:13 -05:00
Thomas Harte 0371b0507a Avoid potential extending run-out-of-bounds. 2024-12-03 09:19:23 -05:00
Thomas Harte 9fa71231c4 Support zero-length files; further fix bounds checks. 2024-12-02 17:23:50 -05:00
Thomas Harte 32beafc12d Test Plus 4 detectionl; add shout for additional start address. 2024-12-02 15:27:37 -05:00
Thomas Harte 09e2ef334b Fix sign of bounds check. 2024-12-02 15:27:03 -05:00
Thomas Harte c0ce62ed2b Merge pull request #1425 from TomHarte/MoreIndentation
Take another big swing at indentation, some `const`s.
2024-12-01 22:02:25 -05:00
Thomas Harte d3ed485e7a Take another big swing at indentation, some consts. 2024-12-01 21:44:14 -05:00
Thomas Harte 31c878b654 Merge pull request #1424 from TomHarte/InstructionSetFormatting
Improve formatting, `const`ness in instruction sets.
2024-12-01 20:24:55 -05:00
Thomas Harte 3a0f4a0bfc Improve constness, formatting. 2024-12-01 18:09:19 -05:00
Thomas Harte 8b88d1294d Remove errant spaces. 2024-12-01 09:04:32 -05:00
Thomas Harte 43fcf46d69 Limit line lengths. 2024-12-01 09:00:29 -05:00
Thomas Harte 394fe0f1f1 Improve formatting, constness in 68k and ARM instruction set implementations. 2024-12-01 08:20:24 -05:00
Thomas Harte 872921f635 Merge pull request #1423 from TomHarte/InputsFormatting
Roll formatting and `const` tweaks into Inputs.
2024-11-30 19:25:50 -05:00
Thomas Harte 7248470950 Roll formatting and const tweaks into Inputs. 2024-11-30 18:57:56 -05:00
Thomas Harte 9d87296316 Merge pull request #1422 from TomHarte/MutableLevels
Correct improper application of `const`.
2024-11-30 17:53:56 -05:00
Thomas Harte 23c67f7e38 Correct improper application of const. 2024-11-30 17:32:16 -05:00
Thomas Harte bd98d95dbf Merge pull request #1421 from TomHarte/FurtherFormatting
Further improve formatting.
2024-11-30 17:22:00 -05:00
Thomas Harte 3addb8d72b Finish updating components. 2024-11-30 17:21:00 -05:00
Thomas Harte 5545906063 Adopt new indentation, improve constness. 2024-11-30 15:53:58 -05:00
Thomas Harte 36edfe9715 Merge pull request #1420 from TomHarte/NewIcon
Import new icons.
2024-11-29 23:10:31 -05:00
Thomas Harte 030b54a2b6 Import new icons. 2024-11-29 23:04:28 -05:00
Thomas Harte f332613922 Merge pull request #1419 from TomHarte/Reformatting
Begin a general reformatting.
2024-11-29 22:52:29 -05:00
Thomas Harte 088bc14b11 Begin a reformatting of components. 2024-11-29 22:43:54 -05:00
Thomas Harte 86fa8da8c5 Reformat ClockReceiver. 2024-11-29 22:12:57 -05:00
Thomas Harte abfc73299e Update remainder of 'Analyser'. 2024-11-29 21:08:35 -05:00
Thomas Harte bd97fd5973 Improve indentation, constness of 'Activity' and dynamic analyser. 2024-11-29 17:23:05 -05:00
Thomas Harte f00e7c4a80 Merge pull request #1413 from TomHarte/ShakerScanTarget
Avoid taking an out-of-range pointer.
2024-10-19 10:15:30 -04:00
Thomas Harte 49c811b5f5 Avoid taking an out-of-range pointer.
(Even though it was safe)
2024-10-19 10:12:51 -04:00
Thomas Harte b6c21e071d Update version number. 2024-10-19 09:19:59 -04:00
Thomas Harte e68129e47e Merge pull request #1412 from TomHarte/CRTCType
Specify correct 6845; experiment with vsync.
2024-10-18 20:31:45 -04:00
Thomas Harte 72d7917415 Specify correct 6845; experiment with vsync. 2024-10-16 21:02:58 -04:00
Thomas Harte 53837fe132 Merge pull request #1411 from TomHarte/CMakeWarnings
Resolve GCC/Ubuntu CI warnings.
2024-10-15 22:25:06 -04:00
Thomas Harte 08d094c786 Use appropriate std::array semantics. 2024-10-15 22:14:29 -04:00
Thomas Harte a1634ab496 Reduce uninitialised usages. 2024-10-15 22:10:16 -04:00
Thomas Harte d35165bd8e Correct parameter usage. 2024-10-15 21:54:04 -04:00
Thomas Harte b701ce9721 Shuffle construction order. 2024-10-15 21:51:23 -04:00
Thomas Harte f3e18da416 Use custom type for deleter. 2024-10-15 21:49:42 -04:00
Thomas Harte 131ab00304 Merge pull request #1410 from TomHarte/CPCLatency
Further improve the CPC side of the CPC:CRTC relationship.
2024-10-15 21:30:39 -04:00
Thomas Harte 26d7d58a5f Add TODO. 2024-10-15 21:16:07 -04:00
Thomas Harte 02f92a7818 Handle runs that don't cross a pixel boundary.
`
2024-10-15 21:15:30 -04:00
Thomas Harte b6fff521e4 Allow new interrupts to override the end of previous. 2024-10-15 12:27:30 -04:00
Thomas Harte 23f1308231 Experiment with reads/writes earlier in the transaction. 2024-10-15 12:10:36 -04:00
Thomas Harte 947e890c59 Adjust mode latch time, timer hsync signalling. 2024-10-15 11:53:00 -04:00
Thomas Harte 0f1714de7c Merge pull request #1409 from TomHarte/68000Constness
68000: `Const` as many arguments as possible.
2024-10-13 21:58:02 -04:00
Thomas Harte a7d2b0f63b Const as many arguments as possible. 2024-10-13 21:40:39 -04:00
Thomas Harte 9c550a8154 Merge pull request #1408 from TomHarte/M50740ExecutorStyle
Eliminate majority of M50740 macros
2024-10-10 13:46:34 -04:00
Thomas Harte 49012a21c8 Convert index macro. 2024-10-09 21:50:03 -04:00
Thomas Harte f136151064 Transcribe op_X macros. 2024-10-09 21:46:30 -04:00
Thomas Harte 4838728521 Eliminate nibble macros. 2024-10-09 21:04:32 -04:00
Thomas Harte 95fac5dc13 Begin macro elimination. 2024-10-09 14:27:35 -04:00
Thomas Harte ac1f7884b5 Merge pull request #1407 from TomHarte/OptionalCPMData
Reduce costs of CPC disk analysis by not loading unused contents.
2024-10-09 14:16:53 -04:00
Thomas Harte ab411512d4 Merge pull request #1405 from TomHarte/CRTCFixes
Redraft CRTC closer to raw logic.
2024-10-09 14:14:43 -04:00
Thomas Harte 704495ff42 Made reading of data optional. 2024-10-09 12:27:51 -04:00
Thomas Harte 9acc80260f Eliminate phases due to lack of evidence. 2024-10-09 11:59:27 -04:00
Thomas Harte 7759fb7e68 Add TODO. 2024-10-09 11:48:08 -04:00
Thomas Harte 0d71724598 Eliminate extra-scanline flag. 2024-10-09 11:45:32 -04:00
Thomas Harte ae436f7a51 Fix conflicting usages of EOF. 2024-10-09 11:16:12 -04:00
Thomas Harte 43ac20cbd2 Fix non-interlaced frame length. 2024-10-07 21:50:56 -04:00
Thomas Harte 2d90868f5c Reinstitute cursor. 2024-10-07 21:13:44 -04:00
Thomas Harte 60987ae4a7 Round out interlaced output. 2024-10-07 20:53:41 -04:00
Thomas Harte 65c1d99120 Add, disable some logging. 2024-10-05 22:30:53 -04:00
Thomas Harte 35acf88847 Take a swing at adding an adjustment period. 2024-10-03 22:07:46 -04:00
Thomas Harte 45549b5fcd Switch CRTC type. 2024-10-03 22:07:12 -04:00
Thomas Harte 2eb9fb6a08 Add faulty attempt at adjustment period. 2024-09-30 23:47:27 -04:00
Thomas Harte 0d0e1083e6 Fix potential out-of-bounds access. 2024-09-30 13:37:44 -04:00
Thomas Harte e650f3772a Limit vertical visibility. 2024-09-30 13:35:28 -04:00
Thomas Harte e5ff4c65b7 Fix accidental skew, off-by-one end of line. 2024-09-30 13:20:18 -04:00
Thomas Harte 276809f76a Stabilise image, albeit incorrectly. 2024-09-30 13:16:03 -04:00
Thomas Harte 5e3840c5f1 Attempt to skirt with coherence. 2024-09-29 23:08:39 -04:00
Thomas Harte 6eace2a3ef Improve address counting. 2024-09-27 21:27:56 -04:00
Thomas Harte 7817b23857 Take a swing at vertical sync. 2024-09-27 21:14:57 -04:00
Thomas Harte 432854aeb5 Restore some form of visuals. 2024-09-26 22:08:22 -04:00
Thomas Harte 433c8f9c3c Make negligible progress. 2024-09-25 19:30:08 -04:00
Thomas Harte ea25dbfd1e Begin CRTC rejig. 2024-09-23 21:11:54 -04:00
Thomas Harte 10f8318e79 Merge pull request #1404 from TomHarte/65816SquareD
65816: correct emulation-mode `[d], y`, `PEI` and `PLB`.
2024-09-21 21:46:00 -04:00
Thomas Harte 17ff0c4f65 Fix PLD/PLB sizes. 2024-09-21 21:28:38 -04:00
Thomas Harte 9abd653fb9 Avoid impossible clamps. 2024-09-21 21:25:49 -04:00
Thomas Harte ff6753fcdf PEI: don't page wrap. 2024-09-21 21:12:04 -04:00
Thomas Harte a65551f652 Give PLB the same stack behaviour as PLD. 2024-09-21 21:08:02 -04:00
Thomas Harte f0d807a0fe Fix [d], y page-wrapping behaviour. 2024-09-21 20:49:59 -04:00
Thomas Harte dfcdbe5b6a Merge pull request #1402 from TomHarte/CPCInterruptTiming
Pull CPC interrupt to start of hsync.
2024-09-12 21:12:02 -04:00
Thomas Harte 53e73238fd Merge pull request #1403 from TomHarte/OricVSync
Extend Oric vsync to four lines.
2024-09-12 21:08:51 -04:00
Thomas Harte 581454db69 Tweak mode latch time too. 2024-09-12 20:47:27 -04:00
Thomas Harte 63d501b629 Pull interrupt to start of hsync. 2024-09-12 20:45:28 -04:00
Thomas Harte 60bd877ed9 Merge pull request #1401 from TomHarte/OricVSync
Add the Oric's v-sync hardware hack.
2024-09-10 21:18:03 -04:00
Thomas Harte 44574465c5 Extend vsync to four lines. 2024-09-10 21:06:49 -04:00
Thomas Harte 2b7382a014 Loop in vsync as a potential tape input. 2024-09-10 20:59:05 -04:00
Thomas Harte 584b6df40d Tweak 60Hz period. 2024-09-10 20:43:01 -04:00
Thomas Harte e55f61deb2 Add vsync getter. 2024-09-10 20:31:35 -04:00
Thomas Harte a6c6a1c6da Eliminate macros. 2024-09-10 20:29:34 -04:00
Thomas Harte bdb5abe47b Record updated version number. 2024-09-08 21:34:02 -04:00
Thomas Harte dbe0ebc93e Merge pull request #1400 from TomHarte/DelegateOrderTest
Fix order of `if` tests.
2024-09-08 21:30:44 -04:00
Thomas Harte 1c2f66e855 Fix order of if tests. 2024-09-08 21:23:58 -04:00
Thomas Harte 7eee3f9e5e Merge pull request #1399 from TomHarte/ElectronULARedux
Replace Electron graphics generation with FPGA transcription.
2024-09-08 21:23:09 -04:00
Thomas Harte b7f069e1bd Add a colour burst. 2024-09-08 21:12:45 -04:00
Thomas Harte 51c8396e32 Fix faulty centring. 2024-09-08 21:06:59 -04:00
Thomas Harte 0efe649ca5 Post pixel clock. 2024-09-08 20:57:43 -04:00
Thomas Harte 75db0018bc Add note on provenance. 2024-09-08 20:20:03 -04:00
Thomas Harte 2a9e1ea045 Use normal member naming convention. 2024-09-08 20:16:43 -04:00
Thomas Harte 8feb8aaadc Reintroduce cropping, even if faulty. 2024-09-06 22:12:19 -04:00
Thomas Harte b8f4385501 Fix palette generation. 2024-09-06 21:47:13 -04:00
Thomas Harte d8b6d87a1c Attempt colour. 2024-09-06 21:36:05 -04:00
Thomas Harte f10702b3ca Edge towards proper serialisation. 2024-09-06 21:01:30 -04:00
Thomas Harte 88248d7062 Fix base address, delays. 2024-09-06 20:55:26 -04:00
Thomas Harte 5ca1659bcc Do just enough to get 1bpp fixed-palette pixels. 2024-09-06 20:36:27 -04:00
Thomas Harte 59530a12fd Sub in basic transliteration of hoglet's FPGA. 2024-09-06 20:21:46 -04:00
Thomas Harte aab2dd68b6 Substitute in a real-time video generator. 2024-09-06 20:18:29 -04:00
812 changed files with 60519 additions and 41515 deletions
+55 -3
View File
@@ -1,18 +1,26 @@
name: Build
on: [pull_request]
jobs:
build-mac-xcodebuild:
name: Mac UI / xcodebuild / ${{ matrix.os }}
strategy:
matrix:
os: [macos-12, macos-13, macos-14]
os: [macos-latest] #[macos-13, macos-14, macos-15]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Make
working-directory: OSBindings/Mac
run: xcodebuild CODE_SIGN_IDENTITY=-
run: |
xcodebuild -downloadComponent MetalToolchain
xcodebuild CODE_SIGN_IDENTITY=-
build-sdl-cmake:
name: SDL UI / cmake / ${{ matrix.os }}
strategy:
@@ -31,6 +39,7 @@ jobs:
sudo apt-get --fix-missing install cmake gcc-10 libsdl2-dev
;;
macOS)
brew uninstall cmake
brew install cmake sdl2
;;
esac
@@ -49,11 +58,12 @@ jobs:
esac
cmake -S. -Bbuild -DCLK_UI=SDL -DCMAKE_BUILD_TYPE=Release
cmake --build build -v -j"$jobs"
build-sdl-scons:
name: SDL UI / scons / ${{ matrix.os }}
strategy:
matrix:
os: [macos-14, ubuntu-latest]
os: [macos-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
@@ -85,3 +95,45 @@ jobs:
jobs=1
esac
scons -j"$jobs"
build-qt5:
name: Qt 5 / ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
uses: jurplel/install-qt-action@v3
with:
version: '5.15.2'
archives: 'qtbase qtmultimedia qtx11extras icu'
- name: Make
working-directory: OSBindings/Qt
shell: bash
run: |
qmake -o Makefile clksignal.pro
make
# build-qt6:
# name: Qt 6 / ${{ matrix.os }}
# strategy:
# matrix:
# os: [ubuntu-latest]
# runs-on: ${{ matrix.os }}
# steps:
# - name: Checkout
# uses: actions/checkout@v4
# - name: Install dependencies
# uses: jurplel/install-qt-action@v4
# with:
# version: '6.8'
# archives: qtbase
# - name: Make
# working-directory: OSBindings/Qt
# shell: bash
# run: |
# qmake -o Makefile clksignal.pro
# make
+25 -25
View File
@@ -22,38 +22,38 @@ namespace Activity {
and/or to show or unshow status indicators.
*/
class Observer {
public:
virtual ~Observer() = default;
public:
virtual ~Observer() = default;
/// Provides hints as to the sort of information presented on an LED.
enum LEDPresentation: uint8_t {
/// This LED informs the user of some sort of persistent state, e.g. scroll lock.
/// If this flag is absent then the LED describes an ephemeral state, such as media access.
Persistent = (1 << 0),
};
/// Provides hints as to the sort of information presented on an LED.
enum LEDPresentation: uint8_t {
/// This LED informs the user of some sort of persistent state, e.g. scroll lock.
/// If this flag is absent then the LED describes an ephemeral state, such as media access.
Persistent = (1 << 0),
};
/// Announces to the receiver that there is an LED of name @c name.
virtual void register_led([[maybe_unused]] const std::string &name, [[maybe_unused]] uint8_t presentation = 0) {}
/// Announces to the receiver that there is an LED of name @c name.
virtual void register_led([[maybe_unused]] const std::string &name, [[maybe_unused]] uint8_t presentation = 0) {}
/// Announces to the receiver that there is a drive of name @c name.
///
/// If a drive has the same name as an LED, that LED goes with this drive.
virtual void register_drive([[maybe_unused]] const std::string &name) {}
/// Announces to the receiver that there is a drive of name @c name.
///
/// If a drive has the same name as an LED, that LED goes with this drive.
virtual void register_drive([[maybe_unused]] const std::string &name) {}
/// Informs the receiver of the new state of the LED with name @c name.
virtual void set_led_status([[maybe_unused]] const std::string &name, [[maybe_unused]] bool lit) {}
/// Informs the receiver of the new state of the LED with name @c name.
virtual void set_led_status([[maybe_unused]] const std::string &name, [[maybe_unused]] bool lit) {}
enum class DriveEvent {
StepNormal,
StepBelowZero,
StepBeyondMaximum
};
enum class DriveEvent {
StepNormal,
StepBelowZero,
StepBeyondMaximum
};
/// Informs the receiver that the named event just occurred for the drive with name @c name.
virtual void announce_drive_event([[maybe_unused]] const std::string &name, [[maybe_unused]] DriveEvent event) {}
/// Informs the receiver that the named event just occurred for the drive with name @c name.
virtual void announce_drive_event([[maybe_unused]] const std::string &name, [[maybe_unused]] DriveEvent event) {}
/// Informs the receiver of the motor-on status of the drive with name @c name.
virtual void set_drive_motor_status([[maybe_unused]] const std::string &name, [[maybe_unused]] bool is_on) {}
/// Informs the receiver of the motor-on status of the drive with name @c name.
virtual void set_drive_motor_status([[maybe_unused]] const std::string &name, [[maybe_unused]] bool is_on) {}
};
}
+2 -2
View File
@@ -13,8 +13,8 @@
namespace Activity {
class Source {
public:
virtual void set_activity_observer(Observer *observer) = 0;
public:
virtual void set_activity_observer(Observer *) = 0;
};
}
+1 -1
View File
@@ -10,7 +10,7 @@
using namespace Analyser::Dynamic;
float ConfidenceCounter::get_confidence() {
float ConfidenceCounter::confidence() const {
return float(hits_) / float(hits_ + misses_);
}
+15 -15
View File
@@ -18,25 +18,25 @@ namespace Analyser::Dynamic {
The initial value of the confidence counter is 0.5.
*/
class ConfidenceCounter: public ConfidenceSource {
public:
/*! @returns The computed probability, based on the history of events. */
float get_confidence() final;
public:
/*! @returns The computed probability, based on the history of events. */
float confidence() const final;
/*! Records an event that implies this is the appropriate class: pushes probability up towards 1.0. */
void add_hit();
/*! Records an event that implies this is the appropriate class: pushes probability up towards 1.0. */
void add_hit();
/*! Records an event that implies this is not the appropriate class: pushes probability down towards 0.0. */
void add_miss();
/*! Records an event that implies this is not the appropriate class: pushes probability down towards 0.0. */
void add_miss();
/*!
Records an event that could be correct but isn't necessarily so; which can push probability
down towards 0.5, but will never push it upwards.
*/
void add_equivocal();
/*!
Records an event that could be correct but isn't necessarily so; which can push probability
down towards 0.5, but will never push it upwards.
*/
void add_equivocal();
private:
int hits_ = 1;
int misses_ = 1;
private:
int hits_ = 1;
int misses_ = 1;
};
}
+1 -1
View File
@@ -17,7 +17,7 @@ namespace Analyser::Dynamic {
program is handed to an Atari 2600 then its confidence should grow towards 1.0.
*/
struct ConfidenceSource {
virtual float get_confidence() = 0;
virtual float confidence() const = 0;
};
}
+6 -3
View File
@@ -13,16 +13,19 @@
using namespace Analyser::Dynamic;
ConfidenceSummary::ConfidenceSummary(const std::vector<ConfidenceSource *> &sources, const std::vector<float> &weights) :
ConfidenceSummary::ConfidenceSummary(
const std::vector<ConfidenceSource *> &sources,
const std::vector<float> &weights
) :
sources_(sources), weights_(weights) {
assert(weights.size() == sources.size());
weight_sum_ = std::accumulate(weights.begin(), weights.end(), 0.0f);
}
float ConfidenceSummary::get_confidence() {
float ConfidenceSummary::confidence() const {
float result = 0.0f;
for(std::size_t index = 0; index < sources_.size(); ++index) {
result += sources_[index]->get_confidence() * weights_[index];
result += sources_[index]->confidence() * weights_[index];
}
return result / weight_sum_;
}
+15 -15
View File
@@ -18,24 +18,24 @@ namespace Analyser::Dynamic {
Summaries a collection of confidence sources by calculating their weighted sum.
*/
class ConfidenceSummary: public ConfidenceSource {
public:
/*!
Instantiates a summary that will produce the weighted sum of
@c sources, each using the corresponding entry of @c weights.
public:
/*!
Instantiates a summary that will produce the weighted sum of
@c sources, each using the corresponding entry of @c weights.
Requires that @c sources and @c weights are of the same length.
*/
ConfidenceSummary(
const std::vector<ConfidenceSource *> &sources,
const std::vector<float> &weights);
Requires that @c sources and @c weights are of the same length.
*/
ConfidenceSummary(
const std::vector<ConfidenceSource *> &sources,
const std::vector<float> &weights);
/*! @returns The weighted sum of all sources. */
float get_confidence() final;
/*! @returns The weighted sum of all sources. */
float confidence() const final;
private:
const std::vector<ConfidenceSource *> sources_;
const std::vector<float> weights_;
float weight_sum_;
private:
const std::vector<ConfidenceSource *> sources_;
const std::vector<float> weights_;
float weight_sum_;
};
}
@@ -15,90 +15,90 @@ using namespace Analyser::Dynamic;
namespace {
class MultiStruct: public Reflection::Struct {
public:
MultiStruct(const std::vector<Configurable::Device *> &devices) : devices_(devices) {
for(auto device: devices) {
options_.emplace_back(device->get_options());
public:
MultiStruct(const std::vector<Configurable::Device *> &devices) : devices_(devices) {
for(auto device: devices) {
options_.emplace_back(device->get_options());
}
}
void apply() {
auto options = options_.begin();
for(auto device: devices_) {
device->set_options(*options);
++options;
}
}
std::vector<std::string> all_keys() const final {
std::set<std::string> keys;
for(auto &options: options_) {
const auto new_keys = options->all_keys();
keys.insert(new_keys.begin(), new_keys.end());
}
return std::vector<std::string>(keys.begin(), keys.end());
}
std::vector<std::string> values_for(const std::string &name) const final {
std::set<std::string> values;
for(auto &options: options_) {
const auto new_values = options->values_for(name);
values.insert(new_values.begin(), new_values.end());
}
return std::vector<std::string>(values.begin(), values.end());
}
const std::type_info *type_of(const std::string &name) const final {
for(auto &options: options_) {
auto info = options->type_of(name);
if(info) return info;
}
return nullptr;
}
size_t count_of(const std::string &name) const final {
for(auto &options: options_) {
auto info = options->type_of(name);
if(info) return options->count_of(name);
}
return 0;
}
const void *get(const std::string &name) const final {
for(auto &options: options_) {
auto value = options->get(name);
if(value) return value;
}
return nullptr;
}
void *get(const std::string &name) final {
for(auto &options: options_) {
auto value = options->get(name);
if(value) return value;
}
return nullptr;
}
void set(const std::string &name, const void *value, const size_t offset) final {
const auto safe_type = type_of(name);
if(!safe_type) return;
// Set this property only where the child's type is the same as that
// which was returned from here for type_of.
for(auto &options: options_) {
const auto type = options->type_of(name);
if(!type) continue;
if(*type == *safe_type) {
options->set(name, value, offset);
}
}
}
void apply() {
auto options = options_.begin();
for(auto device: devices_) {
device->set_options(*options);
++options;
}
}
std::vector<std::string> all_keys() const final {
std::set<std::string> keys;
for(auto &options: options_) {
const auto new_keys = options->all_keys();
keys.insert(new_keys.begin(), new_keys.end());
}
return std::vector<std::string>(keys.begin(), keys.end());
}
std::vector<std::string> values_for(const std::string &name) const final {
std::set<std::string> values;
for(auto &options: options_) {
const auto new_values = options->values_for(name);
values.insert(new_values.begin(), new_values.end());
}
return std::vector<std::string>(values.begin(), values.end());
}
const std::type_info *type_of(const std::string &name) const final {
for(auto &options: options_) {
auto info = options->type_of(name);
if(info) return info;
}
return nullptr;
}
size_t count_of(const std::string &name) const final {
for(auto &options: options_) {
auto info = options->type_of(name);
if(info) return options->count_of(name);
}
return 0;
}
const void *get(const std::string &name) const final {
for(auto &options: options_) {
auto value = options->get(name);
if(value) return value;
}
return nullptr;
}
void *get(const std::string &name) final {
for(auto &options: options_) {
auto value = options->get(name);
if(value) return value;
}
return nullptr;
}
void set(const std::string &name, const void *value, size_t offset) final {
const auto safe_type = type_of(name);
if(!safe_type) return;
// Set this property only where the child's type is the same as that
// which was returned from here for type_of.
for(auto &options: options_) {
const auto type = options->type_of(name);
if(!type) continue;
if(*type == *safe_type) {
options->set(name, value, offset);
}
}
}
private:
const std::vector<Configurable::Device *> &devices_;
std::vector<std::unique_ptr<Reflection::Struct>> options_;
private:
const std::vector<Configurable::Device *> &devices_;
std::vector<std::unique_ptr<Reflection::Struct>> options_;
};
}
@@ -115,6 +115,6 @@ void MultiConfigurable::set_options(const std::unique_ptr<Reflection::Struct> &s
options->apply();
}
std::unique_ptr<Reflection::Struct> MultiConfigurable::get_options() {
std::unique_ptr<Reflection::Struct> MultiConfigurable::get_options() const {
return std::make_unique<MultiStruct>(devices_);
}
@@ -8,8 +8,8 @@
#pragma once
#include "../../../../Machines/DynamicMachine.hpp"
#include "../../../../Configurable/Configurable.hpp"
#include "Machines/DynamicMachine.hpp"
#include "Configurable/Configurable.hpp"
#include <memory>
#include <vector>
@@ -23,15 +23,15 @@ namespace Analyser::Dynamic {
order of delivered messages.
*/
class MultiConfigurable: public Configurable::Device {
public:
MultiConfigurable(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines);
public:
MultiConfigurable(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &);
// Below is the standard Configurable::Device interface; see there for documentation.
void set_options(const std::unique_ptr<Reflection::Struct> &options) final;
std::unique_ptr<Reflection::Struct> get_options() final;
// Below is the standard Configurable::Device interface; see there for documentation.
void set_options(const std::unique_ptr<Reflection::Struct> &) final;
std::unique_ptr<Reflection::Struct> get_options() const final;
private:
std::vector<Configurable::Device *> devices_;
private:
std::vector<Configurable::Device *> devices_;
};
}
@@ -15,52 +15,52 @@ using namespace Analyser::Dynamic;
namespace {
class MultiJoystick: public Inputs::Joystick {
public:
MultiJoystick(std::vector<MachineTypes::JoystickMachine *> &machines, std::size_t index) {
for(const auto &machine: machines) {
const auto &joysticks = machine->get_joysticks();
if(joysticks.size() >= index) {
joysticks_.push_back(joysticks[index].get());
}
public:
MultiJoystick(std::vector<MachineTypes::JoystickMachine *> &machines, const std::size_t index) {
for(const auto &machine: machines) {
const auto &joysticks = machine->get_joysticks();
if(joysticks.size() > index) {
joysticks_.push_back(joysticks[index].get());
}
}
}
const std::vector<Input> &get_inputs() final {
if(inputs.empty()) {
for(const auto &joystick: joysticks_) {
std::vector<Input> joystick_inputs = joystick->get_inputs();
for(const auto &input: joystick_inputs) {
if(std::find(inputs.begin(), inputs.end(), input) != inputs.end()) {
inputs.push_back(input);
}
const std::vector<Input> &get_inputs() final {
if(inputs.empty()) {
for(const auto &joystick: joysticks_) {
std::vector<Input> joystick_inputs = joystick->get_inputs();
for(const auto &input: joystick_inputs) {
if(std::find(inputs.begin(), inputs.end(), input) != inputs.end()) {
inputs.push_back(input);
}
}
}
return inputs;
}
void set_input(const Input &digital_input, bool is_active) final {
for(const auto &joystick: joysticks_) {
joystick->set_input(digital_input, is_active);
}
}
return inputs;
}
void set_input(const Input &digital_input, float value) final {
for(const auto &joystick: joysticks_) {
joystick->set_input(digital_input, value);
}
void set_input(const Input &digital_input, const bool is_active) final {
for(const auto &joystick: joysticks_) {
joystick->set_input(digital_input, is_active);
}
}
void reset_all_inputs() final {
for(const auto &joystick: joysticks_) {
joystick->reset_all_inputs();
}
void set_input(const Input &digital_input, const float value) final {
for(const auto &joystick: joysticks_) {
joystick->set_input(digital_input, value);
}
}
private:
std::vector<Input> inputs;
std::vector<Inputs::Joystick *> joysticks_;
void reset_all_inputs() final {
for(const auto &joystick: joysticks_) {
joystick->reset_all_inputs();
}
}
private:
std::vector<Input> inputs;
std::vector<Inputs::Joystick *> joysticks_;
};
}
@@ -8,7 +8,7 @@
#pragma once
#include "../../../../Machines/DynamicMachine.hpp"
#include "Machines/DynamicMachine.hpp"
#include <memory>
#include <vector>
@@ -22,14 +22,14 @@ namespace Analyser::Dynamic {
order of delivered messages.
*/
class MultiJoystickMachine: public MachineTypes::JoystickMachine {
public:
MultiJoystickMachine(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines);
public:
MultiJoystickMachine(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &);
// Below is the standard JoystickMachine::Machine interface; see there for documentation.
const std::vector<std::unique_ptr<Inputs::Joystick>> &get_joysticks() final;
// Below is the standard JoystickMachine::Machine interface; see there for documentation.
const std::vector<std::unique_ptr<Inputs::Joystick>> &get_joysticks() final;
private:
std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_;
private:
std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_;
};
}
@@ -24,7 +24,7 @@ void MultiKeyboardMachine::clear_all_keys() {
}
}
void MultiKeyboardMachine::set_key_state(uint16_t key, bool is_pressed) {
void MultiKeyboardMachine::set_key_state(const uint16_t key, const bool is_pressed) {
for(const auto &machine: machines_) {
machine->set_key_state(key, is_pressed);
}
@@ -36,7 +36,7 @@ void MultiKeyboardMachine::type_string(const std::string &string) {
}
}
bool MultiKeyboardMachine::can_type(char c) const {
bool MultiKeyboardMachine::can_type(const char c) const {
bool can_type = true;
for(const auto &machine: machines_) {
can_type &= machine->can_type(c);
@@ -51,12 +51,20 @@ Inputs::Keyboard &MultiKeyboardMachine::get_keyboard() {
MultiKeyboardMachine::MultiKeyboard::MultiKeyboard(const std::vector<::MachineTypes::KeyboardMachine *> &machines)
: machines_(machines) {
for(const auto &machine: machines_) {
observed_keys_.insert(machine->get_keyboard().observed_keys().begin(), machine->get_keyboard().observed_keys().end());
observed_keys_.insert(
machine->get_keyboard().observed_keys().begin(),
machine->get_keyboard().observed_keys().end()
);
is_exclusive_ |= machine->get_keyboard().is_exclusive();
}
}
bool MultiKeyboardMachine::MultiKeyboard::set_key_pressed(Key key, char value, bool is_pressed, bool is_repeat) {
bool MultiKeyboardMachine::MultiKeyboard::set_key_pressed(
const Key key,
const char value,
const bool is_pressed,
const bool is_repeat
) {
bool was_consumed = false;
for(const auto &machine: machines_) {
was_consumed |= machine->get_keyboard().set_key_pressed(key, value, is_pressed, is_repeat);
@@ -8,8 +8,8 @@
#pragma once
#include "../../../../Machines/DynamicMachine.hpp"
#include "../../../../Machines/KeyboardMachine.hpp"
#include "Machines/DynamicMachine.hpp"
#include "Machines/KeyboardMachine.hpp"
#include <memory>
#include <vector>
@@ -23,34 +23,34 @@ namespace Analyser::Dynamic {
order of delivered messages.
*/
class MultiKeyboardMachine: public MachineTypes::KeyboardMachine {
private:
std::vector<MachineTypes::KeyboardMachine *> machines_;
class MultiKeyboard: public Inputs::Keyboard {
public:
MultiKeyboard(const std::vector<MachineTypes::KeyboardMachine *> &machines);
bool set_key_pressed(Key key, char value, bool is_pressed, bool is_repeat) final;
void reset_all_keys() final;
const std::set<Key> &observed_keys() const final;
bool is_exclusive() const final;
private:
const std::vector<MachineTypes::KeyboardMachine *> &machines_;
std::set<Key> observed_keys_;
bool is_exclusive_ = false;
};
std::unique_ptr<MultiKeyboard> keyboard_;
private:
std::vector<MachineTypes::KeyboardMachine *> machines_;
class MultiKeyboard: public Inputs::Keyboard {
public:
MultiKeyboardMachine(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines);
MultiKeyboard(const std::vector<MachineTypes::KeyboardMachine *> &);
// Below is the standard KeyboardMachine::Machine interface; see there for documentation.
void clear_all_keys() final;
void set_key_state(uint16_t key, bool is_pressed) final;
void type_string(const std::string &) final;
bool can_type(char c) const final;
Inputs::Keyboard &get_keyboard() final;
bool set_key_pressed(Key key, char value, bool is_pressed, bool is_repeat) final;
void reset_all_keys() final;
const std::set<Key> &observed_keys() const final;
bool is_exclusive() const final;
private:
const std::vector<MachineTypes::KeyboardMachine *> &machines_;
std::set<Key> observed_keys_;
bool is_exclusive_ = false;
};
std::unique_ptr<MultiKeyboard> keyboard_;
public:
MultiKeyboardMachine(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines);
// Below is the standard KeyboardMachine::Machine interface; see there for documentation.
void clear_all_keys() final;
void set_key_state(uint16_t key, bool is_pressed) final;
void type_string(const std::string &) final;
bool can_type(char c) const final;
Inputs::Keyboard &get_keyboard() final;
};
}
@@ -7,6 +7,7 @@
//
#include "MultiMediaTarget.hpp"
#include <unordered_set>
using namespace Analyser::Dynamic;
@@ -18,9 +19,38 @@ MultiMediaTarget::MultiMediaTarget(const std::vector<std::unique_ptr<::Machine::
}
bool MultiMediaTarget::insert_media(const Analyser::Static::Media &media) {
// TODO: copy media afresh for each target machine; media
// generally has mutable state.
bool inserted = false;
for(const auto &target : targets_) {
inserted |= target->insert_media(media);
}
return inserted;
}
MultiMediaChangeObserver::MultiMediaChangeObserver(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines) {
for(const auto &machine: machines) {
auto media_change_observer = machine->media_change_observer();
if(media_change_observer) targets_.push_back(media_change_observer);
}
}
using ChangeEffect = MachineTypes::MediaChangeObserver::ChangeEffect;
ChangeEffect MultiMediaChangeObserver::effect_for_file_did_change(const std::string &name) const {
if(targets_.empty()) {
return ChangeEffect::None;
}
std::unordered_set<ChangeEffect> effects;
for(const auto &target: targets_) {
effects.insert(target->effect_for_file_did_change(name));
}
// No agreement => restart.
if(effects.size() > 1) {
return ChangeEffect::RestartMachine;
}
return *effects.begin();
}
@@ -8,8 +8,8 @@
#pragma once
#include "../../../../Machines/MediaTarget.hpp"
#include "../../../../Machines/DynamicMachine.hpp"
#include "Machines/MediaTarget.hpp"
#include "Machines/DynamicMachine.hpp"
#include <memory>
#include <vector>
@@ -23,14 +23,25 @@ namespace Analyser::Dynamic {
order of delivered messages.
*/
struct MultiMediaTarget: public MachineTypes::MediaTarget {
public:
MultiMediaTarget(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines);
public:
MultiMediaTarget(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &);
// Below is the standard MediaTarget::Machine interface; see there for documentation.
bool insert_media(const Analyser::Static::Media &media) final;
// Below is the standard MediaTarget::Machine interface; see there for documentation.
bool insert_media(const Analyser::Static::Media &) final;
private:
std::vector<MachineTypes::MediaTarget *> targets_;
private:
std::vector<MachineTypes::MediaTarget *> targets_;
};
struct MultiMediaChangeObserver: public MachineTypes::MediaChangeObserver {
public:
MultiMediaChangeObserver(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &);
// Below is the standard MediaTarget::Machine interface; see there for documentation.
ChangeEffect effect_for_file_did_change(const std::string &) const final;
private:
std::vector<MachineTypes::MediaChangeObserver *> targets_;
};
}
@@ -19,7 +19,7 @@ template <typename MachineType>
void MultiInterface<MachineType>::perform_parallel(const std::function<void(MachineType *)> &function) {
// Apply a blunt force parallelisation of the machines; each run_for is dispatched
// to a separate queue and this queue will block until all are done.
volatile std::size_t outstanding_machines;
std::size_t outstanding_machines;
std::condition_variable condition;
std::mutex mutex;
{
@@ -33,7 +33,7 @@ void MultiInterface<MachineType>::perform_parallel(const std::function<void(Mach
if(machine) function(machine);
std::lock_guard lock(mutex);
outstanding_machines--;
--outstanding_machines;
condition.notify_all();
});
}
@@ -53,7 +53,7 @@ void MultiInterface<MachineType>::perform_serial(const std::function<void(Machin
}
// MARK: - MultiScanProducer
void MultiScanProducer::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
void MultiScanProducer::set_scan_target(Outputs::Display::ScanTarget *const scan_target) {
scan_target_ = scan_target;
std::lock_guard machines_lock(machines_mutex_);
@@ -80,7 +80,12 @@ void MultiScanProducer::did_change_machine_order() {
}
// MARK: - MultiAudioProducer
MultiAudioProducer::MultiAudioProducer(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines, std::recursive_mutex &machines_mutex) : MultiInterface(machines, machines_mutex) {
MultiAudioProducer::MultiAudioProducer(
const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines,
std::recursive_mutex &machines_mutex
) :
MultiInterface(machines, machines_mutex)
{
speaker_ = MultiSpeaker::create(machines);
}
@@ -96,10 +101,10 @@ void MultiAudioProducer::did_change_machine_order() {
// MARK: - MultiTimedMachine
void MultiTimedMachine::run_for(Time::Seconds duration) {
void MultiTimedMachine::run_for(const Time::Seconds duration) {
perform_parallel([duration](::MachineTypes::TimedMachine *machine) {
if(machine->get_confidence() >= 0.01f) machine->run_for(duration);
});
if(delegate_) delegate_->did_run_machines(this);
if(delegate_) delegate_->did_run_machines(*this);
}
@@ -8,9 +8,9 @@
#pragma once
#include "../../../../Concurrency/AsyncTaskQueue.hpp"
#include "../../../../Machines/MachineTypes.hpp"
#include "../../../../Machines/DynamicMachine.hpp"
#include "Concurrency/AsyncTaskQueue.hpp"
#include "Machines/MachineTypes.hpp"
#include "Machines/DynamicMachine.hpp"
#include "MultiSpeaker.hpp"
@@ -21,88 +21,91 @@
namespace Analyser::Dynamic {
template <typename MachineType> class MultiInterface {
public:
MultiInterface(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines, std::recursive_mutex &machines_mutex) :
machines_(machines), machines_mutex_(machines_mutex), queues_(machines.size()) {}
public:
MultiInterface(
const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines,
std::recursive_mutex &machines_mutex
) :
machines_(machines), machines_mutex_(machines_mutex), queues_(machines.size()) {}
protected:
/*!
Performs a parallel for operation across all machines, performing the supplied
function on each and returning only once all applications have completed.
protected:
/*!
Performs a parallel for operation across all machines, performing the supplied
function on each and returning only once all applications have completed.
No guarantees are extended as to which thread operations will occur on.
*/
void perform_parallel(const std::function<void(MachineType *)> &);
No guarantees are extended as to which thread operations will occur on.
*/
void perform_parallel(const std::function<void(MachineType *)> &);
/*!
Performs a serial for operation across all machines, performing the supplied
function on each on the calling thread.
*/
void perform_serial(const std::function<void(MachineType *)> &);
/*!
Performs a serial for operation across all machines, performing the supplied
function on each on the calling thread.
*/
void perform_serial(const std::function<void(MachineType *)> &);
protected:
const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines_;
std::recursive_mutex &machines_mutex_;
protected:
const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines_;
std::recursive_mutex &machines_mutex_;
private:
std::vector<Concurrency::AsyncTaskQueue<true>> queues_;
private:
std::vector<Concurrency::AsyncTaskQueue<true>> queues_;
};
class MultiTimedMachine: public MultiInterface<MachineTypes::TimedMachine>, public MachineTypes::TimedMachine {
public:
using MultiInterface::MultiInterface;
public:
using MultiInterface::MultiInterface;
/*!
Provides a mechanism by which a delegate can be informed each time a call to run_for has
been received.
*/
struct Delegate {
virtual void did_run_machines(MultiTimedMachine *) = 0;
};
/// Sets @c delegate as the receiver of delegate messages.
void set_delegate(Delegate *delegate) {
delegate_ = delegate;
}
/*!
Provides a mechanism by which a delegate can be informed each time a call to run_for has
been received.
*/
struct Delegate {
virtual void did_run_machines(MultiTimedMachine &) = 0;
};
/// Sets @c delegate as the receiver of delegate messages.
void set_delegate(Delegate *const delegate) {
delegate_ = delegate;
}
void run_for(Time::Seconds duration) final;
void run_for(Time::Seconds duration) final;
private:
void run_for(const Cycles) final {}
Delegate *delegate_ = nullptr;
private:
void run_for(Cycles) final {}
Delegate *delegate_ = nullptr;
};
class MultiScanProducer: public MultiInterface<MachineTypes::ScanProducer>, public MachineTypes::ScanProducer {
public:
using MultiInterface::MultiInterface;
public:
using MultiInterface::MultiInterface;
/*!
Informs the MultiScanProducer that the order of machines has changed; it
uses this as an opportunity to synthesis any CRTMachine::Machine::Delegate messages that
are necessary to bridge the gap between one machine and the next.
*/
void did_change_machine_order();
/*!
Informs the MultiScanProducer that the order of machines has changed; it
uses this as an opportunity to synthesis any CRTMachine::Machine::Delegate messages that
are necessary to bridge the gap between one machine and the next.
*/
void did_change_machine_order();
void set_scan_target(Outputs::Display::ScanTarget *scan_target) final;
Outputs::Display::ScanStatus get_scan_status() const final;
void set_scan_target(Outputs::Display::ScanTarget *) final;
Outputs::Display::ScanStatus get_scan_status() const final;
private:
Outputs::Display::ScanTarget *scan_target_ = nullptr;
private:
Outputs::Display::ScanTarget *scan_target_ = nullptr;
};
class MultiAudioProducer: public MultiInterface<MachineTypes::AudioProducer>, public MachineTypes::AudioProducer {
public:
MultiAudioProducer(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines, std::recursive_mutex &machines_mutex);
public:
MultiAudioProducer(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &, std::recursive_mutex &);
/*!
Informs the MultiAudio that the order of machines has changed; it
uses this as an opportunity to switch speaker delegates as appropriate.
*/
void did_change_machine_order();
/*!
Informs the MultiAudio that the order of machines has changed; it
uses this as an opportunity to switch speaker delegates as appropriate.
*/
void did_change_machine_order();
Outputs::Speaker::Speaker *get_speaker() final;
Outputs::Speaker::Speaker *get_speaker() final;
private:
MultiSpeaker *speaker_ = nullptr;
private:
MultiSpeaker *speaker_ = nullptr;
};
/*!
@@ -28,7 +28,7 @@ MultiSpeaker::MultiSpeaker(const std::vector<Outputs::Speaker::Speaker *> &speak
}
}
float MultiSpeaker::get_ideal_clock_rate_in_range(float minimum, float maximum) {
float MultiSpeaker::get_ideal_clock_rate_in_range(const float minimum, const float maximum) {
float ideal = 0.0f;
for(const auto &speaker: speakers_) {
ideal += speaker->get_ideal_clock_rate_in_range(minimum, maximum);
@@ -37,7 +37,7 @@ float MultiSpeaker::get_ideal_clock_rate_in_range(float minimum, float maximum)
return ideal / float(speakers_.size());
}
void MultiSpeaker::set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) {
void MultiSpeaker::set_computed_output_rate(const float cycles_per_second, const int buffer_size, const bool stereo) {
stereo_output_ = stereo;
for(const auto &speaker: speakers_) {
speaker->set_computed_output_rate(cycles_per_second, buffer_size, stereo);
@@ -54,39 +54,39 @@ bool MultiSpeaker::get_is_stereo() {
return false;
}
void MultiSpeaker::set_output_volume(float volume) {
void MultiSpeaker::set_output_volume(const float volume) {
for(const auto &speaker: speakers_) {
speaker->set_output_volume(volume);
}
}
void MultiSpeaker::speaker_did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) {
void MultiSpeaker::speaker_did_complete_samples(Speaker &speaker, const std::vector<int16_t> &buffer) {
auto delegate = delegate_.load(std::memory_order_relaxed);
if(!delegate) return;
{
std::lock_guard lock_guard(front_speaker_mutex_);
if(speaker != front_speaker_) return;
if(&speaker != front_speaker_) return;
}
did_complete_samples(this, buffer, stereo_output_);
}
void MultiSpeaker::speaker_did_change_input_clock(Speaker *speaker) {
void MultiSpeaker::speaker_did_change_input_clock(Speaker &speaker) {
auto delegate = delegate_.load(std::memory_order_relaxed);
if(!delegate) return;
{
std::lock_guard lock_guard(front_speaker_mutex_);
if(speaker != front_speaker_) return;
if(&speaker != front_speaker_) return;
}
delegate->speaker_did_change_input_clock(this);
delegate->speaker_did_change_input_clock(*this);
}
void MultiSpeaker::set_new_front_machine(::Machine::DynamicMachine *machine) {
void MultiSpeaker::set_new_front_machine(::Machine::DynamicMachine *const machine) {
{
std::lock_guard lock_guard(front_speaker_mutex_);
front_speaker_ = machine->audio_producer()->get_speaker();
}
auto delegate = delegate_.load(std::memory_order_relaxed);
if(delegate) {
delegate->speaker_did_change_input_clock(this);
delegate->speaker_did_change_input_clock(*this);
}
}
@@ -8,8 +8,8 @@
#pragma once
#include "../../../../Machines/DynamicMachine.hpp"
#include "../../../../Outputs/Speaker/Speaker.hpp"
#include "Machines/DynamicMachine.hpp"
#include "Outputs/Speaker/Speaker.hpp"
#include <memory>
#include <mutex>
@@ -25,32 +25,32 @@ namespace Analyser::Dynamic {
abreast of the current frontmost machine.
*/
class MultiSpeaker: public Outputs::Speaker::Speaker, Outputs::Speaker::Speaker::Delegate {
public:
/*!
Provides a construction mechanism that may return nullptr, in the case that all included
machines return nullptr as their speaker.
*/
static MultiSpeaker *create(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines);
public:
/*!
Provides a construction mechanism that may return nullptr, in the case that all included
machines return nullptr as their speaker.
*/
static MultiSpeaker *create(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &);
/// This class requires the caller to nominate changes in the frontmost machine.
void set_new_front_machine(::Machine::DynamicMachine *machine);
/// This class requires the caller to nominate changes in the frontmost machine.
void set_new_front_machine(::Machine::DynamicMachine *);
// Below is the standard Outputs::Speaker::Speaker interface; see there for documentation.
float get_ideal_clock_rate_in_range(float minimum, float maximum) override;
void set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) override;
bool get_is_stereo() override;
void set_output_volume(float) override;
// Below is the standard Outputs::Speaker::Speaker interface; see there for documentation.
float get_ideal_clock_rate_in_range(float minimum, float maximum) override;
void set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) override;
bool get_is_stereo() override;
void set_output_volume(float) override;
private:
void speaker_did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) final;
void speaker_did_change_input_clock(Speaker *speaker) final;
MultiSpeaker(const std::vector<Outputs::Speaker::Speaker *> &speakers);
private:
void speaker_did_complete_samples(Speaker &, const std::vector<int16_t> &buffer) final;
void speaker_did_change_input_clock(Speaker &) final;
MultiSpeaker(const std::vector<Outputs::Speaker::Speaker *> &speakers);
std::vector<Outputs::Speaker::Speaker *> speakers_;
Outputs::Speaker::Speaker *front_speaker_ = nullptr;
std::mutex front_speaker_mutex_;
std::vector<Outputs::Speaker::Speaker *> speakers_;
Outputs::Speaker::Speaker *front_speaker_ = nullptr;
std::mutex front_speaker_mutex_;
bool stereo_output_ = false;
bool stereo_output_ = false;
};
}
+15 -14
View File
@@ -7,14 +7,12 @@
//
#include "MultiMachine.hpp"
#include "../../../Outputs/Log.hpp"
#include "Outputs/Log.hpp"
#include <algorithm>
namespace {
Log::Logger<Log::Source::MultiMachine> logger;
using Logger = Log::Logger<Log::Source::MultiMachine>;
}
using namespace Analyser::Dynamic;
@@ -27,7 +25,9 @@ MultiMachine::MultiMachine(std::vector<std::unique_ptr<DynamicMachine>> &&machin
audio_producer_(machines_, machines_mutex_),
joystick_machine_(machines_),
keyboard_machine_(machines_),
media_target_(machines_) {
media_target_(machines_),
media_change_observer_(machines_)
{
timed_machine_.set_delegate(this);
}
@@ -35,13 +35,13 @@ Activity::Source *MultiMachine::activity_source() {
return nullptr; // TODO
}
#define Provider(type, name, member) \
type *MultiMachine::name() { \
if(has_picked_) { \
#define Provider(type, name, member) \
type *MultiMachine::name() { \
if(has_picked_) { \
return machines_.front()->name(); \
} else { \
return &member; \
} \
} else { \
return &member; \
} \
}
Provider(Configurable::Device, configurable_device, configurable_)
@@ -51,6 +51,7 @@ Provider(MachineTypes::AudioProducer, audio_producer, audio_producer_)
Provider(MachineTypes::JoystickMachine, joystick_machine, joystick_machine_)
Provider(MachineTypes::KeyboardMachine, keyboard_machine, keyboard_machine_)
Provider(MachineTypes::MediaTarget, media_target, media_target_)
Provider(MachineTypes::MediaChangeObserver, media_change_observer, media_change_observer_)
MachineTypes::MouseMachine *MultiMachine::mouse_machine() {
// TODO.
@@ -65,11 +66,11 @@ bool MultiMachine::would_collapse(const std::vector<std::unique_ptr<DynamicMachi
(machines.front()->timed_machine()->get_confidence() >= 2.0f * machines[1]->timed_machine()->get_confidence());
}
void MultiMachine::did_run_machines(MultiTimedMachine *) {
void MultiMachine::did_run_machines(MultiTimedMachine &) {
std::lock_guard machines_lock(machines_mutex_);
if constexpr (logger.enabled) {
auto line = logger.info();
if constexpr (Logger::InfoEnabled) {
auto line = Logger::info();
for(const auto &machine: machines_) {
auto timed_machine = machine->timed_machine();
line.append("%0.4f %s; ", timed_machine->get_confidence(), timed_machine->debug_type().c_str());
+41 -39
View File
@@ -8,14 +8,14 @@
#pragma once
#include "../../../Machines/DynamicMachine.hpp"
#include "Machines/DynamicMachine.hpp"
#include "Implementation/MultiProducer.hpp"
#include "Implementation/MultiConfigurable.hpp"
#include "Implementation/MultiProducer.hpp"
#include "Implementation/MultiJoystickMachine.hpp"
#include "Implementation/MultiKeyboardMachine.hpp"
#include "Implementation/MultiMediaTarget.hpp"
#include "Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.hpp"
#include "Analyser/Dynamic/MultiMachine/Implementation/MultiConfigurable.hpp"
#include "Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.hpp"
#include "Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp"
#include "Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp"
#include "Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.hpp"
#include <memory>
#include <mutex>
@@ -38,44 +38,46 @@ namespace Analyser::Dynamic {
the others in the set, that machine stops running.
*/
class MultiMachine: public ::Machine::DynamicMachine, public MultiTimedMachine::Delegate {
public:
/*!
Allows a potential MultiMachine creator to enquire as to whether there's any benefit in
requesting this class as a proxy.
public:
/*!
Allows a potential MultiMachine creator to enquire as to whether there's any benefit in
requesting this class as a proxy.
@returns @c true if the multimachine would discard all but the first machine in this list;
@c false otherwise.
*/
static bool would_collapse(const std::vector<std::unique_ptr<DynamicMachine>> &machines);
MultiMachine(std::vector<std::unique_ptr<DynamicMachine>> &&machines);
@returns @c true if the multimachine would discard all but the first machine in this list;
@c false otherwise.
*/
static bool would_collapse(const std::vector<std::unique_ptr<DynamicMachine>> &);
MultiMachine(std::vector<std::unique_ptr<DynamicMachine>> &&);
Activity::Source *activity_source() final;
Configurable::Device *configurable_device() final;
MachineTypes::TimedMachine *timed_machine() final;
MachineTypes::ScanProducer *scan_producer() final;
MachineTypes::AudioProducer *audio_producer() final;
MachineTypes::JoystickMachine *joystick_machine() final;
MachineTypes::KeyboardMachine *keyboard_machine() final;
MachineTypes::MouseMachine *mouse_machine() final;
MachineTypes::MediaTarget *media_target() final;
void *raw_pointer() final;
Activity::Source *activity_source() final;
Configurable::Device *configurable_device() final;
MachineTypes::TimedMachine *timed_machine() final;
MachineTypes::ScanProducer *scan_producer() final;
MachineTypes::AudioProducer *audio_producer() final;
MachineTypes::JoystickMachine *joystick_machine() final;
MachineTypes::KeyboardMachine *keyboard_machine() final;
MachineTypes::MouseMachine *mouse_machine() final;
MachineTypes::MediaTarget *media_target() final;
MachineTypes::MediaChangeObserver *media_change_observer() final;
void *raw_pointer() final;
private:
void did_run_machines(MultiTimedMachine *) final;
private:
void did_run_machines(MultiTimedMachine &) final;
std::vector<std::unique_ptr<DynamicMachine>> machines_;
std::recursive_mutex machines_mutex_;
std::vector<std::unique_ptr<DynamicMachine>> machines_;
std::recursive_mutex machines_mutex_;
MultiConfigurable configurable_;
MultiTimedMachine timed_machine_;
MultiScanProducer scan_producer_;
MultiAudioProducer audio_producer_;
MultiJoystickMachine joystick_machine_;
MultiKeyboardMachine keyboard_machine_;
MultiMediaTarget media_target_;
MultiConfigurable configurable_;
MultiTimedMachine timed_machine_;
MultiScanProducer scan_producer_;
MultiAudioProducer audio_producer_;
MultiJoystickMachine joystick_machine_;
MultiKeyboardMachine keyboard_machine_;
MultiMediaTarget media_target_;
MultiMediaChangeObserver media_change_observer_;
void pick_first();
bool has_picked_ = false;
void pick_first();
bool has_picked_ = false;
};
}
+2
View File
@@ -18,6 +18,7 @@ enum class Machine {
AtariST,
Amiga,
Archimedes,
BBCMicro,
ColecoVision,
Electron,
Enterprise,
@@ -25,6 +26,7 @@ enum class Machine {
MasterSystem,
MSX,
Oric,
Plus4,
PCCompatible,
Vic20,
ZX8081,
+32 -14
View File
@@ -8,9 +8,9 @@
#include "Disk.hpp"
#include "../../../Storage/Disk/Controller/DiskController.hpp"
#include "../../../Storage/Disk/Encodings/MFM/Parser.hpp"
#include "../../../Numeric/CRC.hpp"
#include "Storage/Disk/Controller/DiskController.hpp"
#include "Storage/Disk/Encodings/MFM/Parser.hpp"
#include "Numeric/CRC.hpp"
#include <algorithm>
#include <cstring>
@@ -44,32 +44,44 @@ std::unique_ptr<Catalogue> Analyser::Static::Acorn::GetDFSCatalogue(const std::s
case 3: catalogue->bootOption = Catalogue::BootOption::ExecBOOT; break;
}
for(std::size_t file_offset = 8; file_offset < final_file_offset; file_offset += 8) {
for(std::size_t file_offset = 8; file_offset <= final_file_offset; file_offset += 8) {
File new_file;
char name[10];
snprintf(name, 10, "%c.%.7s", names->samples[0][file_offset + 7] & 0x7f, &names->samples[0][file_offset]);
new_file.name = name;
new_file.load_address = uint32_t(details->samples[0][file_offset] | (details->samples[0][file_offset+1] << 8) | ((details->samples[0][file_offset+6]&0x0c) << 14));
new_file.execution_address = uint32_t(details->samples[0][file_offset+2] | (details->samples[0][file_offset+3] << 8) | ((details->samples[0][file_offset+6]&0xc0) << 10));
new_file.load_address = uint32_t(
details->samples[0][file_offset] |
(details->samples[0][file_offset+1] << 8) |
((details->samples[0][file_offset+6]&0x0c) << 14)
);
new_file.execution_address = uint32_t(
details->samples[0][file_offset+2] |
(details->samples[0][file_offset+3] << 8) |
((details->samples[0][file_offset+6]&0xc0) << 10)
);
if(names->samples[0][file_offset + 7] & 0x80) {
// File is locked; it may not be altered or deleted.
new_file.flags |= File::Flags::Locked;
}
long data_length = long(details->samples[0][file_offset+4] | (details->samples[0][file_offset+5] << 8) | ((details->samples[0][file_offset+6]&0x30) << 12));
auto data_length = long(
details->samples[0][file_offset+4] |
(details->samples[0][file_offset+5] << 8) |
((details->samples[0][file_offset+6]&0x30) << 12)
);
int start_sector = details->samples[0][file_offset+7] | ((details->samples[0][file_offset+6]&0x03) << 8);
new_file.data.reserve(size_t(data_length));
if(start_sector < 2) continue;
while(data_length > 0) {
uint8_t sector = uint8_t(start_sector % 10);
uint8_t track = uint8_t(start_sector / 10);
start_sector++;
const uint8_t sector = uint8_t(start_sector % 10);
const uint8_t track = uint8_t(start_sector / 10);
++start_sector;
const Storage::Encodings::MFM::Sector *next_sector = parser.sector(0, track, sector);
if(!next_sector) break;
long length_from_sector = std::min(data_length, 256l);
const long length_from_sector = std::min(data_length, 256l);
new_file.data.insert(new_file.data.end(), next_sector->samples[0].begin(), next_sector->samples[0].begin() + length_from_sector);
data_length -= length_from_sector;
}
@@ -133,7 +145,8 @@ std::unique_ptr<Catalogue> Analyser::Static::Acorn::GetADFSCatalogue(const std::
}
// Parse the root directory, at least.
for(std::size_t file_offset = 0x005; file_offset < (catalogue->has_large_sectors ? 0x7d7 : 0x4cb); file_offset += 0x1a) {
const std::size_t directory_extent = catalogue->has_large_sectors ? 0x7d7 : 0x4cb;
for(std::size_t file_offset = 0x005; file_offset < directory_extent; file_offset += 0x1a) {
// Obtain the name, which will be at most ten characters long, and will
// be terminated by either a NULL character or a \r.
char name[11]{};
@@ -190,11 +203,16 @@ std::unique_ptr<Catalogue> Analyser::Static::Acorn::GetADFSCatalogue(const std::
new_file.data.reserve(size);
while(new_file.data.size() < size) {
const Storage::Encodings::MFM::Sector *const sector = parser.sector(start_sector / (80 * 16), (start_sector / 16) % 80, start_sector % 16);
const Storage::Encodings::MFM::Sector *const sector =
parser.sector(start_sector / (80 * 16), (start_sector / 16) % 80, start_sector % 16);
if(!sector) break;
const auto length_from_sector = std::min(size - new_file.data.size(), sector->samples[0].size());
new_file.data.insert(new_file.data.end(), sector->samples[0].begin(), sector->samples[0].begin() + ssize_t(length_from_sector));
new_file.data.insert(
new_file.data.end(),
sector->samples[0].begin(),
sector->samples[0].begin() + ssize_t(length_from_sector)
);
++start_sector;
}
+3 -3
View File
@@ -9,7 +9,7 @@
#pragma once
#include "File.hpp"
#include "../../../Storage/Disk/Disk.hpp"
#include "Storage/Disk/Disk.hpp"
namespace Analyser::Static::Acorn {
@@ -27,7 +27,7 @@ struct Catalogue {
} bootOption;
};
std::unique_ptr<Catalogue> GetDFSCatalogue(const std::shared_ptr<Storage::Disk::Disk> &disk);
std::unique_ptr<Catalogue> GetADFSCatalogue(const std::shared_ptr<Storage::Disk::Disk> &disk);
std::unique_ptr<Catalogue> GetDFSCatalogue(const std::shared_ptr<Storage::Disk::Disk> &);
std::unique_ptr<Catalogue> GetADFSCatalogue(const std::shared_ptr<Storage::Disk::Disk> &);
}
+1
View File
@@ -8,6 +8,7 @@
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
+185 -67
View File
@@ -12,28 +12,45 @@
#include "Tape.hpp"
#include "Target.hpp"
#include "../../../Numeric/StringSimilarity.hpp"
#include "Numeric/StringSimilarity.hpp"
#include <algorithm>
#include <map>
using namespace Analyser::Static::Acorn;
namespace {
bool is_basic(const File &file) {
std::size_t pointer = 0;
const uint8_t *const data = file.data.data();
const std::size_t data_size = file.data.size();
while(true) {
if(pointer >= data_size-1 || data[pointer] != 0x0d) {
return false;
}
if((data[pointer+1]&0x7f) == 0x7f) break;
pointer += data[pointer+3];
}
return true;
}
}
static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
AcornCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
AcornCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> acorn_cartridges;
for(const auto &cartridge : cartridges) {
const auto &segments = cartridge->get_segments();
// only one mapped item is allowed
// Only one mapped item is allowed.
if(segments.size() != 1) continue;
// which must be 8 or 16 kb in size
// Cartridges must be 8 or 16 kb in size.
const Storage::Cartridge::Cartridge::Segment &segment = segments.front();
if(segment.data.size() != 0x4000 && segment.data.size() != 0x2000) continue;
// is a copyright string present?
// Check copyright string.
const uint8_t copyright_offset = segment.data[7];
if(
segment.data[copyright_offset] != 0x00 ||
@@ -42,16 +59,16 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
segment.data[copyright_offset+3] != 0x29
) continue;
// is the language entry point valid?
// Check language entry point.
if(!(
(segment.data[0] == 0x00 && segment.data[1] == 0x00 && segment.data[2] == 0x00) ||
(segment.data[0] != 0x00 && segment.data[2] >= 0x80 && segment.data[2] < 0xc0)
)) continue;
// is the service entry point valid?
// Check service entry point.
if(!(segment.data[5] >= 0x80 && segment.data[5] < 0xc0)) continue;
// probability of a random binary blob that isn't an Acorn ROM proceeding to here:
// Probability of a random binary blob that isn't an Acorn ROM proceeding to here:
// 1/(2^32) *
// ( ((2^24)-1)/(2^24)*(1/4) + 1/(2^24) ) *
// 1/4
@@ -62,45 +79,44 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
return acorn_cartridges;
}
Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType) {
auto target8bit = std::make_unique<ElectronTarget>();
Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(
const Media &media,
const std::string &file_name,
TargetPlatform::IntType,
bool
) {
const auto early_exit = [](auto &ptr) {
TargetList list;
list.push_back(std::move(ptr));
return list;
};
auto targetElectron = std::make_unique<ElectronTarget>();
auto targetBBC = std::make_unique<BBCMicroTarget>();
auto targetArchimedes = std::make_unique<ArchimedesTarget>();
int bbc_hits = 0;
int electron_hits = 0;
bool format_prefers_bbc = false;
// Copy appropriate cartridges to the 8-bit target.
target8bit->media.cartridges = AcornCartridgesFrom(media.cartridges);
// Copy appropriate cartridges to the 8-bit targets.
targetElectron->media.cartridges = AcornCartridgesFrom(media.cartridges);
targetBBC->media.cartridges = AcornCartridgesFrom(media.cartridges);
// If there are any tapes, attempt to get data from the first.
// If there are tapes, attempt to get data from the first.
if(!media.tapes.empty()) {
std::shared_ptr<Storage::Tape::Tape> tape = media.tapes.front();
std::vector<File> files = GetFiles(tape);
tape->reset();
auto serialiser = tape->serialiser();
std::vector<File> files = GetFiles(*serialiser);
// continue if there are any files
// Continue only if there are any files.
if(!files.empty()) {
bool is_basic = true;
// If a file is execute-only, that means *RUN.
if(files.front().flags & File::Flags::ExecuteOnly) is_basic = false;
// check also for a continuous threading of BASIC lines; if none then this probably isn't BASIC code,
// so that's also justification to *RUN
std::size_t pointer = 0;
uint8_t *const data = &files.front().data[0];
const std::size_t data_size = files.front().data.size();
while(1) {
if(pointer >= data_size-1 || data[pointer] != 13) {
is_basic = false;
break;
}
if((data[pointer+1]&0x7f) == 0x7f) break;
pointer += data[pointer+3];
}
// Inspect first file. If it's protected or doesn't look like BASIC
// then the loading command is *RUN. Otherwise it's CHAIN"".
target8bit->loading_command = is_basic ? "CHAIN\"\"\n" : "*RUN\n";
targetElectron->loading_command =
(files.front().flags & File::Flags::ExecuteOnly) || !is_basic(files.front()) ? "*RUN\n" : "CHAIN\"\"\n";
targetElectron->media.tapes = media.tapes;
target8bit->media.tapes = media.tapes;
// TODO: my BBC Micro doesn't yet support tapes; evaluate here in the future.
}
}
@@ -115,25 +131,67 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me
// 8-bit options: DFS and Hugo-style ADFS.
if(dfs_catalogue || (adfs_catalogue && !adfs_catalogue->has_large_sectors && adfs_catalogue->is_hugo)) {
// Accept the disk and determine whether DFS or ADFS ROMs are implied.
// Use the Pres ADFS if using an ADFS, as it leaves Page at &EOO.
target8bit->media.disks = media.disks;
target8bit->has_dfs = bool(dfs_catalogue);
target8bit->has_pres_adfs = bool(adfs_catalogue);
// Check whether a simple shift+break will do for loading this disk.
Catalogue::BootOption bootOption = (dfs_catalogue ?: adfs_catalogue)->bootOption;
if(bootOption != Catalogue::BootOption::None) {
target8bit->should_shift_restart = true;
} else {
target8bit->loading_command = "*CAT\n";
// Electron: use the Pres ADFS if using an ADFS, as it leaves Page at &E00.
targetElectron->media.disks = media.disks;
targetElectron->has_dfs = bool(dfs_catalogue);
targetElectron->has_pres_adfs = bool(adfs_catalogue);
// BBC: only the 1770 DFS is currently supported, so use that.
targetBBC->media.disks = media.disks;
targetBBC->has_1770dfs = bool(dfs_catalogue);
targetBBC->has_adfs = bool(adfs_catalogue);
// Special case: if there's only one file, and it is called CPMDISC,
// select a BBC with the Z80 second processor.
const auto &files = dfs_catalogue ? dfs_catalogue->files : adfs_catalogue->files;
if(files.size() == 1 && files[0].name == "$.CPMDISC") {
targetBBC->tube_processor = BBCMicroTarget::TubeProcessor::Z80;
return early_exit(targetBBC);
}
// Check whether adding the AP6 ROM is justified.
// For now this is an incredibly dense text search;
// if any of the commands that aren't usually present
// on a stock Electron are here, add the AP6 ROM and
// some sideways RAM such that the SR commands are useful.
for(const auto &file: dfs_catalogue ? dfs_catalogue->files : adfs_catalogue->files) {
// Check whether a simple shift+break will do for loading this disk.
const auto bootOption = (dfs_catalogue ?: adfs_catalogue)->bootOption;
if(bootOption != Catalogue::BootOption::None) {
targetBBC->should_shift_restart = targetElectron->should_shift_restart = true;
} else {
// Otherwise: if there's only one BASIC program then chain it.
// Failing that, do a *CAT to be communicative.
const File *sole_basic_file = nullptr;
for(const auto &file: dfs_catalogue ? dfs_catalogue->files : adfs_catalogue->files) {
if(is_basic(file)) {
if(!sole_basic_file) {
sole_basic_file = &file;
} else {
sole_basic_file = nullptr;
break;
}
}
}
targetBBC->loading_command = targetElectron->loading_command =
sole_basic_file ? "CHAIN \"" + sole_basic_file->name + "\"\n" : "*CAT\n";
}
// Further special case: if any of the files have a top word of 0x0003 then
// they're for a 6502 second processor, so provide a BBC with one of those.
for(const auto &file: files) {
if((file.load_address >> 16) == 3) {
targetBBC->tube_processor = BBCMicroTarget::TubeProcessor::WDC65C02;
return early_exit(targetBBC);
}
}
// Add a slight preference for the BBC over the Electron, all else being equal, if this is a DFS floppy.
format_prefers_bbc = bool(dfs_catalogue);
for(const auto &file: files) {
// Electron: check whether adding the AP6 ROM is justified.
// For now this is an incredibly dense text search;
// if any of the commands that aren't usually present
// on a stock Electron are here, add the AP6 ROM and
// some sideways RAM such that the SR commands are useful.
for(const auto &command: {
"AQRPAGE", "BUILD", "DUMP", "FORMAT", "INSERT", "LANG", "LIST", "LOADROM",
"LOCK", "LROMS", "RLOAD", "ROMS", "RSAVE", "SAVEROM", "SRLOAD", "SRPAGE",
@@ -141,10 +199,60 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me
"VERIFY", "ZERO"
}) {
if(std::search(file.data.begin(), file.data.end(), command, command+strlen(command)) != file.data.end()) {
target8bit->has_ap6_rom = true;
target8bit->has_sideways_ram = true;
targetElectron->has_ap6_rom = true;
targetElectron->has_sideways_ram = true;
}
}
// Look for any 'BBC indicators', i.e. direct access to BBC-specific hardware.
// Also currently a dense search.
const auto hits = [&](const std::initializer_list<uint16_t> collection) {
int hits = 0;
for(const auto address: collection) {
const uint8_t sta_address[3] = {
0x8d, uint8_t(address & 0xff), uint8_t(address >> 8)
};
if(std::search(
file.data.begin(), file.data.end(),
std::begin(sta_address), std::end(sta_address)
) != file.data.end()) {
++hits;
}
// I think I'll want std::ranges::contains_subrange if/when building for C++23.
}
return hits;
};
bbc_hits += hits({
// The video control registers.
0xfe20, 0xfe21,
// The system VIA.
0xfe40, 0xfe41, 0xfe42, 0xfe43, 0xfe44, 0xfe45, 0xfe46, 0xfe47,
0xfe48, 0xfe49, 0xfe4a, 0xfe4b, 0xfe4c, 0xfe4d, 0xfe4e, 0xfe4f,
// The user VIA.
0xfe60, 0xfe61, 0xfe62, 0xfe63, 0xfe64, 0xfe65, 0xfe66, 0xfe67,
0xfe68, 0xfe69, 0xfe6a, 0xfe6b, 0xfe6c, 0xfe6d, 0xfe6e, 0xfe6f,
});
// BASIC for "MODE7".
static constexpr uint8_t mode7[] = {0xeb, 0x37};
bbc_hits += std::search(
file.data.begin(), file.data.end(),
std::begin(mode7), std::end(mode7)
) != file.data.end();
electron_hits += hits({
// ULA addresses that aren't also the BBC's CRTC.
0xfe03, 0xfe04, 0xfe05,
0xfe06, 0xfe07, 0xfe08,
0xfe09, 0xfe0a, 0xfe0b,
0xfe0c, 0xfe0d, 0xfe0e,
0xfe0f,
});
}
} else if(adfs_catalogue) {
// Archimedes options, implicitly: ADFS, non-Hugo.
@@ -159,8 +267,8 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me
// Take whatever else comes with a preference for things that don't
// have 'boot' or 'read' in them (the latter of which will tend to be
// read_me or read_this or similar).
constexpr char read[] = "read";
constexpr char boot[] = "boot";
static constexpr char read[] = "read";
static constexpr char boot[] = "boot";
const auto has = [&](const char *begin, const char *end) {
return std::search(
file.name.begin(), file.name.end(),
@@ -189,28 +297,38 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me
// Enable the Acorn ADFS if a mass-storage device is attached;
// unlike the Pres ADFS it retains SCSI logic.
if(!media.mass_storage_devices.empty()) {
target8bit->has_pres_adfs = false; // To override a floppy selection, if one was made.
target8bit->has_acorn_adfs = true;
targetElectron->has_pres_adfs = false; // To override a floppy selection, if one was made.
targetElectron->has_acorn_adfs = true;
// Assume some sort of later-era Acorn work is likely to happen;
// so ensure *TYPE, etc are present.
target8bit->has_ap6_rom = true;
target8bit->has_sideways_ram = true;
targetElectron->has_ap6_rom = true;
targetElectron->has_sideways_ram = true;
target8bit->media.mass_storage_devices = media.mass_storage_devices;
targetElectron->media.mass_storage_devices = media.mass_storage_devices;
// Check for a boot option.
const auto sector = target8bit->media.mass_storage_devices.front()->get_block(1);
const auto sector = targetElectron->media.mass_storage_devices.front()->get_block(1);
if(sector[0xfd]) {
target8bit->should_shift_restart = true;
targetElectron->should_shift_restart = true;
} else {
target8bit->loading_command = "*CAT\n";
targetElectron->loading_command = "*CAT\n";
}
}
TargetList targets;
if(!target8bit->media.empty()) {
targets.push_back(std::move(target8bit));
if(!targetElectron->media.empty() && !targetBBC->media.empty()) {
if(bbc_hits > electron_hits || (bbc_hits == electron_hits && format_prefers_bbc)) {
targets.push_back(std::move(targetBBC));
} else {
targets.push_back(std::move(targetElectron));
}
} else {
if(!targetElectron->media.empty()) {
targets.push_back(std::move(targetElectron));
} else if(!targetBBC->media.empty()) {
targets.push_back(std::move(targetBBC));
}
}
if(!targetArchimedes->media.empty()) {
targets.push_back(std::move(targetArchimedes));
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Acorn {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+60 -67
View File
@@ -10,70 +10,68 @@
#include <deque>
#include "../../../Numeric/CRC.hpp"
#include "../../../Storage/Tape/Parsers/Acorn.hpp"
#include "Numeric/CRC.hpp"
#include "Storage/Tape/Parsers/Acorn.hpp"
using namespace Analyser::Static::Acorn;
static std::unique_ptr<File::Chunk> GetNextChunk(const std::shared_ptr<Storage::Tape::Tape> &tape, Storage::Tape::Acorn::Parser &parser) {
static std::unique_ptr<File::Chunk> GetNextChunk(
Storage::Tape::TapeSerialiser &serialiser,
Storage::Tape::Acorn::Parser &parser
) {
auto new_chunk = std::make_unique<File::Chunk>();
int shift_register = 0;
// TODO: move this into the parser
const auto shift = [&] {
shift_register = (shift_register >> 1) | (parser.get_next_bit(tape) << 9);
const auto find = [&](int target) {
while(!serialiser.is_at_end() && (shift_register != target)) {
shift_register = (shift_register >> 1) | (parser.get_next_bit(serialiser) << 9);
}
};
// find next area of high tone
while(!tape->is_at_end() && (shift_register != 0x3ff)) {
shift();
}
// find next 0x2a (swallowing stop bit)
while(!tape->is_at_end() && (shift_register != 0x254)) {
shift();
}
// Find first sync byte that follows high tone.
find(0x3ff);
find(0x254); // i.e. 0x2a wrapped in a 1 start bit and a 0 stop bit.
parser.reset_crc();
parser.reset_error_flag();
// read out name
char name[11];
// Read name.
char name[11]{};
std::size_t name_ptr = 0;
while(!tape->is_at_end() && name_ptr < sizeof(name)) {
name[name_ptr] = char(parser.get_next_byte(tape));
while(!serialiser.is_at_end() && name_ptr < sizeof(name)) {
name[name_ptr] = char(parser.get_next_byte(serialiser));
if(!name[name_ptr]) break;
++name_ptr;
}
name[sizeof(name)-1] = '\0';
new_chunk->name = name;
// addresses
new_chunk->load_address = uint32_t(parser.get_next_word(tape));
new_chunk->execution_address = uint32_t(parser.get_next_word(tape));
new_chunk->block_number = uint16_t(parser.get_next_short(tape));
new_chunk->block_length = uint16_t(parser.get_next_short(tape));
new_chunk->block_flag = uint8_t(parser.get_next_byte(tape));
new_chunk->next_address = uint32_t(parser.get_next_word(tape));
// Read rest of header fields.
new_chunk->load_address = uint32_t(parser.get_next_word(serialiser));
new_chunk->execution_address = uint32_t(parser.get_next_word(serialiser));
new_chunk->block_number = uint16_t(parser.get_next_short(serialiser));
new_chunk->block_length = uint16_t(parser.get_next_short(serialiser));
new_chunk->block_flag = uint8_t(parser.get_next_byte(serialiser));
new_chunk->next_address = uint32_t(parser.get_next_word(serialiser));
uint16_t calculated_header_crc = parser.get_crc();
uint16_t stored_header_crc = uint16_t(parser.get_next_short(tape));
stored_header_crc = uint16_t((stored_header_crc >> 8) | (stored_header_crc << 8));
new_chunk->header_crc_matched = stored_header_crc == calculated_header_crc;
const auto matched_crc = [&]() {
const uint16_t calculated_crc = parser.get_crc();
uint16_t stored_crc = uint16_t(parser.get_next_short(serialiser));
stored_crc = uint16_t((stored_crc >> 8) | (stored_crc << 8));
return stored_crc == calculated_crc;
};
new_chunk->header_crc_matched = matched_crc();
if(!new_chunk->header_crc_matched) return nullptr;
parser.reset_crc();
new_chunk->data.reserve(new_chunk->block_length);
for(int c = 0; c < new_chunk->block_length; c++) {
new_chunk->data.push_back(uint8_t(parser.get_next_byte(tape)));
}
// Bit 6 of the block flag means 'empty block'; allow it to override declared block length.
if(new_chunk->block_length && !(new_chunk->block_flag&0x40)) {
uint16_t calculated_data_crc = parser.get_crc();
uint16_t stored_data_crc = uint16_t(parser.get_next_short(tape));
stored_data_crc = uint16_t((stored_data_crc >> 8) | (stored_data_crc << 8));
new_chunk->data_crc_matched = stored_data_crc == calculated_data_crc;
parser.reset_crc();
new_chunk->data.reserve(new_chunk->block_length);
for(int c = 0; c < new_chunk->block_length; c++) {
new_chunk->data.push_back(uint8_t(parser.get_next_byte(serialiser)));
}
new_chunk->data_crc_matched = matched_crc();
} else {
new_chunk->data_crc_matched = true;
}
@@ -82,67 +80,62 @@ static std::unique_ptr<File::Chunk> GetNextChunk(const std::shared_ptr<Storage::
}
static std::unique_ptr<File> GetNextFile(std::deque<File::Chunk> &chunks) {
// find next chunk with a block number of 0
while(chunks.size() && chunks.front().block_number) {
// Find next chunk with a block number of 0.
while(!chunks.empty() && chunks.front().block_number) {
chunks.pop_front();
}
if(chunks.empty()) return nullptr;
if(!chunks.size()) return nullptr;
// accumulate chunks for as long as block number is sequential and the end-of-file bit isn't set
// Accumulate sequential blocks until end-of-file bit is set.
auto file = std::make_unique<File>();
uint16_t block_number = 0;
while(chunks.size()) {
while(!chunks.empty()) {
if(chunks.front().block_number != block_number) return nullptr;
bool was_last = chunks.front().block_flag & 0x80;
const bool was_last = chunks.front().block_flag & 0x80;
file->chunks.push_back(chunks.front());
chunks.pop_front();
block_number++;
++block_number;
if(was_last) break;
}
// accumulate total data, copy flags appropriately
// Grab metadata flags.
file->name = file->chunks.front().name;
file->load_address = file->chunks.front().load_address;
file->execution_address = file->chunks.front().execution_address;
// I think the final chunk's flags are the ones that count; TODO: check.
if(file->chunks.back().block_flag & 0x01) {
// File is locked, which in more generalised terms means it is
// for execution only.
// File is locked i.e. for execution only.
file->flags |= File::Flags::ExecuteOnly;
}
// copy all data into a single big block
for(File::Chunk chunk : file->chunks) {
// Copy data into a single big block.
file->data.reserve(file->chunks.size() * 256);
for(auto &chunk : file->chunks) {
file->data.insert(file->data.end(), chunk.data.begin(), chunk.data.end());
}
return file;
}
std::vector<File> Analyser::Static::Acorn::GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape) {
std::vector<File> Analyser::Static::Acorn::GetFiles(Storage::Tape::TapeSerialiser &serialiser) {
Storage::Tape::Acorn::Parser parser;
// populate chunk list
// Read all chunks.
std::deque<File::Chunk> chunk_list;
while(!tape->is_at_end()) {
std::unique_ptr<File::Chunk> chunk = GetNextChunk(tape, parser);
while(!serialiser.is_at_end()) {
const std::unique_ptr<File::Chunk> chunk = GetNextChunk(serialiser, parser);
if(chunk) {
chunk_list.push_back(*chunk);
chunk_list.push_back(std::move(*chunk));
}
}
// decompose into file list
// Convert to files.
std::vector<File> file_list;
while(chunk_list.size()) {
std::unique_ptr<File> next_file = GetNextFile(chunk_list);
while(!chunk_list.empty()) {
const std::unique_ptr<File> next_file = GetNextFile(chunk_list);
if(next_file) {
file_list.push_back(*next_file);
file_list.push_back(std::move(*next_file));
}
}
+4 -4
View File
@@ -8,13 +8,13 @@
#pragma once
#include <memory>
#include "File.hpp"
#include "../../../Storage/Tape/Tape.hpp"
#include "Storage/Tape/Tape.hpp"
#include <vector>
namespace Analyser::Static::Acorn {
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
std::vector<File> GetFiles(Storage::Tape::TapeSerialiser &);
}
+43 -10
View File
@@ -8,8 +8,9 @@
#pragma once
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
#include <string>
namespace Analyser::Static::Acorn {
@@ -23,14 +24,42 @@ struct ElectronTarget: public ::Analyser::Static::Target, public Reflection::Str
bool should_shift_restart = false;
std::string loading_command;
ElectronTarget() : Analyser::Static::Target(Machine::Electron) {
if(needs_declare()) {
DeclareField(has_pres_adfs);
DeclareField(has_acorn_adfs);
DeclareField(has_dfs);
DeclareField(has_ap6_rom);
DeclareField(has_sideways_ram);
}
ElectronTarget() : Analyser::Static::Target(Machine::Electron) {}
private:
friend Reflection::StructImpl<ElectronTarget>;
void declare_fields() {
DeclareField(has_pres_adfs);
DeclareField(has_acorn_adfs);
DeclareField(has_dfs);
DeclareField(has_ap6_rom);
DeclareField(has_sideways_ram);
}
};
struct BBCMicroTarget: public ::Analyser::Static::Target, public Reflection::StructImpl<BBCMicroTarget> {
std::string loading_command;
bool should_shift_restart = false;
bool has_1770dfs = false;
bool has_adfs = false;
bool has_sideways_ram = true;
bool has_beebsid = false;
ReflectableEnum(TubeProcessor, None, WDC65C02, Z80);
TubeProcessor tube_processor = TubeProcessor::None;
BBCMicroTarget() : Analyser::Static::Target(Machine::BBCMicro) {}
private:
friend Reflection::StructImpl<BBCMicroTarget>;
void declare_fields() {
DeclareField(has_1770dfs);
DeclareField(has_adfs);
DeclareField(has_sideways_ram);
DeclareField(has_beebsid);
AnnounceEnum(TubeProcessor);
DeclareField(tube_processor);
}
};
@@ -38,6 +67,10 @@ struct ArchimedesTarget: public ::Analyser::Static::Target, public Reflection::S
std::string main_program;
ArchimedesTarget() : Analyser::Static::Target(Machine::Archimedes) {}
private:
friend Reflection::StructImpl<ArchimedesTarget>;
void declare_fields() {}
};
}
+7 -2
View File
@@ -9,9 +9,14 @@
#include "StaticAnalyser.hpp"
#include "Target.hpp"
Analyser::Static::TargetList Analyser::Static::Amiga::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::Amiga::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool is_confident
) {
// This analyser can comprehend disks and mass-storage devices only.
if(media.disks.empty()) return {};
if(media.disks.empty() && !is_confident) return {};
// As there is at least one usable media image, wave it through.
Analyser::Static::TargetList targets;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Amiga {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+11 -9
View File
@@ -8,8 +8,8 @@
#pragma once
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Struct.hpp"
namespace Analyser::Static::Amiga {
@@ -28,13 +28,15 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
ChipRAM chip_ram = ChipRAM::FiveHundredAndTwelveKilobytes;
FastRAM fast_ram = FastRAM::EightMegabytes;
Target() : Analyser::Static::Target(Machine::Amiga) {
if(needs_declare()) {
DeclareField(fast_ram);
DeclareField(chip_ram);
AnnounceEnum(FastRAM);
AnnounceEnum(ChipRAM);
}
Target() : Analyser::Static::Target(Machine::Amiga) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(fast_ram);
DeclareField(chip_ram);
AnnounceEnum(FastRAM);
AnnounceEnum(ChipRAM);
}
};
+110 -63
View File
@@ -8,17 +8,26 @@
#include "StaticAnalyser.hpp"
#include <algorithm>
#include <cstring>
#include "../../../Storage/Disk/Parsers/CPM.hpp"
#include "../../../Storage/Disk/Encodings/MFM/Parser.hpp"
#include "../../../Storage/Tape/Parsers/Spectrum.hpp"
#include "Storage/Disk/Parsers/CPM.hpp"
#include "Storage/Disk/Encodings/MFM/Parser.hpp"
#include "Storage/Tape/Parsers/Spectrum.hpp"
#include "Target.hpp"
#include <algorithm>
#include <cstring>
#include <unordered_set>
namespace {
std::string rtrimmed(const std::string &input) {
auto trimmed = input;
trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), [](const char ch) {
return !std::isspace(ch);
}).base(), trimmed.end());
return trimmed;
}
bool strcmp_insensitive(const char *a, const char *b) {
if(std::strlen(a) != std::strlen(b)) return false;
while(*a) {
@@ -63,8 +72,8 @@ std::string RunCommandFor(const Storage::Disk::CPM::File &file) {
void InspectCatalogue(
const Storage::Disk::CPM::Catalogue &catalogue,
const std::unique_ptr<Analyser::Static::AmstradCPC::Target> &target) {
const std::unique_ptr<Analyser::Static::AmstradCPC::Target> &target
) {
std::vector<const Storage::Disk::CPM::File *> candidate_files;
candidate_files.reserve(catalogue.files.size());
for(const auto &file : catalogue.files) {
@@ -104,61 +113,91 @@ void InspectCatalogue(
return;
}
// If only one file is [potentially] BASIC, run that one; otherwise if only one has a suffix
// that AMSDOS allows to be omitted, pick that one.
int basic_files = 0;
int implicit_suffixed_files = 0;
const auto run_name = [&]() -> std::optional<std::string> {
// Collect:
//
// 1. a set of all files that can be run without specifying an extension plus their appearance counts;
// 2. a set of all BASIC file names.
std::unordered_map<std::string, int> candidates;
std::unordered_set<std::string> basic_names;
for(std::size_t c = 0; c < candidate_files.size(); c++) {
// Files with nothing but spaces in their name can't be loaded by the user, so disregard them.
if(
(candidate_files[c]->type == " " && candidate_files[c]->name == " ") ||
!is_implied_extension(candidate_files[c]->type)
) {
continue;
}
std::size_t last_basic_file = 0;
std::size_t last_implicit_suffixed_file = 0;
for(std::size_t c = 0; c < candidate_files.size(); c++) {
// Files with nothing but spaces in their name can't be loaded by the user, so disregard them.
if(candidate_files[c]->type == " " && candidate_files[c]->name == " ")
continue;
// Check for whether this is [potentially] BASIC.
if(candidate_files[c]->data.size() >= 128 && !((candidate_files[c]->data[18] >> 1) & 7)) {
basic_files++;
last_basic_file = c;
}
// Check suffix for emptiness.
if(is_implied_extension(candidate_files[c]->type)) {
implicit_suffixed_files++;
last_implicit_suffixed_file = c;
}
}
if(basic_files == 1 || implicit_suffixed_files == 1) {
std::size_t selected_file = (basic_files == 1) ? last_basic_file : last_implicit_suffixed_file;
target->loading_command = RunCommandFor(*candidate_files[selected_file]);
return;
}
// One more guess: if only one remaining candidate file has a different name than the others,
// assume it is intended to stand out.
std::map<std::string, int> name_counts;
std::map<std::string, std::size_t> indices_by_name;
std::size_t index = 0;
for(const auto &file : candidate_files) {
name_counts[file->name]++;
indices_by_name[file->name] = index;
index++;
}
if(name_counts.size() == 2) {
for(const auto &pair : name_counts) {
if(pair.second == 1) {
target->loading_command = RunCommandFor(*candidate_files[indices_by_name[pair.first]]);
return;
++candidates[candidate_files[c]->name];
if(candidate_files[c]->data.size() >= 128 && !((candidate_files[c]->data[18] >> 1) & 7)) {
basic_names.insert(candidate_files[c]->name);
}
}
}
// Desperation.
target->loading_command = "cat\n";
// Only one candidate total.
if(candidates.size() == 1) {
return candidates.begin()->first;
}
// Only one BASIC candidate.
if(basic_names.size() == 1) {
return *basic_names.begin();
}
// Exactly two candidate names, but only one is a unique name.
if(candidates.size() == 2) {
const auto item1 = candidates.begin();
const auto item2 = std::next(item1);
if(item1->second == 1 && item2->second != 1) {
return item1->first;
}
if(item2->second == 1 && item1->second != 1) {
return item2->first;
}
}
// Remove from candidates anything that is just a suffixed version of
// another name, as long as the other name is three or more characters.
std::vector<std::string> to_remove;
for(const auto &lhs: candidates) {
const auto trimmed = rtrimmed(lhs.first);
if(trimmed.size() < 3) {
continue;
}
for(const auto &rhs: candidates) {
if(lhs.first == rhs.first) {
continue;
}
if(rhs.first.find(trimmed) == 0) {
to_remove.push_back(rhs.first);
}
}
}
for(const auto &candidate: to_remove) {
candidates.erase(candidate);
}
if(candidates.size() == 1) {
return candidates.begin()->first;
}
return {};
} ();
if(run_name.has_value()) {
target->loading_command = "run\"" + rtrimmed(*run_name) + "\n";
} else {
target->loading_command = "cat\n";
}
}
bool CheckBootSector(const std::shared_ptr<Storage::Disk::Disk> &disk, const std::unique_ptr<Analyser::Static::AmstradCPC::Target> &target) {
bool CheckBootSector(
const std::shared_ptr<Storage::Disk::Disk> &disk,
const std::unique_ptr<Analyser::Static::AmstradCPC::Target> &target
) {
Storage::Encodings::MFM::Parser parser(Storage::Encodings::MFM::Density::Double, disk);
const Storage::Encodings::MFM::Sector *boot_sector = parser.sector(0, 0, 0x41);
if(boot_sector != nullptr && !boot_sector->samples.empty() && boot_sector->samples[0].size() == 512) {
@@ -182,7 +221,7 @@ bool CheckBootSector(const std::shared_ptr<Storage::Disk::Disk> &disk, const std
return false;
}
bool IsAmstradTape(const std::shared_ptr<Storage::Tape::Tape> &tape) {
bool IsAmstradTape(Storage::Tape::TapeSerialiser &serialiser) {
// Limited sophistication here; look for a CPC-style file header, that is
// any Spectrum-esque block with a synchronisation character of 0x2c.
//
@@ -191,7 +230,7 @@ bool IsAmstradTape(const std::shared_ptr<Storage::Tape::Tape> &tape) {
Parser parser(Parser::MachineType::AmstradCPC);
while(true) {
const auto block = parser.find_block(tape);
const auto block = parser.find_block(serialiser);
if(!block) break;
if(block->type == 0x2c) {
@@ -204,7 +243,12 @@ bool IsAmstradTape(const std::shared_ptr<Storage::Tape::Tape> &tape) {
} // namespace
Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
TargetList destination;
auto target = std::make_unique<Target>();
target->confidence = 0.5;
@@ -214,7 +258,8 @@ Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Medi
if(!media.tapes.empty()) {
bool has_cpc_tape = false;
for(auto &tape: media.tapes) {
has_cpc_tape |= IsAmstradTape(tape);
const auto serialiser = tape->serialiser();
has_cpc_tape |= IsAmstradTape(*serialiser);
}
if(has_cpc_tape) {
@@ -233,7 +278,8 @@ Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Medi
for(auto &disk: media.disks) {
// Check for an ordinary catalogue, making sure this isn't actually a ZX Spectrum disk.
std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue = Storage::Disk::CPM::GetCatalogue(disk, data_format);
std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue =
Storage::Disk::CPM::GetCatalogue(disk, data_format, false);
if(data_catalogue && !data_catalogue->is_zx_spectrum_booter()) {
InspectCatalogue(*data_catalogue, target);
target->media.disks.push_back(disk);
@@ -247,7 +293,8 @@ Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Medi
}
// Failing that check for a system catalogue.
std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue = Storage::Disk::CPM::GetCatalogue(disk, system_format);
std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue =
Storage::Disk::CPM::GetCatalogue(disk, system_format, false);
if(system_catalogue && !system_catalogue->is_zx_spectrum_booter()) {
InspectCatalogue(*system_catalogue, target);
target->media.disks.push_back(disk);
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::AmstradCPC {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+12 -10
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include <string>
namespace Analyser::Static::AmstradCPC {
@@ -26,13 +26,15 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
// This is used internally for testing; it therefore isn't exposed reflectively.
bool catch_ssm_codes = false;
Target() : Analyser::Static::Target(Machine::AmstradCPC) {
if(needs_declare()) {
DeclareField(model);
DeclareField(crtc_type);
AnnounceEnum(Model);
AnnounceEnum(CRTCType);
}
Target() : Analyser::Static::Target(Machine::AmstradCPC) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(model);
DeclareField(crtc_type);
AnnounceEnum(Model);
AnnounceEnum(CRTCType);
}
};
+6 -1
View File
@@ -9,7 +9,12 @@
#include "StaticAnalyser.hpp"
#include "Target.hpp"
Analyser::Static::TargetList Analyser::Static::AppleII::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::AppleII::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
auto target = std::make_unique<Target>();
target->media = media;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::AppleII {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+16 -14
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
namespace Analyser::Static::AppleII {
@@ -36,21 +36,23 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
SCSIController scsi_controller = SCSIController::None;
bool has_mockingboard = true;
Target() : Analyser::Static::Target(Machine::AppleII) {
if(needs_declare()) {
DeclareField(model);
DeclareField(disk_controller);
DeclareField(scsi_controller);
DeclareField(has_mockingboard);
Target() : Analyser::Static::Target(Machine::AppleII) {}
AnnounceEnum(Model);
AnnounceEnum(DiskController);
AnnounceEnum(SCSIController);
}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(model);
DeclareField(disk_controller);
DeclareField(scsi_controller);
DeclareField(has_mockingboard);
AnnounceEnum(Model);
AnnounceEnum(DiskController);
AnnounceEnum(SCSIController);
}
};
constexpr bool is_iie(Target::Model model) {
constexpr bool is_iie(const Target::Model model) {
return model == Target::Model::IIe || model == Target::Model::EnhancedIIe;
}
+6 -1
View File
@@ -9,7 +9,12 @@
#include "StaticAnalyser.hpp"
#include "Target.hpp"
Analyser::Static::TargetList Analyser::Static::AppleIIgs::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::AppleIIgs::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
auto target = std::make_unique<Target>();
target->media = media;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::AppleIIgs {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+12 -10
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
namespace Analyser::Static::AppleIIgs {
@@ -29,13 +29,15 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
Model model = Model::ROM01;
MemoryModel memory_model = MemoryModel::EightMB;
Target() : Analyser::Static::Target(Machine::AppleIIgs) {
if(needs_declare()) {
DeclareField(model);
DeclareField(memory_model);
AnnounceEnum(Model);
AnnounceEnum(MemoryModel);
}
Target() : Analyser::Static::Target(Machine::AppleIIgs) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(model);
DeclareField(memory_model);
AnnounceEnum(Model);
AnnounceEnum(MemoryModel);
}
};
+48 -32
View File
@@ -10,7 +10,7 @@
#include "Target.hpp"
#include "../Disassembler/6502.hpp"
#include "Analyser/Static/Disassembler/6502.hpp"
using namespace Analyser::Static::Atari2600;
using Target = Analyser::Static::Atari2600::Target;
@@ -33,11 +33,13 @@ static void DeterminePagingFor2kCartridge(Target &target, const Storage::Cartrid
// Assume that any kind of store that looks likely to be intended for large amounts of memory implies
// large amounts of memory.
bool has_wide_area_store = false;
for(std::map<uint16_t, Analyser::Static::MOS6502::Instruction>::value_type &entry : high_location_disassembly.instructions_by_address) {
for(const auto &entry : high_location_disassembly.instructions_by_address) {
using Instruction = Analyser::Static::MOS6502::Instruction;
if(entry.second.operation == Analyser::Static::MOS6502::Instruction::STA) {
has_wide_area_store |= entry.second.addressing_mode == Analyser::Static::MOS6502::Instruction::Indirect;
has_wide_area_store |= entry.second.addressing_mode == Analyser::Static::MOS6502::Instruction::IndexedIndirectX;
has_wide_area_store |= entry.second.addressing_mode == Analyser::Static::MOS6502::Instruction::IndirectIndexedY;
has_wide_area_store |=
entry.second.addressing_mode == Instruction::Indirect ||
entry.second.addressing_mode == Instruction::IndexedIndirectX ||
entry.second.addressing_mode == Instruction::IndirectIndexedY;
if(has_wide_area_store) break;
}
@@ -50,13 +52,21 @@ static void DeterminePagingFor2kCartridge(Target &target, const Storage::Cartrid
if(has_wide_area_store) target.paging_model = Target::PagingModel::CommaVid;
}
static void DeterminePagingFor8kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &segment, const Analyser::Static::MOS6502::Disassembly &disassembly) {
static void DeterminePagingFor8kCartridge(
Target &target,
const Storage::Cartridge::Cartridge::Segment &segment,
const Analyser::Static::MOS6502::Disassembly &disassembly
) {
// Activision stack titles have their vectors at the top of the low 4k, not the top, and
// always list 0xf000 as both vectors; they do not repeat them, and, inexplicably, they all
// issue an SEI as their first instruction (maybe some sort of relic of the development environment?).
if(
segment.data[4095] == 0xf0 && segment.data[4093] == 0xf0 && segment.data[4094] == 0x00 && segment.data[4092] == 0x00 &&
(segment.data[8191] != 0xf0 || segment.data[8189] != 0xf0 || segment.data[8190] != 0x00 || segment.data[8188] != 0x00) &&
segment.data[4095] == 0xf0 && segment.data[4093] == 0xf0 &&
segment.data[4094] == 0x00 && segment.data[4092] == 0x00 &&
(
segment.data[8191] != 0xf0 || segment.data[8189] != 0xf0 ||
segment.data[8190] != 0x00 || segment.data[8188] != 0x00
) &&
segment.data[0] == 0x78
) {
target.paging_model = Target::PagingModel::ActivisionStack;
@@ -88,7 +98,11 @@ static void DeterminePagingFor8kCartridge(Target &target, const Storage::Cartrid
else if(tigervision_access_count > atari_access_count) target.paging_model = Target::PagingModel::Tigervision;
}
static void DeterminePagingFor16kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &, const Analyser::Static::MOS6502::Disassembly &disassembly) {
static void DeterminePagingFor16kCartridge(
Target &target,
const Storage::Cartridge::Cartridge::Segment &,
const Analyser::Static::MOS6502::Disassembly &disassembly
) {
// Make an assumption that this is the Atari paging model.
target.paging_model = Target::PagingModel::Atari16k;
@@ -108,7 +122,11 @@ static void DeterminePagingFor16kCartridge(Target &target, const Storage::Cartri
if(mnetwork_access_count > atari_access_count) target.paging_model = Target::PagingModel::MNetwork;
}
static void DeterminePagingFor64kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &, const Analyser::Static::MOS6502::Disassembly &disassembly) {
static void DeterminePagingFor64kCartridge(
Target &target,
const Storage::Cartridge::Cartridge::Segment &,
const Analyser::Static::MOS6502::Disassembly &disassembly
) {
// Make an assumption that this is a Tigervision if there is a write to 3F.
target.paging_model =
(disassembly.external_stores.find(0x3f) != disassembly.external_stores.end()) ?
@@ -121,8 +139,12 @@ static void DeterminePagingForCartridge(Target &target, const Storage::Cartridge
return;
}
const uint16_t entry_address = uint16_t(segment.data[segment.data.size() - 4] | (segment.data[segment.data.size() - 3] << 8));
const uint16_t break_address = uint16_t(segment.data[segment.data.size() - 2] | (segment.data[segment.data.size() - 1] << 8));
const auto word = [](const uint8_t low, const uint8_t high) {
return uint16_t(low | (high << 8));
};
const auto entry_address = word(segment.data[segment.data.size() - 4], segment.data[segment.data.size() - 3]);
const auto break_address = word(segment.data[segment.data.size() - 2], segment.data[segment.data.size() - 1]);
std::function<std::size_t(uint16_t address)> address_mapper = [](uint16_t address) {
if(!(address & 0x1000)) return size_t(-1);
@@ -130,27 +152,16 @@ static void DeterminePagingForCartridge(Target &target, const Storage::Cartridge
};
const std::vector<uint8_t> final_4k(segment.data.end() - 4096, segment.data.end());
Analyser::Static::MOS6502::Disassembly disassembly = Analyser::Static::MOS6502::Disassemble(final_4k, address_mapper, {entry_address, break_address});
const auto disassembly =
Analyser::Static::MOS6502::Disassemble(final_4k, address_mapper, {entry_address, break_address});
switch(segment.data.size()) {
case 8192:
DeterminePagingFor8kCartridge(target, segment, disassembly);
break;
case 10495:
target.paging_model = Target::PagingModel::Pitfall2;
break;
case 12288:
target.paging_model = Target::PagingModel::CBSRamPlus;
break;
case 16384:
DeterminePagingFor16kCartridge(target, segment, disassembly);
break;
case 32768:
target.paging_model = Target::PagingModel::Atari32k;
break;
case 65536:
DeterminePagingFor64kCartridge(target, segment, disassembly);
break;
case 8192: DeterminePagingFor8kCartridge(target, segment, disassembly); break;
case 10495: target.paging_model = Target::PagingModel::Pitfall2; break;
case 12288: target.paging_model = Target::PagingModel::CBSRamPlus; break;
case 16384: DeterminePagingFor16kCartridge(target, segment, disassembly); break;
case 32768: target.paging_model = Target::PagingModel::Atari32k; break;
case 65536: DeterminePagingFor64kCartridge(target, segment, disassembly); break;
default:
break;
}
@@ -177,7 +188,12 @@ static void DeterminePagingForCartridge(Target &target, const Storage::Cartridge
}
}
Analyser::Static::TargetList Analyser::Static::Atari2600::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::Atari2600::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
// TODO: sanity checking; is this image really for an Atari 2600?
auto target = std::make_unique<Target>();
target->confidence = 0.5;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Atari2600 {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+1 -1
View File
@@ -8,7 +8,7 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
namespace Analyser::Static::Atari2600 {
+6 -1
View File
@@ -9,7 +9,12 @@
#include "StaticAnalyser.hpp"
#include "Target.hpp"
Analyser::Static::TargetList Analyser::Static::AtariST::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::AtariST::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
// This analyser can comprehend disks and mass-storage devices only.
if(media.disks.empty()) return {};
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::AtariST {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+9 -7
View File
@@ -8,8 +8,8 @@
#pragma once
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Struct.hpp"
namespace Analyser::Static::AtariST {
@@ -20,11 +20,13 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
FourMegabytes);
MemorySize memory_size = MemorySize::OneMegabyte;
Target() : Analyser::Static::Target(Machine::AtariST) {
if(needs_declare()) {
DeclareField(memory_size);
AnnounceEnum(MemorySize);
}
Target() : Analyser::Static::Target(Machine::AtariST) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(memory_size);
AnnounceEnum(MemorySize);
}
};
+12 -3
View File
@@ -9,7 +9,7 @@
#include "StaticAnalyser.hpp"
static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
ColecoCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
ColecoCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> coleco_cartridges;
for(const auto &cartridge : cartridges) {
@@ -52,11 +52,20 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
return coleco_cartridges;
}
Analyser::Static::TargetList Analyser::Static::Coleco::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::Coleco::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
const bool is_confident
) {
TargetList targets;
auto target = std::make_unique<Target>(Machine::ColecoVision);
target->confidence = 1.0f - 1.0f / 32768.0f;
target->media.cartridges = ColecoCartridgesFrom(media.cartridges);
if(is_confident) {
target->media = media;
} else {
target->media.cartridges = ColecoCartridgesFrom(media.cartridges);
}
if(!target->media.empty())
targets.push_back(std::move(target));
return targets;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Coleco {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+170 -150
View File
@@ -7,166 +7,168 @@
//
#include "Disk.hpp"
#include "../../../Storage/Disk/Controller/DiskController.hpp"
#include "../../../Storage/Disk/Encodings/CommodoreGCR.hpp"
#include "../../../Storage/Data/Commodore.hpp"
#include "Storage/Disk/Controller/DiskController.hpp"
#include "Storage/Disk/Encodings/CommodoreGCR.hpp"
#include "Storage/Data/Commodore.hpp"
#include <limits>
#include <vector>
#include <array>
#include <limits>
#include <unordered_map>
#include <vector>
using namespace Analyser::Static::Commodore;
class CommodoreGCRParser: public Storage::Disk::Controller {
public:
CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
emplace_drive(4000000, 300, 2);
set_drive(1);
get_drive().set_motor_on(true);
}
public:
CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
emplace_drive(4000000, 300, 2);
set_drive(1);
get_drive().set_motor_on(true);
}
struct Sector {
uint8_t sector, track;
std::array<uint8_t, 256> data;
bool header_checksum_matched;
bool data_checksum_matched;
};
struct Sector {
uint8_t sector, track;
std::array<uint8_t, 256> data;
bool header_checksum_matched;
bool data_checksum_matched;
};
/*!
Attempts to read the sector located at @c track and @c sector.
/*!
Attempts to read the sector located at @c track and @c sector.
@returns a sector if one was found; @c nullptr otherwise.
*/
std::shared_ptr<Sector> sector(uint8_t track, uint8_t sector) {
int difference = int(track) - int(track_);
track_ = track;
@returns a sector if one was found; @c nullptr otherwise.
*/
const Sector *sector(const uint8_t track, const uint8_t sector) {
int difference = int(track) - int(track_);
track_ = track;
if(difference) {
int direction = difference < 0 ? -1 : 1;
difference *= direction;
if(difference) {
const int direction = difference < 0 ? -1 : 1;
difference *= direction;
for(int c = 0; c < difference; c++) {
get_drive().step(Storage::Disk::HeadPosition(direction));
}
unsigned int zone = 3;
if(track >= 18) zone = 2;
else if(track >= 25) zone = 1;
else if(track >= 31) zone = 0;
set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(zone));
for(int c = 0; c < difference; c++) {
get_drive().step(Storage::Disk::HeadPosition(direction));
}
return get_sector(sector);
unsigned int zone = 3;
if(track >= 18) zone = 2;
else if(track >= 25) zone = 1;
else if(track >= 31) zone = 0;
set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(zone));
}
void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
get_drive().set_disk(disk);
return get_sector(sector);
}
void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
get_drive().set_disk(disk);
}
private:
unsigned int shift_register_;
int index_count_;
int bit_count_;
uint8_t track_;
std::unordered_map<uint16_t, std::unique_ptr<Sector>> sector_cache_;
void process_input_bit(const int value) override {
shift_register_ = ((shift_register_ << 1) | unsigned(value)) & 0x3ff;
bit_count_++;
}
unsigned int proceed_to_next_block(const int max_index_count) {
// find GCR lead-in
proceed_to_shift_value(0x3ff);
if(shift_register_ != 0x3ff) return 0xff;
// find end of lead-in
while(shift_register_ == 0x3ff && index_count_ < max_index_count) {
run_for(Cycles(1));
}
private:
unsigned int shift_register_;
int index_count_;
int bit_count_;
uint8_t track_;
std::shared_ptr<Sector> sector_cache_[65536];
void process_input_bit(int value) {
shift_register_ = ((shift_register_ << 1) | unsigned(value)) & 0x3ff;
bit_count_++;
// continue for a further nine bits
bit_count_ = 0;
while(bit_count_ < 9 && index_count_ < max_index_count) {
run_for(Cycles(1));
}
unsigned int proceed_to_next_block(int max_index_count) {
// find GCR lead-in
proceed_to_shift_value(0x3ff);
if(shift_register_ != 0x3ff) return 0xff;
return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
}
// find end of lead-in
while(shift_register_ == 0x3ff && index_count_ < max_index_count) {
run_for(Cycles(1));
}
unsigned int get_next_byte() {
bit_count_ = 0;
while(bit_count_ < 10) run_for(Cycles(1));
return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
}
// continue for a further nine bits
bit_count_ = 0;
while(bit_count_ < 9 && index_count_ < max_index_count) {
run_for(Cycles(1));
}
return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
void proceed_to_shift_value(const unsigned int shift_value) {
const int max_index_count = index_count_ + 2;
while(shift_register_ != shift_value && index_count_ < max_index_count) {
run_for(Cycles(1));
}
}
unsigned int get_next_byte() {
bit_count_ = 0;
while(bit_count_ < 10) run_for(Cycles(1));
return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
void process_index_hole() override {
index_count_++;
}
const Sector *get_sector(const uint8_t sector) {
const uint16_t sector_address = uint16_t((track_ << 8) | sector);
auto existing = sector_cache_.find(sector_address);
if(existing != sector_cache_.end()) return existing->second.get();
const auto first_sector = get_next_sector();
if(!first_sector) return first_sector;
if(first_sector->sector == sector) return first_sector;
while(true) {
const auto next_sector = get_next_sector();
if(next_sector->sector == first_sector->sector) return nullptr;
if(next_sector->sector == sector) return next_sector;
}
}
void proceed_to_shift_value(unsigned int shift_value) {
const int max_index_count = index_count_ + 2;
while(shift_register_ != shift_value && index_count_ < max_index_count) {
run_for(Cycles(1));
}
}
void process_index_hole() {
index_count_++;
}
std::shared_ptr<Sector> get_sector(uint8_t sector) {
const uint16_t sector_address = uint16_t((track_ << 8) | sector);
if(sector_cache_[sector_address]) return sector_cache_[sector_address];
const std::shared_ptr<Sector> first_sector = get_next_sector();
if(!first_sector) return first_sector;
if(first_sector->sector == sector) return first_sector;
const Sector *get_next_sector() {
auto sector = std::make_unique<Sector>();
const int max_index_count = index_count_ + 2;
while(index_count_ < max_index_count) {
// look for a sector header
while(1) {
const std::shared_ptr<Sector> next_sector = get_next_sector();
if(next_sector->sector == first_sector->sector) return nullptr;
if(next_sector->sector == sector) return next_sector;
if(proceed_to_next_block(max_index_count) == 0x08) break;
if(index_count_ >= max_index_count) return nullptr;
}
// get sector details, skip if this looks malformed
uint8_t checksum = uint8_t(get_next_byte());
sector->sector = uint8_t(get_next_byte());
sector->track = uint8_t(get_next_byte());
uint8_t disk_id[2];
disk_id[0] = uint8_t(get_next_byte());
disk_id[1] = uint8_t(get_next_byte());
if(checksum != (sector->sector ^ sector->track ^ disk_id[0] ^ disk_id[1])) continue;
// look for the following data
while(1) {
if(proceed_to_next_block(max_index_count) == 0x07) break;
if(index_count_ >= max_index_count) return nullptr;
}
checksum = 0;
for(std::size_t c = 0; c < 256; c++) {
sector->data[c] = uint8_t(get_next_byte());
checksum ^= sector->data[c];
}
if(checksum == get_next_byte()) {
uint16_t sector_address = uint16_t((sector->track << 8) | sector->sector);
auto pair = sector_cache_.emplace(sector_address, std::move(sector));
return pair.first->second.get();
}
}
std::shared_ptr<Sector> get_next_sector() {
auto sector = std::make_shared<Sector>();
const int max_index_count = index_count_ + 2;
while(index_count_ < max_index_count) {
// look for a sector header
while(1) {
if(proceed_to_next_block(max_index_count) == 0x08) break;
if(index_count_ >= max_index_count) return nullptr;
}
// get sector details, skip if this looks malformed
uint8_t checksum = uint8_t(get_next_byte());
sector->sector = uint8_t(get_next_byte());
sector->track = uint8_t(get_next_byte());
uint8_t disk_id[2];
disk_id[0] = uint8_t(get_next_byte());
disk_id[1] = uint8_t(get_next_byte());
if(checksum != (sector->sector ^ sector->track ^ disk_id[0] ^ disk_id[1])) continue;
// look for the following data
while(1) {
if(proceed_to_next_block(max_index_count) == 0x07) break;
if(index_count_ >= max_index_count) return nullptr;
}
checksum = 0;
for(std::size_t c = 0; c < 256; c++) {
sector->data[c] = uint8_t(get_next_byte());
checksum ^= sector->data[c];
}
if(checksum == get_next_byte()) {
uint16_t sector_address = uint16_t((sector->track << 8) | sector->sector);
sector_cache_[sector_address] = sector;
return sector;
}
}
return nullptr;
}
return nullptr;
}
};
std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<Storage::Disk::Disk> &disk) {
@@ -174,20 +176,26 @@ std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<St
CommodoreGCRParser parser;
parser.set_disk(disk);
// find any sector whatsoever to establish the current track
std::shared_ptr<CommodoreGCRParser::Sector> sector;
// assemble directory
// Assemble directory.
std::vector<uint8_t> directory;
uint8_t next_track = 18;
uint8_t next_sector = 1;
while(1) {
sector = parser.sector(next_track, next_sector);
directory.reserve(20 * 1024); // Probably more than plenty.
std::set<std::pair<uint8_t, uint8_t>> visited;
while(true) {
// Don't be fooled by disks that are encoded with a looping directory.
const auto key = std::make_pair(next_track, next_sector);
if(visited.find(key) != visited.end()) break;
visited.insert(key);
// Append sector to directory and follow next link.
const auto sector = parser.sector(next_track, next_sector);
if(!sector) break;
directory.insert(directory.end(), sector->data.begin(), sector->data.end());
next_track = sector->data[0];
next_sector = sector->data[1];
// Check for end-of-directory.
if(!next_track) break;
}
@@ -216,24 +224,36 @@ std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<St
}
new_file.name = Storage::Data::Commodore::petscii_from_bytes(&new_file.raw_name[0], 16, false);
std::size_t number_of_sectors = size_t(directory[header_pointer + 0x1e]) + (size_t(directory[header_pointer + 0x1f]) << 8);
new_file.data.reserve((number_of_sectors - 1) * 254 + 252);
const std::size_t number_of_sectors =
size_t(directory[header_pointer + 0x1e]) +
(size_t(directory[header_pointer + 0x1f]) << 8);
if(number_of_sectors) {
new_file.data.reserve((number_of_sectors - 1) * 254 + 252);
bool is_first_sector = true;
while(next_track) {
sector = parser.sector(next_track, next_sector);
if(!sector) break;
bool is_first_sector = true;
while(next_track) {
const auto sector = parser.sector(next_track, next_sector);
if(!sector) break;
next_track = sector->data[0];
next_sector = sector->data[1];
next_track = sector->data[0];
next_sector = sector->data[1];
if(is_first_sector) new_file.starting_address = uint16_t(sector->data[2]) | uint16_t(sector->data[3] << 8);
if(next_track)
new_file.data.insert(new_file.data.end(), sector->data.begin() + (is_first_sector ? 4 : 2), sector->data.end());
else
new_file.data.insert(new_file.data.end(), sector->data.begin() + 2, sector->data.begin() + next_sector);
if(is_first_sector) new_file.starting_address = uint16_t(sector->data[2]) | uint16_t(sector->data[3] << 8);
if(next_track)
new_file.data.insert(
new_file.data.end(),
sector->data.begin() + (is_first_sector ? 4 : 2),
sector->data.end()
);
else
new_file.data.insert(
new_file.data.end(),
sector->data.begin() + 2,
sector->data.begin() + next_sector
);
is_first_sector = false;
is_first_sector = false;
}
}
if(!next_track) files.push_back(new_file);
+2 -2
View File
@@ -8,13 +8,13 @@
#pragma once
#include "../../../Storage/Disk/Disk.hpp"
#include "Storage/Disk/Disk.hpp"
#include "File.hpp"
#include <vector>
namespace Analyser::Static::Commodore {
std::vector<File> GetFiles(const std::shared_ptr<Storage::Disk::Disk> &disk);
std::vector<File> GetFiles(const std::shared_ptr<Storage::Disk::Disk> &);
}
-47
View File
@@ -1,47 +0,0 @@
//
// File.cpp
// Clock Signal
//
// Created by Thomas Harte on 10/09/2016.
// Copyright 2016 Thomas Harte. All rights reserved.
//
#include "File.hpp"
bool Analyser::Static::Commodore::File::is_basic() {
// BASIC files are always relocatable (?)
if(type != File::RelocatableProgram) return false;
uint16_t line_address = starting_address;
int line_number = -1;
// decide whether this is a BASIC file based on the proposition that:
// (1) they're always relocatable; and
// (2) they have a per-line structure of:
// [4 bytes: address of start of next line]
// [4 bytes: this line number]
// ... null-terminated code ...
// (with a next line address of 0000 indicating end of program)
while(1) {
if(size_t(line_address - starting_address) >= data.size() + 2) break;
uint16_t next_line_address = data[line_address - starting_address];
next_line_address |= data[line_address - starting_address + 1] << 8;
if(!next_line_address) {
return true;
}
if(next_line_address < line_address + 5) break;
if(size_t(line_address - starting_address) >= data.size() + 5) break;
uint16_t next_line_number = data[line_address - starting_address + 2];
next_line_number |= data[line_address - starting_address + 3] << 8;
if(next_line_number <= line_number) break;
line_number = uint16_t(next_line_number);
line_address = next_line_address;
}
return false;
}
-2
View File
@@ -29,8 +29,6 @@ struct File {
Relative
} type;
std::vector<uint8_t> data;
bool is_basic();
};
}
+317 -99
View File
@@ -12,26 +12,33 @@
#include "File.hpp"
#include "Tape.hpp"
#include "Target.hpp"
#include "../../../Storage/Cartridge/Encodings/CommodoreROM.hpp"
#include "../../../Outputs/Log.hpp"
#include "Storage/Cartridge/Encodings/CommodoreROM.hpp"
#include "Outputs/Log.hpp"
#include "Analyser/Static/Disassembler/6502.hpp"
#include "Analyser/Static/Disassembler/AddressMapper.hpp"
#include <algorithm>
#include <cstring>
#include <optional>
#include <sstream>
#include <unordered_set>
using namespace Analyser::Static::Commodore;
static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
Vic20CartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
namespace {
std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
Vic20CartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> vic20_cartridges;
for(const auto &cartridge : cartridges) {
const auto &segments = cartridge->get_segments();
// only one mapped item is allowed
// Only one mapped item is allowed ...
if(segments.size() != 1) continue;
// which must be 16 kb in size
// ... which must be 16 kb in size.
Storage::Cartridge::Cartridge::Segment segment = segments.front();
if(segment.start_address != 0xa000) continue;
if(!Storage::Cartridge::Encodings::CommodoreROM::isROM(segment.data)) continue;
@@ -39,126 +46,312 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
vic20_cartridges.push_back(cartridge);
}
// TODO: other machines?
return vic20_cartridges;
}
Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType) {
TargetList destination;
struct BASICAnalysis {
enum class Version {
NotBASIC,
BASIC2,
BASIC4,
BASIC3_5,
} minimum_version = Version::NotBASIC;
std::vector<uint16_t> machine_code_addresses;
};
auto target = std::make_unique<Target>();
target->machine = Machine::Vic20; // TODO: machine estimation
target->confidence = 0.5; // TODO: a proper estimation
std::optional<BASICAnalysis> analyse(const File &file) {
BASICAnalysis analysis;
switch(file.type) {
// For 'program' types, proceed with analysis below.
case File::RelocatableProgram:
case File::NonRelocatableProgram:
break;
// For sequential and relative data stop right now.
case File::DataSequence:
case File::Relative:
return std::nullopt;
// For user data, try decoding from the starting point.
case File::User:
analysis.machine_code_addresses.push_back(file.starting_address);
return analysis;
}
// Don't form an opinion if file is empty.
if(file.data.empty()) {
return std::nullopt;
}
uint16_t line_address = file.starting_address;
// int previous_line_number = -1;
const auto byte = [&](uint16_t address) {
return file.data[address - file.starting_address];
};
const auto word = [&](uint16_t address) {
return uint16_t(byte(address) | byte(address + 1) << 8);
};
// BASIC programs have a per-line structure of:
// [2 bytes: address of start of next line]
// [2 bytes: this line number]
// ... null-terminated code ...
// (with a next line address of 0000 indicating end of program)
//
// If a SYS is encountered that jumps into the BASIC program then treat that as
// a machine code entry point.
std::unordered_set<uint16_t> visited_lines;
while(true) {
// Analysis has failed if there isn't at least one complete BASIC line from here.
// Fall back on guessing the start address as a machine code entrypoint.
if(size_t(line_address - file.starting_address) + 5 >= file.data.size() || line_address < file.starting_address) {
analysis.machine_code_addresses.push_back(file.starting_address);
break;
}
const auto next_line_address = word(line_address);
// const auto line_number = word(line_address + 2);
uint16_t code = line_address + 4;
const auto next = [&]() -> uint8_t {
if(code >= file.starting_address + file.data.size()) {
return 0;
}
return byte(code++);
};
// TODO: sanity check on apparent line contents.
// TODO: observe token set (and possibly parameters?) to guess BASIC version.
while(true) {
const auto token = next();
if(!token || token == 0x8f) break;
switch(token) {
case 0x9e: { // SYS; parse following ASCII argument.
uint16_t address = 0;
while(true) {
const auto c = next();
if(c < '0' || c > '9') {
break;
}
address = (address * 10) + (c - '0');
};
analysis.machine_code_addresses.push_back(address);
} break;
}
}
// Exit if a formal end of the program has been declared or if, as some copy protections do,
// the linked list of line contents has been made circular.
visited_lines.insert(line_address);
if(!next_line_address || visited_lines.find(next_line_address) != visited_lines.end()) {
break;
}
// previous_line_number = line_number;
line_address = next_line_address;
}
return analysis;
}
template <typename TargetT>
void set_loading_command(TargetT &target) {
if(target.media.disks.empty()) {
target.loading_command = "LOAD\"\",1,1\nRUN\n";
} else {
target.loading_command = "LOAD\"*\",8,1\nRUN\n";
}
}
bool obviously_uses_ted(const File &file) {
const auto analysis = analyse(file);
if(!analysis) return false;
// Disassemble.
const auto disassembly = Analyser::Static::MOS6502::Disassemble(
file.data,
Analyser::Static::Disassembler::OffsetMapper(file.starting_address),
analysis->machine_code_addresses
);
// Check for interrupt status and paging touches.
for(const auto address: {0xff3e, 0xff3f, 0xff09}) {
for(const auto &collection: {
disassembly.external_loads,
disassembly.external_stores,
disassembly.external_modifies
}) {
if(collection.find(uint16_t(address)) != collection.end()) {
return true;
}
}
}
return false;
}
struct FileAnalysis {
int device = 0;
std::vector<File> files;
bool is_disk = false;
Analyser::Static::Media media;
};
// strip out inappropriate cartridges
target->media.cartridges = Vic20CartridgesFrom(media.cartridges);
template <TargetPlatform::Type platform>
FileAnalysis analyse_files(const Analyser::Static::Media &media) {
FileAnalysis analysis;
// check disks
// Find all valid Commodore files on disks.
for(auto &disk : media.disks) {
std::vector<File> disk_files = GetFiles(disk);
if(!disk_files.empty()) {
is_disk = true;
files.insert(files.end(), disk_files.begin(), disk_files.end());
target->media.disks.push_back(disk);
if(!device) device = 8;
analysis.is_disk = true;
analysis.files.insert(
analysis.files.end(),
std::make_move_iterator(disk_files.begin()),
std::make_move_iterator(disk_files.end())
);
analysis.media.disks.push_back(disk);
if(!analysis.device) analysis.device = 8;
}
}
// check tapes
// Find all valid Commodore files on tapes.
for(auto &tape : media.tapes) {
std::vector<File> tape_files = GetFiles(tape);
tape->reset();
auto serialiser = tape->serialiser();
std::vector<File> tape_files = GetFiles(*serialiser, platform);
if(!tape_files.empty()) {
files.insert(files.end(), tape_files.begin(), tape_files.end());
target->media.tapes.push_back(tape);
if(!device) device = 1;
analysis.files.insert(
analysis.files.end(),
std::make_move_iterator(tape_files.begin()),
std::make_move_iterator(tape_files.end())
);
analysis.media.tapes.push_back(tape);
if(!analysis.device) analysis.device = 1;
}
}
if(!files.empty()) {
auto memory_model = Target::MemoryModel::Unexpanded;
std::ostringstream string_stream;
string_stream << "LOAD\"" << (is_disk ? "*" : "") << "\"," << device << ",";
if(files.front().is_basic()) {
string_stream << "0";
} else {
string_stream << "1";
return analysis;
}
std::string loading_command(const FileAnalysis &file_analysis) {
std::ostringstream string_stream;
string_stream << "LOAD\"" << (file_analysis.is_disk ? "*" : "") << "\"," << file_analysis.device;
const auto analysis = analyse(file_analysis.files[0]);
if(analysis && !analysis->machine_code_addresses.empty()) {
string_stream << ",1";
}
string_stream << "\nRUN\n";
return string_stream.str();
}
std::pair<TargetPlatform::IntType, std::optional<Vic20Target::MemoryModel>>
analyse_starting_address(uint16_t starting_address) {
switch(starting_address) {
case 0x1c01:
// TODO: assume C128.
default:
Log::Logger<Log::Source::CommodoreStaticAnalyser>::error().append(
"Unrecognised loading address for Commodore program: %04x", starting_address);
[[fallthrough]];
case 0x1001:
return std::make_pair(TargetPlatform::Vic20 | TargetPlatform::Plus4, Vic20Target::MemoryModel::Unexpanded);
case 0x1201: return std::make_pair(TargetPlatform::Vic20, Vic20Target::MemoryModel::ThirtyTwoKB);
case 0x0401: return std::make_pair(TargetPlatform::Vic20, Vic20Target::MemoryModel::EightKB);
case 0x0801: return std::make_pair(TargetPlatform::C64, std::nullopt);
}
}
template <TargetPlatform::IntType platform>
std::unique_ptr<Analyser::Static::Target> get_target(
const Analyser::Static::Media &media,
const std::string &file_name,
bool is_confident
);
template<>
std::unique_ptr<Analyser::Static::Target> get_target<TargetPlatform::Plus4>(
const Analyser::Static::Media &media,
const std::string &,
bool is_confident
) {
auto target = std::make_unique<Plus4Target>();
if(is_confident) {
target->media = media;
set_loading_command(*target);
} else {
const auto files = analyse_files<TargetPlatform::Plus4>(media);
if(!files.files.empty()) {
target->loading_command = loading_command(files);
}
string_stream << "\nRUN\n";
target->loading_command = string_stream.str();
// make a first guess based on loading address
switch(files.front().starting_address) {
default:
Log::Logger<Log::Source::CommodoreStaticAnalyser>().error().append("Unrecognised loading address for Commodore program: %04x", files.front().starting_address);
[[fallthrough]];
case 0x1001:
memory_model = Target::MemoryModel::Unexpanded;
break;
case 0x1201:
memory_model = Target::MemoryModel::ThirtyTwoKB;
break;
case 0x0401:
memory_model = Target::MemoryModel::EightKB;
break;
}
target->set_memory_model(memory_model);
// General approach: increase memory size conservatively such that the largest file found will fit.
// for(File &file : files) {
// std::size_t file_size = file.data.size();
// bool is_basic = file.is_basic();
/*if(is_basic)
{
// BASIC files may be relocated, so the only limit is size.
//
// An unexpanded machine has 3583 bytes free for BASIC;
// a 3kb expanded machine has 6655 bytes free.
if(file_size > 6655)
target->vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
else if(target->vic20.memory_model == Vic20MemoryModel::Unexpanded && file_size > 3583)
target->vic20.memory_model = Vic20MemoryModel::EightKB;
}
else
{*/
// if(!file.type == File::NonRelocatableProgram)
// {
// Non-BASIC files may be relocatable but, if so, by what logic?
// Given that this is unknown, take starting address as literal
// and check against memory windows.
//
// (ignoring colour memory...)
// An unexpanded Vic has memory between 0x0000 and 0x0400; and between 0x1000 and 0x2000.
// A 3kb expanded Vic fills in the gap and has memory between 0x0000 and 0x2000.
// A 32kb expanded Vic has memory in the entire low 32kb.
// uint16_t starting_address = file.starting_address;
// If anything above the 8kb mark is touched, mark as a 32kb machine; otherwise if the
// region 0x0400 to 0x1000 is touched and this is an unexpanded machine, mark as 3kb.
// if(starting_address + file_size > 0x2000)
// target->memory_model = Target::MemoryModel::ThirtyTwoKB;
// else if(target->memory_model == Target::MemoryModel::Unexpanded && !(starting_address >= 0x1000 || starting_address+file_size < 0x0400))
// target->memory_model = Target::MemoryModel::ThirtyTwoKB;
// }
// }
target->media.disks = media.disks;
target->media.tapes = media.tapes;
}
// Attach a 1541 if there are any disks here.
target->has_c1541 = !target->media.disks.empty();
return target;
}
template<>
std::unique_ptr<Analyser::Static::Target> get_target<TargetPlatform::Vic20>(
const Analyser::Static::Media &media,
const std::string &file_name,
bool is_confident
) {
auto target = std::make_unique<Vic20Target>();
const auto files = analyse_files<TargetPlatform::Vic20>(media);
if(!files.files.empty()) {
target->loading_command = loading_command(files);
const auto model = analyse_starting_address(files.files[0].starting_address);
if(model.second.has_value()) {
target->set_memory_model(*model.second);
}
}
if(is_confident) {
target->media = media;
set_loading_command(*target);
} else {
// Strip out inappropriate cartridges but retain all tapes and disks.
target->media.cartridges = Vic20CartridgesFrom(media.cartridges);
target->media.disks = media.disks;
target->media.tapes = media.tapes;
}
for(const auto &file : files.files) {
// The Vic-20 never has RAM after 0x8000.
if(file.ending_address >= 0x8000) {
return nullptr;
}
if(obviously_uses_ted(file)) {
return nullptr;
}
}
// Inspect filename for configuration hints.
if(!target->media.empty()) {
// Inspect filename for configuration hints.
using Region = Analyser::Static::Commodore::Vic20Target::Region;
std::string lowercase_name = file_name;
std::transform(lowercase_name.begin(), lowercase_name.end(), lowercase_name.begin(), ::tolower);
// Hint 1: 'ntsc' anywhere in the name implies America.
if(lowercase_name.find("ntsc") != std::string::npos) {
target->region = Analyser::Static::Commodore::Target::Region::American;
target->region = Region::American;
}
// Potential additional hints: check for TheC64 tags.
// Potential additional hints: check for TheC64 tags; these are Vic-20 exclusive.
auto final_underscore = lowercase_name.find_last_of('_');
if(final_underscore != std::string::npos) {
auto iterator = lowercase_name.begin() + ssize_t(final_underscore) + 1;
@@ -180,10 +373,10 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
target->enabled_ram.bank3 |= !strcmp(next_tag, "b3");
target->enabled_ram.bank5 |= !strcmp(next_tag, "b5");
if(!strcmp(next_tag, "tn")) { // i.e. NTSC.
target->region = Analyser::Static::Commodore::Target::Region::American;
target->region = Region::American;
}
if(!strcmp(next_tag, "tp")) { // i.e. PAL.
target->region = Analyser::Static::Commodore::Target::Region::European;
target->region = Region::European;
}
// Unhandled:
@@ -194,11 +387,36 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
// RO: this disk image should be treated as read-only.
}
}
}
// Attach a 1540 if there are any disks here.
target->has_c1540 = !target->media.disks.empty();
// Attach a 1540 if there are any disks here.
target->has_c1540 = !target->media.disks.empty();
return target;
}
destination.push_back(std::move(target));
}
Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(
const Media &media,
const std::string &file_name,
TargetPlatform::IntType platforms,
bool is_confident
) {
TargetList destination;
if(platforms & TargetPlatform::Vic20) {
auto vic20 = get_target<TargetPlatform::Vic20>(media, file_name, is_confident);
if(vic20) {
destination.push_back(std::move(vic20));
}
}
if(platforms & TargetPlatform::Plus4) {
auto plus4 = get_target<TargetPlatform::Plus4>(media, file_name, is_confident);
if(plus4) {
destination.push_back(std::move(plus4));
}
}
return destination;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Commodore {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+18 -19
View File
@@ -7,26 +7,27 @@
//
#include "Tape.hpp"
#include "Storage/Tape/Parsers/Commodore.hpp"
#include "../../../Storage/Tape/Parsers/Commodore.hpp"
#include <algorithm>
using namespace Analyser::Static::Commodore;
std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape) {
Storage::Tape::Commodore::Parser parser;
std::vector<File> Analyser::Static::Commodore::GetFiles(Storage::Tape::TapeSerialiser &serialiser, TargetPlatform::Type type) {
Storage::Tape::Commodore::Parser parser(type);
std::vector<File> file_list;
std::unique_ptr<Storage::Tape::Commodore::Header> header = parser.get_next_header(tape);
std::unique_ptr<Storage::Tape::Commodore::Header> header = parser.get_next_header(serialiser);
while(!tape->is_at_end()) {
while(!serialiser.is_at_end()) {
if(!header) {
header = parser.get_next_header(tape);
header = parser.get_next_header(serialiser);
continue;
}
switch(header->type) {
case Storage::Tape::Commodore::Header::DataSequenceHeader: {
File new_file;
File &new_file = file_list.emplace_back();
new_file.name = header->name;
new_file.raw_name = header->raw_name;
new_file.starting_address = header->starting_address;
@@ -34,38 +35,36 @@ std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<St
new_file.type = File::DataSequence;
new_file.data.swap(header->data);
while(!tape->is_at_end()) {
header = parser.get_next_header(tape);
while(!serialiser.is_at_end()) {
header = parser.get_next_header(serialiser);
if(!header) continue;
if(header->type != Storage::Tape::Commodore::Header::DataBlock) break;
std::copy(header->data.begin(), header->data.end(), std::back_inserter(new_file.data));
std::ranges::copy(header->data, std::back_inserter(new_file.data));
}
file_list.push_back(new_file);
}
break;
case Storage::Tape::Commodore::Header::RelocatableProgram:
case Storage::Tape::Commodore::Header::NonRelocatableProgram: {
std::unique_ptr<Storage::Tape::Commodore::Data> data = parser.get_next_data(tape);
std::unique_ptr<Storage::Tape::Commodore::Data> data = parser.get_next_data(serialiser);
if(data) {
File new_file;
File &new_file = file_list.emplace_back();
new_file.name = header->name;
new_file.raw_name = header->raw_name;
new_file.starting_address = header->starting_address;
new_file.ending_address = header->ending_address;
new_file.data.swap(data->data);
new_file.type = (header->type == Storage::Tape::Commodore::Header::RelocatableProgram) ? File::RelocatableProgram : File::NonRelocatableProgram;
file_list.push_back(new_file);
new_file.type =
header->type == Storage::Tape::Commodore::Header::RelocatableProgram
? File::RelocatableProgram : File::NonRelocatableProgram;
}
header = parser.get_next_header(tape);
header = parser.get_next_header(serialiser);
}
break;
default:
header = parser.get_next_header(tape);
header = parser.get_next_header(serialiser);
break;
}
}
+3 -2
View File
@@ -8,11 +8,12 @@
#pragma once
#include "../../../Storage/Tape/Tape.hpp"
#include "Storage/Tape/Tape.hpp"
#include "Storage/TargetPlatforms.hpp"
#include "File.hpp"
namespace Analyser::Static::Commodore {
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
std::vector<File> GetFiles(Storage::Tape::TapeSerialiser &, TargetPlatform::Type);
}
+31 -15
View File
@@ -8,14 +8,28 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
#include <string>
namespace Analyser::Static::Commodore {
struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Target> {
struct Plus4Target: public Analyser::Static::Target, public Reflection::StructImpl<Plus4Target> {
// TODO: region, etc.
std::string loading_command;
bool has_c1541 = false;
Plus4Target() : Analyser::Static::Target(Machine::Plus4) {}
private:
friend Reflection::StructImpl<Plus4Target>;
void declare_fields() {
DeclareField(has_c1541);
}
};
struct Vic20Target: public Analyser::Static::Target, public Reflection::StructImpl<Vic20Target> {
enum class MemoryModel {
Unexpanded,
EightKB,
@@ -54,17 +68,19 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
bool has_c1540 = false;
std::string loading_command;
Target() : Analyser::Static::Target(Machine::Vic20) {
if(needs_declare()) {
DeclareField(enabled_ram.bank0);
DeclareField(enabled_ram.bank1);
DeclareField(enabled_ram.bank2);
DeclareField(enabled_ram.bank3);
DeclareField(enabled_ram.bank5);
DeclareField(region);
DeclareField(has_c1540);
AnnounceEnum(Region);
}
Vic20Target() : Analyser::Static::Target(Machine::Vic20) {}
private:
friend Reflection::StructImpl<Vic20Target>;
void declare_fields() {
DeclareField(enabled_ram.bank0);
DeclareField(enabled_ram.bank1);
DeclareField(enabled_ram.bank2);
DeclareField(enabled_ram.bank3);
DeclareField(enabled_ram.bank5);
DeclareField(region);
DeclareField(has_c1540);
AnnounceEnum(Region);
}
};
+32 -14
View File
@@ -17,7 +17,12 @@ using PartialDisassembly = Analyser::Static::Disassembly::PartialDisassembly<Dis
struct MOS6502Disassembler {
static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<uint8_t> &memory, const std::function<std::size_t(uint16_t)> &address_mapper, uint16_t entry_point) {
static void AddToDisassembly(
PartialDisassembly &disassembly,
const std::vector<uint8_t> &memory,
const std::function<std::size_t(uint16_t)> &address_mapper,
uint16_t entry_point
) {
disassembly.disassembly.internal_calls.insert(entry_point);
uint16_t address = entry_point;
while(true) {
@@ -75,23 +80,25 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
}
// Decode operation.
#define RM_INSTRUCTION(base, op) \
case base+0x09: case base+0x05: case base+0x15: case base+0x01: case base+0x11: case base+0x0d: case base+0x1d: case base+0x19: \
instruction.operation = op; \
#define RM_INSTRUCTION(base, op) \
case base+0x09: case base+0x05: case base+0x15: case base+0x01: \
case base+0x11: case base+0x0d: case base+0x1d: case base+0x19: \
instruction.operation = op; \
break;
#define URM_INSTRUCTION(base, op) \
#define URM_INSTRUCTION(base, op) \
case base+0x07: case base+0x17: case base+0x03: case base+0x13: case base+0x0f: case base+0x1f: case base+0x1b: \
instruction.operation = op; \
instruction.operation = op; \
break;
#define M_INSTRUCTION(base, op) \
#define M_INSTRUCTION(base, op) \
case base+0x0a: case base+0x06: case base+0x16: case base+0x0e: case base+0x1e: \
instruction.operation = op; \
instruction.operation = op; \
break;
#define IM_INSTRUCTION(base, op) \
#define IM_INSTRUCTION(base, op) \
case base: instruction.operation = op; break;
switch(operation) {
default:
instruction.operation = Instruction::KIL;
@@ -259,7 +266,10 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
disassembly.disassembly.instructions_by_address[instruction.address] = instruction;
// TODO: something wider-ranging than this
if(instruction.addressing_mode == Instruction::Absolute || instruction.addressing_mode == Instruction::ZeroPage) {
if(
instruction.addressing_mode == Instruction::Absolute ||
instruction.addressing_mode == Instruction::ZeroPage
) {
const size_t mapped_address = address_mapper(instruction.operand);
const bool is_external = mapped_address >= memory.size();
@@ -272,20 +282,23 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
case Instruction::ADC: case Instruction::SBC:
case Instruction::LAS:
case Instruction::CMP: case Instruction::CPX: case Instruction::CPY:
(is_external ? disassembly.disassembly.external_loads : disassembly.disassembly.internal_loads).insert(instruction.operand);
(is_external ? disassembly.disassembly.external_loads : disassembly.disassembly.internal_loads)
.insert(instruction.operand);
break;
case Instruction::STY: case Instruction::STX: case Instruction::STA:
case Instruction::AXS: case Instruction::AHX: case Instruction::SHX: case Instruction::SHY:
case Instruction::TAS:
(is_external ? disassembly.disassembly.external_stores : disassembly.disassembly.internal_stores).insert(instruction.operand);
(is_external ? disassembly.disassembly.external_stores : disassembly.disassembly.internal_stores)
.insert(instruction.operand);
break;
case Instruction::SLO: case Instruction::RLA: case Instruction::SRE: case Instruction::RRA:
case Instruction::DCP: case Instruction::ISC:
case Instruction::INC: case Instruction::DEC:
case Instruction::ASL: case Instruction::ROL: case Instruction::LSR: case Instruction::ROR:
(is_external ? disassembly.disassembly.external_modifies : disassembly.disassembly.internal_modifies).insert(instruction.operand);
(is_external ? disassembly.disassembly.external_modifies : disassembly.disassembly.internal_modifies)
.insert(instruction.operand);
break;
}
}
@@ -330,5 +343,10 @@ Disassembly Analyser::Static::MOS6502::Disassemble(
const std::vector<uint8_t> &memory,
const std::function<std::size_t(uint16_t)> &address_mapper,
std::vector<uint16_t> entry_points) {
return Analyser::Static::Disassembly::Disassemble<Disassembly, uint16_t, MOS6502Disassembler>(memory, address_mapper, entry_points, false);
return Analyser::Static::Disassembly::Disassemble<Disassembly, uint16_t, MOS6502Disassembler>(
memory,
address_mapper,
entry_points,
false
);
}
@@ -16,7 +16,7 @@ namespace Analyser::Static::Disassembler {
Provides an address mapper that relocates a chunk of memory so that it starts at
address @c start_address.
*/
template <typename T> std::function<std::size_t(T)> OffsetMapper(T start_address) {
template <typename T> std::function<std::size_t(T)> OffsetMapper(const T start_address) {
return [start_address](T argument) {
return size_t(argument - start_address);
};
+103 -63
View File
@@ -16,51 +16,55 @@ namespace {
using PartialDisassembly = Analyser::Static::Disassembly::PartialDisassembly<Disassembly, uint16_t>;
class Accessor {
public:
Accessor(const std::vector<uint8_t> &memory, const std::function<std::size_t(uint16_t)> &address_mapper, uint16_t address) :
memory_(memory), address_mapper_(address_mapper), address_(address) {}
public:
Accessor(
const std::vector<uint8_t> &memory,
const std::function<std::size_t(uint16_t)> &address_mapper,
uint16_t address
) :
memory_(memory), address_mapper_(address_mapper), address_(address) {}
uint8_t byte() {
std::size_t mapped_address = address_mapper_(address_);
address_++;
if(mapped_address >= memory_.size()) {
overrun_ = true;
return 0xff;
}
return memory_[mapped_address];
uint8_t byte() {
std::size_t mapped_address = address_mapper_(address_);
++address_;
if(mapped_address >= memory_.size()) {
overrun_ = true;
return 0xff;
}
return memory_[mapped_address];
}
uint16_t word() {
uint8_t low = byte();
uint8_t high = byte();
return uint16_t(low | (high << 8));
}
uint16_t word() {
uint8_t low = byte();
uint8_t high = byte();
return uint16_t(low | (high << 8));
}
bool overrun() {
return overrun_;
}
bool overrun() const {
return overrun_;
}
bool at_end() {
std::size_t mapped_address = address_mapper_(address_);
return mapped_address >= memory_.size();
}
bool at_end() const {
std::size_t mapped_address = address_mapper_(address_);
return mapped_address >= memory_.size();
}
uint16_t address() {
return address_;
}
uint16_t address() const {
return address_;
}
private:
const std::vector<uint8_t> &memory_;
const std::function<std::size_t(uint16_t)> &address_mapper_;
uint16_t address_;
bool overrun_ = false;
private:
const std::vector<uint8_t> &memory_;
const std::function<std::size_t(uint16_t)> &address_mapper_;
uint16_t address_;
bool overrun_ = false;
};
constexpr uint8_t x(uint8_t v) { return v >> 6; }
constexpr uint8_t y(uint8_t v) { return (v >> 3) & 7; }
constexpr uint8_t q(uint8_t v) { return (v >> 3) & 1; }
constexpr uint8_t p(uint8_t v) { return (v >> 4) & 3; }
constexpr uint8_t z(uint8_t v) { return v & 7; }
constexpr uint8_t x(const uint8_t v) { return v >> 6; }
constexpr uint8_t y(const uint8_t v) { return (v >> 3) & 7; }
constexpr uint8_t q(const uint8_t v) { return (v >> 3) & 1; }
constexpr uint8_t p(const uint8_t v) { return (v >> 4) & 3; }
constexpr uint8_t z(const uint8_t v) { return v & 7; }
Instruction::Condition condition_table[] = {
Instruction::Condition::NZ, Instruction::Condition::Z,
@@ -83,8 +87,12 @@ Instruction::Location register_pair_table2[] = {
Instruction::Location::AF
};
Instruction::Location RegisterTableEntry(int offset, Accessor &accessor, Instruction &instruction, bool needs_indirect_offset) {
Instruction::Location register_table[] = {
Instruction::Location RegisterTableEntry(
const int offset, Accessor &accessor,
Instruction &instruction,
const bool needs_indirect_offset
) {
static constexpr Instruction::Location register_table[] = {
Instruction::Location::B, Instruction::Location::C,
Instruction::Location::D, Instruction::Location::E,
Instruction::Location::H, Instruction::Location::L,
@@ -92,7 +100,7 @@ Instruction::Location RegisterTableEntry(int offset, Accessor &accessor, Instruc
Instruction::Location::A
};
Instruction::Location location = register_table[offset];
const Instruction::Location location = register_table[offset];
if(location == Instruction::Location::HL_Indirect && needs_indirect_offset) {
instruction.offset = accessor.byte() - 128;
}
@@ -100,7 +108,7 @@ Instruction::Location RegisterTableEntry(int offset, Accessor &accessor, Instruc
return location;
}
Instruction::Operation alu_table[] = {
constexpr Instruction::Operation alu_table[] = {
Instruction::Operation::ADD,
Instruction::Operation::ADC,
Instruction::Operation::SUB,
@@ -111,7 +119,7 @@ Instruction::Operation alu_table[] = {
Instruction::Operation::CP
};
Instruction::Operation rotation_table[] = {
constexpr Instruction::Operation rotation_table[] = {
Instruction::Operation::RLC,
Instruction::Operation::RRC,
Instruction::Operation::RL,
@@ -122,19 +130,32 @@ Instruction::Operation rotation_table[] = {
Instruction::Operation::SRL
};
Instruction::Operation block_table[][4] = {
{Instruction::Operation::LDI, Instruction::Operation::CPI, Instruction::Operation::INI, Instruction::Operation::OUTI},
{Instruction::Operation::LDD, Instruction::Operation::CPD, Instruction::Operation::IND, Instruction::Operation::OUTD},
{Instruction::Operation::LDIR, Instruction::Operation::CPIR, Instruction::Operation::INIR, Instruction::Operation::OTIR},
{Instruction::Operation::LDDR, Instruction::Operation::CPDR, Instruction::Operation::INDR, Instruction::Operation::OTDR},
constexpr Instruction::Operation block_table[][4] = {
{
Instruction::Operation::LDI, Instruction::Operation::CPI,
Instruction::Operation::INI, Instruction::Operation::OUTI
},
{
Instruction::Operation::LDD, Instruction::Operation::CPD,
Instruction::Operation::IND, Instruction::Operation::OUTD
},
{
Instruction::Operation::LDIR, Instruction::Operation::CPIR,
Instruction::Operation::INIR, Instruction::Operation::OTIR
},
{
Instruction::Operation::LDDR, Instruction::Operation::CPDR,
Instruction::Operation::INDR, Instruction::Operation::OTDR
},
};
void DisassembleCBPage(Accessor &accessor, Instruction &instruction, bool needs_indirect_offset) {
void DisassembleCBPage(Accessor &accessor, Instruction &instruction, const bool needs_indirect_offset) {
const uint8_t operation = accessor.byte();
if(!x(operation)) {
instruction.operation = rotation_table[y(operation)];
instruction.source = instruction.destination = RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
instruction.source = instruction.destination =
RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
} else {
instruction.destination = RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
instruction.source = Instruction::Location::Operand;
@@ -148,7 +169,7 @@ void DisassembleCBPage(Accessor &accessor, Instruction &instruction, bool needs_
}
}
void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_indirect_offset) {
void DisassembleEDPage(Accessor &accessor, Instruction &instruction, const bool needs_indirect_offset) {
const uint8_t operation = accessor.byte();
switch(x(operation)) {
@@ -170,7 +191,8 @@ void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_
if(y(operation) == 6) {
instruction.destination = Instruction::Location::None;
} else {
instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
instruction.destination =
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
}
break;
case 1:
@@ -179,7 +201,8 @@ void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_
if(y(operation) == 6) {
instruction.source = Instruction::Location::None;
} else {
instruction.source = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
instruction.source =
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
}
break;
case 2:
@@ -190,11 +213,13 @@ void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_
case 3:
instruction.operation = Instruction::Operation::LD;
if(q(operation)) {
instruction.destination = RegisterTableEntry(p(operation), accessor, instruction, needs_indirect_offset);
instruction.destination =
RegisterTableEntry(p(operation), accessor, instruction, needs_indirect_offset);
instruction.source = Instruction::Location::Operand_Indirect;
} else {
instruction.destination = Instruction::Location::Operand_Indirect;
instruction.source = RegisterTableEntry(p(operation), accessor, instruction, needs_indirect_offset);
instruction.source =
RegisterTableEntry(p(operation), accessor, instruction, needs_indirect_offset);
}
instruction.operand = accessor.word();
break;
@@ -202,7 +227,8 @@ void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_
instruction.operation = Instruction::Operation::NEG;
break;
case 5:
instruction.operation = (y(operation) == 1) ? Instruction::Operation::RETI : Instruction::Operation::RETN;
instruction.operation =
y(operation) == 1 ? Instruction::Operation::RETI : Instruction::Operation::RETN;
break;
case 6:
instruction.operation = Instruction::Operation::IM;
@@ -253,7 +279,7 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
} hl_substitution = None;
while(true) {
uint8_t operation = accessor.byte();
const uint8_t operation = accessor.byte();
switch(x(operation)) {
case 0:
@@ -343,15 +369,18 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
break;
case 4:
instruction.operation = Instruction::Operation::INC;
instruction.source = instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
instruction.source = instruction.destination =
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
break;
case 5:
instruction.operation = Instruction::Operation::DEC;
instruction.source = instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
instruction.source = instruction.destination =
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
break;
case 6:
instruction.operation = Instruction::Operation::LD;
instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
instruction.destination =
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
instruction.source = Instruction::Location::Operand;
instruction.operand = accessor.byte();
break;
@@ -374,8 +403,10 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
instruction.operation = Instruction::Operation::HALT;
} else {
instruction.operation = Instruction::Operation::LD;
instruction.source = RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
instruction.source =
RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
instruction.destination =
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
}
break;
case 2:
@@ -517,10 +548,14 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
instruction.destination == Instruction::Location::HL_Indirect) {
if(instruction.source == Instruction::Location::HL_Indirect) {
instruction.source = (hl_substitution == IX) ? Instruction::Location::IX_Indirect_Offset : Instruction::Location::IY_Indirect_Offset;
instruction.source =
hl_substitution == IX ?
Instruction::Location::IX_Indirect_Offset : Instruction::Location::IY_Indirect_Offset;
}
if(instruction.destination == Instruction::Location::HL_Indirect) {
instruction.destination = (hl_substitution == IX) ? Instruction::Location::IX_Indirect_Offset : Instruction::Location::IY_Indirect_Offset;
instruction.destination =
hl_substitution == IX ?
Instruction::Location::IX_Indirect_Offset : Instruction::Location::IY_Indirect_Offset;
}
return;
}
@@ -542,7 +577,12 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
}
struct Z80Disassembler {
static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<uint8_t> &memory, const std::function<std::size_t(uint16_t)> &address_mapper, uint16_t entry_point) {
static void AddToDisassembly(
PartialDisassembly &disassembly,
const std::vector<uint8_t> &memory,
const std::function<std::size_t(uint16_t)> &address_mapper,
const uint16_t entry_point
) {
disassembly.disassembly.internal_calls.insert(entry_point);
Accessor accessor(memory, address_mapper, entry_point);
+18 -11
View File
@@ -8,14 +8,14 @@
#include "StaticAnalyser.hpp"
#include "../AppleII/Target.hpp"
#include "../AppleIIgs/Target.hpp"
#include "../Oric/Target.hpp"
#include "../Disassembler/6502.hpp"
#include "../Disassembler/AddressMapper.hpp"
#include "Analyser/Static/AppleII/Target.hpp"
#include "Analyser/Static//AppleIIgs/Target.hpp"
#include "Analyser/Static//Oric/Target.hpp"
#include "Analyser/Static//Disassembler/6502.hpp"
#include "Analyser/Static//Disassembler/AddressMapper.hpp"
#include "../../../Storage/Disk/Track/TrackSerialiser.hpp"
#include "../../../Storage/Disk/Encodings/AppleGCR/SegmentParser.hpp"
#include "Storage/Disk/Track/TrackSerialiser.hpp"
#include "Storage/Disk/Encodings/AppleGCR/SegmentParser.hpp"
namespace {
@@ -47,7 +47,12 @@ Analyser::Static::Target *OricTarget(const Storage::Encodings::AppleGCR::Sector
}
Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
// This analyser can comprehend disks only.
if(media.disks.empty()) return {};
@@ -55,14 +60,15 @@ Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &m
TargetList targets;
// If the disk image is too large for a 5.25" disk, map this to the IIgs.
if(disk->get_maximum_head_position() > Storage::Disk::HeadPosition(40)) {
if(disk->maximum_head_position() > Storage::Disk::HeadPosition(40)) {
targets.push_back(std::unique_ptr<Analyser::Static::Target>(AppleIIgsTarget()));
targets.back()->media = media;
return targets;
}
// Grab track 0, sector 0: the boot sector.
const auto track_zero = disk->get_track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
const auto track_zero =
disk->track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
const auto sector_map = Storage::Encodings::AppleGCR::sectors_from_segment(
Storage::Disk::track_serialisation(*track_zero, Storage::Time(1, 50000)));
@@ -89,7 +95,8 @@ Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &m
// If the boot sector looks like it's intended for the Oric, create an Oric.
// Otherwise go with the Apple II.
const auto disassembly = Analyser::Static::MOS6502::Disassemble(sector_zero->data, Analyser::Static::Disassembler::OffsetMapper(0xb800), {0xb800});
const auto disassembly = Analyser::Static::MOS6502::Disassemble(
sector_zero->data, Analyser::Static::Disassembler::OffsetMapper(0xb800), {0xb800});
bool did_read_shift_register = false;
bool is_oric = false;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::DiskII {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
@@ -9,7 +9,7 @@
#include "StaticAnalyser.hpp"
#include "Target.hpp"
#include "../../../Storage/Disk/Parsers/FAT.hpp"
#include "Storage/Disk/Parsers/FAT.hpp"
#include <algorithm>
@@ -26,7 +26,12 @@ bool insensitive_equal(const std::string &lhs, const std::string &rhs) {
}
Analyser::Static::TargetList Analyser::Static::Enterprise::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::Enterprise::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
// This analyser can comprehend disks only.
if(media.disks.empty()) return {};
@@ -72,7 +77,8 @@ Analyser::Static::TargetList Analyser::Static::Enterprise::GetTargets(const Medi
if(!has_exdos_ini) {
if(did_pick_file) {
target->loading_command = std::string("run \"") + selected_file->name + "." + selected_file->extension + "\"\n";
target->loading_command =
std::string("run \"") + selected_file->name + "." + selected_file->extension + "\"\n";
} else {
target->loading_command = ":dir\n";
}
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Enterprise {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+18 -16
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
#include <string>
@@ -30,20 +30,22 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
Speed speed = Speed::FourMHz;
std::string loading_command;
Target() : Analyser::Static::Target(Machine::Enterprise) {
if(needs_declare()) {
AnnounceEnum(Model);
AnnounceEnum(EXOSVersion);
AnnounceEnum(BASICVersion);
AnnounceEnum(DOS);
AnnounceEnum(Speed);
Target() : Analyser::Static::Target(Machine::Enterprise) {}
DeclareField(model);
DeclareField(exos_version);
DeclareField(basic_version);
DeclareField(dos);
DeclareField(speed);
}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
AnnounceEnum(Model);
AnnounceEnum(EXOSVersion);
AnnounceEnum(BASICVersion);
AnnounceEnum(DOS);
AnnounceEnum(Speed);
DeclareField(model);
DeclareField(exos_version);
DeclareField(basic_version);
DeclareField(dos);
DeclareField(speed);
}
};
+18 -12
View File
@@ -8,15 +8,20 @@
#include "StaticAnalyser.hpp"
#include "../Enterprise/StaticAnalyser.hpp"
#include "../PCCompatible/StaticAnalyser.hpp"
#include "Analyser/Static/Enterprise/StaticAnalyser.hpp"
#include "Analyser/Static/PCCompatible/StaticAnalyser.hpp"
#include "../../../Storage/Disk/Track/TrackSerialiser.hpp"
#include "../../../Storage/Disk/Encodings/MFM/Constants.hpp"
#include "../../../Storage/Disk/Encodings/MFM/SegmentParser.hpp"
#include "Storage/Disk/Track/TrackSerialiser.hpp"
#include "Storage/Disk/Encodings/MFM/Constants.hpp"
#include "Storage/Disk/Encodings/MFM/SegmentParser.hpp"
Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType platforms) {
Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(
const Media &media,
const std::string &file_name,
TargetPlatform::IntType platforms,
bool
) {
// This analyser can comprehend disks only.
if(media.disks.empty()) return {};
@@ -34,12 +39,13 @@ Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(const Media &me
// If the disk image is very small or large, map it to the PC. That's the only option old enough
// to have used 5.25" media.
if(disk->get_maximum_head_position() <= Storage::Disk::HeadPosition(40)) {
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms);
if(disk->maximum_head_position() <= Storage::Disk::HeadPosition(40)) {
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms, true);
}
// Attempt to grab MFM track 0, sector 1: the boot sector.
const auto track_zero = disk->get_track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
const auto track_zero =
disk->track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
const auto sector_map = Storage::Encodings::MFM::sectors_from_segment(
Storage::Disk::track_serialisation(
*track_zero,
@@ -48,7 +54,7 @@ Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(const Media &me
// If no sectors were found, assume this disk was either single density or high density, which both imply the PC.
if(sector_map.empty() || sector_map.size() > 10) {
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms);
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms, true);
}
const Storage::Encodings::MFM::Sector *boot_sector = nullptr;
@@ -77,7 +83,7 @@ Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(const Media &me
if(
std::search(sample.begin(), sample.end(), string.begin(), string.end()) != sample.end()
) {
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms);
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms, true);
}
}
@@ -96,5 +102,5 @@ Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(const Media &me
// could redirect to an MSX2 with MSX-DOS2? Though it'd be nicer if I had a machine that was pure CP/M.
// Being unable to prove that this is a PC disk, throw it to the Enterprise.
return Analyser::Static::Enterprise::GetTargets(media, file_name, platforms);
return Analyser::Static::Enterprise::GetTargets(media, file_name, platforms, false);
}
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::FAT12 {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+2 -2
View File
@@ -8,7 +8,7 @@
#pragma once
#include "../../../Storage/Cartridge/Cartridge.hpp"
#include "Storage/Cartridge/Cartridge.hpp"
namespace Analyser::Static::MSX {
@@ -26,7 +26,7 @@ struct Cartridge: public ::Storage::Cartridge::Cartridge {
};
const Type type;
Cartridge(const std::vector<Segment> &segments, Type type) :
Cartridge(const std::vector<Segment> &segments, const Type type) :
Storage::Cartridge::Cartridge(segments), type(type) {}
};
+17 -9
View File
@@ -12,8 +12,8 @@
#include "Tape.hpp"
#include "Target.hpp"
#include "../Disassembler/Z80.hpp"
#include "../Disassembler/AddressMapper.hpp"
#include "Analyser/Static/Disassembler/Z80.hpp"
#include "Analyser/Static//Disassembler/AddressMapper.hpp"
#include <algorithm>
@@ -27,7 +27,8 @@ static std::unique_ptr<Analyser::Static::Target> CartridgeTarget(
std::vector<Storage::Cartridge::Cartridge::Segment> output_segments;
if(segment.data.size() & 0x1fff) {
std::vector<uint8_t> truncated_data;
std::vector<uint8_t>::difference_type truncated_size = std::vector<uint8_t>::difference_type(segment.data.size()) & ~0x1fff;
const auto truncated_size =
std::vector<uint8_t>::difference_type(segment.data.size()) & ~0x1fff;
truncated_data.insert(truncated_data.begin(), segment.data.begin(), segment.data.begin() + truncated_size);
output_segments.emplace_back(start_address, truncated_data);
} else {
@@ -82,7 +83,7 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
if(segments.size() != 1) continue;
// Which must be no more than 63 bytes larger than a multiple of 8 kb in size.
Storage::Cartridge::Cartridge::Segment segment = segments.front();
const Storage::Cartridge::Cartridge::Segment &segment = segments.front();
const size_t data_size = segment.data.size();
if(data_size < 0x2000 || (data_size & 0x1fff) > 64) continue;
@@ -101,7 +102,7 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
// Reject cartridge if the ROM header wasn't found.
if(!found_start) continue;
uint16_t init_address = uint16_t(segment.data[2] | (segment.data[3] << 8));
const uint16_t init_address = uint16_t(segment.data[2] | (segment.data[3] << 8));
// TODO: check for a rational init address?
// If this ROM is less than 48kb in size then it's an ordinary ROM. Just emplace it and move on.
@@ -137,10 +138,12 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
}
// Weight confidences by number of observed hits; if any is above 60% confidence, just use it.
const auto ascii_8kb_total = address_counts[0x6000] + address_counts[0x6800] + address_counts[0x7000] + address_counts[0x7800];
const auto ascii_8kb_total =
address_counts[0x6000] + address_counts[0x6800] + address_counts[0x7000] + address_counts[0x7800];
const auto ascii_16kb_total = address_counts[0x6000] + address_counts[0x7000] + address_counts[0x77ff];
const auto konami_total = address_counts[0x6000] + address_counts[0x8000] + address_counts[0xa000];
const auto konami_with_scc_total = address_counts[0x5000] + address_counts[0x7000] + address_counts[0x9000] + address_counts[0xb000];
const auto konami_with_scc_total =
address_counts[0x5000] + address_counts[0x7000] + address_counts[0x9000] + address_counts[0xb000];
const auto total_hits = ascii_8kb_total + ascii_16kb_total + konami_total + konami_with_scc_total;
@@ -182,7 +185,12 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
return targets;
}
Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
TargetList destination;
// Append targets for any cartridges that look correct.
@@ -194,7 +202,7 @@ Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(const Media &medi
// Check tapes for loadable files.
for(auto &tape : media.tapes) {
std::vector<File> files_on_tape = GetFiles(tape);
const std::vector<File> files_on_tape = GetFiles(tape);
if(!files_on_tape.empty()) {
switch(files_on_tape.front().type) {
case File::Type::ASCII: target->loading_command = "RUN\"CAS:\r"; break;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::MSX {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+3 -3
View File
@@ -8,7 +8,7 @@
#include "Tape.hpp"
#include "../../../Storage/Tape/Parsers/MSX.hpp"
#include "Storage/Tape/Parsers/MSX.hpp"
using namespace Analyser::Static::MSX;
@@ -29,12 +29,12 @@ std::vector<File> Analyser::Static::MSX::GetFiles(const std::shared_ptr<Storage:
Storage::Tape::BinaryTapePlayer tape_player(1000000);
tape_player.set_motor_control(true);
tape_player.set_tape(tape);
tape_player.set_tape(tape, TargetPlatform::MSX);
using Parser = Storage::Tape::MSX::Parser;
// Get all recognisable files from the tape.
while(!tape->is_at_end()) {
while(!tape_player.is_at_end()) {
// Try to locate and measure a header.
std::unique_ptr<Parser::FileSpeed> file_speed = Parser::find_header(tape_player);
if(!file_speed) continue;
+2 -2
View File
@@ -8,7 +8,7 @@
#pragma once
#include "../../../Storage/Tape/Tape.hpp"
#include "Storage/Tape/Tape.hpp"
#include <string>
#include <vector>
@@ -32,6 +32,6 @@ struct File {
File();
};
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &);
}
+14 -12
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
#include <string>
namespace Analyser::Static::MSX {
@@ -33,15 +33,17 @@ struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl<
);
Region region = Region::USA;
Target(): Analyser::Static::Target(Machine::MSX) {
if(needs_declare()) {
DeclareField(has_disk_drive);
DeclareField(has_msx_music);
DeclareField(region);
AnnounceEnum(Region);
DeclareField(model);
AnnounceEnum(Model);
}
Target(): Analyser::Static::Target(Machine::MSX) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(has_disk_drive);
DeclareField(has_msx_music);
DeclareField(region);
AnnounceEnum(Region);
DeclareField(model);
AnnounceEnum(Model);
}
};
+8 -3
View File
@@ -9,9 +9,14 @@
#include "StaticAnalyser.hpp"
#include "Target.hpp"
Analyser::Static::TargetList Analyser::Static::Macintosh::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::Macintosh::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool is_confident
) {
// This analyser can comprehend disks and mass-storage devices only.
if(media.disks.empty() && media.mass_storage_devices.empty()) return {};
if(media.disks.empty() && media.mass_storage_devices.empty() && !is_confident) return {};
// As there is at least one usable media image, wave it through.
Analyser::Static::TargetList targets;
@@ -24,7 +29,7 @@ Analyser::Static::TargetList Analyser::Static::Macintosh::GetTargets(const Media
if(media.mass_storage_devices.empty()) {
bool has_800kb_disks = false;
for(const auto &disk: media.disks) {
has_800kb_disks |= disk->get_head_count() > 1;
has_800kb_disks |= disk->head_count() > 1;
}
if(!has_800kb_disks) {
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Macintosh {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+10 -9
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
namespace Analyser::Static::Macintosh {
@@ -18,12 +18,13 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
ReflectableEnum(Model, Mac128k, Mac512k, Mac512ke, MacPlus);
Model model = Model::MacPlus;
Target() : Analyser::Static::Target(Machine::Macintosh) {
// Boilerplate for declaring fields and potential values.
if(needs_declare()) {
DeclareField(model);
AnnounceEnum(Model);
}
Target() : Analyser::Static::Target(Machine::Macintosh) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(model);
AnnounceEnum(Model);
}
};
+85 -40
View File
@@ -11,10 +11,10 @@
#include "Tape.hpp"
#include "Target.hpp"
#include "../Disassembler/6502.hpp"
#include "../Disassembler/AddressMapper.hpp"
#include "Analyser/Static/Disassembler/6502.hpp"
#include "Analyser/Static/Disassembler/AddressMapper.hpp"
#include "../../../Storage/Disk/Encodings/MFM/Parser.hpp"
#include "Storage/Disk/Encodings/MFM/Parser.hpp"
#include <cstring>
@@ -22,12 +22,22 @@ using namespace Analyser::Static::Oric;
namespace {
int score(const Analyser::Static::MOS6502::Disassembly &disassembly, const std::set<uint16_t> &rom_functions, const std::set<uint16_t> &variable_locations) {
int score(
const Analyser::Static::MOS6502::Disassembly &disassembly,
const std::set<uint16_t> &rom_functions,
const std::set<uint16_t> &variable_locations
) {
int score = 0;
for(const auto address : disassembly.outward_calls) score += (rom_functions.find(address) != rom_functions.end()) ? 1 : -1;
for(const auto address : disassembly.external_stores) score += (variable_locations.find(address) != variable_locations.end()) ? 1 : -1;
for(const auto address : disassembly.external_loads) score += (variable_locations.find(address) != variable_locations.end()) ? 1 : -1;
for(const auto address : disassembly.outward_calls) {
score += (rom_functions.find(address) != rom_functions.end()) ? 1 : -1;
}
for(const auto address : disassembly.external_stores) {
score += (variable_locations.find(address) != variable_locations.end()) ? 1 : -1;
}
for(const auto address : disassembly.external_loads) {
score += (variable_locations.find(address) != variable_locations.end()) ? 1 : -1;
}
return score;
}
@@ -35,19 +45,32 @@ int score(const Analyser::Static::MOS6502::Disassembly &disassembly, const std::
int basic10_score(const Analyser::Static::MOS6502::Disassembly &disassembly) {
const std::set<uint16_t> rom_functions = {
0x0228, 0x022b,
0xc3ca, 0xc3f8, 0xc448, 0xc47c, 0xc4b5, 0xc4e3, 0xc4e0, 0xc524, 0xc56f, 0xc5a2, 0xc5f8, 0xc60a, 0xc6a5, 0xc6de, 0xc719, 0xc738,
0xc773, 0xc824, 0xc832, 0xc841, 0xc8c1, 0xc8fe, 0xc91f, 0xc93f, 0xc941, 0xc91e, 0xc98b, 0xc996, 0xc9b3, 0xc9e0, 0xca0a, 0xca1c,
0xca1f, 0xca3e, 0xca61, 0xca78, 0xca98, 0xcad2, 0xcb61, 0xcb9f, 0xcc59, 0xcbed, 0xcc0a, 0xcc8c, 0xcc8f, 0xccba, 0xccc9, 0xccfd,
0xce0c, 0xce77, 0xce8b, 0xcfac, 0xcf74, 0xd03c, 0xd059, 0xcff0, 0xd087, 0xd0f2, 0xd0fc, 0xd361, 0xd3eb, 0xd47e, 0xd4a6, 0xd401,
0xd593, 0xd5a3, 0xd4fa, 0xd595, 0xd730, 0xd767, 0xd816, 0xd82a, 0xd856, 0xd861, 0xd8a6, 0xd8b5, 0xd80a, 0xd867, 0xd938, 0xd894,
0xd89d, 0xd8ac, 0xd983, 0xd993, 0xd9b5, 0xd93d, 0xd965, 0xda3f, 0xd9c6, 0xda16, 0xdaab, 0xdada, 0xda6b, 0xdb92, 0xdbb9, 0xdc79,
0xdd4d, 0xdda3, 0xddbf, 0xd0d0, 0xde77, 0xdef4, 0xdf0b, 0xdf0f, 0xdf04, 0xdf12, 0xdf31, 0xdf4c, 0xdf8c, 0xdfa5, 0xdfcf, 0xe076,
0xe0c1, 0xe22a, 0xe27c, 0xe2a6, 0xe313, 0xe34b, 0xe387, 0xe38e, 0xe3d7, 0xe407, 0xe43b, 0xe46f, 0xe4a8, 0xe4f2, 0xe554, 0xe57d,
0xe585, 0xe58c, 0xe594, 0xe5a4, 0xe5ab, 0xe5b6, 0xe5ea, 0xe563, 0xe5c6, 0xe630, 0xe696, 0xe6ba, 0xe6ca, 0xe725, 0xe7aa, 0xe903,
0xe7db, 0xe80d, 0xe987, 0xe9d1, 0xe87d, 0xe905, 0xe965, 0xe974, 0xe994, 0xe9a9, 0xe9bb, 0xec45, 0xeccc, 0xedc4, 0xecc7, 0xed01,
0xed09, 0xed70, 0xed81, 0xed8f, 0xe0ad, 0xeee8, 0xeef8, 0xebdf, 0xebe2, 0xebe5, 0xebeb, 0xebee, 0xebf4, 0xebf7, 0xebfa, 0xebe8,
0xf43c, 0xf4ef, 0xf523, 0xf561, 0xf535, 0xf57b, 0xf5d3, 0xf71a, 0xf73f, 0xf7e4, 0xf7e0, 0xf82f, 0xf88f, 0xf8af, 0xf8b5, 0xf920,
0xf967, 0xf960, 0xf9c9, 0xfa14, 0xfa85, 0xfa9b, 0xfab1, 0xfac7, 0xfafa, 0xfb10, 0xfb26, 0xfbb6, 0xfbfe
0xc3ca, 0xc3f8, 0xc448, 0xc47c, 0xc4b5, 0xc4e3, 0xc4e0, 0xc524,
0xc56f, 0xc5a2, 0xc5f8, 0xc60a, 0xc6a5, 0xc6de, 0xc719, 0xc738,
0xc773, 0xc824, 0xc832, 0xc841, 0xc8c1, 0xc8fe, 0xc91f, 0xc93f,
0xc941, 0xc91e, 0xc98b, 0xc996, 0xc9b3, 0xc9e0, 0xca0a, 0xca1c,
0xca1f, 0xca3e, 0xca61, 0xca78, 0xca98, 0xcad2, 0xcb61, 0xcb9f,
0xcc59, 0xcbed, 0xcc0a, 0xcc8c, 0xcc8f, 0xccba, 0xccc9, 0xccfd,
0xce0c, 0xce77, 0xce8b, 0xcfac, 0xcf74, 0xd03c, 0xd059, 0xcff0,
0xd087, 0xd0f2, 0xd0fc, 0xd361, 0xd3eb, 0xd47e, 0xd4a6, 0xd401,
0xd593, 0xd5a3, 0xd4fa, 0xd595, 0xd730, 0xd767, 0xd816, 0xd82a,
0xd856, 0xd861, 0xd8a6, 0xd8b5, 0xd80a, 0xd867, 0xd938, 0xd894,
0xd89d, 0xd8ac, 0xd983, 0xd993, 0xd9b5, 0xd93d, 0xd965, 0xda3f,
0xd9c6, 0xda16, 0xdaab, 0xdada, 0xda6b, 0xdb92, 0xdbb9, 0xdc79,
0xdd4d, 0xdda3, 0xddbf, 0xd0d0, 0xde77, 0xdef4, 0xdf0b, 0xdf0f,
0xdf04, 0xdf12, 0xdf31, 0xdf4c, 0xdf8c, 0xdfa5, 0xdfcf, 0xe076,
0xe0c1, 0xe22a, 0xe27c, 0xe2a6, 0xe313, 0xe34b, 0xe387, 0xe38e,
0xe3d7, 0xe407, 0xe43b, 0xe46f, 0xe4a8, 0xe4f2, 0xe554, 0xe57d,
0xe585, 0xe58c, 0xe594, 0xe5a4, 0xe5ab, 0xe5b6, 0xe5ea, 0xe563,
0xe5c6, 0xe630, 0xe696, 0xe6ba, 0xe6ca, 0xe725, 0xe7aa, 0xe903,
0xe7db, 0xe80d, 0xe987, 0xe9d1, 0xe87d, 0xe905, 0xe965, 0xe974,
0xe994, 0xe9a9, 0xe9bb, 0xec45, 0xeccc, 0xedc4, 0xecc7, 0xed01,
0xed09, 0xed70, 0xed81, 0xed8f, 0xe0ad, 0xeee8, 0xeef8, 0xebdf,
0xebe2, 0xebe5, 0xebeb, 0xebee, 0xebf4, 0xebf7, 0xebfa, 0xebe8,
0xf43c, 0xf4ef, 0xf523, 0xf561, 0xf535, 0xf57b, 0xf5d3, 0xf71a,
0xf73f, 0xf7e4, 0xf7e0, 0xf82f, 0xf88f, 0xf8af, 0xf8b5, 0xf920,
0xf967, 0xf960, 0xf9c9, 0xfa14, 0xfa85, 0xfa9b, 0xfab1, 0xfac7,
0xfafa, 0xfb10, 0xfb26, 0xfbb6, 0xfbfe
};
const std::set<uint16_t> variable_locations = {
0x0228, 0x0229, 0x022a, 0x022b, 0x022c, 0x022d, 0x0230
@@ -59,19 +82,32 @@ int basic10_score(const Analyser::Static::MOS6502::Disassembly &disassembly) {
int basic11_score(const Analyser::Static::MOS6502::Disassembly &disassembly) {
const std::set<uint16_t> rom_functions = {
0x0238, 0x023b, 0x023e, 0x0241, 0x0244, 0x0247,
0xc3c6, 0xc3f4, 0xc444, 0xc47c, 0xc4a8, 0xc4d3, 0xc4e0, 0xc524, 0xc55f, 0xc592, 0xc5e8, 0xc5fa, 0xc692, 0xc6b3, 0xc6ee, 0xc70d,
0xc748, 0xc7fd, 0xc809, 0xc816, 0xc82f, 0xc855, 0xc8c1, 0xc915, 0xc952, 0xc971, 0xc973, 0xc9a0, 0xc9bd, 0xc9c8, 0xc9e5, 0xca12,
0xca3c, 0xca4e, 0xca51, 0xca70, 0xca99, 0xcac2, 0xcae2, 0xcb1c, 0xcbab, 0xcbf0, 0xcc59, 0xccb0, 0xccce, 0xcd16, 0xcd19, 0xcd46,
0xcd55, 0xcd89, 0xce98, 0xcf03, 0xcf17, 0xcfac, 0xd000, 0xd03c, 0xd059, 0xd07c, 0xd113, 0xd17e, 0xd188, 0xd361, 0xd3eb, 0xd47e,
0xd4a6, 0xd4ba, 0xd593, 0xd5a3, 0xd5b5, 0xd650, 0xd730, 0xd767, 0xd816, 0xd82a, 0xd856, 0xd861, 0xd8a6, 0xd8b5, 0xd8c5, 0xd922,
0xd938, 0xd94f, 0xd958, 0xd967, 0xd983, 0xd993, 0xd9b5, 0xd9de, 0xda0c, 0xda3f, 0xda51, 0xdaa1, 0xdaab, 0xdada, 0xdaf6, 0xdb92,
0xdbb9, 0xdcaf, 0xdd51, 0xdda7, 0xddc3, 0xddd4, 0xde77, 0xdef4, 0xdf0b, 0xdf0f, 0xdf13, 0xdf21, 0xdf49, 0xdf4c, 0xdf8c, 0xdfbd,
0xdfe7, 0xe076, 0xe0c5, 0xe22e, 0xe27c, 0xe2aa, 0xe313, 0xe34f, 0xe38b, 0xe392, 0xe3db, 0xe407, 0xe43f, 0xe46f, 0xe4ac, 0xe4e0,
0xe4f2, 0xe56c, 0xe57d, 0xe585, 0xe58c, 0xe594, 0xe5a4, 0xe5ab, 0xe5b6, 0xe5ea, 0xe5f5, 0xe607, 0xe65e, 0xe6c9, 0xe735, 0xe75a,
0xe76a, 0xe7b2, 0xe85b, 0xe903, 0xe909, 0xe946, 0xe987, 0xe9d1, 0xeaf0, 0xeb78, 0xebce, 0xebe7, 0xec0c, 0xec21, 0xec33, 0xec45,
0xeccc, 0xedc4, 0xede0, 0xee1a, 0xee22, 0xee8c, 0xee9d, 0xeeab, 0xeec9, 0xeee8, 0xeef8, 0xf0c8, 0xf0fd, 0xf110, 0xf11d, 0xf12d,
0xf204, 0xf210, 0xf268, 0xf37f, 0xf495, 0xf4ef, 0xf523, 0xf561, 0xf590, 0xf5c1, 0xf602, 0xf71a, 0xf77c, 0xf7e4, 0xf816, 0xf865,
0xf88f, 0xf8af, 0xf8b5, 0xf920, 0xf967, 0xf9aa, 0xf9c9, 0xfa14, 0xfa9f, 0xfab5, 0xfacb, 0xfae1, 0xfb14, 0xfb2a, 0xfb40, 0xfbd0,
0xc3c6, 0xc3f4, 0xc444, 0xc47c, 0xc4a8, 0xc4d3, 0xc4e0, 0xc524,
0xc55f, 0xc592, 0xc5e8, 0xc5fa, 0xc692, 0xc6b3, 0xc6ee, 0xc70d,
0xc748, 0xc7fd, 0xc809, 0xc816, 0xc82f, 0xc855, 0xc8c1, 0xc915,
0xc952, 0xc971, 0xc973, 0xc9a0, 0xc9bd, 0xc9c8, 0xc9e5, 0xca12,
0xca3c, 0xca4e, 0xca51, 0xca70, 0xca99, 0xcac2, 0xcae2, 0xcb1c,
0xcbab, 0xcbf0, 0xcc59, 0xccb0, 0xccce, 0xcd16, 0xcd19, 0xcd46,
0xcd55, 0xcd89, 0xce98, 0xcf03, 0xcf17, 0xcfac, 0xd000, 0xd03c,
0xd059, 0xd07c, 0xd113, 0xd17e, 0xd188, 0xd361, 0xd3eb, 0xd47e,
0xd4a6, 0xd4ba, 0xd593, 0xd5a3, 0xd5b5, 0xd650, 0xd730, 0xd767,
0xd816, 0xd82a, 0xd856, 0xd861, 0xd8a6, 0xd8b5, 0xd8c5, 0xd922,
0xd938, 0xd94f, 0xd958, 0xd967, 0xd983, 0xd993, 0xd9b5, 0xd9de,
0xda0c, 0xda3f, 0xda51, 0xdaa1, 0xdaab, 0xdada, 0xdaf6, 0xdb92,
0xdbb9, 0xdcaf, 0xdd51, 0xdda7, 0xddc3, 0xddd4, 0xde77, 0xdef4,
0xdf0b, 0xdf0f, 0xdf13, 0xdf21, 0xdf49, 0xdf4c, 0xdf8c, 0xdfbd,
0xdfe7, 0xe076, 0xe0c5, 0xe22e, 0xe27c, 0xe2aa, 0xe313, 0xe34f,
0xe38b, 0xe392, 0xe3db, 0xe407, 0xe43f, 0xe46f, 0xe4ac, 0xe4e0,
0xe4f2, 0xe56c, 0xe57d, 0xe585, 0xe58c, 0xe594, 0xe5a4, 0xe5ab,
0xe5b6, 0xe5ea, 0xe5f5, 0xe607, 0xe65e, 0xe6c9, 0xe735, 0xe75a,
0xe76a, 0xe7b2, 0xe85b, 0xe903, 0xe909, 0xe946, 0xe987, 0xe9d1,
0xeaf0, 0xeb78, 0xebce, 0xebe7, 0xec0c, 0xec21, 0xec33, 0xec45,
0xeccc, 0xedc4, 0xede0, 0xee1a, 0xee22, 0xee8c, 0xee9d, 0xeeab,
0xeec9, 0xeee8, 0xeef8, 0xf0c8, 0xf0fd, 0xf110, 0xf11d, 0xf12d,
0xf204, 0xf210, 0xf268, 0xf37f, 0xf495, 0xf4ef, 0xf523, 0xf561,
0xf590, 0xf5c1, 0xf602, 0xf71a, 0xf77c, 0xf7e4, 0xf816, 0xf865,
0xf88f, 0xf8af, 0xf8b5, 0xf920, 0xf967, 0xf9aa, 0xf9c9, 0xfa14,
0xfa9f, 0xfab5, 0xfacb, 0xfae1, 0xfb14, 0xfb2a, 0xfb40, 0xfbd0,
0xfc18
};
const std::set<uint16_t> variable_locations = {
@@ -102,7 +138,7 @@ bool is_microdisc(Storage::Encodings::MFM::Parser &parser) {
return !std::memcmp(signature, first_sample.data(), sizeof(signature));
}
bool is_400_loader(Storage::Encodings::MFM::Parser &parser, uint16_t range_start, uint16_t range_end) {
bool is_400_loader(Storage::Encodings::MFM::Parser &parser, const uint16_t range_start, const uint16_t range_end) {
/*
Both the Jasmin and BD-DOS boot sectors are sector 1 of track 0 and are loaded at $400;
use disassembly to test for likely matches.
@@ -120,8 +156,8 @@ bool is_400_loader(Storage::Encodings::MFM::Parser &parser, uint16_t range_start
}
// Grab a disassembly.
const auto disassembly =
Analyser::Static::MOS6502::Disassemble(first_sample, Analyser::Static::Disassembler::OffsetMapper(0x400), {0x400});
const auto disassembly = Analyser::Static::MOS6502::Disassemble(
first_sample, Analyser::Static::Disassembler::OffsetMapper(0x400), {0x400});
// Check for references to the Jasmin registers.
int register_hits = 0;
@@ -145,7 +181,12 @@ bool is_bd500(Storage::Encodings::MFM::Parser &parser) {
}
Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
auto target = std::make_unique<Target>();
target->confidence = 0.5;
@@ -153,14 +194,18 @@ Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &med
int basic11_votes = 0;
for(auto &tape : media.tapes) {
std::vector<File> tape_files = GetFiles(tape);
tape->reset();
auto serialiser = tape->serialiser();
std::vector<File> tape_files = GetFiles(*serialiser);
if(!tape_files.empty()) {
for(const auto &file : tape_files) {
if(file.data_type == File::MachineCode) {
std::vector<uint16_t> entry_points = {file.starting_address};
const Analyser::Static::MOS6502::Disassembly disassembly =
Analyser::Static::MOS6502::Disassemble(file.data, Analyser::Static::Disassembler::OffsetMapper(file.starting_address), entry_points);
Analyser::Static::MOS6502::Disassemble(
file.data,
Analyser::Static::Disassembler::OffsetMapper(file.starting_address),
entry_points
);
if(basic10_score(disassembly) > basic11_score(disassembly)) ++basic10_votes; else ++basic11_votes;
}
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Oric {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+20 -20
View File
@@ -7,61 +7,61 @@
//
#include "Tape.hpp"
#include "../../../Storage/Tape/Parsers/Oric.hpp"
#include "Storage/Tape/Parsers/Oric.hpp"
using namespace Analyser::Static::Oric;
std::vector<File> Analyser::Static::Oric::GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape) {
std::vector<File> Analyser::Static::Oric::GetFiles(Storage::Tape::TapeSerialiser &serialiser) {
std::vector<File> files;
Storage::Tape::Oric::Parser parser;
while(!tape->is_at_end()) {
while(!serialiser.is_at_end()) {
// sync to next lead-in, check that it's one of three 0x16s
bool is_fast = parser.sync_and_get_encoding_speed(tape);
bool is_fast = parser.sync_and_get_encoding_speed(serialiser);
int next_bytes[2];
next_bytes[0] = parser.get_next_byte(tape, is_fast);
next_bytes[1] = parser.get_next_byte(tape, is_fast);
next_bytes[0] = parser.get_next_byte(serialiser, is_fast);
next_bytes[1] = parser.get_next_byte(serialiser, is_fast);
if(next_bytes[0] != 0x16 || next_bytes[1] != 0x16) continue;
// get the first byte that isn't a 0x16, check it was a 0x24
int byte = 0x16;
while(!tape->is_at_end() && byte == 0x16) {
byte = parser.get_next_byte(tape, is_fast);
while(!serialiser.is_at_end() && byte == 0x16) {
byte = parser.get_next_byte(serialiser, is_fast);
}
if(byte != 0x24) continue;
// skip two empty bytes
parser.get_next_byte(tape, is_fast);
parser.get_next_byte(tape, is_fast);
parser.get_next_byte(serialiser, is_fast);
parser.get_next_byte(serialiser, is_fast);
// get data and launch types
File new_file;
switch(parser.get_next_byte(tape, is_fast)) {
switch(parser.get_next_byte(serialiser, is_fast)) {
case 0x00: new_file.data_type = File::ProgramType::BASIC; break;
case 0x80: new_file.data_type = File::ProgramType::MachineCode; break;
default: new_file.data_type = File::ProgramType::None; break;
}
switch(parser.get_next_byte(tape, is_fast)) {
switch(parser.get_next_byte(serialiser, is_fast)) {
case 0x80: new_file.launch_type = File::ProgramType::BASIC; break;
case 0xc7: new_file.launch_type = File::ProgramType::MachineCode; break;
default: new_file.launch_type = File::ProgramType::None; break;
}
// read end and start addresses
new_file.ending_address = uint16_t(parser.get_next_byte(tape, is_fast) << 8);
new_file.ending_address |= uint16_t(parser.get_next_byte(tape, is_fast));
new_file.starting_address = uint16_t(parser.get_next_byte(tape, is_fast) << 8);
new_file.starting_address |= uint16_t(parser.get_next_byte(tape, is_fast));
new_file.ending_address = uint16_t(parser.get_next_byte(serialiser, is_fast) << 8);
new_file.ending_address |= uint16_t(parser.get_next_byte(serialiser, is_fast));
new_file.starting_address = uint16_t(parser.get_next_byte(serialiser, is_fast) << 8);
new_file.starting_address |= uint16_t(parser.get_next_byte(serialiser, is_fast));
// skip an empty byte
parser.get_next_byte(tape, is_fast);
parser.get_next_byte(serialiser, is_fast);
// read file name, up to 16 characters and null terminated
char file_name[17];
int name_pos = 0;
while(name_pos < 16) {
file_name[name_pos] = char(parser.get_next_byte(tape, is_fast));
file_name[name_pos] = char(parser.get_next_byte(serialiser, is_fast));
if(!file_name[name_pos]) break;
name_pos++;
}
@@ -72,11 +72,11 @@ std::vector<File> Analyser::Static::Oric::GetFiles(const std::shared_ptr<Storage
std::size_t body_length = new_file.ending_address - new_file.starting_address + 1;
new_file.data.reserve(body_length);
for(std::size_t c = 0; c < body_length; c++) {
new_file.data.push_back(uint8_t(parser.get_next_byte(tape, is_fast)));
new_file.data.push_back(uint8_t(parser.get_next_byte(serialiser, is_fast)));
}
// only one validation check: was there enough tape?
if(!tape->is_at_end()) {
if(!serialiser.is_at_end()) {
files.push_back(new_file);
}
}
+2 -2
View File
@@ -8,7 +8,7 @@
#pragma once
#include "../../../Storage/Tape/Tape.hpp"
#include "Storage/Tape/Tape.hpp"
#include <string>
#include <vector>
@@ -28,6 +28,6 @@ struct File {
std::vector<uint8_t> data;
};
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
std::vector<File> GetFiles(Storage::Tape::TapeSerialiser &);
}
+14 -12
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
#include <string>
namespace Analyser::Static::Oric {
@@ -41,15 +41,17 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
std::string loading_command;
bool should_start_jasmin = false;
Target(): Analyser::Static::Target(Machine::Oric) {
if(needs_declare()) {
DeclareField(rom);
DeclareField(disk_interface);
DeclareField(processor);
AnnounceEnum(ROM);
AnnounceEnum(DiskInterface);
AnnounceEnum(Processor);
}
Target(): Analyser::Static::Target(Machine::Oric) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(rom);
DeclareField(disk_interface);
DeclareField(processor);
AnnounceEnum(ROM);
AnnounceEnum(DiskInterface);
AnnounceEnum(Processor);
}
};
@@ -9,7 +9,12 @@
#include "StaticAnalyser.hpp"
#include "Target.hpp"
Analyser::Static::TargetList Analyser::Static::PCCompatible::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::PCCompatible::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
// This analyser can comprehend disks only.
if(media.disks.empty()) return {};
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::PCCompatible {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+31 -14
View File
@@ -8,29 +8,46 @@
#pragma once
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Struct.hpp"
namespace Analyser::Static::PCCompatible {
ReflectableEnum(Model,
XT,
TurboXT,
AT
);
constexpr bool is_xt(const Model model) {
return model <= Model::TurboXT;
}
constexpr bool is_at(const Model model) {
return model >= Model::AT;
}
constexpr bool has_ide(const Model model) {
return model >= Model::AT;
}
struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Target> {
ReflectableEnum(VideoAdaptor,
MDA,
CGA);
CGA,
);
VideoAdaptor adaptor = VideoAdaptor::CGA;
Model model = Model::TurboXT;
ReflectableEnum(Speed,
ApproximatelyOriginal,
Fast);
Speed speed = Speed::Fast;
Target() : Analyser::Static::Target(Machine::PCCompatible) {}
Target() : Analyser::Static::Target(Machine::PCCompatible) {
if(needs_declare()) {
AnnounceEnum(VideoAdaptor);
AnnounceEnum(Speed);
DeclareField(adaptor);
DeclareField(speed);
}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
AnnounceEnum(VideoAdaptor);
AnnounceEnum(Model);
DeclareField(adaptor);
DeclareField(model);
}
};
+10 -4
View File
@@ -13,7 +13,12 @@
#include <algorithm>
#include <cstring>
Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(
const Media &media,
const std::string &file_name,
TargetPlatform::IntType,
bool
) {
if(media.cartridges.empty())
return {};
@@ -54,7 +59,8 @@ Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &med
if(lowercase_name.find("(jp)") == std::string::npos) {
target->region =
(lowercase_name.find("(us)") == std::string::npos &&
lowercase_name.find("(ntsc)") == std::string::npos) ? Target::Region::Europe : Target::Region::USA;
lowercase_name.find("(ntsc)") == std::string::npos) ?
Target::Region::Europe : Target::Region::USA;
}
} break;
}
@@ -63,9 +69,9 @@ Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &med
// If one is found, set the paging scheme appropriately.
const uint16_t inverse_checksum = uint16_t(0x10000 - (data[0x7fe6] | (data[0x7fe7] << 8)));
if(
data[0x7fe3] >= 0x87 && data[0x7fe3] < 0x96 && // i.e. game is dated between 1987 and 1996
data[0x7fe3] >= 0x87 && data[0x7fe3] < 0x96 && // i.e. game is dated between 1987 and 1996
(inverse_checksum&0xff) == data[0x7fe8] &&
(inverse_checksum >> 8) == data[0x7fe9] && // i.e. the standard checksum appears to be present
(inverse_checksum >> 8) == data[0x7fe9] && // i.e. the standard checksum appears to be present.
!data[0x7fea] && !data[0x7feb] && !data[0x7fec] && !data[0x7fed] && !data[0x7fee] && !data[0x7fef]
) {
target->paging_scheme = Target::PagingScheme::Codemasters;
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::Sega {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+11 -9
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
namespace Analyser::Static::Sega {
@@ -37,15 +37,17 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
Region region = Region::Japan;
PagingScheme paging_scheme = PagingScheme::Sega;
Target() : Analyser::Static::Target(Machine::MasterSystem) {
if(needs_declare()) {
DeclareField(region);
AnnounceEnum(Region);
}
Target() : Analyser::Static::Target(Machine::MasterSystem) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(region);
AnnounceEnum(Region);
}
};
constexpr bool is_master_system(Analyser::Static::Sega::Target::Model model) {
constexpr bool is_master_system(const Analyser::Static::Sega::Target::Model model) {
return model >= Analyser::Static::Sega::Target::Model::MasterSystem;
}
+102 -87
View File
@@ -9,82 +9,85 @@
#include "StaticAnalyser.hpp"
#include <algorithm>
#include <bit>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <iterator>
// Analysers
#include "Acorn/StaticAnalyser.hpp"
#include "Amiga/StaticAnalyser.hpp"
#include "AmstradCPC/StaticAnalyser.hpp"
#include "AppleII/StaticAnalyser.hpp"
#include "AppleIIgs/StaticAnalyser.hpp"
#include "Atari2600/StaticAnalyser.hpp"
#include "AtariST/StaticAnalyser.hpp"
#include "Coleco/StaticAnalyser.hpp"
#include "Commodore/StaticAnalyser.hpp"
#include "DiskII/StaticAnalyser.hpp"
#include "Enterprise/StaticAnalyser.hpp"
#include "FAT12/StaticAnalyser.hpp"
#include "Macintosh/StaticAnalyser.hpp"
#include "MSX/StaticAnalyser.hpp"
#include "Oric/StaticAnalyser.hpp"
#include "PCCompatible/StaticAnalyser.hpp"
#include "Sega/StaticAnalyser.hpp"
#include "ZX8081/StaticAnalyser.hpp"
#include "ZXSpectrum/StaticAnalyser.hpp"
#include "Analyser/Static/Acorn/StaticAnalyser.hpp"
#include "Analyser/Static/Amiga/StaticAnalyser.hpp"
#include "Analyser/Static/AmstradCPC/StaticAnalyser.hpp"
#include "Analyser/Static/AppleII/StaticAnalyser.hpp"
#include "Analyser/Static/AppleIIgs/StaticAnalyser.hpp"
#include "Analyser/Static/Atari2600/StaticAnalyser.hpp"
#include "Analyser/Static/AtariST/StaticAnalyser.hpp"
#include "Analyser/Static/Coleco/StaticAnalyser.hpp"
#include "Analyser/Static/Commodore/StaticAnalyser.hpp"
#include "Analyser/Static/DiskII/StaticAnalyser.hpp"
#include "Analyser/Static/Enterprise/StaticAnalyser.hpp"
#include "Analyser/Static/FAT12/StaticAnalyser.hpp"
#include "Analyser/Static/Macintosh/StaticAnalyser.hpp"
#include "Analyser/Static/MSX/StaticAnalyser.hpp"
#include "Analyser/Static/Oric/StaticAnalyser.hpp"
#include "Analyser/Static/PCCompatible/StaticAnalyser.hpp"
#include "Analyser/Static/Sega/StaticAnalyser.hpp"
#include "Analyser/Static/ZX8081/StaticAnalyser.hpp"
#include "Analyser/Static/ZXSpectrum/StaticAnalyser.hpp"
// Cartridges
#include "../../Storage/Cartridge/Formats/BinaryDump.hpp"
#include "../../Storage/Cartridge/Formats/PRG.hpp"
#include "Storage/Cartridge/Formats/BinaryDump.hpp"
#include "Storage/Cartridge/Formats/PRG.hpp"
// Disks
#include "../../Storage/Disk/DiskImage/Formats/2MG.hpp"
#include "../../Storage/Disk/DiskImage/Formats/AcornADF.hpp"
#include "../../Storage/Disk/DiskImage/Formats/AmigaADF.hpp"
#include "../../Storage/Disk/DiskImage/Formats/AppleDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/CPCDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/D64.hpp"
#include "../../Storage/Disk/DiskImage/Formats/G64.hpp"
#include "../../Storage/Disk/DiskImage/Formats/DMK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/FAT12.hpp"
#include "../../Storage/Disk/DiskImage/Formats/HFE.hpp"
#include "../../Storage/Disk/DiskImage/Formats/IPF.hpp"
#include "../../Storage/Disk/DiskImage/Formats/IMD.hpp"
#include "../../Storage/Disk/DiskImage/Formats/MacintoshIMG.hpp"
#include "../../Storage/Disk/DiskImage/Formats/MSA.hpp"
#include "../../Storage/Disk/DiskImage/Formats/NIB.hpp"
#include "../../Storage/Disk/DiskImage/Formats/OricMFMDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/PCBooter.hpp"
#include "../../Storage/Disk/DiskImage/Formats/SSD.hpp"
#include "../../Storage/Disk/DiskImage/Formats/STX.hpp"
#include "../../Storage/Disk/DiskImage/Formats/WOZ.hpp"
#include "Storage/Disk/DiskImage/Formats/2MG.hpp"
#include "Storage/Disk/DiskImage/Formats/AcornADF.hpp"
#include "Storage/Disk/DiskImage/Formats/AmigaADF.hpp"
#include "Storage/Disk/DiskImage/Formats/AppleDSK.hpp"
#include "Storage/Disk/DiskImage/Formats/CPCDSK.hpp"
#include "Storage/Disk/DiskImage/Formats/D64.hpp"
#include "Storage/Disk/DiskImage/Formats/G64.hpp"
#include "Storage/Disk/DiskImage/Formats/DMK.hpp"
#include "Storage/Disk/DiskImage/Formats/FAT12.hpp"
#include "Storage/Disk/DiskImage/Formats/HFE.hpp"
#include "Storage/Disk/DiskImage/Formats/IPF.hpp"
#include "Storage/Disk/DiskImage/Formats/IMD.hpp"
#include "Storage/Disk/DiskImage/Formats/JFD.hpp"
#include "Storage/Disk/DiskImage/Formats/MacintoshIMG.hpp"
#include "Storage/Disk/DiskImage/Formats/MSA.hpp"
#include "Storage/Disk/DiskImage/Formats/NIB.hpp"
#include "Storage/Disk/DiskImage/Formats/OricMFMDSK.hpp"
#include "Storage/Disk/DiskImage/Formats/PCBooter.hpp"
#include "Storage/Disk/DiskImage/Formats/SSD.hpp"
#include "Storage/Disk/DiskImage/Formats/STX.hpp"
#include "Storage/Disk/DiskImage/Formats/WOZ.hpp"
// Mass Storage Devices (i.e. usually, hard disks)
#include "../../Storage/MassStorage/Formats/DAT.hpp"
#include "../../Storage/MassStorage/Formats/DSK.hpp"
#include "../../Storage/MassStorage/Formats/HDV.hpp"
#include "../../Storage/MassStorage/Formats/HFV.hpp"
#include "Storage/MassStorage/Formats/DAT.hpp"
#include "Storage/MassStorage/Formats/DSK.hpp"
#include "Storage/MassStorage/Formats/HDV.hpp"
#include "Storage/MassStorage/Formats/HFV.hpp"
#include "Storage/MassStorage/Formats/VHD.hpp"
// State Snapshots
#include "../../Storage/State/SNA.hpp"
#include "../../Storage/State/SZX.hpp"
#include "../../Storage/State/Z80.hpp"
#include "Storage/State/SNA.hpp"
#include "Storage/State/SZX.hpp"
#include "Storage/State/Z80.hpp"
// Tapes
#include "../../Storage/Tape/Formats/CAS.hpp"
#include "../../Storage/Tape/Formats/CommodoreTAP.hpp"
#include "../../Storage/Tape/Formats/CSW.hpp"
#include "../../Storage/Tape/Formats/OricTAP.hpp"
#include "../../Storage/Tape/Formats/TapePRG.hpp"
#include "../../Storage/Tape/Formats/TapeUEF.hpp"
#include "../../Storage/Tape/Formats/TZX.hpp"
#include "../../Storage/Tape/Formats/ZX80O81P.hpp"
#include "../../Storage/Tape/Formats/ZXSpectrumTAP.hpp"
#include "Storage/Tape/Formats/CAS.hpp"
#include "Storage/Tape/Formats/CommodoreTAP.hpp"
#include "Storage/Tape/Formats/CSW.hpp"
#include "Storage/Tape/Formats/OricTAP.hpp"
#include "Storage/Tape/Formats/TapePRG.hpp"
#include "Storage/Tape/Formats/TapeUEF.hpp"
#include "Storage/Tape/Formats/TZX.hpp"
#include "Storage/Tape/Formats/ZX80O81P.hpp"
#include "Storage/Tape/Formats/ZXSpectrumTAP.hpp"
// Target Platform Types
#include "../../Storage/TargetPlatforms.hpp"
#include "Storage/TargetPlatforms.hpp"
template<class> inline constexpr bool always_false_v = false;
@@ -104,14 +107,14 @@ std::string get_extension(const std::string &name) {
}
class MediaAccumulator {
public:
public:
MediaAccumulator(const std::string &file_name, TargetPlatform::IntType &potential_platforms) :
file_name_(file_name), potential_platforms_(potential_platforms), extension_(get_extension(file_name)) {}
/// Adds @c instance to the media collection and adds @c platforms to the set of potentials.
/// If @c instance is an @c TargetPlatform::TypeDistinguisher then it is given an opportunity to restrict the set of potentials.
template <typename InstanceT>
void insert(TargetPlatform::IntType platforms, std::shared_ptr<InstanceT> instance) {
void insert(const TargetPlatform::IntType platforms, std::shared_ptr<InstanceT> instance) {
if constexpr (std::is_base_of_v<Storage::Disk::Disk, InstanceT>) {
media.disks.push_back(instance);
} else if constexpr (std::is_base_of_v<Storage::Tape::Tape, InstanceT>) {
@@ -127,20 +130,23 @@ class MediaAccumulator {
potential_platforms_ |= platforms;
// Check whether the instance itself has any input on target platforms.
TargetPlatform::TypeDistinguisher *const distinguisher =
dynamic_cast<TargetPlatform::TypeDistinguisher *>(instance.get());
if(distinguisher) potential_platforms_ &= distinguisher->target_platform_type();
TargetPlatform::Distinguisher *const distinguisher =
dynamic_cast<TargetPlatform::Distinguisher *>(instance.get());
if(distinguisher) {
was_distinguished = true;
potential_platforms_ &= distinguisher->target_platforms();
}
}
/// Concstructs a new instance of @c InstanceT supplying @c args and adds it to the back of @c list using @c insert_instance.
template <typename InstanceT, typename... Args>
void insert(TargetPlatform::IntType platforms, Args &&... args) {
void insert(const TargetPlatform::IntType platforms, Args &&... args) {
insert(platforms, std::make_shared<InstanceT>(std::forward<Args>(args)...));
}
/// Calls @c insert with the specified parameters, ignoring any exceptions thrown.
template <typename InstanceT, typename... Args>
void try_insert(TargetPlatform::IntType platforms, Args &&... args) {
void try_insert(const TargetPlatform::IntType platforms, Args &&... args) {
try {
insert<InstanceT>(platforms, std::forward<Args>(args)...);
} catch(...) {}
@@ -149,22 +155,23 @@ class MediaAccumulator {
/// Performs a @c try_insert for an object of @c InstanceT if @c extension matches that of the file name,
/// providing the file name as the only construction argument.
template <typename InstanceT>
void try_standard(TargetPlatform::IntType platforms, const char *extension) {
void try_standard(const TargetPlatform::IntType platforms, const char *extension) {
if(name_matches(extension)) {
try_insert<InstanceT>(platforms, file_name_);
}
}
bool name_matches(const char *extension) {
bool name_matches(const char *const extension) {
return extension_ == extension;
}
Media media;
bool was_distinguished = false;
private:
const std::string &file_name_;
TargetPlatform::IntType &potential_platforms_;
const std::string extension_;
private:
const std::string &file_name_;
TargetPlatform::IntType &potential_platforms_;
const std::string extension_;
};
}
@@ -201,6 +208,7 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
accumulator.try_standard<Disk::DiskImageHolder<Disk::AcornADF>>(TargetPlatform::Acorn, "adf");
accumulator.try_standard<Disk::DiskImageHolder<Disk::AmigaADF>>(TargetPlatform::Amiga, "adf");
accumulator.try_standard<Disk::DiskImageHolder<Disk::AcornADF>>(TargetPlatform::Acorn, "adl");
accumulator.try_standard<Disk::DiskImageHolder<Disk::JFD>>(TargetPlatform::Archimedes, "jfd");
accumulator.try_standard<Cartridge::BinaryDump>(TargetPlatform::AllCartridge, "bin");
@@ -209,7 +217,7 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
accumulator.try_standard<Cartridge::BinaryDump>(TargetPlatform::Coleco, "col");
accumulator.try_standard<Tape::CSW>(TargetPlatform::AllTape, "csw");
accumulator.try_standard<Disk::DiskImageHolder<Disk::D64>>(TargetPlatform::Commodore, "d64");
accumulator.try_standard<Disk::DiskImageHolder<Disk::D64>>(TargetPlatform::Commodore8bit, "d64");
accumulator.try_standard<MassStorage::DAT>(TargetPlatform::Acorn, "dat");
accumulator.try_standard<Disk::DiskImageHolder<Disk::DMK>>(TargetPlatform::MSX, "dmk");
accumulator.try_standard<Disk::DiskImageHolder<Disk::AppleDSK>>(TargetPlatform::DiskII, "do");
@@ -223,11 +231,12 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
accumulator.try_standard<Disk::DiskImageHolder<Disk::FAT12>>(TargetPlatform::MSX, "dsk");
accumulator.try_standard<Disk::DiskImageHolder<Disk::OricMFMDSK>>(TargetPlatform::Oric, "dsk");
accumulator.try_standard<Disk::DiskImageHolder<Disk::G64>>(TargetPlatform::Commodore, "g64");
accumulator.try_standard<Disk::DiskImageHolder<Disk::G64>>(TargetPlatform::Commodore8bit, "g64");
accumulator.try_standard<MassStorage::HDV>(TargetPlatform::AppleII, "hdv");
accumulator.try_standard<Disk::DiskImageHolder<Disk::HFE>>(
TargetPlatform::Acorn | TargetPlatform::AmstradCPC | TargetPlatform::Commodore | TargetPlatform::Oric | TargetPlatform::ZXSpectrum,
TargetPlatform::Acorn | TargetPlatform::AmstradCPC | TargetPlatform::Commodore |
TargetPlatform::Oric | TargetPlatform::ZXSpectrum,
"hfe"); // TODO: switch to AllDisk once the MSX stops being so greedy.
accumulator.try_standard<Disk::DiskImageHolder<Disk::FAT12>>(TargetPlatform::PCCompatible, "ima");
@@ -264,13 +273,14 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
accumulator.try_standard<Tape::ZX80O81P>(TargetPlatform::ZX8081, "p81");
static constexpr auto PRGTargets = TargetPlatform::Vic20; //Commodore8bit; // Disabled until analysis improves.
if(accumulator.name_matches("prg")) {
// Try instantiating as a ROM; failing that accept as a tape.
try {
accumulator.insert<Cartridge::PRG>(TargetPlatform::Commodore, file_name);
accumulator.insert<Cartridge::PRG>(PRGTargets, file_name);
} catch(...) {
try {
accumulator.insert<Tape::PRG>(TargetPlatform::Commodore, file_name);
accumulator.insert<Tape::PRG>(PRGTargets, file_name);
} catch(...) {}
}
}
@@ -285,7 +295,7 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
accumulator.try_standard<Disk::DiskImageHolder<Disk::FAT12>>(TargetPlatform::AtariST, "st");
accumulator.try_standard<Disk::DiskImageHolder<Disk::STX>>(TargetPlatform::AtariST, "stx");
accumulator.try_standard<Tape::CommodoreTAP>(TargetPlatform::Commodore, "tap");
accumulator.try_standard<Tape::CommodoreTAP>(TargetPlatform::Commodore8bit, "tap");
accumulator.try_standard<Tape::OricTAP>(TargetPlatform::Oric, "tap");
accumulator.try_standard<Tape::ZXSpectrumTAP>(TargetPlatform::ZXSpectrum, "tap");
accumulator.try_standard<Tape::TZX>(TargetPlatform::MSX, "tsx");
@@ -293,6 +303,8 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
accumulator.try_standard<Tape::UEF>(TargetPlatform::Acorn, "uef");
accumulator.try_standard<MassStorage::VHD>(TargetPlatform::PCCompatible, "vhd");
accumulator.try_standard<Disk::DiskImageHolder<Disk::WOZ>>(TargetPlatform::DiskII, "woz");
return accumulator.media;
@@ -334,14 +346,24 @@ TargetList Analyser::Static::GetTargets(const std::string &file_name) {
TargetPlatform::IntType potential_platforms = 0;
Media media = GetMediaAndPlatforms(file_name, potential_platforms);
int total_options = std::popcount(potential_platforms);
const bool is_confident = total_options == 1;
// i.e. This analyser `is_confident` if file analysis suggested only one potential target platform.
// The machine-specific static analyser will still run in case it can provide meaningful annotations on
// loading command, machine configuration, etc, but the flag will be passed onwards to mean "don't reject this".
// Hand off to platform-specific determination of whether these
// things are actually compatible and, if so, how to load them.
const auto append = [&](TargetPlatform::IntType platform, auto evaluator) {
if(!(potential_platforms & platform)) {
return;
}
auto new_targets = evaluator(media, file_name, potential_platforms);
std::move(new_targets.begin(), new_targets.end(), std::back_inserter(targets));
auto new_targets = evaluator(media, file_name, potential_platforms, is_confident);
targets.insert(
targets.end(),
std::make_move_iterator(new_targets.begin()),
std::make_move_iterator(new_targets.end())
);
};
append(TargetPlatform::Acorn, Acorn::GetTargets);
@@ -352,7 +374,7 @@ TargetList Analyser::Static::GetTargets(const std::string &file_name) {
append(TargetPlatform::Atari2600, Atari2600::GetTargets);
append(TargetPlatform::AtariST, AtariST::GetTargets);
append(TargetPlatform::Coleco, Coleco::GetTargets);
append(TargetPlatform::Commodore, Commodore::GetTargets);
append(TargetPlatform::Commodore8bit, Commodore::GetTargets);
append(TargetPlatform::DiskII, DiskII::GetTargets);
append(TargetPlatform::Enterprise, Enterprise::GetTargets);
append(TargetPlatform::FAT12, FAT12::GetTargets);
@@ -364,13 +386,6 @@ TargetList Analyser::Static::GetTargets(const std::string &file_name) {
append(TargetPlatform::ZX8081, ZX8081::GetTargets);
append(TargetPlatform::ZXSpectrum, ZXSpectrum::GetTargets);
// Reset any tapes to their initial position.
for(const auto &target : targets) {
for(auto &tape : target->media.tapes) {
tape->reset();
}
}
// Sort by initial confidence. Use a stable sort in case any of the machine-specific analysers
// picked their insertion order carefully.
std::stable_sort(targets.begin(), targets.end(),
+9 -8
View File
@@ -8,13 +8,14 @@
#pragma once
#include "../Machines.hpp"
#include "Analyser/Machines.hpp"
#include "../../Storage/Cartridge/Cartridge.hpp"
#include "../../Storage/Disk/Disk.hpp"
#include "../../Storage/MassStorage/MassStorageDevice.hpp"
#include "../../Storage/Tape/Tape.hpp"
#include "../../Reflection/Struct.hpp"
#include "Storage/Cartridge/Cartridge.hpp"
#include "Storage/Disk/Disk.hpp"
#include "Storage/MassStorage/MassStorageDevice.hpp"
#include "Storage/Tape/Tape.hpp"
#include "Storage/TargetPlatforms.hpp"
#include "Reflection/Struct.hpp"
#include <memory>
#include <string>
@@ -64,9 +65,9 @@ struct Target {
Machine machine;
Media media;
float confidence = 0.0f;
float confidence = 0.5f;
};
typedef std::vector<std::unique_ptr<Target>> TargetList;
using TargetList = std::vector<std::unique_ptr<Target>>;
/*!
Attempts, through any available means, to return a list of potential targets for the file with the given name.
+14 -9
View File
@@ -12,27 +12,32 @@
#include <vector>
#include "Target.hpp"
#include "../../../Storage/Tape/Parsers/ZX8081.hpp"
#include "Storage/Tape/Parsers/ZX8081.hpp"
static std::vector<Storage::Data::ZX8081::File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape) {
static std::vector<Storage::Data::ZX8081::File> GetFiles(Storage::Tape::TapeSerialiser &serialiser) {
std::vector<Storage::Data::ZX8081::File> files;
Storage::Tape::ZX8081::Parser parser;
while(!tape->is_at_end()) {
std::shared_ptr<Storage::Data::ZX8081::File> next_file = parser.get_next_file(tape);
if(next_file != nullptr) {
files.push_back(*next_file);
while(!serialiser.is_at_end()) {
const auto next_file = parser.get_next_file(serialiser);
if(next_file) {
files.push_back(std::move(*next_file));
}
}
return files;
}
Analyser::Static::TargetList Analyser::Static::ZX8081::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType potential_platforms) {
Analyser::Static::TargetList Analyser::Static::ZX8081::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType potential_platforms,
bool
) {
TargetList destination;
if(!media.tapes.empty()) {
std::vector<Storage::Data::ZX8081::File> files = GetFiles(media.tapes.front());
media.tapes.front()->reset();
const auto serialiser = media.tapes.front()->serialiser();
std::vector<Storage::Data::ZX8081::File> files = GetFiles(*serialiser);
if(!files.empty()) {
Target *const target = new Target;
destination.push_back(std::unique_ptr<::Analyser::Static::Target>(target));
+3 -3
View File
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::ZX8081 {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+12 -10
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
#include <string>
namespace Analyser::Static::ZX8081 {
@@ -27,13 +27,15 @@ struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl<
bool ZX80_uses_ZX81_ROM = false;
std::string loading_command;
Target(): Analyser::Static::Target(Machine::ZX8081) {
if(needs_declare()) {
DeclareField(memory_model);
DeclareField(is_ZX81);
DeclareField(ZX80_uses_ZX81_ROM);
AnnounceEnum(MemoryModel);
}
Target(): Analyser::Static::Target(Machine::ZX8081) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(memory_model);
DeclareField(is_ZX81);
DeclareField(ZX80_uses_ZX81_ROM);
AnnounceEnum(MemoryModel);
}
};
+13 -7
View File
@@ -8,9 +8,9 @@
#include "StaticAnalyser.hpp"
#include "../../../Storage/Disk/Parsers/CPM.hpp"
#include "../../../Storage/Disk/Encodings/MFM/Parser.hpp"
#include "../../../Storage/Tape/Parsers/Spectrum.hpp"
#include "Storage/Disk/Parsers/CPM.hpp"
#include "Storage/Disk/Encodings/MFM/Parser.hpp"
#include "Storage/Tape/Parsers/Spectrum.hpp"
#include "Target.hpp"
@@ -18,7 +18,7 @@
namespace {
bool IsSpectrumTape(const std::shared_ptr<Storage::Tape::Tape> &tape) {
bool IsSpectrumTape(Storage::Tape::TapeSerialiser &tape) {
using Parser = Storage::Tape::ZXSpectrum::Parser;
Parser parser(Parser::MachineType::ZXSpectrum);
@@ -97,13 +97,18 @@ bool IsSpectrumDisk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
}
// ... otherwise read a CPM directory and look for a BASIC program called "DISK".
const auto catalogue = Storage::Disk::CPM::GetCatalogue(disk, cpm_format);
const auto catalogue = Storage::Disk::CPM::GetCatalogue(disk, cpm_format, false);
return catalogue && catalogue->is_zx_spectrum_booter();
}
}
Analyser::Static::TargetList Analyser::Static::ZXSpectrum::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
Analyser::Static::TargetList Analyser::Static::ZXSpectrum::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
TargetList destination;
auto target = std::make_unique<Target>();
target->confidence = 0.5;
@@ -111,7 +116,8 @@ Analyser::Static::TargetList Analyser::Static::ZXSpectrum::GetTargets(const Medi
if(!media.tapes.empty()) {
bool has_spectrum_tape = false;
for(auto &tape: media.tapes) {
has_spectrum_tape |= IsSpectrumTape(tape);
auto serialiser = tape->serialiser();
has_spectrum_tape |= IsSpectrumTape(*serialiser);
}
if(has_spectrum_tape) {
@@ -8,12 +8,12 @@
#pragma once
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::ZXSpectrum {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
TargetList GetTargets(const Media &, const std::string &, TargetPlatform::IntType, bool);
}
+10 -8
View File
@@ -8,9 +8,9 @@
#pragma once
#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
#include "Analyser/Static/StaticAnalyser.hpp"
#include "Reflection/Enum.hpp"
#include "Reflection/Struct.hpp"
namespace Analyser::Static::ZXSpectrum {
@@ -27,11 +27,13 @@ struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl<
Model model = Model::Plus2;
bool should_hold_enter = false;
Target(): Analyser::Static::Target(Machine::ZXSpectrum) {
if(needs_declare()) {
DeclareField(model);
AnnounceEnum(Model);
}
Target(): Analyser::Static::Target(Machine::ZXSpectrum) {}
private:
friend Reflection::StructImpl<Target>;
void declare_fields() {
DeclareField(model);
AnnounceEnum(Model);
}
};
+2 -1
View File
@@ -5,7 +5,7 @@ project(CLK
VERSION 24.01.22
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
@@ -29,6 +29,7 @@ endif()
message(STATUS "Configuring for ${CLK_UI} UI")
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include_directories(".")
include("CLK_SOURCES")
add_executable(clksignal ${CLK_SOURCES})
+195 -180
View File
@@ -56,205 +56,220 @@
Boolean operators, but forcing callers and receivers to be explicit as to usage.
*/
template <class T> class WrappedInt {
public:
using IntType = int64_t;
public:
using IntType = int64_t;
forceinline constexpr WrappedInt(IntType l) noexcept : length_(l) {}
forceinline constexpr WrappedInt() noexcept : length_(0) {}
forceinline constexpr WrappedInt(IntType l) noexcept : length_(l) {}
forceinline constexpr WrappedInt() noexcept : length_(0) {}
forceinline T &operator =(const T &rhs) {
length_ = rhs.length_;
return *this;
forceinline T &operator =(const T &rhs) {
length_ = rhs.length_;
return *this;
}
forceinline T &operator +=(const T &rhs) {
length_ += rhs.length_;
return *static_cast<T *>(this);
}
forceinline T &operator -=(const T &rhs) {
length_ -= rhs.length_;
return *static_cast<T *>(this);
}
forceinline T &operator ++() {
++ length_;
return *static_cast<T *>(this);
}
forceinline T &operator ++(int) {
length_ ++;
return *static_cast<T *>(this);
}
forceinline T &operator --() {
-- length_;
return *static_cast<T *>(this);
}
forceinline T &operator --(int) {
length_ --;
return *static_cast<T *>(this);
}
forceinline T &operator *=(const T &rhs) {
length_ *= rhs.length_;
return *static_cast<T *>(this);
}
forceinline T &operator /=(const T &rhs) {
length_ /= rhs.length_;
return *static_cast<T *>(this);
}
forceinline T &operator %=(const T &rhs) {
length_ %= rhs.length_;
return *static_cast<T *>(this);
}
forceinline T &operator &=(const T &rhs) {
length_ &= rhs.length_;
return *static_cast<T *>(this);
}
forceinline constexpr T operator +(const T &rhs) const { return T(length_ + rhs.length_); }
forceinline constexpr T operator -(const T &rhs) const { return T(length_ - rhs.length_); }
forceinline constexpr T operator *(const T &rhs) const { return T(length_ * rhs.length_); }
forceinline constexpr T operator /(const T &rhs) const { return T(length_ / rhs.length_); }
forceinline constexpr T operator %(const T &rhs) const { return T(length_ % rhs.length_); }
forceinline constexpr T operator &(const T &rhs) const { return T(length_ & rhs.length_); }
forceinline constexpr T operator -() const { return T(- length_); }
auto operator <=>(const WrappedInt &) const = default;
forceinline constexpr bool operator !() const { return !length_; }
// bool operator () is not supported because it offers an implicit cast to int,
// which is prone silently to permit misuse.
/// @returns The underlying int, converted to an integral type of your choosing, clamped to that int's range.
template<typename Type = IntType> forceinline constexpr Type as() const {
if constexpr (sizeof(Type) == sizeof(IntType)) {
if constexpr (std::is_same_v<Type, IntType>) {
return length_;
} else if constexpr (std::is_signed_v<Type>) {
// Both integers are the same size, but a signed result is being asked for
// from an unsigned original.
return length_ > Type(std::numeric_limits<Type>::max()) ?
Type(std::numeric_limits<Type>::max()) : Type(length_);
} else {
// An unsigned result is being asked for from a signed original.
return length_ < 0 ? 0 : Type(length_);
}
}
forceinline T &operator +=(const T &rhs) {
length_ += rhs.length_;
return *static_cast<T *>(this);
}
const auto clamped = std::clamp(
length_,
IntType(std::numeric_limits<Type>::min()),
IntType(std::numeric_limits<Type>::max())
);
return Type(clamped);
}
forceinline T &operator -=(const T &rhs) {
length_ -= rhs.length_;
return *static_cast<T *>(this);
}
/// @returns The underlying int, in its native form.
forceinline constexpr IntType as_integral() const { return length_; }
forceinline T &operator ++() {
++ length_;
return *static_cast<T *>(this);
}
/*!
Severs from @c this the effect of dividing by @c divisor; @c this will end up with
the value of @c this modulo @c divisor and @c divided by @c divisor is returned.
*/
template <typename Result = T> forceinline Result divide(const T &divisor) {
Result r;
static_cast<T *>(this)->fill(r, divisor);
return r;
}
forceinline T &operator ++(int) {
length_ ++;
return *static_cast<T *>(this);
}
/*!
Flushes the value in @c this. The current value is returned, and the internal value
is reset to zero.
*/
template <typename Result> Result flush() {
// Jiggery pokery here; switching to function overloading avoids
// the namespace-level requirement for template specialisation.
Result r;
static_cast<T *>(this)->fill(r);
return r;
}
forceinline T &operator --() {
-- length_;
return *static_cast<T *>(this);
}
// operator int() is deliberately not provided, to avoid accidental subtitution of
// classes that use this template.
forceinline T &operator --(int) {
length_ --;
return *static_cast<T *>(this);
}
forceinline T &operator *=(const T &rhs) {
length_ *= rhs.length_;
return *static_cast<T *>(this);
}
forceinline T &operator /=(const T &rhs) {
length_ /= rhs.length_;
return *static_cast<T *>(this);
}
forceinline T &operator %=(const T &rhs) {
length_ %= rhs.length_;
return *static_cast<T *>(this);
}
forceinline T &operator &=(const T &rhs) {
length_ &= rhs.length_;
return *static_cast<T *>(this);
}
forceinline constexpr T operator +(const T &rhs) const { return T(length_ + rhs.length_); }
forceinline constexpr T operator -(const T &rhs) const { return T(length_ - rhs.length_); }
forceinline constexpr T operator *(const T &rhs) const { return T(length_ * rhs.length_); }
forceinline constexpr T operator /(const T &rhs) const { return T(length_ / rhs.length_); }
forceinline constexpr T operator %(const T &rhs) const { return T(length_ % rhs.length_); }
forceinline constexpr T operator &(const T &rhs) const { return T(length_ & rhs.length_); }
forceinline constexpr T operator -() const { return T(- length_); }
forceinline constexpr bool operator <(const T &rhs) const { return length_ < rhs.length_; }
forceinline constexpr bool operator >(const T &rhs) const { return length_ > rhs.length_; }
forceinline constexpr bool operator <=(const T &rhs) const { return length_ <= rhs.length_; }
forceinline constexpr bool operator >=(const T &rhs) const { return length_ >= rhs.length_; }
forceinline constexpr bool operator ==(const T &rhs) const { return length_ == rhs.length_; }
forceinline constexpr bool operator !=(const T &rhs) const { return length_ != rhs.length_; }
forceinline constexpr bool operator !() const { return !length_; }
// bool operator () is not supported because it offers an implicit cast to int, which is prone silently to permit misuse
/// @returns The underlying int, converted to an integral type of your choosing, clamped to that int's range.
template<typename Type = IntType> forceinline constexpr Type as() const {
const auto clamped = std::clamp(length_, IntType(std::numeric_limits<Type>::min()), IntType(std::numeric_limits<Type>::max()));
return Type(clamped);
}
/// @returns The underlying int, in its native form.
forceinline constexpr IntType as_integral() const { return length_; }
/*!
Severs from @c this the effect of dividing by @c divisor; @c this will end up with
the value of @c this modulo @c divisor and @c divided by @c divisor is returned.
*/
template <typename Result = T> forceinline Result divide(const T &divisor) {
Result r;
static_cast<T *>(this)->fill(r, divisor);
return r;
}
/*!
Flushes the value in @c this. The current value is returned, and the internal value
is reset to zero.
*/
template <typename Result> Result flush() {
// Jiggery pokery here; switching to function overloading avoids
// the namespace-level requirement for template specialisation.
Result r;
static_cast<T *>(this)->fill(r);
return r;
}
// operator int() is deliberately not provided, to avoid accidental subtitution of
// classes that use this template.
protected:
IntType length_;
protected:
IntType length_;
};
/// Describes an integer number of whole cycles: pairs of clock signal transitions.
class Cycles: public WrappedInt<Cycles> {
public:
forceinline constexpr Cycles(IntType l) noexcept : WrappedInt<Cycles>(l) {}
forceinline constexpr Cycles() noexcept : WrappedInt<Cycles>() {}
forceinline static constexpr Cycles max() {
return Cycles(std::numeric_limits<IntType>::max());
}
public:
forceinline constexpr Cycles(IntType l) noexcept : WrappedInt<Cycles>(l) {}
forceinline constexpr Cycles() noexcept : WrappedInt<Cycles>() {}
forceinline static constexpr Cycles max() {
return Cycles(std::numeric_limits<IntType>::max());
}
private:
friend WrappedInt;
void fill(Cycles &result) {
result.length_ = length_;
length_ = 0;
}
private:
friend WrappedInt;
void fill(Cycles &result) {
result.length_ = length_;
length_ = 0;
}
void fill(Cycles &result, const Cycles &divisor) {
result.length_ = length_ / divisor.length_;
length_ %= divisor.length_;
}
void fill(Cycles &result, const Cycles &divisor) {
result.length_ = length_ / divisor.length_;
length_ %= divisor.length_;
}
};
/// Describes an integer number of half cycles: single clock signal transitions.
class HalfCycles: public WrappedInt<HalfCycles> {
public:
forceinline constexpr HalfCycles(IntType l) noexcept : WrappedInt<HalfCycles>(l) {}
forceinline constexpr HalfCycles() noexcept : WrappedInt<HalfCycles>() {}
forceinline static constexpr HalfCycles max() {
return HalfCycles(std::numeric_limits<IntType>::max());
}
public:
forceinline constexpr HalfCycles(IntType l) noexcept : WrappedInt<HalfCycles>(l) {}
forceinline constexpr HalfCycles() noexcept : WrappedInt<HalfCycles>() {}
forceinline static constexpr HalfCycles max() {
return HalfCycles(std::numeric_limits<IntType>::max());
}
forceinline constexpr HalfCycles(const Cycles &cycles) noexcept : WrappedInt<HalfCycles>(cycles.as_integral() * 2) {}
forceinline constexpr HalfCycles(const Cycles &cycles) noexcept :
WrappedInt<HalfCycles>(cycles.as_integral() * 2) {}
/// @returns The number of whole cycles completely covered by this span of half cycles.
forceinline constexpr Cycles cycles() const {
return Cycles(length_ >> 1);
}
/// @returns The number of whole cycles completely covered by this span of half cycles.
forceinline constexpr Cycles cycles() const {
return Cycles(length_ >> 1);
}
/*!
Severs from @c this the effect of dividing by @c divisor; @c this will end up with
the value of @c this modulo @c divisor . @c this divided by @c divisor is returned.
*/
forceinline Cycles divide_cycles(const Cycles &divisor) {
const HalfCycles half_divisor = HalfCycles(divisor);
const Cycles result(length_ / half_divisor.length_);
length_ %= half_divisor.length_;
return result;
}
/*!
Severs from @c this the effect of dividing by @c divisor; @c this will end up with
the value of @c this modulo @c divisor . @c this divided by @c divisor is returned.
*/
forceinline Cycles divide_cycles(const Cycles &divisor) {
const HalfCycles half_divisor = HalfCycles(divisor);
const Cycles result(length_ / half_divisor.length_);
length_ %= half_divisor.length_;
return result;
}
/*!
Equivalent to @c divide_cycles(Cycles(1)) but faster.
*/
forceinline Cycles divide_cycles() {
const Cycles result(length_ >> 1);
length_ &= 1;
return result;
}
/*!
Equivalent to @c divide_cycles(Cycles(1)) but faster.
*/
forceinline Cycles divide_cycles() {
const Cycles result(length_ >> 1);
length_ &= 1;
return result;
}
private:
friend WrappedInt;
void fill(Cycles &result) {
result = Cycles(length_ >> 1);
length_ &= 1;
}
private:
friend WrappedInt;
void fill(Cycles &result) {
result = Cycles(length_ >> 1);
length_ &= 1;
}
void fill(HalfCycles &result) {
result.length_ = length_;
length_ = 0;
}
void fill(HalfCycles &result) {
result.length_ = length_;
length_ = 0;
}
void fill(Cycles &result, const HalfCycles &divisor) {
result = Cycles(length_ / (divisor.length_ << 1));
length_ %= (divisor.length_ << 1);
}
void fill(Cycles &result, const HalfCycles &divisor) {
result = Cycles(length_ / (divisor.length_ << 1));
length_ %= (divisor.length_ << 1);
}
void fill(HalfCycles &result, const HalfCycles &divisor) {
result.length_ = length_ / divisor.length_;
length_ %= divisor.length_;
}
void fill(HalfCycles &result, const HalfCycles &divisor) {
result.length_ = length_ / divisor.length_;
length_ %= divisor.length_;
}
};
// Create a specialisation of WrappedInt::flush for converting HalfCycles to Cycles
@@ -265,14 +280,14 @@ class HalfCycles: public WrappedInt<HalfCycles> {
automatically to gain run_for(HalfCycles).
*/
template <class T> class HalfClockReceiver: public T {
public:
using T::T;
public:
using T::T;
forceinline void run_for(const HalfCycles half_cycles) {
half_cycles_ += half_cycles;
T::run_for(half_cycles_.flush<Cycles>());
}
forceinline void run_for(const HalfCycles half_cycles) {
half_cycles_ += half_cycles;
T::run_for(half_cycles_.flush<Cycles>());
}
private:
HalfCycles half_cycles_;
private:
HalfCycles half_cycles_;
};

Some files were not shown because too many files have changed in this diff Show More