ALU
module alu(
     input      [3:0] opcode,
     input      [7:0] operand1,
     input      [7:0] operand2,
     output reg [7:0] result,
     output     [1:0] flags
);
always @(*) begin
     case(opcode)
     4'b0001: result = operand1 + operand2;
     4'b0010: result = operand1 - operand2;
     4'b1000,
     4'b1001,
     4'b1010: result = operand2;
     // urmeaza implementarea altor operatii
     default: result = 8'd0; // ramura default este obligatorie pentru a ne asigura ca blocul este combinational
     endcase
end
assign flags[0] = (result == 0);
assign flags[1] = result[7]; // In complement fata de 2 bitul MSB este bit de semn
endmodule
REGS
module regs(
     input       clk,
     // portul de scriere
     input      wen,
     input [3:0] waddr,
     input [7:0] wdata,
     // porturile de citire
     input [3:0] raddr1,
     input [3:0] raddr2,
     output [7:0] rdata1,
     output [7:0] rdata2
);
reg [7:0] registru [0:15]; // set de 16 registre a câte 8 bi?i fiecare
// portul de scriere
always @(posedge clk) begin
     if(wen) registru[waddr] <= wdata; // scriere sincron? - pe ceas - a rezultatului în registrul destina?ie
end
// portul 1 de citire
assign rdata1 = registru[raddr1]; // ie?irea rdata1 este valoarea din registrul cu num?rul raddr1
// portul 2 de citire
assign rdata2 = registru[raddr2]; // ie?irea rdata2 este valoarea din registrul cu num?rul raddr2
endmodule
RALU
module ralu(
     input      clk,
     input      rst,
     input [3:0] opcode,
     input      wen,
     input [3:0] dest,
     input [7:0] wdata,
     input [3:0] sursa1,
     input [3:0] sursa2,
     output [7:0] result,
     output reg [1:0] flags
);
wire [7:0] operand1;
wire [7:0] operand2;
wire [1:0] flags_alu;
//-----------------------------------------------------------------------------
regs regs(
     .clk     (clk     ),
     .wen      (wen         ),
     .waddr (dest           ),
     .wdata    (wdata ),
     .raddr1 (sursa1 ),
     .raddr2 (sursa2 ),
     .rdata1 (operand1 ),
     .rdata2 (operand2 )
);
//-----------------------------------------------------------------------------
alu alu(
     .opcode (opcode ),
     .operand1 (operand1 ),
     .operand2 (operand2 ),
     .result (result ),
     .flags (flags_alu)
);
//-----------------------------------------------------------------------------
always @(posedge clk) begin
     if(rst)
        flags <= 2'b00;
     else
        flags <= flags_alu;
