Skip to main content
Department of Information Technology

Programming Guide for the MIPS Machine

The machine you are going to be programming roughly consists of three parts:

  • The processor
  • The memory (only RAM in this case)
  • The peripheral units (serial terminal in this case)

The memory and the peripheral units are both accessed via the memory map of the processor.

The Processor

The processor used is a MIPS 4Kc. It implements the 32-bit MIPS32 integer instruction set. It does not have a floating-point unit (it is a typical embedded part where floating point is not considered necessary). It does have a memory-management unit, but that can be ignored for the basic project work.

Relevant facts about the processor:

The Memory Map

As is common on the MIPS architecture (and most other modern computer architectures, with the x86 family being the only notable exception), all IO devices are memory-mapped. The following describes where in physical memory the various devices are mapped.

Virtual Memory

Note that the MIPS has a virtual memory system, as described in Chapter 3 of the MIPS 4Kc user's manual. This means that the addresses leaving the processor and used to access memory in a physical system, i.e. the physical addresses, are not necessarily the same addresses as seen by the software. Think about the physical addresses as the address bus connecting the processor to its surroundings, and the virtual memory system as a translator sitting between the addressses as seen by the software and the physical addresses sent out onto the address bus.

In practice in this project, you will not access memory over addresses starting at 0x0000_0000, but use the automatic mappings provided by the MIPS processor in Kernel mode (and as documented on page 50 of the MIPS programming manual):

  • The memory from address 0x0000_0000 is also accessed via address 0x8000_0000, corresponding to kseg0. These accesses are unmapped (bypasses the TLBs) but potentially cached (which does not matter here, as there are no caches in the system). The kseg0 mapping extends to address 0x9FFF_FFFF, covering 512 MB of address space.
  • The memory from address 0x1000_0000 is mapped also at address 0xA000_0000. This is kseg1, which is unmapped and always uncached. The fact that it is uncached makes it very appropriate to perform I/O operations (think about what caches would do to a device read, for example). The kseg1 mapping extends to address 0xBFFF_FFFF, covering 512 MB of address space. Thus, the device space is mapped here, and this is the recommended way of addressing devices on the MIPS.

Note that you will be running both your operating system and your application programs (processes) in kernel mode in this operating system assignment. In effect, this means that RAM memory (and thus your code) will be accessed using addresses around 0x8000_0000, and that devices will be accessed using addresses around 0xb000_0000. This style of addressing is used in the example files.

To see the memory map within Simics, use the command phys_mem0.map, once Simics has loaded the machine configuration.

Once again, note that the memory map given below uses physical addresses.

0x0000_0000: RAM

8 MB of RAM are mapped at address zero. This should be very sufficient for your operating systems, do not be surprised if only some few hundred kilobytes are used.

0x1800_0070: rtc0

rtc0 is a Dallas Semiconductor DS12887 real-time clock, as found in standard PCs. In our case, only the seconds counter is implemented and used. Some information from the Simics Reference Guide:

The DS12887 device implements real time clock functionality and non-volatile storage (NVRAM). The device is often referred to as CMOS Clock. The DS12887 includes time-of-day alarm, both 12 and 24 hour time format, periodic interrupts and 114 bytes of general purpose RAM. Limitations: Alarm interrupt not implemented. Daylight Savings Time not implemented.

The following offsets are mapped:

  0x00 - seconds
  0x01 - alarm seconds

To inspect the state of the real-time clock from the Simics command line, there are specieal commands available, for example: rtc0.get-date-time.

See the Datasheet for information on the functionality.

0x1800_03f8: tty0

tty0 is a National Semiconductor PC16550 serial port controller (also knows as a UART for Universal Asynchronous Receiver Transmitter). The control registers exposed at offset 0x03f8 in the device belong to the COM1 port of it. This device communicates with the serial port and is responsible for reading from and writing to the serial console.

The following offsets are mapped:

  0x00 - RBR/THR data read/write register
  0x01 - IER interrupt enable register
  0x02 - IIR/FCR interrupt identification register/FIFO ctrl
  0x03 - LCR line control register
  0x04 - MCR modem control register
  0x05 - LSR line status register
  0x06 - MSR modem status register
  0x07 - SCR scratch register

Note that the OUT2 bit in register MCR has to be set for the serial controller to generate interrupts to the processor. For interrupt processing purposese, it is directly connected to the processor, and uses external interrupt 0 on the MIPS (which is interrupt pending bit 2 in the cause register).

See the Datasheet for information on the functionality.

