Background

One of the intresting problems from my Computer Architecture classes was a Hypothetical "Subtract and Branch if Negative" datapath. It was unique in that it had only that one instruction.... It would subtract one number from another, writing the result into a register and taking a branch if the result was negative.

The mnemonics for this would be:
SBN R3, R2, R1, 4  <=== Subtract R2 from R1 and place result in E3. Branch by +4 if written value is negative. Take the next instruction otherwise.  
Most assemblers would reserve a General Purpose register as a 'scratchpad'. Some would force R0=0 as a known reference.
The obvious advantages are that such an implementation is very simple and takes little silicon area, allowing for easy development and implementaiton.
Among the much larger disadvantages:

Other Instructions

Add

ADD could be implmented as a subtract of an addend from 0 and then subtracting that difference from the other addend.

Multiply

MULT R3 = R1*R2 could be implemented as:

Divide

Divides (R3 = R1/R2) could be implemented by subtracting R2 from R1 until the result falls negative while simultaneously subtracting -1 from a counter. The counter would be the quotient and re-adding the dividend to the result gives the remainder.

High Level Languages

A simple
 
if (var < 2) 
  MyFunc(otherVar);
else 
  j=j+1 

// Assuming variable "var" is in R2 and j is in R3.

SUB R0,R3,2,#myFunc 
SUB R3,R3,-1,1      // Subtract -1 from R3, branch by 1 no matter what
..
.
.
#myfunc:


Relevance to prior work experience

On the TMS320C6X architecture TM3320C6201,02 and 03 I worked on the Program Fetch, Data Path, Host Port, DMA and EMIF as well as JTAG Integration/testing and integrating the full chip.

Implementation

For demo purposes I've picked a simple non-pipelined single-threaded implementation. The AXI Bus provides a means via an AXI-LITE Slave interface to communicate with the datapath providing memory mapped IO.
The registers are mapped as follows:
Register OffsetValue
0x00Instruction 0
...
0x3CInstruction 15
0x40Done (bit 2, RO) Reset (bit 1,RW) Enable (bit 0,RW)
0x44Datapath Register Write Enable (bit 8), Datapath Register File Address(bits 4-0)
0x48Datapath Register File Write
0x4CDatapath Register File Read
0x50-0x70Reserved
0x74debug
0x78Instruction count
0x7CChecksum (0xDEBAC7E).. In real implementations this might be a peripheral ID to ease driver enablement.
For simplicity I allow for Register File reads and writes from the "control" registers.

Pipelines and Delayed Branches

A pipeline could be implemented using a delayed branch mechanism, where on any instruction it and the next instruction are guaranteed to execute (on the C6x we had 5 delay slots).

Multithreading

Since this processor doesn't offer a call stack or return instruction, there is no way to implement the context switching needed for multithreading.

Assembly

//  Instruction format:
//     32 registers, 32 bits wide, R0 is always 0
//
//  All numbers are signed. 
//
//   Bits7-0  subtrahend
//   Bits15-8 minuend
//   Bits23-16 destination (always a register number)
//   Bits31-28 Branch Offset 
//   Bits24: subtrahend is constant (1), register (0)
//   Bits25: minuend is constant (1), register (0)
//
//   Mnemonic is:   SBN R5,R6,R0,5     # R5=R6-R0, Branch by signed(5) if negative (1 otherwise)

Github

All of my code is in my github. This includes an Assembler, source and test code. Obviously for a more serious example there would be far more test coverage. To run, provide with a .sbn file (in /testcases/testSourceAssembly) to the assembler. This will generate a json file (in testcases/testAssembled) and the results can be compared with files in the (testcases/testResults).

Running

The easiest way to run this is to examine the RunPushtoZYNQAndTest.py script. Be sure to also pull the files it indicates (also automatically generated). If you are really interested I can provide bit files.
You may also run example code from as in this example:
root@pynq:/home/xilinx/SubtractBranchNegative# ./RunSBNOverlay.py Multiply4And3.sbn.json Multiply4And3.result.json 
CONTROL Reads 0x6
Control Register 0 0x12010001
Control Register 1 0x31020201
Control Register 2 0x30301
Control Register 3 0xe3000001
Control Register 4 0x0
Control Register 5 0x0
Control Register 6 0x0
Control Register 7 0x0
Control Register 8 0x0
Control Register 9 0x0
Control Register 10 0x0
Control Register 11 0x0
Control Register 12 0x0
Control Register 13 0x0
Control Register 14 0x0
Control Register 15 0x0
Control Register 16 0x6
Control Register 17 0xe
Control Register 18 0x0
Control Register 19 0x0
Control Register 20 0x4
Control Register 21 0x0
Control Register 22 0x0
Control Register 23 0x0
Control Register 24 0x0
Control Register 25 0x0
Control Register 26 0x0
Control Register 27 0x0
Control Register 28 0x0
Control Register 29 0x0
Control Register 30 0xc
Control Register 31 0xdebac7e
Datapath Register 0 Actual  0x0 Expected 0x0
Datapath Register 1 Actual  0xfffc Expected 0xfffc
Datapath Register 2 Actual  0xffff Expected 0xffff
Datapath Register 3 Actual  0xc Expected 0xc
Datapath Register 4 Actual  0x0 Expected 0x0
Datapath Register 5 Actual  0x0 Expected 0x0
Datapath Register 6 Actual  0x0 Expected 0x0
Datapath Register 7 Actual  0x0 Expected 0x0
Datapath Register 8 Actual  0x0 Expected 0x0
Datapath Register 9 Actual  0x0 Expected 0x0
Datapath Register 10 Actual  0x0 Expected 0x0
Datapath Register 11 Actual  0x0 Expected 0x0
Datapath Register 12 Actual  0x0 Expected 0x0
Datapath Register 13 Actual  0x0 Expected 0x0
Datapath Register 14 Actual  0x0 Expected 0x0
PASS!