Fundamental Architecture and Advantages
In practice, One-Der is a bit more complex, but not much. The main CPU is about 140 lines of Verilog code -- less if you deduct the comments. However, this main portion is really just defining the bus between functional units. All the real work is in one of the functional units -- even the program memory and the program counter are functional units.
The main bus has two other functions that augment the transfer of data between functional units. First, it allows for conditional transfers. That is, based on a set of conditional tests, a transfer may not be allowed and the bus cycle becomes a NOP instruction.
The second augmentation is the ability to load constants. The program counter functional unit has a special operation: load the next 32-bit word into a special constant register (which is also part of the PC's functional unit). Because many constants don't require the full 32-bit word, there is also a way to use illegal conditional instructions to load shorter (28-bit) constants in a single 32-bit bus cycle (using the same constant register). In addition, one or more "constant" functional units can make common constants (like zero, for example) easily accessible to any instruction.
This points out one of the major advantages of the One-Der architecture. Need a special set of constants that I don't use? It is trivial to add a new functional unit with your constant. A practical functional unit might be more difficult, but the interface of your logic to the CPU is trivial. Each functional unit has an 8-bit address, so you simply need to create a module for your functional unit and instantiate it in the CPU at an unused address. By convention, all the functional units have the same module signature to a point and then custom parameters follow the standard ones. It is often simpler to test individual functional units separately before integrating them with the main CPU, another advantage.
For example, Listing 1 shows the roughly 70 lines of Verilog that make up the current constant unit. The address is one of the parameters passed in when you instantiate the module.
'timescale 1ns / 1ps 'default_nettype none /********************************************************************** One-Der Copyright 2006, 2007, 2008, 2009 by Al Williams (firstname.lastname@example.org). This file is part of One-Der. One-Der is free software: you can redistribute it and/or modify it under the terms of the GNU General Public Licenses as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. One-Der is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY: without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with One-Der (see LICENSE.TXT). If not, see http://www.gnu.org/licenses/. If a non-GPL license is desired, contact the author. This is the FU that contains 16 useful constants. ***********************************************************************/ module FConstant(input wire xreset, // reset input wire clk0, // clock input wire invclk, input wire phase, inout wire [31:0] dbus, // data input wire [12:0] srcadd, // source add input wire [12:0] dstadd, // dest add (not used) input wire [12:0] cfg, // configured address output wire dta, // data transfer ack input wire dtain); // dta input wire wire oe; // tri state control wire [3:0] subunit; // match addresses assign oe=srcadd[7:0]==cfg[7:0]&& srcadd==cfg; assign subunit=srcadd[11:8]; assign dta=1'b1; reg [31:0] const; assign dbus=oe?const:32'bz; // set up the constants always @(subunit) begin case (subunit) 4'b0000 : const=32'b0; 4'b0001 : const=32'b1; 4'b0010 : const=32'h2; 4'b0011 : const=32'h80000000; 4'b0100 : const=32'h4; 4'b0101 : const=32'hff; 4'b0110 : const=32'hff00; 4'b0111 : const=32'hff0000; 4'b1000 : const=32'hff000000; 4'b1001 : const=32'h00000010; 4'b1010 : const=32'ha; 4'b1011 : const=32'hf; 4'b1100 : const=32'hf0; 4'b1101 : const=32'h80; 4'b1110 : const=32'haaaaaaaa; 4'b1111 : const=32'hffffffff; default: const=32'h0; endcase end endmodule
To add a new set of constants, simply copy and paste this module to a new Verilog file, rename the module, and instantiate it with a new address in the main CPU file (oneder.v) and you can put 16 more constants in your new custom instruction set. For example, here's the line that includes the existing unit:
// Constant source (unit 0) FConstant constant(xreset, clk0,invclk,phase, dbus, src, dst, 13'h0, dta, dta);
Constants are a simple example, but perhaps your program would benefit from three accumulators or four different loop counters. No problem. Just instantiate the existing module multiple times, each with a different address. It is just as easy to remove modules to save space on the FPGA if you find your program never uses a particular module.
While it is handy to be able to add, multiply, and subtract functional units by hand, a ripe area of research is using this architectural style in reconfigurable computing applications. A compiler could determine the optimum number and types of functional units and literally build a custom CPU on the fly optimized for the task at hand.
There is one other feature that functional units can use to manipulate the bus. The bus manages a line known as dta (data transfer acknowledge). This bit allows either the sender or the reciever to stall the bus if necessary. This can be useful for slow external memory access for example. The FIO functional unit takes advantage of the bus stall to implement a delay subfunction.
In addition to functional units, One-Der has a set of registers that can act as the source or destination of a transfer. These act like registers on any garden-variety CPU; they simply store values until needed.