What are ASIC miners actually doing? I'm trying to understand Bitcoin mining (software-wise), and I wonder how ASIC miners are different? I'm going through this minimal Bitcoin miner Github repository.

Which part of Program.cs are ASICs optimizing (I guess Program.cs line 90)? Where can I read more about in-depth working of miners? Is there any documentation?
From trying to design my own ASIC---I got as far as having a simulated but not completely debugged Verilog implementation---I can tell you how mine would have worked. Whilst I have not checked, the design choices seem so obvious to me that I doubt anyone would do it differently.

The inner loop of the mining process is a double SHA-256 hash of data where only one 32-bit word, essentially a counter or "nonce", changes. It looks for a specific result where there are enough zeros in the right place after the second SHA-256 and only needs to output that counter value for which this is the case (if it is for any).

This inner loop is perfect for implementation in hardware: The SHA-256 is of reasonably low complexity, is itself a loop that can easily be unrolled and pipelined (there are 64 identical steps in each of the two applications after an optimization I'll describe later), and if the counter-loop is included in the hardware, then the required IO is very low, both in terms of actual data transmitted and in the sense that it can be very slow with negligible impact on overall performance.

In the source code you reference, the loop I am talking about constitutes the entire function FindShare (lines 85 through 107). However, let me explain that of the actual work, implemented in FindShare as Sha256(Sha256(Current)) in line 90, due to an easy and very common optimization, only half of the initial function call is executed. The first half can easily be moved outside the loop.

If you really want to know the details, then I should add that part of the first of the two SHA-256 runs that should be done for each counter value is identical for all counter values. Naturally that should be optimized, and removing it reduces the hardware complexity significantly. It is even removed from many software mining implementations (one protocol used for mining pools actually lets the pool solve that bit, passing only the intermediary SHA-256 data to the miners). So what remains for the ASIC is some I/O logic to get that intermediate SHA-256 data and then finish 2 applications of the SHA-256 hash algorithms on the resulting data, check the output (and output a signal if it corresponds to finding a block or solving a share in a mining pool), and iterate 2^32 times with the next counter value.

Because an ASIC is a really custom-made chip, and because SHA-256 is such a hardware-implementation-friendly algorithm, it is reasonable to generate one new double-SHA-256-hash every clock cycle from a much smaller area of silicon than it takes to make a general purpose CPU, which takes many hundred clock cycles for the same computation. Whilst in principle the same is true for FPGAs, the fact that their structure isn't quite what one would wish for to do fully unrolled, pipelined SHA-256 (the area-intensive more efficient method of choice for Bitcoin mining, but not typical for other applications and pre-mining ASIC cores for SHA-256) means that in many cost-effective FPGAs one struggles to fit a single fully unrolled double SHA-256, whilst an ASIC can easily accomodate many.