Make a2_pack_*.py use the same LZSS compressor, rev flag controls the direction
authorNick Downing <nick@ndcode.org>
Tue, 21 Jun 2022 09:50:48 +0000 (19:50 +1000)
committerNick Downing <nick@ndcode.org>
Tue, 21 Jun 2022 09:50:48 +0000 (19:50 +1000)
loader/a2_pack_fwd.py
loader/a2_pack_rev.py

index d474b32..07d4a92 100755 (executable)
@@ -30,7 +30,10 @@ out_a2bin = sys.argv[4]
 with open(lzss_unpack_fwd_bin, 'rb') as fin:
   lzss_unpack_fwd = list(fin.read())
 
-def lzss_pack(dest, bin):
+def lzss_pack(dest, bin, rev):
+  if rev:
+    bin = bin[::-1] # makes it easier to construct LZSS items
+
   heads = {}
   links = [-1] * len(bin)
   lzss = []
@@ -68,16 +71,16 @@ def lzss_pack(dest, bin):
       i += 1
 
   # checking
-  #bin1 = []
-  #lzss1 = lzss[::-1]
-  #while len(lzss1):
-  #  _len, dist = lzss1.pop()
-  #  if _len == 1:
-  #    bin1.append(dist)
-  #  else:
-  #    for i in range(_len):
-  #      bin1.append(bin1[-dist])
-  #assert bin == bin1
+  bin1 = []
+  lzss1 = lzss[::-1]
+  while len(lzss1):
+    _len, dist = lzss1.pop()
+    if _len == 1:
+      bin1.append(dist)
+    else:
+      for i in range(_len):
+        bin1.append(bin1[-dist])
+  assert bin == bin1
 
   # construct the real output in reverse to how it will be decoded,
   # this means we flush the bits at the right time for the decoder,
@@ -102,7 +105,13 @@ def lzss_pack(dest, bin):
       elif _len < (1 << LEN_BITS1) and dist < (1 << DIST_BITS1):
         item = dist | (_len << DIST_BITS1)
         #print('c', item)
-        lzss1.extend([item >> 8, item & 0xff])
+        # keep the 16-bit words in little-endian order in memory,
+        # means swapping them if the output will be reversed later
+        lzss1.extend(
+          [item & 0xff, item >> 8]
+        if rev else
+          [item >> 8, item & 0xff]
+        )
         cf = 1
       else:
         assert False
@@ -123,51 +132,57 @@ def lzss_pack(dest, bin):
       lzss1.append(bits & 0xff)
       bits = 1
       count += 1
-  lzss = lzss1[::-1]
+  lzss = lzss1
 
   # checking
-  #bin1 = []
-  #lzss1 = lzss[::-1]
-  #count1 = count
-  #bits1 = bits
-  #while True:
-  #  if bits1 == 1:
-  #    if count1 == 0:
-  #      break
-  #    count1 -= 1
-  #    bits1 = lzss1.pop() | 0x100
-  #    #print('e', bits1)
-  #  cf = bits1 & 1
-  #  bits1 >>= 1
-  #
-  #  if cf:
-  #    if bits1 == 1:
-  #      bits1 = lzss1.pop() | 0x100
-  #      #print('d', bits1)
-  #    cf = bits1 & 1
-  #    bits1 >>= 1
-  #
-  #    if cf:
-  #      item = lzss1[-1] | (lzss1[-2] << 8)
-  #      del lzss1[-2:]
-  #      #print('c', item)
-  #      dist = item & ((1 << DIST_BITS1) - 1)
-  #      _len = item >> DIST_BITS1
-  #    else:
-  #      item = lzss1.pop()
-  #      #print('b', item)
-  #      dist = item & ((1 << DIST_BITS0) - 1)
-  #      _len = item >> DIST_BITS0
-  #    _len += 2
-  #    dist += 1
-  #
-  #    for i in range(_len):
-  #      bin1.append(bin1[-dist])
-  #  else:
-  #    #print('a', lzss1[-1])
-  #    bin1.append(lzss1.pop())
-  #assert len(lzss1) == 0
-  #assert bin1 == bin
+  bin1 = []
+  lzss1 = list(lzss)
+  count1 = count
+  bits1 = bits
+  while True:
+    if bits1 == 1:
+      if count1 == 0:
+        break
+      count1 -= 1
+      bits1 = lzss1.pop() | 0x100
+      #print('e', bits1)
+    cf = bits1 & 1
+    bits1 >>= 1
+  
+    if cf:
+      if bits1 == 1:
+        bits1 = lzss1.pop() | 0x100
+        #print('d', bits1)
+      cf = bits1 & 1
+      bits1 >>= 1
+  
+      if cf:
+        # keep the 16-bit words in little-endian order in memory,
+        # means swapping them if the output will be reversed later
+        item = (
+          lzss1[-2] | (lzss1[-1] << 8)
+        if rev else
+          lzss1[-1] | (lzss1[-2] << 8)
+        )
+        del lzss1[-2:]
+        #print('c', item)
+        dist = item & ((1 << DIST_BITS1) - 1)
+        _len = item >> DIST_BITS1
+      else: 
+        item = lzss1.pop()
+        #print('b', item)
+        dist = item & ((1 << DIST_BITS0) - 1)
+        _len = item >> DIST_BITS0
+      _len += 2
+      dist += 1
+  
+      for i in range(_len):
+        bin1.append(bin1[-dist])
+    else:
+      #print('a', lzss1[-1])
+      bin1.append(lzss1.pop())
+  assert len(lzss1) == 0
+  assert bin1 == bin
 
   # optimization: provided the input is not null, the first byte
   # has to be literal, so the loader can fall straight into the
