1 |
2 |
ayersg |
`timescale 1ns / 1ps
|
2 |
|
|
/*
|
3 |
|
|
* File : MemControl.v
|
4 |
|
|
* Project : University of Utah, XUM Project MIPS32 core
|
5 |
|
|
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
6 |
|
|
*
|
7 |
|
|
* Modification History:
|
8 |
|
|
* Rev Date Initials Description of Change
|
9 |
|
|
* 1.0 24-Jun-2011 GEA Initial design.
|
10 |
|
|
* 2.0 28-Jun-2012 GEA Expanded from a simple byte/half/word unit to
|
11 |
|
|
* An advanced data memory controller capable of
|
12 |
|
|
* handling big/little endian, atomic and unaligned
|
13 |
|
|
* memory accesses.
|
14 |
|
|
*
|
15 |
|
|
* Standards/Formatting:
|
16 |
|
|
* Verilog 2001, 4 soft tab, wide column.
|
17 |
|
|
*
|
18 |
|
|
* Description:
|
19 |
|
|
* A Data Memory Controller which handles all read and write requests from the
|
20 |
|
|
* processor to data memory. All data accesses--whether big endian, little endian,
|
21 |
|
|
* byte, half, word, or unaligned transfers--are transformed into a simple read
|
22 |
|
|
* and write command to data memory over a 32-bit data bus, where the read command
|
23 |
|
|
* is one bit and the write command is 4 bits, one for each byte in the 32-bit word.
|
24 |
|
|
*/
|
25 |
|
|
module MemControl(
|
26 |
|
|
input clock,
|
27 |
|
|
input reset,
|
28 |
|
|
input [31:0] DataIn, // Data from CPU
|
29 |
|
|
input [31:0] Address, // From CPU
|
30 |
|
|
input [31:0] MReadData, // Data from Memory
|
31 |
|
|
input MemRead, // Memory Read command from CPU
|
32 |
|
|
input MemWrite, // Memory Write command from CPU
|
33 |
|
|
input DataMem_Ready, // Ready signal from Memory
|
34 |
|
|
input Byte, // Load/Store is Byte (8-bit)
|
35 |
|
|
input Half, // Load/Store is Half (16-bit)
|
36 |
|
|
input SignExtend, // Sub-word load should be sign extended
|
37 |
|
|
input KernelMode, // (Exception logic)
|
38 |
|
|
input ReverseEndian, // Reverse Endian Memory for User Mode
|
39 |
|
|
input LLSC, // (LLSC logic)
|
40 |
|
|
input ERET, // (LLSC logic)
|
41 |
|
|
input Left, // Unaligned Load/Store Word Left
|
42 |
|
|
input Right, // Unaligned Load/Store Word Right
|
43 |
|
|
input M_Exception_Stall,
|
44 |
|
|
input IF_Stall, // XXX Clean this up between this module and HAZ/FWD
|
45 |
|
|
output reg [31:0] DataOut, // Data to CPU
|
46 |
|
|
output [31:0] MWriteData, // Data to Memory
|
47 |
|
|
output reg [3:0] WriteEnable, // Write Enable to Memory for each of 4 bytes of Memory
|
48 |
|
|
output ReadEnable, // Read Enable to Memory
|
49 |
|
|
output M_Stall,
|
50 |
|
|
output EXC_AdEL, // Load Exception
|
51 |
|
|
output EXC_AdES // Store Exception
|
52 |
|
|
);
|
53 |
|
|
|
54 |
|
|
`include "MIPS_Parameters.v"
|
55 |
|
|
|
56 |
|
|
/*** Reverse Endian Mode
|
57 |
|
|
Normal memory accesses in the processor are Big Endian. The endianness can be reversed
|
58 |
|
|
to Little Endian in User Mode only.
|
59 |
|
|
*/
|
60 |
|
|
wire BE = KernelMode | ~ReverseEndian;
|
61 |
|
|
|
62 |
|
|
/*** Indicator that the current memory reference must be word-aligned ***/
|
63 |
|
|
wire Word = ~(Half | Byte | Left | Right);
|
64 |
|
|
|
65 |
|
|
// Exception Detection
|
66 |
|
|
wire EXC_KernelMem = ~KernelMode & (Address < UMem_Lower);
|
67 |
|
|
wire EXC_Word = Word & (Address[1] | Address[0]);
|
68 |
|
|
wire EXC_Half = Half & Address[0];
|
69 |
|
|
assign EXC_AdEL = MemRead & (EXC_KernelMem | EXC_Word | EXC_Half);
|
70 |
|
|
assign EXC_AdES = MemWrite & (EXC_KernelMem | EXC_Word | EXC_Half);
|
71 |
|
|
|
72 |
|
|
/*** Load Linked and Store Conditional logic ***
|
73 |
|
|
|
74 |
|
|
A 32-bit register keeps track of the address for atomic Load Linked / Store Conditional
|
75 |
|
|
operations. This register can be updated during stalls since it is not visible to
|
76 |
|
|
forward stages. It does not need to be flushed during exceptions, since ERET destroys
|
77 |
|
|
the atomicity condition and there are no detrimental effects in an exception handler.
|
78 |
|
|
|
79 |
|
|
The atomic condition is set with a Load Linked instruction, and cleared on an ERET
|
80 |
|
|
instruction or when any store instruction writes to one or more bytes covered by
|
81 |
|
|
the word address register. It does not update on a stall condition.
|
82 |
|
|
|
83 |
|
|
The MIPS32 spec states that an ERET instruction between LL and SC will cause the
|
84 |
|
|
atomicity condition to fail. This implementation uses the ERET signal from the ID
|
85 |
|
|
stage, which means instruction sequences such as "LL SC" could appear to have an
|
86 |
|
|
ERET instruction between them even though they don't. One way to fix this is to pass
|
87 |
|
|
the ERET signal through the pipeline to the MEM stage. However, because of the nature
|
88 |
|
|
of LL/SC operations (they occur in a loop which checks the result at each iteration),
|
89 |
|
|
an ERET will normally never be inserted into the pipeline programmatically until the
|
90 |
|
|
LL/SC sequence has completed (exceptions such as interrupts can still cause ERET, but
|
91 |
|
|
they can still cause them in the LL SC sequence as well). In other words, by not passing
|
92 |
|
|
ERET through the pipeline, the only possible effect is a performance penalty. Also this
|
93 |
|
|
may be irrelevant since currently ERET stalls for forward stages which can cause exceptions,
|
94 |
|
|
which includes LL and SC.
|
95 |
|
|
*/
|
96 |
|
|
reg [29:0] LLSC_Address;
|
97 |
|
|
reg LLSC_Atomic;
|
98 |
|
|
wire LLSC_MemWrite_Mask;
|
99 |
|
|
|
100 |
|
|
always @(posedge clock) begin
|
101 |
|
|
LLSC_Address <= (reset) ? 30'b0 : (MemRead & LLSC) ? Address[31:2] : LLSC_Address;
|
102 |
|
|
end
|
103 |
|
|
|
104 |
|
|
always @(posedge clock) begin
|
105 |
|
|
if (reset) begin
|
106 |
|
|
LLSC_Atomic <= 0;
|
107 |
|
|
end
|
108 |
|
|
else if (MemRead) begin
|
109 |
|
|
LLSC_Atomic <= (LLSC) ? 1 : LLSC_Atomic;
|
110 |
|
|
end
|
111 |
|
|
// XXX GEA Bug for Ganesh: remove "& ~IF_Stall" from below, then SC will always fail:
|
112 |
|
|
else if (ERET | (~M_Stall & ~IF_Stall & MemWrite & (Address[31:2] == LLSC_Address))) begin
|
113 |
|
|
LLSC_Atomic <= 0;
|
114 |
|
|
end
|
115 |
|
|
else begin
|
116 |
|
|
LLSC_Atomic <= LLSC_Atomic;
|
117 |
|
|
end
|
118 |
|
|
end
|
119 |
|
|
assign LLSC_MemWrite_Mask = (LLSC & MemWrite & (~LLSC_Atomic | (Address[31:2] != LLSC_Address)));
|
120 |
|
|
|
121 |
|
|
wire WriteCondition = MemWrite & ~(EXC_KernelMem | EXC_Word | EXC_Half) & ~LLSC_MemWrite_Mask;
|
122 |
|
|
wire ReadCondition = MemRead & ~(EXC_KernelMem | EXC_Word | EXC_Half);
|
123 |
|
|
|
124 |
|
|
reg RW_Mask;
|
125 |
|
|
always @(posedge clock) begin
|
126 |
|
|
RW_Mask <= (reset) ? 0 : (((MemWrite | MemRead) & DataMem_Ready) ? 1 : ((~M_Stall & ~IF_Stall) ? 0 : RW_Mask));
|
127 |
|
|
end
|
128 |
|
|
assign M_Stall = ReadEnable | (WriteEnable != 4'b0000) | DataMem_Ready | M_Exception_Stall;
|
129 |
|
|
assign ReadEnable = ReadCondition & ~RW_Mask;
|
130 |
|
|
|
131 |
|
|
wire Half_Access_L = (Address[1] ^ BE);
|
132 |
|
|
wire Half_Access_R = (Address[1] ~^ BE);
|
133 |
|
|
wire Byte_Access_LL = Half_Access_L & (Address[1] ~^ Address[0]);
|
134 |
|
|
wire Byte_Access_LM = Half_Access_L & (Address[0] ~^ BE);
|
135 |
|
|
wire Byte_Access_RM = Half_Access_R & (Address[0] ^ BE);
|
136 |
|
|
wire Byte_Access_RR = Half_Access_R & (Address[1] ~^ Address[0]);
|
137 |
|
|
|
138 |
|
|
// Write-Enable Signals to Memory
|
139 |
|
|
always @(*) begin
|
140 |
|
|
if (WriteCondition & ~RW_Mask) begin
|
141 |
|
|
if (Byte) begin
|
142 |
|
|
WriteEnable[3] <= Byte_Access_LL;
|
143 |
|
|
WriteEnable[2] <= Byte_Access_LM;
|
144 |
|
|
WriteEnable[1] <= Byte_Access_RM;
|
145 |
|
|
WriteEnable[0] <= Byte_Access_RR;
|
146 |
|
|
end
|
147 |
|
|
else if (Half) begin
|
148 |
|
|
WriteEnable[3] <= Half_Access_L;
|
149 |
|
|
WriteEnable[2] <= Half_Access_L;
|
150 |
|
|
WriteEnable[1] <= Half_Access_R;
|
151 |
|
|
WriteEnable[0] <= Half_Access_R;
|
152 |
|
|
end
|
153 |
|
|
else if (Left) begin
|
154 |
|
|
case (Address[1:0])
|
155 |
|
|
2'b00 : WriteEnable <= (BE) ? 4'b1111 : 4'b0001;
|
156 |
|
|
2'b01 : WriteEnable <= (BE) ? 4'b0111 : 4'b0011;
|
157 |
|
|
2'b10 : WriteEnable <= (BE) ? 4'b0011 : 4'b0111;
|
158 |
|
|
2'b11 : WriteEnable <= (BE) ? 4'b0001 : 4'b1111;
|
159 |
|
|
endcase
|
160 |
|
|
end
|
161 |
|
|
else if (Right) begin
|
162 |
|
|
case (Address[1:0])
|
163 |
|
|
2'b00 : WriteEnable <= (BE) ? 4'b1000 : 4'b1111;
|
164 |
|
|
2'b01 : WriteEnable <= (BE) ? 4'b1100 : 4'b1110;
|
165 |
|
|
2'b10 : WriteEnable <= (BE) ? 4'b1110 : 4'b1100;
|
166 |
|
|
2'b11 : WriteEnable <= (BE) ? 4'b1111 : 4'b1000;
|
167 |
|
|
endcase
|
168 |
|
|
end
|
169 |
|
|
else begin
|
170 |
|
|
WriteEnable <= 4'b1111;
|
171 |
|
|
end
|
172 |
|
|
end
|
173 |
|
|
else begin
|
174 |
|
|
WriteEnable <= 4'b0000;
|
175 |
|
|
end
|
176 |
|
|
end
|
177 |
|
|
|
178 |
|
|
// Data Going to Memory
|
179 |
|
|
assign MWriteData[31:24] = (Byte) ? DataIn[7:0] : ((Half) ? DataIn[15:8] : DataIn[31:24]);
|
180 |
|
|
assign MWriteData[23:16] = (Byte | Half) ? DataIn[7:0] : DataIn[23:16];
|
181 |
|
|
assign MWriteData[15:8] = (Byte) ? DataIn[7:0] : DataIn[15:8];
|
182 |
|
|
assign MWriteData[7:0] = DataIn[7:0];
|
183 |
|
|
|
184 |
|
|
// Data Read from Memory
|
185 |
|
|
always @(*) begin
|
186 |
|
|
if (Byte) begin
|
187 |
|
|
if (Byte_Access_LL) begin
|
188 |
|
|
DataOut <= (SignExtend & MReadData[31]) ? {24'hFFFFFF, MReadData[31:24]} : {24'h000000, MReadData[31:24]};
|
189 |
|
|
end
|
190 |
|
|
else if (Byte_Access_LM) begin
|
191 |
|
|
DataOut <= (SignExtend & MReadData[23]) ? {24'hFFFFFF, MReadData[23:16]} : {24'h000000, MReadData[23:16]};
|
192 |
|
|
end
|
193 |
|
|
else if (Byte_Access_RM) begin
|
194 |
|
|
DataOut <= (SignExtend & MReadData[15]) ? {24'hFFFFFF, MReadData[15:8]} : {24'h000000, MReadData[15:8]};
|
195 |
|
|
end
|
196 |
|
|
else begin
|
197 |
|
|
DataOut <= (SignExtend & MReadData[7]) ? {24'hFFFFFF, MReadData[7:0]} : {24'h000000, MReadData[7:0]};
|
198 |
|
|
end
|
199 |
|
|
end
|
200 |
|
|
else if (Half) begin
|
201 |
|
|
if (Half_Access_L) begin
|
202 |
|
|
DataOut <= (SignExtend & MReadData[31]) ? {16'hFFFF, MReadData[31:16]} : {16'h0000, MReadData[31:16]};
|
203 |
|
|
end
|
204 |
|
|
else begin
|
205 |
|
|
DataOut <= (SignExtend & MReadData[15]) ? {16'hFFFF, MReadData[15:0]} : {16'h0000, MReadData[15:0]};
|
206 |
|
|
end
|
207 |
|
|
end
|
208 |
|
|
else if (LLSC & MemWrite) begin
|
209 |
|
|
DataOut <= (LLSC_Atomic & (Address[31:2] == LLSC_Address)) ? 32'h0000_0001 : 32'h0000_0000;
|
210 |
|
|
end
|
211 |
|
|
else if (Left) begin
|
212 |
|
|
case (Address[1:0])
|
213 |
|
|
2'b00 : DataOut <= (BE) ? MReadData : {MReadData[7:0], DataIn[23:0]};
|
214 |
|
|
2'b01 : DataOut <= (BE) ? {MReadData[23:0], DataIn[7:0]} : {MReadData[15:0], DataIn[15:0]};
|
215 |
|
|
2'b10 : DataOut <= (BE) ? {MReadData[15:0], DataIn[15:0]} : {MReadData[23:0], DataIn[7:0]};
|
216 |
|
|
2'b11 : DataOut <= (BE) ? {MReadData[7:0], DataIn[23:0]} : MReadData;
|
217 |
|
|
endcase
|
218 |
|
|
end
|
219 |
|
|
else if (Right) begin
|
220 |
|
|
case (Address[1:0])
|
221 |
|
|
2'b00 : DataOut <= (BE) ? {DataIn[31:8], MReadData[31:24]} : MReadData;
|
222 |
|
|
2'b01 : DataOut <= (BE) ? {DataIn[31:16], MReadData[31:16]} : {DataIn[31:24], MReadData[31:8]};
|
223 |
|
|
2'b10 : DataOut <= (BE) ? {DataIn[31:24], MReadData[31:8]} : {DataIn[31:16], MReadData[31:16]};
|
224 |
|
|
2'b11 : DataOut <= (BE) ? MReadData : {DataIn[31:8], MReadData[31:24]};
|
225 |
|
|
endcase
|
226 |
|
|
end
|
227 |
|
|
else begin
|
228 |
|
|
DataOut <= MReadData;
|
229 |
|
|
end
|
230 |
|
|
end
|
231 |
|
|
|
232 |
|
|
endmodule
|
233 |
3 |
ayersg |
|