`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
/*
|
/*
|
* File : MemControl.v
|
* File : MemControl.v
|
* Project : University of Utah, XUM Project MIPS32 core
|
* Project : University of Utah, XUM Project MIPS32 core
|
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
*
|
*
|
* Modification History:
|
* Modification History:
|
* Rev Date Initials Description of Change
|
* Rev Date Initials Description of Change
|
* 1.0 24-Jun-2011 GEA Initial design.
|
* 1.0 24-Jun-2011 GEA Initial design.
|
* 2.0 28-Jun-2012 GEA Expanded from a simple byte/half/word unit to
|
* 2.0 28-Jun-2012 GEA Expanded from a simple byte/half/word unit to
|
* An advanced data memory controller capable of
|
* An advanced data memory controller capable of
|
* handling big/little endian, atomic and unaligned
|
* handling big/little endian, atomic and unaligned
|
* memory accesses.
|
* memory accesses.
|
*
|
*
|
* Standards/Formatting:
|
* Standards/Formatting:
|
* Verilog 2001, 4 soft tab, wide column.
|
* Verilog 2001, 4 soft tab, wide column.
|
*
|
*
|
* Description:
|
* Description:
|
* A Data Memory Controller which handles all read and write requests from the
|
* A Data Memory Controller which handles all read and write requests from the
|
* processor to data memory. All data accesses--whether big endian, little endian,
|
* processor to data memory. All data accesses--whether big endian, little endian,
|
* byte, half, word, or unaligned transfers--are transformed into a simple read
|
* byte, half, word, or unaligned transfers--are transformed into a simple read
|
* and write command to data memory over a 32-bit data bus, where the read command
|
* and write command to data memory over a 32-bit data bus, where the read command
|
* is one bit and the write command is 4 bits, one for each byte in the 32-bit word.
|
* is one bit and the write command is 4 bits, one for each byte in the 32-bit word.
|
*/
|
*/
|
module MemControl(
|
module MemControl(
|
input clock,
|
input clock,
|
input reset,
|
input reset,
|
input [31:0] DataIn, // Data from CPU
|
input [31:0] DataIn, // Data from CPU
|
input [31:0] Address, // From CPU
|
input [31:0] Address, // From CPU
|
input [31:0] MReadData, // Data from Memory
|
input [31:0] MReadData, // Data from Memory
|
input MemRead, // Memory Read command from CPU
|
input MemRead, // Memory Read command from CPU
|
input MemWrite, // Memory Write command from CPU
|
input MemWrite, // Memory Write command from CPU
|
input DataMem_Ready, // Ready signal from Memory
|
input DataMem_Ready, // Ready signal from Memory
|
input Byte, // Load/Store is Byte (8-bit)
|
input Byte, // Load/Store is Byte (8-bit)
|
input Half, // Load/Store is Half (16-bit)
|
input Half, // Load/Store is Half (16-bit)
|
input SignExtend, // Sub-word load should be sign extended
|
input SignExtend, // Sub-word load should be sign extended
|
input KernelMode, // (Exception logic)
|
input KernelMode, // (Exception logic)
|
input ReverseEndian, // Reverse Endian Memory for User Mode
|
input ReverseEndian, // Reverse Endian Memory for User Mode
|
input LLSC, // (LLSC logic)
|
input LLSC, // (LLSC logic)
|
input ERET, // (LLSC logic)
|
input ERET, // (LLSC logic)
|
input Left, // Unaligned Load/Store Word Left
|
input Left, // Unaligned Load/Store Word Left
|
input Right, // Unaligned Load/Store Word Right
|
input Right, // Unaligned Load/Store Word Right
|
input M_Exception_Stall,
|
input M_Exception_Stall,
|
input IF_Stall, // XXX Clean this up between this module and HAZ/FWD
|
input IF_Stall, // XXX Clean this up between this module and HAZ/FWD
|
output reg [31:0] DataOut, // Data to CPU
|
output reg [31:0] DataOut, // Data to CPU
|
output [31:0] MWriteData, // Data to Memory
|
output [31:0] MWriteData, // Data to Memory
|
output reg [3:0] WriteEnable, // Write Enable to Memory for each of 4 bytes of Memory
|
output reg [3:0] WriteEnable, // Write Enable to Memory for each of 4 bytes of Memory
|
output ReadEnable, // Read Enable to Memory
|
output ReadEnable, // Read Enable to Memory
|
output M_Stall,
|
output M_Stall,
|
output EXC_AdEL, // Load Exception
|
output EXC_AdEL, // Load Exception
|
output EXC_AdES // Store Exception
|
output EXC_AdES // Store Exception
|
);
|
);
|
|
|
`include "MIPS_Parameters.v"
|
`include "MIPS_Parameters.v"
|
|
|
/*** Reverse Endian Mode
|
/*** Reverse Endian Mode
|
Normal memory accesses in the processor are Big Endian. The endianness can be reversed
|
Normal memory accesses in the processor are Big Endian. The endianness can be reversed
|
to Little Endian in User Mode only.
|
to Little Endian in User Mode only.
|
*/
|
*/
|
wire BE = KernelMode | ~ReverseEndian;
|
wire BE = KernelMode | ~ReverseEndian;
|
|
|
/*** Indicator that the current memory reference must be word-aligned ***/
|
/*** Indicator that the current memory reference must be word-aligned ***/
|
wire Word = ~(Half | Byte | Left | Right);
|
wire Word = ~(Half | Byte | Left | Right);
|
|
|
// Exception Detection
|
// Exception Detection
|
wire EXC_KernelMem = ~KernelMode & (Address < UMem_Lower);
|
wire EXC_KernelMem = ~KernelMode & (Address < UMem_Lower);
|
wire EXC_Word = Word & (Address[1] | Address[0]);
|
wire EXC_Word = Word & (Address[1] | Address[0]);
|
wire EXC_Half = Half & Address[0];
|
wire EXC_Half = Half & Address[0];
|
assign EXC_AdEL = MemRead & (EXC_KernelMem | EXC_Word | EXC_Half);
|
assign EXC_AdEL = MemRead & (EXC_KernelMem | EXC_Word | EXC_Half);
|
assign EXC_AdES = MemWrite & (EXC_KernelMem | EXC_Word | EXC_Half);
|
assign EXC_AdES = MemWrite & (EXC_KernelMem | EXC_Word | EXC_Half);
|
|
|
/*** Load Linked and Store Conditional logic ***
|
/*** Load Linked and Store Conditional logic ***
|
|
|
A 32-bit register keeps track of the address for atomic Load Linked / Store Conditional
|
A 32-bit register keeps track of the address for atomic Load Linked / Store Conditional
|
operations. This register can be updated during stalls since it is not visible to
|
operations. This register can be updated during stalls since it is not visible to
|
forward stages. It does not need to be flushed during exceptions, since ERET destroys
|
forward stages. It does not need to be flushed during exceptions, since ERET destroys
|
the atomicity condition and there are no detrimental effects in an exception handler.
|
the atomicity condition and there are no detrimental effects in an exception handler.
|
|
|
The atomic condition is set with a Load Linked instruction, and cleared on an ERET
|
The atomic condition is set with a Load Linked instruction, and cleared on an ERET
|
instruction or when any store instruction writes to one or more bytes covered by
|
instruction or when any store instruction writes to one or more bytes covered by
|
the word address register. It does not update on a stall condition.
|
the word address register. It does not update on a stall condition.
|
|
|
The MIPS32 spec states that an ERET instruction between LL and SC will cause the
|
The MIPS32 spec states that an ERET instruction between LL and SC will cause the
|
atomicity condition to fail. This implementation uses the ERET signal from the ID
|
atomicity condition to fail. This implementation uses the ERET signal from the ID
|
stage, which means instruction sequences such as "LL SC" could appear to have an
|
stage, which means instruction sequences such as "LL SC" could appear to have an
|
ERET instruction between them even though they don't. One way to fix this is to pass
|
ERET instruction between them even though they don't. One way to fix this is to pass
|
the ERET signal through the pipeline to the MEM stage. However, because of the nature
|
the ERET signal through the pipeline to the MEM stage. However, because of the nature
|
of LL/SC operations (they occur in a loop which checks the result at each iteration),
|
of LL/SC operations (they occur in a loop which checks the result at each iteration),
|
an ERET will normally never be inserted into the pipeline programmatically until the
|
an ERET will normally never be inserted into the pipeline programmatically until the
|
LL/SC sequence has completed (exceptions such as interrupts can still cause ERET, but
|
LL/SC sequence has completed (exceptions such as interrupts can still cause ERET, but
|
they can still cause them in the LL SC sequence as well). In other words, by not passing
|
they can still cause them in the LL SC sequence as well). In other words, by not passing
|
ERET through the pipeline, the only possible effect is a performance penalty. Also this
|
ERET through the pipeline, the only possible effect is a performance penalty. Also this
|
may be irrelevant since currently ERET stalls for forward stages which can cause exceptions,
|
may be irrelevant since currently ERET stalls for forward stages which can cause exceptions,
|
which includes LL and SC.
|
which includes LL and SC.
|
*/
|
*/
|
reg [29:0] LLSC_Address;
|
reg [29:0] LLSC_Address;
|
reg LLSC_Atomic;
|
reg LLSC_Atomic;
|
wire LLSC_MemWrite_Mask;
|
wire LLSC_MemWrite_Mask;
|
|
|
always @(posedge clock) begin
|
always @(posedge clock) begin
|
LLSC_Address <= (reset) ? 30'b0 : (MemRead & LLSC) ? Address[31:2] : LLSC_Address;
|
LLSC_Address <= (reset) ? 30'b0 : (MemRead & LLSC) ? Address[31:2] : LLSC_Address;
|
end
|
end
|
|
|
always @(posedge clock) begin
|
always @(posedge clock) begin
|
if (reset) begin
|
if (reset) begin
|
LLSC_Atomic <= 0;
|
LLSC_Atomic <= 0;
|
end
|
end
|
else if (MemRead) begin
|
else if (MemRead) begin
|
LLSC_Atomic <= (LLSC) ? 1 : LLSC_Atomic;
|
LLSC_Atomic <= (LLSC) ? 1 : LLSC_Atomic;
|
end
|
end
|
// XXX GEA Bug for Ganesh: remove "& ~IF_Stall" from below, then SC will always fail:
|
// XXX GEA Bug for Ganesh: remove "& ~IF_Stall" from below, then SC will always fail:
|
else if (ERET | (~M_Stall & ~IF_Stall & MemWrite & (Address[31:2] == LLSC_Address))) begin
|
else if (ERET | (~M_Stall & ~IF_Stall & MemWrite & (Address[31:2] == LLSC_Address))) begin
|
LLSC_Atomic <= 0;
|
LLSC_Atomic <= 0;
|
end
|
end
|
else begin
|
else begin
|
LLSC_Atomic <= LLSC_Atomic;
|
LLSC_Atomic <= LLSC_Atomic;
|
end
|
end
|
end
|
end
|
assign LLSC_MemWrite_Mask = (LLSC & MemWrite & (~LLSC_Atomic | (Address[31:2] != LLSC_Address)));
|
assign LLSC_MemWrite_Mask = (LLSC & MemWrite & (~LLSC_Atomic | (Address[31:2] != LLSC_Address)));
|
|
|
wire WriteCondition = MemWrite & ~(EXC_KernelMem | EXC_Word | EXC_Half) & ~LLSC_MemWrite_Mask;
|
wire WriteCondition = MemWrite & ~(EXC_KernelMem | EXC_Word | EXC_Half) & ~LLSC_MemWrite_Mask;
|
wire ReadCondition = MemRead & ~(EXC_KernelMem | EXC_Word | EXC_Half);
|
wire ReadCondition = MemRead & ~(EXC_KernelMem | EXC_Word | EXC_Half);
|
|
|
reg RW_Mask;
|
reg RW_Mask;
|
always @(posedge clock) begin
|
always @(posedge clock) begin
|
RW_Mask <= (reset) ? 0 : (((MemWrite | MemRead) & DataMem_Ready) ? 1 : ((~M_Stall & ~IF_Stall) ? 0 : RW_Mask));
|
RW_Mask <= (reset) ? 0 : (((MemWrite | MemRead) & DataMem_Ready) ? 1 : ((~M_Stall & ~IF_Stall) ? 0 : RW_Mask));
|
end
|
end
|
assign M_Stall = ReadEnable | (WriteEnable != 4'b0000) | DataMem_Ready | M_Exception_Stall;
|
assign M_Stall = ReadEnable | (WriteEnable != 4'b0000) | DataMem_Ready | M_Exception_Stall;
|
assign ReadEnable = ReadCondition & ~RW_Mask;
|
assign ReadEnable = ReadCondition & ~RW_Mask;
|
|
|
wire Half_Access_L = (Address[1] ^ BE);
|
wire Half_Access_L = (Address[1] ^ BE);
|
wire Half_Access_R = (Address[1] ~^ BE);
|
wire Half_Access_R = (Address[1] ~^ BE);
|
wire Byte_Access_LL = Half_Access_L & (Address[1] ~^ Address[0]);
|
wire Byte_Access_LL = Half_Access_L & (Address[1] ~^ Address[0]);
|
wire Byte_Access_LM = Half_Access_L & (Address[0] ~^ BE);
|
wire Byte_Access_LM = Half_Access_L & (Address[0] ~^ BE);
|
wire Byte_Access_RM = Half_Access_R & (Address[0] ^ BE);
|
wire Byte_Access_RM = Half_Access_R & (Address[0] ^ BE);
|
wire Byte_Access_RR = Half_Access_R & (Address[1] ~^ Address[0]);
|
wire Byte_Access_RR = Half_Access_R & (Address[1] ~^ Address[0]);
|
|
|
// Write-Enable Signals to Memory
|
// Write-Enable Signals to Memory
|
always @(*) begin
|
always @(*) begin
|
if (WriteCondition & ~RW_Mask) begin
|
if (WriteCondition & ~RW_Mask) begin
|
if (Byte) begin
|
if (Byte) begin
|
WriteEnable[3] <= Byte_Access_LL;
|
WriteEnable[3] <= Byte_Access_LL;
|
WriteEnable[2] <= Byte_Access_LM;
|
WriteEnable[2] <= Byte_Access_LM;
|
WriteEnable[1] <= Byte_Access_RM;
|
WriteEnable[1] <= Byte_Access_RM;
|
WriteEnable[0] <= Byte_Access_RR;
|
WriteEnable[0] <= Byte_Access_RR;
|
end
|
end
|
else if (Half) begin
|
else if (Half) begin
|
WriteEnable[3] <= Half_Access_L;
|
WriteEnable[3] <= Half_Access_L;
|
WriteEnable[2] <= Half_Access_L;
|
WriteEnable[2] <= Half_Access_L;
|
WriteEnable[1] <= Half_Access_R;
|
WriteEnable[1] <= Half_Access_R;
|
WriteEnable[0] <= Half_Access_R;
|
WriteEnable[0] <= Half_Access_R;
|
end
|
end
|
else if (Left) begin
|
else if (Left) begin
|
case (Address[1:0])
|
case (Address[1:0])
|
2'b00 : WriteEnable <= (BE) ? 4'b1111 : 4'b0001;
|
2'b00 : WriteEnable <= (BE) ? 4'b1111 : 4'b0001;
|
2'b01 : WriteEnable <= (BE) ? 4'b0111 : 4'b0011;
|
2'b01 : WriteEnable <= (BE) ? 4'b0111 : 4'b0011;
|
2'b10 : WriteEnable <= (BE) ? 4'b0011 : 4'b0111;
|
2'b10 : WriteEnable <= (BE) ? 4'b0011 : 4'b0111;
|
2'b11 : WriteEnable <= (BE) ? 4'b0001 : 4'b1111;
|
2'b11 : WriteEnable <= (BE) ? 4'b0001 : 4'b1111;
|
endcase
|
endcase
|
end
|
end
|
else if (Right) begin
|
else if (Right) begin
|
case (Address[1:0])
|
case (Address[1:0])
|
2'b00 : WriteEnable <= (BE) ? 4'b1000 : 4'b1111;
|
2'b00 : WriteEnable <= (BE) ? 4'b1000 : 4'b1111;
|
2'b01 : WriteEnable <= (BE) ? 4'b1100 : 4'b1110;
|
2'b01 : WriteEnable <= (BE) ? 4'b1100 : 4'b1110;
|
2'b10 : WriteEnable <= (BE) ? 4'b1110 : 4'b1100;
|
2'b10 : WriteEnable <= (BE) ? 4'b1110 : 4'b1100;
|
2'b11 : WriteEnable <= (BE) ? 4'b1111 : 4'b1000;
|
2'b11 : WriteEnable <= (BE) ? 4'b1111 : 4'b1000;
|
endcase
|
endcase
|
end
|
end
|
else begin
|
else begin
|
WriteEnable <= 4'b1111;
|
WriteEnable <= 4'b1111;
|
end
|
end
|
end
|
end
|
else begin
|
else begin
|
WriteEnable <= 4'b0000;
|
WriteEnable <= 4'b0000;
|
end
|
end
|
end
|
end
|
|
|
// Data Going to Memory
|
// Data Going to Memory
|
assign MWriteData[31:24] = (Byte) ? DataIn[7:0] : ((Half) ? DataIn[15:8] : DataIn[31:24]);
|
assign MWriteData[31:24] = (Byte) ? DataIn[7:0] : ((Half) ? DataIn[15:8] : DataIn[31:24]);
|
assign MWriteData[23:16] = (Byte | Half) ? DataIn[7:0] : DataIn[23:16];
|
assign MWriteData[23:16] = (Byte | Half) ? DataIn[7:0] : DataIn[23:16];
|
assign MWriteData[15:8] = (Byte) ? DataIn[7:0] : DataIn[15:8];
|
assign MWriteData[15:8] = (Byte) ? DataIn[7:0] : DataIn[15:8];
|
assign MWriteData[7:0] = DataIn[7:0];
|
assign MWriteData[7:0] = DataIn[7:0];
|
|
|
// Data Read from Memory
|
// Data Read from Memory
|
always @(*) begin
|
always @(*) begin
|
if (Byte) begin
|
if (Byte) begin
|
if (Byte_Access_LL) begin
|
if (Byte_Access_LL) begin
|
DataOut <= (SignExtend & MReadData[31]) ? {24'hFFFFFF, MReadData[31:24]} : {24'h000000, MReadData[31:24]};
|
DataOut <= (SignExtend & MReadData[31]) ? {24'hFFFFFF, MReadData[31:24]} : {24'h000000, MReadData[31:24]};
|
end
|
end
|
else if (Byte_Access_LM) begin
|
else if (Byte_Access_LM) begin
|
DataOut <= (SignExtend & MReadData[23]) ? {24'hFFFFFF, MReadData[23:16]} : {24'h000000, MReadData[23:16]};
|
DataOut <= (SignExtend & MReadData[23]) ? {24'hFFFFFF, MReadData[23:16]} : {24'h000000, MReadData[23:16]};
|
end
|
end
|
else if (Byte_Access_RM) begin
|
else if (Byte_Access_RM) begin
|
DataOut <= (SignExtend & MReadData[15]) ? {24'hFFFFFF, MReadData[15:8]} : {24'h000000, MReadData[15:8]};
|
DataOut <= (SignExtend & MReadData[15]) ? {24'hFFFFFF, MReadData[15:8]} : {24'h000000, MReadData[15:8]};
|
end
|
end
|
else begin
|
else begin
|
DataOut <= (SignExtend & MReadData[7]) ? {24'hFFFFFF, MReadData[7:0]} : {24'h000000, MReadData[7:0]};
|
DataOut <= (SignExtend & MReadData[7]) ? {24'hFFFFFF, MReadData[7:0]} : {24'h000000, MReadData[7:0]};
|
end
|
end
|
end
|
end
|
else if (Half) begin
|
else if (Half) begin
|
if (Half_Access_L) begin
|
if (Half_Access_L) begin
|
DataOut <= (SignExtend & MReadData[31]) ? {16'hFFFF, MReadData[31:16]} : {16'h0000, MReadData[31:16]};
|
DataOut <= (SignExtend & MReadData[31]) ? {16'hFFFF, MReadData[31:16]} : {16'h0000, MReadData[31:16]};
|
end
|
end
|
else begin
|
else begin
|
DataOut <= (SignExtend & MReadData[15]) ? {16'hFFFF, MReadData[15:0]} : {16'h0000, MReadData[15:0]};
|
DataOut <= (SignExtend & MReadData[15]) ? {16'hFFFF, MReadData[15:0]} : {16'h0000, MReadData[15:0]};
|
end
|
end
|
end
|
end
|
else if (LLSC & MemWrite) begin
|
else if (LLSC & MemWrite) begin
|
DataOut <= (LLSC_Atomic & (Address[31:2] == LLSC_Address)) ? 32'h0000_0001 : 32'h0000_0000;
|
DataOut <= (LLSC_Atomic & (Address[31:2] == LLSC_Address)) ? 32'h0000_0001 : 32'h0000_0000;
|
end
|
end
|
else if (Left) begin
|
else if (Left) begin
|
case (Address[1:0])
|
case (Address[1:0])
|
2'b00 : DataOut <= (BE) ? MReadData : {MReadData[7:0], DataIn[23:0]};
|
2'b00 : DataOut <= (BE) ? MReadData : {MReadData[7:0], DataIn[23:0]};
|
2'b01 : DataOut <= (BE) ? {MReadData[23:0], DataIn[7:0]} : {MReadData[15:0], DataIn[15:0]};
|
2'b01 : DataOut <= (BE) ? {MReadData[23:0], DataIn[7:0]} : {MReadData[15:0], DataIn[15:0]};
|
2'b10 : DataOut <= (BE) ? {MReadData[15:0], DataIn[15:0]} : {MReadData[23:0], DataIn[7:0]};
|
2'b10 : DataOut <= (BE) ? {MReadData[15:0], DataIn[15:0]} : {MReadData[23:0], DataIn[7:0]};
|
2'b11 : DataOut <= (BE) ? {MReadData[7:0], DataIn[23:0]} : MReadData;
|
2'b11 : DataOut <= (BE) ? {MReadData[7:0], DataIn[23:0]} : MReadData;
|
endcase
|
endcase
|
end
|
end
|
else if (Right) begin
|
else if (Right) begin
|
case (Address[1:0])
|
case (Address[1:0])
|
2'b00 : DataOut <= (BE) ? {DataIn[31:8], MReadData[31:24]} : MReadData;
|
2'b00 : DataOut <= (BE) ? {DataIn[31:8], MReadData[31:24]} : MReadData;
|
2'b01 : DataOut <= (BE) ? {DataIn[31:16], MReadData[31:16]} : {DataIn[31:24], MReadData[31:8]};
|
2'b01 : DataOut <= (BE) ? {DataIn[31:16], MReadData[31:16]} : {DataIn[31:24], MReadData[31:8]};
|
2'b10 : DataOut <= (BE) ? {DataIn[31:24], MReadData[31:8]} : {DataIn[31:16], MReadData[31:16]};
|
2'b10 : DataOut <= (BE) ? {DataIn[31:24], MReadData[31:8]} : {DataIn[31:16], MReadData[31:16]};
|
2'b11 : DataOut <= (BE) ? MReadData : {DataIn[31:8], MReadData[31:24]};
|
2'b11 : DataOut <= (BE) ? MReadData : {DataIn[31:8], MReadData[31:24]};
|
endcase
|
endcase
|
end
|
end
|
else begin
|
else begin
|
DataOut <= MReadData;
|
DataOut <= MReadData;
|
end
|
end
|
end
|
end
|
|
|
endmodule
|
endmodule
|
|
|
No newline at end of file
|
No newline at end of file
|
|
|
No newline at end of file
|
No newline at end of file
|