I don't know what you mean by "quickly", but here's a "GetBlock" subroutine I've used in the past:
Code:
;----------------------------------------------------------------
;DESCRIPTION:
; Finds the code of the block at the specified map coordinates.
;INPUT:
; BlockX, BlockY: pixel coordinates of the block to find;
;OUTPUT:
; A: code of the requested block;
;----------------------------------------------------------------
Assembler_StartMember Level, GetBlock
Assembler_StartAbsoluteVariables System::Scratchpad
BlockX: .res 2 ;horizontal coordinate of the block to find
BlockY: .res 2 ;vertical coordinate of the block to find
MapRowAddress: .res 2 ;pointer used to get screens from the level map
Assembler_EndAbsoluteVariables
;read the index of the huge structure from the level map (37 cycles)
lda BlockY+1
and Level::WrapMaskY
tay
lda (Level::MapRowsLow), y
sta MapRowAddress+0
lda (Level::MapRowsHigh), y
sta MapRowAddress+1
lda BlockX+1
and Level::WrapMaskX
tay
lda (MapRowAddress), y
;HugeStructureFound:
;read the index of the large structure from the huge structure (19, 20 or 21 cycles)
tay
bit BlockY+0
bmi :++
bit BlockX+0
bmi :+
lda (Level::HugeStructuresPart0), y
jmp LargeStructureFound
: lda (Level::HugeStructuresPart1), y
jmp LargeStructureFound
: bit BlockX+0
bmi :+
lda (Level::HugeStructuresPart2), y
jmp LargeStructureFound
: lda (Level::HugeStructuresPart3), y
LargeStructureFound:
;read the index of the small structure from the large structure (19, 20 or 21 cycles)
tay
bit BlockY+0
bvc :++
bit BlockX+0
bvc :+
lda (Level::LargeStructuresPart0), y
jmp SmallStructureFound
: lda (Level::LargeStructuresPart1), y
jmp SmallStructureFound
: bit BlockX+0
bvc :+
lda (Level::LargeStructuresPart2), y
jmp SmallStructureFound
: lda (Level::LargeStructuresPart3), y
SmallStructureFound:
;read the index of the tiny structure from the small structure (21, 22 or 23 cycles)
tay
lda #%00100000
bit BlockY+0
bne :++
bit BlockX+0
bne :+
lda (Level::SmallStructuresPart0), y
jmp TinyStructureFound
: lda (Level::SmallStructuresPart1), y
jmp TinyStructureFound
: bit BlockX+0
bne :+
lda (Level::SmallStructuresPart2), y
jmp TinyStructureFound
: lda (Level::SmallStructuresPart3), y
TinyStructureFound:
;read the index of the block from the tiny structure (21, 22 or 23 cycles)
tay
lda #%00010000
bit BlockY+0
bne :++
bit BlockX+0
bne :+
lda (Level::TinyStructuresPart0), y
jmp Return
: lda (Level::TinyStructuresPart1), y
jmp Return
: bit BlockX+0
bne :+
lda (Level::TinyStructuresPart2), y
jmp Return
: lda (Level::TinyStructuresPart3), y
Return:
;return
rts
Assembler_EndMember
I had pointers in ZP pointing to the 4 quadrants of every type of block, and looking at bits from the coordinates I selected which quadrant to read at each step. This subroutine only reads the index of a 16x16-pixel block from the map, if you want more information about the block you still have to look it up.
Now that I'm looking at it again, this does seem to be a bit on the slow side, depending on how many blocks you have to read per frame. I don't see why we can't discuss other possibilities, though. IIRC, this subroutine is meant for random access to anywhere in the map, but when decoding rows and columns of blocks you can probably unroll the code somehow to avoid reading the same blocks over and over (specially the 256x256-pixel block, here called "huge structure"). I never got to do this because at the time I didn't think it was worth the trouble.