diff --git a/lib/77bit/packjt77.f90 b/lib/77bit/packjt77.f90
index eab4ff6c6..b0a1312b5 100644
--- a/lib/77bit/packjt77.f90
+++ b/lib/77bit/packjt77.f90
@@ -43,6 +43,38 @@ module packjt77
 
   contains
   
+subroutine readhash(filename)
+   character(len=*), intent(in) :: filename
+   logical :: file_exists
+
+   inquire(file=filename, exist=file_exists)
+   if (file_exists) then
+      open(unit=10, file=filename, access='STREAM', form='UNFORMATTED', STATUS='OLD')
+
+      READ(10) calls10
+      READ(10) calls12
+      READ(10) calls22
+      READ(10) ihash22
+      READ(10) nzhash
+      close(unit=10)
+   endif
+
+end subroutine readhash
+
+subroutine writehash(filename)
+   character(len=*), intent(in) :: filename
+
+   open(unit=10, file=filename, access='STREAM', form='UNFORMATTED', STATUS='REPLACE')
+
+   WRITE(10) calls10
+   WRITE(10) calls12
+   WRITE(10) calls22
+   WRITE(10) ihash22
+   WRITE(10) nzhash
+   close(unit=10)
+
+end subroutine writehash
+
 subroutine hash10(n10,c13)
 
   character*13 c13
diff --git a/lib/jt9.f90 b/lib/jt9.f90
index c6c80164f..0b2cf285e 100644
--- a/lib/jt9.f90
+++ b/lib/jt9.f90
@@ -12,6 +12,7 @@ program jt9
   use readwav
   use ft8_mod1, only : dd8
   use jt65_mod6, only : dd
+  use packjt77
 
   include 'jt9com.f90'
 
@@ -32,8 +33,9 @@ program jt9
   logical :: read_files = .true., tx9 = .false., display_help = .false.,     &
        bLowSidelobes = .false., nexp_decode_set = .false.,                   &
        have_ntol = .false.,multift8 = .false.,hidedupes = .false.,           &
-       lft8lowth = .true.,lft8subpass = .true.,lwidedxcsearch = .true.
-  type (option) :: long_options(41) = [                                      &
+       lft8lowth = .true.,lft8subpass = .true.,lwidedxcsearch = .true.,      &
+       persist_hash = .false.
+  type (option) :: long_options(42) = [                                      &
     option ('help', .false., 'h', 'Display this help message', ''),          &
     option ('shmem',.true.,'s','Use shared memory for sample data','KEY'),   &
     option ('tr-period', .true., 'p', 'Tx/Rx period, default SECONDS=60',    &
@@ -102,6 +104,8 @@ program jt9
     option ('my-grid', .true., 'G', 'my grid locator', 'GRID'),              &
     option ('his-call', .true., 'x', 'his callsign', 'CALL'),                &
     option ('his-grid', .true., 'g', 'his grid locator', 'GRID'),            &
+    option ('persist-hash', .true.,                                          &
+        'P', 'persist hashcodes', 'PATH'),                                   &
     option ('experience-decode', .true., 'X',                                &
         'experience based decoding flags (1..n), default FLAGS=0',           &
         'FLAGS') ]
@@ -119,7 +123,7 @@ program jt9
   TRperiod=60.d0
 
   do
-     call getopt('hs:e:a:b:r:m:p:d:f:F:w:t:9876543WYqkTMUSZL:S:H:c:G:x:g:X:Q:C:R:N:E:D:',     &
+     call getopt('hs:e:a:b:r:m:p:d:f:F:w:t:9876543WYqkTMUSZL:S:H:c:G:x:g:P:X:Q:C:R:N:E:D:',   &
           long_options,c,optarg,arglen,stat,offset,remain,.true.)
      if (stat .ne. 0) then
         exit
@@ -209,6 +213,9 @@ program jt9
            read (optarg(:arglen), *) hiscall
         case ('g')
            read (optarg(:arglen), *) hisgrid
+        case ('P')
+           hash_file = optarg(:arglen)
+           persist_hash = .true.
         case ('X')
            read (optarg(:arglen), *) nexp_decode
            nexp_decode_set = .true.
@@ -233,6 +240,10 @@ program jt9
      stop
   endif
 
+  if (persist_hash) then
+     call readhash(hash_file)
+  end if
+
   iret=fftwf_init_threads()            !Initialize FFTW threading 
 
 ! Default to 1 thread, but use nthreads for the big ones
@@ -512,4 +523,8 @@ program jt9
   call fftwf_cleanup_threads()
   call fftwf_cleanup()
 
+  if (persist_hash) then
+     call writehash(hash_file)
+  end if
+
 end program jt9
diff --git a/lib/prog_args.f90 b/lib/prog_args.f90
index d8caa5495..5c7348940 100644
--- a/lib/prog_args.f90
+++ b/lib/prog_args.f90
@@ -2,5 +2,6 @@ MODULE prog_args
   CHARACTER(len=80) :: shm_key
   CHARACTER(len=500) :: exe_dir = '.', data_dir = '.', temp_dir = '.',    &
        share_dir = '.' !ft8md added share_dir
+  CHARACTER(len=500) :: hash_file = 'hash.dat'
   LOGICAL :: lquiet = .false.
 END MODULE prog_args
