Wednesday, September 30, 2026

Zip-ties and Double Loops

I had stood in the yard between Block 10 and Block 11 days earlier. The pavement was gray. The wall was blank. I had nothing to say to it. I carried that yard with me across the border. By the time I reached Dachau, the sky was light blue.

Dachau was a model camp. Not a model of humane treatment, but a prototype. An operating manual written in barbed wire, stone, and procedure. Its watchtowers, roll-call yards, classification systems, and guard protocols were refined there and then installed across occupied Europe. The wider network ran to over 44,000 sites, ghettos included. That isn't a number. It's a map of ordinary towns where ordinary men reported for a shift, clocked in, and went home at the end of the day. It is in the lunch pails. It is in the train schedules.

Over 200,000 people were imprisoned at Dachau. At least 40,000 died there or in its subcamps: of typhus, of starvation, of being worked until they stopped, of a bullet at the range, of a death march in the final weeks when the war was already lost and the machine kept running because nobody told it to stop. Not because they couldn't. Because stopping was never part of the procedure. The true figure is unknown and always will be. Those brought to the camp for execution were never registered.

Today German police recruits are required to walk those grounds. Depending on the state, they go to Sachsenhausen, Neuengamme, or Dachau. Not as a field trip. They stand on the pavement where the SS formed ranks and they look up at the same towers.

The badge is not cheaply earned. Years of conditioning, legal education, psychology, crisis intervention, marksmanship. High failure rates, merciless standards. The state demands extraordinary rigor of these recruits, and then demands the one thing rigor cannot supply: that they understand a badge, a manual, and a chain of command confer no morality whatsoever. The men who ran Dachau passed their physicals. They qualified on the range. They were disciplined professionals executing a protocol, and they were good at it. That is the whole horror, and it has nothing to do with monsters. Monsters are easy. Monsters let us sleep.

At Dachau the Bavarian police train on the former SS grounds, the training complex the guards used, adjoining the prisoner camp. Not the victims' quarters. The perpetrators'. That distinction cuts the wrong way for comfort, which is exactly why it belongs in the curriculum.

What the camps industrialized was not cruelty. Cruelty is old and needs no engineering. What they industrialized was restraint as a procurement problem: standardized, catalogued, requisitioned by the gross, applied by men who had been trained in the application and not in the question. Barbed wire, then zip ties. The form persists. Not the hardware, but the requisition form.

Alongside the memorial visits comes antisemitism training. Curricula on symbols, on coded language, on tropes that outlive the regimes that coined them. I want to be careful here, because the intent is real and the alternative is indefensible. But a seminar is a seminar. Antisemitism gets taught as recognition: learn the symbol, learn the slogan, file the report. That is what the organizational theorist Chris Argyris called single-loop learning, refining your performance inside the protocol and never asking what the protocol is for. The double loop is the one that asks what the badge obligates you to when no report is required. It rarely gets taught, because it cannot be graded.

I can only speak to what I saw. In Hanover I was stopped before I was out of the station and asked what I was doing in Germany. I said I had come to see Bergen-Belsen. I was advised not to go. Nothing in the exchange was unlawful and nothing in it was casual. The questions circled, doubled back, waited. Less an inquiry than a probe for a flinch. I was dressed brightly and I was not from there, and that was sufficient to make me worth checking. They had been trained to look. They had not been trained to know what they were looking at.

I also watched police scanning for anything that might read as Nazi. That is not zeal, it is statute: German law bans the symbols outright, and officers are required to look. The scanning does what it is designed to do: catch the obvious. The obvious has never been the problem. The problem is the one who does not announce himself. The one you trust for critical services. The one you've known for 25 years.

Recognition is the codified duty. Which explains the shape of the training, and its limit. The symbol is in the criminal code. The synagogue door is not.

On Yom Kippur 2019, nobody was standing outside the synagogue in Halle. The state police of Saxony-Anhalt had taken no extra precautions there for the holiday. The gunman spent nine minutes on it, firing at the main door and a side gate, setting off improvised explosives, with fifty-one people on the other side. The door held. He killed a woman passing by, then drove to a kebab shop and killed a customer. The door held. Not the state. The officers in that jurisdiction had been taught the history. The history was not the problem. The congregation had asked, and asked, and was met with a curriculum.

At Majdanek a guide told me, loudly, hands raised, that I should try on a survivor's shoes. The shoes are there, in their hundreds of thousands, and she meant it as an exercise.

That is my quarrel with commemoration as pedagogy. A day at a memorial is finite, legible, completable, and the men who ran the camps are safely dead. Vigilance is none of those things. It's a Tuesday. It's an unglamorous patrol car parked where a congregation asked for one, for the eleventh year running, on a holiday when nothing happens, because nothing happening is the entire point. Nobody thanks you for the morning the threat never materialized.

And still: the nation that built this machinery makes its own police stand where it was designed and insists they look. Whatever that costs Germany in self-regard, it pays. The rest of us are asked to pay nothing, and mostly we don't. Which leaves the question I couldn't put down in that yard. Not whether I would have been the guard or the prisoner, because everyone flatters themselves on that one. Whether I'd have been the third thing. The clerk. The driver. The man who noticed the trains and decided it wasn't his department. The man who signed the requisition without reading it.

The barbed wire is gone. The blueprint isn't.

Waning crescent

Thursday, June 7, 2018

HiKey 960 Linux Bridged Firewall

The Kirin 960 SoC and on-board USB 3.0 make the HiKey 960 SBC an ideal platform for running a Linux Bridged firewall. The number of single-board computers with an SoC as powerful as the HiSilicon Kirin 960 is limited.

When compared with the Raspberry Pi series of single board computers (SBC), the HiKey 960 SBC is significantly more powerful. The Kirin 960 also stands above the ARM powered SoCs which reside in most commercial routers.

USB 3.0 makes the HiKey 960 board an attractive option for bridging or routing, filtering network traffic, or connecting to an external gateway via IPSec. Both network traffic filtering and IPSec tunneling can be computationally expensive operations. However, the multicore Kirin 960 is well suited for these types of tasks.

In order to be able to run an IPSec client tunnel and a Linux Bridged firewall connected over 1G ethernet links, certain kernel configuration modifications are needed. Furthermore, the Android Linux kernel for the HiKey 960 board does not boot on a standard Linux root filesystem because it is designed to boot an Android customized rootfs.

The latest googlesource Linux kernel (hikey-linaro-4.9) for Android (designed to boot Android on the HiKey 960 board) has been customized to remove the Android specific components so that the kernel boots on a standard Linux root filesystem, with the proper drivers enabled for network connectivity via attached 1000Mb/s USB 3.0 to ethernet adapters. The standard UART interface on the board should be used for serial connectivity and shell access. WiFi and Bluetooth have been removed from the kernel configuration. The kernel should be booted off of a microSDHC UHS-I card. The 96boards instructions should be followed for configuring the HiKey 960 board, setting the jumpers on the board, building and flashing the l-loader, firmware package, partition tables, UEFI loader, ARM Trusted Firmware, and optional Op-TEE. Links for the normal Linux kernel configuration, multi-interface bridge configuration, and single interface IPSec configuration are below. Additional kernel config modifications may be needed for certain types of applications.

kernel build instructions

mkdir /usr/local/toolchains
cd /usr/local/toolchains/
TC=gcc-linaro-7.2.1-2017.11-x86_64_aarch64-linux-gnu
wget https://releases.linaro.org/components/toolchain/binaries/latest/aarch64-linux-gnu/$TC.tar.xz
tar -xJf $TC.tar.xz
export ARCH=arm64
export CROSS_COMPILE=/usr/local/toolchains/$TC/bin/aarch64-linux-gnu-
export PATH=/usr/local/toolchains/$TC/gcc-aarch64-linux-gnu/bin:$PATH
cd /usr/local/src
git clone https://android.googlesource.com/kernel/hikey-linaro
cd hikey-linaro
git checkout -b android-hikey-linaro-4.9
make hikey960_defconfig
make -j8

multi-interface bridge configuration

Bridged configuration, no ip addresses on dual nic interfaces. (crossover cable is useful for testing). Bridge interface obtains dhcp address (/11) from wlan router. Aliased interface added to br0 and assigned private subnet ip on different subnet (/8). Spanning tree set on bridge interface. Basic ebtables and iptables ruleset below.

brctl addbr <br>
brctl addif <br> <eth1> <eth2>
ifconfig <br> up
ifconfig <eth1> up
ifconfig <eth2> up
brctl stp <br> yes
dhclient <br>
ifconfig <br>:0 <a.b.c.d/sn> up

iptables --table nat --append POSTROUTING --out-interface <br> -j MASQUERADE
iptables -P INPUT DROP
iptables --append FORWARD --in-interface <br>:0 -j ACCEPT
ebtables -P FORWARD DROP
ebtables -P INPUT DROP
ebtables -P OUTPUT DROP
ebtables -t filter -A FORWARD -p IPv4 -j ACCEPT
ebtables -t filter -A INPUT -p IPv4 -j ACCEPT
ebtables -t filter -A OUTPUT -p IPv4 -j ACCEPT
ebtables -t filter -A INPUT -p ARP -j ACCEPT
ebtables -t filter -A OUTPUT -p ARP -j ACCEPT
ebtables -t filter -A FORWARD -p ARP -j REJECT
ebtables -t filter -A FORWARD -p IPv6 -j DROP
ebtables -t filter -A FORWARD -d Multicast -j DROP
ebtables -t filter -A FORWARD -p X25 -j DROP
ebtables -t filter -A FORWARD -p FR_ARP -j DROP
ebtables -t filter -A FORWARD -p BPQ -j DROP
ebtables -t filter -A FORWARD -p DEC -j DROP
ebtables -t filter -A FORWARD -p DNA_DL -j DROP
ebtables -t filter -A FORWARD -p DNA_RC -j DROP
ebtables -t filter -A FORWARD -p LAT -j DROP
ebtables -t filter -A FORWARD -p DIAG -j DROP
ebtables -t filter -A FORWARD -p CUST -j DROP
ebtables -t filter -A FORWARD -p SCA -j DROP
ebtables -t filter -A FORWARD -p TEB -j DROP
ebtables -t filter -A FORWARD -p RAW_FR -j DROP
ebtables -t filter -A FORWARD -p AARP -j DROP
ebtables -t filter -A FORWARD -p ATALK -j DROP
ebtables -t filter -A FORWARD -p 802_1Q -j DROP
ebtables -t filter -A FORWARD -p IPX -j DROP
ebtables -t filter -A FORWARD -p NetBEUI -j DROP
ebtables -t filter -A FORWARD -p PPP -j DROP
ebtables -t filter -A FORWARD -p ATMMPOA -j DROP
ebtables -t filter -A FORWARD -p PPP_DISC -j DROP
ebtables -t filter -A FORWARD -p PPP_SES -j DROP
ebtables -t filter -A FORWARD -p ATMFATE -j DROP
ebtables -t filter -A FORWARD -p LOOP -j DROP
ebtables -t filter -A FORWARD --log-level info --log-ip --log-prefix FFWLOG
ebtables -t filter -A OUTPUT --log-level info --log-ip --log-arp --log-prefix OFWLOG -j DROP
ebtables -t filter -A INPUT --log-level info --log-ip --log-prefix IFWLOG

single-interface ipsec gateway configuration

iptables -t nat -A POSTROUTING -s <clientip>/32 -o <eth> -j SNAT --to-source <virtualip>
iptables -t nat -A POSTROUTING -s <clientip>/32 -o <eth> -m policy --dir out --pol ipsec -j ACCEPT

Thursday, February 1, 2018

a Hardware Design for XOR gates using sequential logic in VHDL

ModelSim full window view with waveform output of the XOR simulation.
ModelSim-Intel FPGA Starter Edition © Intel

XOR logic gates are a fundamental component in cryptography, and many of the typical stream and block ciphers use XOR gates. A few of these ciphers are ChaCha (stream cipher), AES (block cipher), and RSA (block cipher).

While many compiled and interpreted languages support bitwise operations such as XOR, the software implementation of both block and stream ciphers is computationally inefficient compared to FPGA and ASIC implementations.

Hybrid FPGA boards integrate FPGAs with multicore ARM and Intel application processors over high-speed buses. The ARM and Intel processors are general-purpose processors. On a hybrid board, the ARM or Intel processor is termed the hard processor system or HPS. Writing to the FPGA from the HPS is typically performed via C from an embedded Linux build (yocto or buildroot) running on the ARM or Intel core. A simple bitstream can also be loaded into the FPGA fabric without using any ARM design blocks or functionality in the ARM core for a hybrid ARM configuration.

The following is a simple hardware design written in VHDL and simulated in ModelSim. The image contains the waveform output of a simulation in ModelSim. The HPS is not used. On boot, the bitstream is loaded into the FPGA fabric. VHDL components are utilized, and a testbench is defined for testing the design. The entity and architecture VHDL design units are below.

--three input xnor gate entity declaration - external interface to design entity
entity xnorgate is
port (
    a,b,c : in std_logic;
    q : out std_logic);
end xnorgate;

architecture xng of xnorgate is
begin
    q <= a xnor b xnor c;
end xng;

--chain of xor / xnor gates using components and sequential logic
entity xorchain is
port (
    A,B,C,D,E,F : in std_logic;
    Av,Bv       : in std_logic_vector(31 downto 0);
    CLOCK_50    : in std_logic;
    Q           : out std_logic;
    Qv          : out std_logic_vector(31 downto 0));
end xorchain;

architecture rtl of xorchain is
component xorgate is
port (
    a,b  : in std_logic;
    q    : out std_logic);
end component;

component xnorgate is
port (
    a,b,c  : in std_logic;
    q      : out std_logic);
end component;

component xorsgate is
port (
    av : in std_logic_vector(31 downto 0);
    bv : in std_logic_vector(31 downto 0);
    qv : out std_logic_vector(31 downto 0));
end component;

signal a_in, b_in, c_in, d_in, e_in, f_in : std_logic;
signal av_in, bv_in : std_logic_vector(31 downto 0);

signal conn1, conn2, conn3 : std_logic;

begin
    xorgt1  : xorgate port map(a => a_in, b => b_in, q => conn1);
    xorgt2  : xorgate port map(a => c_in, b => d_in, q => conn2);
    xorgt3  : xorgate port map(a => e_in, b => f_in, q => conn3);
    xnorgt1 : xnorgate port map(conn1, conn2, conn3, Q);
    xorsgt1 : xorsgate port map(av => av_in, bv => bv_in, qv => Qv);

   process(CLOCK_50)
   begin
       if rising_edge(CLOCK_50) then --assign inputs on rising clock edge
           a_in <= A;
           b_in <= B;
           c_in <= C;
           d_in <= D;
           e_in <= E;
           f_in <= F;
           av_in(31 downto 0) <= Av(31 downto 0);
           bv_in(31 downto 0) <= Bv(31 downto 0);
       end if;
    end process;
end rtl;

entity xorchain_tb is
end xorchain_tb;

architecture xorchain_tb_arch of xorchain_tb is
    signal A_in,B_in,C_in,D_in,E_in,F_in : std_logic := '0';
    signal Av_in                         : std_logic_vector(31 downto 0);
    signal Bv_in                         : std_logic_vector(31 downto 0);
    signal CLOCK_50_in                   : std_logic;
    signal BRK                           : boolean := FALSE;
    signal Q_out                         : std_logic;
    signal Qv_out                        : std_logic_vector(31 downto 0);

