Overview
I'm not certain why, but I've seen very few hobbyist projects based around the early MIPS processors.
MIPS-1 is a very interesting architecture, for a few reasons:
- Up until RISC-V, it was very heavily used as a teaching architecture in universities, so there's plenty of documentation available online
- The memory map is divided up in a way that makes implementing cached / noncached / user / supervisor regions quite simple
- The instruction set is very easy to understand
For this project, I've selected IDT's "RISController" series, the IDT79R3041 / IDT79R3051 / IDT79R3071 / IDT79R3081, based around the MIPS R3000 core. The documentation for these devices is very good, and covers the startup process in detail.
All of my work so far has been with the 3051, but the board should also work for the 3041, 3051E, 3071, 3071E, 3081 and 3081E.
The completed board (with a couple of bodge wires) looks like this:
Hardware
This project is built as a processor card for the Modular CPU platform. It's mostly just level shifters and buffering, but a few notes to highlight:
- A couple of components (RN22, JP3) need to be fitted only if a R3041 is used and must not be populated for any other components. I saw some very strange startup issues when JP3 was fitted while trying to bring up an R3051.
- Ideally, these would be properly buffered so they could be driven by the FPGA
- LV_BOOTCFG_DIR net should be connected to LV_BOOTCFG_EN
- This was missed on the PCBs that were ordered, but wasn't too difficult to add a wire for.
- On the R3081, the WR and ALE pins are bidirectional, not just outputs - they can be used for cache invalidation.
- The R30x1 series use a moderate amount of power (2-3W at 5V depending on frequency), so power supplies (and current limits) should be set with this in mind
- The footprint I selected for the 74LVC245 levelshifters seems to be incorrect - it was still just about possible to solder these, but it wasn't trivial.
FPGA Gateware
Not too much to write here - there's a very simple (and quite inefficient) bus bridge to go between the R30x1 processor bus and an on-chip wishbone bus.
For the moment, I'm instantiating a 32 bit by 1024 word RAM and the same size ROM, although it would be possible to connect this to the QSPI RAM on the board at some point.
I used my On-FPGA Logic Analyser extensively throughout the bringup process on this project.
Here's an example of a boot, printing "Hello, World" on the debug interface:
(Note - to save space in the capture buffer, I've gated off sample capturing at any point where the wishbone cycle signal is low, so these screen captures don't show the complete bus cycle).
The first few instructions read after reset look like this:
Software Environment
For this project, I built GCC for MIPS using crosstool (configuration included in the ZIP at the end of this page).
It seemed (subjectively) much easier to get the software environment up and running to the point of being able to call C code compared to other processors I've tried in the past, although I've not quite got variadic arguments for printf working yet (UPDATE 2024-10-06, printf works now - see update at the end of the page).
A simple "Hello World" project is included in the ZIP file. The startup script isn't the most efficient (the BSS zeroing and DATA copying is done byte-by-byte), but it seems to work.
Challenges
Although it's mentioned in the software bringup guide, I didn't quite realise the importance of clearing the Cache isolation bit immediately during startup.
If this bit is 1, any data memory access (including those to non-cachable regions) will not go out onto the system bus.
This bit is not set to a defined value on hardware reset, so I found that a working MIPS startup program failed when I returned to the project a short time later.
MIPS-1 is a pipelined architecture, and this needs to be taken into consideration when looking at Waveforms for debug.
Status
Overall, this project is probably "Complete, for now".
I've only tested it with a R3051, but in the future, I might look at adding some more features:
- I'd be interested to try to get linux running on a R3081E.
- Try the board with some of the other processors in the range
- Try to write a small operating system for MIPS
UPDATE 2024-10-06
- The printf issues were caused by an incorrect byte-addressable RAM in the FPGA.
- The FPGA image has a 32 bit RAM, which is byte accessible
- Due to a duplicated always @ block, all bits of the RAM were being written even during byte writes.
- In the MIPS R3000, during a byte write, the unused bits of the data output seem to be undefined (rather than containing a fixed/known value)
- In practice, these bits seem to contain whatever was previously in the ALU, which means that simple memory tests may pass even if a word is written in place of a byte
- I've updated the memory test in the startup.S to intentionally clear the ALU between bytes, and the wb_ram_rom.v to correctly write bytes.
- I strongly suspect the coprocessor0 instruction encoding in the MIPS R3000 Software Reference Manual that I have is incorrect
- When I tried manually writing
mtc0
(to clear the Cache Isolation bit) instructions using a opcode value of decimal 24, I was seeing exceptions - GCC generates opcode value decimal 16 for this instruction, which works OK
- When I tried manually writing
Some possibly useful resources: