Code Monkey home page Code Monkey logo

msemu's Introduction

MailStation EMUlator

This emulator is still obviously in early stages, but so far it seems to be capable of running the Mailstation OS for its core functionality. The actual emulation is handled by the z80ex library.

A ROM image of the Mailstation codeflash, the main firmware, is required. By default, msemu looks for ./codeflash.bin, or the path can be specified on the command line. This can be used to switch between firmware versions or run custom code.

Functionality has really only been tested with DET1 models, firmware up to and 3.03A. It would be interesting to see what happens with other firmware versions.

Additionally, the Mailstation has a dataflash ROM inside. While not exactly required by msemu, an image is still needed. A real image can be used, or msemu can generate a blank one which the Mailstation firmware will initialize it for use. By default, this file is ./dataflash.bin if the path is not otherwise specified.

Once the Mailstation firmware is fully booted, it can be interacted with through the keyboard as on real hardware. Some keys are remapped. See below for key mappings in msemu.

There is also a very rudimentary interactive debugger implemented. This allows for setting a breakpoint on a specific PC address, single stepping (which also shows the current opcode and any IO or MEM accesses), and changing the current terminal verbosity output. More information about this is below.

Keyboard Mappings and Control

Mappings

F12     - Mailstation Power button
L_CTRL  - Function/Fn
Home    - Main
End     - Back
Insert  - Print
F1      - F1 (leftmost grey key underneath the LCD screen)
F2      - F2
F3      - F3
F4      - F4
F5      - F5 (rightmost grey key underneath the LCD screen)
F6      - @
F7      - Size
F8      - Check Spelling
F9      - Get E-Mail

Control

The graphical window has a couple of control keys:

ESC       - Exits the emulator (this is a normal method of shutdown)
R_CTRL+R  - Force emulator reset; Z80 resets to PC 0x0000

Debugger

The 'msemu' contains an interactive debugger. Be warned, its operation is very rough. Once 'msemu' is started, ctrl+c can be pressed on the terminal window, not the graphical LCD window, to break execution and issue a few simple commands. It allows for a single breakpoint to be set when the PC reaches the specified value.

Available commands:
f - Force debug printing o[F]f during exec
o - Force debug printing [O]n during exec
e - [E]xamine current registers
b - Set a [B]reakpoint on PC, 'b <PC>', -1 to disable
l - [L]ist the current breakpoint
h - Display this [H]elp menu
s - [S]ingle step execution
c - [C]ontinue execution
q - [Q]uit emulation and exit completely

Note that 'q' will exit the emulator the same as pressing ESC on the graphical window.

Currently Known Shortcomings

Things NOT emulated:

  • The modem.
  • The parallel port.
  • Variable CPU speed
  • Variable timer/interrupt speeds
  • Writing to the real-time clock
  • Standard INT handling

Developer Quick Start

Prerequisites

  • cmake 3.7+
  • libz80ex, SDL 2, SDL-image 2, and SDL-ttf 2
    • (Linux) Install via your package manager
    • (Windows) Run ./external/Download-Deps.ps1 to install these.
  • (Windows) Visual Studio 2019 or Build Tools for Visual Studio 2019 (other versions of VS may work, but are not tested)

Building

Create a build directory, run cmake, and build:

mkdir build
cd build
cmake ..
cmake --build .

By default, cmake will configure the Debug configuration. Other options are Release, MinSizeRel, and RelWithDebInfo. These can be set like so:

cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..

Running

The application can be started from the build directory with:

./src/msemu -c /path/to/codeflash.bin -d /path/to/dataflash.bin

If not provided, msemu will attempt to open ./codeflash.bin and ./dataflash.bin As noted above, codeflash.bin is required for execution as this is the main firmware ROM. If dataflash.bin is not provided, ./dataflash.bin will be created and populated.

History

This work was originally pioneered by and would not have existed without the effort put in by Fyberoptic. A huge thanks to Fyberoptic for letting development of this continue nearly a decade after it was originally started. The first major public release of msemu, marked rev 0.1a, was dated 2010/01/05. Original work unlicensed, licensed with permission. Splashscreen font by codeman38.

msemu's People

Contributors

captainnic avatar fryday avatar kbembedded avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

msemu's Issues

Fully emulate all Mailstation keys

Some keys are not currently emulated properly. These need to be assigned a key for completeness.

I think the only ones not emulated are:
Get E-Mail
"@"
Print

Support different operating frequencies

The Mailstation can supposedly run at a few different clock frequencies. Currently msemu is hardcoded to 12 MHz.

This should be achievable by adjusting the amount of T states between NMI checks as well as delaying for different periods of time before/after an NMI is issued since the real-time gating is done by gating when the NMIs happen which is based on a timer.

Support DET-1B (and other?) LCD devices

I think some of the models had different LCD layouts?

Yes, the DET-1B hardware uses a different LCD so it has a different layout. At some point, would be nice to be able to emulate other hardware. There is a clear FW version difference, e.g. 4.x is used on the DET-1B hardware, so that could be something we could guess at and/or add cmdline options to force.

Originally posted by @kbembedded in #57 (comment)

May be a good idea to extract the LCD implementation into a separate place at first, then implement the other lcd devices against the same interface. Then the lcd device could be selected via some configuration when creating the msemu context.

Support newer SDL releases

Currently, this is all built around and requires SDL 1.2. Its an old release and bumping up to the latest might afford some better features in SDL. Dunno.

Option to prevent writing dataflash binary

In some testing cases it would be nice to keep the dataflash on disk untouched once its loaded and let msemu only modify the buffer. For example, in the Mailstation test menu, the dataflash test will completely wipe the dataflash.