component xorchain
port (
    A,B,C,D,E,F      : in std_logic;
    Av               : in std_logic_vector(31 downto 0);
    Bv               : in std_logic_vector(31 downto 0);
    CLOCK_50         : in std_logic;
    Q                : out std_logic;
    Qv               : out std_logic_vector(31 downto 0));
end component;

begin
    xorchain_instance: xorchain port map (A => A_in,B => B_in, C => C_in,
                                          D => D_in, E => E_in, F => F_in, Av => Av_in,
                                          Bv => Bv_in, CLOCK_50 => CLOCK_50_in, Q => Q_out,
                                          Qv => Qv_out);
clockprocess: process
    begin
        while not BRK loop
            CLOCK_50_in <= '0';
                wait for 20 ns;
                CLOCK_50_in <= '1';
                wait for 20 ns;
        end loop;
    wait;
end process clockprocess;

testprocess : process
    begin
        A_in <= '1';
        B_in <= '0';
        C_in <= '1';
        D_in <= '0';
        E_in <= '1';
        F_in <= '1';
        wait for 40 ns;
        A_in <= '1';
        B_in <= '0';
        C_in <= '1';
        D_in <= '0';
        E_in <= '1';
        F_in <= '0';
        wait for 20 ns;
        A_in <= '0';
        B_in <= '0';
        C_in <= '1';
        D_in <= '0';
        E_in <= '1';
        F_in <= '0';
        wait for 40 ns;
        BRK <= TRUE;
        wait;
    end process testprocess;
end xorchain_tb_arch;

entity xorgate is
port (
    a,b : in std_logic;
    q   : out std_logic);
end xorgate;

architecture xg of xorgate is
begin
    q <= a xor b;
end xg;

entity xorsgate is
port (
    av : in std_logic_vector(31 downto 0);
    bv : in std_logic_vector(31 downto 0);
    qv : out std_logic_vector(31 downto 0));
end xorsgate;

architecture xsg of xorsgate is
begin
    qv <= av xor bv;
end xsg;

Saturday, September 17, 2016

Implementing Software-defined radio and Infrared Time-lapse Imaging with Tensorflow on a custom Linux distribution for the Raspberry Pi 3

The Raspberry Pi 3 is powered by the ARM Cortex-A53 processor. This 1.2GHz 64-bit quad-core processor fully supports the ARMv8-A architecture. For this project, a custom Linux distribution was created for the Raspberry Pi 3.

GNURadio Companion Qt Gui Frequency Sync - multiple FIR filter taps sample running on Raspberry Pi 3 custom Linux distribution
© 2018 Bryan R. Hinton

The custom Linux distribution includes support for GNURadio, several FPGA and ARM Powered SDR devices, D-STAR (hotspot, repeater, and dongle support), hsuart, libusb, hardware real-time clock support, Sony 14 megapixel NoIR image sensor, HDMI and 3.5mm audio, USB Microphone input, X-windows with Xfce, Lighttpd and PHP, Bluetooth, WiFi, SSH, TCPDump, Docker, Docker registry, MySQL, Perl, Python, QT, GTK, IPTables, x11vnc, SELinux, and full native-toolchain development support.

The Sony 14 megapixel image sensor with the infrared filter removed can be connected to the Raspberry Pi 3's MIPI camera serial interface. Image capture and recognition can then be performed over contiguous periods of time, and time-lapsed video can be created from the images. With support for Tensorflow and OpenCV, object recognition within images can be performed.

D-STAR hotspot with time-lapsed infrared imaging.
© 2018 Bryan R. Hinton

For the initial run, an infrared Time-lapse Video was created from an initial image capture run of one 3280x2460 infrared jpeg image captured every 15 seconds for three hours. 40, 5mm, 940nm LEDs, powered by 500ma over 12v DC, provided infrared illumination in the 940nm wavelength.

