/*  This is the verilog simulator for the computer
    which we will call CHAPTER5.  
    1. The picture for the computer's outline is 
       on page 130 of the text.
    2. The basic computer instructions are shown
       in Table 5-2 page 133 of the text.
    3. The complete specifications from which this
       verilog program is made are found in Table
       5-6 page 159 of the text.
*/
            

module CHAPTER5;

parameter            CYCLE = 20;
parameter            MEMWIDTH = 16;
parameter            REGWIDTH = 16;
parameter            ADDRSIZE = 12;
parameter            MEMSIZE = 1<<ADDRSIZE;
parameter            DSIZE   = 8;

reg [MEMWIDTH-1:0]   MEM[0:MEMSIZE];

reg [ADDRSIZE-1:0]   AR,PC;

reg [MEMWIDTH-1:0]   DR,AC,IR,TR;

reg [MEMWIDTH:0]     Result;

reg [DSIZE-1:0]      D;

reg I,E,TempE,S,SC;

reg [8*4:1] String;

integer i;

`define OPCODE       IR[15:12]
`define CCODE        IR[14:12]
`define ICODE        IR[15:15]
`define SRC          IR[11:0]

reg [MEMWIDTH-1:0]   result;

`define AND          4'h0
`define ADD          4'h1
`define LDA          4'h2
`define STA          4'h3
`define BUN          4'h4
`define BSA          4'h5
`define ISZ          4'h6

`define CLA           12'h800
`define CLE           12'h400
`define CMA           12'h200
`define CME           12'h100
`define CIR           12'h080
`define CIL           12'h040
`define INC           12'h020
`define SPA           12'h010
`define SNA           12'h008
`define SZA           12'h004
`define SZE           12'h002
`define HLT           12'h001

`define INP           16'hF800
`define OUT           16'hF400
`define SKI           16'hF200
`define SKO           16'hF100
`define ION           16'hF080
`define IOF           16'hF040


task T0;
begin
  AR = PC;
end
endtask

task T1;
begin
  IR = MEM[AR];
  PC =PC + 1;
end
endtask

task T2;
begin
  D = 1<<(`CCODE);
  AR = `SRC;
  I = `ICODE;
end
endtask

task executeRRI;
begin
  SC = 0;
  case(`SRC)
    `CLA:  AC = 16'h0000;
    `CLE:  E= 1'b0;
    `CMA:  AC = AC ^ 16'hFFFF;
    `CME:  E = ~E;
    `CIR:  begin
             TempE = E;
             E = AC[0];
             AC = AC>>1;
             AC[15] = TempE;
           end
    `CIL:  begin
             TempE = E;
             E = AC[15];
             AC = AC<<1;
             AC[0] = TempE;
           end
    `INC:  AC = AC +1;
    `SPA:  if (~AC[15])
             PC = PC + 1;
    `SNA:  if (AC[15])
             PC = PC + 1;
    `SZA:  if (~(|AC))
             PC = PC + 1;
    `SZE:  if (~E)
             PC = PC + 1;
    `HLT:  S = 0;
  endcase   
end
endtask


task executeIOI;
begin

/*
  This part is not done yet.
*/

end
endtask


task T3;
begin
  if (~D[7])
    begin
      if (I)
        AR = MEM[AR];
    end
  else
    begin
      if (~I)
        executeRRI;
      else
        executeIOI;
    end
end
endtask

task T4;
begin
  if (D[0] | D[1] | D[2])
    DR = MEM[AR];
  else if (D[3])
    begin
      MEM[AR] = AC;
      SC = 0;
    end
  else if (D[4])
    begin
      PC = AR;
      SC = 0;
    end
  else if (D[5])
    begin
      MEM[AR] = PC;
      AR = AR + 1;
    end
  else if (D[6])
    begin
      DR = MEM[AR];
    end
end
endtask

task T5;
begin
  if (D[0])
    begin
      AC = AC & DR;
      SC = 0;
    end
  else if (D[1])
    begin
      Result = AC + DR;
      E = Result[16];
      AC = Result[15:0];
      SC = 0;
    end
  else if (D[2])
    begin
      AC = DR;
      SC = 0;
    end
  else if (D[5])
    begin
      PC = AR;
      SC = 0;
    end
  else if (D[6])
    begin
      DR = DR + 1;
    end
end
endtask

task T6;
begin
  if (D[6])
    begin
      MEM[AR] = DR;
      if (~(|DR))
        PC = PC + 1;
      SC = 0;
    end
end
endtask

task apply_reset;
begin
  S = 1;
  PC = 0;
end
endtask

task make_string;
begin
  case(`CCODE)
    0:  String = "AND";
    1:  String = "ADD";
    2:  String = "LDA";
    3:  String = "STA";
    4:  String = "BUN";
    5:  String = "BSA";
    6:  String = "ISZ";
    7: 
      begin
        case(`SRC)
          12'h800: String = "CLA";
          12'h400: String = "CLE";
          12'h200: String = "CMA";
          12'h100: String = "CME";
          12'h080: String = "CIR";
          12'h040: String = "CIL";
          12'h020: String = "INC";
          12'h010: String = "SPA";
          12'h008: String = "SNA";
          12'h004: String = "SZA";
          12'h002: String = "SZE";
          12'h001: String = "HLT";
        endcase
      end
    8:  String = "AND";
    9:  String = "ADD";
    10:  String = "LDA";
    11:  String = "STA";
    12:  String = "BUN";
    13:  String = "BSA";
    14:  String = "ISZ";
    15:  String = "IOI";
  endcase
end
endtask

initial
  begin               :  prog_load
    $readmemb("CHAPTER5.bin",MEM);
    $display("\n\n    PC  AR         DR               AC               IR       E\n");
    apply_reset;
  end

always
  begin               : main_loop
    SC = 1;
    #CYCLE T0;
    $display("T0 %h %h %b %b %b %b",PC,AR,DR,AC,IR,E);
    #CYCLE T1;
/*
    $display("T1 %h %h %b %b %b %b",PC,AR,DR,AC,IR,E);
*/
    #CYCLE T2;
/*
    $display("T2 %h %h %b %b %b %b",PC,AR,DR,AC,IR,E);
*/
    #CYCLE T3;
/*
    $display("T3 %h %h %b %b %b %b",PC,AR,DR,AC,IR,E);
*/
    if (SC)
      begin
        #CYCLE T4;
/*
        $display("T4 %h %h %b %b %b %b",PC,AR,DR,AC,IR,E);
*/
      end
    if (SC)
      begin
        #CYCLE T5;
/*
        $display("T5 %h %h %b %b %b %b",PC,AR,DR,AC,IR,E);
*/
      end
    if (SC)
      begin
        #CYCLE T6;
/*
        $display("T6 %h %h %b %b %b %b",PC,AR,DR,AC,IR,E);
*/
      end
    make_string;      
if ((`OPCODE==4'b0111) || (`OPCODE==4'b1111))
  $display("   PC  AC      DR=%h          AC=%h          IR=%h    E=%b %s",DR,AC,IR,E,String);  
else
  begin
  if (`ICODE==1'b1)
    $display("   PC  AC      DR=%h          AC=%h          IR=%h    E=%b %s %h I",DR,AC,IR,E,String,`SRC);
  else
    $display("   PC  AC      DR=%h          AC=%h          IR=%h    E=%b %s %h",DR,AC,IR,E,String,`SRC);
  end
if (~S)
  begin
    $display("   PC  AC      DR=%h          AC=%d (decimal)",DR,AC );
    $finish;
  end

  end
endmodule