Probably depends on #22 first.

Missing Symbols

nico@nico-debian:~/projects/msemu$ cd src/z80em
nico@nico-debian:~/projects/msemu/src/z80em$ make

# ... blah blah blah ...

nico@nico-debian:~/projects/msemu/src/z80em$ cd ..
nico@nico-debian:~/projects/msemu/src$ make
gcc -Os -Wall -DLSB_FIRST -DX86_ASM -DDEBUG -c msemu.c -o msemu.o
In file included from msemu.c:17:0:
flashops.h:10:13: warning: inline function ‘readDataflash’ declared but never defined
 inline byte readDataflash(unsigned int translated_addr);
             ^~~~~~~~~~~~~
flashops.h:9:13: warning: inline function ‘writeCodeFlash’ declared but never defined
 inline void writeCodeFlash(uint32_t translated_addr);
             ^~~~~~~~~~~~~~
flashops.h:8:16: warning: inline function ‘readCodeFlash’ declared but never defined
 inline uint8_t readCodeFlash(uint32_t translated_addr);
                ^~~~~~~~~~~~~
gcc -Os -Wall -DLSB_FIRST -DX86_ASM -DDEBUG -c flashops.c -o flashops.o
gcc -Os -Wall -DLSB_FIRST -DX86_ASM -DDEBUG z80em/Z80.o z80em/Z80Debug.o flashops.o  msemu.o  -o msemu  -lSDLmain  -lSDL  -lSDL_gfx 
msemu.o: In function `Z80_RDMEM':
msemu.c:(.text+0x5ed): undefined reference to `readCodeFlash'
msemu.c:(.text+0x647): undefined reference to `readDataflash'
collect2: error: ld returned 1 exit status
makefile:24: recipe for target 'msemu.exe' failed
make: *** [msemu.exe] Error 1

Unable to power on, off, and back on again

This previously worked, probably broke something when overhauling the mem access.

When the emulation is turned off by pressing F12, it will not turn back on again, nor will the emulation properly exit when esc is pressed.

Fix "double press" of F12 to turn of msemu.

power_button value cycles properly here:
https://github.com/kbembedded/msemu/blob/master/src/msemu.c#L980-L994

but does not directly trigger the power off event (write 0x01 to port 0x28):
https://github.com/kbembedded/msemu/blob/master/src/msemu.c#L557-L564

My next thought was that maybe IO READ on port 0x09 was related:
https://github.com/kbembedded/msemu/blob/master/src/msemu.c#L439-L441

but that port always reads back 0x0F, so it doesn't seem to be responsible for triggering the write to IO 0x28.

Next step would be to inspect and potentially disassemble the binary to see if the double press is a software feature to avoid accidental power off or something.

Originally posted by @CaptainNic in #14 (comment)

Enable per-device debug output

Currently all device access is output via log_debug(). Separate it out so individual device access can be monitored when debugging.

Probably going to be a pain in the ass to implement with the current debugging setup and would require a rewrite.

Key parsing is slow compared to real mailstation

Not sure the source of this. In the internal testing menu it can be very readily seen.

  1. Press Shift+Function+t (LCtrl+Shift+t on msemu)
  2. Power unit on while holding above buttons
  3. Press '3' to enter "F/A Test"
  4. Press '3' to enter "Keyboard Test"
  5. At a reasonable pace, slide finger across a row of keys and see that a lot of them are missed. Real MS picks them up better.

This is likely due to how often SDL key events are checked, not sure.

EDIT: Added step

Optimize LCD drawing

(This might benefit from #20 and #23?_

There is still sometimes lag when drawing to screen. I believe the LCD buffer is transferred to the SDL window 20 ms AFTER the last write to the LCD buffer, rather than at a constant rate. This may also be able to be optimized in other ways but I don't know enough about SDL.

Emulate parallel port

A large part of the interaction of this device comes from the parallel port. Without it, its not easy to load code.

Emulation of the parallel port means a lot of testing can happen in the emulator that currently would require real hardware.

Not sure how to best handle this however. Named pipe maybe? The emulator can handle the port bit shuffling, just need a quick and easy way to get data in and out. Named pipe might not be the best since it will block.

Optimize execution

(This might benefit from first addressing #20?)

Currently, execution is gated to real-time by doing execution steps. Execute a number of T states that would occur in the 64 Hz window between NMIs being issued. Once the number of T states is met or exceeded, check to see if the NMI should be called. After NMI is called, wait 15 ms before calling the next execution step. This 15 ms is handled by SDL ticks and probably ends up taking longer than that due to timing.

Not really sure what can be done about this, once everything is more stable it might be worth running some tests on various ways to gate the execution more closely to real time.

Expand log options

In #35 (comment) it was suggested to expand logging capabilities to have different layers.

e.g.
log_debug() would be very very verbose
log_trace() would only log/display opcodes executed, still noisy
log_warn() to log warnable things (not sure what would fall here)
log_info() to always output/log, similar to error but not actually an error
log_error() to log critical errors that happen

Reduce dataflash writes to disk

Currently, when the dataflash buffer is updated, a flag is set. If this flag is set then the whole dataflash buffer gets written back to disk after the next NMI.

This can lead to heavy disk thrashing on SSDs if the whole dataflash is written. It's a rather rare occurrence, however.

Open to ideas, but I think the best strategy might be to write the whole buffer back to disk on emulator exit. This can pretty much only be done by pressing ESC on the visual window, (ctrl+c is caught with the interactive debugger), which is accounted for in the main loop.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.