end
endmodule
UCP
module ucp(
     input     clk,
     input     rst,
     input [3:0] opcode,
     input [1:0] flags,
     // control signals
     output pc_incr,
     output pc_load,
     output addr_load,
     output sel_addr,
     output sel_mem_data,
     output sel_instr_data,
     output ir_load_high,
     output ir_load_low,
     output regs_wen,
     output write
);
localparam FETCH1 = 3'd0;
localparam FETCH2 = 3'd1;
localparam EXECUTE = 3'd2;
localparam LDADDR = 3'd3;
localparam LDCONST = 3'd4;
localparam LD_DATA = 3'd5;
localparam ST_DATA = 3'd6;
localparam HALT = 3'd7;
reg [2:0] state;
reg [9:0] control_vector;
assign pc_incr          = control_vector[9];
assign pc_load          = control_vector[8];
assign addr_load         = control_vector[7];
assign sel_addr         = control_vector[6];
assign sel_mem_data = control_vector[5];
assign sel_instr_data = control_vector[4];
assign ir_load_high = control_vector[3];
assign ir_load_low = control_vector[2];
assign regs_wen          = control_vector[1];
assign write       = control_vector[0];
always @(posedge clk) begin
  if(rst) begin
     state <= FETCH1;
  end
  else begin
     case(state)
     FETCH1: state <= FETCH2;
     FETCH2: begin
        case(opcode)
        4'b0000: state <= FETCH1; // NOP
        4'b0001: state <= EXECUTE; // ADD
        4'b1000: state <= LDCONST; // LOADC
        4'b1001: state <= LDADDR; // LOAD
        4'b1010: state <= LDADDR; // STORE
        4'b1111: state <= HALT;    // HALT
        endcase
     end
     LDCONST: state <= FETCH1;
     LDADDR : begin
        if(opcode == 4'b1001)
           state <= LD_DATA;
        if(opcode == 4'b1010)
           state <= ST_DATA;
     end
      LD_DATA: state <= FETCH1;
      ST_DATA: state <= FETCH1;
      EXECUTE: state <= FETCH1;
      HALT : state <= HALT;
      default: state <= HALT;
      endcase
  end
end
always @(*) begin
  case(state)
  FETCH1 : control_vector = 10'b10_0010_1000; // PC <- PC + 1, IRH <- data_from_mem
  FETCH2 : control_vector = 10'b10_0010_0100; // PC <- PC + 1, IRL <- data_from_mem
  LDCONST: control_vector = 10'b00_0001_0010; // R[dest] <- instrdata
  LDADDR : control_vector = 10'b00_1000_0000; // ADDR <- result,
  EXECUTE: control_vector = 10'b00_0000_0010; // R[dest] <- result
  LD_DATA: control_vector = 10'b00_0110_0010; // addr = ADDR, R[dest] <- data_from_mem
  ST_DATA: control_vector = 10'b00_0100_0001; // addr = ADDR, write
  HALT : control_vector = 10'b00_0000_0000; // nothing to do
  endcase
end
endmodule
PROCESOR
module processor(
     input     clk,
     input     rst,
     input [7:0] data_in, // data from memory
     output [7:0] data_out, // data to memory
     output [7:0] addr,    // memory address
     output     write     // memory write enable
);
reg [7:0] pc;           // program counter
reg [7:0] data_addr; // address for data in memory
reg [15:0] instruction; // instruction register
reg [7:0] common_data;
wire [3:0] opcode;
wire [3:0] dest;
wire [3:0] sursa1;
wire [3:0] sursa2;
wire [7:0] instr_data;
wire [7:0] result;
wire [1:0] flags;
wire         pc_incr;
wire         pc_load;
wire         addr_load;
wire         sel_addr;
wire         sel_mem_data;
wire         sel_instr_data;
wire         ir_load_high;
wire         ir_load_low;
wire         regs_wen;
//-----------------------------------------------------------------------------
// address mux
assign addr = sel_addr ? data_addr : pc;
//-----------------------------------------------------------------------------
// PC
always @(posedge clk) begin
   if(rst)
       pc <= 0;
   else begin
       if(pc_load)
         pc <= common_data;
       else if(pc_incr)
         pc <= pc + 1;
       else
         pc <= pc;
   end
end
//-----------------------------------------------------------------------------
// ADDR
always @(posedge clk) begin
   if(rst)
        data_addr <= 0;
   else begin
        if(addr_load)
          data_addr <= common_data;
        else
          data_addr <= data_addr;
   end
end
//-----------------------------------------------------------------------------
// IR
always @(posedge clk) begin
   if(rst)
        instruction <= 0;
   else begin
        if(ir_load_high)
          instruction[15:8] <= common_data;
        else if(ir_load_low)
          instruction[ 7:0] <= common_data;
        else
          instruction <= instruction;
   end
end
//-----------------------------------------------------------------------------
// decode
assign opcode           = instruction[15:12];
assign dest           = instruction[11: 8];
assign sursa1          = instruction[ 7: 4];
assign sursa2          = addr_load ? instruction[ 7: 4] : instruction[ 3: 0];
assign instr_data = instruction[ 7: 0];
//-----------------------------------------------------------------------------
// common data mux
always @(*) begin
   if(sel_mem_data)
      common_data = data_in; // se selecteaz? data dinspre memorie
   else if(sel_instr_data)
      common_data = instr_data; // se selecteaz? constanta
   else
      common_data = result;                 // se selecteaz? rezultatul de la ALU
end
//-----------------------------------------------------------------------------
ralu ralu(
   .clk      (clk        ),
   .rst      (rst       ),
   .opcode (opcode                     ),
   .wen       (regs_wen ),
   .dest      (dest          ),
   .wdata      (common_data),
   .sursa1 (sursa1                ),
   .sursa2 (sursa2                ),
   .result (result           ),
   .flags (flags             )
);
//-----------------------------------------------------------------------------
assign data_out = result;
//-----------------------------------------------------------------------------
ucp ucp(
     .clk         (clk         ),
     .rst         (rst        ),
     .opcode         (opcode            ),
     .flags        (flags          ),
     .pc_incr       (pc_incr            ),
     .pc_load        (pc_load            ),
     .addr_load          (addr_load           ),
     .sel_addr       (sel_addr          ),
     .sel_mem_data (sel_mem_data ),
     .sel_instr_data (sel_instr_data),
     .ir_load_high (ir_load_high ),
     .ir_load_low (ir_load_low ),
     .regs_wen           (regs_wen            ),
     .write        (write           )
);
Endmodule
MEMORIE
module memory(
     input      clk,
     input      write,
     input [7:0] addr,
     input [7:0] din,
     output [7:0] dout
);
reg [7:0] memory [0:255];
// citire din memorie
assign dout = memory[addr];
// scriere in memorie
always @(posedge clk) if(write) memory[addr] <= din;
// program
initial begin
     {memory[00], memory[01]} = 16'b1000_0000_1111_1111; // LOADC R0 #255
     {memory[02], memory[03]} = 16'b1000_0001_1111_1110; // LOADC R1 #254
     {memory[04], memory[05]} = 16'b1000_0010_1111_1101; // LOADC R2 #253
     {memory[06], memory[07]} = 16'b1001_0100_0000_0000; // LOAD R4 R0
     {memory[08], memory[09]} = 16'b1001_0101_0001_0000; // LOAD R5 R1
     {memory[10], memory[11]} = 16'b0001_0110_0101_0100; // ADD R6 R5 R4
     {memory[12], memory[13]} = 16'b1010_0000_0010_0110; // STORE R2 R6
     {memory[14], memory[15]} = 16'b1111_1111_1111_1111; // HALT
end
// date initiale
initial begin
     memory[254] = 17;
     memory[255] = 23;
end
endmodule
NEUMANN
module neumann(
     input clk,
     input rst
);
wire         write;
wire [7:0] addr;
wire [7:0] data_from_mem;
wire [7:0] data_to_mem;
processor procesor(
     .clk    (clk      ),
     .rst    (rst     ),
     .data_in (data_from_mem),
     .data_out(data_to_mem ),
     .addr    (addr         ),
     .write (write          )
);
memory memorie(
     .clk     (clk        ),
     .write (write             ),
     .addr        (addr        ),
     .din     (data_to_mem ),
     .dout (data_from_mem)
);
Endmodule
NEUMANN_TB
module neumann_tb;
// declara?ii de variable
reg clk;
reg rst;
// instan?ierea calculatorului
neumann dut(
     .clk (clk),
     .rst (rst)
);
// generarea semnalului de ceas
initial begin
     clk = 0;
     forever #10 clk = ~clk;
end
// generarea semnalului de reset
initial begin
  rst = 0;
  #13 rst = 1; // reset activ în 1 logic
  #20 rst = 0;
end
// un bloc initial pentru oprirea simularii
initial begin
  repeat (100) @(posedge clk);
  $stop;
end
endmodule