Why is there seemingly no delay in a block ram read
Did you instantiate a primitive, generated IP, or infer it with an array?  

IP typically has a choice for registered output or not.  

If a primitive or inferred, you decide whether to register it (clocked process) or not in your RTL.  The primitive is typically an asynchronous output, save any vendor-specific attributes that may be associated with it.  

As @EugeneSh. said, The data sheet will tell you everything you need to know.  


  Data stored in caches or in ram would need to be fetched into a register before it can be operated on right?


You do not need to register a signal to operate on it...  Depends on the situation.  For reading memory, I probably would.


  Are these block ram objects just implemented via registers on the chip?


You can choose to "push" memory into registers during synthesis, but, if you have RAM available, typically you would use the RAM (and the tool would default to implement that way too... especially if you used a primitive).  The data sheet will tell you how much RAM you have, and how it is arranged.  The synthesis report will tell you how it was implemented.

To make life easy, I would just infer RAM with an array.