├── C2MInterface.sv ├── CalcMax.sv ├── Controller_FSM.sv ├── DDR4Interface.sv ├── Definitions.pkg ├── LICENSE.txt ├── Makefile ├── Memory.sv ├── MemoryController.sv ├── README.md ├── ReadWrite.sv ├── Read_data_comm.sv ├── Receive_command.sv ├── Scheduler.sv ├── Send_command.sv ├── ShiftReg.sv ├── Timer.sv └── Top.sv /C2MInterface.sv: -------------------------------------------------------------------------------- 1 | //This is the interface between the Cache BFM and the Memory Controller. 2 | //Author: Ananth Bhat 3 | /////////////////////////////////////////////////////////////////////////// 4 | 5 | interface C2MInterface 6 | #( 7 | parameter DWIDTH = 512, AWIDTH = 32 8 | ) 9 | ( 10 | input logic clock,reset 11 | ); 12 | 13 | ////////////////////////////////TRANSACTION SIGNALS////////////////////////////// 14 | 15 | logic [DWIDTH-1:0] data_tran; //Data sent from Cache to Memory Controller to 16 | //be written 17 | 18 | logic [AWIDTH-1:0] addr; //Address sent from Cache to Memory Controller 19 | 20 | logic rw; //Read-Write signal 21 | 22 | logic valid_tran; //Indicates that the Data from Cache to Memory 23 | //is valid 24 | 25 | logic [2:0] tag_tran; //Tag returned along with acknowledgemnt 26 | //signal 27 | 28 | logic ack_tran; //Acknowledgement signal from Memory to cache 29 | 30 | logic full; //A full signal indicating that the memory 31 | //controller cannot accept any more transactions 32 | 33 | //////////////////////////////READ DATA SIGNALS////////////////////////////////////// 34 | 35 | logic [DWIDTH-1:0] read_data; //Data sent from Memory to Cache in 36 | //response to a read 37 | logic [2:0] tag_data; //Tag sent along with the data from the 38 | //Memory controller to Cache 39 | 40 | logic ack_data; //Ack sent from Cache to Memory 41 | 42 | logic valid_data; //Indicates that the data sent from Memory 43 | //to cache is valid 44 | 45 | 46 | //////////////////////////////////MODPORTS/////////////////////////////////////////// 47 | 48 | modport Cache_tran ( 49 | input ack_tran,tag_tran,full,reset,clock, 50 | output addr, data_tran, rw, valid_tran 51 | ); 52 | 53 | modport Cache_data ( 54 | input read_data,reset,clock,tag_data,valid_data, 55 | output ack_data 56 | ); 57 | 58 | modport Mem_tran ( 59 | input clock,reset,addr,data_tran,rw,valid_tran, 60 | output ack_tran,tag_tran,full 61 | ); 62 | 63 | modport Mem_data ( 64 | input ack_data,reset,clock, 65 | output read_data,tag_data,valid_data 66 | ); 67 | 68 | endinterface 69 | -------------------------------------------------------------------------------- /CalcMax.sv: -------------------------------------------------------------------------------- 1 | //The modules here are used in the Scheduler for calculations 2 | //Author: Sriram VB 3 | module Compare(Count1, Count2, Index1, Index2, Max); 4 | input [15:0]Count1, Count2; 5 | input [2:0]Index1,Index2; 6 | output logic [2:0] Max; 7 | 8 | always_comb begin 9 | if(Count2>Count1) 10 | Max = Index2; 11 | else 12 | Max = Index1; 13 | end 14 | 15 | endmodule 16 | 17 | 18 | module CalcMax#(parameter BuffLength = 8)(Counters, MaxValue); 19 | input [BuffLength - 1:0][15:0] Counters; 20 | output logic [2:0]MaxValue; 21 | 22 | wire [5:0][2:0]max; 23 | Compare c0(Counters[0],Counters[1],3'd0,3'd1,max[0]); 24 | Compare c1(Counters[2],Counters[3],3'd2,3'd3,max[1]); 25 | Compare c2(Counters[4],Counters[5],3'd4,3'd5,max[2]); 26 | Compare c3(Counters[6],Counters[7],3'd6,3'd7,max[3]); 27 | 28 | Compare c4(Counters[max[0]],Counters[max[1]],max[0],max[1],max[4]); 29 | Compare c5(Counters[max[2]],Counters[max[3]],max[2],max[3],max[5]); 30 | 31 | Compare c6(Counters[max[4]],Counters[max[5]],max[4],max[5],MaxValue); 32 | endmodule 33 | -------------------------------------------------------------------------------- /Controller_FSM.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////MEMORY CONTROLLER FSM///////////////////////////////// 2 | //This module handles the communication between the memory controller and the memory. 3 | //It uses the methods from the DDR4 interface to communicate with the memory. 4 | //It uses the ReadMod and WriteMod modules from ReadWrite.sv to transfer data at DDR. 5 | //Author: Ananth Bhat 6 | `define DPRINT $display($time, "\t%m\t STATE: %s",state.name) 7 | module MemContFSM 8 | #( 9 | //Parameters included from Definitions.h 10 | `include "Definitions.pkg" 11 | ) 12 | ( 13 | input logic reset, clock,clock2x, 14 | input logic start,rw,refresh,ap, 15 | input logic [BuffBits-1:0] tagreadin, 16 | input logic [BWIDTH-1:0] bank, 17 | input logic [BGWIDTH-1:0] bankgroup, 18 | input logic [RWIDTH-1:0] row, 19 | input logic [CWIDTH-1:0] column, 20 | input logic [1:0] PageHit, 21 | input logic PageMiss,PageEmpty, 22 | output logic done,buff, 23 | output logic [BuffBits-1:0] tagreadout, 24 | output wire [DATAWIDTH-1:0] dataread, 25 | input wire [DATAWIDTH-1:0] datawrite, 26 | interface DDR4Bus 27 | ); 28 | //Enumerated State Definitions 29 | enum {Reset,Wait,Activate,Read,Write,DataRead,DataWrite,Done,Refresh,Precharge,LoadTimer} state,next,prev; 30 | 31 | //Variable definitions 32 | logic HitZero,set,StartRd_n,StartWr_n,read,write; 33 | logic [31:0] Load; 34 | logic [SHIFTBITS:0] ShiftInputRd,ShiftOutputRd, ShiftInputWr, ShiftOutputWr; 35 | wire [DATAWIDTH-1:0] DataHost; 36 | 37 | ///////////Module Instantiations/////////////// 38 | CountdownTimer C (.clock,.Load, .Reset(set),.HitZero(HitZero)); 39 | ReadMod RC (.read,.reset(StartRd_n),.DataHost(dataread),.DataBus(DDR4Bus.pin_dq), .DQS_t(DDR4Bus.dqs_t), .DQS_c(DDR4Bus.dqs_c)); 40 | WriteMod WC(.write,.clock2x,.reset(StartWr_n),.DataHost,.DataBus(DDR4Bus.pin_dq),.DQS_t(DDR4Bus.dqs_t), .DQS_c(DDR4Bus.dqs_c)); 41 | ShiftRegMC ShiftRead (.clock, .reset, .ShiftInput(ShiftInputRd), .ShiftOutput(ShiftOutputRd)); 42 | ShiftRegMC ShiftWrite (.clock, .reset, .ShiftInput(ShiftInputWr), .ShiftOutput(ShiftOutputWr)); 43 | 44 | //Variable Definitions 45 | logic [DATAWIDTH-1:0]WriteArray [TCL-1:0]; 46 | logic WriteFlag; 47 | logic [SHIFTBITS-1:0] pointer,LatchPointer; 48 | logic [3:0] WaitRegWr; 49 | logic [4:0] WaitRegRd; 50 | wire waitrd,waitwr; 51 | logic shiftrd,shiftwr; 52 | 53 | assign DataHost = WriteArray[LatchPointer]; 54 | 55 | //Continuous Assignments 56 | assign buff = WaitRegRd[0]; //Buff tells the scheduler that a read is done 57 | assign waitrd = ~|WaitRegRd;//Logic to determine start, read, write signals 58 | assign waitwr = ~|WaitRegWr; 59 | assign {StartRd_n,StartWr_n} = {waitrd,waitwr}; 60 | assign {read,write} = {~waitrd,~waitwr}; 61 | 62 | 63 | //Shift Register, Write Array, Pointer logic 64 | always_ff @(posedge clock) 65 | begin 66 | if(reset) begin 67 | pointer <= 1'b0; 68 | WaitRegRd <= 4'b0; 69 | WaitRegWr <= 4'b0; 70 | end 71 | else begin 72 | WaitRegRd <= {ShiftOutputRd[SHIFTBITS],WaitRegRd[4:1]}; 73 | WaitRegWr <= {ShiftOutputWr[SHIFTBITS],WaitRegWr[3:1]}; 74 | assert( !$isunknown(WaitRegWr) && $countones(WaitRegWr)<=1) 75 | else $fatal("Write Timing Violation:WaitRegWr value isnt perfect\tWaitRegWr:%b",WaitRegWr); 76 | assert(!$isunknown(WaitRegRd) && $countones(WaitRegRd)<=1) 77 | else $fatal("Read Timing Violation:WaitRegRd value isnt perfect\tWaitRegRd:%b",WaitRegRd); 78 | if(WriteFlag==1'b1) 79 | pointer <= pointer + 1'b1; 80 | 81 | end 82 | 83 | end 84 | 85 | //Logic to latch pointer during data read/write 86 | always_latch begin 87 | if(ShiftOutputWr[SHIFTBITS]) 88 | LatchPointer = ShiftOutputWr[SHIFTBITS-1:0]; 89 | if(ShiftOutputRd[SHIFTBITS]) 90 | tagreadout = ShiftOutputRd[SHIFTBITS-1:1]; 91 | end 92 | 93 | 94 | //LatchPointer should remain constant for 4 clock cycles 95 | property Latch_Pointer; 96 | @(posedge clock) 97 | ShiftOutputWr[SHIFTBITS] |=> !($changed(LatchPointer))[*3]; 98 | endproperty 99 | 100 | assert property (Latch_Pointer) 101 | else $fatal("RW Address not constant during transfer. Latch pointer not constant\tLatchPointer:%0d",LatchPointer); 102 | 103 | 104 | ////////// FINITE STATE MACHINE /////////// 105 | always_ff @(posedge clock) 106 | begin 107 | if(reset) 108 | state <= Reset; 109 | else begin 110 | state <= next; 111 | prev <= state; 112 | end 113 | end 114 | 115 | //Next State Logic 116 | always_comb 117 | begin 118 | next = state; 119 | case (state) 120 | Reset: case({start,refresh}) inside 121 | 2'b0x: next = Reset; 122 | 2'b11: next = Refresh; 123 | 2'b10: next = LoadTimer; 124 | endcase 125 | LoadTimer: begin 126 | unique case(prev) 127 | Reset: begin 128 | assert(PageEmpty) 129 | else $fatal("Protocol Violation:First access to bank without precharge is not allowed"); 130 | next = Activate; 131 | 132 | end 133 | Precharge: next = Activate; 134 | Done: begin 135 | if(PageEmpty) 136 | next = Activate; 137 | else 138 | next = Wait; 139 | end 140 | endcase 141 | end 142 | 143 | Wait: begin 144 | case ({HitZero,rw}) inside 145 | 2'b0x: next = Wait; 146 | 2'b10: next = Write; 147 | 2'b11: next = Read; 148 | endcase 149 | 150 | end 151 | Activate: begin 152 | case ({HitZero,rw}) inside 153 | 2'b0x: next = Wait; 154 | 2'b10: next = Write; 155 | 2'b11: next = Read; 156 | endcase 157 | end 158 | Read: next = Done; 159 | Write: next = Done; 160 | Done: if(start) begin 161 | assert($countones({PageEmpty,PageMiss,PageHit})>0) 162 | else $fatal("Protocol Violation: Check Page Inputs from Scheduler"); 163 | unique case ({PageEmpty,PageMiss,PageHit,refresh}) inside 164 | 5'b10000: next = LoadTimer; 165 | 5'b01000: next = Precharge; 166 | 5'b00100: next = LoadTimer; 167 | 5'b00110: next = LoadTimer; 168 | 5'bxxxx1: next = Refresh; 169 | endcase 170 | end 171 | else 172 | next = Done; 173 | Precharge: next = LoadTimer; 174 | Refresh: next = Done; 175 | 176 | endcase 177 | end 178 | 179 | //Output Function Logic 180 | always_comb 181 | begin 182 | `DPRINT; 183 | ShiftInputWr='0; 184 | ShiftInputRd='0; 185 | WriteFlag = 1'b0; 186 | done=1'b0; 187 | set = 1'b0; 188 | DDR4Bus.dq_c = 'z; 189 | case (state) 190 | Reset: begin 191 | DDR4Bus.MRS(3'b0,13'b0); 192 | done = 1'b1;//Done is made high to tell the 193 | //sceduler to send the first request 194 | end 195 | LoadTimer: begin 196 | set = 1'b1; 197 | unique case(prev) 198 | Reset: Load = TRCD-1; 199 | Activate: Load = TCL-1; 200 | Precharge: Load = TRP-1; 201 | Done: begin 202 | unique case ({PageEmpty,PageHit}) inside 203 | 3'b100: Load = TRCD -1; 204 | 3'b010: Load = TCCD_S-1; 205 | 3'b011: Load = TCCD_L-1; 206 | endcase 207 | end 208 | 209 | endcase 210 | end 211 | Wait: DDR4Bus.DES; 212 | Activate: begin 213 | DDR4Bus.ACT(row,bankgroup,bank); 214 | end 215 | Read: begin 216 | ShiftInputRd = {1'b1,tagreadin,1'b0}; 217 | if(ap) 218 | DDR4Bus.RDA(column,bankgroup,bank); 219 | else 220 | DDR4Bus.RD(column,bankgroup,bank); 221 | end 222 | 223 | Write: begin 224 | ShiftInputWr = {1'b1,pointer}; 225 | WriteArray[pointer] = datawrite; 226 | WriteFlag = 1'b1; 227 | if(ap) 228 | DDR4Bus.WRA(column,bankgroup,bank); 229 | else 230 | DDR4Bus.WR(column,bankgroup,bank); 231 | end 232 | 233 | Done: begin 234 | DDR4Bus.DES; 235 | done =1'b1; 236 | end 237 | Precharge: DDR4Bus.PRE(bankgroup,bank); 238 | Refresh: DDR4Bus.REF; 239 | endcase 240 | end 241 | 242 | endmodule 243 | -------------------------------------------------------------------------------- /DDR4Interface.sv: -------------------------------------------------------------------------------- 1 | //This file contains the DDR4 interface definitons between the Memory and 2 | //the controller. This interface defines pin signals and contains methods 3 | //which can be used by both the memory controller as well as the memory. 4 | //Basic assertions included within the interface check for timing violations 5 | //Author: Ananth Bhat 6 | // Sriram VB 7 | interface DDR4Interface 8 | #( 9 | `include "Definitions.pkg" 10 | ) 11 | ( 12 | input logic clock,reset 13 | ); 14 | 15 | //Definitions and LocalParameters 16 | `define RAS A[16] //RAS Command Input 17 | `define CAS A[15] //CAS Command Input 18 | `define WE A[14] //WE Command Input 19 | `define BC A[12] //Burst Chop 20 | `define AP A[10] // Auto Precharge 21 | `define HIGH '1 22 | localparam LOW = '0; 23 | localparam TRI ='z; 24 | 25 | /**************Define Interface Signals*********************/ 26 | //Address Inputs 27 | logic [AWIDTH-1:0] A; //Transaction Level Model(TLM) variable 28 | wire [AWIDTH-1:0] pin_A; 29 | 30 | //Control Signals 31 | logic act_n; //Activate Command Input 32 | logic [BG_BITS-1:0] bg; //Bank Address Inputs 33 | logic [B_BITS-1:0] b; //Bank Group Address Inputs 34 | logic clk_t, clk_c; //Differential Clock Inputs 35 | logic cke; //Clock Enable 36 | logic cs_n; //Chip Select 37 | logic dm_n,udm_n,ldm_n; //Input Data Mask 38 | logic odt; //On Die Termination 39 | logic par; //Parity 40 | logic reset_n; //Asynchronous Reset 41 | logic ten; //Connectivity Test Mode 42 | logic alert_n; //Alert output 43 | 44 | //Data Signals 45 | wire [DWIDTH-1:0] pin_dq; //Bidirectional Data Bus 46 | wire dbi_n, udbi_n, ldbi_n; //Data Bus Inversion 47 | wire dqs_t,dqs_c, //Data Strobe pins 48 | dqsu_t,dqsu_c, 49 | dqsl_t,dqsl_u; 50 | wire tdqs_t,tdws_c; //Termination Data Strobe. 51 | logic [DWIDTH-1:0] dq_m, dq_c; ////Transaction Level Model(TLM) variable 52 | 53 | /*****************************************************************/ 54 | //Assignments to pins from TLM variables 55 | assign pin_dq = dq_m; 56 | assign pin_A = A; 57 | assign pin_dq = dq_c; 58 | assign reset_n = ~reset; 59 | 60 | //Modport Definitions 61 | modport Memory ( 62 | import IsActivate, IsRefresh, IsWrite, IsRead, IsWriteA, IsReadA, IsPrePreA, 63 | import ReadRowBank, ReadColumnBank, 64 | input cke,cs_n,dm_n,udm_n,ldm_n,odt, par,reset_n,ten,pin_A,act_n,bg, b,clk_t,clk_c,clock, 65 | output alert_n,tdqs_t,tdws_c,dq_m, 66 | inout pin_dq,dbi_n,udbi_n,ldbi_n,dqs_t,dqs_c 67 | ); 68 | 69 | modport Controller ( 70 | import ACT,MRS,REF,PRE,PREA,WR,RD,WRA,RDA,NOP,DES, 71 | output cke,cs_n,dm_n,udm_n,ldm_n,odt, par,ten,pin_A,act_n,bg, b,clk_t,clk_c,dq_c, 72 | input alert_n,tdqs_t,tdws_c,reset_n, 73 | inout pin_dq,dbi_n,udbi_n,ldbi_n,dqs_t,dqs_c 74 | ); 75 | 76 | /**************************CONTROLLER METHODS**********************************/ 77 | //Bank Activate 78 | function automatic void ACT (input logic [/*AWIDTH-1*/14:0]Row_Address, 79 | logic [BG_BITS-1:0] bankgrp, 80 | logic [B_BITS-1:0] bank); 81 | $display($time, "\tACTIVATE\tRow Address:%b",Row_Address); 82 | bg = bankgrp; b = bank; 83 | {cs_n,act_n} = LOW; 84 | cke = `HIGH; 85 | A[14:0] = Row_Address; 86 | 87 | endfunction 88 | 89 | //Mode Register Set(MRS) access 90 | function automatic void MRS (input logic [2:0] MrsSelect, logic [13:0] code); 91 | $display($time, "\tMRS"); 92 | {bg[0],b} = MrsSelect; 93 | {cs_n,`RAS,`CAS,`WE} = LOW; 94 | act_n = `HIGH; 95 | bg[1] = 1'b0; 96 | A[17] = 1'b0; 97 | A[13:0] = code; 98 | endfunction 99 | 100 | //Refresh 101 | function automatic void REF(); 102 | $display($time, "\tREF"); 103 | {cke,cs_n,act_n,`RAS,`CAS,`WE} = 6'b101000; 104 | endfunction 105 | 106 | //Precharge 107 | function automatic void PRE (input logic [BG_BITS-1:0] bankgrp, logic [B_BITS-1:0] bank); 108 | $display($time, "\tPRECHARGE"); 109 | {cke,act_n,`CAS} = `HIGH; 110 | {cs_n,`RAS,`WE,`AP} = LOW; 111 | bg = bankgrp; b = bank; 112 | endfunction 113 | 114 | //Auto-Precharge 115 | function automatic void PREA(); 116 | $display($time, "\tAUTO PRECHARGE"); 117 | {cke,act_n,`CAS,`AP} = `HIGH; 118 | {cs_n,`RAS,`WE} = LOW; 119 | endfunction 120 | 121 | //Write 122 | function automatic void WR (input logic [9:0] col_add, 123 | logic [BG_BITS-1:0] bankgrp, 124 | logic [B_BITS-1:0] bank 125 | ); 126 | $display($time, "\tWRITE"); 127 | {cke,act_n,`RAS} = `HIGH; 128 | {cs_n,`CAS,`WE,`AP} = LOW; 129 | A[9:0] = col_add; 130 | bg = bankgrp; b = bank; 131 | endfunction 132 | 133 | //Read 134 | function automatic void RD (input logic [9:0] col_add, 135 | logic [BG_BITS-1:0] bankgrp, 136 | logic [B_BITS-1:0] bank 137 | ); 138 | 139 | $display($time, "\tREAD"); 140 | {cke,act_n,`RAS,`WE} = `HIGH; 141 | {cs_n,`CAS,`AP} = LOW; 142 | A[9:0] = col_add; 143 | bg = bankgrp; b = bank; 144 | endfunction 145 | 146 | //Write with Precharge 147 | function automatic void WRA (input logic [9:0] col_add, 148 | logic [BG_BITS-1:0] bankgrp, 149 | logic [B_BITS-1:0] bank 150 | ); 151 | $display($time, "\tWRITE WITH PRECHARGE\tColumn Address:%b",col_add); 152 | {cke,act_n,`RAS,`AP} = `HIGH; 153 | {cs_n,`CAS,`WE} = LOW; 154 | A[9:0] = col_add; 155 | bg = bankgrp; b = bank; 156 | endfunction 157 | 158 | //Read with Precharge 159 | function automatic void RDA (input logic [9:0] col_add, 160 | logic [BG_BITS-1:0] bankgrp, 161 | logic [B_BITS-1:0] bank 162 | ); 163 | 164 | $display($time, "\tREAD WITH PRECHARGE"); 165 | {cke,act_n,`RAS,`WE,`AP} = `HIGH; 166 | {cs_n,`CAS} = LOW; 167 | A[9:0] = col_add; 168 | bg = bankgrp; b = bank; 169 | endfunction 170 | 171 | //No-Operation 172 | function automatic void NOP; 173 | $display($time, "\tNO OP"); 174 | {cke,act_n,`RAS,`CAS,`WE} = `HIGH; 175 | cs_n = LOW; 176 | endfunction 177 | 178 | //Deselect 179 | function automatic void DES; 180 | $display($time, "\tDESELECT"); 181 | {cke,cs_n} = `HIGH; 182 | endfunction 183 | 184 | /****************************MEMORY METHODS*************************************/ 185 | function automatic bit IsActivate; 186 | bit IsBit; 187 | if(({cs_n,act_n} === LOW) && (cke === `HIGH)) 188 | IsBit = 1'b1; 189 | return IsBit; 190 | endfunction /* IsActivate */ 191 | 192 | function automatic bit IsRefresh; 193 | bit IsBit; 194 | if ({cke,cs_n,act_n,`RAS,`CAS,`WE} === 6'b101000) 195 | IsBit = 1'b1; 196 | return IsBit; 197 | endfunction /* IsRefresh */ 198 | 199 | function automatic bit IsWrite; 200 | bit IsBit; 201 | if (({cke,act_n,`RAS} === `HIGH) && ({cs_n,`CAS,`WE,`AP} === LOW)) 202 | IsBit = 1'b1; 203 | return IsBit; 204 | endfunction /* IsWrite */ 205 | 206 | function automatic bit IsRead; 207 | bit IsBit; 208 | if (({cke,act_n,`RAS,`WE} === `HIGH) && ({cs_n,`CAS,`AP} === LOW)) 209 | IsBit = 1'b1; 210 | return IsBit; 211 | endfunction /* IsRead */ 212 | 213 | function automatic bit IsWriteA; 214 | bit IsBit; 215 | if (({cke,act_n,`RAS,`AP} === `HIGH) && ({cs_n,`CAS,`WE} === LOW)) 216 | IsBit = 1'b1; 217 | return IsBit; 218 | endfunction /* IsWriteA */ 219 | 220 | function automatic bit IsReadA; 221 | bit IsBit; 222 | if (({cke,act_n,`RAS,`WE,`AP} === `HIGH) && ({cs_n,`CAS} === LOW)) 223 | IsBit = 1'b1; 224 | return IsBit; 225 | endfunction /* IsReadA */ 226 | 227 | function automatic bit IsPrePreA; 228 | bit IsBit; 229 | if (({cke,act_n,`CAS} === `HIGH) && ({cs_n,`RAS,`WE} === LOW)) 230 | IsBit = 1'b1; 231 | return IsBit; 232 | endfunction /* IsPrePreA */ 233 | 234 | function automatic logic[15 + B_BITS + BG_BITS-1:0] ReadRowBank; 235 | $display($time,"\tROW:%b\tBANK:%x\tBG:%x",pin_A[14:0],b,bg); 236 | assert ($isunknown(pin_A[14:0])==0) 237 | else $warning("The row address isnt read correctly"); 238 | return {pin_A[14:0],b,bg}; 239 | endfunction /* ReadRowBank */ 240 | 241 | function automatic logic[10 + BG_BITS + B_BITS-1:0] ReadColumnBank; 242 | $display($time,"\tThe cloumn address read is: %b",pin_A[9:0]); 243 | assert ($isunknown(pin_A[9:0])==0) 244 | else $warning("The column address isnt read correctly"); 245 | return {A[9:0],b,bg}; 246 | endfunction /* ReadColumnBank */ 247 | 248 | //////////////////////ASSSERTIONS////////////////////////////////// 249 | property Act_RW; 250 | @(posedge clock) 251 | ((cs_n === LOW) && (cke === `HIGH) && $fell(act_n))|-> ##TRCD ($fell(`CAS) || $rose(act_n)); 252 | endproperty 253 | 254 | assert property(Act_RW) 255 | else $warning("TRCD Violation"); 256 | 257 | sequence S1; 258 | @(edge clock) 259 | ($rose(act_n) && ({cke,`RAS} === `HIGH) && ({cs_n,`CAS,`AP} === LOW)); 260 | endsequence 261 | 262 | property RW_to_Data; 263 | @(edge clock) 264 | S1|-> ##(2*TCL) (!$isunknown(pin_dq)); 265 | endproperty 266 | 267 | assert property(RW_to_Data) 268 | else $warning("TCL violation"); 269 | 270 | endinterface 271 | 272 | /////////////////////////////////////////////////////////////////////////// 273 | -------------------------------------------------------------------------------- /Definitions.pkg: -------------------------------------------------------------------------------- 1 | //Parameters 2 | parameter TRP = 16, 3 | parameter TRCD = 16, 4 | parameter TCL = 16, 5 | parameter TCCD_L = 6, 6 | parameter TCCD_S = 4, 7 | parameter CWIDTH = 10, 8 | parameter RWIDTH = 15, 9 | parameter BWIDTH = 2, 10 | parameter BGWIDTH = 2, 11 | parameter TWIDTH = 3, 12 | parameter DATAWIDTH = 512 , 13 | parameter ADDRESSWIDTH = 32, 14 | parameter AWIDTH = 18, 15 | parameter DWIDTH = 64, 16 | parameter BANKGROUP = 4, 17 | parameter BANKS = 4, 18 | parameter B_BITS = $clog2(BANKS), 19 | parameter BG_BITS = $clog2(BANKGROUP), 20 | parameter SHIFTBITS = $clog2(TCL), 21 | parameter BuffLength = 8, 22 | parameter BuffBits = $clog2(BuffLength), 23 | parameter Threshold = 16'h1000 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ananth Bhat;Sriram VB;Shivank Dhote;Niraj Thakkar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ll: clean compile sim 2 | 3 | RTL= C2MInterface.sv \ 4 | DDR4Interface.sv \ 5 | Memory.sv \ 6 | Receive_command.sv \ 7 | Scheduler.sv \ 8 | Controller_FSM.sv \ 9 | Timer.sv \ 10 | CalcMax.sv \ 11 | MemoryController.sv \ 12 | ReadWrite.sv \ 13 | Read_data_comm.sv \ 14 | Send_command.sv \ 15 | ShiftReg.sv \ 16 | Top.sv 17 | 18 | TOP= Top 19 | 20 | run: work compile sim 21 | 22 | work: 23 | vlib work 24 | compile: 25 | vlog -source ${RTL} 26 | sim: 27 | vsim -c ${TOP} -do "run -all;" 28 | clean: 29 | rm -rf work transcript vsim.wlf 30 | -------------------------------------------------------------------------------- /Memory.sv: -------------------------------------------------------------------------------- 1 | //This file contains the Memory BFM which interacts with the Mrmroy Controller. 2 | //Author: Sriram VB 3 | 4 | `define DPRINT //$display($time, "\t%m\tState: %s",State.name) 5 | 6 | module Memory#(`include "Definitions.pkg")(DDR4Interface.Memory Bus, input clock2x); 7 | 8 | // Memory 9 | logic [DATAWIDTH - 1:0] Mem [logic[31:0]]; 10 | 11 | //Local Bank and Bankgroup variables 12 | logic [BWIDTH-1:0] Bank; 13 | logic [BGWIDTH-1:0] BankGrp; 14 | 15 | // Register Array and pointers 16 | logic [TCL-1:0][ADDRESSWIDTH-1:0] AddressReg; //Array to store addresses 17 | wire [ADDRESSWIDTH - 1:0] Address;//Address given by the FSM to perform data transfer 18 | logic [SHIFTBITS-1:0] Ptr,LatchPtr; //Pointers to access AddressReg. Latch pointer latches Ptr during data transfer 19 | logic [4:0] WaitRegR; 20 | logic [3:0] WaitRegW;//Registers used to wait during data transfer 21 | 22 | wire [BANKS*BANKGROUP-1:0] Rarray,Warray;//Array of reads and writes respectively 23 | logic W,R; //W,R are the OR of Warray and Rarray Respectively 24 | logic [BANKS*BANKGROUP-1:0] Select; //Selects which FSM is active 25 | 26 | wire StartRn, StartWn; //Enable signals for the Read and Write modules 27 | wire Start_check; //checks validity of enable signals for read and write modules 28 | 29 | // Scheduled read writes 30 | logic [SHIFTBITS:0]RSch,WSch;//Output of Shift Register which waits for TCL 31 | logic [ADDRESSWIDTH-1:0] MemAddress;//Stores the effective address for Memory Access 32 | 33 | //Data wire is defined to store the incoming data from the controller 34 | //into memory array 35 | wire [DATAWIDTH-1:0] Data; 36 | logic [DATAWIDTH-1:0] Data_var; 37 | 38 | //Continuous Assigns 39 | assign {Bank,BankGrp} = {Bus.b,Bus.bg}; 40 | assign {W,R} = {|Warray,|Rarray}; 41 | assign StartRn = ~|WaitRegR; 42 | assign StartWn = ~|WaitRegW; 43 | assign Start_check = StartRn & StartWn; 44 | assign Data = Data_var; 45 | 46 | //Logic to Handle the pointer to the address register 47 | always_ff@(posedge Bus.clock) 48 | begin 49 | if(!Bus.reset_n) 50 | Ptr <= '0; 51 | else if(W || R) 52 | Ptr <= Ptr + 1'b1; 53 | else 54 | Ptr <= Ptr; 55 | end 56 | 57 | //Logic to handle Latchpointer and memory address 58 | always_latch begin 59 | if(!Bus.reset_n) 60 | MemAddress = '0; 61 | else if(WSch[SHIFTBITS]) begin 62 | LatchPtr = WSch[SHIFTBITS-1:0]; 63 | MemAddress = AddressReg[LatchPtr]; 64 | end 65 | else if(RSch[SHIFTBITS]) begin 66 | LatchPtr = RSch[SHIFTBITS-1:0]; 67 | MemAddress = AddressReg[LatchPtr]; 68 | end 69 | end 70 | 71 | //Always Assign the incoming address from FSM into the Address Register 72 | always_latch 73 | AddressReg[Ptr] = Address; 74 | 75 | //Logic to Handle Wait registers 76 | always_ff @(posedge Bus.clock) begin 77 | if(!Bus.reset_n) begin 78 | WaitRegW <= '0; 79 | WaitRegR <= '0; 80 | end 81 | else begin 82 | WaitRegW <= {WSch[SHIFTBITS], WaitRegW[3:1]};//Shift Registers 83 | WaitRegR <= {RSch[SHIFTBITS], WaitRegR[4:1]}; 84 | //Assertions to check that atmost there is only 1 bit which is 1 85 | //and there are no unknowns in the registers 86 | assert( !$isunknown(WaitRegW) && $countones(WaitRegW)<=1) 87 | else $fatal("WaitRegW value isnt perfect\tWaitRegW:%b",WaitRegW); 88 | assert(!$isunknown(WaitRegR) && $countones(WaitRegR)<=1) 89 | else $fatal("WaitRegR value isnt perfect\tWaitRegR:%b",WaitRegR); 90 | end 91 | end 92 | 93 | always_latch begin 94 | if(!StartRn) begin 95 | Mem[MemAddress] = Data; 96 | end 97 | else if(!StartWn) 98 | Data_var = Mem[MemAddress]; 99 | else begin 100 | Data_var = 'z; 101 | end 102 | end 103 | 104 | always_latch begin 105 | if (!W) 106 | Bus.dq_m = 'z; 107 | end 108 | 109 | //////////////////////////INSTANTIATIONS/////////////////////////////////////// 110 | 111 | //Instantiate the FSM Array using a Generate loop 112 | genvar i; 113 | generate; 114 | for(i=0;i<(BANKS*BANKGROUP);i++) begin 115 | assign Select[i] = (i=={BankGrp,Bank});//Select logic 116 | MemoryFSM fi(Bus,Select[i],Address,Warray[i],Rarray[i]); 117 | end 118 | endgenerate 119 | 120 | //Instantiate the read and write modules 121 | ReadMod RM( .read(~StartRn), 122 | .reset(StartRn), 123 | .DataBus(Bus.pin_dq), 124 | .DataHost(Data), 125 | .DQS_t(Bus.dqs_t), 126 | .DQS_c(Bus.dqs_c) 127 | ); 128 | 129 | WriteMod WM(.clock2x(clock2x), 130 | .reset(StartWn), 131 | .write(~StartWn), 132 | .DataBus(Bus.pin_dq), 133 | .DataHost(Data), 134 | .DQS_t(Bus.dqs_t), 135 | .DQS_c(Bus.dqs_c) 136 | ); 137 | 138 | 139 | //Instantiate the 2 shift registers to wait for TCL. One is for read and 140 | //the other is for write 141 | ShiftRegMem r(Bus.clock,~Bus.reset_n,{R,Ptr},RSch); 142 | ShiftRegMem w(Bus.clock,~Bus.reset_n,{W,Ptr},WSch); 143 | 144 | //////////////////////////////////////////////////////////////////////////////// 145 | 146 | //Final block displays memory contents 147 | final begin 148 | foreach(Mem[i]) begin 149 | $display("Mem[%x] = %x",i,Mem[i]); 150 | end 151 | end 152 | 153 | //////////////////////////CONTINUOUS ASSERTIONS/////////////////////////////////////////////////////// 154 | //LatchPointer should remain constant for 4 clock cycles 155 | 156 | property Latch_Pointer; 157 | @(posedge Bus.clock) 158 | (RSch[SHIFTBITS] || WSch[SHIFTBITS])|=> !($changed(LatchPtr))[*3]; 159 | endproperty 160 | 161 | assert property (Latch_Pointer) 162 | else $fatal("Latch pointer not constant\tLatchPointer:%0d",LatchPtr); 163 | 164 | 165 | property RWReg_Check; 166 | @ (posedge Bus.clock) 167 | ($fell(StartRn) || $fell(StartWn)) |-> !Start_check[*3]; 168 | endproperty 169 | 170 | assert property (RWReg_Check) 171 | else $fatal("Both Read and Write modules are active. StartWn:%x\tStartRn:%x",StartWn,StartRn); 172 | 173 | 174 | property Read_To_Start; 175 | @(posedge Bus.clock) 176 | $rose(R) |-> ##(TCL-2) $rose(RSch[SHIFTBITS]); 177 | endproperty 178 | assert property (Read_To_Start) 179 | else $error("TCL violation in Memory"); 180 | 181 | property Start; 182 | @ (posedge Bus.clock) 183 | $fell(StartRn) |=> !$changed(StartRn)[*3]; 184 | endproperty 185 | 186 | assert property (Start) 187 | else $error("Start is not Low for 4 clock cycle"); 188 | 189 | ////////////////////////////////////////////////////////////////////////////////////////////////// 190 | 191 | 192 | endmodule 193 | 194 | 195 | /***************************************************************************************** 196 | // MEMORY FSM for each BANK and BANK GROUP 197 | ******************************************************************************************/ 198 | module MemoryFSM#(`include "Definitions.pkg") 199 | ( 200 | interface Bus, 201 | input bit Select, 202 | output logic [ADDRESSWIDTH-1:0]Address, 203 | output logic W,R 204 | ); 205 | wire Activate; 206 | logic [RWIDTH - 1:0] Row; 207 | logic [CWIDTH - 1:0] Column; 208 | logic [B_BITS- 1:0] Bank; 209 | logic [BG_BITS- 1:0] BankGrp; 210 | 211 | typedef enum{init, wait_state, idle, refresh, activate, read, write, readA, writeA, precharge}State_T; 212 | State_T State, Prev; 213 | 214 | // Next State Logic for States activate, read, write 215 | function automatic State_T ReadWriteState(bit IsWrite, IsRead, IsWriteA, IsReadA, IsPrePreA); 216 | State_T next; 217 | unique case({IsWrite, IsRead, IsWriteA, IsReadA, IsPrePreA}) 218 | 5'b10000: next = write; 219 | 5'b01000: next = read; 220 | 5'b00100: next = writeA; 221 | 5'b00010: next = readA; 222 | 5'b00001: next = precharge; 223 | 5'b00000: next = wait_state; 224 | endcase 225 | return next; 226 | endfunction 227 | 228 | // Next State Logic in Sequential Block 229 | always_ff@(posedge Bus.clock) 230 | begin 231 | if(!Bus.reset_n) 232 | State <= init; 233 | else if(Select) 234 | unique case(State) 235 | init : begin 236 | unique case({Bus.IsActivate, Bus.IsRefresh}) 237 | 2'b10: State <= activate; 238 | 2'b01: State <= refresh; 239 | 2'b00: State <= idle; 240 | endcase 241 | end 242 | 243 | idle : begin 244 | unique case({Bus.IsActivate, Bus.IsRefresh}) 245 | 2'b10: State <= activate; 246 | 2'b01: State <= refresh; 247 | 2'b00: State <= idle; 248 | endcase 249 | end 250 | // put assertion for read and write signals to be 0 here 251 | /*idle_S: assert ($onehot0({Bus.IsActivate, Bus.IsRefresh}) 252 | else 253 | $warning("Idle State: Activate- %b, Refresh-%b", $sample(Bus.IsActivate), $sample(Bus.Refresh));*/ 254 | refresh : State <= idle; 255 | activate: State <= ReadWriteState(Bus.IsWrite, Bus.IsRead, Bus.IsWriteA, Bus.IsReadA, Bus.IsPrePreA); 256 | write : State <= wait_state; 257 | writeA : State <= precharge; 258 | read : State <= wait_state; 259 | readA : State <= precharge; 260 | wait_state:State <= ReadWriteState(Bus.IsWrite, Bus.IsRead, Bus.IsWriteA, Bus.IsReadA, Bus.IsPrePreA); 261 | precharge: State <= idle; 262 | endcase 263 | else 264 | State <= State; 265 | end 266 | 267 | // Output Function Logic 268 | always_comb 269 | begin 270 | {W,R} = '0; 271 | Address = 'z; 272 | unique case(State) 273 | init : `DPRINT; 274 | idle : `DPRINT; 275 | refresh : `DPRINT; 276 | activate: begin 277 | `DPRINT; 278 | {Row, Bank, BankGrp} = Bus.ReadRowBank; 279 | end 280 | read,readA : begin 281 | `DPRINT; 282 | {Column, Bank, BankGrp} = Bus.ReadColumnBank; 283 | Address = CalcAddress(Row, Bank, BankGrp, Column); 284 | W = 1'b1; 285 | end 286 | write,writeA : begin 287 | `DPRINT; 288 | {Column, Bank, BankGrp} = Bus.ReadColumnBank; 289 | Address = CalcAddress(Row, Bank, BankGrp, Column); 290 | R = 1'b1; 291 | end 292 | wait_state: `DPRINT; 293 | precharge: `DPRINT; 294 | endcase 295 | end 296 | 297 | function automatic logic [RWIDTH + Bus.B_BITS + Bus.BG_BITS + CWIDTH + 3 - 1:0] CalcAddress(logic[RWIDTH-1:0] Row, logic[Bus.B_BITS-1:0]Bank, logic[Bus.BG_BITS-1:0]BankGrp,logic [CWIDTH-1:0]Column); 298 | logic [ADDRESSWIDTH-1:0] Address; 299 | Address = {Row, Bank, Column[CWIDTH-1:3],BankGrp,6'b000_000}; 300 | return Address; 301 | 302 | endfunction 303 | 304 | endmodule 305 | 306 | -------------------------------------------------------------------------------- /MemoryController.sv: -------------------------------------------------------------------------------- 1 | //This file contains the Memory Controller module. 2 | //The Scheduler is included in another file named Scheduler.sv. This file instantiates 3 | //all necessary modules, such as the scheduler, and the communication module are instantiated here. 4 | // Author: Ananth Bhat 5 | 6 | module MemoryController 7 | #( 8 | `include "Definitions.pkg" 9 | ) 10 | ( 11 | input logic reset,clock,clock2x, 12 | interface DDR4Bus, MCTx, MCRx 13 | ); 14 | 15 | //Define signals for connection between read_command 16 | logic [ADDRESSWIDTH-1:0] Address_cs,Address_sf;//Scheduler Output 17 | logic [DATAWIDTH-1:0] Data_cs,Data_sf;//Scheduler Output 18 | logic rw_cs,rw_sf;//ReadWrite Cache to Scheduler;ReadWrite Scheduler to FSM 19 | logic [2:0] tag,tagreadin,tagreadout; 20 | logic full; //Full signal between Scheduler and receive_command 21 | logic buff; 22 | 23 | //Define Control,Address,data Signals for the FSM 24 | logic start,refresh,ap,done; 25 | wire [DATAWIDTH-1:0] data; 26 | logic [BWIDTH-1:0] bank; 27 | logic [BGWIDTH-1:0] bankgroup; 28 | logic [RWIDTH-1:0] row; 29 | logic [CWIDTH-1:0] column; 30 | logic [1:0] PageHit; 31 | logic PageMiss, PageEmpty; 32 | logic valid; 33 | 34 | /////////////////////////BUFFER/////////////////////////////////// 35 | 36 | //A buffer is created to store the result of a read 37 | //0The upper 512 MSB is the Data, the lower 3 bits are the tag 38 | logic [DATAWIDTH+TWIDTH-1:0] ReadBuffer; 39 | wire [514:3] databuff; 40 | always_ff @(posedge clock) 41 | begin 42 | if(buff) begin 43 | ReadBuffer[514:3] <= databuff; 44 | ReadBuffer[2:0] <= tagreadout;//Put Tag 45 | end 46 | else 47 | ReadBuffer <= ReadBuffer; 48 | end 49 | ////////////////////////////////////////////////////////////////// 50 | 51 | 52 | assign row = Address_sf [31:17]; 53 | assign bank = Address_sf[16:15]; 54 | assign column = {Address_sf[14:8],Address_sf[5:3]}; 55 | assign bankgroup = Address_sf[7:6]; 56 | 57 | //Instantiate all necessary mdoules 58 | //Instantiate the FSM 59 | MemContFSM m( .start, .rw(rw_sf), .refresh, .ap, 60 | .bank,.bankgroup, 61 | .row,.column, 62 | .datawrite(Data_sf), .dataread(databuff), .buff,.tagreadin,.tagreadout, 63 | .DDR4Bus(DDR4Bus), 64 | .reset,.clock,.clock2x,.done, 65 | .PageHit,.PageEmpty,.PageMiss 66 | ); 67 | 68 | //Instantiate the Scheduler 69 | Scheduler S ( .DataIn(Data_cs),.AddrIn(Address_cs), 70 | .rw_in(rw_cs),.reset,.clock,.valid, 71 | .DataOut(Data_sf), .AddrOut(Address_sf), 72 | .rw_out(rw_sf),.full,.refresh,.ap,.tag, 73 | .start,.done,.tagread(tagreadin),.tagfsm(tagreadout), 74 | .buff,.PageHit,.PageMiss,.PageEmpty 75 | ); 76 | 77 | //Interface to the Memory Controller receiver that receives requests from cache 78 | receive_command rc ( .IF(MCRx),.data_out(Data_cs), 79 | .addr_out(Address_cs), .valid,.rw_out(rw_cs), 80 | .tag_gen(tag),.fifo_full(full) 81 | ); 82 | 83 | //Interface to the Memory Controller that sends data to cache 84 | send_read_data srd ( .IF(MCTx), 85 | .data_in(ReadBuffer[514:3]), 86 | .tag_gen(ReadBuffer[2:0]), 87 | .internal_ready(buff) 88 | ); 89 | 90 | endmodule 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DDR4MemoryController 2 | 3 | #### Introduction 4 | 5 | This project implements a DDR4 Memory Controller in SystemVerilog which implements Open Page Policy and Out of Order execution. 6 | The project includes a CacheBFM (integrated in the Top Module) and a Memory BFM. The cache controller sends 64 bytes of write-data along with a 32-bit address and a read/write request. The memory controller has a queue which can store up to 8 requests. 7 | This project doesnt include an extensive testbench. However a Top module is included with 4 Write commands. The top module can be replaced with a more exhastive testbench. 8 | This project was originally developed for the Veloce Emulator. It has however been modified to run on the QuestaSim simulator. 9 | 10 | Authors: 11 | 12 | Ananth Bhat 13 | 14 | Niraj Thakkar 15 | 16 | Sriram VB 17 | 18 | Shivank Dhote 19 | 20 | #### Steps for Simulation 21 | 22 | A make file has been provided. To run the project, make sure QuestaSim is installed. In the Direcotry, run the following command: 23 | 24 | >% make 25 | 26 | This will automatically create a library, compile the files and simulate the project. 27 | The make file has been created with respect to QuestaSim. 28 | 29 | ### Copyrights 30 | Anyone who wishes to use this project and modify it can do so with but with permission from the authors. Please have a look at the license file included within the poject and make sure it is always included in all future versions of the project. 31 | 32 | #### The contribution of each memeber is given below: 33 | 34 | Ananth Bhat: MemoryController.sv, DDR4Interface.sv, ReadWrite.sv, ShiftReg.sv,C2MInterface.sv 35 | 36 | Sriram VB: Scheduler.sv, DDR4Interface.sv, ReadWrite.sv, ShiftReg.sv,Memory.sv,CalcMax.sv 37 | 38 | Niraj Thakkar: Read_data_comm.sv, Receive_command.sv, Send_command.sv 39 | 40 | Shivank Dhote: Top.sv 41 | -------------------------------------------------------------------------------- /ReadWrite.sv: -------------------------------------------------------------------------------- 1 | //This is a Data transfer module between the Memory Controller and the Memory. 2 | //It facilitates Data Transfer at Double Data Rate(DDR) 3 | //The modules in this file are used by both the Memory and the Controller 4 | //Authors: Ananth Bhat 5 | // Sriram VB 6 | 7 | ////////////////////////////////////DATA TRANSFER MODULE/////////////////////////////////// 8 | //Print Definition 9 | /***********Read Module********************/ 10 | //Reads 8 bursts of data from the Bus to the Host. 11 | //This module is used both by the Memory COntroller and the Memory BFM 12 | module ReadMod( 13 | input read, 14 | input reset, 15 | input [63:0] DataBus, 16 | output [7:0][63:0] DataHost, 17 | input DQS_t, 18 | input DQS_c); 19 | 20 | //Variable Definitions 21 | logic [7:0][63:0] varDataHost; 22 | assign DataHost = varDataHost; 23 | logic [2:0] count; 24 | 25 | //Counter to count 8 bursts of Data 26 | always_ff @(posedge DQS_t, posedge DQS_c) 27 | begin 28 | if(reset) 29 | count <= 3'b0; 30 | else 31 | count <= count + 1'b1; 32 | end 33 | 34 | //Procedural Block to transfer data 35 | always_ff @(posedge DQS_t, posedge DQS_c) begin 36 | if(reset) begin 37 | varDataHost <= 'z; 38 | end 39 | else if(read) begin 40 | varDataHost[count] <= DataBus; 41 | $strobe($time,"\t%m\tREAD\tDataBus is:%x\tDataHost is:%x\tcount=%0d",DataBus,DataHost,count); 42 | $display($time,"\t%m\tcount=%0d",count); 43 | end 44 | else begin 45 | varDataHost <= 'z; 46 | end 47 | end 48 | 49 | endmodule 50 | 51 | 52 | /***********Write Module********************/ 53 | //Writes 8 bursts of data from the Host to the Bus. 54 | //This module is used both by the Memory COntroller and the Memory BFM 55 | module WriteMod( 56 | input clock2x, 57 | input reset, 58 | input write, 59 | output [63:0] DataBus, 60 | input [7:0][63:0] DataHost, 61 | output logic DQS_t, 62 | output logic DQS_c); 63 | 64 | //Variable Definition 65 | logic [63:0] varDataBus; 66 | logic [2:0] count; 67 | 68 | assign DataBus = varDataBus; 69 | 70 | //Counter to count 8 bursts of Data 71 | always_ff @(posedge clock2x) 72 | begin 73 | if(reset) 74 | count <= 3'b0; 75 | else 76 | count <= count + 1'b1; 77 | end 78 | 79 | //Create Data Synchronous Strobe signals (DQS) 80 | always_ff@(posedge clock2x) begin 81 | if(reset) 82 | DQS_t = 1'b1; 83 | else begin 84 | case(write) 85 | 1'b0: DQS_t <= 'z; 86 | 1'b1: DQS_t <= ~DQS_t; 87 | endcase 88 | end 89 | end 90 | assign DQS_c = reset?1'b1:~DQS_t; 91 | 92 | //Procedural Block to transfer data 93 | always_ff@(negedge clock2x) begin 94 | if(reset) 95 | varDataBus <= 'z; 96 | else if(write) 97 | begin 98 | varDataBus <= DataHost[count]; 99 | $display($time,"\t%m\tcount=%0d",count); 100 | $strobe($time,"\t%m\tWRITE\tDataHost is:%x\tDataBus is:%x",DataHost[count],DataBus); 101 | end 102 | else 103 | varDataBus <= 'z; 104 | end 105 | 106 | endmodule 107 | -------------------------------------------------------------------------------- /Read_data_comm.sv: -------------------------------------------------------------------------------- 1 | //This file handles the communication between the memory controller and the \ 2 | //Cache BFM with respect to the data read by the controller from the memory. 3 | //Send_read_data is used by the controller 4 | //receive_read_data is used by the cache bfm 5 | //Author: Niraj Thakkar 6 | module send_read_data 7 | ( 8 | C2MInterface.Mem_data IF, 9 | input logic internal_ready, 10 | [IF.DWIDTH-1:0]data_in, 11 | [2:0] tag_gen 12 | ); 13 | 14 | assign IF.read_data = (internal_ready)?data_in:'z; 15 | assign IF.tag_data = (internal_ready)?tag_gen:'z; 16 | assign IF.valid_data = internal_ready; 17 | 18 | endmodule 19 | 20 | module receive_read_data 21 | (C2MInterface.Cache_data IF,output logic read_valid, [IF.DWIDTH-1:0] data_out,[2:0] tag_out); 22 | 23 | assign data_out = IF.read_data; 24 | assign tag_out = IF.tag_data; 25 | assign read_valid = IF.valid_data; 26 | 27 | endmodule 28 | -------------------------------------------------------------------------------- /Receive_command.sv: -------------------------------------------------------------------------------- 1 | //This module is used by the Memory controller to receive commands from the Cache 2 | //Author: Niraj Thakkar 3 | module receive_command 4 | ( 5 | C2MInterface.Mem_tran IF, 6 | input logic fifo_full, [2:0] tag_gen, 7 | output logic rw_out, valid, 8 | [IF.AWIDTH-1:0] addr_out, 9 | [IF.DWIDTH-1:0]data_out 10 | ); 11 | 12 | logic [IF.DWIDTH-1:0] data; 13 | logic [IF.AWIDTH-1:0] addr; 14 | logic [2:0] tag; 15 | logic rw; 16 | logic full; 17 | logic ack; 18 | 19 | assign valid = IF.ack_tran; 20 | 21 | //Enumerated types of States 22 | typedef enum logic [1:0] {init=2'b01,receive=2'b10}st; 23 | st state,next_state; 24 | 25 | //Sequential Logic 26 | always_ff @(posedge IF.clock) 27 | begin 28 | data_out<=data; 29 | addr_out<=addr; 30 | rw_out<=rw; 31 | 32 | if(IF.reset) 33 | state<=init; 34 | else begin 35 | state<=next_state; 36 | end 37 | end 38 | 39 | //Next State Logic 40 | always_comb 41 | begin 42 | case(state) 43 | init: if(fifo_full || !IF.valid_tran) 44 | next_state=init; 45 | else 46 | next_state=receive; 47 | 48 | receive: if(fifo_full || IF.valid_tran) 49 | next_state=init; 50 | else 51 | next_state=receive; 52 | endcase 53 | end 54 | 55 | always_comb 56 | begin 57 | case(state) 58 | init: 59 | begin 60 | if(fifo_full) 61 | IF.full=1; 62 | else 63 | IF.full=0; 64 | addr=IF.addr; data=IF.data_tran; 65 | rw=IF.rw; IF.ack_tran=0; 66 | tag=tag_gen; 67 | end 68 | receive: 69 | begin 70 | full=0; 71 | addr=IF.addr; 72 | rw=IF.rw; 73 | IF.ack_tran=1; 74 | IF.tag_tran=tag_gen; 75 | data=IF.data_tran; 76 | end 77 | endcase 78 | end 79 | 80 | endmodule 81 | -------------------------------------------------------------------------------- /Scheduler.sv: -------------------------------------------------------------------------------- 1 | //This file contains the Scheduler which handles out of order execution 2 | //as well as Open Page Policy. 3 | //Author: Sriram VB 4 | 5 | module Scheduler 6 | #( 7 | `include "Definitions.pkg", 8 | parameter threshold = 5 9 | ) 10 | ( 11 | input logic [DATAWIDTH-1:0] DataIn, 12 | input logic [ADDRESSWIDTH-1:0] AddrIn, 13 | input logic rw_in,reset,clock, 14 | input logic done,valid,buff, 15 | input [BuffBits-1:0] tagfsm, 16 | output logic [DATAWIDTH-1:0] DataOut, 17 | output logic [ADDRESSWIDTH-1:0] AddrOut, 18 | output logic rw_out, full,refresh,ap, 19 | output logic start, 20 | output logic [BuffBits -1:0]tagread, tag, 21 | output logic PageMiss, PageEmpty, 22 | output logic [1:0] PageHit 23 | ); 24 | 25 | ////////////////////////QUEUE///////////////////////////////// 26 | typedef struct packed 27 | { 28 | bit rw; 29 | logic [DATAWIDTH-1:0] data; 30 | //logic [ADDRESSWIDTH-1:0] address; 31 | logic [RWIDTH-1:0] row; 32 | logic [CWIDTH-1:0] column; 33 | logic [BWIDTH-1:0] bank; 34 | logic [BGWIDTH-1:0] bankgrp; 35 | logic rstcount; 36 | }Transaction; 37 | Transaction CurrentTx; 38 | Transaction Queue[BuffLength]; 39 | 40 | assign refresh = 1'b0; 41 | assign ap = 1'b0; 42 | 43 | /////////////////////////////////////// 44 | wire checkthresh; 45 | wire empty; 46 | logic NextPageHitL, NextPageHitS; 47 | logic [BuffBits-1:0] PageHitIndL,PageHitIndS; 48 | 49 | typedef logic [15:0] Count; 50 | Count [BuffLength - 1:0]Counters; 51 | 52 | logic [BuffBits-1:0] Readptr,Writeptr; 53 | logic [BuffBits-1:0] NextTr; 54 | 55 | logic [BuffLength-1:0] Freelist; 56 | logic [BuffLength-1:0] ThresholdCrossed; 57 | 58 | logic [BuffLength-1:0] ScheduledList; 59 | 60 | logic [BuffBits-1:0] MaxValue; 61 | 62 | logic [2:0] PageHitT; 63 | logic PageMissT; 64 | logic PageEmptyT; 65 | 66 | typedef struct packed 67 | { 68 | bit valid; 69 | logic [RWIDTH - 1:0] RowAddress; 70 | }OpenRow; 71 | OpenRow [BANKGROUP*BANKS -1:0]OpenRowList; 72 | 73 | ///////////////////Outputs to the CPU side modules//////////////// 74 | assign full = &Freelist; // bitwise AND of all the bits in the Freelist array 75 | assign empty = ~(|Freelist); 76 | assign tag = valid?Writeptr:'z; 77 | 78 | ///////////////Logic for filling the Queue/////////////////////////////// 79 | // write pointer pointing to the first empty memory 80 | always_latch begin 81 | if(!full) begin 82 | unique case(Freelist) inside 83 | 8'bxxxx_xxx0: Writeptr = 3'd0; 84 | 8'bxxxx_xx01: Writeptr = 3'd1; 85 | 8'bxxxx_x011: Writeptr = 3'd2; 86 | 8'bxxxx_0111: Writeptr = 3'd3; 87 | 8'bxxx0_1111: Writeptr = 3'd4; 88 | 8'bxx01_1111: Writeptr = 3'd5; 89 | 8'bx011_1111: Writeptr = 3'd6; 90 | 8'b0111_1111: Writeptr = 3'd7; 91 | endcase 92 | end 93 | end 94 | 95 | // writing into the queue 96 | always_ff@(posedge clock) begin 97 | if(valid) begin 98 | Queue[Writeptr].rw <= rw_in; 99 | Queue[Writeptr].row <= AddrIn[31:17]; 100 | Queue[Writeptr].column <= {AddrIn[14:8],AddrIn[5:3]}; 101 | Queue[Writeptr].bank <= AddrIn[16:15]; 102 | Queue[Writeptr].bankgrp <= AddrIn[7:6]; 103 | Queue[Writeptr].data <= DataIn; 104 | Queue[Writeptr].rstcount <= 1'b1; 105 | $display($time,"\tWriteptr: %0d\tQueue[ptr]=%x",Writeptr, AddrIn); 106 | end 107 | else begin 108 | for(int i=0;i Threshold) 165 | ThresholdCrossed[i] = 1'b1; 166 | else 167 | ThresholdCrossed[i] = 1'b0; 168 | end 169 | end 170 | 171 | assign checkthresh = |ThresholdCrossed; 172 | 173 | function automatic bit OpenPageShort(input logic [BuffBits-1:0] i); 174 | bit Open; 175 | if(Queue[i].row == OpenRowList[{Queue[i].bankgrp, Queue[i].bank}].RowAddress && OpenRowList[{Queue[i].bankgrp, Queue[i].bank}].valid && Freelist[i] && CurrentTx.bankgrp!=Queue[i].bankgrp && !ScheduledList[i]) 176 | Open = 1'b1; 177 | else 178 | Open = 1'b0; 179 | return Open; 180 | endfunction 181 | 182 | function automatic bit OpenPageLong(input logic [BuffBits-1:0] i); 183 | bit Open; 184 | if(Queue[i].row == OpenRowList[{Queue[i].bankgrp, Queue[i].bank}].RowAddress && OpenRowList[{Queue[i].bankgrp, Queue[i].bank}].valid && Freelist[i] && !ScheduledList[i]) 185 | Open = 1'b1; 186 | else 187 | Open = 1'b0; 188 | return Open; 189 | endfunction 190 | 191 | 192 | always_comb begin 193 | NextPageHitS = 1'b0; 194 | case(1'b1) 195 | OpenPageShort(3'd0): begin 196 | NextPageHitS = 1'b1; 197 | PageHitIndS = 3'd0; 198 | end 199 | OpenPageShort(3'd1): begin 200 | NextPageHitS = 1'b1; 201 | PageHitIndS = 3'd1; 202 | end 203 | OpenPageShort(3'd2): begin 204 | NextPageHitS = 1'b1; 205 | PageHitIndS = 3'd2; 206 | end 207 | OpenPageShort(3'd3): begin 208 | NextPageHitS = 1'b1; 209 | PageHitIndS = 3'd3; 210 | end 211 | OpenPageShort(3'd4): begin 212 | NextPageHitS = 1'b1; 213 | PageHitIndS = 3'd4; 214 | end 215 | OpenPageShort(3'd5): begin 216 | NextPageHitS = 1'b1; 217 | PageHitIndS = 3'd5; 218 | end 219 | OpenPageShort(3'd6): begin 220 | NextPageHitS = 1'b1; 221 | PageHitIndS = 3'd6; 222 | end 223 | OpenPageShort(3'd7): begin 224 | NextPageHitS = 1'b1; 225 | PageHitIndS = 3'd7; 226 | end 227 | endcase 228 | 229 | 230 | end 231 | 232 | always_comb begin 233 | NextPageHitL = 1'b0; 234 | case(1'b1) 235 | OpenPageLong(3'd0): begin 236 | NextPageHitL = 1'b1; 237 | PageHitIndL = 3'd0; 238 | end 239 | OpenPageLong(3'd1): begin 240 | NextPageHitL = 1'b1; 241 | PageHitIndL = 3'd1; 242 | end 243 | OpenPageLong(3'd2): begin 244 | NextPageHitL = 1'b1; 245 | PageHitIndL = 3'd2; 246 | end 247 | OpenPageLong(3'd3): begin 248 | NextPageHitL = 1'b1; 249 | PageHitIndL = 3'd3; 250 | end 251 | OpenPageLong(3'd4): begin 252 | NextPageHitL = 1'b1; 253 | PageHitIndL = 3'd4; 254 | end 255 | OpenPageLong(3'd5): begin 256 | NextPageHitL = 1'b1; 257 | PageHitIndL = 3'd5; 258 | end 259 | OpenPageLong(3'd6): begin 260 | NextPageHitL = 1'b1; 261 | PageHitIndL = 3'd6; 262 | end 263 | OpenPageLong(3'd7): begin 264 | NextPageHitL = 1'b1; 265 | PageHitIndL = 3'd7; 266 | end 267 | endcase 268 | end 269 | 270 | // Next State logic 271 | always_comb begin 272 | // Checking threshold 273 | if(checkthresh) begin 274 | NextTr = MaxValue; 275 | if(OpenPageShort(MaxValue)) 276 | {PageHitT,PageMissT,PageEmptyT} = 4'b1000; 277 | else if(OpenPageLong(MaxValue)) 278 | {PageHitT,PageMissT,PageEmptyT} = 4'b1100; 279 | else if(OpenRowList[{Queue[MaxValue].bankgrp,Queue[MaxValue].bank}].valid) 280 | {PageHitT,PageMissT,PageEmptyT} = 4'b0010; 281 | else 282 | {PageHitT,PageMissT,PageEmptyT} = 4'b0001; 283 | end 284 | 285 | // checking for tccds 286 | else if(NextPageHitS) begin 287 | NextTr = PageHitIndS; 288 | {PageHitT,PageMissT,PageEmptyT} = 4'b1000; 289 | end 290 | 291 | // checking for tccdl 292 | else if(NextPageHitL) begin 293 | NextTr = PageHitIndL; 294 | {PageHitT,PageMissT,PageEmptyT} = 4'b1100; 295 | end 296 | 297 | // checking for the max value 298 | else begin 299 | NextTr = MaxValue; 300 | if(OpenRowList[{Queue[MaxValue].bankgrp,Queue[MaxValue].bank}].valid) 301 | {PageHitT,PageMissT,PageEmptyT} = 4'b0010; 302 | else 303 | {PageHitT,PageMissT,PageEmptyT} = 4'b0001; 304 | end 305 | end 306 | 307 | // Giving values when done comes 308 | always_ff@(posedge clock) begin 309 | if(start || empty || !done) 310 | start <= 1'b0; 311 | else 312 | start <= 1'b1; 313 | end 314 | 315 | always_ff@(posedge clock) begin 316 | if(done) begin 317 | CurrentTx <= Queue[NextTr]; 318 | {PageHit,PageMiss,PageEmpty} <= {PageHitT,PageMissT,PageEmptyT}; 319 | Readptr <= NextTr; 320 | tagread <= NextTr; 321 | end 322 | end 323 | 324 | // writing into the queue 325 | always_ff@(posedge clock) begin 326 | if(done) begin 327 | rw_out <= Queue[NextTr].rw; 328 | AddrOut[31:17] <= Queue[NextTr].row; 329 | AddrOut[14:8] <= Queue[NextTr].column[CWIDTH-1:3]; 330 | AddrOut[16:15] <= Queue[NextTr].bank; 331 | AddrOut[7:6] <= Queue[NextTr].bankgrp; 332 | AddrOut[5:0] <= 6'b0; 333 | DataOut <= Queue[NextTr].data; 334 | end 335 | end 336 | 337 | // updating the table of open rows 338 | always_ff@(posedge clock) begin 339 | int i; 340 | if(reset) begin 341 | for(i=0;i> 31; 84 | valid <= 1'b1; 85 | flag <=1; 86 | $strobe($time,"\t%m\tAddress Sent:%x:", address); 87 | end 88 | else if (ack_in) 89 | begin 90 | valid <= 1'b0; 91 | $display($time,"\t%m\tThe tag received is:%0d",tag_in); 92 | MemoryTb[tag_in] <= sentvalue; 93 | flag <= 1'b0; 94 | end 95 | else begin 96 | address <= sentvalue; 97 | data_in <= {16{sentvalue}}; 98 | operation <= sentvalue >> 31; 99 | valid <= 1'b1; 100 | end 101 | end 102 | else 103 | begin 104 | valid <=0; 105 | flag <= 0; 106 | end 107 | end 108 | 109 | always@(posedge clock) 110 | begin 111 | if(ack_out) 112 | begin 113 | receivedvalue <= data_out[31:0]; 114 | errorvalue <= 32'hFFFFFFFF; 115 | if(receivedvalue === MemoryTb[tag_out]) 116 | $display("The Data Read has matched"); 117 | else 118 | $display("The Data Read hasnt matched"); 119 | end 120 | end 121 | 122 | 123 | 124 | //initial 125 | // $monitor($time,"\tACT:%b\tCS:%b\tCKE:%b\tAddress:%h\tData:%x\tDone:%x\tStart:%x",DDR4Bus.act_n,DDR4Bus.cs_n,DDR4Bus.cke,sentvalue,DDR4Bus.pin_dq,C.S.done,C.S.start); 126 | // $monitor($time,"\tACK_IN:%x,FLAG:%x,ACK_OUT:%x,Address:%x\tcontrol:%x\tvalid:%x\tvalid_xrtl:%x\tfull:%0d",ack_in,flag,ack_out,address,control,valid,sc.valid_xrtl,full); 127 | /* 128 | final 129 | $display("Full is : %0d",full); 130 | */ 131 | //Instantiate the DDR4Interface 132 | DDR4Interface DDR4Bus (clock,Reset); 133 | 134 | //Instantiate The C2M Bus 135 | C2MInterface C2MBus (clock,Reset); 136 | 137 | //Instantiate The Memory BFM 138 | Memory M (DDR4Bus.Memory,clock2x); 139 | 140 | //Instantiate the Memory Controller 141 | MemoryController C (.clock2x, .clock, .reset(Reset), .DDR4Bus(DDR4Bus.Controller),.MCTx(C2MBus.Mem_data),.MCRx(C2MBus.Mem_tran)); 142 | 143 | receive_read_data rrd (C2MBus, ack_out, data_out, tag_out); 144 | send_command sc (C2MBus, operation, valid, data_in,address, ack_in, full,tag_in); 145 | 146 | endmodule 147 | --------------------------------------------------------------------------------