Die im folgende beschriebene CPU ist so programmiert, dass sie eine Fibonacci-Reihe berechnet.
Die CPU verfügt über folgende Register:
reg [7:0] DATA_ADR; // Daten-ROM Adressregister reg [7:0] PROG_ADR; // Programm-ROM Adressregister (PC) reg [15:0] CMD; // Befehlsregister reg [31:0] ARG1; // Argument 1 reg [15:0] ARG2; // Argument 2 reg [31:0] RESULT; // Resultat (Akkumulator) reg [15:0] AUX1; // Hilfsregister 1-4 reg [15:0] AUX2; reg [15:0] AUX3; reg [15:0] AUX4;
Ein Steuerregister kontrolliert die sechsstufige Abarbeitung der Befehle:
reg [5:0] STATE; always @(posedge SYS_CLOCK) begin case (STATE) 6'b000000: STATE <= 6'b000001; // 1. Load program counter 6'b000001: ... // 2. Load command from program memory 6'b000010: ... // 3. Load Argument 1 6'b000100: ... // 4. Load Argument 2 6'b001000: ... // 5. Load Result 6'b010000: ... // 6. Store Result 6'b100000: endcase end
Ein Assembler Befehl besteht aus 4 Nibbles und ist wie folgt strukturiert:
[Argument 1] [Argument 2] [Operator] [Ziel]
Folgende Werte sind hier möglich:
Wert Arg.1/2 Ziel Operator 0 RESULTAT - NOP (tu nichts) 1 DATA_IN - ADD (+, Addition) 2 DATA_ADR DATA_ADR SUB (-, Subtraktion) 3 PROG_ADR PROG_ADR MUL (*, Multiplikation) 4 AUX1 AUX1 DIV (/, Division) 5 AUX2 AUX2 LEFTSHIFT 6 AUX3 AUX3 RIGHTSHIFT 7 AUX4 AUX4 -
Das Programm für die Fibonacci-Reihe sieht wie folgt aus:
Adr Bytecode Mnemonic Kommentar 1 0114 RESULTAT + DATA_IN => AUX1 AUX1 = 1 2 4516 AUX1 + AUX2 => AUX3 3 5614 AUX2 + AUX3 => AUX1 4 6415 AUX3 + AUX1 => AUX2 5 7113 AUX4 + DATA_IN => PROG_ADR Spring zu Adr 2
Das Programm liefert folgende Resultate, die ich mit Zahlen aus einer Tabellenkalkulation verglichen habe:
OO Calc CPU 1 0001 1 0001 1 2 0002 2 3 0003 3 5 0005 5 8 0008 8 13 000D D 21 0015 15 34 0022 22 55 0037 37 89 0059 59 144 0090 90 233 00E9 E9 377 0179 179 610 0262 262 987 03DB 3DB 1597 063D 63D 2584 0A18 A18 4181 1055 1055 6765 1A6D 1A6D 10946 2AC2 2AC2
Das Projekt zum download: ex2 _fibonacci.zip
EX2_CPU.v:
// // CPU Core // module EX2_CPU (SYS_CLOCK, DATA_IN, PROG_IN, DATA_ADR, PROG_ADR, CMD, ARG1, ARG2, RESULT, AUX1, AUX2, AUX3, AUX4, STATE ); // input SYS_CLOCK; input DATA_IN; input PROG_IN; // reg [7:0] DATA_ADR; reg [7:0] PROG_ADR; reg [15:0] CMD; reg [31:0] ARG1; reg [15:0] ARG2; reg [31:0] RESULT; reg [15:0] AUX1; reg [15:0] AUX2; reg [15:0] AUX3; reg [15:0] AUX4; // reg [5:0] STATE; // output [7:0] DATA_ADR; output [7:0] PROG_ADR; output [15:0] CMD; output [31:0] ARG1; output [15:0] ARG2; output [31:0] RESULT; output [15:0] AUX1; output [15:0] AUX2; output [15:0] AUX3; output [15:0] AUX4; output [5:0] STATE; // wire [15:0] DATA_IN; wire [15:0] PROG_IN; // always @(posedge SYS_CLOCK) begin case (STATE) 6'b000000: STATE <= 6'b000001; // 1. Load program counter 6'b000001: begin STATE <= 6'b000010; PROG_ADR <= PROG_ADR+1; end // 2. Load command from program memory 6'b000010: begin STATE <= 6'b000100; CMD <= PROG_IN; end // 3. Load Argument 1 6'b000100: begin STATE <= 6'b001000; case (CMD[15:12]) 4'b0000: ARG1 <= RESULT; 4'b0001: ARG1 <= DATA_IN; 4'b0010: ARG1 <= DATA_ADR; 4'b0011: ARG1 <= PROG_ADR; 4'b0100: ARG1 <= AUX1; 4'b0101: ARG1 <= AUX2; 4'b0110: ARG1 <= AUX3; 4'b0111: ARG1 <= AUX4; endcase end // 4. Load Argument 2 6'b001000: begin STATE <= 6'b010000; case (CMD[11:8]) 4'b0000: ARG2 <= RESULT; 4'b0001: ARG2 <= DATA_IN; 4'b0010: ARG2 <= DATA_ADR; 4'b0011: ARG2 <= PROG_ADR; 4'b0100: ARG2 <= AUX1; 4'b0101: ARG2 <= AUX2; 4'b0110: ARG2 <= AUX3; 4'b0111: ARG2 <= AUX4; endcase end // 5. Load Result 6'b010000: begin STATE <= 6'b100000; case (CMD[7:4]) 4'b0001: RESULT <= ARG1+ARG2; // ADD 4'b0010: RESULT <= ARG1-ARG2; // SUB 4'b0011: RESULT <= ARG1*ARG2; // MUL 4'b0100: RESULT <= ARG1/ARG2; // DIV 4'b0101: RESULT <= ARG1<<ARG2; // left shift 4'b0110: RESULT <= ARG1>>ARG2; // right shift endcase end // 6. Store Result 6'b100000: begin STATE <= 6'b000001; case (CMD[3:0]) 4'b0010: DATA_ADR <= RESULT[7:0]; 4'b0011: PROG_ADR <= RESULT[7:0]; 4'b0100: AUX1 <= RESULT[15:0]; 4'b0101: AUX2 <= RESULT[15:0]; 4'b0110: AUX3 <= RESULT[15:0]; 4'b0111: AUX4 <= RESULT[15:0]; endcase end endcase end endmodule
Kritik: Register initialisieren.