incremental
diff --git a/include/ast_jpeg_decoder.hpp b/include/ast_jpeg_decoder.hpp
index 7e09678..e7b36dc 100644
--- a/include/ast_jpeg_decoder.hpp
+++ b/include/ast_jpeg_decoder.hpp
@@ -1,26 +1,25 @@
 #pragma once
 
-#include <cstdint>
 #include <array>
 #include <aspeed/JTABLES.H>
+#include <ast_video_types.hpp>
+#include <cassert>
+#include <cstdint>
+#include <iostream>
 #include <vector>
 
-#include <ast_video_types.hpp>
-#include <iostream>
+template <class T, class Compare>
+constexpr const T &clamp(const T &v, const T &lo, const T &hi, Compare comp) {
+  return assert(!comp(hi, lo)), comp(v, lo) ? lo : comp(hi, v) ? hi : v;
+}
+
+template <class T>
+constexpr const T &clamp(const T &v, const T &lo, const T &hi) {
+  return clamp(v, lo, hi, std::less<>());
+}
 
 namespace AstVideo {
 
-static const uint32_t VQ_HEADER_MASK = 0x01;
-static const uint32_t VQ_NO_UPDATE_HEADER = 0x00;
-static const uint32_t VQ_UPDATE_HEADER = 0x01;
-static const int VQ_NO_UPDATE_LENGTH = 0x03;
-static const int VQ_UPDATE_LENGTH = 0x1B;
-static const uint32_t VQ_INDEX_MASK = 0x03;
-static const uint32_t VQ_COLOR_MASK = 0xFFFFFF;
-
-static const int BLOCK_AST2100_START_LENGTH = 0x04;
-static const int BLOCK_AST2100_SKIP_LENGTH = 20;  // S:1 H:3 X:8 Y:8
-
 struct COLOR_CACHE {
   unsigned long Color[4];
   unsigned char Index[4];
@@ -541,15 +540,9 @@
           pYUV[n].B = cb;
           pYUV[n].G = y;
           pYUV[n].R = cr;
-          pByte[n].B = rlimit_table[m_Y[y] + m_CbToB[cb]];
-          pByte[n].G = rlimit_table[m_Y[y] + m_CbToG[cb] + m_CrToG[cr]];
-          pByte[n].R = rlimit_table[m_Y[y] + m_CrToR[cr]];
-          /*
-          std::cout << "set y:" << n / 800 << " x:" << n % 800 << " to "
-                    << " B:" << static_cast<uint32_t>(pByte[n].B)
-                    << " G:" << static_cast<uint32_t>(pByte[n].G)
-                    << " R:" << static_cast<uint32_t>(pByte[n].R) << "\n";
-                    */
+          pByte[n].B = clamp(m_Y[y] + m_CbToB[cb], 0, 0xFF);
+          pByte[n].G = clamp(m_Y[y] + m_CbToG[cb] + m_CrToG[cr], 0, 0xFF);
+          pByte[n].R = clamp(m_Y[y] + m_CrToR[cr], 0, 0xFF);
         }
         pos += WIDTH;
       }
@@ -570,9 +563,9 @@
           cb = pcb[m];
           cr = pcr[m];
           n = pos + i;
-          pByte[n].B = rlimit_table[m_Y[y] + m_CbToB[cb]];
-          pByte[n].G = rlimit_table[m_Y[y] + m_CbToG[cb] + m_CrToG[cr]];
-          pByte[n].R = rlimit_table[m_Y[y] + m_CrToR[cr]];
+          pByte[n].B = clamp(m_Y[y] + m_CbToB[cb], 0, 0xFF);
+          pByte[n].G = clamp(m_Y[y] + m_CbToG[cb] + m_CrToG[cr], 0, 0xFF);
+          pByte[n].R = clamp(m_Y[y] + m_CrToR[cr], 0, 0xFF);
         }
         pos += WIDTH;
       }
@@ -614,9 +607,9 @@
           pYUV[n].B = cb;
           pYUV[n].G = y;
           pYUV[n].R = cr;
-          pByte[n].B = rlimit_table[m_Y[y] + m_CbToB[cb]];
-          pByte[n].G = rlimit_table[m_Y[y] + m_CbToG[cb] + m_CrToG[cr]];
-          pByte[n].R = rlimit_table[m_Y[y] + m_CrToR[cr]];
+          pByte[n].B = clamp(m_Y[y] + m_CbToB[cb], 0, 0xFF);
+          pByte[n].G = clamp(m_Y[y] + m_CbToG[cb] + m_CrToG[cr], 0, 0xFF);
+          pByte[n].R = clamp(m_Y[y] + m_CrToR[cr], 0, 0xFF);
         }
         pos += WIDTH;
       }
