E01 vs E01S
Version notes are given in reverse chronological order.|
Until the emulator is operational, all versions will be 0.00 - use the date as a reference.
FileStore versions log
Added initialise routine to FDC.
CHANGED LICENCE TO (open source) EUPL.
Please refer to the included eupl_v1-1_en.pdf.
FDC em now does the type I commands, plus poll
routines for follow-through.
As far as I can see, the current log is:
FDC change: Test=No, MRst=No, DDen=Yes; FDC1=Yes,
FDC read : 0 <- 0 [Status/Command]
FDC write : 80 -> 1 [Track]
FDC read : 80 <- 1 [Track]
FDC write : 0 -> 3 [Data]
FDC read : 0 <- 0 [Status/Command]
Network IRQs disabled [READ]
FDC write : 8 -> 0 [Status/Command] [point **A**]
FDC command type I, params = 8
VIA read : <- 13 [IFR]
VIA read : <- 14 [IER]
Network IRQs disabled [READ]
NET read : <- 0 [CR1/SR1] CanIRQ = No
FDC read : 68 <- 0 [Status/Command]
Network IRQs enabled [READ]
FDC read : 68 <- 0 [Status/Command]
Network IRQs disabled [READ]
go to point [**A**] and repeat a bunch of times.
It does this numerous times on the left drive, then the
right, then it fast-blinks the red LED (error - no disc?).
What I don't get - we write 80 to the track register, read
it back, blank the data register, then "restore" to find
track zero. Um... I'm sorry, shouldn't we like, read a sector
or something? The return code is 68 which is WRITE PROTECT
and TRACK ZERO. Isn't that a good return code?
FDC emulator now recognises commands.
Started work on FDC emulation.
Minor corrections to ROL/ROR for values written back to Acc.
Must remember - CByte() is NOT the same as a byte-wide cast!
PLA flags corrected.
BRK is now, correctly, treated as a two byte instruction.
Bit operations test script written.
Load and save operations test script written.
Comparison operations test script written.
Other-stuff test script written.
All test scripts written. CPU core passes tests.
[now I can start work on other stuff...]
SBC now ought to be correct. Erm... I hope. :-/
Maths test script complete.
Corrected ADC V flag, overflowing a byte sets C, not V.
Made the script parser a little more bulletproof; plus it
better reports where the assert whoopsee occurred.
Corrections to SBC handling of C and V. Surprised? :-)
[still not entirely correct]
Fixed bug in ADC re. adding in 1 for Carry.
0.00 2010/07/18 [daytime]
Fixed bug in resolution of [(ABS,X)] addresses.
Fixed bug in BRK handler.
Fixed bug in Carry Clear / Carry Set in CMP.
0.00 2010/07/18 [early hours]
Validation script system created. I've only written one
script to perform basic tests on flags and registers, and
check all the opcodes are present.
This picked up an error with PLP's opcode number (oops!)
and one of the SBCs too.
More test scripts to be created. My next lot, God help me,
will be to verify the correct functioning of the addressing
The script command format is:
<reg> = X Y A SP PC PS C Z I D B V N
\-- flags --/
All numbers are given in hex, without a prefix.
assert <reg>|m<addr> <cond> <value>
Confirm that a register, or memory location (m prefix)
is or is not a specific value. The condition codes
are '=' (is) or '!' (is not). Flags are 'ff' if set.
assert a = 7f ; check accumulator is 127
assert m0 = 0 ; check memory at &0000 is zero
cont / exec
As an alternative to using the "op" command, especially
with tricky things like conditional branches, you can
poke code directly into memory and then execute it.
Execution starts at &0200.
The difference between "exec" and "cont" is that "exec"
sets up the environment before stepping once, while
"cont" simply steps once.
Thus, to execute three instructions, you could:
It is possible to execute code at other locations by
massaging PC before calling "cont".
Loads a secondary script and begins executing it. The
filename should be a plain name with no quotes and no
path (the path is fixed).
You can only have ONE secondary script at a time. When
this script is complete, execution passed back to the
Note - you CANNOT chain one script from another. To
implement this sort of behaviour, create a "wrapper"
script that loads each of the desired scripts in turn
(look at how I've implemented it).
Zero the address specified. If the address is not
specified, all memory except page &FC will be cleared.
memset <addr> [<value>]
Set the memory at the address given to the value given,
or zero if no value.
Simply displays the rest of the line (so no quotes) to
the user in a messagebox. Clicking OK is required, so
don't overdo it.
op <op> [<param> [<param>]]
Writes all the values given into memory byte by byte,
starting at &0200, then steps the processor to execute
the code. A maximum of three bytes can be given. As
values are given as bytes, take care with the order of
bytes for word values.
op ea ; NOP
op 4c ad de ; JMP &DEAD
regset <reg> [<value>]
Referring to the list above, this allows you to set
the specified register or flag to either the value given
or zero if no value specified.
NOTE: YOU CANNOT SET PS OR PC.
Resets the CPU to sane defaults, then pokes the memory
latch to disable the EPROM.
Here is an example of testing carry flag bahaviour:
regset a 21
op 0a ; = 42
assert c = 0
op 0a ; = 84
assert c = 0
op 0a ; = roll over, 108 but we only see 8
assert a = 8
assert c = ff
[remember, flags that are set are 'ff' and not '1'; think
of it as 'ff' being '-1' (which is exactly what it is!)]
If you look in the source, you may or may not see other
commands and/or options. These should be used with care,
read through the source to understand their effects.
Note that the script interpreter is simple and fairly easy
to break. It is NOT intended as a user function, more a
means to script up and perform repeatable tests.
There's a button in the setup dialogue to invoke the script.
[this will go once things are working, to be replaced with
a command line option]
Closing the setup dialogue now properly quits the emulator.
Fixed bug where SBC set the flags the wrong way around. Now
the code crashes with an undefined instruction at address &79
I'm looking to writing some validation scripts.
I have caught a cold. I feel like crap. This is when I would
"traditionally" put a fair amount of work into this project,
but I have to fit feeling like this around work. Ugh.
*Totally* untested, but if the server writes an error report
to the NVRAM, it should stop at that point and ask if you wish
to cease execution (so you can check out what the error is).
In disassembly, highlights the current instruction in an
In disassembly, pressing F8 may cause the highlight to be
'lost' if you JSR, RTS or something that goes away from what
is currently shown. No worries, pressing ^D will realign the
disassembly to the current instruction.
Note, by current instruction we mean the one that has JUST
Disassembly now has a processor status 'popup'. ^S will
toggle it visible/invisible.
CPU status can now be used to muck with the processor. Note
that changes take effect IMMEDIATELY if you click on a flag,
or when you press [Enter] if changing a register.
Memory dump 'Go' text entry dodah now accepts [Enter] key.
Fixed bug in BIT instruction where it was setting the result
back to front.
Fixed bugette with the memory dump opening 'blank'.
Added F7 as a keypress to mean "Halt". This was chosen as
it is next to F8 (step) and not next to F5 (run). The VB
IDE uses ^Break, but this is not really available for the
technical reason that it'll interrupt the IDE instead! :-)
Added disassembler. It is only part colourised in that
comments are green. Everything else is plain black, with
the instruction in bold type. I did consider a Zap-like
colourisation, but felt it would be overkill.
The disassembler will annotate disassembly from a list of
'known' locations created specifically for each version of
the EPROM. The most detailed is for v1.31 thanks to Johan's
disassembly. This information is read from the "locs####.dat"
file, where the '####' is the EPROM ID in hex.
If no such file exists, then "locsxxxx.dat" will be used,
which is a generic file containing hardware locations.
When in disassembly, you can use Up/Down to move around (up
goes back a byte). PageUp/PageDown for bigger jumping (and
as before PageUp goes back 32 bytes). You can also use F5,
F7, and F8 as in the main window.
All run/halt/singlestep calls indirect through a routine in
frmMain - this saves lots of stupid code dupe. It is a
routine in frmMain and not CPU65C102 because it is mostly
UI stuff and twiddling one global variable...
Added Halt/Run[^Step] to the CPU status window. Also made
the mem dump and disassemble buttons work.
The beginnings of a VIA.
Added Run/Halt/Singe-step, plus a reset option.
Added some hotkeys. The F5/F8 match those used in VB.
Added a picture of me hard at work. :-)
CPU reset now resets the hardware.
Removed spurious unnecessary CPU reset prior to start of
EPROM patches are now applied from the "rompatch.dat" file.
The format of this is:
All values are given in hex.
The ROM ID can be determined from the Development menu.
The length is how many bytes to alter.
The original (in-EPROM) contents of these bytes are summed
to create the check value. If this value does not agree, the
check won't be applied.
Finally, the replacement byte values comma separated. The
results are 'undefined' if the data supplied differs from the
number given previously.
The entire rompatch.dat file is read, so it is possible to
hold multiple patches to the same EPROM image.
Hacked in a compilation option "DEMON". When set to '1', it
will remove the instruction/branch recording, the
disassembly, and logging hardware accesses. In the start-up
test, it only shaved off around half a second... on the other
hand, no clutter from an oversized hardware trace.
Obviously this option is incompatible with others, like the
insane internal trace one.
After getting the crappy memory dump looking as I wanted it,
I ripped out half the code and rewrote it to be a lot more
optimal (namely via a page buffer raw-reading from the RAM
array instead of 512 memory accesses which aren't really
Moving the mouse over the hex data or the ASCII data will show
the byte with a cyan box around it. Double-clicking a byte
that is highlighted will allow you to change that byte.
Added a 'catch' to the CPU status. If you are playing with
memory and you replace code with an incorrect instruction
(such as &028A (I think!?) to a NOP), there is a chance you
will see endless "unknown instruction" messages and never get
a chance to exit. So hold down SHIFT and CTRL when clicking
"OK" and you'll be asked if you wish to abort emulation.
Implemented crappy rough'n'ready memory dump display.
Emulator will no longer about upon unknown instruction and/or
addressing mode - instead it will report the problem and then
open the CPU status window. The eventual aim is to be able to
'update' the CPU status, perhaps to fake the unknown opcode,
but this bit hasn't been implemented yet.
The special check for if running on Aiko (to redirect to the
local server as I don't have Internet at home) has been
extended to cater for Azumi as well in preparedness for the
code/support being copied onto my eeePC901. Don't rely on this
though, as I may rename the computer, I may decide to hold the
live server on Aiko via ethernet... or I may just shoot myself
in the foot with a water pistol. :-0
Better shutdown routine.
FS error report now displays the SIN. I *think* I have the
bytes in the right order. :-)
If the cycle count passes &6FFFFFFF, it will revert back to
zero. This is to prevent "Overflow" errors; this value being
15 minutes and 40 seconds of emulated time.
You might ask why not &7FFFFFFF, the actual point of overflow.
Well, this is to give space for things that schedule in
advance (like the RTC saying "I'll bother you again in a sec"
with "a sec" being 2,000,000 cycles...). We can support advance
scheduling up to two minutes, this ought to be more than enough
for the various possible timeouts.
BBRx/BBSx/RMBx/SMBx will not be supported. These are Rockwell
specific instructions and may well not be present in the E01(S)
firmware. If they are, they'll be added, but...
Fixed TRB/TSB not to screw up the Accumulator. [Tom Walker]
Expanded the 'catch' range in the register contents display to
remove the black-box "undefined character" symbols.
The EPROM joiner should now be considerably more resiliant.
Now updates CPU status window (every 32 instructions). This'll
be more useful when single-stepping is implemented. In that
case, updating an option in the status window will change the
processor's internals (like setting X, Y, A and flags...).
Implemented the basics of a disassembler, you can see this in
the trace of the CPU status.
Implemented TSB and TRB. I don't have information on how these
actually work, other than in the processor datasheet (which
doesn't say much!). So I have guessed. If you know, please give
the TRB/TSB code a thumbs up (or down?)!
Messages appear for the currently unsupported instructions
Added an EPROM version report. This is so you can check which
EPROM image is running, and also so you can see the ROMCHK
without running the code in the IDE. This is because... well,
look at the "locs31f0.dat" file. You can create another called
"locsXXXX.dat" where the X's are the ID. It'll have a tad more
significance in the disassembler, when I have written it. :-)
Added ADLC status form. Not linked yet, but it's a start. Only
had a few minutes (well, about half an hour) before "Evil
Aliens" on Zone Horror. :-)
In between films, added the FS error report lookup. This makes
it easier than eyeballing the NVRAM file in a hex editor.
Basic does-nothing-much implentation of the ADLC, so the
server will believe an ADLC and valid Econet is connected...
...well, that's the idea! Doesn't quite get that far, I think
we need the VIA next?
Rejigged the emulator to operate with a single 64KiB EPROM
image file. To make life easier if you have split files (as
most BBC-based EPROM programmers could only read in 16KiB or
32KiB chunks), you can 'join' either 4×16KiB parts, or 2×32KiB
parts. There's a new button (and associated window) for this.
Those "..." buttons now open the "Open" dialog(ue) so we don't
have to try to remember paths.
Note that *ANY* instance of a reference into the FileStore's
own folder will be replaced with "<AppPath>". This is going to
be used throughout as it makes things much tidier in the
Implemented 'dummy' routines for the ADLC, FDC, HDC, and VIA.
Calls to the hardware will result in output to "hwlog.txt" so
we can see which parts of the devices are being used...
For what it is worth, this is the first version of the emulator
capable of running the firmware until it reaches a state of
sitting doing very little except blinking the Mode LED (i.e. a
sort of 'panic'). The previous version probably was able, but
I didn't let the code run long enough!
[note: this does NOT occur with the v1.40 firmware
as this behaves rather differently]
Implemented the Miscellaneous Functions Latch. That was dead
easy. The array is public scope so it can easily be seen by
the FDC and NVRAM code. It handles the red LED by itself.
Implemented a lot of the NVRAM; and the RTC is totally faked
by reading the values from the host. Note that the first ten
bytes are therefore not used in our implementation (and,
furthermore, attempting to write a new time/date will silently
fail...) so in the "nvram.dat" file, you should NOT attempt to
make any assumptions whatsoever about these bytes.
The ~10 second delay might make sense on a real FileStore, to
allow discs to spin up (etc). In an emulation, it is just
wasting our time; therefore the emulator will patch this delay
loop out of the loaded EPROM image (the original file is NOT
We have built-in support for:
E01 firmware "FileStore 1.31" (C)Acorn 1988
E01S firmware "FileStore 1.33" (C)Acorn 1988
E01S firmware "FileStore 1.40.00" (C)1989 Acorn
For other versions, I'll need a complete EPROM dump. If your
version is not recognised, then no patch will be applied and
you won't be warned about it either...
Fixed bug in PC adjustment of absolute indirect addressing.
Added JMP/JSR to list of opcodes for which NOT to perform a
'hidden' memory read (not for safety as you won't be jumping
to a read-sensitive location, but rather for efficiency as the
read isn't needed).
No read functional changes, just implemented messages for menu
options, and the front flap open/close (purely an effect atm)
for the initial public release. To be honest it is WAAAAAY too
early to release, but I'm hoping to get somebody else on-board
so at least somebody can laugh at my mistakes... before fixing
I think this one might still say it is the 2009/04/15 build?
Patched in some normally-inactive code to load up Johan's E01
EPROM dumps (16KiB bits) and create the expected 32KiB dumps
from them. You might ask why I want to run the E01 firmware on
an E01S emulator. Good question - it's because Johan's partial
disassembly is for his firmware, not the E01S code. It will
help greatly to have the two match up when developing this
NOTE: In the future, it is HIGHLY likely that FileStore will
operate with a single 64KiB EPROM image, and there will
be some sort of utility provided to 'join' smaller images
into a full-sized dump.
You might also notice that we are using the Wiki-recommended
"Kikibyte" terminology. This is apparently because some
dickhead decided that KILObyte should be used to refer to 1000
byte units (which is logically correct) DESPITE the fact that
programmers have been using that phrase to refer to 1024 byte
units since the dawn of Unixtime (or 1970). It all started when
harddisc manufacturers AGES ago switched to using decimal maths
for their products in order to make them seem larger. A test
case in the US failed on account of it being the "industry
standard" way of describing storage capacity, which is bollocks
for numerous reasons, namely:
1. A 1Mb capacity floppy disc can hold 1Mb of data (which is
usually anything between 640Kb and 800Kb depending on how
much is lost to formatting and soft-sectoring).
2. Onto a 700Mb CD-R, I can actually fit 703Mb. If it was
decimal Mb, you'd only be able to fit on ~668Mb.
3. Funny, using the various lookup schemes implemented on
harddiscs for addressing, they are all quite well aware
of non-decimal units. The default (PC-like) scheme is for
a sector of 512 units of 8 bit bytes. Why does a harddisc
not provide 500 units of 10 bit bytes if they are so hung
up on being decimal?
It's all sales and marketing cons, which is why my 250Gb
harddisc actually holds around 235Gb, and a pack of DVD-Rs
claiming 4.7Gb actually holds exactly 4488Mb (but in my own
copy-over I aim for around 4.35 as anything more seems likely
to spill over, housekeeping/filesystem must be somewhat
Anyway, a "KiB" is a "kibibyte" which is units of 1024 bytes;
what us old-timers have been calling "Ks" and "kilobytes" for
Implemented EPROM/RAM selection so it can switch to execution
from RAM after initial copy.
Fixed BRx instructions, the method of creating a signed value
was totally bogus so I simply recoded it all.
Added in TRACE and TRACEMORE macros to permit the CPUcore to
be traced in operation. It will, later, be converted into
something to allow... well, just look in the CPU window!
Fixed bug in SBC, when CARRY you don't subtract one but when
no Carry you do? Surely this means you must SEC before every
SBC? Why doesn't the 65C02 have a plain 'SUB' that does a plain
Fixed stupid bug in INC/DEC where you can use accumulator
addressing. This is new to the CMOS and I missed it. Sorry.
Added code (or a kludge, if you prefer!) to the PreFetch. You
see, the CPUcore works out the addressing mode and sets up two
'secret' registers with the effective address and/or the data
to be acted upon. This is, I believe, a mite slower but a lot
more code-optimal than having each opcode do its own work; it
also means that we can group opcodes together (i.e. ALL of the
LDAs do pretty much the same thing in the same way...).
HOWEVER, if we are WRITING to &FC08 to poke on the red LED, we
sure as hell don't want to do a 'hidden' READ on that address
as doing so will flip the EPROM/RAM latch to RAM-only and then
it all goes tits waving in the air and you're scratching your
head trying to work out why it's all total gibberish.
Added a manky kludge to turn on the red LED. We don't need the
rest of our Misc. Func. Latch yet, and having the red LED light
up means we've successfully executed THREE instructions. :-)
Lots of GUI stuff added, inc. the cute main window.
CPU core believed to be mostly correct except for undefined
ops, some CMOS-specific ops, and BCD. I'll need to look up
what/how BBRx/BBSx/TSBx (etc) actually operate.
Emulator now capable of loading an EPROM image to begin to
Project coding started after a bunch of R&D. :-)