Commit Graph

45 Commits

Author SHA1 Message Date
Will Scullin 45a5e63cf9
Use debugger from submodule 2023-11-24 10:12:19 -08:00
Will Scullin 1e79d9d59d
Prettier (#203)
* Enabled prettier

* Update lint, fix issues

* Restore some array formatting
2023-11-24 06:45:55 -08:00
Will Scullin e7891114c6
Use submodules for apple2shader and cpu6502 (#202)
* Use submodules for apple2shader and cpu6502

* Update instructions
2023-11-22 16:28:40 -08:00
Ian Flanigan 486f554d5b
Improve Disk II test reliability (#195)
Before, the garbage test had only about a 92% chance of success
because it relied on random numbers not being equal.  This change just
repeats the test 5 times and allows up to 1 failure.  This increases
the chance of the test passing to a hair less that 99.8%.
2023-08-12 15:50:48 -07:00
Ian Flanigan 6923d43873
Fix issue #187 (and upgrade jest) (#188)
* Update jest to v29.5.0

This updates jest to the latest version (29.5.0) and fixes everything
that the upgrade breaks.  One of the biggest differences is that the
mock types changed and I'm once again confused as to the "proper" way
to create mocks in jest.  Whatever.

* Fix issue #187 were bank writing was not working correctly

Before, `mmu.ts` would deactivate writing to the language card if
`prewrite` was reset.  However, it is totally possible to reset
`prewrite` and leave writing enabled, as shown my Sather in
_Understanding the Apple IIe_, table 5.5, p. 5-24.  For example:

```assembly_x86
    sta  $c08a  ; WRITE DISABLE; READ DISABLE
    lda  $c08b  ; PRE-WRITE set
    lda  $c08b  ; WRITE enabled
    sta  $c08a  ; PRE-WRITE reset; WRITE still enabled!
    lda  $c08b  ; PRE-WRITE set; WRITE still enabled!
```

would not work correctly because the last line would clear `_writebsr`
before setting `_prewrite`, which is incorrect.

Now, `_writebsr` is only set when `_prewrite` is set and thus only
cleared when `writeSwitch` is false.  This matches Table 5.5.

* Fix pre-write for the language card

This is the same issue as the `MMU`, namely that `langcard.ts` would
deactivate writing to the language card if `prewrite` was reset.
However, it is totally possible to reset `prewrite` and leave writing
enabled, as shown my Sather in _Understanding the Apple II_, table
5.4, p. 5-30. See the previous commit for an example.

This change also adds a test for the `LanguageCard` class.
2023-07-08 11:18:38 -07:00
Will Scullin 7a97414e5d
Fix disk format type checks (#176) 2023-01-28 09:06:03 -08:00
Ian Flanigan 4bbfac5a5a
Rename drive number fields/variables/parameters to `driveNo`
Before, the naming of fields, variables, and parameters that took
`DriveNumber` was very inconsistent. This changes them all to
`driveNo`.
2022-09-24 08:53:48 +02:00
Ian Flanigan 51ba03ac28
Split handling of nibble disks and WOZ disks into separate drivers
Before, the `DiskII` object took care of both nibble disks and WOZ
disks at the same time. This made it hard to see which code affected
which disks.

Now, nibble disks are handled by the `NibbleDiskDriver` and WOZ disks
are handled by the `WozDiskDriver`. This separation of code should
lead to easeir testing and, perhaps, faster evolution of disk
handling.

An upcoming change will move the `NibbleDiskDriver` and the
`WozDiskDriver` to separate files.

This passes all tests, compiles, and runs both nibble disks and WOZ
disks.
2022-09-18 21:37:03 +02:00
Ian Flanigan e280c3d7b8
Add 13 sector disk support to `getBinary` (#159)
Before, `getBinary` did not work for 13 sector disks because it
assumed that all tracks had 16 sectors. On top of that, `readSector`
could not decode sectors with 5 and 3 encoding. And finally,
`findSector` couldn't even find sectors with DOS 3.2 address fields.

All of these have been fixed and some tests added to make sure that
they keep working.
2022-09-18 06:40:08 -07:00
Ian Flanigan 2793c25c9f
Split disk data out into its own record (#158)
* Harmonize drive and disk type hierarchies

Before, the `XXXDrive` and `XXXDisk` type hierarchies were similar,
but not exactly the same. For example, `encoding` and `format` were
missing on some `XXXDisk` types where they existed on the `XXXDrive`
type. This change attempts to bring the hierarchies closer together.

However, the biggest visible consequence is the introduction of the
`FLOPPY_FORMATS` array and its associated `FloppyFormat` type.  This
replaces `NIBBLE_FORMATS` in most places.  A couple of new type guards
for disk formats and disks have been added as well.

All tests pass, everything compiles with no errors, and both WOZ and
nibble format disks load in the emulator.

* Move disk data to a `disk` field in the drive

Before, disk data was mixed in with state about the drive itself (like
track, motor phase, etc.). This made it hard to know exactly what data
was necessary for different image formats.

Now, the disk data is in a `disk` field whose type depends on the
drive type.  This makes responisbility a bit easier.

One oddity, though, is that the `Drive` has metadata _and_ the `Disk`
has metadata.  When a disk is in the drive, these should be `===`, but
when there is no disk in the drive, obviously only the drive metadata
is set.

All tests pass, everything compiles, and both WOZ and nibble disks
work in the emulator (both preact and classic).

* Squash the `Drive` type hierarchy

Before, the type of the drive depended on the type of the disk in the
drive. Thus, `NibbleDrive` contained a `NibbleDisk` and a `WozDrive`
contained a `WozDisk`.  With the extraction of the disk data to a
single field, this type hierarchy makes no sense.  Instead, it
suffices to check the type of the disk.

This change removes the `NibbleDrive` and `WozDrive` types and type
guards, checking the disk type where necessary. This change also
introduces the `NoFloppyDisk` type to represent the lack of a
disk. This allows the drive to have metadata, for one.

All tests pass, everything compiles, and both WOZ and nibble disks
work locally.

* Use more destructuring assignment

Now, more places use constructs like:

```TypeScript
    const { metadata, readOnly, track, head, phase, dirty } = drive;
    return {
        disk: getDiskState(drive.disk),
        metadata: {...metadata},
        readOnly,
        track,
        head,
        phase,
        dirty,
    };
```

* Remove the `Disk` object from the `Drive` object

This change splits out the disk objects into a record parallel to the
drive objects. The idea is that the `Drive` structure becomes a
representation of the state of the drive that is separate from the
disk image actually in the drive. This helps in an upcoming
refactoring.

This also changes the default empty disks to be writable. While odd,
the write protect switch should be in the "off" position since there
is no disk pressing on it.

Finally, `insertDisk` now resets the head position to 0 since there is
no way of preserving the head position across disks. (Even in the real
world, the motor-off delay plus spindle spin-down would make it
impossible to know the disk head position with any accuracy.)
2022-09-17 06:41:35 -07:00
Ian Flanigan 41e0609f55
Floppy controller refactorings 1 (#155)
* Add `DiskMetada` to the `Disk` interface

Before, metadata about the image, such as name, side, etc. was mixed
in with actual disk image information.  This change breaks that
information into a separate structure called `DiskMetadata`.
Currently, the only two fields are `name` and `side`, but the idea is
that more fields could be added as necessary, like a description, a
scan of the disk or label, etc.  In a follow-on change, the default
write-protection status will come from the metadata as well.

The current implementation copies the metadata when saving/restoring
state, loading disk images, etc.  In the future, the metadata should
passed around until the format is required to change (like saving one
disk image format as another).  Likewise, in the future, in may be
desirable to be able to override the disk image metadata with
user-supplied metadata.  This could be use, for example, to
temporarily add or remove write-protection from a disk image.

All existing tests pass and the emulator builds with no errors.

* Rename `writeMode` to `q7`

Before, nibble disk emulation used the `writeMode` field to keep track
of whether the drive should be read from or written to, but the WOZ
emulation used `q7` to keep track of the same state.

This change renames `writeMode` to `q7` because it more accurately
reflects the state of the Disk II controller as specified in the
manuals, DOS source, and, especially, _Understanding the Apple //e_ by
Jim Sather.

* Remove the coil state

Before, `q` captured the state of the coils.  But it was never read.
This change just deletes it.

* Use the bootstrap and sequencer ROMs with indirection

Before, the contents of the bootstrap ROM and sequencer ROM were set
directly on fields of the controller.  These were not saved or
restored with the state in `getState` and `setState`.  (It would have
been very space inefficient if they had).

Now, these ROMs are used from constants indexed by the number of
sectors the card supports.  This, in turn, means that if the number of
sectors is saved with the state, it can be easily restored.

* Split out the Disk II controller state

This change factors the emulated hardware state into a separate
structure in the Disk II controller.  The idea is that this hardware
state will be able to be shared with the WOZ and nibble disk code
instead of sharing _all_ of the controller state (like callbacks and
so forth).

* Factor out disk insertion

Before, several places in the code essentially inserted a new disk
image into the drive, which similar—but not always exactly the
same—code.  Now there is an `insertDisk` method that is responsible
for inserting a new `FloppyDisk`.

All tests pass, everything compiles, manually tested nibble disks and
WOZ disks.
2022-08-31 18:55:01 -07:00
Ian Flanigan 5e224006e4
Make `DiskII.drives` a `Record` instead of an array (#154)
Before, the `drives` field was an `array[0..1]` of `Drive`, but all of
the methods took a `DriveNumber`, which was `[1..2]`.  This meant that
code everywhere was always subtracting 1 from the drive number.

Now, `drives` is a `Record<DriveNumber, Drive>`, which means tha it
has indexes `1, 2` and there's no need to subtract 1 everywhere.

This change updates the `DiskII` class and its tests.

The motivation for this change is to slowly split the WOZ disk
implementation from the nibble disk implementation.  I've tried twice,
but the change has always grown too big and hairy, so I'm starting
very small this time and working my way up.
2022-08-31 09:06:38 -07:00
Will Scullin e414f8d105
Debugger disk info groundwork (#145) 2022-07-23 12:00:38 -07:00
Will Scullin c0ff1e8129
More debugger panels (#141) 2022-07-13 20:34:50 -07:00
Ian Flanigan d67f3d8086
Applesoft compiler fixes (#98)
* Add tests for Applesoft compiler in preparation for refactoring

While refactoring the compiler, I found several small bugs:

*   Lower-case letters in strings and REM statements were converted
    to upper-case.
*   Lines are stored in the order received, not sorted by line number.
*   Does not prefer `ATN` to `AT`.
*   Does not prefer `TO` to `AT`.
*   `DATA` statements don't preserve spaces.
*   `DATA` statements don't preserve lowercase.

These will be fixed in the upcoming refactoring.

* Refactor the Applesoft Compiler

Before, the compiler had a few bugs that were not trivial to solve
because the implementation was in one heavily-nested function.

In this refactoring of the compiler, things like tokenization have
been split into separate methods which makes them a bit easier to
understand.

This refactoring also passes all of the tests.

* Set `PRGEND` when compiling to memory

Before, `PRGEND` was not adjusted which made round-tripping from
the Applesoft compiler to the decompiler not work.  This change
now updates `PRGEND` with the end-of-program + 2 bytes which seems
to be the most frequent value that I have observed.

* Fix two compiler bugs

In debugging the decompiler, I noticed two bugs in the compiler:
*   The first character after a line number was skipped.
*   `?` was not accepted as a shortcut for `PRINT`.

This change fixes these two problems and adds tests.

* Ignore spaces more aggressively

It turns out that Applesoft happily accepts 'T H E N' for `THEN`
but the parser did not. This change fixes that and adds tests for
some odd cases.

Interestingly, this means that there are some valid statements
that Applesoft can never parse correctly because it is greedy
and ignores (most) spaces. For example, `NOT RACE` will always
parse as `NOTRACE` even though `NOT RACE` is a valid expression.

* Move tokens into a separate file

Because the token lists are just maps in opposite directions, put
them in the same file. In the future, maybe we can build one
automatically.

* Fix `apple2.ts`

I had neglected to actually update `apple2.ts` to use the new
compiler and decompiler. They now do.

Also, the decompiler can be created from `Memory`. It assumes,
though, that the zero page pointers to the start and end of the
program are correct.

* Address comments

*   No more `as const` for tokens.
*   Extracted zero page constants to their own file.

Co-authored-by: Will Scullin <scullin@scullin.com>
2022-06-23 20:41:45 -07:00
Ian Flanigan 7e41c69366
Add a basic write test for WOZ images (#138)
* Add a basic write test for WOZ images

The new test just tries to change some random nibbles at the beginning
of the image and then verifies that the change has been recorded.
This exposed a bug where `q7` was never set to `true` when write mode
was toggled on.

Also, the assumptions and limitations of `moveHead` are more clearly
documented.

* Address comments

* Improved `moveHead` documentation a bit more.
* Removed redundant variable in `readNibble`.
* Refactored `findSector` and commented out the chatty log line.

All tests pass. No lint warnings.
2022-06-23 06:38:36 -07:00
Will Scullin f283dae7e1
2IMG Download support. (#137)
* 2IMG Download support.

* Use string encoder/decoder
2022-06-21 20:34:19 -07:00
Ian Flanigan 99ba052597
Add tests for WOZ disks (#136)
* Add a test for the dirty callback on writes

This new test just checks that a clean disk becomes dirty after a
write _and_ that the dirty callback is fired.

* Add tests for WOZ disks

The new tests verify the basic read behavior of the state sequencer on
well-behaved disks, including sync bytes and so on.  Write tests are
still to come.

There's also a change to the Woz format to return the info chunk data
as well.
2022-06-19 19:52:06 -07:00
Will Scullin 466a7eed78
Cheap and cheerful debugger (#135)
* Cheap and cheerful debugger

* Try to manage focus
2022-06-19 19:42:34 -07:00
Ian Flanigan 5b5655b70e
Add tests for the Disk II card (#133)
* Add tests for the DiskII card

This change adds basic read tests for nibble-based disks for the
DiskII card and fixes a few minor errors.

These tests are in preparation for refactoring.

* Add write tests

These are some basic tests of writing to nibble disks.  In the process,
one minor bug was found, fixed and documented.

* Fix the write tests

I misinterpreted something from Sather and thought that the high bit
had to be set on the data for writing to happen at all.  This is not
true.  Instead, there is a flux transition every time the high bit is
set as the data is left-shifted out of the data register.  The
erroneous test has been removed.

At the same time, I finally understand what `skip` does and documented
that.

* Add tests for saving and restoring Disk II state

These are not exhaustive tests, but they ensure that some basic state
is saved and restored.
2022-06-18 16:54:33 -07:00
Ian Flanigan c9b7987c4c
Fix 2mg header parsing and add tests (#127)
Before, the offset for `FLAGS` in `2mg.ts` was `0x0A`, which is
incorrect according to the spec at:

https://apple2.org.za/gswv/a2zine/Docs/DiskImage_2MG_Info.txt

Now, all of the fields in the 2mg header are described, including
their lengths and any constraints.  These constraints are enforced by
`read2MGHeader` and tested by new tests.
2022-06-06 18:10:06 -07:00
Ian Flanigan 04ae0327c2
Add the recommended eslint plugins for TypeScript (#121)
This adds both the recommended TypeScript checks, plus the recommended
TypeScript checks that require type checking.  This latter addition
means that eslint essentially has to compile all of the TypeScript in
the project, causing it to be slower. This isn't much of a problem in
VS Code because there's a lot of caching being done, but it's clearly
slower when run on the commandline.

All of the errors are either fixed or suppressed.  Some errors are
suppressed because fixing them would be too laborious for the little
value gained.

The eslint config is also slightly refactored to separate the strictly
TypeScript checks from the JavaScript checks.
2022-05-31 08:38:40 -07:00
Will Scullin d4db26574d
Jest lint (#118)
* Jest lint

* Feedback
2022-05-30 09:29:48 -07:00
Will Scullin 2bd7fa59b7
Enforce strict equality (#115) 2022-05-18 08:19:45 -07:00
Will Scullin 4a188a9a5c
Preact UI (#106)
First pass at a Preact UI, still short some major features but full proof of concept.
2022-05-10 06:52:06 -07:00
Will Scullin badc2fdb74
Support Tom Harte test suite (#88)
A test data set was published at https://github.com/TomHarte/ProcessorTests which contain cycle traces of instructions for various versions of the 6502.

This adds a test harness that reads those data files, and adjusts the CPU6502 behavior to match the behavior of the vanilla and WDC 65C02 test data.

Also converts the existing CPU tests to Typescript, and fixes any inconsistencies that came up from the new behaviors.
2021-10-13 09:15:29 -07:00
Will Scullin 2daef8040f
Keep track of disk sides (#87)
Disk side information was being dropped and thus not displayable in the UI. This plumbs the value through various formats and adds some light testing.

Also fixes an issue where URL encoded hashes were not properly interpreted.
2021-10-02 11:45:09 -07:00
Will Scullin 52f9c3e99e
jest 27 2021-10-02 07:21:37 -07:00
Will Scullin f4b0100c98
touchups 2021-07-11 15:18:18 -07:00
Will Scullin 044e28e050
Woz to TypeScript (#84)
Woz to TypeScript, with tests added before conversion.
2021-07-09 17:54:27 -07:00
Will Scullin ce3631f3a2
Refactor disk parsing into webworker (#83)
* Refactor disk handling to allow disk processing to happen in a worker
* Type cleanup
* Convert format handlers to TypeScript
* Convert CFFA to TypeScript
2021-07-06 17:04:02 -07:00
Will Scullin 8087294456
Lazy load ROMs (#81)
* Switch modules to `esnext` to allow `webpack` to see import statements
* Pass rom names into Apple2 class
* Move ROMs into `system` and `character` directories to allow webpack bundle appropriate ROMs.
* Wait for ROMs to load before completing initialization.
2021-06-13 17:06:16 -07:00
Will Scullin af57378852
Videomode refactor 2 (#80)
Remove globals from video implementations to allow further refactoring. Experiment with testing video modes.
2021-05-25 12:08:10 -07:00
Will Scullin 09c6d6fbb1
Options modal (#75)
Refactor Options modal, webgl scanline, restore `Apple2.apple2`, other minor fixes.
2021-04-20 17:42:32 -07:00
Will Scullin afa33a4710
fix test 2021-03-13 16:54:09 -08:00
Will Scullin bb09a1ec33
Improve debug performance, abstract debugger. (#61)
Stop stringifying opcodes during runtime and only do so upon inspection. Moves all the debugging logic to a common place to allow building an interface.
2021-03-11 22:03:05 -08:00
Will Scullin afc5280ac2
Flesh out some state stuff (#59)
Get save and restore state limping along to nearly as well as before I refactored and broke everything.
2021-02-27 19:17:36 -08:00
Will Scullin 8ddb17202b
fix test typing 2021-02-07 21:54:11 -08:00
Ian Flanigan dc13b6a59a
DOS 13-sector tests and fixes (#53)
Like the DOS 3.3 and ProDOS sector order issues, this change fixes the
physical order of the sectors on 13-sector disks when nibblized.

This change also adds tests for the 13-sector format to verify the
sector order.

One of the crazy things is that _Beneath Apple DOS_ failed me in this
instance because it doesn't discuss what happens to the last byte in
"5 and 3" encoding anywhere (AFAICT). I went back to the DOS 3.1
source released by the Computer History Museum here:

    https://computerhistory.org/blog/apple-ii-dos-source-code/

The code is in `appdos31.lst` in the `POSTNIB` routine on line 4777.
2021-01-03 15:01:30 -08:00
Ian Flanigan 715ea6ffaa
ProDOS image format tests and fixes (#51)
Like the DOS 3.3 sector order issues in #49, this change fixes the
order of the physical sectors on the ProDOS disk when nibblized.

This change also adds tests similar to the DOS 3.3 tests to verify the
sector order.

Because the DOS 3.3 and ProDOS tests are so similar, the utility
methods have been refactored into their own file.
2021-01-03 14:59:42 -08:00
Ian Flanigan 72ecce113a
DOS 3.3 image format tests and fixes (#49)
* Adds an initial test for DOS format (.do) files

* Fix physical sector order when nibblizing DOS 3.3 ordered images

Before, when `.dsk` or `.do` images were nibblized, the resulting
track had the sectors in the wrong physical layout.

Now the nibblized track has the correct physical layout (all sectors
in order) which results in the correct DOS 3.3 layout as well.

There is also a test that verifies the order.

* Add another test for a non-zero sector

The new test checks that the values in physical sector 1 are those for
DOS sector 7.

* Add test for all physical sectors on all tracks

This change also removes a few stray console.log calls in the test.
2020-12-29 06:40:40 -08:00
Will Scullin 1e58e2c1b8
lint 2020-11-24 08:53:43 -08:00
Ian Flanigan b80436d99c
More typescript conversion (#46)
* Convert js/ram to a class

* Convert js/mmu to Typescript

* Convert js/apple2io to Typescript

* Convert js/canvas to Typescript

* Use new types in js/mmu

* Rename js/symbols.js to js/symbols.ts

* Remove the difference between readPages and writePages

As @whscullin said in PR #38, there's no need to have both readable
and writable pages since all implementations are currently both. This
change combines them into `Page`. Likewise, `PageHandler` now extends
`Page`.

`Apple2IO` now implements `PageHandler`. This caught a bug where `end`
had been renamed `endend` by mistake.

There are a few other formatting changes as well.

* Convert js/apple2 to Typescript

* Convert js/prefs to Typescript

* Convert all of the ROMs in js/roms to Typescript

Now all of the ROMs are classes that extend the ROM class. There is
some rudamentary checking to make sure that the length of the ROM
matches the declared start and end pages. (This caught what looks to
be an error in roms/apple2e, but it's hard for me to tell.)

The typing also caught an error where the character ROM was being
used for the main ROM for the apple2j version.

* Convert js/roms/cards/* to Typescript

* Convert js/formats/format_utils to Typescript

This change also seems to fix a bug with `.po` image files that
weren't being read correctly.
2020-11-24 08:48:14 -08:00
Will Scullin f600f7c6b4
typescript linting 2020-11-07 16:46:27 -08:00
Ian Flanigan c4df78cf06
Typescript conversion of several files, including js/cpu6502 (#38)
* Convert `js/util.js` to Typescript and add tests

Besides converting `js/util.js` to Typescript, this change also adds
`js/types.ts` that defines common types used in apple2js. Some of
these types, like `byte` and `word` are for information only.

* Convert `js/base64.js` to Typescript

This also adds a new type, `memory`, that is either an array of
numbers, or a Uint8Array.

* Convert `js/ram.js` to Typescript

This change does not convert `RAM` to a class; it just introduces types.

* Basic typing of cpu6502

This is a really rough first pass. There are some problems that can't
be fixed until this is turned into a real class, but at least all of
the function arguments are now typed. This caught a few cases where
extra arguments were being passed in.

* Convert `js/cpu6502` to a class

In theory, idiomatic classes should be better than the previous
closure-based classes. However, this conversion shows that the
instruction table does not fit well with idiomatic classes as method
referenced in the table need to be called with the correct `this`
everywhere.

This should, at best, be considered a first attempt.
2020-11-01 08:43:48 -08:00