Implemnt sound capture in the simulator
diff --git a/verilog/sim/Makefile b/verilog/sim/Makefile
index eb56330..7ee86b6 100644
--- a/verilog/sim/Makefile
+++ b/verilog/sim/Makefile
@@ -36,10 +36,13 @@
 
 CPPSRCS += \
 	./main.cpp \
+	./audiosim.cpp \
+	./cic.cpp \
 	./dispsim.cpp \
 	./mbcsim.cpp \
 	./memsim.cpp \
 	./mmrprobe.cpp \
+	./waveheader.cpp \
 	verilated.cpp \
 	verilated_vcd_c.cpp
 
diff --git a/verilog/sim/audiosim.cpp b/verilog/sim/audiosim.cpp
new file mode 100644
index 0000000..55894e5
--- /dev/null
+++ b/verilog/sim/audiosim.cpp
@@ -0,0 +1,103 @@
+//
+// VerilogBoy simulator
+// Copyright 2022 Wenting Zhang
+//
+// audiosim.cpp: Capture PDM output and pass through a filter then save to wave
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <vector>
+#include "cic.h"
+#include "audiosim.h"
+#include "waveheader.h"
+
+AUDIOSIM::AUDIOSIM(void) {
+    initializeCicFilterStruct(3, DECIMATION_M, &filter_left);
+    initializeCicFilterStruct(3, DECIMATION_M, &filter_right);
+    pcm.clear();
+    bit_counter = 0;
+    byte_counter = 0;
+    bypass_counter = 0;
+}
+
+AUDIOSIM::~AUDIOSIM(void) {
+
+}
+
+void AUDIOSIM::save(char *fname) {
+    printf("Max: %d, min: %d\n", max, min);
+    save_wav(fname, pcm);
+    save_wav("bypass.wav", byp);
+}
+
+void AUDIOSIM::save_wav(char *fname, std::vector<int16_t> &pcm) {
+    uint8_t header[44];
+    waveheader(header, 48000, 16, pcm.size() / 2);
+    FILE *fp;
+    fp = fopen(fname, "wb+");
+    fwrite(header, 44, 1, fp);
+    fwrite(&pcm[0], pcm.size() * 2, 1, fp);
+    fclose(fp);
+    printf("Audio save to %s\n", fname);
+}
+
+void AUDIOSIM::apply(uint8_t left, uint8_t right) {
+    byte_left |= left << 7;
+    byte_right |= right << 7;
+    bit_counter++;
+    if (bit_counter < 8) {
+        byte_left >>= 1;
+        byte_right >>= 1;
+    }
+    else {
+        bit_counter = 0;
+        pdm_buffer_left[byte_counter] = byte_left;
+        pdm_buffer_right[byte_counter] = byte_right;
+        byte_counter++;
+        if (byte_counter == PDM_SAMPLE_SIZE * DECIMATION_M / 8) {
+            byte_counter = 0;
+            executeCicFilter(pdm_buffer_left, PDM_SAMPLE_SIZE * DECIMATION_M,
+                    pcm_buffer_left, &filter_left);
+            executeCicFilter(pdm_buffer_right, PDM_SAMPLE_SIZE * DECIMATION_M,
+                    pcm_buffer_right, &filter_right);
+            for (int i = 0; i < PDM_SAMPLE_SIZE; i++) {
+                pcm.push_back((int16_t)(pcm_buffer_left[i] / 64));
+                pcm.push_back((int16_t)(pcm_buffer_right[i] / 64));
+                if (pcm_buffer_left[i] > max)
+                    max = pcm_buffer_left[i];
+                if (pcm_buffer_left[i] < min)
+                    min = pcm_buffer_left[i];
+            }
+        }
+    }
+}
+
+void AUDIOSIM::bypass(int16_t left, int16_t right) {
+    bypass_counter++;
+    if (bypass_counter == DECIMATION_M) {
+        bypass_counter = 0;
+        byp.push_back(left);
+        byp.push_back(right);
+    }
+}
\ No newline at end of file
diff --git a/verilog/sim/audiosim.h b/verilog/sim/audiosim.h
new file mode 100644
index 0000000..97c2a86
--- /dev/null
+++ b/verilog/sim/audiosim.h
@@ -0,0 +1,58 @@
+//
+// VerilogBoy simulator
+// Copyright 2022 Wenting Zhang
+//
+// audiosim.h: Capture PDM output and pass through a filter then save to wave
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+#pragma once
+
+// 4M->48K: 88 times decimation
+#define DECIMATION_M        88
+#define PDM_SAMPLE_SIZE     4096
+
+class AUDIOSIM {
+public:
+    AUDIOSIM(void);
+    ~AUDIOSIM(void);
+    void save(char *fname);
+    void apply(uint8_t left, uint8_t right);
+    void bypass(int16_t left, int16_t right);
+private:
+    int bit_counter;
+    int byte_counter;
+    uint8_t byte_left;
+    uint8_t byte_right;
+    struct CicFilter_t filter_left;
+    struct CicFilter_t filter_right;
+    uint8_t pdm_buffer_left[PDM_SAMPLE_SIZE * DECIMATION_M / 8];
+    int32_t pcm_buffer_left[PDM_SAMPLE_SIZE];
+    uint8_t pdm_buffer_right[PDM_SAMPLE_SIZE * DECIMATION_M / 8];
+    int32_t pcm_buffer_right[PDM_SAMPLE_SIZE];
+    std::vector<int16_t> pcm;
+
+    int bypass_counter;
+    std::vector<int16_t> byp;
+
+    int32_t max;
+    int32_t min;
+
+    void save_wav(char *fname, std::vector<int16_t> &pcm);
+};
diff --git a/verilog/sim/cic.cpp b/verilog/sim/cic.cpp
new file mode 100644
index 0000000..e0fa141
--- /dev/null
+++ b/verilog/sim/cic.cpp
@@ -0,0 +1,104 @@
+// Software CIC
+// https://blog.y2kb.com/posts/pdm-mic-spi-cic/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "cic.h"
+
+void initializeCicFilterStruct(uint8_t CicFilterOrder, uint32_t CicFilterDecimation, struct CicFilter_t* st)
+{
+    if (CicFilterOrder == 0)
+    {
+        printf("Order of CIC filter must be over 0\r\n");
+        return;
+    }
+    if(CicFilterDecimation == 0)
+    {
+        printf("Decimation of CIC filter must be over 0\r\n");
+        return;
+    }
+    st->order = CicFilterOrder;
+    st->decimation = CicFilterDecimation;
+    st->out_i = (int32_t*) malloc(sizeof(int32_t) * st->order);
+    st->out_c = (int32_t*) malloc(sizeof(int32_t) * st->order);
+    st->z1_c  = (int32_t*) malloc(sizeof(int32_t) * st->order);
+    
+    if ((st->out_i == NULL) || (st->out_c == NULL) || (st->z1_c == NULL))
+    {
+        printf("CicFilterStruct malloc error\r\n");
+        return;
+    }
+    resetCicFilterStruct(st);
+}
+
+void resetCicFilterStruct(struct CicFilter_t* st)
+{
+    if(st == NULL)
+        return;
+    
+    for(uint8_t i = 0; i < st->order; i++)
+    {
+        *(st->out_i + i) = 0;
+        *(st->out_c + i) = 0;
+        *(st->z1_c  + i) = 0;
+    }
+}
+
+void executeCicFilter(uint8_t* pInBit, uint32_t pInBit_Num, int32_t* pOut_int32, struct CicFilter_t* st)
+{
+    //uint8_t Bout = st->order * (uint8_t)(ceil(log2f(st->decimation))) + 1;
+    int32_t in_bit;
+    uint8_t in_Byte;
+    uint32_t Bit_i, Decimation_count;
+    uint8_t i;
+
+    for(Bit_i = 0, Decimation_count = st->decimation - 1; Bit_i < pInBit_Num; ++Bit_i, --Decimation_count)
+    {
+        in_Byte = *(pInBit + (Bit_i >> 3) );
+        if( (in_Byte >> (Bit_i & 0x07)) & 0x01 )    // First bit is [b0]
+            in_bit = 1;
+        else
+            in_bit = -1;
+
+        // Integrator (No need to consider saturation.
+        //   ref : http://d.hatena.ne.jp/suikan+blackfin/20060611/1149996053 (Japanese) )
+        *(st->out_i) += in_bit;
+
+        for (i = 1; i < st->order; ++i)
+        {
+            *(st->out_i + i) += *(st->out_i + i - 1);
+        }
+
+        // Decimation
+        if(Decimation_count == 0)
+        {
+            Decimation_count = st->decimation;
+
+            // Comb filter
+            *(st->out_c) = *(st->out_i + st->order - 1) - *(st->z1_c);
+            *(st->z1_c)  = *(st->out_i + st->order - 1);
+
+            for (i = 1; i < st->order; ++i)
+            {
+                *(st->out_c + i) = *(st->out_c + i - 1) - *(st->z1_c + i);
+                *(st->z1_c  + i) = *(st->out_c + i - 1);
+            }
+
+            *(pOut_int32 + Bit_i / st->decimation) = *(st->out_c + st->order - 1);
+        }
+    }
+}
+
+void finalizeCicFilterStruct(struct CicFilter_t* st)
+{
+    if (st == NULL)
+        return;
+    
+    st->order = 0;
+    st->decimation = 0;
+    free(st->out_i);
+    free(st->out_c);
+    free(st->z1_c);
+}
diff --git a/verilog/sim/cic.h b/verilog/sim/cic.h
new file mode 100644
index 0000000..abe8e89
--- /dev/null
+++ b/verilog/sim/cic.h
@@ -0,0 +1,17 @@
+// Software CIC
+// https://blog.y2kb.com/posts/pdm-mic-spi-cic/
+#pragma once
+
+struct CicFilter_t
+{
+    uint8_t order;
+    uint32_t decimation;
+    int32_t *out_i;
+    int32_t *out_c;
+    int32_t *z1_c;
+};
+
+void initializeCicFilterStruct(uint8_t, uint32_t, struct CicFilter_t*);
+void resetCicFilterStruct(struct CicFilter_t*);
+void executeCicFilter(uint8_t*, uint32_t, int32_t*, struct CicFilter_t*);
+void finalizeCicFilterStruct(struct CicFilter_t*);
diff --git a/verilog/sim/main.cpp b/verilog/sim/main.cpp
index b98ede5..396fb3e 100644
--- a/verilog/sim/main.cpp
+++ b/verilog/sim/main.cpp
@@ -26,6 +26,7 @@
 #include <stdint.h>
 #include <assert.h>
 #include <time.h>