Tensorflow ran in the background (on v4l2 kmod) and provided continuous object recognition and scoring within each image via a sample model. Finally, OpenCV was also installed in the root file system.

The time-lapse infrared video was captured of the living room using the above setup. Below this image are images of Tensorflow running in a terminal in the background on the Raspberry Pi 3 and recognizing/scoring objects in the living room.

Tensorflow running on the Raspberry Pi 3 and continuously capturing frames from the image sensor and scoring objects
© 2018 Bryan R. Hinton
GNURadio Companion running on xfce on the Raspberry Pi 3
© 2018 Bryan R. Hinton

Tuesday, August 16, 2016

Profiling Multiprocess C programs with ARM DS-5 Streamline

The ARM DS-5 Streamline Performance Analyzer is a powerful tool for debugging, profiling, and analyzing multithreaded and multiprocess C programs. Instructions can easily be traced between load and store operations. Per process and per thread function call paths can be broken down by system utilization percentage. Branch mispredictions and multi-level CPU caches can be analyzed. Furthermore, disk I/O usage, stack and heap usage, and a number of other useful metrics can quickly be referenced within the debugger. These are just a few of its capabilities.

In order to capture meaningful information from the DS-5 Streamline Performance Analyzer tool, a Linux, multiprocess, C program was modified to insert 1000 packets into a packet processing simulation buffer. A code excerpt from the program is below. The child processes were modified to sleep and then wake 1000 times in order to simulate process activity. The program was analyzed using the DS-5 Streamline Performance Analyzer tool. There are two screenshots below the code excerpt where the program is loaded into the DS-5 Streamline Performance Analyzer.

