Fable, a FPGA Able

The Able processor fits nicely in an FPGA, occupying about 300 slices of a Spartan3 for the processor, in addition to ROMs/RAMs and devices. An implementation in VHDL is here,.

The processor implementation is based on a close reading of the manual, but may not be completely accurate.

On-chip devices and memory are not completely asynchronous, but share the processor global clock. They may acknowledge on any rising edge, including the request. Interrupt support is optional, and does not attempt to reproduce the Able.

A small assembler here generates code as a VHDL array. Instructions use assignment operators instead of MOV, and hexadecimal instead of octal.

Registers/Memory

Registers are r0 through rF. Reading a register can post-increment it. As a special case, rC is post-decremented when storing to memory, making it useful as a downward-growing stack pointer. Note that both increment and decrement are applied post-read, so they are not exact inverses.

Memory is always addressed with a register - the only addressing mode is register-indirect, with an optional post-increment/decrement. Adding an address offset requires an accumulator operation.

Source Operand

The lower half of an instruction word specifies the source operand.

16-bit immediate values are loaded from the instruction stream using a PC post-increment source, [rF++] (or [rE++] in interrupt code), which loads the word following an instruction and skips over it.

Destination Operand

The upper half of an instruction word specifies the destination operand. Destinations include ALU accumulator operations and conditional jumps.

ALU/Test

ALU operations combine the source with one of four accumulator registers, r0 through r3. The result is written back to the accumulator

ALU destinations set three condition codes. Add/subtract-with-carry and conditional jumps read these codes.

Test destinations perform the ALU operationand update condition codes, but do not update the accumulator register. Tests are limited to a subset of ALU operations.

Jumps

Special destinations provide absolute and relative conditional jumps operating on the current PC (rF or rE).

11010---

11011---

1101-0--

1101-1--

jump :=

jump +=

jump absolute

jump relative

j

jn

jump if true

jump if false

Jumps are implemented as load/add to the current PC, without updating conditions and updating the register only if the condition is met.

Additionally, assigning to the PC causes an unconditional absolute jump. Adding an immediate to the PC causes a short relative jump.

I/O

The Able used a bidirectional tristated bus. This isn't practical in an FPGA, so Fable uses a daisy-chained bus similar to Wishbone.

The Able reserved bits in a processor status word (PSW) for each kind of device capable of interrupts. Here interrupt support is optional, provided through an interrupt control word (ICW) device which merely schedules interrupts. Interrupt status amd configuration is left to each device. Interrupts are edge-triggered, so no device operation is required to clear the interrupt.

Clearing I exits interrupt handling. Setting Q causes a software interrupt.

The processor maintains two sets of condition codes, one for each interrupt state, so an interrupt handler need not save and restore them. As noted above, each interrupt state has its own PC, rE or rF. Any other registers must be managed explicitly.