@@ -637,15 +630,15 @@
           cb = pcb[m];
           cr = pcr[m];
           n = pos + i;
-          pByte[n].B = rlimit_table[m_Y[y] + m_CbToB[cb]];
-          pByte[n].G = rlimit_table[m_Y[y] + m_CbToG[cb] + m_CrToG[cr]];
-          pByte[n].R = rlimit_table[m_Y[y] + m_CrToR[cr]];
+          pByte[n].B = clamp(m_Y[y] + m_CbToB[cb], 0, 0xFF);
+          pByte[n].G = clamp(m_Y[y] + m_CbToG[cb] + m_CrToG[cr], 0, 0xFF);
+          pByte[n].R = clamp(m_Y[y] + m_CrToR[cr], 0, 0xFF);
         }
         pos += WIDTH;
       }
     }
   }
-  int Decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection) {
+  void Decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection) {
     unsigned char *ptr;
     unsigned char byTileYuv[768] = {};
 
@@ -686,19 +679,10 @@
     //    YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf);
     //  YUVBuffer for YUV record
     YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf);
-    if (txb == 0 && tyb == 0) {
-      for (int i=0; i < 10; i++) {
-        auto pixel = YUVBuffer[i];
-        std::cout << "YUBuffer " << static_cast<int>(pixel.R) << " "
-                  << static_cast<int>(pixel.G) << static_cast<int>(pixel.B)
-                  << "\n";
-      }
-    }
-    return 1;
   }
 
-  int Decompress_2PASS(int txb, int tyb, char *outBuf,
-                       uint8_t QT_TableSelection) {
+  void Decompress_2PASS(int txb, int tyb, char *outBuf,
+                        uint8_t QT_TableSelection) {
     unsigned char *ptr;
     unsigned char byTileYuv[768];
     memset(DCT_coeff, 0, 384 * 2);
@@ -717,12 +701,10 @@
 
     YUVToBuffer(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf);
     //    YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf);
-
-    return 1;
   }
 
-  int VQ_Decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection,
-                    struct COLOR_CACHE *VQ) {
+  void VQ_Decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection,
+                     struct COLOR_CACHE *VQ) {
     unsigned char *ptr, i;
     unsigned char byTileYuv[192];
     int Data;
@@ -747,23 +729,21 @@
     }
     //    YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf);
     YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf);
