From using a debugger on Gradius 3, the oam buffer is stored at $7e3c00 (or was it $7f3c00? Got to double check), and it manages the top 32 bytes of the oam like this:
First it sets the first word of the hi-oam 32 bytes to #$0001. Then, for every sprite it shifts the x and size bits into the word. When it shifts the "1" from the #$0001 into the carry bit, it knows it's time to set up the next word in the hi-oam.
This method is really inefficient. A much swifter way to do this is to temporarily store the x and size bits separate from the oam, and do all the hi-oam processing at the end of the main loop. It is a lot easier for the 65816 to do one job individually at a time, instead of going back and forth between many different jobs.