A high level emulator for the TS-7200 Single Board Computer, as used in CS 452 - Real Time Operating Systems at the University of Waterloo.
Choo Choo! 🚂
The primary purpose of this emulator is to enable rapid prototyping and development of the CS 452 kernel without having to literally live in the Trains lab. That said, at the end of the day, you won't be marked on how well your kernel runs in this emulator, you'll be marked on how well your kernel runs on the actual hardware in the trains lab!
We make no guarantees about the accuracy and/or stability of this emulator! Use it at your own risk!
- Instruction timings and hardware access times are waaay off, so any profiling/benchmarking performed in the emulator won't be representative of the real hardware whatsoever!
- Emulated UARTs are can be quite forgiving when it comes to sending / receiving data. Namely, the CTS behavior is not representative of actual hardware.
If you find any bugs, please file an issue! Even better, if you happen to spot and fix a bug yourself, please consider upstreaming any improvements!
ts7200
is written in Rust, and uses the standard Rust package manager (cargo
) for building / installation. If you don't have Rust installed, you can install it via rustup
.
You can install ts7200
to your $PATH
by running the following command:
cargo install --path .
Alternatively, if you simply want to try-out the emulator, you can build and run it without adding it to you $PATH
:
cargo run --release -- [FLAGS] [OPTIONS] <kernel-elf>
Run ts7200 --help
for information on how to use the emulator.
Make sure to redirect the emulator's stderr
to a file / tty!
By default, the emulator puts the tty into "raw" mode (as part of the --uart2 default config). This clashes with the logging info being sent over stderr
, and the two end up intertwining and "smearing" across the terminal.
This can be avoided by redirecting ts7200
's stderr
to a separate tty:
- open a new terminal window
- run the
tty
command to get it's corresponding tty device - redirect the output when running ts7200:
ts7200 [...] 2> /dev/pts/X
There are quite a few features present in the emulator which are not available on actual hardware:
- GDB Debugging across context switches!
- The GDB server is part of the emulator itself (as opposed to running within the emulated hardware), which means it can provide "true" instruction-level step-by-step debugging of your code.
- To start a debugging session, pass the
-g
flag tots7200
, and use the GDB commandtarget remote localhost:<port>
to connect to the GDB server.
- Emulated devices emit
ContractViolation
errors if they are accessed "incorrectly", instead of silently-failing as they would on real hardware. Keep an eye on thosestderr
logs!- e.g: Accessing Uninitialized RAM logs a warning to stderr
- e.g: Trying to enable a timer without giving it an initial value throws a fatal error
- (optional) Add a virtual UART3 device mapped at 0x808e_0000 (using the
--hack-uart3-enable
flag)- When used in conjunction with
--hack-nodelay-uart-tx
and--hack-uart3=file:/dev/pts/X
, a virtual UART3 can be a useful non-intrusive (unlike GDB, which "stops the world") debugging tool! - Just Remember: The TS-7200 only has 2 UARTs, and trying to access UART3 on actual hardware will result in undefined behavior! This virtual UART3 is NOT the same UART3 as the one specified in the EP93xx user's guide! UART3 is just a clone of UART2 with different VIC interrupts.
- When used in conjunction with
- Instead of zeroing-out RAM, uninitialized RAM is set to the ASCII value corresponding to '-' (i.e: decimal 45, hex 0x2d). This, along with the uninitialized RAM logs, makes it easier to spot any uninitialized memory issues in your code.
- While most keycodes are forwarded directly to the emulated code,
Ctrl-C
is "hijacked" withints7200
to early-terminate the emulator. If your Kernel usesCtrl-C
for any functionality, you may need to tweak eitherts7200
or your kernel's source.- This could be fixed by implemented a "leader-key" system, similar to tmux. PRs welcome!
- GDB Debugging "breaks" in the presence of Timer interrupts
- Trying to step to the next instruction will most-likely result in GDB jumping to the IRQ handler instead
- This can be worked-around by avoiding the
n
ands
GDB commands when debugging code with IRQs, and instead setting specific breakpoints viab
to "step" through the code. - Note: It should be possible to fix this by artificially disabling interrupts when single-stepping in the GDB implementation. A PR to implement this functionality would be much appreciated!
At the moment, the majority of devices critical for running basic CS 452 kernels have been implemented and tested. That said, there are plenty of devices that could still be added and/or improved further. PRs are more than welcome!
NOTE: This is a non-exhaustive list of the project's status. There are also a plethora of TODOs, FIXMEs, XXXs, and stubs littered throughout the codebase, which provide an informal overview of subtle bits of missing and/or flat out wrong functionality.
- Core features
- HLE boot (emulating CS 452's Redboot configuration)
- ELF file parsing
- Initializes devices / key memory locations with hardware-validated values
- Debugging with GDB
- HLE boot (emulating CS 452's Redboot configuration)
- Devices
- UARTs - Implemented, but too forgiving!
- Real UART hardware can be quite finicky, especially when interacting with the Marklin train controller. Things that work fine on the emulator may not work on actual hardware!
- RX/TX Flags
- CTS flag (inaccurate: always set to
1
whenever UART isn't transmitting) - All "important" registers (for CS 452)
- Interrupts
- Timers - Totally Accurate!
- Note: Timer 4, the 47 bit debug timer, is not currently implemented.
- All Documented Register Functionality
- Interrupts
- VIC - Mostly Accurate
- Asserts and Clears Interrupts
- Correct daisy-chaining behavior
- Vectored Interrupt Support (caution: not very well tested)
- Reading from the VectAddr register doesn't actually mask out interrupts until you write to it
- Protection bit can be accessed from any mode (not just privileged modes)
- System Controller (Syscon) - Only the Important Parts
- Note: Lot of stuff in the Syscon isn't relevant to CS 452, and will be left unimplemented
- Correct handling of SW Locked Registers
- Low Power Halt
- Low Power Standby
- The two 32bit scratch registers (just for fun lol)
- RTC
- Co-Processor Functionality
- Note:
arm7tdmi-rs
doesn't currently expose a configurable coprocessor interface. Instead, any coprocessor operations are simply logged, and treated as no-ops. Untilarm7tdmi-rs
adds support for custom coprocessors, the following devices cannot be emulated correctly: - MMU
- Caches
- MaverickCrunch Co-Processor (i.e: math coprocessor)
- Note:
- UARTs - Implemented, but too forgiving!
- LLE emulation of all TS-7200 hardware (e.g: to support "cold boots" directly into Redboot)
- Most of the devices on the board aren't used by the CS 452 kernel, so emulating / stubbing them out just to get Redboot working isn't a great use of our time.
- Totally Accurate CPU performance
- The emulated CPU runs as fast as the host system lets it, so performance will vary based on which machine you run the emulator on.
- Note: Timers are implemented using the system clock, and will do the Right Thing no matter how fast the host system is.
- Train emulation
- You mean you want me to write a physics simulator for virtual trains? Hahahaha, yeah... no.
- Update: Looks like someone else was crazy enough to actually attempt doing this! Check out the MarklinSim project!
- You may need to use the
--hack-inf-uart-rx
flag to get this working, depending on how you're querying CTS in your kernel.
- You may need to use the