This project is IN DEVELOPMENT! All promises made below are lies.
ICM68K (Instrument Control Module, 68k) is an embeddable M68010 computer, intended for controlling test equipment (or whatever else you want to control!). Its features include:
- Motorola M68010 CPU running at 10 MHz
- Optional memory-mapped M68881 FPU running at 10 MHz
- Up to 13 MB application RAM plus 512 kB system memory
- A memory protection unit supporting up to 127 user processes with read, write, and execute control
- Dual-channel UART with hardware flow control on one channel
- Dual-channel SPI (one for on-board peripherals, one for user) operating at up to fSCK = 10 MHz
- Onboard micro SD card slot
- Eight user GPIOs with interrupts
- Real-time clock with alarm and system tick interrupts
- Beeper with hardware volume control and frequency generation
Note that this is a large, very featureful and somewhat expensive board. See the ICM68M for a budget option.
||512 kB||Supervisor/OS ROM/RAM|
||384 kB||Not mapped|
||80 kB||Not mapped|
||1024 kB||System bus|
||14366 kB||User RAM|
The M68010 CPU always boots from a reset vector located at address
It is the responsibility of the memory/debug card to ensure there is a valid
vector at this location at reset. Debug cards implement RAM in this region
and provide a supervisor microcontroller to preload it with valid data;
the simple memory card will likely map a flash device here. Note that unlike
the M68000, the M68010 provides a vector base register, so no hardware
remapping is required to allow both a valid reset vector on boot and runtime
The ICM68K provides interrupts in multiple layers; the board support package for the A6 operating system will decompose these into a flat set of software interrupts.
First level (M68k hardware interrupts)
There is no priority encoder generating the IPL signals to the CPU; instead, each signal is used independently as an IRQ line, with autovectoring always generated by the bus control unit. Therefore, each ISR may map to multiple vectors — as it clears its own interrupt, more interrupts will become visible.
Note that autovector 7 is a non-maskable interrupt, so if the debug interrupt is used, this ISR must not interfere in any way with OS function.
Second level (DUART interrupts)
A second level of interrupts is provided by the DUART on pins IP1 (
nIRQ_GPIO), and IP3 (
nIRQ_RTC). These interrupts may be decoded and
acknowledged by a read to the interrupt status register in the DUART; see the
68681 datasheet for more information.
Note: the schematic shows IP4 as
nIRQ_SPI. However, this pin is not
interrupt capable. A future revision could move it to IP0, but interrupt
functionality is not generally required on the SPI transceiver so the current
plan is to leave this unfixed.
nIRQ_RTC is a general-purpose RTC IRQ which may be used for the
alarm functionality. The OS tick interrupt, also generated by the RTC, is
routed directly to the CPU.
Third level (GPIO interrupts)
Up to eight user interrupts are provided by the MCP23S08 GPIO chip, whose interrupt pin connects to the DUART on IP2.
OS tick interrupt
The OS tick interrupt is handled in a special way. It is generated by the
real-time clock, which outputs a square wave. This is converted into an
interrupt pulse by an XOR gate combining it with a GPIO. When the OS tick
ISR executes, it should toggle the state of pin OP5 (
RTC_IRQPOL) on the
DUART to acknowledge the interrupt.
Because the RTC state is not cleared by system reset, this interrupt could be active at boot.
There is no onboard system memory; both supervisor and user regions are provided by a mezzanine card. This interface is designed to provide the option of a hardware debugger (which is at the time of writing the only mezzanine card that has been built).
In addition to the normal memory interface, this mezzanine connector provides:
- System clock (10 MHz)
- Reset in/out
- Breakpoint-detected signal from the bus control unit
- Separate chip selects for supervisor and user spaces
- Bus mastering signals
- One IRQ line
- Bus timeout inhibit control
- Access to the CPU function code bits
- 5V and 3.3V power; 5V is bidirectional (the debug card allows powering the ICM68K via a USB port)
Bus control unit
The bus control unit is a CPLD, named OAK, providing address decode, clock generation, and part of the memory protection unit functionality.
Memory protection unit
The memory protection unit (MPU) on the ICM68K allows the operating system to apply memory protection to up to 127 user-mode processes. Within each process, every 2 KB section of address space can be assigned a permission mode. Permission violation when in user mode triggers a bus error.
To select the active process, write the process ID (0 to 127, with 0 intended
for the kernel) to the task select register, using a byte-size write to
any even-numbered address with function code 3 (use
movec to load 3 into
the DFC register, then use the
moves instruction to perform the write with
this function code). The high bit functions as an active-low "bypass" bit and
should be set to 1 (currently, A6 does not make use of this bypass
To write to the protection table for a process, first select that process as
above in the task select register. Then, write a control byte to the first
odd-numbered address in the block of four 2 KB pages, using function code
3 as above. For example, the control byte for the page containing address
069420 is at
(0x069420 & 0xFFE000) | 1 or
0x068001. This control byte
contains permission codes for all four pages in the block, as follows:
msb lsb +---+---+---+---+---+---+---+---+ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +---+---+---+---+---+---+---+---+ |___| |___| |___| |___| | | | | | | | |____ page n + 0 | | | | | |____________ page n + 1 | | | |____________________ page n + 2 | |____________________________ page n + 3
Permission modes are:
NO_ACCESS: all access denied
READ_ONLY: data reads allowed, writes and code reads denied
READ_WRITE: data reads/writes allowed, code reads denied
READ_EXEC: data and code reads allowed, writes denied
Note that memory may not allow both execution and writing at the same time. Memory protection does not apply to supervisor-mode accesses or while bus mastering is active.
The memory protection table may be read back by performing a FC=3 read to the same address (note that you must then also place 3 in the SFC control register). However, the task select register cannot be read back.
Hint: if the kernel needs to validate whether the current process has permission to access a location, it is much faster to simply perform this access with FC=1 (userspace data) and let the MPU block it than it is to read back the protection table and compute whether the access would be permitted. This requires the support of the bus error vector handler.
The 68681 dual UART provides two UARTs, one timer, and several inputs and outputs.
- UART 0 provides only TXD and RXD.
- UART 1 provides TXD, RXD, RTS, and CTS. It is intended for use with the system and bootloader console.
- The timer can be used to control the beeper or as a baud rate generator or periodic interrupt generator. (Note that for system ticks, the intended source is the RTC.)
- The following IOs are used:
- OP0: SPI chip select for the user GPIO
- OP1: UART 1 RTS
- OP2: up/down control for the beeper loudness adjustment
- OP3: timer output; provides square wave for beeper
- OP4: SPI chip select for the SD card
- OP5: RTC IRQ polarity/acknowledge
- OP6: SPI chip select for RTC
- OP7: beeper loudness adjustment chip select and status LED (see that section)
- IP0: not connected
- IP1: UART 1 CTS (interrupt capable)
- IP2: GPIO IRQ (interrupt capable)
- IP3: RTC IRQ (interrupt capable; separate from OS tick)
- IP4: SPI IRQ/flag (bug: NOT interrupt capable)
- IP5: SD card sense
The SPI transceiver is a CPLD, named ASH, providing two SPI channels with configurable mode and frequency up to 10 MHz. (TODO: add documentation on this)
Beeper and status LED
The onboard beeper is controlled by the DUART. To set the loudness, drive the up/down control (OP2) and chip select (OP7) per the digital potentiometer datasheet here (MCP4011). The potentiometer only permits relative adjustment; to set an absolute value, send enough "up" or "down" commands to saturate it at the top or bottom first.
The beeper output OP3 should be held high when not in use.
The LED is multiplexed with the loudness chip select, with a bypass capacitor across it to prevent flashing while adjusting loudness. To control the LED, simply drive this pin to a constant level. Additional pulses may be sent to the potentiometer to compensate for the resulting one-step change in loudness that will be caused by the LED toggle; alternatively, always set the loudness to an absolute level as described above when emitting a beep.
The A6 board support pack for the ICM68K will provide a driver to handle this and present demultiplexed LED and beeper devices to userspace.
By convention, a memory mapped debug console is provided by the debug card. The memory interface control hardware on that card intercepts writes to the supervisor region and uses this to implement a control interface.
The control interface takes the form of a single 16-bit memory mapped register
located at address
07FFFE, the last address in supervisor space. Each write
to this register is a command, with the command index in the upper byte and
the argument in the lower byte. Commands are as follows:
TRANSMIT(0): send the argument on the debug console.
SET_RXBUF_3(0x10): set byte 3 (MSB) of the receive buffer address
SET_RXBUF_2(0x11): set byte 2 of the receive buffer address
SET_RXBUF_1(0x12): set byte 1 of the receive buffer address
SET_RXBUF_0(0x13): set byte 0 (LSB) of the receive buffer address
SET_RXLEN_1(0x14): set byte 1 (MSB) of the receive buffer length
SET_RXLEN_0(0x15): set byte 0 (LSB) of the receive buffer length
EN_DIS_RX(0x16): enable (arg is true) or disable (arg is false) receive
SET_VECTOR(0x17): set vector number for RX interrupt (see below)
IACK(0x18): acknowledge the interrupt (see below)
The receive buffer is a ring buffer the operating system must allocate in RAM.
It must be word-aligned. The first word is the head index, the second word is
the tail index, and the rest is data. Once allocated, write the address of the
beginning of the ring buffer using the
SET_RXBUF_n commands, write the length
of the data portion in bytes using the
SET_RXLEN_n commands, then enable
EN_DIS_RX. As bytes are received by the debugger and passed to
the operating system, the debugger will increment the tail index, and the
operating system will detect
head != tail, receive the bytes and increment
the head index. Always use word-size accesses to ensure atomicity.
The debug console interface definition supports both full M68000 interrupt vectoring and autovectoring; the ICM68K only supports autovectoring. To enable interrupt on byte received, write any autovec vector number into the debug console's vector register to enable interrupts. When the ISR runs, you must write the IACK command to acknowledge and clear the interrupt. Beware that the ICM68K maps the IRQs such that this may be a nonmaskable interrupt if all three IRQs assert simultaneously. Use of this interrupt is generally not recommended or needed, though it may be useful to support future debug functionality.
(TODO: the control register was previously mapped at
The code still needs to be updated to reflect this.)
Floating point unit
The M68010 does not support coprocessor instructions, but it is possible to memory-map a M68881 floating point unit. The ICM68K provides a socket for this. Note that the A6 operating system does not presently provide any support for it.
The FPU SENSE line is not wired up. To detect presence or absence of the FPU, simply attempt to access it. Because ICM68K generates a bus error on timeout, this access will not hang if the FPU is not present. A future A6 FPU kernel module will perform this test on boot — it is not available to userspace.
This address range is for user expansion via the DIN 41612 connector. The system bus chip select line is asserted by the bus controller whenever an address in this range is accessed. If the system bus (or a section of it) is not used, it may reply with a bus error, but the onboard bus timeout generator can take care of this automaticaly.
The last four words of RAM (
FFFFFF) should not be used; they
may map to control registers of PSRAM on memory cards. Memory cards should
ensure these all sit at the end of RAM (if using multiple chips, interleave
them), and should ensure that the usable region is also aligned to the end of
RAM. Memory cards must respond to accesses to the entire User RAM region; all
of these detectable variations are permitted:
- Entire address range maps to RAM (fully populated option)
- Some segments trigger bus error
- Some segments acknowledge, but no data is read or written
- Some segments overlap with other segments
Because overlap (generally the cheapest way to map smaller amounts of RAM to larger address ranges) is permitted, an operating system looking to dynamically detect RAM must test by writing to a region, then scanning forward to ensure its write did not show up elsewhere.
Segments must be at least 512 kilobits (64 kB) in size.
Bus timeout generator
The ICM68K contains a bus timeout generator circuit that generates a bus error
condition if the address strobe asserts for approximately 4 ms without a
response. This may be disabled by the memory/debug interface by applying at
least 3V, and no more than 6V, to the
BTO_INHIBIT signal. This signal should
otherwise float, and voltage may be applied via a diode to ensure this. Because
the bus timeout generator only watches the AS signal, it will trigger for all
hung accesses to any address.
OAK: The config files for OAK, the bus control unit, may be found at TODO. OAK must be a 5V-variant ATF1502 or ATF1504 CPLD, or the Altera equivalents.
ASH: The config files for ASH, the SPI transceiver, may be found at TODO. ASH must be a 3.3V-variant ATF1504 CPLD, or the Altera equivalent.
Intellectual property is bullshit. This is everyone's design.
Contact me (issue reports, patches, bare board requests)
Send an email to my username at alexisvl.rocks. I suggest mentioning the project name in the subject line.