-
-    return 1;
   }
 
   void MoveBlockIndex(void) {
     if (yuvmode == YuvMode::YUV444) {
       txb++;
-      if (txb >= (int)(tmp_WIDTH / 8)) {
+      if (txb >= (int)(WIDTH / 8)) {
         tyb++;
-        if (tyb >= (int)(tmp_HEIGHT / 8)) tyb = 0;
+        if (tyb >= (int)(HEIGHT / 8)) tyb = 0;
         txb = 0;
       }
     } else {
       txb++;
-      if (txb >= (int)(tmp_WIDTH / 16)) {
+      if (txb >= (int)(WIDTH / 16)) {
         tyb++;
-        if (tyb >= (int)(tmp_HEIGHT / 16)) tyb = 0;
+        if (tyb >= (int)(HEIGHT / 16)) tyb = 0;
         txb = 0;
       }
     }
@@ -780,7 +760,6 @@
     VQ->Color[2] = 0x808080;
     VQ->Color[3] = 0xC08080;
   }
-  void init_QT() {}
 
   void Init_Color_Table() {
     int i, x;
@@ -867,7 +846,6 @@
     }
   }
   void init_jpg_table() {
-    init_QT();
     Init_Color_Table();
     prepare_range_limit_table();
     load_Huffman_table(&HTDC[0], std_dc_luminance_nrcodes,
@@ -1054,46 +1032,36 @@
     uint32_t i;
     COLOR_CACHE Decode_Color;
 
+    if (width != WIDTH || height != HEIGHT || yuvmode_in != yuvmode ||
+        y_selector != Y_selector || uv_selector != UV_selector) {
+      init_JPG_decoding();
+    }
+
     // TODO(ed) use the enum everywhere, not just externally
-    yuvmode = yuvmode_in;          // 0 = YUV444, 1 = YUV420
+    yuvmode = yuvmode_in;       // 0 = YUV444, 1 = YUV420
     Y_selector = y_selector;    // 0-7
     UV_selector = uv_selector;  // 0-7
 
     // TODO(ed) Magic number section.  Document appropriately
     advance_selector = 0;  // 0-7
-    First_Frame = 1;       // 0 or 1
     Mapping = 0;           // 0 or 1
-    /*
-    if (yuvmode == YuvMode::YUV420) {
-      Y_selector = 4;
-      UV_selector = 7;
-      Mapping = 0;
-    } else {  // YUV444
-      Y_selector = 7;
-      UV_selector = 7;
-      Mapping = 0;
-    }
-    */
-    auto test = static_cast<int>(yuvmode);
-    std::cout << "YUVmode " << test << " " << static_cast<int>(Y_selector) << static_cast<int>(UV_selector) << "\n";
 
-    tmp_WIDTH = width;
-    tmp_HEIGHT = height;
     WIDTH = width;
     HEIGHT = height;
 
     VQ_Initialize(&Decode_Color);
     // OutputDebugString  ("In decode\n");
     //            GetINFData (VideoEngineInfo);
-    //  WIDTH = VideoEngineInfo->SourceModeInfo.X = 640;
-    //  HEIGHT = VideoEngineInfo->SourceModeInfo.Y = 480;
     //  AST2000 JPEG block is 16x16(pixels) base
+
     if (yuvmode == YuvMode::YUV420) {
+      auto remainder = WIDTH % 16;
       if (WIDTH % 16) {
-        WIDTH = WIDTH + 16 - (WIDTH % 16);
+        WIDTH = WIDTH + 16 - remainder;
       }
-      if (HEIGHT % 16) {
-        HEIGHT = HEIGHT + 16 - (HEIGHT % 16);
+      remainder = HEIGHT % 16;
+      if (remainder) {
+        HEIGHT = HEIGHT + 16 - remainder;
       }
     } else {
       if (WIDTH % 8) {
@@ -1104,25 +1072,6 @@
       }
     }
 
-    //  tmp_WDITH, tmp_HEIGHT are for block position
-    //  tmp_WIDTH = VideoEngineInfo->DestinationModeInfo.X;
-    //  tmp_HEIGHT = VideoEngineInfo->DestinationModeInfo.Y;
-    if (yuvmode == YuvMode::YUV420) {
-      if (tmp_WIDTH % 16) {
-        tmp_WIDTH = tmp_WIDTH + 16 - (tmp_WIDTH % 16);
-      }
-      if (tmp_HEIGHT % 16) {
-        tmp_HEIGHT = tmp_HEIGHT + 16 - (tmp_HEIGHT % 16);
-      }
-    } else {
-      if (tmp_WIDTH % 8) {
-        tmp_WIDTH = tmp_WIDTH + 8 - (tmp_WIDTH % 8);
-      }
-      if (tmp_HEIGHT % 8) {
-        tmp_HEIGHT = tmp_HEIGHT + 8 - (tmp_HEIGHT % 8);
-      }
-    }
-
     int qfactor = 16;
 
     SCALEFACTOR = qfactor;
@@ -1130,10 +1079,6 @@
     ADVANCESCALEFACTOR = 16;
     ADVANCESCALEFACTORUV = 16;
 
-    if (First_Frame == 1) {
-      init_jpg_table();
-      init_JPG_decoding();
-    }
     // TODO(ed) cleanup cruft
     Buffer = buffer.data();
 
@@ -1145,6 +1090,17 @@
     newbits = 32;
     DCY = DCCb = DCCr = 0;
 
+    static const uint32_t VQ_HEADER_MASK = 0x01;
+    static const uint32_t VQ_NO_UPDATE_HEADER = 0x00;
+    static const uint32_t VQ_UPDATE_HEADER = 0x01;
+    static const int VQ_NO_UPDATE_LENGTH = 0x03;
+    static const int VQ_UPDATE_LENGTH = 0x1B;
+    static const uint32_t VQ_INDEX_MASK = 0x03;
+    static const uint32_t VQ_COLOR_MASK = 0xFFFFFF;
+
+    static const int BLOCK_AST2100_START_LENGTH = 0x04;
+    static const int BLOCK_AST2100_SKIP_LENGTH = 20;  // S:1 H:3 X:8 Y:8
+
     do {
       auto block_header = static_cast<JpgBlock>((codebuf >> 28) & 0xFF);
       switch (block_header) {
@@ -1334,8 +1290,6 @@
   // WIDTH and HEIGHT are the modes your display used
   unsigned long WIDTH;
   unsigned long HEIGHT;
-  unsigned long tmp_HEIGHT;
-  unsigned long tmp_WIDTH;
   unsigned char Y_selector;
   int SCALEFACTOR;
   int SCALEFACTORUV;
@@ -1344,7 +1298,6 @@
   int Mapping;
   unsigned char UV_selector;
   unsigned char advance_selector;
-  unsigned char First_Frame;
   int byte_pos;  // current byte position
 
   // quantization tables, no more than 4 quantization tables