void *insertpackets(void *arg) {

   struct pktbuf *pkbuf;
   struct packet *pkt;
   int idx;

   if(arg != NULL) {

      pkbuf = (struct pktbuf *)arg;

      /* seed random number generator */
      ...

      /* insert 1000 packets into the packet buffer */
      for(idx = 0; idx < 1000; ++idx) {

         pkt = (struct packet *)malloc(sizeof(struct packet));

         if(pkt != NULL) {

            /* set the packet processing simulation multiplier to 3 */
            pkt->mlt=...()%3;

            /* insert packet in the packet buffer */
            if(pkt_queue(pkbuf,pkt) != 0) {

               ...
            ...
         ...
      ...
   ...
...

int fcnb(time_t secs, long nsecs) {

   struct timespec rqtp;
   struct timespec rmtp;
   int ret;
   int idx;

   rqtp.tv_sec = secs;
   rqtp.tv_nsec = nsecs;

   for(idx = 0; idx < 1000; idx++) {

      ret = nanosleep(&rqtp, &rmtp);

      ...
   ...
...
ARM DS-5 Streamline - Profiling the process creation application
© 2018 Bryan R. Hinton
ARM DS-5 Streamline - Code View with C code in the top window and ARM assembly instructions in the bottom window
© 2018 Bryan R. Hinton

Source: run.c

Thursday, June 30, 2016

VHDL Processes for Pulsing Multiple GPIO Pins at Different Frequencies on Altera FPGA

DE1-SoC GPIO Pins connected to 780nm Infrared Laser Diodes, 660nm Red Laser Diodes, and Oscilloscope
© Bryan R. Hinton

The following VHDL processes pulse the GPIO pins at different frequencies on the Altera DE1-SoC using multiple Phase-Locked Loops. Several diodes were connected to the GPIO banks and pulsed at a 50% duty cycle with 16mA across 3.3V. Each GPIO bank on the DE1-SoC has 36 pins. Pin 1 is pulsed at 20Hz from GPIO bank 0, and pins 0 and 1 are pulsed at 30Hz from GPIO bank 1. A direct mode PLL with locked output was configured using the Altera Quartus Prime MegaWizard. The PLL reference clock frequency is set to 50MHz, the output clock frequency is set to 50MHz, and the duty cycle is set to 50%. The pin mappings for GPIO banks 0 and 1 are documented on the DE1-SoC datasheet.

Pulsed Laser Diodes via GPIO pins on DE1-SoC FPGA
© Bryan R. Hinton
-----------------------------------------------------------
-- CLOCK A AND B PROCESSES --
-- INPUT: direct mode pll with locked output
-- and reference clock frequency set to 50MHz,
-- output clock frequency set to 50MHz with 50% duty
-- cycle and output frequency scaled by freq divider constant
-----------------------------------------------------------

clk_a_process : process (lkd_pll_clk_a)
begin
    if rising_edge(lkd_pll_clk_a) then
        if (cycle_ctr_a < FREQ_A_DIVIDER) then
            cycle_ctr_a <= cycle_ctr_a + 1;
        else
            cycle_ctr_a <= 0;
        end if;
    end if;
end process clk_a_process;

clk_b_process : process (lkd_pll_clk_b)
begin
    if rising_edge(lkd_pll_clk_b) then
        if (cycle_ctr_b < FREQ_B_DIVIDER) then
            cycle_ctr_b <= cycle_ctr_b + 1;
        else
            cycle_ctr_b <= 0;
        end if;
    end if;
end process clk_b_process;

-----------------------------------------------------------
-- GPIO A AND B PROCESSES --
-- INPUT: direct mode pll with locked output
-----------------------------------------------------------

gpio_a_process : process (lkd_pll_clk_a)
begin
    if rising_edge(lkd_pll_clk_a) then
        if (cycle_ctr_a = 0) then
            gpio_sig_0 <= NOT gpio_sig_0;
        end if;
    end if;
end process gpio_a_process;

gpio_b_process : process (lkd_pll_clk_b)
begin
    if rising_edge(lkd_pll_clk_b) then
        if (cycle_ctr_b = 0) then
            gpio_sig_1 <= NOT gpio_sig_1;
        end if;
    end if;
end process gpio_b_process;

GPIO_0 <= gpio_sig_0;
GPIO_1 <= gpio_sig_1;

Friday, June 3, 2016

FPGA Audio Processing with the Cyclone V Dual-Core ARM Cortex-A9

The DE1-SoC FPGA Development board from Terasic is powered by an integrated Altera Cyclone V FPGA and ARM MPCore Cortex-A9 processor. The FPGA and ARM core are connected by a high-speed interconnect fabric. Linux can be booted on the ARM core and the FPGA and ARM core can communicate.

The DE1-SoC board below has been programmed via Quartus Prime running on Fedora 23, 64-bit Linux. The FPGA bitstream was compiled from the Terasic Audio codec design reference. After the bitstream was loaded on to the FPGA over the USB blaster II interface, the NIOS II command shell was used to load the NIOS II software image onto the chip. A menu-driven, debug interface is running from a terminal on the host via the NIOS II shell with the target connected over the USB Blaster II interface.

A low-level hardware abstraction layer was programmed in C to configure the on-board audio codec chip. The NIOS II chip is stored in on-chip memory and a PLL driven, clock signal is fed into the audio chip. The Verilog code for the hardware design was generated from Qsys. The design supports configurable sample rates, mic in, and line in/out.

Additional components are connected to the DE1-SoC board in this photo. The Linear DC934A (LTC2607) DAC is connected to the DE1-SoC and an oscilloscope is connected to the ground and vref pins on the DAC.

The DC934A features an LTC2607 16-Bit Dual DAC with i2c interface and an LTC2422 2-Channel 20-Bit uPower No Latency Delta Sigma ADC.

3.5mm audio cables are connected to the mic in and line out ports, respectively. The DE1-SoC is connected to an external display over VGA so that a local console can be managed via a connected keyboard and mouse when Linux is booted from uSD.

With GPIO pins accessible via the GPIO 0 and 1 breakouts, external LEDs can be pulsed directly from the Hard Processor System (HPS), FPGA, or the FPGA via the HPS.