@@ -175,13 +190,22 @@ def lzss_pack(dest, bin):
   if bits == 1:
     assert count
     count -= 1
-    bits = lzss.pop(0) | 0x100
+    bits = lzss.pop() | 0x100
   assert (bits & 1) == 0
   bits >>= 1
 
-  # prepend data block
+  # LZSS data has been reversed by stackwise encoding method
+  # change it back if needed and put the data block on correct end
   count ^= 0xffff # inc/test is easier than test/dec
-  return [dest & 0xff, dest >> 8, count & 0xff, count >> 8, bits] + lzss
+  data_block = [dest & 0xff, dest >> 8, count & 0xff, count >> 8, bits]
+  if rev:
+    # append data block
+    lzss.extend(data_block)
+  else:
+    # prepend data block
+    lzss.extend(data_block[::-1])
+    lzss = lzss[::-1]
+  return lzss
 
 intelhex = IntelHex(in_ihx)
 entry_point = intelhex.start_addr['EIP']
@@ -337,7 +361,7 @@ for i in range(0, len(segments), 2):
   else:
     addr2 = len(section_payload.data)
     section_payload.data.extend(
-      lzss_pack(addr0, data)
+      lzss_pack(addr0, data, False)
     )
     addr3 = len(section_payload.data)
     report.append(
index a836597..806f397 100755 (executable)
@@ -30,8 +30,9 @@ out_a2bin = sys.argv[4]
 with open(lzss_unpack_rev_bin, 'rb') as fin:
   lzss_unpack_rev = list(fin.read())
 
-def lzss_pack(dest, bin):
-  bin = bin[::-1] # !!! for rev, makes it easier to construct LZSS items
+def lzss_pack(dest, bin, rev):
+  if rev:
+    bin = bin[::-1] # makes it easier to construct LZSS items
 
   heads = {}
   links = [-1] * len(bin)
@@ -104,7 +105,13 @@ def lzss_pack(dest, bin):
       elif _len < (1 << LEN_BITS1) and dist < (1 << DIST_BITS1):
         item = dist | (_len << DIST_BITS1)
         #print('c', item)
-        lzss1.extend([item & 0xff, item >> 8]) # !!! swapped for rev
+        # keep the 16-bit words in little-endian order in memory,
+        # means swapping them if the output will be reversed later
+        lzss1.extend(
+          [item & 0xff, item >> 8]
+        if rev else
+          [item >> 8, item & 0xff]
+        )
         cf = 1
       else:
         assert False
@@ -125,11 +132,11 @@ def lzss_pack(dest, bin):
       lzss1.append(bits & 0xff)
       bits = 1
       count += 1
-  lzss = lzss1 # !!! not reversed for rev
+  lzss = lzss1
 
   # checking
   bin1 = []
-  lzss1 = list(lzss) # !!! not reversed for rev
+  lzss1 = list(lzss)
   count1 = count
   bits1 = bits
   while True:
@@ -150,7 +157,13 @@ def lzss_pack(dest, bin):
       bits1 >>= 1
   
       if cf:
-        item = lzss1[-2] | (lzss1[-1] << 8) # !!! swapped for rev
+        # keep the 16-bit words in little-endian order in memory,
+        # means swapping them if the output will be reversed later
+        item = (
+          lzss1[-2] | (lzss1[-1] << 8)
+        if rev else
+          lzss1[-1] | (lzss1[-2] << 8)
+        )
         del lzss1[-2:]
         #print('c', item)
         dist = item & ((1 << DIST_BITS1) - 1)
@@ -177,13 +190,22 @@ def lzss_pack(dest, bin):
   if bits == 1:
     assert count
     count -= 1
-    bits = lzss.pop() | 0x100 # !!! from end for rev
+    bits = lzss.pop() | 0x100
   assert (bits & 1) == 0
   bits >>= 1
 
-  # append data block
+  # LZSS data has been reversed by stackwise encoding method
+  # change it back if needed and put the data block on correct end
   count ^= 0xffff # inc/test is easier than test/dec
-  return lzss + [dest & 0xff, dest >> 8, count & 0xff, count >> 8, bits]
+  data_block = [dest & 0xff, dest >> 8, count & 0xff, count >> 8, bits]
+  if rev:
+    # append data block
+    lzss.extend(data_block)
+  else:
+    # prepend data block
+    lzss.extend(data_block[::-1])
+    lzss = lzss[::-1]
+  return lzss
 
 intelhex = IntelHex(in_ihx)
 entry_point = intelhex.start_addr['EIP']
@@ -346,7 +368,7 @@ for i in range(len(segments) - 2, -2, -2):
   else:
     addr3 = -len(section_payload.data)
     section_payload.data.extend(
-      lzss_pack(addr1 - 1, data)[::-1]
+      lzss_pack(addr1 - 1, data, True)[::-1]
     )
     addr2 = -len(section_payload.data)
     report.append(