When the CPU needs a piece of data from memory, the requested address is sent to the cache controller. The controller then probes it's frames to see if any of their tags match the address. If a match is found then the data in that frame is sent back to the CPU, otherwise the data has to be fetched from main memory. When an access to main memory occurs, the cache is updated with the value, an empty frame is chosen if possible, otherwise one is picked at random from those probed.
Associativity controls how the cache controller probes the cache frames. The probing is done in parallel, and it is expensive to build hardware to do this. A fully associative cache in which all the frames are probed is the most expensive, and a direct mapped cache in which only one frame with index (memory_address_requested % number_of_frames) is probed, is the cheapest.
The applet's source code.