aboutsummaryrefslogtreecommitdiffstats
path: root/sources/apps/QUAC-TRNG
diff options
context:
space:
mode:
Diffstat (limited to 'sources/apps/QUAC-TRNG')
-rw-r--r--sources/apps/QUAC-TRNG/.gitignore1
-rw-r--r--sources/apps/QUAC-TRNG/Makefile.ent28
-rw-r--r--sources/apps/QUAC-TRNG/Makefile.observe32
-rw-r--r--sources/apps/QUAC-TRNG/Makefile.sha28
-rw-r--r--sources/apps/QUAC-TRNG/README.md58
-rw-r--r--sources/apps/QUAC-TRNG/bin/.gitkeep0
-rw-r--r--sources/apps/QUAC-TRNG/scripts/convert_ent.py32
-rw-r--r--sources/apps/QUAC-TRNG/scripts/ft200_rc/README.md21
-rw-r--r--sources/apps/QUAC-TRNG/scripts/ft200_rc/__init__.py0
-rw-r--r--sources/apps/QUAC-TRNG/scripts/ft200_rc/docs/1189902393_ft200_lcd.pdfbin0 -> 14203337 bytes
-rw-r--r--sources/apps/QUAC-TRNG/scripts/ft200_rc/docs/210.pdfbin0 -> 102947 bytes
-rw-r--r--sources/apps/QUAC-TRNG/scripts/ft200_rc/ft200.py182
-rwxr-xr-xsources/apps/QUAC-TRNG/scripts/ft200_rc/usb_dev_path.sh13
-rw-r--r--sources/apps/QUAC-TRNG/scripts/run_ent.py43
-rw-r--r--sources/apps/QUAC-TRNG/scripts/run_vn_nist.py125
-rw-r--r--sources/apps/QUAC-TRNG/scripts/sha_bitstreams.py87
-rw-r--r--sources/apps/QUAC-TRNG/scripts/top_ents.py35
-rw-r--r--sources/apps/QUAC-TRNG/src/observe.cpp726
-rw-r--r--sources/apps/QUAC-TRNG/src/slow_entropy.cpp204
-rw-r--r--sources/apps/QUAC-TRNG/src/slow_sha.cpp233
-rw-r--r--sources/apps/QUAC-TRNG/src/util.cpp670
-rw-r--r--sources/apps/QUAC-TRNG/src/util.h55
22 files changed, 2573 insertions, 0 deletions
diff --git a/sources/apps/QUAC-TRNG/.gitignore b/sources/apps/QUAC-TRNG/.gitignore
new file mode 100644
index 0000000..8fce603
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/.gitignore
@@ -0,0 +1 @@
+data/
diff --git a/sources/apps/QUAC-TRNG/Makefile.ent b/sources/apps/QUAC-TRNG/Makefile.ent
new file mode 100644
index 0000000..468a10b
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/Makefile.ent
@@ -0,0 +1,28 @@
+program_NAME := bin/ENT
+program_CXX_SRCS := src/slow_entropy.cpp src/util.cpp $(wildcard ../../api/*.c) $(wildcard ../../api/*.cpp)
+program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
+program_CXX_OBJS := ${program_CXX_OBJS:.c=.o}
+program_OBJS := $(program_CXX_OBJS)
+program_INCLUDE_DIRS := ../../api ../../../boost-lib
+program_LIBRARY_DIRS :=
+program_LIBRARIES :=
+CPPFLAGS += -g -std=c++11 -pthread -O3
+
+CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
+LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
+LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))
+
+CC=g++
+
+.PHONY: all clean distclean
+
+all: $(program_NAME)
+
+$(program_NAME): $(program_OBJS)
+ $(CC) $(CPPFLAGS) $(program_OBJS) -o $(program_NAME) $(LDFLAGS)
+
+clean:
+ @- $(RM) $(program_NAME)
+ @- $(RM) $(program_OBJS)
+
+distclean: clean
diff --git a/sources/apps/QUAC-TRNG/Makefile.observe b/sources/apps/QUAC-TRNG/Makefile.observe
new file mode 100644
index 0000000..d5b1adb
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/Makefile.observe
@@ -0,0 +1,32 @@
+program_NAME := bin/OBSERVE
+program_CXX_SRCS := src/observe.cpp $(wildcard ../../api/*.c) $(wildcard ../../api/*.cpp)
+program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
+program_CXX_OBJS := ${program_CXX_OBJS:.c=.o}
+program_OBJS := $(program_CXX_OBJS)
+program_INCLUDE_DIRS := ../../api ../../../boost-lib
+program_LIBRARY_DIRS :=
+program_LIBRARIES :=
+CPPFLAGS += -g -std=c++11 -pthread -O3
+
+CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
+LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
+LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))
+
+CC=g++
+
+.PHONY: all clean distclean
+
+all: $(program_NAME)
+
+$(program_NAME): $(program_OBJS)
+ $(CC) $(CPPFLAGS) $(program_OBJS) -o $(program_NAME) $(LDFLAGS)
+
+clean:
+ @- $(RM) $(program_NAME)
+ @- $(RM) $(program_OBJS)
+
+parser:
+ $(MAKE) -C ../../api/lexyacc
+ cp ../../api/lexyacc/smc_parser .
+
+distclean: clean
diff --git a/sources/apps/QUAC-TRNG/Makefile.sha b/sources/apps/QUAC-TRNG/Makefile.sha
new file mode 100644
index 0000000..bd0c463
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/Makefile.sha
@@ -0,0 +1,28 @@
+program_NAME := bin/SHA
+program_CXX_SRCS := src/slow_sha.cpp src/util.cpp $(wildcard ../../api/*.c) $(wildcard ../../api/*.cpp)
+program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
+program_CXX_OBJS := ${program_CXX_OBJS:.c=.o}
+program_OBJS := $(program_CXX_OBJS)
+program_INCLUDE_DIRS := ../../api ../../../boost-lib
+program_LIBRARY_DIRS :=
+program_LIBRARIES := ssl crypto
+CPPFLAGS += -g -std=c++11 -pthread -O3
+
+CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
+LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
+LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))
+
+CC=g++
+
+.PHONY: all clean distclean
+
+all: $(program_NAME)
+
+$(program_NAME): $(program_OBJS)
+ $(CC) $(CPPFLAGS) $(program_OBJS) -o $(program_NAME) $(LDFLAGS)
+
+clean:
+ @- $(RM) $(program_NAME)
+ @- $(RM) $(program_OBJS)
+
+distclean: clean
diff --git a/sources/apps/QUAC-TRNG/README.md b/sources/apps/QUAC-TRNG/README.md
new file mode 100644
index 0000000..437d0dd
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/README.md
@@ -0,0 +1,58 @@
+## Scripts to Reproduce QUAC-TRNG
+
+This directory provides all necessary files and instructions to reproduce the results of [QUAC-TRNG](https://people.inf.ethz.ch/omutlu/pub/QUAC-TRNG-DRAM_isca21.pdf).
+
+```
+@inproceedings{olgun2022quactrng,
+ title={QUAC-TRNG: High-Throughput True Random Number Generation Using Quadruple Row Activation in Commodity DRAM Chips},
+ author={Ataberk Olgun, Minesh Patel, A. Giray Yaglikci, Haocong Luo, Jeremie S. Kim, F. Nisa Bostanci, Nandita Vijaykumar, Oguz Ergin, and Onur Mutlu},
+ year={2021},
+ booktitle={ISCA}
+}
+```
+
+### Obtain NIST STS
+
+Download the NIST standard test suite (NIST STS) for random number generators using [this link](https://github.com/arcetri/sts). Install it under `tools` using the instructions provided in the linked repository's README.
+
+After installing NIST STS, `QUAC-TRNG/tools/sts` should point to the NIST STS executable.
+
+### Copy SoftMC_reset to bin/
+
+Run the following command to copy the reset program under bin/ directory.
+
+`cp ../ResetBoard/SoftMC_reset bin/`
+
+### Entropy Tests
+
+To run entropy tests, simply execute the `run_ent.py` script (you have to execute this in QUAC-TRNG directory):
+
+```
+make -f Makefile.ent
+python3 scripts/run_ent.py <DIMM_NAME> <TEMPERATURE_IN_CELCIUS> <QUAC_ITERATIONS> <ROW_STRIDE>
+```
+
+Example: `python3 scripts/run_ent.py hytt04 50 1000 4`
+
+This script will output one text file for every tested 4-bit data pattern (variable named placement in run_ent.py). Each line in the text file starts with the starting `row id` of a DRAM segment, followed by the observed entropy numbers for each bit in the segment.
+
+### von Neumann Corrected Bitstreams
+
+This will collect 1 Mb bitstreams from frequently switching bitlines and input them to NIST STS. The script will stop the moment it finds a cell that passes all NIST tests.
+
+```
+make -f Makefile.observe
+python3 scripts/run_vn_nist.py <DIMM_NAME> <TEMPERATURE_IN_CELCIUS>
+```
+
+Example: `python3 scripts/run_vn_nist.py hytt04 50`
+
+### SHA-256 Bitstreams
+
+This section describes how to get the NIST STS results for SHA-256 processed bitstreams. Doing so consists of two steps: 1) finding the DRAM segments with top 10 entropy, 2) generating bitstreams from the top-10-entropy segments and processing them using SHA-256 and performing NIST STS tests.
+
+First, run `make -f Makefile.sha`.
+
+1- Obtain the entropy distribution to find the desired 4-bit data pattern (refer to "Entropy Tests").
+2- Get the segments with max. entropy: `python3 scripts/top_ents.py <DIMM_NAME> <PATTERN> <TEMPERATURE>`
+3- Run the SHA-256 bitstream generator script: `python3 scripts/sha_bitstreams.py <DIMM_NAME> <PATTERN> <TEMPERATURE>` \ No newline at end of file
diff --git a/sources/apps/QUAC-TRNG/bin/.gitkeep b/sources/apps/QUAC-TRNG/bin/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/bin/.gitkeep
diff --git a/sources/apps/QUAC-TRNG/scripts/convert_ent.py b/sources/apps/QUAC-TRNG/scripts/convert_ent.py
new file mode 100644
index 0000000..b2c66ea
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/convert_ent.py
@@ -0,0 +1,32 @@
+import os
+import argparse
+from numpy import array
+
+parser = argparse.ArgumentParser(description = "Run this script to preprocess entropy files")
+parser.add_argument('indir', help="Path to entropy files")
+args = parser.parse_args()
+
+files = []
+for fname in os.listdir(args.indir):
+ files.append(fname)
+
+for file in files:
+ print("Processing:", file)
+ # Add this placement
+ fpath = os.path.normpath(args.indir + '/' + file)
+ infile = open(fpath,'r')
+ wfile = file.split('.')[0] + '_floats.bin'
+ wfpath = os.path.normpath(args.indir + '/' + wfile)
+ output_file = open(wfpath, 'wb')
+
+ lines = infile.readlines()
+
+ # First row reserved for metadata
+ for lidx in range(1,len(lines)):
+ line = lines[lidx].strip()
+ split = line.split()
+ elements = [float(i) for i in split[1:]]
+ a = array(elements,'float32')
+ a.tofile(output_file)
+
+ output_file.close() \ No newline at end of file
diff --git a/sources/apps/QUAC-TRNG/scripts/ft200_rc/README.md b/sources/apps/QUAC-TRNG/scripts/ft200_rc/README.md
new file mode 100644
index 0000000..de91b27
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/ft200_rc/README.md
@@ -0,0 +1,21 @@
+# FT200 remote read and write
+
+Make sure that the FT200 controller match the parameters you are using in your script.
+The relevant parameters are:
+
+PASS-0101 menu (see documentation in doc folder):
+* ldN0 (Device address)
+* bAUd (rate)
+* UCR (parity)
+
+## Requirements
+* pip3 install -U minimalmodbus
+
+
+## Add your user to the dialout group
+
+sudo gpasswd --add ${USER} dialout
+(You need to log out and log back in again for it to be effective)
+
+## Execute test
+* python3 ft200.py
diff --git a/sources/apps/QUAC-TRNG/scripts/ft200_rc/__init__.py b/sources/apps/QUAC-TRNG/scripts/ft200_rc/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/ft200_rc/__init__.py
diff --git a/sources/apps/QUAC-TRNG/scripts/ft200_rc/docs/1189902393_ft200_lcd.pdf b/sources/apps/QUAC-TRNG/scripts/ft200_rc/docs/1189902393_ft200_lcd.pdf
new file mode 100644
index 0000000..8c18eaa
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/ft200_rc/docs/1189902393_ft200_lcd.pdf
Binary files differ
diff --git a/sources/apps/QUAC-TRNG/scripts/ft200_rc/docs/210.pdf b/sources/apps/QUAC-TRNG/scripts/ft200_rc/docs/210.pdf
new file mode 100644
index 0000000..e4d0d39
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/ft200_rc/docs/210.pdf
Binary files differ
diff --git a/sources/apps/QUAC-TRNG/scripts/ft200_rc/ft200.py b/sources/apps/QUAC-TRNG/scripts/ft200_rc/ft200.py
new file mode 100644
index 0000000..aa50a1f
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/ft200_rc/ft200.py
@@ -0,0 +1,182 @@
+"""""
+Code for monitoring and controlling temperature in the Maxwell FT200 controller using the Modbus RS485 protocol
+@author: Lois Orosa
+"""""
+import minimalmodbus as mm, serial, time
+import time
+import os
+import sys
+import pathlib
+
+class FT200:
+ """
+ Controls and monitors the Maxwell FT200 tempoerature controller
+ """
+ READ_ERROR = -999
+ WRITE_ERROR = -998
+ def __init__(self, _baud=9600, _ft200_addr=1, _temp_tolerance=2):
+ self.baud = _baud
+ self.write_reg = 5 # Write register
+ self.read_reg = 0 # Read register
+ self.ft200_addr = _ft200_addr # Address of the device (by default is 1)
+ self.temp_tolerance = _temp_tolerance # Temperature tolerance. By default, we consider that we reach the target value if the measured value is within +-0.2C
+
+ try:
+ self.device = self.findDevice() # Get the USB-RS485 device
+ print("USB-RS485 Device: "+str(self.device))
+ self.instrument = mm.Instrument(self.device , 3 , debug = False)
+ self.instrument.serial.baudrate = self.baud
+ self.instrument.address = self.ft200_addr
+ self.instrument.serial.timeout = 1
+ self.instrument.serial.parity = serial.PARITY_NONE
+ self.instrument.mode = mm.MODE_RTU
+ print("Device "+self.device+": conected")
+ except:
+ raise
+
+ # Automatically find the USB-RS485 Device
+ def findDevice(self):
+ '''
+ Find the USB-RS485 device
+ This function might raise two exceptions:
+ -> NameError: There is more than 1 USB-RS485 device, or other USB device has a similar name as the USB-RS485 device
+ -> IOError: Device not found.
+ '''
+ DEVICENAME = "1a86_USB"
+ name = ''
+ while True:
+ path = pathlib.Path(__file__).parent.absolute()
+ f = os.popen(str(path)+"/usb_dev_path.sh")
+ for device in f:
+ if DEVICENAME in device:
+ if name == '':
+ name = device.split()[0]
+ else:
+ raise NameError("There are at least two USB devices whose name contains "+str(DEVICENAME))
+ if name == '':
+ raise IOError("Device not found.")
+ return name
+
+ # Read Temperature from FT200
+ # The output value has 1 decimal, and it is multiplied by 10
+ # E.g., data= 102 represents a temperature of 10.2C
+ def readTemp(self):
+ try:
+ data = self.instrument.read_register(self.read_reg, functioncode=3)
+ return data
+ except IOError:
+ print("Failed to read from instrument")
+ return self.READ_ERROR
+
+ # Check if the temperature reached a value
+ # The input value has 1 decimal, and it is multiplied by 10
+ # E.g., data= 102 represents a temperature of 10.2C
+ def isTemp(self, temperature):
+ try:
+ data = self.instrument.read_register(self.read_reg, functioncode=3)
+ if data >= (temperature-self.temp_tolerance) and data <= (temperature+self.temp_tolerance):
+ return True
+ else:
+ return False
+ except IOError:
+ print("Failed to read from instrument")
+ return False
+
+ # Set Temperature FT200
+ # The value should be a integer, and it should be the temperature value with 1 decimal multiplied by 10
+ # E.g., value= 102 represents a temperature of 10.2C
+ def setTemp(self, value):
+ try:
+ self.instrument.write_register(self.write_reg, value, functioncode=6)
+ except IOError:
+ print("Failed to write to instrument")
+ return self.WRITE_ERROR
+ return 0
+
+ # Set the temperature and wait for the temperature to be stable
+ # Optimized version that reach the target temperature earlier
+ # The value should be a integer, and it should be the temperature value with 1 decimal multiplied by 10
+ # E.g., value= 102 represents a temperature of 10.2C
+ def autoSetAndWait(self, temperature, debug = False):
+ acceleration_factor = 5
+ stability = 10 # Iterations that the temperature needs to be stable
+ time_sleep = 1 # 1 second wait per loop iteration
+ stable_count = stability # Counter for taking into account the stability of the temperature
+ stable_margin = 20 # We do not change the set temperature if we are within 2C from the target
+ optTemp = temperature
+ self.setTemp(optTemp) # Set the temperature
+ curTemp = self.readTemp() # Read the temperature
+ if debug:
+ print("[TEMPERATURE] current: "+str(curTemp/10.0)+", goal: "+str(temperature/10.0)+", programmed: "+str(optTemp/10.0))
+ while (((curTemp > (temperature + self.temp_tolerance)) or (curTemp < (temperature - self.temp_tolerance))) or (stable_count!=0)):
+ if debug:
+ print("[TEMPERATURE] current: "+str(curTemp/10.0)+", goal: "+str(temperature/10.0)+", programmed: "+str(optTemp/10.0)+", stable_count: "+str(stable_count))
+ prev_optTemp = optTemp
+ if (temperature - curTemp) > 0: #(stable_margin): # If we are far away more than 2C
+ optTemp = temperature + (temperature - curTemp)*acceleration_factor # Optimization to accelerate convergence
+ else:
+ optTemp = temperature
+ if optTemp != prev_optTemp:
+ self.setTemp(optTemp) # Set temperature only if different from the previous iteration
+
+ time.sleep(time_sleep) # WAit for a while
+
+ curTemp = self.readTemp() # Read the temperature
+ while (curTemp == self.READ_ERROR): # If there is an error, read again
+ curTemp = self.readTemp()
+ # Five iterations in the range
+ if (curTemp > (temperature + self.temp_tolerance)) or (curTemp < (temperature - self.temp_tolerance)):
+ stable_count = stability
+ else:
+ stable_count -= 1 # The temperature has to remain stable for a while
+
+ def autoSetAndWait_2(self, temperature, debug = False):
+ acceleration_factor = 150
+ stability = 10 # Iterations that the temperature needs to be stable
+ time_sleep = 1 # 1 second wait per loop iteration
+ stable_count = stability # Counter for taking into account the stability of the temperature
+ stable_margin = 5 # We do not change the set temperature if we are within 2C from the target
+ optTemp = temperature
+ self.setTemp(optTemp) # Set the temperature
+ curTemp = self.readTemp() # Read the temperature
+ if debug:
+ print("[TEMPERATURE] current: "+str(curTemp/10.0)+", goal: "+str(temperature/10.0)+", programmed: "+str(optTemp/10.0))
+ while (((curTemp > (temperature + self.temp_tolerance)) or (curTemp < (temperature - self.temp_tolerance))) or (stable_count!=0)):
+ if debug:
+ print("[TEMPERATURE] current: "+str(curTemp/10.0)+", goal: "+str(temperature/10.0)+", programmed: "+str(optTemp/10.0)+", stable_count: "+str(stable_count))
+ prev_optTemp = optTemp
+ if abs(temperature - curTemp) > (stable_margin): # If we are far away more than 2C
+ if temperature > curTemp:
+ optTemp = temperature + acceleration_factor # Optimization to accelerate convergence
+ else:
+ optTemp = temperature - acceleration_factor # Optimization to accelerate convergence
+ else:
+ optTemp = temperature
+
+ time.sleep(time_sleep) # WAit for a while
+
+ curTemp = self.readTemp() # Read the temperature
+ while (curTemp == self.READ_ERROR): # If there is an error, read again
+ curTemp = self.readTemp()
+ # Five iterations in the range
+ if (curTemp > (temperature + self.temp_tolerance)) or (curTemp < (temperature - self.temp_tolerance)):
+ stable_count = stability
+ else:
+ stable_count -= 1 # The temperature has to remain stable for a while
+
+if __name__ == '__main__':
+ ## Example of how to use the FT200 class
+ try:
+ tc = FT200()
+ except Exception as error:
+ print("[ERROR] "+ repr(error))
+ sys.exit(0)
+
+ # Temperature
+ value = int(sys.argv[1]) * 10
+ print(value)
+ print(tc.readTemp())
+ tc.autoSetAndWait(value,True)
+
+
+
diff --git a/sources/apps/QUAC-TRNG/scripts/ft200_rc/usb_dev_path.sh b/sources/apps/QUAC-TRNG/scripts/ft200_rc/usb_dev_path.sh
new file mode 100755
index 0000000..241aef1
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/ft200_rc/usb_dev_path.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+# https://unix.stackexchange.com/questions/144029/command-to-determine-ports-of-a-device-like-dev-ttyusb0
+echo "USB devices:"
+for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do
+ (
+ syspath="${sysdevpath%/dev}"
+ devname="$(udevadm info -q name -p $syspath)"
+[[ "$devname" == "bus/"* ]] && exit
+ eval "$(udevadm info -q property --export -p $syspath)"
+[[ -z "$ID_SERIAL" ]] && exit
+ echo "/dev/$devname - $ID_SERIAL"
+ )
+done
diff --git a/sources/apps/QUAC-TRNG/scripts/run_ent.py b/sources/apps/QUAC-TRNG/scripts/run_ent.py
new file mode 100644
index 0000000..5163c5f
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/run_ent.py
@@ -0,0 +1,43 @@
+import os
+import argparse
+import subprocess
+import time
+
+parser = argparse.ArgumentParser(description = "Collects entropy for different data patterns")
+
+parser.add_argument('dimm', help="DIMM label under test")
+parser.add_argument('temperature', help="DIMM temperature in centigrades")
+parser.add_argument('iters', help="How many times do we QUAC to find entropy")
+parser.add_argument('stride', help="Stride (in rows) used to skim through segments, default: 4")
+
+args = parser.parse_args()
+
+# ---------------- SETUP DIRECTORIES -------------------
+
+if not os.path.isdir("data"):
+ os.mkdir("data")
+
+if not os.path.isdir("data/" + args.dimm):
+ os.mkdir("data/" + args.dimm)
+
+if not os.path.isdir("data/" + args.dimm + "/ent"):
+ os.mkdir("data/" + args.dimm + "/ent")
+
+if not os.path.isdir("data/" + args.dimm + "/ent/" + args.temperature + "C"):
+ os.mkdir("data/" + args.dimm + "/ent/" + args.temperature + "C")
+
+outdir = os.path.normpath("data/" + args.dimm + "/ent/" + args.temperature + "C")
+
+# -------------------- RUN TESTS -----------------------
+
+placements = ["1000", "1001", "1010", "1011", "1100" , "1101", "1110", "1111", \
+ "0111", "0110", "0101", "0100", "0011" , "0010", "0001", "0000"]
+
+ent_path = os.path.normpath("bin/ENT")
+results_path = outdir
+stride = args.stride
+iters = args.iters
+
+for placement in placements:
+ print("sudo " + ent_path + " " + results_path + " " + placement + " " + stride + " " + iters)
+ os.system("sudo " + ent_path + " " + results_path + " " + placement + " " + stride + " " + iters)
diff --git a/sources/apps/QUAC-TRNG/scripts/run_vn_nist.py b/sources/apps/QUAC-TRNG/scripts/run_vn_nist.py
new file mode 100644
index 0000000..c439da8
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/run_vn_nist.py
@@ -0,0 +1,125 @@
+import os
+import argparse
+import subprocess
+import time
+
+parser = argparse.ArgumentParser(description = "Run this script to evaluate bitstreams")
+
+parser.add_argument('dimm', help="DIMM label under test")
+parser.add_argument('temperature', help="DIMM temperature in centigrades")
+
+args = parser.parse_args()
+
+# ---------------- SETUP DIRECTORIES -------------------
+
+if not os.path.isdir("data"):
+ os.mkdir("data")
+
+if not os.path.isdir("data/" + args.dimm):
+ os.mkdir("data/" + args.dimm)
+
+if not os.path.isdir("data/" + args.dimm + "/vnc"):
+ os.mkdir("data/" + args.dimm + "/vnc")
+
+if not os.path.isdir("data/" + args.dimm + "/vnc/" + args.temperature + "C"):
+ os.mkdir("data/" + args.dimm + "/vnc/" + args.temperature + "C")
+
+if not os.path.isdir("data/" + args.dimm + "/vnc/" +
+ args.temperature + "C/nist_results"):
+ os.mkdir("data/" + args.dimm + "/vnc/" + args.temperature + "C/nist_results")
+
+if not os.path.isdir("data/" + args.dimm + "/vnc/" +
+ args.temperature + "C/binaries"):
+ os.mkdir("data/" + args.dimm + "/vnc/" + args.temperature + "C/binaries")
+
+outdir = os.path.normpath("data/" + args.dimm + "/vnc/" + args.temperature + "C/nist_results")
+indir = os.path.normpath("data/" + args.dimm + "/vnc/" + args.temperature + "C/binaries")
+
+if not os.path.isfile(indir + "/lastrow.txt"):
+ input("I am going to overwrite 'lastrow.txt', proceed with caution")
+ init_file = open(indir + "/lastrow.txt", "w")
+ init_file.write(str(0) + "\n")
+
+# Hard-reset SoftMC before other experiments
+reset_path = os.path.normpath("bin/SoftMC_reset")
+reset = subprocess.Popen("exec sudo " + reset_path, shell=True, preexec_fn=os.setpgrp)
+time.sleep(5)
+os.system("sudo pkill -9 -P" + str(os.getpgid(reset.pid)))
+reset.wait()
+
+# First run OBSERVE to collect von Neumann corrected bitstreams
+observe_path = os.path.normpath("bin/OBSERVE " + indir)
+observe_args = " > " + os.path.normpath(outdir + "/output.log")
+observe = subprocess.Popen("exec sudo " + observe_path + observe_args, shell=True, preexec_fn=os.setpgrp)
+
+# Watch the bitstream directory for new files
+before = ["lastrow.txt"]
+
+while True:
+ time.sleep(1)
+ after = os.listdir(indir)
+ s = set(before)
+ diff = [x for x in after if x not in s]
+ before = after
+ if len(diff) == 0:
+ continue
+
+ bitstream = [[] for i in range(8)] # at most 8 STS runs
+
+ # Partition
+ i = 0
+ for fname in diff:
+ bitstream[i].append(fname)
+ i = (i+1) % 8
+
+ found = False
+ for i in range(len(bitstream[0])):
+ print("Finished " + str(i) + " out of " + str(len(bitstream[7])))
+ processes = []
+ for thr in range(0,8):
+ if len(bitstream[thr]) <= i:
+ break
+ command_output = os.path.normpath(outdir + "/thr" + str(thr))
+ command_input = os.path.normpath(indir + '/' + bitstream[thr][i])
+ command = 'tools/sts -O -i 1 -I 1 -S '+ str(1024*1024) +' -w ' + command_output +' -F r ' + command_input + " 2>/dev/null"
+ process = subprocess.Popen(command, shell=True)
+ processes.append(process)
+
+ # Collect statuses
+ output = [p.wait() for p in processes]
+
+ for thr in range(0,8):
+ if len(bitstream[thr]) <= i:
+ break
+ res_txt = open(os.path.normpath(outdir + '/thr' + str(thr) + '/finalAnalysisReport.txt'), "r")
+ lines = res_txt.readlines()
+ n_success = 0
+ for j in range(7, len(lines)):
+ line = lines[j].strip()
+ if not ("1" in line or "0" in line):
+ break
+ split = line.split()
+ if "/" in split[11]:
+ n_success += int(split[11].split("/")[0])
+ res_txt.close()
+ print(bitstream[thr][i] + " succeeded in " + str(n_success) + "tests + bits: " + str(1024*1024))
+ if n_success < 187:
+ os.system("rm -f " + indir + "/" + bitstream[thr][i])
+ if n_success > 186:
+ os.system("mkdir " + outdir + "/" + bitstream[thr][i])
+ os.system("cp " + outdir + '/thr' + str(thr) + "/finalAnalysisReport.txt " + outdir + "/" + bitstream[thr][i])
+ if n_success == 188:
+ os.system("sudo pkill -9 -P" + str(os.getpgid(observe.pid)))
+ observe.wait() # wait until the process actually terminates
+ found = True
+ if found:
+ break
+
+print("Finally found one cell that passes all NIST tests!")
+
+# Reset SoftMC because last process was killed prematurely
+reset_path = os.path.normpath("bin/SoftMC_reset")
+reset = subprocess.Popen("exec sudo " + observe_path, shell=True, preexec_fn=os.setpgrp)
+time.sleep(5)
+os.system("sudo pkill -9 -P" + str(os.getpgid(reset.pid)))
+reset.wait()
diff --git a/sources/apps/QUAC-TRNG/scripts/sha_bitstreams.py b/sources/apps/QUAC-TRNG/scripts/sha_bitstreams.py
new file mode 100644
index 0000000..fd4dbfb
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/sha_bitstreams.py
@@ -0,0 +1,87 @@
+import os
+import argparse
+import subprocess
+import time
+
+parser = argparse.ArgumentParser(description = "Collects sha bitstreams for a data pattern")
+
+parser.add_argument('dimm', help="DIMM label under test")
+parser.add_argument('pattern', help="data pattern to use")
+parser.add_argument('temperature', help="DIMM temperature in centigrades")
+
+args = parser.parse_args()
+
+bitstreams_available = False
+
+if not os.path.isdir("data/" + args.dimm + "/sha"):
+ os.mkdir("data/" + args.dimm + "/sha")
+
+if os.path.isdir("data/" + args.dimm + "/sha/" + args.temperature + "C"):
+ bitstreams_available = True
+
+if not os.path.isdir("data/" + args.dimm + "/sha/" + args.temperature + "C"):
+ os.mkdir("data/" + args.dimm + "/sha/" + args.temperature + "C")
+
+infile = os.path.normpath("data/" + args.dimm + "/ent/" + args.temperature + "C/top.txt")
+outdir = os.path.normpath("data/" + args.dimm + "/sha/" + args.temperature + "C")
+
+if not os.path.isdir("data/" + args.dimm + "/sha"):
+ os.mkdir("data/" + args.dimm + "/sha_nist_results")
+
+if not os.path.isdir("data/" + args.dimm + "/sha/" + args.temperature + "C"):
+ os.mkdir("data/" + args.dimm + "/sha_nist_results/" + args.temperature + "C")
+
+sha_output = os.path.normpath("data/" + args.dimm + "/sha_nist_results/" + args.temperature + "C")
+
+if not bitstreams_available:
+ sha_path = "bin/SHA"
+ print("sudo " + sha_path + " " + outdir + " " + infile)
+ os.system("sudo " + sha_path + " " + outdir + " " + infile)
+else:
+ print("I think we have the bitstreams available, I won't run softmc code again")
+
+i=0
+bitstream = []
+
+for j in range(0,10):
+ bitstream.append([])
+
+for fname in os.listdir(outdir):
+ bitstream[i].append(fname)
+ i+=1
+ i = i % 10
+
+print(bitstream)
+
+for i in range(len(bitstream[9])):
+ print("Finished " + str(i) + " out of " + str(len(bitstream[9])))
+ processes = []
+ for thr in range(0,10):
+ outpath = os.path.normpath(sha_output+'/thr'+str(thr))
+ if not os.path.isdir(outpath):
+ os.mkdir(outpath)
+ command = 'tools/sts -O -i 1024 -I 1 -P 11=0.001 -S '+ str(1024*1024) +' -w '+ outpath +' -F r ' + outdir+'/'+bitstream[thr][i] + " 2>/dev/null"
+ process = subprocess.Popen(command, shell=True)
+ processes.append(process)
+ print(command)
+
+ # Collect statuses
+ output = [p.wait() for p in processes]
+
+ for thr in range(0,10):
+ outpath = os.path.normpath(sha_output+'/thr'+str(thr))
+ res_txt = open(outpath + '/finalAnalysisReport.txt', "r")
+ lines = res_txt.readlines()
+ n_success = 0
+ for j in range(7, len(lines)):
+ line = lines[j].strip()
+ if not ("1" in line or "0" in line):
+ break
+ split = line.split()
+ if "/" in split[11]:
+ n_success += int(split[11].split("/")[0])
+ res_txt.close()
+ print(bitstream[thr][i] + " succeeded in " + str(n_success) + "tests + bits: " + str(1024*1024))
+ if n_success > 186:
+ os.system("mkdir "+sha_output+"/" + bitstream[thr][i])
+ os.system("cp "+sha_output+'/thr'+str(thr)+"/finalAnalysisReport.txt "+sha_output+"/" + bitstream[thr][i])
diff --git a/sources/apps/QUAC-TRNG/scripts/top_ents.py b/sources/apps/QUAC-TRNG/scripts/top_ents.py
new file mode 100644
index 0000000..2a74569
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/scripts/top_ents.py
@@ -0,0 +1,35 @@
+import os
+import argparse
+import pandas as pd
+import numpy as np
+
+parser = argparse.ArgumentParser(description = "Postprocess entropy files and obtain top-10 segments with the highest entropy")
+parser.add_argument('dimm', help="DIMM label")
+parser.add_argument('pattern', help="4-bit data pattern [1000, 1001, 0111, etc]")
+parser.add_argument('temp', help="temperature in centigrades")
+args = parser.parse_args()
+
+dimm = args.dimm
+pattern = args.pattern
+temp = args.temp
+
+no_segments = 8192
+no_bitlines = 512 * 128
+
+fn = "data/" + dimm + "/ent/" + temp + "C/1_1000_128_32768_" + pattern + "_floats.bin"
+dirname = "data/" + dimm + "/ent/" + temp + "C/"
+
+arr = np.fromfile(fn, dtype=np.float32)
+arr = arr.reshape(no_segments, no_bitlines)
+arr = arr.sum(axis = 1)
+indices = arr.argsort()[-10:][::-1]
+print(indices)
+print(arr[indices])
+
+log = open(dirname + "top.txt", "w")
+log.write("10\n")
+for index in indices:
+ # bank is always 1
+ # multiply segment # by 4 to get starting row addr
+ log.write("1 " + str(int(index) * 4) + " " + str(arr[index]) + " " + pattern + "\n")
+log.close()
diff --git a/sources/apps/QUAC-TRNG/src/observe.cpp b/sources/apps/QUAC-TRNG/src/observe.cpp
new file mode 100644
index 0000000..275c516
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/src/observe.cpp
@@ -0,0 +1,726 @@
+#include "instruction.h"
+#include "prog.h"
+#include "platform.h"
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <cstring>
+#include <list>
+#include <algorithm>
+#include <iterator>
+#include <iomanip>
+
+#define NEWFILTER
+
+using namespace std;
+
+#define NO_BANKS 2
+#define NO_ROWS 32*1024
+
+// Stride register ids are fixed and should not be changed
+// CASR should always be reg 0
+#define CASR 0
+// BASR should always be reg 1
+#define BASR 1
+// RASR should always be reg 2
+#define RASR 2
+
+#define PATTERN_REG 12
+#define INV_PATTERN_REG 13
+#define TEMP_PATTERN_REG 14
+
+#define BAR 3
+#define CAR 4
+#define RARBASE 5
+#define RAR1 6
+#define RAR2 9
+
+#define ONE_REG 10
+#define ZERO_REG 11
+
+#define ITER_REG 7
+#define CTR_REG 8
+
+#define INIT_LOOP 15
+
+Program genRowCopy(int t1, int t2, int row1_reg, int row2_reg, int bank_reg)
+{
+ Program ret;
+ // t1 -> ACT to PRE, t2 -> PRE to 2nd ACT
+ int sz = 3 + t1 + t2;
+ sz = (4-(sz%4)) + sz;
+ Mininst buff[sz];
+ for(int i = 0 ; i < sz ; i++)
+ buff[i] = SMC_NOP();
+
+ // Overwrite with the actual sequence
+ buff[0] = SMC_ACT(bank_reg, 0, row1_reg, 0);
+ buff[1+t1] = SMC_PRE(bank_reg, 0, 0);
+ buff[2+t1+t2] = SMC_ACT(bank_reg, 0, row2_reg, 0);
+
+ for(int i = 0 ; i < sz ; i+=4)
+ ret.add_inst(buff[i], buff[i+1], buff[i+2], buff[i+3]);
+
+ return ret;
+}
+
+/**
+ * To send an ACT -> SLEEP t1 -> PRE -> SLEEP t2 -> ACT sequence
+ * This seq. will use BAR RAR1 and RAR2 registers
+ */
+Program genActPreActSequence(int t1, int t2, int row1_reg, int row2_reg, int bank_reg)
+{
+ Program ret;
+ // t1 -> ACT to PRE, t2 -> PRE to 2nd ACT
+ int sz = 3 + t1 + t2;
+ sz = (4-(sz%4)) + sz;
+ Mininst buff[sz];
+ for(int i = 0 ; i < sz ; i++)
+ buff[i] = SMC_NOP();
+
+ // Overwrite with the actual sequence
+ buff[0] = SMC_ACT(bank_reg, 0, row1_reg, 0);
+ buff[1+t1] = SMC_PRE(bank_reg, 0, 0);
+ buff[2+t1+t2] = SMC_ACT(bank_reg, 0, row2_reg, 0);
+
+ for(int i = 0 ; i < sz ; i+=4)
+ ret.add_inst(buff[i], buff[i+1], buff[i+2], buff[i+3]);
+
+ return ret;
+}
+
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+
+Program genCopyRange(int row_reg, int no_rows, int bank_reg, bool stripes)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_inst(SMC_LI(0, ONE_REG));
+ ret.add_inst(SMC_LI(1, ZERO_REG));
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_below(genRowCopy(4,4,ONE_REG,row_reg,bank_reg));
+ ret.add_inst(SMC_SLEEP(6));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_ADDI(row_reg, 1, row_reg));
+
+ ret.add_inst(SMC_SLEEP(6));
+ ret.add_below(genRowCopy(4,4,ZERO_REG,row_reg,bank_reg));
+ ret.add_inst(SMC_SLEEP(6));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_ADDI(row_reg, 1, row_reg));
+
+ ret.add_inst(SMC_SLEEP(6));
+
+ ret.add_below(genRowCopy(4,4,ONE_REG,row_reg,bank_reg));
+ ret.add_inst(SMC_SLEEP(6));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_ADDI(row_reg, 1, row_reg));
+ ret.add_inst(SMC_SLEEP(6));
+
+ ret.add_below(genRowCopy(4,4,ZERO_REG,row_reg,bank_reg));
+ ret.add_inst(SMC_SLEEP(6));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_ADDI(row_reg, 1, row_reg));
+ ret.add_inst(SMC_SLEEP(6));
+
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1000(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+
+Program genWriteRange(int row_reg, int no_rows, int bank_reg, bool stripes)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+ for(int i = 0 ; i < 64 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ if(stripes)
+ {
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+ }
+ ret.add_branch(ret.BR_TYPE::BL, row_reg, INIT_LOOP, "genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+Program genReadRange(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // read until this row
+ ret.add_label("genReadRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR)); // TODO: fix this
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+ for(int i = 0 ; i < 64 ; i++)
+ {
+ ret.add_inst(SMC_READ(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_READ(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_branch(ret.BR_TYPE::BL, row_reg, INIT_LOOP, "genReadRange:LOOP_BEGIN");
+ /*
+ ret.add_inst(SMC_SLEEP(5));
+ ret.dump_registers();
+ ret.add_inst(SMC_END());
+ */
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+/**
+ * @return an instruction formed by NOPs
+ */
+Inst all_nops()
+{
+ return __pack_mininsts(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP());
+}
+
+Program gen_test_prog(int bank, int r1, int r2,int iters)
+{
+ Program program;
+
+ program.add_inst(SMC_LI(8, CASR)); // Load 8 into CASR since each READ reads 8 columns
+ program.add_inst(SMC_LI(1, BASR)); // Load 1 into BASR
+ program.add_inst(SMC_LI(1, RASR)); // Load 1 into RASR
+
+ program.add_inst(SMC_LI(0xffffffff, PATTERN_REG));
+ program.add_inst(SMC_LI(0x00000000, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ program.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ program.add_inst(SMC_LI(bank, BAR));
+ program.add_inst(SMC_LI(r1-(r1%4), RARBASE));
+
+ program.add_inst(SMC_LI(iters, ITER_REG));
+ program.add_inst(SMC_LI(0, CTR_REG));
+
+ program.add_label("WRITE_BEGIN");
+ program.add_inst(SMC_PRE(BAR, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ program.add_inst(SMC_SLEEP(3));
+ program.add_below(genWriteRange(RARBASE, 4, BAR, true));
+ //program.add_below(genWriteRange1000(RARBASE, 4, BAR));
+ //program.add_below(genCopyRange(RARBASE, 4, BAR, true));
+ program.add_inst(SMC_LI(r1, RAR1));
+ program.add_inst(SMC_LI(r2, RAR2));
+
+ program.add_below(genActPreActSequence(1, 1, RAR1, RAR2, BAR));
+
+ program.add_inst(SMC_SLEEP(6));
+ program.add_inst(SMC_PRE(BAR, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ program.add_below(genReadRange(RARBASE, 1, BAR));
+ program.add_inst(SMC_ADDI(CTR_REG, 1, CTR_REG));
+
+ program.add_branch(program.BR_TYPE::BL, CTR_REG, ITER_REG, "WRITE_BEGIN");
+ program.add_inst(SMC_END());
+
+ return program;
+}
+
+bool nonoverlapping_pattern(std::vector<uint8_t> bv)
+{
+ unsigned wsize = bv.size()/8;
+ uint8_t buf[wsize];
+ for(int j = 0 ; j < wsize ; j++)
+ {
+ uint8_t intermediate = 0;
+ for(int k = 0 ; k < 8 ; k++)
+ intermediate = (intermediate << 1) | bv[j*8 + k];
+ buf[j] = intermediate;
+ }
+
+ int bin[8] = {0};
+ for (int i = 0 ; i < (1024*128*8 - 3) ; i += 3)
+ {
+ if (i % 8 < 6)
+ bin[(buf[i/8] >> (i%8)) & 0x7]++;
+ else
+ {
+ int next_bits = 3 - (8-(i%8));
+ int next_mask = next_bits == 2 ? 0x3 : 0x1;
+ int this_mask = next_bits == 2 ? 0x1 : 0x3;
+ uint8_t next_pattern = (buf[(i/8)+1]) & next_mask;
+ uint8_t this_pattern = (buf[i/8] >> (i%8)) & this_mask;
+ bin[(next_pattern << (3-next_bits)) | this_pattern]++;
+ }
+ }
+
+ bool pass = true;
+ for (int i = 0 ; i < 8 ; i++)
+ {
+ cout << i << ": " << bin[i] << endl;
+ if (bin[i] < 30000 || bin[i] > 55000)
+ pass = false;
+ }
+ return pass;
+}
+
+vector<int> pre_filter(SoftMCPlatform& platform, int bank, int row)
+{
+ vector<int> cells_to_track;
+
+ const int NO_CELLS = 64 * 1024;
+ const int pre_pre_filter_iterations = 128*1024;
+ const int threshold_size = 4096;
+
+ Program prog = gen_test_prog(bank, row, row+3, pre_pre_filter_iterations);
+ platform.execute(prog);
+ uint8_t buf1[8*1024];
+ uint8_t buf2[8*1024];
+
+ vector<vector<uint8_t>> vnc_bitstreams;
+
+ for (int i = 0 ; i < NO_CELLS ; i++)
+ vnc_bitstreams.push_back(vector<uint8_t>());
+
+ // Von neumann corrector first
+ for (int i = 0 ; i < pre_pre_filter_iterations/2 ; i++)
+ {
+ platform.receiveData((char*)buf1, 8*1024);
+ platform.receiveData((char*)buf2, 8*1024);
+
+ for (int b = 0 ; b < NO_CELLS ; b++)
+ {
+ if(vnc_bitstreams[b].size() == threshold_size)
+ continue;
+
+ int b1 = (buf1[b/8] >> b%8) & 0x1;
+ int b2 = (buf2[b/8] >> b%8) & 0x1;
+
+ if (~b1 & b2)
+ vnc_bitstreams[b].push_back(1);
+ else if (b1 & ~b2)
+ vnc_bitstreams[b].push_back(0);
+ }
+ }
+
+ int cnt = 0;
+ for (int b = 0 ; b < NO_CELLS ; b++)
+ {
+ if (vnc_bitstreams[b].size() == threshold_size)
+ cnt++;
+ }
+
+ cout << cnt << " cells have passed initial filtering." << endl;
+
+ // counter bins for each bitline
+ int bin[NO_CELLS][8];
+ for (int i = 0 ; i < NO_CELLS ; i++)
+ {
+ for (int j = 0 ; j < 8 ; j++)
+ bin[i][j] = 0;
+ }
+
+ int freq[NO_CELLS] = {0};
+
+ for (int b = 0 ; b < NO_CELLS ; b++)
+ {
+ if (vnc_bitstreams[b].size() < threshold_size - 1)
+ continue;
+ for (int i = 0 ; i < (threshold_size - 1)/3 ; i++)
+ {
+ int b1 = vnc_bitstreams[b][i] & 0x1;
+ int b2 = vnc_bitstreams[b][i+1] & 0x1;
+ int b3 = vnc_bitstreams[b][i+2] & 0x1;
+
+ if (b1)
+ freq[b]++;
+ if (b2)
+ freq[b]++;
+ if (b3)
+ freq[b]++;
+
+ bin[b][(b3 << 2) | (b2 << 1) | b1]++;
+ }
+ }
+
+ bool passed_frequency[NO_CELLS] = {false};
+
+ int upper_freq = threshold_size/2 + threshold_size/2/100;
+ int lower_freq = threshold_size/2 - threshold_size/2/100;
+ for (int i = 0 ; i < NO_CELLS ; i++)
+ {
+ if (vnc_bitstreams[i].size() < threshold_size - 1)
+ continue;
+ if (freq[i] < upper_freq && freq[i] > lower_freq)
+ passed_frequency[i] = true;
+ }
+
+ cnt = 0;
+ for (int b = 0 ; b < NO_CELLS ; b++)
+ {
+ if (passed_frequency[b])
+ cnt++;
+ }
+
+ cout << cnt << " cells have passed frequency filtering." << endl;
+
+ //cout << "Cell: " << i << endl;
+ int lower_limit = ((threshold_size - 1) / 3 / 8) - (((threshold_size - 1) / 3 / 8) / 10);
+ int upper_limit = ((threshold_size - 1) / 3 / 8) + (((threshold_size - 1) / 3 / 8) / 10);
+ cout << "UL: " << upper_limit << " LL: " << lower_limit << endl;
+ bool passed[NO_CELLS];
+
+ for (int b = 0 ; b < NO_CELLS ; b++)
+ passed[b] = true;
+
+ for (int i = 0 ; i < NO_CELLS ; i++)
+ {
+ if (!passed_frequency[i])
+ {
+ passed[i] = false;
+ continue;
+ }
+ for (int j = 0 ; j < 8 ; j++)
+ {
+ //cout << "Bin" << j << ": " << bin[i][j] << endl;
+ if (bin[i][j] < lower_limit || bin[i][j] > upper_limit)
+ {
+ //cout << "Cell " << i << " Bin" << j << ": " << bin[i][j] << endl;
+ passed[i] = false;
+ break;
+ }
+ }
+ if (passed[i])
+ cout << i << " " << "PASSed" << endl;
+ }
+
+ for (int i = 0 ; i < NO_CELLS ; i++)
+ {
+ if (passed[i])
+ cells_to_track.push_back(i);
+ }
+
+ return cells_to_track;
+}
+
+int main(int argc, char *argv[])
+{
+ SoftMCPlatform platform;
+ int err;
+
+ // buffer allocated for reading data from the board
+ uint8_t buf[8*1024];
+ uint8_t prev_read[8*1024];
+
+ // Initialize the platform, opens file descriptors for the board PCI-E interface.
+ if((err = platform.init()) != SOFTMC_SUCCESS){
+ cerr << "Could not initialize SoftMC Platform: " << err << endl;
+ }
+ // reset the board to hopefully restore the board's state
+ platform.reset_fpga();
+ platform.set_aref(true);
+
+ ifstream lfFile;
+ string trackFn = string(argv[1]) + "/" + "lastrow.txt";
+ lfFile.open(trackFn);
+
+ int x=0;
+ lfFile >> x;
+
+ lfFile.close();
+
+ for(int bank = 1 ; bank < NO_BANKS ; bank++)
+ {
+ for(int r1 = x ; r1 < NO_ROWS ; r1 += 4)
+ {
+ bool satisfied = false;
+ #ifdef NEWFILTER
+ vector<int> cell_pos = pre_filter(platform, bank, r1);
+ #else
+ // Enrollment phase:
+ // Look at switching activity of each cell in a row
+ Program prog = gen_test_prog(bank, r1, r1+3, 32*1024);
+ platform.execute(prog);
+ int n_switches[64*1024]; // how many times each cell have switched
+ fill(n_switches, n_switches + 64*1024, 0);
+ platform.receiveData((char*)prev_read, 8*1024);
+ for(int k = 0; k < 32*1024-1 ; k++)
+ {
+ platform.receiveData((char*)buf, 8*1024); // read one segment each iteration
+ for(int i = 0 ; i < 8 * 1024 ; i++)
+ {
+ uint8_t diff = prev_read[i] ^ buf[i];
+ for(int j = 0 ; j < 8 ; j++)
+ n_switches[i*8 + j] += (diff >> j) & 0x1;
+ }
+ copy(begin(buf), end(buf), begin(prev_read));
+ }
+ vector<int> cell_pos; // Switching cell positions
+ float total_bps = 0;
+ for(int i = 0 ; i < 8*8*1024 ; i++)
+ {
+ // In total it takes 132ms to execute all the DRAM commands
+ // We compute bps based on switching
+ total_bps += (1000/132.f) * n_switches[i];
+ if(n_switches[i] > 1000)
+ cell_pos.push_back(i);
+ }
+
+ cout << "Finished enrollment for bank " << bank <<
+ " row " << r1 << "... " << cell_pos.size() << " cells passed... Predicted bps "
+ << fixed << setw(11) << setprecision(6) << total_bps << endl;
+ #endif
+
+ cout << "Finished enrollment for bank " << bank <<
+ " row " << r1 << "... " << cell_pos.size() << " cells passed..." << endl;
+
+ if(cell_pos.size() == 0)
+ continue;
+
+ for (int i = 0 ; i < cell_pos.size() ; i++)
+ cout << cell_pos[i] << " ";
+ cout << endl;
+
+ // Begin filtered acquisition phase
+ vector<vector<uint8_t>> stream_per_cell;
+ for(int i = 0 ; i < cell_pos.size() ; i++)
+ {
+ stream_per_cell.push_back(vector<uint8_t>());
+ }
+
+ int prev_bpc_i = 0;
+ int prev_cell_flips[cell_pos.size()]{0};
+
+ int loop_count = 0;
+ int loop_limit = 15;
+ bool bcf = false; // has the best cell exceeded the threshold
+
+ while(!satisfied)
+ {
+ if(loop_count == loop_limit)
+ {
+ cout << "Exiting because we have iterated enough times" << endl;
+ break;
+ }
+ int iterations = 1024*1024;
+ Program prog = gen_test_prog(bank, r1, r1+3, iterations);
+ platform.execute(prog);
+
+ for(int k = 0; k < iterations/2 ; k++)
+ {
+ platform.receiveData((char*)prev_read, 8*1024); // read one segment each iteration
+ platform.receiveData((char*)buf, 8*1024); // read one segment each iteration
+ //VON NEUMANN CORRECTOR BELOW
+ for(int i = 0 ; i < cell_pos.size() ; i++)
+ {
+ uint8_t b1 = (prev_read[cell_pos[i]/8] >> (cell_pos[i]%8)) & 0x1;
+ uint8_t b2 = (buf[cell_pos[i]/8] >> (cell_pos[i]%8)) & 0x1;
+ uint8_t b3 = b1 ^ b2;
+ if(!b3) continue;
+ if(b2) stream_per_cell[i].push_back(1);
+ else stream_per_cell[i].push_back(0);
+ }
+ }
+
+ int bpc_flips = 0; // best performing cell flip count
+ int bpc_i = 0; // best performing cell index
+ for(int i = 0 ; i < cell_pos.size() ; i++)
+ {
+ if(stream_per_cell[i].size() > bpc_flips)
+ {
+ bpc_flips = stream_per_cell[i].size();
+ bpc_i = i;
+ }
+ }
+
+ /*
+ cout << "Dumping # of switches per cell..." << endl;
+ for(int i = 0 ; i < cell_pos.size() ; i++)
+ {
+ cout << "Cell#" << cell_pos[i] << " Got:" << stream_per_cell[i].size() - prev_cell_flips[i]
+ << "Exp:" << 32*n_switches[cell_pos[i]] << endl;
+ }
+ */
+
+ if(!bcf)
+ {
+ if(prev_bpc_i == bpc_i)
+ {
+ int remaining_bits = 1024*1024 - bpc_flips;
+ int count_diff = bpc_flips - prev_cell_flips[bpc_i];
+ if(remaining_bits/count_diff + 1 > 16)
+ {
+ cout << "Exiting because it will take too long" << endl;
+ break;
+ }
+ if(remaining_bits < 0){
+ cout << "Finished one cell, will keep iterating for 5 iterations" << endl;
+ bcf = true;
+ loop_limit = loop_count + 5;
+ }
+ else{
+ cout << "It will take " << remaining_bits/count_diff + 1 << " more iterations to finish" << endl;
+ cout << "Based on the best cell's performance which has flipped " << bpc_flips << " times so far" << endl;
+ }
+ }else
+ {
+ cout << "Cannot approximate test time because the best performing cell changed" << endl;
+ cout << "Was " << cell_pos[prev_bpc_i] << " Now " << cell_pos[bpc_i] << endl;
+ }
+ }
+ cout << "Cells about to finish: " << endl;
+ for(int i = 0 ; i < cell_pos.size() ; i++){
+ if(stream_per_cell[i].size() > 768*1024)
+ cout << cell_pos[i] << ":" << stream_per_cell[i].size() << " ";
+
+ prev_cell_flips[i] = stream_per_cell[i].size();
+ }
+ cout << endl;
+ prev_bpc_i = bpc_i;
+ loop_count ++;
+ }
+
+ cout << "Writing bitstreams..." << endl;
+ int filtered_streams = 0;
+ for(int i = 0 ; i < cell_pos.size() ; i++){
+ if(stream_per_cell[i].size() >= 1024*1024){ //&& nonoverlapping_pattern(stream_per_cell[i])){
+ ofstream dump_file;
+ filtered_streams++;
+ string fn = string(argv[1]) + "/" + to_string(bank) + "_" + to_string(r1) +
+ "_" + to_string(r1+3) + "_" + to_string(cell_pos[i]);
+ dump_file.open(fn, ofstream::binary);
+ unsigned wsize = stream_per_cell[i].size()/8;
+ uint8_t wbuf[wsize];
+ for(int j = 0 ; j < wsize ; j++)
+ {
+ uint8_t intermediate = 0;
+ for(int k = 0 ; k < 8 ; k++)
+ intermediate = (intermediate << 1) | stream_per_cell[i][j*8 + k];
+ wbuf[j] = intermediate;
+ }
+ dump_file.write((char*)wbuf, wsize);
+ dump_file.close();
+ }
+ }
+ //cout << "Filtered streams: " << filtered_streams << endl;
+ cout << "Finished processing b:" << bank << " r1:" << r1 << " r2:" << r1+3 << endl;
+ ofstream lfFile;
+ string trackFn = string(argv[1]) + "/" + "lastrow.txt";
+ lfFile.open(trackFn);
+ lfFile << r1;
+ lfFile.close();
+ }
+ }
+}
diff --git a/sources/apps/QUAC-TRNG/src/slow_entropy.cpp b/sources/apps/QUAC-TRNG/src/slow_entropy.cpp
new file mode 100644
index 0000000..a18cf6e
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/src/slow_entropy.cpp
@@ -0,0 +1,204 @@
+#include "instruction.h"
+#include "prog.h"
+#include "platform.h"
+#include "util.h"
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <cstring>
+#include <list>
+#include <math.h>
+#include <algorithm>
+#include <iterator>
+#include <iomanip>
+
+using namespace std;
+
+Program gen_test_prog(int bank, int r1, int r2, int iters, int read_cols, int placement)
+{
+ Program program;
+
+ program.add_inst(SMC_LI(8, CASR)); // Load 8 into CASR since each READ reads 8 columns
+ program.add_inst(SMC_LI(1, RASR)); // Load 1 into RASR
+
+ program.add_inst(SMC_LI(bank, BAR));
+ program.add_inst(SMC_LI(r1, RARBASE));
+
+ program.add_inst(SMC_LI(iters, ITER_REG));
+ program.add_inst(SMC_LI(0, CTR_REG));
+
+ program.add_inst(SMC_PRE(BAR,0,1),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ program.add_inst(SMC_SLEEP(5));
+
+ program.add_inst(SMC_LI(r1, RAR1));
+ program.add_inst(SMC_LI(r2, RAR2));
+
+ program.add_label("WRITE_BEGIN");
+ //program.add_below(genWriteRange(RARBASE, 4, BAR, true));
+ switch(placement)
+ {
+ // Invert 0-1 start pattern before here when we set the
+ // WIDEREG
+ case 1000:
+ program.add_below(genWriteRange1000(RARBASE, 4, BAR));
+ break;
+ case 1001:
+ program.add_below(genWriteRange1001(RARBASE, 4, BAR));
+ break;
+ case 1010:
+ program.add_below(genWriteRange1010(RARBASE, 4, BAR));
+ break;
+ case 1011:
+ program.add_below(genWriteRange1011(RARBASE, 4, BAR));
+ break;
+ case 1100:
+ program.add_below(genWriteRange1100(RARBASE, 4, BAR));
+ break;
+ case 1101:
+ program.add_below(genWriteRange1101(RARBASE, 4, BAR));
+ break;
+ case 1110:
+ program.add_below(genWriteRange1110(RARBASE, 4, BAR));
+ break;
+ case 1111:
+ program.add_below(genWriteRange1111(RARBASE, 4, BAR));
+ break;
+ default:
+ printf("Unexpected placement encoding\n");
+ exit(0);
+ }
+
+ program.add_below(genActPreActSequence(1, 1, RAR1, RAR2, BAR));
+ program.add_inst(SMC_SLEEP(4));
+ program.add_inst(SMC_PRE(BAR, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ program.add_inst(SMC_SLEEP(4));
+ program.add_below(genReadRange(RARBASE, 1, BAR, read_cols));
+
+ program.add_inst(SMC_ADDI(CTR_REG, 1, CTR_REG));
+ program.add_branch(program.BR_TYPE::BL, CTR_REG, ITER_REG, "WRITE_BEGIN");
+ program.add_inst(SMC_END());
+
+ return program;
+}
+
+int main(int argc, char *argv[])
+{
+ bool DUMP_RAW = false;
+
+ SoftMCPlatform platform;
+ int err;
+
+ // buffer allocated for reading data from the board
+ uint8_t buf[4*READ_CL*64];
+
+ // Initialize the platform, opens file descriptors for the board PCI-E interface.
+ if((err = platform.init()) != SOFTMC_SUCCESS){
+ cerr << "Could not initialize SoftMC Platform: " << err << endl;
+ }
+ // reset the board to hopefully restore the board's state
+ platform.reset_fpga();
+ platform.set_aref(true);
+
+ int bank = 1;
+
+ int row_stride = atoi(argv[3]);
+
+ string placement = argv[2];
+ bool invert = false;
+
+ int iters = atoi(argv[4]);
+
+ ofstream ent_file;
+ string fn = string(argv[1]) + "/" + to_string(bank) + "_" + to_string(iters) + "_" + to_string(READ_CL) + "_" + to_string(NO_ROWS) + "_" + placement + ".txt";
+ cout << "Saving to file " << fn << endl;
+ ent_file.open(fn);
+
+ char new_placement[10];
+ if (placement[0] == '0')
+ {
+ for (std::string::size_type i = 0 ; i < placement.size() ; i++)
+ if(placement[i] == '0')
+ new_placement[i] = '1';
+ else if(placement[i] == '1')
+ new_placement[i] = '0';
+ else
+ new_placement[i] = placement[i];
+ placement = string(new_placement);
+ invert = true;
+ }
+
+ Program program;
+ program.add_inst(SMC_LI(invert ? 0x0 : 0xffffffff, PATTERN_REG));
+ program.add_inst(SMC_LI(invert ? 0xffffffff : 0x0, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ program.add_inst(SMC_LDWD(PATTERN_REG,i));
+ program.add_inst(SMC_END());
+ platform.execute(program);
+
+ unsigned char *byte_buf[READ_CL*64];
+ for(int i = 0 ; i < READ_CL*64 ; i++)
+ byte_buf[i] = new unsigned char[iters];
+
+ // Frequency of 1s and 0s generated by each bitline
+ int alphabet[READ_CL*64*8][2];
+
+ ent_file << NO_ROWS/row_stride << " " << READ_CL << endl;
+
+ for(int r1 = 0 ; r1 < NO_ROWS ; r1+=row_stride)
+ {
+ ent_file << r1 << " ";
+ Program prog = gen_test_prog(bank, r1, r1+3, iters, READ_CL, std::stoi(placement));
+ platform.execute(prog);
+
+ for(int i = 0 ; i < iters ; i++)
+ {
+ platform.receiveData((char*)buf, READ_CL*64); // read one segment each iteration
+ for(int j = 0 ; j < READ_CL*64 ; j++)
+ byte_buf[j][i] = buf[j];
+ }
+
+ for(int i = 0 ; i < READ_CL*64*8 ; i++)
+ for(int j = 0 ; j < 2 ; j++)
+ alphabet[i][j] = 0;
+
+ for(int j = 0 ; j < READ_CL*64*8 ; j++)
+ {
+ for(int i = 0 ; i < iters ; i++)
+ alphabet[j][(byte_buf[j/8][i]>>(j%8))&0x1] += 1;
+
+ float approxent = 0;
+ for(int i = 0 ; i < 2 ; i++)
+ {
+ int freq = alphabet[j][i];
+ float p = ((float) freq) / ((float) iters);
+ approxent -= freq == 0 ? 0 : p * log2(p);
+ }
+
+ ent_file << approxent << " ";
+
+ /*
+ if(approxent > 0.995)
+ {
+ unsigned char bits[iters/8]{0};
+ for(int i = 0 ; i < iters ; i++)
+ bits[i/8] |= ((byte_buf[j/8][i] >> (j%8)) & 0x1) << (7-(i%8));
+ ofstream dump_file;
+ string fn = string(argv[2]) + "/" + to_string(r1) + "_" + to_string(j) + ".bin";
+ dump_file.open(fn, ofstream::binary);
+ dump_file.write((char*)(bits), iters/8);
+ dump_file.close();
+ }
+ */
+ }
+
+ ent_file << endl;
+
+ printf("\rrow %d", r1);
+ fflush(stdout);
+ }
+ for(int i = 0 ; i < READ_CL*64 ; i++)
+ delete byte_buf[i];
+ ent_file.close();
+}
diff --git a/sources/apps/QUAC-TRNG/src/slow_sha.cpp b/sources/apps/QUAC-TRNG/src/slow_sha.cpp
new file mode 100644
index 0000000..69bf72f
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/src/slow_sha.cpp
@@ -0,0 +1,233 @@
+#include "instruction.h"
+#include "prog.h"
+#include "platform.h"
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <cstring>
+#include <list>
+#include <algorithm>
+#include <iterator>
+#include <iomanip>
+#include <openssl/sha.h>
+#include "util.h"
+
+using namespace std;
+
+// each iter generates 320 bytes of RN
+// #define ITERS_SHA 450000
+#define READ_CL 128
+
+// Stride register ids are fixed and should not be changed
+// CASR should always be reg 0
+#define CASR 0
+// BASR should always be reg 1
+#define BASR 1
+// RASR should always be reg 2
+#define RASR 2
+
+#define PATTERN_REG 12
+#define INV_PATTERN_REG 13
+#define TEMP_PATTERN_REG 14
+
+#define BAR 3
+#define CAR 4
+#define RARBASE 5
+#define RAR1 6
+#define RAR2 9
+
+#define COPY_REG1 10
+#define COPY_REG2 11
+
+#define ITER_REG 7
+#define CTR_REG 8
+
+#define INIT_LOOP 15
+
+Program gen_test_prog(int bank, int r1, int r2, int iters, int placement)
+{
+ Program program;
+
+ program.add_inst(SMC_LI(8, CASR)); // Load 8 into CASR since each READ reads 8 columns
+ program.add_inst(SMC_LI(1, BASR)); // Load 1 into BASR
+ program.add_inst(SMC_LI(1, RASR)); // Load 1 into RASR
+
+ program.add_inst(SMC_LI(bank, BAR));
+ program.add_inst(SMC_LI(r1-(r1%4), RARBASE));
+
+ program.add_inst(SMC_LI(iters, ITER_REG));
+ program.add_inst(SMC_LI(0, CTR_REG));
+
+ program.add_label("WRITE_BEGIN");
+ program.add_inst(SMC_PRE(BAR, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ program.add_inst(SMC_SLEEP(3));
+ switch(placement)
+ {
+ // Invert 0-1 start pattern before here when we set the
+ // WIDEREG
+ case 1000:
+ program.add_below(genWriteRange1000(RARBASE, 4, BAR));
+ break;
+ case 1001:
+ program.add_below(genWriteRange1001(RARBASE, 4, BAR));
+ break;
+ case 1010:
+ program.add_below(genWriteRange1010(RARBASE, 4, BAR));
+ break;
+ case 1011:
+ program.add_below(genWriteRange1011(RARBASE, 4, BAR));
+ break;
+ case 1100:
+ program.add_below(genWriteRange1100(RARBASE, 4, BAR));
+ break;
+ case 1101:
+ program.add_below(genWriteRange1101(RARBASE, 4, BAR));
+ break;
+ case 1110:
+ program.add_below(genWriteRange1110(RARBASE, 4, BAR));
+ break;
+ case 1111:
+ program.add_below(genWriteRange1111(RARBASE, 4, BAR));
+ break;
+ default:
+ printf("Unexpected placement encoding\n");
+ exit(0);
+ }
+
+ //program.add_below(genCopyRange(RARBASE, 4, BAR, true));
+ program.add_inst(SMC_LI(r1, RAR1));
+ program.add_inst(SMC_LI(r2, RAR2));
+
+ program.add_below(genActPreActSequence(1, 1, RAR1, RAR2, BAR));
+
+ program.add_inst(SMC_SLEEP(6));
+ program.add_inst(SMC_PRE(BAR, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ program.add_below(genReadRange(RARBASE, 1, BAR, 128));
+ program.add_inst(SMC_ADDI(CTR_REG, 1, CTR_REG));
+
+ program.add_branch(program.BR_TYPE::BL, CTR_REG, ITER_REG, "WRITE_BEGIN");
+ program.add_inst(SMC_END());
+
+ return program;
+}
+
+int main(int argc, char *argv[])
+{
+ SoftMCPlatform platform;
+ int err;
+
+ // buffer allocated for reading data from the board
+ unsigned char buf[4*READ_CL*64];
+
+ // Initialize the platform, opens file descriptors for the board PCI-E interface.
+ if((err = platform.init()) != SOFTMC_SUCCESS){
+ cerr << "Could not initialize SoftMC Platform: " << err << endl;
+ }
+ // reset the board to hopefully restore the board's state
+ platform.reset_fpga();
+ platform.set_aref(true);
+ // Read selected segments from file
+ // first line: <number of segments>
+ // each line: <bank> <segment_start> <placement>
+ ifstream sf;
+ string sf_name = string(argv[2]);
+ sf.open(sf_name);
+
+ int n_segments; sf >> n_segments;
+ std::vector<std::string> placements;
+ std::vector<int> banks, segments;
+ std::vector<float> ents;
+ for(int i = 0 ; i < n_segments ; i++)
+ {
+ int read;
+ sf >> read; banks.push_back(read);
+ sf >> read; segments.push_back(read);
+ float ent;
+ sf >> ent; ents.push_back(ent);
+ std::string rd;
+ sf >> rd; placements.push_back(rd);
+ }
+
+ for(int i = 0 ; i < n_segments ; i++)
+ {
+ int bank = banks[i];
+ int r1 = segments[i];
+ float ent = ents[i];
+
+ if (ent < 1)
+ continue;
+
+ std::string placement = placements[i];
+
+ bool invert = false;
+ // placement_magic
+ char new_placement[10];
+ if (placement[0] == '0')
+ {
+ for (std::string::size_type i = 0 ; i < placement.size() ; i++)
+ if(placement[i] == '0')
+ new_placement[i] = '1';
+ else if(placement[i] == '1')
+ new_placement[i] = '0';
+ else
+ new_placement[i] = placement[i];
+ placement = string(new_placement);
+ invert = true;
+ }
+
+ Program program;
+ program.add_inst(SMC_LI(invert ? 0x0 : 0xffffffff, PATTERN_REG));
+ program.add_inst(SMC_LI(invert ? 0xffffffff : 0x0, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ program.add_inst(SMC_LDWD(PATTERN_REG,i));
+ program.add_inst(SMC_END());
+ platform.execute(program);
+
+ unsigned char *bitstream;
+
+ unsigned int sha_input_ent = 256;
+ unsigned int sha_input_blocks = ent/sha_input_ent + 1;
+ unsigned int row_partition_size = 8192/sha_input_blocks;
+ // UNTODO //TODO: from now on this is going to be 16Mbits
+ unsigned int test_iters = (1024*1024*1024)/(8*sha_input_blocks*32);
+
+
+ bitstream = new unsigned char[test_iters*32*sha_input_blocks];
+
+ cout << "Running for " << test_iters << " iterations." << endl;
+ cout << "Total bits of entropy: " << ent << " -> " << sha_input_blocks << " sha input blocks for the row" << endl;
+
+ Program prog = gen_test_prog(bank, r1, r1+3, test_iters, std::stoi(placement));
+ platform.execute(prog);
+
+ for(int i = 0 ; i < test_iters ; i++)
+ {
+ platform.receiveData((char*)buf, 8192); // read one segment each iteration
+ // https://stackoverflow.com/q/13784434
+ for(int j = 0 ; j < sha_input_blocks ; j++)
+ {
+ unsigned char hash[SHA256_DIGEST_LENGTH];
+ SHA256_CTX sha256;
+ SHA256_Init(&sha256);
+ SHA256_Update(&sha256, (char*)(buf+row_partition_size*j), row_partition_size);
+ SHA256_Final(hash, &sha256);
+ for(int k = 0 ; k < SHA256_DIGEST_LENGTH ; k++)
+ {
+ bitstream[i*sha_input_blocks*SHA256_DIGEST_LENGTH + j*SHA256_DIGEST_LENGTH + k] = hash[k];
+ }
+ }
+ }
+ ofstream dump_file;
+ string fn = string(argv[1]) + "/" + placements[i] + "_" + to_string(r1) + ".bin";
+ dump_file.open(fn, ofstream::binary);
+ dump_file.write((char*)(bitstream), test_iters*32*sha_input_blocks);
+ dump_file.close();
+ printf("\rrow %d", r1);
+ fflush(stdout);
+ delete bitstream;
+ }
+
+}
diff --git a/sources/apps/QUAC-TRNG/src/util.cpp b/sources/apps/QUAC-TRNG/src/util.cpp
new file mode 100644
index 0000000..41e4d50
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/src/util.cpp
@@ -0,0 +1,670 @@
+#include "util.h"
+
+/**
+ * To send an ACT -> SLEEP t1 -> PRE -> SLEEP t2 -> ACT sequence
+ * This seq. will use BAR RAR1 and RAR2 registers
+ */
+Program genActPreActSequence(int t1, int t2, int row1_reg, int row2_reg, int bank_reg)
+{
+ Program ret;
+ // t1 -> ACT to PRE, t2 -> PRE to 2nd ACT
+ int sz = 3 + t1 + t2;
+ sz = (4-(sz%4)) + sz;
+ Mininst buff[sz];
+ for(int i = 0 ; i < sz ; i++)
+ buff[i] = SMC_NOP();
+
+ // Overwrite with the actual sequence
+ buff[0] = SMC_ACT(bank_reg, 0, row1_reg, 0);
+ buff[1+t1] = SMC_PRE(bank_reg, 0, 0);
+ buff[2+t1+t2] = SMC_ACT(bank_reg, 0, row2_reg, 0);
+
+ for(int i = 0 ; i < sz ; i+=4)
+ ret.add_inst(buff[i], buff[i+1], buff[i+2], buff[i+3]);
+
+ return ret;
+}
+
+Program genReadRange(int row_reg, int no_rows, int bank_reg, int read_cols)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // read until this row
+ ret.add_label("genReadRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < read_cols/4 ; i++)
+ {
+ ret.add_inst(SMC_READ(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_READ(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_READ(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_READ(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_branch(ret.BR_TYPE::BL, row_reg, INIT_LOOP, "genReadRange:LOOP_BEGIN");
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+
+
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1000(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1001(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1010(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_branch(ret.BR_TYPE::BL, row_reg, INIT_LOOP, "genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1011(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1100(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_inst(SMC_SLEEP(4));
+
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1101(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_inst(SMC_SLEEP(4));
+
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+
+
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1110(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ ret.add_inst(SMC_MV(PATTERN_REG, TEMP_PATTERN_REG));
+ ret.add_inst(SMC_MV(INV_PATTERN_REG, PATTERN_REG));
+ ret.add_inst(SMC_MV(TEMP_PATTERN_REG, INV_PATTERN_REG));
+ for(int i = 0 ; i < 16 ; i++)
+ ret.add_inst(SMC_LDWD(PATTERN_REG,i));
+
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * This function will generate a block of instructions that will
+ * write to a range of rows. It assumes the bank will be precharged.
+ */
+Program genWriteRange1111(int row_reg, int no_rows, int bank_reg)
+{
+ Program ret;
+ ret.add_inst(SMC_LI(no_rows, INIT_LOOP));
+ ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // write until this row
+
+ ret.add_label("genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_LI(0, CAR));
+
+ ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_SLEEP(4));
+
+ for(int i = 0 ; i < 32 ; i++)
+ {
+ ret.add_inst(SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP());
+ ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_WRITE(bank_reg, 0, CAR, 1, 0, 0));
+ ret.add_inst(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP());
+ }
+ ret.add_inst(SMC_SLEEP(4));
+ ret.add_inst(SMC_PRE(bank_reg, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP());
+
+ ret.add_branch(ret.BR_TYPE::BL, row_reg, INIT_LOOP, "genWriteRange:LOOP_BEGIN");
+ ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg));
+ return ret;
+}
+
+/**
+ * @return an instruction formed by NOPs
+ */
+Inst all_nops()
+{
+ return __pack_mininsts(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP());
+}
diff --git a/sources/apps/QUAC-TRNG/src/util.h b/sources/apps/QUAC-TRNG/src/util.h
new file mode 100644
index 0000000..1f07e0e
--- /dev/null
+++ b/sources/apps/QUAC-TRNG/src/util.h
@@ -0,0 +1,55 @@
+#ifndef UTIL_HH
+#define UTIL_HH
+
+#include "prog.h"
+
+#define ITERS_DUMP 1024*1024
+#define READ_CL_DUMP 8
+
+#define ITERS 10000 //1024*1024 // 256*8
+#define READ_CL 128
+
+#define NO_BANKS 1
+#define NO_ROWS 1024*32
+
+// Stride register ids are fixed and should not be changed
+// CASR should always be reg 0
+#define CASR 0
+// BASR should always be reg 1
+#define BASR 1
+// RASR should always be reg 2
+#define RASR 2
+
+#define PATTERN_REG 12
+#define INV_PATTERN_REG 13
+#define TEMP_PATTERN_REG 14
+
+#define BAR 3
+#define CAR 4
+#define RARBASE 5
+#define RAR1 6
+#define RAR2 9
+
+#define COPY_REG1 10
+#define COPY_REG2 11
+
+#define ITER_REG 7
+#define CTR_REG 8
+
+#define INIT_LOOP 15
+
+Program genActPreActSequence(int t1, int t2, int row1_reg, int row2_reg, int bank_reg);
+Program genReadRange(int row_reg, int no_rows, int bank_reg, int read_cols);
+Program genWriteRange1000(int row_reg, int no_rows, int bank_reg);
+Program genWriteRange1111(int row_reg, int no_rows, int bank_reg);
+Program genWriteRange1001(int row_reg, int no_rows, int bank_reg);
+Program genWriteRange1010(int row_reg, int no_rows, int bank_reg);
+Program genWriteRange1011(int row_reg, int no_rows, int bank_reg);
+Program genWriteRange1100(int row_reg, int no_rows, int bank_reg);
+Program genWriteRange1101(int row_reg, int no_rows, int bank_reg);
+Program genWriteRange1110(int row_reg, int no_rows, int bank_reg);
+Inst all_nops();
+
+
+
+#endif