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.
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.
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.
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.
Some NED documentation uses a different assembler notation here. XPL code could generate any instruction as a combination of WRITE() = READ() intrinsic functions.
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.
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
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
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
Unconditional absolute jumps can also be achieved by a move to the current PC.
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
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 5 4 3 2 1 0 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.