0x1f00_0000: malta0

This device is specific to the MIPS MALTA board (which our computer systems machine resembles to some extent), and controls the 8-character LCD display.

See the MALTA Board Manual for information on the functionality, especially how to activate and use the LCD display.

Exception handler example for UART, Clock and Syscall

Look in the provided example files. However, you have to combine the examples to handle all the three tasks simultanuouly. It will probably be similar to this code example:

void kexception() {
   cause_reg_t cause;
 
   // what is the cause of the interrupt?
   cause.reg=kget_cause();
 
   if (cause.field.ip & 0x80) {
     kload_timer(KERNEL_TIMER * timer_msec);
     // this is a timer interrupt
     // check for timers
     executeTimer();
     // check for timer alarms
     executeAlarm();
     // Reload timer
     increaseClock(CLOCK);
   }
 
   if (cause.field.exc == 0) {
     // external interrupt
     if (cause.field.ip & 0x4) {
       executeUART();
       /* Acknowledge UART interrupt. */
       kset_cause(~0x1000, 0);
     }
   }
   if (cause.field.exc == 8) {
     // internal interrupt and syscall
     executeSyscall();
   }
}

Unused Devices

The machine setup contains some devices which are not actually used. This was changed at a late stage in the course, so we keep the information here for reference. But note that the pic0 and gt0 are no longer used.

0x1800_0000: pic0

The pic0 device is pair of Intel i8259 interrupt controllers, as found in standard PCs. A single device contains both the master and slave controllers that are present by architecture. The model used in this simulation is rather limited. We quote the Simics Reference Guide:

The 8259x2 device implements the functionality of two cascaded 8259 interrupt controllers. The 8259x2 supplies 15 interrupt levels that connected devices can use to interrupt the cpu. The interrupt level to use should be set in the interrupting device. Limitations: Most registers in the 8259x2 device change hardware specific parameters. These are do-nothing in the 8259x2. Special Fully Nested Mode is not implemented. Buffered Mode is not implemented. Special Mask Mode is not implemented. Automatic End of Interrupt is not implemented. Rotate commands are not supported. Specific EOI commands are not supported.

The following offsets are mapped:

   0x20 - reg0 of master device
   0x21 - reg1 of master device -- interrupt enable/disable

   0xa0 - slave version of above, 0x20
   0xa1 - slave version of above, 0x21

The master part handles interrupt levels 0 to 7, and the slave part levels 8 to 15. reg1 tells the device which interrupts are enabled. Set bits to 1 to mask, i.e. disable, interrupts, and 0 to enable the interrupts. reg0 is used to determine which interrupts have occured. Bits read as 1 correspond to an interrupt that has been raised. Please see the example code (i8259.c) for how to initialize the pic0 device; it is a routine that has to be done in a certain way. Once initialized, it simply passes interrupts on to the processor and there is no need to interact with this device.

In our machine, the serial port/UART (tty0) is mapped using interrupt level 4 to the pic0. The pic0 is in turn mapped to external interrupt 0 on the MIPS, via the gt0 device documented below.

If you want to, see the Datasheet for information on the functionality.

0x1be0_0000: gt0

This is a GT64120 system controller, which is mainly irrelevant for the project assignment. It implements PCI, among other functions. From the Simics Reference Guide:

System controller chip from Galileo Technology Ltd. (now merged with Marvell Technology Group Ltd.): The GT64120 is a single-chip system controller for MIPS CPUs. This highly-integrated device contains all the key system peripherals needed to build a high-performance 64-bit MIPS system: SDRAM controller (parity support), device controller, DMA engines, timer/counters, and high-performance Universal PCI interfaces.The GT64120 includes an advanced dual-mode PCI interface unit that can support either two independent 32-bit PCI buses, or a single 64-bit PCI interface. PCI bus speeds up to 66MHz are also supported, as is an industry standard I2O messaging unit. Universal PCI for both 3.3V and 5V signalling is included. The 64-bit device controller on the GT64120 supports a wide range of memory devices including SDRAM, Flash, and SRAM.

The gt0 fills one important task in the machine: it links the pic0 interrupt controller to the processor. To clear interrupts coming into the processor, you need to tickle the gt0 to send an acknowledge to the pic0 device. To do this, you need to access the following register:

  0xc34 - PCI_0 Interrupt Acknowledge Virtual Register

Read this four-byte register to clear the interrupt. The gt0 device will tell the pic0 that the interrupt has been handled.

Updated  2004-12-14 22:18:38 by Jakob Engblom.