WIP
diff --git a/vpr/CMakeLists.txt b/vpr/CMakeLists.txt
index fb102fd..5feaf8f 100644
--- a/vpr/CMakeLists.txt
+++ b/vpr/CMakeLists.txt
@@ -8,6 +8,7 @@
 
 #Collect the source files
 file(GLOB_RECURSE EXEC_SOURCES src/main.cpp)
+file(GLOB_RECURSE EXEC_PASSES_SOURCES src/main_passes.cpp)
 file(GLOB_RECURSE LIB_SOURCES src/*/*.cpp)
 file(GLOB_RECURSE LIB_HEADERS src/*/*.h)
 files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
@@ -35,6 +36,11 @@
 target_link_libraries(vpr 
                         libvpr)
 
+#Create the executable
+add_executable(vpr_passes ${EXEC_PASSES_SOURCES})
+target_link_libraries(vpr_passes 
+                        libvpr)
+
 if (VPR_USE_SIGNAL_HANDLER)
     #Check wheter VPR can use sigaction to handle signals (only supported by POSIX)
     CHECK_CXX_SYMBOL_EXISTS(sigaction csignal HAVE_SIGACTION)
diff --git a/vpr/src/base/pass.h b/vpr/src/base/pass.h
new file mode 100644
index 0000000..79fcd76
--- /dev/null
+++ b/vpr/src/base/pass.h
@@ -0,0 +1,97 @@
+#ifndef VPR_PASS_H
+#define VPR_PASS_H
+
+#include "vpr_context_fwd.h"
+
+class Pass {
+    public:
+        virtual bool run_pass() = 0;
+};
+
+/*
+ * Mutable (read/wrtie) pass
+ */
+class MutablePass : public Pass {
+    public:
+        MutablePass(VprContext& vpr_ctx);
+
+        const VprContext& ctx() const { return vpr_ctx_; }
+
+        virtual bool run_pass() final { return run_on_mutable(vpr_ctx_); }
+
+        virtual bool run_on_mutable(VprContext& mutable_ctx) = 0;
+
+    private:
+        VprContext& vpr_ctx_;
+};
+
+/*
+ * Immutable (read-only) pass
+ */
+class ImmutablePass : public Pass {
+    public:
+        ImmutablePass(const VprContext& vpr_ctx);
+
+        const VprContext& ctx() const { return vpr_ctx_; }
+
+        virtual bool run_pass() final { return run_on_immutable(vpr_ctx_); }
+
+        virtual bool run_on_immutable(const VprContext& immutable_ctx) = 0;
+
+    private:
+        const VprContext& vpr_ctx_;
+};
+
+/*
+ * Restricted passes allowing the mutation of only one specific part of the overall context
+ */
+class AtomPass : public MutablePass {
+    public:
+        virtual bool run_on_mutable(VprContext& ctx) final { return run_on_atom(ctx.mutable_atom()); }
+
+        virtual bool run_on_atom(AtomContext& atom_ctx) = 0;
+};
+
+class DevicePass : public MutablePass {
+    public:
+        virtual bool run_on_mutable(VprContext& ctx) final { return run_on_device(ctx.mutable_device()); }
+
+        virtual bool run_on_device(DeviceContext& device_ctx) = 0;
+};
+
+class TimingPass : public MutablePass {
+    public:
+        virtual bool run_on_mutable(VprContext& ctx) final { return run_on_device(ctx.mutable_timing()); }
+
+        virtual bool run_on_timing(TimingContext& timing_ctx) = 0;
+};
+
+class PowerPass : public MutablePass {
+    public:
+        virtual bool run_on_mutable(VprContext& ctx) final { return run_on_device(ctx.mutable_timing()); }
+
+        virtual bool run_on_power(PowerContext& power_ctx) = 0;
+};
+
+class ClusterPass : public MutablePass {
+    public:
+        virtual bool run_on_mutable(VprContext& ctx) final { return run_on_device(ctx.mutable_clustering()); }
+
+        virtual bool run_on_clustering(ClusteringContext& cluster_ctx) = 0;
+};
+
+class PlacePass : public MutablePass {
+    public:
+        virtual bool run_on_mutable(VprContext& ctx) final { return run_on_device(ctx.mutable_placement()); }
+
+        virtual bool run_on_placement(PlacementContext& place_ctx) = 0;
+};
+
+class RoutePass : public MutablePass {
+    public:
+        virtual bool run_on_mutable(VprContext& ctx) final { return run_on_routing(ctx.mutable_routing()); }
+
+        virtual bool run_on_routing(RoutingContext& route_ctx) = 0;
+};
+
+#endif
diff --git a/vpr/src/base/read_circuit.cpp b/vpr/src/base/read_circuit.cpp
index 67ad045..26e47b9 100644
--- a/vpr/src/base/read_circuit.cpp
+++ b/vpr/src/base/read_circuit.cpp
@@ -74,7 +74,7 @@
     return netlist;
 }
 
