The Able processor was designed in the mid-1970s for MSI components, and first assembled by New England Digital (no connection to DEC) in a converted barn in Norwich VT. It was primarily used in embedded applications for experiment control and network processing. Its most successful application was in the Synclavier digital synthesizer.

NED ceased operations in 1992, although a Synclavier user consortium continued manufacturing for several years. An attempt at re-implementation in VHDL is here. It runs under GHDL and synthesizes on a Xilinx Spartan 3C in about 300 slices in addition to a BRAM for code/data. Instructions execute in a minimum of 3 clocks.

Processor

Registers

The Able has sixteen 16-bit registers, r0 ... rF. The first four registers can be used as ALU destinations for accumulator (two-operand) operations. ALU operations set three condition codes, MINUS (negative), ZERO, and CARRY. ALU tests set condition codes but do not update the registers.

The last two registers are used as program counters. In normal operation rF is the PC. During interrupt processing rE is the PC. Jumps modify the current PC. If interrupts are enabled, rE should point to an interrupt handler, which loops after exiting.

Registers can be post-incremented. When used as a destination address, rC is post-decremented instead, making it useful as a stack pointer.

Memory

Memory is 16 bits wide and word addressed. Any register can address memory. The address has no offset, although the register can be post-incremented.

Addresses are 16 bits wide, with no address translation, although late model Able processors included hardware mapping to address several Gigawords.

Memory access are acknowledged, supporting a mix of different speeds of memory.

Devices

Devices are directly addressed with 7-bit addresses. Device registers are 16 bits wide, and may implement arbitrary read/write behavior.

Device access is acknowledged. Devices can also interrupt the processor, with interrupt behavior is defined by the hardware.

The original Able processor used special devices for program status, a priority encoder, and an instruction repeat mode. The FPGA does not reproduce this. It includes a simple PSW adequate to support interrupts.

Assembler

The NED Able was programmed entirely in XPL, using self-hosted and cross-compilers. These notes use syntax for the simple assembler included here.

Some NED documentation uses a different assembler notation here. XPL code could generate any instruction as a combination of WRITE() = READ() intrinsic functions.

Instruction

There is only one instruction, a word move.

Move source

The lower half of an instruction word specifies a move source.
bits assembler use
0------- d0 ... d3F devices
10------ n immediate value -20 ... 1F
1100---- r0 ... rF register
1101---- r0++ ... rF++ register post-increment
1110---- [r0] ... [rF] memory load from register address
1111---- [r0++] ... [rF++] memory load from post-incremented address
16-bit immediate values are loaded from the instruction stream using a PC post-increment source, [rF++] ([rE++] in interrupt code), which addresses the word following an instruction and skips over it.

Move destination

The upper half of an instruction word specifies a move destination. Special destinations include ALU operations and the current PC..
bits assembler use
0------- d0 ... d3F = devices
100----- r0 ... r3 op= set accumulator and conditions
1010---- r0 ... r3 op? test accumulator and set conditions
1011---- r0 ... r3 op= set accumulator and conditions
1100---- r0 ... rF = register
1101--- jump op= conditional jumps
1110---- [r0] ... [rF] = memory store to register address
1111---- [r0++] ... [rF++] = memory store to post-incremented address
11111010 [rC--] = memory store to post-decremented address

ALU

ALU operations use the first four registers, r0 ... r3, as two-operand accumulators. The ALU result sets minus (m) and zero (z) condition codes. Add and subtract set carry (c) from the carry-out. Rotate and shift set carry from the bit shifted out.
bits assembler use
100000-- r0 ... r3 := acc = source
100001-- r0 ... r3 &= acc &= source
100010-- r0 ... r3 += acc += source
100011-- r0 ... r3 -= acc -= source
100100-- r0 ... r3 ^= acc ^= source
100101-- r0 ... r3 <= acc = ROL(acc,1)
100110-- r0 ... r3 |= acc |= source
100111-- r0 ... r3 ~= acc = ~source
101100-- r0 ... r3 %= acc = ROL(acc,8)|source
101101-- r0 ... r3 >= acc = SHR(acc,1)+source
101110-- r0 ... r3 +c= acc += source+c
101111-- r0 ... r3 -c= acc -= source+c

Test operations use the first four registers as operands. Test operations set condition codes but do not update accumulators.

101000-- r0 ... r3 :? source
101001-- r0 ... r3 &? acc & source
101010-- r0 ... r3 +? acc + source
101011-- r0 ... r3 -? acc - source

Jumps

Jumps set the current PC, rF, or rE during interrupts.
11010--- jump := jump absolute
11011--- jump += jump relative

1101-0-- j jump if true
1101-1-- jn jump if false

1101--00 always
1101--01 z if zero
1101--10 c if carry
1101--11 m if minus

Unconditional absolute jumps can also be achieved by a move to the current PC.

Interrupts

Interrupt support is optional. The Able included a Program Status Word at device 1 for interrupt control and status, which included the interrupt state of each peripheral device capable of interrupts.

This implementation includes an optional PSW as device 1, but, because the device interface and possible interrupt sources are different, it does not provide the same behavior. Interrupts are edge-triggered from any device. Software is responsible for polling devices to demultiplex interrupts.

bits 15 - 6 543210
unused I Q E M C Z

The PSW includes the ALU condition codes (M, C, and Z) so that they can be saved on interrupt entry and restored on exit. The interrupt enable bit, E, is initially clear. The interrupt PC (rE) should be initialized before setting E. Q indicates that an interrupt is pending. Setting this bit causes an interrupt. Clearing it has no effect. I is set when the CPU is executing an interrupt handler using rE as the PC. This bit cannot be set or cleared. Instead, writing the PSW causes the CPU to exit interrupt service and revert to using rF as the PC.