+#include <vector>
 
 #include <SDL.h>
 
@@ -37,6 +38,8 @@
 #include "mbcsim.h"
 #include "dispsim.h"
 #include "mmrprobe.h"
+#include "cic.h"
+#include "audiosim.h"
 
 #define CLK_PERIOD_PS 250000
 
@@ -62,6 +65,7 @@
 static bool nostop = false;
 static bool itrace = false;
 static bool usembc = false;
+static bool enable_audio = false;
 static unsigned short breakpoint = 0xff7f;
 static char result_file[127];
 
@@ -71,6 +75,7 @@
 MBCSIM *mbc;
 DISPSIM *dispsim;
 MMRPROBE *mmrprobe;
+AUDIOSIM *audiosim;
 FILE *it;
 
 // State
@@ -115,6 +120,15 @@
             core->valid);
     }
 
+    if (enable_audio) {
+        audiosim->apply(
+            core->audiol,
+            core->audior);
+        audiosim->bypass(
+            core->simtop__DOT__chip__DOT__left,
+            core->simtop__DOT__chip__DOT__right);
+    }
+
     if (verbose) {
         mmrprobe->apply(
             SIGNAL(cpu_dout),
@@ -219,6 +233,10 @@
         if (strcmp(argv[i], "--mbc") == 0) {
             usembc = true;
         }
+        // Enable audio capture
+        if (strcmp(argv[i], "--audio") == 0) {
+            enable_audio = true;
+        }
     }
 
     if (enable_trace) {
@@ -254,6 +272,10 @@
     else
         cartrom->load(argv[1]);
 
+    if (enable_audio) {
+        audiosim = new AUDIOSIM();
+    }
+
     // Start simulation
     if (verbose)
         printf("Simulation start.\n");
@@ -406,6 +428,10 @@
         delete cartrom;
         delete cartram;
     }
+    if (enable_audio) {
+        audiosim->save("audio.wav");
+        delete audiosim;
+    }
 
     return 0;
 }
