aboutsummaryrefslogtreecommitdiffstats
path: root/ee4363/mp2/mipspipe_mp2.v
blob: 9ea9fc21142e36fe1551d3d2bd14a2d0ab37f53f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Incomplete behavioral model of MIPS pipeline

module mipspipe_mp2 (clock);
  // in_out
  input clock;

  // Instruction opcodes
  parameter LW = 6'b100011, SW = 6'b101011, BEQ = 6'b000100, nop = 32'b00000_100000, ALUop = 6'b0;
  reg [31:0] PC, Regs[0:31], IMemory[0:1023], DMemory[0:1023], // instruction and data memories
             IFIDIR, IDEXA, IDEXB, IDEXIR, EXMEMIR, EXMEMB, // pipeline latches
             EXMEMALUOut, MEMWBValue, MEMWBIR;

  wire [4:0] IDEXrs, IDEXrt, EXMEMrd, MEMWBrd, MEMWBrt, IFIDrt, IFIDrs; // hold register fields
  wire [5:0] EXMEMop, MEMWBop, IDEXop, IFIDop; // hold opcodes
  wire [31:0] Ain, Bin; // ALU inputs

  // declare the bypass signals
  wire bypassAfromMEM, bypassAfromALUinWB, bypassBfromMEM, bypassBfromALUinWB, bypassAfromLWinWB, bypassBfromLWinWB, bypassIDEXAfromWB, bypassIDEXBfromWB, STALL;

   // Define fields of pipeline latches
   assign IDEXrs = IDEXIR[25:21]; // rs field
   assign IDEXrt = IDEXIR[20:16]; // rt field
   assign EXMEMrd = EXMEMIR[15:11]; // rd field
   assign MEMWBrd = MEMWBIR[15:11]; // rd field
   assign MEMWBrt = MEMWBIR[20:16]; // rt field -- for loads
   assign EXMEMop = EXMEMIR[31:26]; // opcode
   assign MEMWBop = MEMWBIR[31:26]; // opcode
   assign IDEXop = IDEXIR[31:26]; // opcode
   assign IFIDrs = IFIDIR[25:21];
   assign IFIDrt = IFIDIR[20:16];
   assign IFIDop = IFIDIR[31:26]; 


  // The bypass to input A from the MEM stage for an ALU operation
  assign bypassAfromMEM = (IDEXrs == EXMEMrd) & (IDEXrs!=0) & (EXMEMop==ALUop);
  // The bypass to input B from the MEM stage for an ALU operation
  assign bypassBfromMEM = 0;
  // The bypass to input A from the WB stage for an ALU operation
  assign bypassAfromALUinWB = 0;
  // The bypass to input B from the WB stage for an ALU operation
  assign bypassBfromALUinWB = 0; 
  // The bypass to input A from the WB stage for an LW operation
  assign bypassAfromLWinWB = (IDEXrs == MEMWBIR[20:16]) & (IDEXrs!=0) & (MEMWBop==LW);
  // The bypass to input B from the WB stage for an LW operation
  assign bypassBfromLWinWB = 0;
  //Stall to bypass A or B if need b (I'm not sorry)
  assign bypassIDEXAfromWB = ((MEMWBIR != nop) & (IFIDIR != nop) & (IFIDrs == MEMWBrt) & (MEMWBop == LW)) | 
    ((MEMWBop == ALUop) & (MEMWBrd == IFIDrs)); 
  assign bypassIDEXBfromWB = ((MEMWBIR != nop) & (IFIDIR != nop) & (IFIDrt == MEMWBrt) & (MEMWBop == LW)) | 
    ((MEMWBop == ALUop) & (MEMWBrd == IFIDrt)); 
  // The A input to the ALU is bypassed from MEM if there is a bypass there,
  // Otherwise from WB if there is a bypass there, and otherwise comes from the IDEX register
  assign Ain = bypassAfromMEM? EXMEMALUOut : (bypassAfromALUinWB | bypassAfromLWinWB)? MEMWBValue : IDEXA;

  // The B input to the ALU is bypassed from MEM if there is a bypass there,
  // Otherwise from WB if there is a bypass there, and otherwise comes from the IDEX register
  // Ripped off of above just replacing "A" with "B"
  assign Bin = bypassBfromMEM? EXMEMALUOut : (bypassBfromALUinWB | bypassBfromLWinWB)? MEMWBValue : IDEXB;


  reg [5:0] i; // used to initialize latches
  reg [10:0] j,k; // used to initialize memories

  // Make the Big Stall
  assign STALL = (IDEXop == LW) && 
    //All of this is anded with the above (Lisp would be proud)
    (((IFIDop == LW) && (IFIDrs == IDEXrt)) |
    ((IFIDop == ALUop) && ((IFIDrs == IDEXrt) | (IFIDrt == IDEXrt))) |
    ((IFIDop == SW) && ((IFIDrs == IDEXrt) | (IFIDrt == IDEXrt))));
  
  initial begin
    PC = 0;
    IFIDIR = nop; 
    IDEXIR = nop; 
    EXMEMIR = nop; 
    MEMWBIR = nop; // no-ops in pipeline latches
  
    for (i = 0;i<=31;i = i+1) Regs[i] = i; // initialize latches
  
    IMemory[0] = 32'h00412820; // ADD $5, $2, $1
    IMemory[1] = 32'h8ca30004; // LW $3, 4($5)
    IMemory[2] = 32'haca70005; // SW $7, 5($5)
    // Hazard 1: ADD might not have written to $5 before SW reads from $5 (Type 2: Read after Write)
    IMemory[3] = 32'h00602020; // ADD $4, $3, $0
    // Hazard 2: ADD might read $3 before LW writes to $3 (Type 3: Write after read)
    IMemory[4] = 32'h01093020; // ADD $6, $8, $9
    IMemory[5] = 32'hac06000c; // SW $6, $12($0)
    // Hazard 3: ADD and SW are trying to access the same register (Type 1: Write after Write)
    IMemory[6] = 32'h00c05020; // ADD $10, $6, $0
    // Hazard 4: ADD reads from $6 and is written to (twice) immediately beforehand (Type 2: Read after Write)
    IMemory[7] = 32'h8c0b0010; // LW $11, 32($0)
    IMemory[8] = 32'h00000020; // ADD $0, $0, $0
    IMemory[9] = 32'h002b6020; // ADD $12, $1, $11
    // Hazard 5: LW might not have written to $11 before the last ADD reads from $11 (Type 2: Read after Write)
    for (j=10; j<=1023; j=j+1) IMemory[j] = nop;
    
    DMemory[0] = 32'h00000000;
    DMemory[1] = 32'hffffffff;
    DMemory[2] = 32'h00000000;
    DMemory[3] = 32'h00000000;
    DMemory[4] = 32'hfffffffe;
    for (k=5; k<=1023; k=k+1) DMemory[k] = 0;
  end

  always @ (posedge clock) begin
    if (~STALL) begin
	  // FETCH: Fetch instruction & update PC
      IFIDIR <= IMemory[PC>>2];
      PC <= PC + 4;

      // DECODE: Read registers
      if (~bypassIDEXAfromWB) begin
        IDEXA <= Regs[IFIDIR[25:21]]; 
      end 
       else begin
          IDEXA <= MEMWBValue;
      end

      if (~bypassIDEXBfromWB) begin
        IDEXB <= Regs[IFIDIR[20:16]];
      end 
       else begin
        IDEXB <= MEMWBValue;
      end
        IDEXIR <= IFIDIR; 
    end 
     else begin //IF (STALL)
        IDEXIR <= nop;
    end

    // EX: Address calculation or ALU operation
    if ((IDEXop==LW) |(IDEXop==SW)) // address calculation & copy B
       EXMEMALUOut <= Ain +{{16{IDEXIR[15]}}, IDEXIR[15:0]};
    else if (IDEXop==ALUop) begin
       case (IDEXIR[5:0]) // R-type instruction
         32: EXMEMALUOut <= Ain + Bin; // add operation
         default: ; // other R-type operations: subtract, SLT, etc.
       endcase
    end
   
    EXMEMIR <= IDEXIR; 
    EXMEMB <= Bin; // pass along the IR & B register
   
    // MEM
    if (EXMEMop==ALUop) MEMWBValue <= EXMEMALUOut; // pass along ALU result
    else if (EXMEMop == LW) MEMWBValue <= DMemory[EXMEMALUOut>>2];
    else if (EXMEMop == SW) DMemory[EXMEMALUOut>>2] <=EXMEMB; // store
   
    MEMWBIR <= EXMEMIR; // pass along IR
   
    // WB 
    if ((MEMWBop==ALUop) & (MEMWBrd != 0)) // update latches if ALU operation and destination not 0
    Regs[MEMWBrd] <= MEMWBValue; // ALU operation
    else if ((MEMWBop == LW)& (MEMWBrt != 0)) // Update latches if load and destination not 0
    Regs[MEMWBrt] <= MEMWBValue;
  end

endmodule