From c4898b15bcf5458e35f17cb0c3b4185cec0081aa Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Thu, 31 Jan 2013 07:49:14 -0500 Subject: [PATCH] mem: Add DDR3 and LPDDR2 DRAM controller configurations This patch moves the default DRAM parameters from the SimpleDRAM class to two different subclasses, one for DDR3 and one for LPDDR2. More can be added as we go forward. The regressions that previously used the SimpleDRAM are now using SimpleDDR3 as this is the most similar configuration. --- configs/common/FSConfig.py | 28 ++++---- src/mem/SimpleDRAM.py | 108 ++++++++++++++++++++++++----- tests/configs/inorder-timing.py | 2 +- tests/configs/o3-timing-checker.py | 2 +- tests/configs/o3-timing-mp.py | 2 +- tests/configs/o3-timing.py | 2 +- tests/configs/tgen-simple-dram.py | 2 +- 7 files changed, 111 insertions(+), 35 deletions(-) diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index eb0730ffa..fb3a5408f 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -73,7 +73,7 @@ def makeLinuxAlphaSystem(mem_mode, mdesc = None): # base address (including the PCI config space) self.bridge = Bridge(delay='50ns', ranges = [AddrRange(IO_address_space_base, Addr.max)]) - self.physmem = SimpleDRAM(range = AddrRange(mdesc.mem())) + self.physmem = SimpleDDR3(range = AddrRange(mdesc.mem())) self.mem_ranges = [self.physmem.range] self.bridge.master = self.iobus.slave self.bridge.slave = self.membus.master @@ -110,7 +110,7 @@ def makeLinuxAlphaRubySystem(mem_mode, mdesc = None): ide = IdeController(disks=[Parent.disk0, Parent.disk2], pci_func=0, pci_dev=0, pci_bus=0) - physmem = SimpleDRAM(range = AddrRange(mdesc.mem())) + physmem = SimpleDDR3(range = AddrRange(mdesc.mem())) self = LinuxAlphaSystem(physmem = physmem) self.mem_ranges = [self.physmem.range] if not mdesc: @@ -180,10 +180,10 @@ def makeSparcSystem(mem_mode, mdesc = None): self.t1000 = T1000() self.t1000.attachOnChipIO(self.membus) self.t1000.attachIO(self.iobus) - self.physmem = SimpleDRAM(range = AddrRange(Addr('1MB'), size = '64MB'), - zero = True) - self.physmem2 = SimpleDRAM(range = AddrRange(Addr('2GB'), size ='256MB'), - zero = True) + self.physmem = SimpleDDR3(range = AddrRange(Addr('1MB'), size = '64MB'), + zero = True) + self.physmem2 = SimpleDDR3(range = AddrRange(Addr('2GB'), size ='256MB'), + zero = True) self.mem_ranges = [self.physmem.range, self.physmem2.range] self.bridge.master = self.iobus.slave self.bridge.slave = self.membus.master @@ -274,8 +274,8 @@ def makeArmSystem(mem_mode, machine_type, mdesc = None, bare_metal=False): if bare_metal: # EOT character on UART will end the simulation self.realview.uart.end_on_eot = True - self.physmem = SimpleDRAM(range = AddrRange(Addr(mdesc.mem())), - zero = True) + self.physmem = SimpleDDR3(range = AddrRange(Addr(mdesc.mem())), + zero = True) self.mem_ranges = [self.physmem.range] else: self.kernel = binary('vmlinux.arm.smp.fb.2.6.38.8') @@ -289,10 +289,10 @@ def makeArmSystem(mem_mode, machine_type, mdesc = None, bare_metal=False): boot_flags = 'earlyprintk console=ttyAMA0 lpj=19988480 norandmaps ' + \ 'rw loglevel=8 mem=%s root=/dev/sda1' % mdesc.mem() - self.physmem = SimpleDRAM(range = - AddrRange(self.realview.mem_start_addr, - size = mdesc.mem()), - conf_table_reported = True) + self.physmem = SimpleDDR3(range = + AddrRange(self.realview.mem_start_addr, + size = mdesc.mem()), + conf_table_reported = True) self.mem_ranges = [self.physmem.range] self.realview.setupBootLoader(self.membus, self, binary) self.gic_cpu_addr = self.realview.gic.cpu_addr @@ -328,7 +328,7 @@ def makeLinuxMipsSystem(mem_mode, mdesc = None): self.iobus = NoncoherentBus() self.membus = MemBus() self.bridge = Bridge(delay='50ns') - self.physmem = SimpleDRAM(range = AddrRange('1GB')) + self.physmem = SimpleDDR3(range = AddrRange('1GB')) self.mem_ranges = [self.physmem.range] self.bridge.master = self.iobus.slave self.bridge.slave = self.membus.master @@ -434,7 +434,7 @@ def makeX86System(mem_mode, numCPUs = 1, mdesc = None, self = None, Ruby = False self.mem_mode = mem_mode # Physical memory - self.physmem = SimpleDRAM(range = AddrRange(mdesc.mem())) + self.physmem = SimpleDDR3(range = AddrRange(mdesc.mem())) self.mem_ranges = [self.physmem.range] # Platform diff --git a/src/mem/SimpleDRAM.py b/src/mem/SimpleDRAM.py index 83eaac611..41bad9356 100644 --- a/src/mem/SimpleDRAM.py +++ b/src/mem/SimpleDRAM.py @@ -63,11 +63,6 @@ class SimpleDRAM(AbstractMemory): # bus in front of the controller for multiple ports port = SlavePort("Slave port") - # the physical organisation of the DRAM - lines_per_rowbuffer = Param.Unsigned(64, "Row buffer size in cache lines") - ranks_per_channel = Param.Unsigned(2, "Number of ranks per channel") - banks_per_rank = Param.Unsigned(8, "Number of banks per rank") - # the basic configuration of the controller architecture write_buffer_size = Param.Unsigned(32, "Number of read queue entries") read_buffer_size = Param.Unsigned(32, "Number of write queue entries") @@ -77,21 +72,26 @@ class SimpleDRAM(AbstractMemory): write_thresh_perc = Param.Percent(70, "Threshold to trigger writes") # scheduler, address map and page policy - mem_sched_policy = Param.MemSched('fcfs', "Memory scheduling policy") + mem_sched_policy = Param.MemSched('frfcfs', "Memory scheduling policy") addr_mapping = Param.AddrMap('openmap', "Address mapping policy") page_policy = Param.PageManage('open', "Page closure management policy") + # the physical organisation of the DRAM + lines_per_rowbuffer = Param.Unsigned("Row buffer size in cache lines") + ranks_per_channel = Param.Unsigned("Number of ranks per channel") + banks_per_rank = Param.Unsigned("Number of banks per rank") + # timing behaviour and constraints - all in nanoseconds # the amount of time in nanoseconds from issuing an activate command # to the data being available in the row buffer for a read/write - tRCD = Param.Latency("14ns", "RAS to CAS delay") + tRCD = Param.Latency("RAS to CAS delay") # the time from issuing a read/write command to seeing the actual data - tCL = Param.Latency("14ns", "CAS latency") + tCL = Param.Latency("CAS latency") # minimum time between a precharge and subsequent activate - tRP = Param.Latency("14ns", "Row precharge time") + tRP = Param.Latency("Row precharge time") # time to complete a burst transfer, typically the burst length # divided by two due to the DDR bus, but by making it a parameter @@ -99,23 +99,22 @@ class SimpleDRAM(AbstractMemory): # This parameter has to account for bus width and burst length. # Adjustment also necessary if cache line size is greater than # data size read/written by one full burst. - tBURST = Param.Latency("4ns", - "Burst duration (for DDR burst length / 2 cycles)") + tBURST = Param.Latency("Burst duration (for DDR burst length / 2 cycles)") # time taken to complete one refresh cycle (N rows in all banks) - tRFC = Param.Latency("300ns", "Refresh cycle time") + tRFC = Param.Latency("Refresh cycle time") # refresh command interval, how often a "ref" command needs # to be sent. It is 7.8 us for a 64ms refresh requirement - tREFI = Param.Latency("7.8us", "Refresh command interval") + tREFI = Param.Latency("Refresh command interval") # write-to-read turn around penalty, assumed same as read-to-write - tWTR = Param.Latency("1ns", "Write to read switching time") + tWTR = Param.Latency("Write to read switching time") # time window in which a maximum number of activates are allowed # to take place, set to 0 to disable - tXAW = Param.Latency("0ns", "X activation window") - activation_limit = Param.Unsigned(4, "Max number of activates in window") + tXAW = Param.Latency("X activation window") + activation_limit = Param.Unsigned("Max number of activates in window") # Currently rolled into other params ###################################################################### @@ -127,3 +126,80 @@ class SimpleDRAM(AbstractMemory): # tRC - assumed to be 4 * tRP # burst length for an access derived from peerBlockSize + +# High-level model of a single DDR3 x64 interface (one command and +# address bus), with default timings based on a DDR3-1600 4 Gbit part, +# which would amount to 4 Gbyte of memory in 8x8 or 8 GByte in 16x4 +# configuration. +class SimpleDDR3(SimpleDRAM): + # Assuming 64 byte cache lines, use a 2kbyte page size, this + # depends on the memory density + lines_per_rowbuffer = 32 + + # Use two ranks + ranks_per_channel = 2 + + # DDR3 has 8 banks in all configurations + banks_per_rank = 8 + + # DDR3-1600 11-11-11 + tRCD = '13.75ns' + tCL = '13.75ns' + tRP = '13.75ns' + + # Assuming 64 byte cache lines, across an x64 (8x8 or 16x4) + # interface, translates to BL8, 4 clocks @ 800 MHz + tBURST = '5ns' + + # DDR3, 4 Gb has a tRFC of 240 CK and tCK = 1.25 ns + tRFC = '300ns' + + # DDR3, <=85C, half for >85C + tREFI = '7.8us' + + # Greater of 4 CK or 7.5 ns, 4 CK @ 800 MHz = 5 ns + tWTR = '7.5ns' + + # With a 2kbyte page size, DDR3-1600 lands around 40 ns + tXAW = '40ns' + activation_limit = 4 + + +# High-level model of a single LPDDR2-S4 x64 interface (one +# command/address bus), with default timings based on a LPDDR2-1066 +# 4Gbit part, which whould amount to 1 GByte of memory in 2x32 or +# 2GByte in 4x16 configuration. +class SimpleLPDDR2_S4(SimpleDRAM): + # Assuming 64 byte cache lines, use a 2kbyte page size, this + # depends on the memory density + lines_per_rowbuffer = 32 + + # Use two ranks + ranks_per_channel = 2 + + # LPDDR2-S4 has 8 banks in all configurations + banks_per_rank = 8 + + # Fixed at 15 ns + tRCD = '15ns' + + # 8 CK read latency, 4 CK write latency @ 533 MHz, 1.876 ns cycle time + tCL = '15ns' + + # Pre-charge one bank 15 ns and all banks 18 ns + tRP = '18ns' + + # Assuming 64 byte cache lines, across a x64 interface (2x32 or + # 4x16), translates to BL8, 4 clocks @ 533 MHz + tBURST = '7.5ns' + + # LPDDR2-S4, 4 Gb + tRFC = '130ns' + tREFI = '3.9us' + + # Irrespective of speed grade, tWTR is 7.5 ns + tWTR = '7.5ns' + + # Irrespective of size, tFAW is 50 ns + tXAW = '50ns' + activation_limit = 4 diff --git a/tests/configs/inorder-timing.py b/tests/configs/inorder-timing.py index a92c61ba1..77c4f3d18 100644 --- a/tests/configs/inorder-timing.py +++ b/tests/configs/inorder-timing.py @@ -39,7 +39,7 @@ cpu.addTwoLevelCacheHierarchy(L1Cache(size = '128kB'), cpu.clock = '2GHz' system = System(cpu = cpu, - physmem = SimpleDRAM(), + physmem = SimpleDDR3(), membus = CoherentBus(), mem_mode = "timing") system.system_port = system.membus.slave diff --git a/tests/configs/o3-timing-checker.py b/tests/configs/o3-timing-checker.py index a33a2ac06..cd15cf66b 100644 --- a/tests/configs/o3-timing-checker.py +++ b/tests/configs/o3-timing-checker.py @@ -52,7 +52,7 @@ cpu.addTwoLevelCacheHierarchy(L1Cache(size = '128kB'), cpu.clock = '2GHz' system = System(cpu = cpu, - physmem = SimpleDRAM(), + physmem = SimpleDDR3(), membus = CoherentBus(), mem_mode = "timing") system.system_port = system.membus.slave diff --git a/tests/configs/o3-timing-mp.py b/tests/configs/o3-timing-mp.py index c3a4929bb..59f91a392 100644 --- a/tests/configs/o3-timing-mp.py +++ b/tests/configs/o3-timing-mp.py @@ -36,7 +36,7 @@ cpus = [ DerivO3CPU(cpu_id=i) for i in xrange(nb_cores) ] # system simulated system = System(cpu = cpus, - physmem = SimpleDRAM(), + physmem = SimpleDDR3(), membus = CoherentBus(), mem_mode = "timing") diff --git a/tests/configs/o3-timing.py b/tests/configs/o3-timing.py index 474d13902..8c3c9abe7 100644 --- a/tests/configs/o3-timing.py +++ b/tests/configs/o3-timing.py @@ -41,7 +41,7 @@ cpu.addTwoLevelCacheHierarchy(L1Cache(size = '128kB'), cpu.clock = '2GHz' system = System(cpu = cpu, - physmem = SimpleDRAM(), + physmem = SimpleDDR3(), membus = CoherentBus(), mem_mode = "timing") system.system_port = system.membus.slave diff --git a/tests/configs/tgen-simple-dram.py b/tests/configs/tgen-simple-dram.py index 0e9edc171..19eb15933 100644 --- a/tests/configs/tgen-simple-dram.py +++ b/tests/configs/tgen-simple-dram.py @@ -48,7 +48,7 @@ require_sim_object("CommMonitor") cpu = TrafficGen(config_file = "tests/quick/se/70.tgen/tgen-simple-dram.cfg") # system simulated -system = System(cpu = cpu, physmem = SimpleDRAM(), +system = System(cpu = cpu, physmem = SimpleDDR3(), membus = NoncoherentBus(clock="1GHz", width = 16)) # add a communication monitor