\ No newline at end of file
diff --git a/verilog/sim/waveheader.cpp b/verilog/sim/waveheader.cpp
new file mode 100644
index 0000000..1e44700
--- /dev/null
+++ b/verilog/sim/waveheader.cpp
@@ -0,0 +1,53 @@
+#include <stdint.h>
+#include "waveheader.h"
+
+void waveheader(uint8_t *header, uint32_t sampleRate, uint32_t bitsPerSample, uint32_t samples) {
+    uint32_t audioDataLen = samples * (bitsPerSample / 8u) * 2u;
+    uint32_t fileSize = audioDataLen + 44u;
+    uint32_t totalDataLen = fileSize - 8u;
+    uint32_t byteRate = sampleRate * (bitsPerSample / 8u) * 2u;
+    header[0] = 'R';
+    header[1] = 'I';
+    header[2] = 'F';
+    header[3] = 'F';
+    header[4] = (totalDataLen & 0xff); /* file-size (equals file-size - 8) */
+    header[5] = ((totalDataLen >> 8U) & 0xff);
+    header[6] = ((totalDataLen >> 16U) & 0xff);
+    header[7] = ((totalDataLen >> 24U) & 0xff);
+    header[8] = 'W'; /* Mark it as type "WAVE" */
+    header[9] = 'A';
+    header[10] = 'V';
+    header[11] = 'E';
+    header[12] = 'f'; /* Mark the format section 'fmt ' chunk */
+    header[13] = 'm';
+    header[14] = 't';
+    header[15] = ' ';
+    header[16] = 16; /* 4 bytes: size of 'fmt ' chunk, Length of format data.  Always 16 */
+    header[17] = 0;
+    header[18] = 0;
+    header[19] = 0;
+    header[20] = 1; /* format = 1 ,Wave type PCM */
+    header[21] = 0;
+    header[22] = 2; /* channels */
+    header[23] = 0;
+    header[24] = (sampleRate & 0xff);
+    header[25] = ((sampleRate >> 8U) & 0xff);
+    header[26] = ((sampleRate >> 16U) & 0xff);
+    header[27] = ((sampleRate >> 24U) & 0xff);
+    header[28] = (byteRate & 0xff);
+    header[29] = ((byteRate >> 8U) & 0xff);
+    header[30] = ((byteRate >> 16U) & 0xff);
+    header[31] = ((byteRate >> 24U) & 0xff);
+    header[32] = (2 * bitsPerSample / 8); /* block align */
+    header[33] = 0;
+    header[34] = bitsPerSample; /* bits per sample */
+    header[35] = 0;
+    header[36] = 'd'; /*"data" marker */
+    header[37] = 'a';
+    header[38] = 't';
+    header[39] = 'a';
+    header[40] = (audioDataLen & 0xff); /* data-size (equals file-size - 44).*/
+    header[41] = ((audioDataLen >> 8) & 0xff);
+    header[42] = ((audioDataLen >> 16) & 0xff);
+    header[43] = ((audioDataLen >> 24) & 0xff);
+}
\ No newline at end of file
diff --git a/verilog/sim/waveheader.h b/verilog/sim/waveheader.h
new file mode 100644
index 0000000..cce5f7e
--- /dev/null
+++ b/verilog/sim/waveheader.h
@@ -0,0 +1,4 @@
+
+#pragma once
+
+void waveheader(uint8_t *header, uint32_t sampleRate, uint32_t bitsPerSample, uint32_t samples);
\ No newline at end of file