138 lines
5.7 KiB
Python
138 lines
5.7 KiB
Python
#! /usr/bin/env python3
|
|
# vim: set fileencoding=utf-8
|
|
|
|
# Copyright (c) 2018, Technische Universität Kaiserslautern
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are
|
|
# met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above copyright notice,
|
|
# this list of conditions and the following disclaimer.
|
|
#
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# 3. Neither the name of the copyright holder nor the names of its
|
|
# contributors may be used to endorse or promote products derived from
|
|
# this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
|
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
# Author: Éder F. Zulian
|
|
|
|
import ctypes
|
|
|
|
# A trace file is a pre-recorded file containing memory transactions. Each
|
|
# memory transaction has a timestamp that tells the simulator when it shall
|
|
# happen, a transaction type (read or write) and a memory address given in
|
|
# hexadecimal.
|
|
#
|
|
# Here is an example syntax:
|
|
#
|
|
# ```
|
|
# # Comment lines begin with #
|
|
# # [clock-cyle]: [write|read] [hex-address]
|
|
# 31: read 0x400140
|
|
# 33: read 0x400160
|
|
# 56: write 0x7fff8000
|
|
# 81: read 0x400180
|
|
# ```
|
|
#
|
|
# The timestamp corresponds to the time the request is to be issued and it is
|
|
# given in cycles of the bus master device. Example: the device is a FPGA with
|
|
# frequency 200 MHz (clock period of 5 ns). If the timestamp is 10 it means
|
|
# that the request is to be issued when time is 50 ns.
|
|
#
|
|
|
|
# The default values given as example assume the following address mapping:
|
|
#
|
|
# DIMM Characteristics:
|
|
# Byte Offset (Y): 8 [0:2] (8-byte-wide memory module, i.e., 64-bit-wide data bus) -> 3 bit
|
|
# Cols (C): 1K [3:12] (A0 - A9) -> 10 bit
|
|
# Rows (R): 128K [13:29] (A0 - A16) -> 17 bit
|
|
# Bank (B): 8 [30:32] (BA0 - BA2) -> 3 bit
|
|
#
|
|
# 3 3 3 | 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 | 1 1 1
|
|
# 2 1 0 | 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 | 2 1 0 9 8 7 6 5 4 3 | 2 1 0
|
|
# B B B | R R R R R R R R R R R R R R R R R | C C C C C C C C C C | Y Y Y
|
|
#
|
|
|
|
# Transaction type (read or write)
|
|
transaction = 'read'
|
|
|
|
# Channel information. If your address mapping does not have channel bits keep
|
|
# it equal to 1 and set the shift to the extreme left of the address.
|
|
num_ch = 1 # Number of channels
|
|
ch_shift = 34 # Shift to reach the frist bit reserved for channels in the address
|
|
ch_mask = 0x1 # Mask for all channel bits in the address
|
|
|
|
# Bank group information. If your address mapping does not have bank groups
|
|
# keep it equal to 1 and set the shift to the extreme left of the address.
|
|
num_bank_groups = 1 # Number of bank groups
|
|
bgroup_shift = 33 # Shift to reach the frist bit reserved for bank groups in the address
|
|
bgroup_mask = 0x1 # Mask for all bits in the address related to bank groups
|
|
|
|
# Bank information
|
|
num_banks = 8 # Number of banks
|
|
bank_shift = 30 # Shift to reach the frist bit reserved for banks in the address
|
|
bank_mask = 0x7 # Mask for all bank bits in the address
|
|
|
|
# Row information
|
|
num_rows = 128 * 1024 # Number of rows
|
|
row_shift = 13 # Shift to reach the frist bit reserved for rows in the address
|
|
row_mask = 0x1ffff # Mask for all row bits in the address
|
|
|
|
# Column information
|
|
num_col = 1 * 1024 # Number of columns
|
|
col_shift = 3 # Shift to reach the frist bit reserved for columns in the address
|
|
col_mask = 0x3ff # Mask for all column bits in the address
|
|
|
|
# Burst length of 8 columns. 8 columns written/read per access (in 4 full
|
|
# clock cycles of the memory bus).
|
|
burst_len = 8
|
|
|
|
# Initial clock cycle
|
|
clock_cycle = 0
|
|
|
|
# Clock cycle increment between two accesses
|
|
clock_increment = 10
|
|
|
|
|
|
def clear_bits(mask, shift, val):
|
|
m = ctypes.c_uint64(~(mask << shift)).value
|
|
return ctypes.c_uint64(val & m).value
|
|
|
|
|
|
def set_bits(mask, shift, val, v):
|
|
val = clear_bits(mask, shift, val)
|
|
return ctypes.c_uint64(val | (v << shift)).value
|
|
|
|
|
|
address = 0
|
|
for ch in range(0, num_ch):
|
|
address = set_bits(ch_mask, ch_shift, address, ch)
|
|
for bg in range(0, num_bank_groups):
|
|
address = set_bits(bgroup_mask, bgroup_shift, address, bg)
|
|
for b in range(0, num_banks):
|
|
address = set_bits(bank_mask, bank_shift, address, b)
|
|
for row in range(0, num_rows):
|
|
address = set_bits(row_mask, row_shift, address, row)
|
|
for col in range(0, num_col, burst_len):
|
|
address = set_bits(col_mask, col_shift, address, col)
|
|
print('# clock cycle: {0:d} | {1} | address: 0x{2:010X} | channel: {3} | bank group: {4} | bank: {5} | row: {6} | column: {7}'.format(clock_cycle, transaction, address, ch, bg, b, row, col))
|
|
print('{0:d}:\t{1}\t0x{2:010X}'.format(clock_cycle, transaction, address))
|
|
clock_cycle = clock_cycle + clock_increment
|