The fingerprint g+ has a 16k rom which has an interesting banking scheme:

To appear in the 2k window at C800-CFFF the 16K rom has 8 2k banks.

Writes to C088,x will set the bank.

The first bit of code at C800 and C100 will reset the bank to 0 so it will always start with bank 0 no matter which bank is initially selected.

Code
c800: 48        pha
c801: a9 00     lda #$00
c803: 99 88 c0  sta $c088, y
and this code gets repeated at the beginning of every bank.

What's cool is that the bank number of the current bank is at CFFC. So if we want to execute some code in another bank and come back to our current bank, we just read CFFC, store it somewhere, then write that value back to C088,y.

Code
0000-07ff is bank 00
0800-0fff is bank 80
1000-17ff is bank 40
1800-1fff is bank c0
2000-27ff is bank 20
2800-2fff is bank a0
3000-37ff is bank 60
3800-3fff is bank e0

reading from cffc will tell you the current bank:

hexdump fingerprint_gplus_27c128.u1 | grep "000.[7f]f0"

00007f0 c080 eaea 80ad 9903 c088 ff60 ff00 0fff    <=== bank = 00
0000ff0 c080 eaea 80ad 9903 c088 ff60 ff80 0fff    <=== bank = 80
00017f0 c080 eaea 80ad 9903 c088 ff60 ff40 0fff    <=== bank = 40
0001ff0 c080 eaea 80ad 9903 c088 ff60 ffc0 0fff
00027f0 c080 eaea 80ad 9903 c088 ff60 ff20 0fff
0002ff0 c080 eaea 80ad 9903 c088 ff60 ffa0 0fff
00037f0 c080 eaea 80ad 9903 c088 ff60 ff60 0fff
0003ff0 c080 eaea 80ad 9903 c088 ff60 ffe0 0fff    

bit 7 is +800         8
bit 6 is +1000        4
bit 5 is +2000        2        

Code

ROM_START(fingerprint_gplus_rom)
	ROM_REGION(0x4000, "prom", 0)
	ROM_LOAD( "fingerprint_gplus_27c128.u1", 0x0000, 0x4000, CRC(90bdec85) SHA1(7218016ad00b2d65a3ff473b6950d1e6e047f717) )
ROM_END


void a2bus_fingerprint_gplus_device::write_c0nx(u8 offset, u8 data)
{

	switch (offset)
	{
...		
	case 8U:
		bank_base_address = (data & 0x80 ? 0x800 : 0) + (data & 0x40 ? 0x1000 : 0) + (data & 0x20 ? 0x2000 : 0);
		printf("bank base address = %x\n",bank_base_address);
	}
}

uint8_t a2bus_fingerprint_gplus_device::read_c800(uint16_t offset)
{
	return m_prom[offset + bank_base_address];
}


and the code for c100 is at offset 3000 + 100 * slot number.


Code
d71c: a2 c7     ldx #$c7      c7 is slot address
d71e: a0 70     ldy #$70     70 is slot offset
d720: 84 26     sty $26
d722: 8e f8 07  stx $07f8
d725: a9 00     lda #$00
d727: 8d ff cf  sta $cfff
d72a: 99 88 c0  sta $c088, y    reset the bank to zero


Code
f = io.open("fingerprint_gplus_27c128.u1")  a=f:read("*a") print(a:len()) for i=0,a:len()-1 do c = a:byte(i+1) if (i%64 == 0) then print() io.write(string.format("%4x",i)..": ") end c = c % 128 if c>=32 and c<=126 then io.write(string.char(c)) else io.write(".") end if c==0x1b then io.write("ESC") end end print()

for j=0,6 do o0=0x3100 o1=0x3100 + j*0x100 for i=0,255 do if a:byte(i+1+o0) ~= a:byte(i+1+o1) then print(i,string.format("%x",i+o1),string.format("%x",a:byte(i+1+o0)),string.format("%x",a:byte(i+1+o1))) end end end
29	321d	c1	c2
31	321f	10	20
29	331d	c1	c3
31	331f	10	30
29	341d	c1	c4
31	341f	10	40
29	351d	c1	c5
31	351f	10	50
29	361d	c1	c6
31	361f	10	60
29	371d	c1	c7

this same pattern gets repeated at offset 3900

Code
> for j=0,6 do o0=0x3900 o1=0x3900 + j*0x100 for i=0,255 do if a:byte(i+1+o0) ~= a:byte(i+1+o1) then print(i,string.format("%x",i+o1),string.format("%x",a:byte(i+1+o0)),string.format("%x",a:byte(i+1+o1))) end end end
29	3a1d	c1	c2
31	3a1f	10	20
29	3b1d	c1	c3
31	3b1f	10	30
29	3c1d	c1	c4
31	3c1f	10	40
29	3d1d	c1	c5
31	3d1f	10	50
29	3e1d	c1	c6
31	3e1f	10	60
29	3f1d	c1	c7
31	3f1f	10	70

comparing the two banks shows a few differences.

Code
> for j=0,6 do o0=0x3100 o1=0x3900 + j*0x100 for i=0,255 do if a:byte(i+1+o0) ~= a:byte(i+1+o1) then print(i,string.format("%x",i+o1),string.format("%x",a:byte(i+1+o0)),string.format("%x",a:byte(i+1+o1))) end end end
129	3981	fe	27
131	3983	fe	0
193	39c1	fe	27
195	39c3	fe	0
29	3a1d	c1	c2
31	3a1f	10	20
129	3a81	fe	27
131	3a83	fe	0
193	3ac1	fe	27
195	3ac3	fe	0
29	3b1d	c1	c3
31	3b1f	10	30
129	3b81	fe	27
131	3b83	fe	0
193	3bc1	fe	27
195	3bc3	fe	0

It seemed to work fine mapping offset 3000 + 100 * slotno() into C100

Code
u8 a2bus_fingerprint_gplus_device::read_cnxx(u8 offset)
{
	return m_prom[offset+0x3000+0x100*slotno()];
}

and I think it's very similar to the grappler plus with regards to reading c080 for status, writing c080 for outputting data to the printer.

it writes c088 to change the bank.

it reads c08f to read the DIP switches on the card. Only switches 1-6 are used, 7-8 are unused.
and it's the inverted bit pattern from the manual so 1 will be zero and 0 will be 1.
SW6 = b0, SW5 = b1, SW4 = b2, SW3 = b3, SW2 = b4, SW1 = b5