-static void process_circuit(AtomNetlist& netlist,
+void process_circuit(AtomNetlist& netlist,
                             const t_model *library_models,
                             bool should_absorb_buffers, 
                             bool should_sweep_dangling_primary_ios, 
diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h
index 6a80330..942d9cd 100644
--- a/vpr/src/base/vpr_context.h
+++ b/vpr/src/base/vpr_context.h
@@ -1,5 +1,7 @@
 #ifndef VPR_CONTEXT_H
 #define VPR_CONTEXT_H
+#include "vpr_context_fwd.h"
+
 #include <unordered_map>
 #include <memory>
 #include <vector>
diff --git a/vpr/src/base/vpr_context_fwd.h b/vpr/src/base/vpr_context_fwd.h
new file mode 100644
index 0000000..9c77e65
--- /dev/null
+++ b/vpr/src/base/vpr_context_fwd.h
@@ -0,0 +1,13 @@
+#ifndef VPR_CONTEXT_FWD_H
+#define VPR_CONTEXT_FWD_H
+
+struct AtomContext;
+struct TimingContext;
+struct DeviceContext;
+struct PowerContext;
+struct ClusteringContext;
+struct PlacementContext;
+struct RoutingContext;
+struct VprContext;
+
+#endif
diff --git a/vpr/src/main_passes.cpp b/vpr/src/main_passes.cpp
new file mode 100644
index 0000000..d72d148
--- /dev/null
+++ b/vpr/src/main_passes.cpp
@@ -0,0 +1,99 @@
+/**

+ VPR is a CAD tool used to conduct FPGA architecture exploration.  It takes, as input, a technology-mapped netlist and a description of the FPGA architecture being investigated.  

+ VPR then generates a packed, placed, and routed FPGA (in .net, .place, and .route files respectively) that implements the input netlist.

+ 

+ This file is where VPR starts execution.

+

+ Key files in VPR:

+ 1.  libarchfpga/physical_types.h - Data structures that define the properties of the FPGA architecture

+ 2.  vpr_types.h - Very major file that defines the core data structures used in VPR.  This includes detailed architecture information, user netlist data structures, and data structures that describe the mapping between those two.

+ 3.  globals.h - Defines the global variables used by VPR.

+ */

+

+#include <cstdio>

+#include <cstring>

+#include <ctime>

+using namespace std;

+

+#include "vtr_error.h"

+#include "vtr_memory.h"

+#include "vtr_log.h"

+

+#include "tatum/error.hpp"

+

+#include "vpr_error.h"

+#include "vpr_api.h"

+#include "vpr_signal_handler.h"

+

+#include "globals.h"

+

+#include "read_arch_pass.h"

+#include "read_blif_pass.h"

+#include "clean_atom_netlist_pass.h"

+

+/*

+ * Exit codes to signal success/failure to scripts

+ * calling vpr

+ */

+constexpr int SUCCESS_EXIT_CODE = 0; //Everything OK

+constexpr int ERROR_EXIT_CODE = 1; //Something went wrong internally

+constexpr int UNIMPLEMENTABLE_EXIT_CODE = 2; //Could not implement (e.g. unroutable)

+constexpr int INTERRUPTED_EXIT_CODE = 3; //VPR was interrupted by the user (e.g. SIGINT/ctr-C)

+

+/**

+ * VPR program

+ * Generate FPGA architecture given architecture description

+ * Pack, place, and route circuit into FPGA architecture

+ * Electrical timing analysis on results

+ *

+ * Overall steps

+ * 1.  Initialization

+ * 2.  Pack

+ * 3.  Place-and-route and timing analysis

+ * 4.  Clean up

+ */

+int main(int argc, const char **argv) {

+    vtr::ScopedPrintTimer vpr_timer("VPR");

+

+    try {

+        auto options = read_options(argc, argv);

+

+        std::vector<std::unique_ptr<Pass>> passes;

+

+        passes.push_back(std::make_unique<ReadArchPass>(g_vpr_ctx, options.ArchFile))

+

+        passes.push_back(std::make_unique<ReadBlifPass>(g_vpr_ctx, options.circuit_format, options.BlifFile))

+

+        passes.push_back(std::make_unique<CleanAtomPass>(g_vpr_ctx))

+

+        for (const auto& pass : passes) {

+            pass->run_pass();

+        }

+

+    } catch (const tatum::Error& tatum_error) {

+        vtr::printf_error(__FILE__, __LINE__, "STA Engine: %s\n", tatum_error.what());

+

+        return ERROR_EXIT_CODE;

+

+    } catch (const VprError& vpr_error) {

+        vpr_print_error(vpr_error);

+

+        if (vpr_error.type() == VPR_ERROR_INTERRUPTED) {

+            return INTERRUPTED_EXIT_CODE;

+        } else {

+            return ERROR_EXIT_CODE;

+        }

+

+    } catch (const vtr::VtrError& vtr_error) {

+        vtr::printf_error(__FILE__, __LINE__, "%s:%d %s\n", vtr_error.filename_c_str(), vtr_error.line(), vtr_error.what());

+

+        return ERROR_EXIT_CODE;

+    }

+

+    /* Signal success to scripts */

+    return SUCCESS_EXIT_CODE;

+}

+

+

+

+

diff --git a/vpr/src/passes/clean_atom_netlist_pass.h b/vpr/src/passes/clean_atom_netlist_pass.h
new file mode 100644
index 0000000..2bee3fd
--- /dev/null
+++ b/vpr/src/passes/clean_atom_netlist_pass.h
@@ -0,0 +1,29 @@
+#ifndef CLEAN_ATOM_NETLIST_PASS_H
+#define CLEAN_ATOM_NETLIST_PASS_H
+
+#include "pass.h"
+
+
+class CleanAtomNetlistPass {
+    
+    bool run_on_atom(AtomContext& atom_ctx) override {
+        auto& arch = ctx().device().arch;
+
+        clean_circuit(atom_ctx.nlist,
+                      &arch.library_models,
+                      should_absorb_buffers_,
+                      should_sweep_dangling_primary_ios_,
+                      should_sweep_dangling_nets_,
+                      should_sweep_dangling_blocks_,
+                      should_sweep_constant_primary_outputs_);
+    }
+
+    private:
+        should_absorb_buffers_ = true;
+        should_sweep_dangling_primary_ios_ = true;
+        should_sweep_dangling_nets_ = true;
+        should_sweep_dangling_blocks_ = true;
+        should_sweep_constant_primary_outputs_ = true;
+};
+
+#endif
diff --git a/vpr/src/passes/read_arch_pass.h b/vpr/src/passes/read_arch_pass.h
new file mode 100644
index 0000000..b02c77f
--- /dev/null
+++ b/vpr/src/passes/read_arch_pass.h
@@ -0,0 +1,25 @@
+#ifndef READ_ARCH_H
+#define READ_ARCH_H
+#include "pass.h"
+
+class ReadArchPass : public DevicePass {
+    public:
+
+        ReadArchPass(const std::string arch_file_path)
+            : arch_file_path_(arch_file_path) {}
+        
+        
+        bool run_on_device(DeviceContext& device_ctx) override {
+            XmlReadArch(arch_file_path_.c_str(), 
+                        true,
+                        &device_ctx.arch,
+                        &device_ctx.block_types,
+                        &device_ctx.num_block_types);
+            return true;
+        }
+
+    private:
+        std::string arch_file_path_;
+};
+
+#endif
diff --git a/vpr/src/passes/read_blif_pass.h b/vpr/src/passes/read_blif_pass.h
new file mode 100644
index 0000000..7edacdf
--- /dev/null
+++ b/vpr/src/passes/read_blif_pass.h
@@ -0,0 +1,25 @@
+#ifndef READ_BLIF_PASS_H
+#define READ_BLIF_PASS_H
+#include "pass.h"
+#include "read_blif.h"
+
+class ReadBlifPass : public DevicePass {
+    ReadBlifPass(const e_circuit_format& cct_fmt,
+                 const std::string& blif_file_path)
+        : cct_fmt_(cct_fmt)
+        , blif_file_path_(blif_file_path) {}
+    
+    
+    bool run_on_atom(AtomContext& atom_ctx) override {
+        const auto& arch = ctx().device().arch;
+
+        atom_ctx.netlist = read_blif(cct_fmt_, blif_file_path, arch.models, arch.model_library);
+
+        return true;
+    }
+
+    std::string blif_file_path_;
+    e_circuit_format cct_fmt_;
+};
+
+#endif