

; --------------------------------------------------------
;	IC Tester I/O
; --------------------------------------------------------

io_pins		data	1	; Anzahl Pins IC gesamt (-> nur gerade Werte)
io_flags	data	1	
io_flag_irpt	equ	7	; io_flags.bit(7) = enable pin display update on interrupt

io_bits_table	data	0	; io pin state table:

io_bits_l	data	0	; leftside pins:	bit 0=top
io_bits_A8	data	4	; pin 1..8	top
io_bits_A9	data	4	; pin 9..16	middle
io_bits_A10	data	4	; pin 17..24	bottom

io_bits_r	data	0	; rightside pins:	bit 7=top
io_bits_A11	data	4	; pin 25..32	bottom
io_bits_A12	data	4	; pin 33..40	middle
io_bits_A13	data	4	; pin 41..48	top

io_offset_out	equ	0	; offset +0: out value
io_offset_in	equ	2	; offset +2: input value
io_offset_new	equ	0	; offset +0: new (to be displayed) value
io_offset_old	equ	1	; offset +1: old (displayed) value

io_bits_data_size  equ	4
io_bits_table_size equ	4*6

; where to display graphics:
ic_middle	equ	24		; 23|24

ic_col_lout	equ	ic_middle-8	; linke Seite:	obits	  1 char
ic_col_ltype	equ	ic_middle-7	;		pin type: 2 char
ic_col_lin	equ	ic_middle-5	;		ibits	  1 char
ic_col_lname	equ	ic_middle-4	;		pin name: 4 char

ic_col_rname	equ	ic_middle+0	;Rechte Seite:	pin name: 4 char
ic_col_rin	equ	ic_middle+4	;		ibits	  1 char
ic_col_rtype	equ	ic_middle+5	;		pin type: 2 char
ic_col_rout	equ	ic_middle+7	;		obits	  1 char



; --------------------------------------------------------
; in:	A = pin no. [0..47]
; out:	HL -> attr
; mod:	AF, BC, HL

calc_attr_hl_for_name:
	ld	c,ic_col_lname
	cp	24
	jr	c,ca1
	ld	c,ic_col_rname
	jr	ca2

calc_attr_hl_for_type:
	ld	c,ic_col_ltype	
	cp	24
	jr	c,ca1
	ld	c,ic_col_rtype
	jr	ca2

calc_attr_hl_for_obit:
	ld	c,ic_col_lout	; col
	cp	24
	jr	c,ca1		; linke Seite

	ld	c,ic_col_rout	; col
ca2	cpl			; rechte Seite
	add	48	
ca1	ld	b,a		; row	
	jp	calc_attr_hl_for_row_b_col_c
	
	

; --------------------------------------------------------
; Berechne aus row B und col C die zugehörige Pinnummer
;
; in:	B = row
;	C = col
; out:	A = pin [0..47]

calc_pin_from_rowcol:
	ld	a,c		; col
	cp	ic_middle	; links der Mitte?
	ld	a,b		; dann pin = row
	ret	c		; ja: linke Seite
	ld	a,47
	sub	b		; sonst rechte Seite
	ret			; pin = 47 - row
	


test_col_c_is_obit:
	ld	a,c
	cp	ic_col_lout	; z -> ja
	ret	z
	cp	ic_col_rout	; z -> ja
	ret

test_col_c_is_name:
	ld	a,c
	cp	ic_col_lname	; z -> ja
	ret	z
	cp	ic_col_rname	; z -> ja
	ret

test_col_c_is_type:
	ld	a,c
	cp	ic_col_ltype	; z -> ja
	ret	z
	cp	ic_col_rtype	; z -> ja
	ret


; --------------------------------------------------------
; Lösche aktuelles Highlight auf Pin, Name oder Type-Feld
;
; in:	--
; out:	--
; mod:	AF

ic_hilight_row		data	1
ic_hilight_col		data	1
ic_hilight_attr		data	1
ic_hilight_size		data	1

ic_clear_hilight:
	exx

	ld	hl,ic_hilight_size
	ld	a,(hl)		; size
	and	a
	jr	z,icca3
	ld	e,a		; e = size
	ld	(hl),0		
	dec	hl
	ld	d,(hl)		; attr
	dec	hl
	ld	c,(hl)		; col
	dec	hl
	ld	b,(hl)		; row

	call	calc_attr_hl_for_row_b_col_c	; pres bc, de
	
icca1	ld	(hl),d
	inc	l
	dec	e
	jr	nz,icca1
	
icca3	exx
	ret


; --------------------------------------------------------
; Setze Highlight auf Pin, Name oder Type-Feld
;
; in:	B = row
;	C = col
; out:	--
; mod:	

ic_set_hilight:
	call	ic_validate_hilight		; -> e = size
	call	ic_clear_hilight		; clear old
	call	calc_attr_hl_for_row_b_col_c	; hl -> attr	((pres. bcde))
	ld	d,(hl)				; d = old attr

; set hilight:
	ld	a,e				; a = size
icsh1	ld	(hl),flashing+bright+red+white_paper
	inc	hl
	dec	a
	jr	nz,icsh1

; update ic_hilight:
	ld	hl,ic_hilight_size
	ld	(hl),e		; size
	dec	hl
	ld	(hl),d		; attr
	dec	hl
	ld	(hl),c		; col
	dec	hl
	ld	(hl),b		; row
	ret
	


; --------------------------------------------------------
; Setze Hilight auf ein obit 
;
; in:	A = pin no. [0..47]
; out:	--
; mod:	AF

ic_set_hilight_on_obit:
	
	ld	b,a			; row = pin
	ld	c,ic_col_lout		; col
	cp	24
	jr	c,ic_set_hilight	; wenn pin<24  ~  linke Seite
	ld	c,ic_col_rout		; col
	cpl
	add	48
	jr	ic_set_hilight	



; --------------------------------------------------------
; Setze Hilight auf ein type feld
;
; in:	A = pin no. [0..47]
; out:	--
; mod:	AF, AF'

ic_set_hilight_on_type:
	ld	b,a			; row = pin
	ld	c,ic_col_ltype		; col
	cp	24
	jr	c,ic_set_hilight	; wenn pin<24  ~  linke Seite
	ld	c,ic_col_rtype		; col
	cpl
	add	48
	jr	ic_set_hilight



; --------------------------------------------------------
; Setze Hilight auf ein name feld
;
; in:	A = pin no. [0..47]
; out:	--
; mod:	AF

ic_set_hilight_on_name:
	ld	b,a			; row = pin
	ld	c,ic_col_lname		; col
	cp	24
	jr	c,ic_set_hilight	; wenn pin<24  ~  linke Seite
	ld	c,ic_col_rname		; col
	cpl
	add	48
	jr	ic_set_hilight



; --------------------------------------------------------
; Validate data for pin field
; 
; in:	B=row
;	C=col
; out:	B = row
;	C = vol
;	E = field size
; mod:	AF, BC, E

ic_size_tab	defb	1,2,2,0,4,4,4,4, 4,4,4,4,0,2,2,1
ic_col0_tab	defb	$10,$11,$11,$11,$14,$14,$14,$14   ; col0 der jeweiligen felder
		defb	$18,$18,$18,$18,$18,$1d,$1d,$1f
ic_next_tab	defb	$11,$14,$14,$14,$18,$18,$18,$18   ; col0 des nächsten feldes
		defb	$1d,$1d,$1d,$1d,$1d,$1f,$1f,$10

ic_validate_hilight:
	push	hl
	call	ic_validate_row
	call	ic_validate_col
	call	ic_get_size_for_col
	pop	hl
	ret	

ic_get_size_for_col:
	ld	hl,ic_size_tab-16
	ld	a,c		
	add	l
	ld	l,a
	ld	e,(hl)
	ret	nc
	inc	h
	ld	e,(hl)
	ret

ic_validate_col:
	ld	hl,ic_col0_tab
	ld	a,c	
	and	$0F
	add	l
	ld	l,a
	ld	c,(hl)
	ret	nc			; <- cy vom 'add l'
	inc	h
	ld	c,(hl)
	ret
	
ic_validate_row:
	ld	a,(io_pins)
	and	a
	jr	nz,$+4
	ld	a,48		; wenn pins=0 dann volle Höhe zulassen
	rrca
	dec	a		; a = max
	cp	b
	ret	nc		; ret if b is in range
	bit	7,b		; test sign to determine side of overflow
	ld	b,a
	ret	nz		; nz => neg => b < 0  => b := max
	ld	b,0		; z => pos => b > max => b := 0		
	ret



; --------------------------------------------------------
; clear hilight on current cell (if any) 
; and advance according to key in A 

ic_move_hilight:
	ld	hl,ic_hilight_row
	ld	b,(hl)				; b = row
	inc	hl
	ld	c,(hl)				; c = col

	ld	hl,ic_set_hilight		; preset return address
	push	hl

	cp	keycode_up
	jr	z,ic_up
	cp	keycode_down
	jr	z,ic_down
	cp	keycode_right
	jr	z,ic_right
	cp	keycode_left
	jr	z,ic_left

	cp	'7'
	jr	z,ic_up
	cp	'6'
	jr	z,ic_down
	cp	'8'
	jr	z,ic_right
	cp	'5'
	jr	z,ic_left

	ret					; error
	
ic_up	dec	b
	ret

ic_down	inc	b
	ret

ic_left	dec	c
	ret

ic_right
	ld	hl,ic_next_tab-$10
	ld	a,c
	add	a,l
	ld	l,a
	ld	c,(hl)
	ret	nc
	inc	h
	ld	c,(hl)
	ret



; --------------------------------------------------------
; Init / Start / Stop IC-Grafik
; Data-Bereich muss bei Systemstart genullt werden.
;
; in:	--
; out:	--
; mod:	--

init_pin_display:
stop_pin_display:
	push	hl
	ld	hl,io_flags
	res	io_flag_irpt,(hl)	; disable Grafik
	pop	hl
	ret

start_pin_display:
	push	af
	call	ic_detect_size		
	pop	af
	;jr	resume_pin_display

resume_pin_display:
	push	hl
	ld	hl,io_flags
	set	io_flag_irpt,(hl)	; enable Grafik
	pop	hl
	;jr	ic_force_redraw



; --------------------------------------------------------
; Erzwinge Neuanzeige der Grafik
;
; Die Grafik wird auch sofort einmal ausgegeben, 
; damit die Updateroutine aufgerufen wird, solange noch alle 
; neuen Bytes != die alten Bytes sind.
;
; in:	--
; out:	--
; mod:	--

ic_force_redraw:
	exx
	push	af
	
	ld	hl,io_bits_table
	ld	b,io_bits_table_size / 2

icfr1	ld	a,(hl)			; a = new state
	inc	hl
	cpl
	ld	(hl),a			; old_state := ~new_state  =>  redraw
	inc	hl
	djnz	icfr1

	call	ic_update_all_pins_no_exx
	
	pop	af
	exx
	ret



; --------------------------------------------------------
; Ermittle Pinzahl des eingesetzten ICs:
;
; Ann.: Corner pinning
; Der Pin links-unten muss fest auf 0 liegen
; Setzt io_pins entsprechend
; 
; in:  --
; out: a = io_pins
; mod: af

ic_detect_size:
	call	ic_switch_off		; all pins -> 0
	push	bc
	ld	b,24

icds1	ld	a,b
	dec	a
	call	ic_set_pin		; set pin to 1
	ld	a,b
	dec	a
	call	ic_get_pin		; read pin back
	jr	z,icds2			; ground jumper found
	djnz	icds1

; ground jumper found (n>0) or not found (n=0) => set io_pins
icds2	ld	a,b
	add	a			; *2
	ld	(io_pins),a

	pop	bc
	jp	ic_switch_off		; alle pins wieder 0



; ---------------------------------------------
; Read pin from test socket
;
; Liest das Bit sofort direkt vom Testsockel
; aktualisiert io_bits_table[byte].in.new
;
; Anm.: Normalerweise sollte man io_sync_ibits aufrufen
; und danach alle Pin-States nur noch aus der Tabelle lesen.
;
; in:	a = pin no. [0..47]
; out:	z = z/nz = 0/1
; mod:	af

ic_get_pin:
	exx

	call	ic_calc_ahlbc_for_pin_a_no_exx
	inc	hl
	inc	hl			; -> io_bits_table[byte].in.new
	in	c,(c)
	ld	(hl),c

	and	c			; ret z/nz

	exx
	ret
	
	

; ---------------------------------------------
; Set pin on test socket acc. to cy-flag
;
; Schreibt das Bit umgehend zum Testsockel
; Die restlichen Bits des betroffenen Bytes werden aus 
; der io_bits_table[].out.new gelesen. Dieses Byte
; wird danach auch aktualisiert.
;
; Anm.: Wenn viele Pins geändert werden sollen, ist es besser,
; diese in io_bits_table[].out.new zu ändern und danach
; io_sync_obits und dann auch io_sync_ibits aufzurufen.
;
; in:  a = pin no. [0..47]
;      f = c/nc => set/reset
; out: --
; mod: af

ic_set_pin_to_cy:
	jr	c,ic_set_pin
	;jr	ic_reset_pin



; ---------------------------------------------
; set/clear/toggle usw. pin a
;
; ic_reset_pin		set pin a to 0
; ic_set_pin		set pin a to 1
; ic_toggle_pin		toggle pin a 0 <-> 1
; ic_trigger_pin	double toggle (0-1-0 or 1-0-1 dep. on current state)
;
; in:  a = pin no. [0..47]
; out: --
; mod: af

ic_reset_pin:
	exx
	call	ic_calc_ahlbc_for_pin_a_no_exx
	cpl			; bmask -> nmask
	and	(hl)
ics1:	ld	(hl),a
ics2:	out	(bc),a
	exx
	ret

ic_set_pin:
	exx
ics3	call	ic_calc_ahlbc_for_pin_a_no_exx
	or	(hl)
	jr	ics1
	
ic_toggle_pin:
	exx
	call	ic_calc_ahlbc_for_pin_a_no_exx
	xor	(hl)
	jr	ics1

ic_trigger_pin:
	exx
	call	ic_calc_ahlbc_for_pin_a_no_exx
	xor	(hl)		; toggle
	out	(bc),a
	ld	a,(hl)		; toggle
	jr	ics2

	
	
; ----------------------------------------------
; Calculate parameters for accessing pin a:
;
; in:  a = pin no [0..47]
; out: a = mask for bit
;      bc = io address for byte
;      hl -> io_bits_table[byte].out.new
; mod: af, bc, de, hl

ic_calc_ahlbc_for_pin_a_no_exx:
ic_calc_ahlbc_for_pin_a:

	ld	b,a			; a = b = pin no.

; calc bit mask:
	and	7			; a = bit no.
	ld	hl,bmasks
	add	a,l
	ld	l,a
	ld	c,(hl)			; c = bit mask for bit

; calc offset in io table	
	ld	a,b			; a = b = pin no.
	and	$38			; a = byte no. * 8
	rrca				; a = byte no. * 4
	ld	d,0			
	ld	e,a			; de = offset in io table

; calc io sub address	
	rrca
	rrca				; a = byte no.
	;ld	h,nmasks/256 == bmasks/256
	add	a,nmasks%256
	ld	l,a
	ld	b,(hl)			; b = io sub addr

; final
	ld	hl,io_bits_table
	add	hl,de			; hl -> io_bits_table[byte]
	
	ld	a,c			; a = bit mask for bit
	ld	c,port			; bc = io addr
	ret



; ---------------------------------------------
; write io_bits_table[].out.new to tester and
; read io_bits_table[].in.new from tester 
;
; in:  --
; out: --
; mod: af

io_sync_iobits:
	call	io_sync_obits
	; jr	io_sync_ibits



; ---------------------------------------------
; read io_bits_table[].in.new from tester 
;
; in:  --
; out: --
; mod: af

io_sync_ibits:
	exx
	
	ld	hl,io_bits_table+io_offset_in+io_offset_new + io_bits_data_size*5
	ld	de,-io_bits_data_size
	ld	bc,port_A13

isi1	in	a,(c)
	ld	(hl),a
	add	hl,de
	rrc	b
	jr	c,isi1

	exx
	ret
	
	
	
; ---------------------------------------------
; write io_bits_table[].out.new to tester 
;
; in:  --
; out: --
; mod: af

io_sync_obits:
	exx

	ld	hl,io_bits_table+io_offset_out+io_offset_new  + io_bits_data_size*5
	ld	de,-io_bits_data_size
	ld	bc,port_A13

iso1	ld	a,(hl)
	out	(bc),a
	add	hl,de
	rrc	b
	jr	c,iso1

	exx
	ret



; ---------------------------------------------
; Prüfe, ob der Tester antwortet
;
; in:	--
; out:	a = error code: 0=ok
;	f = z/nz = ok/error
; mod:	af

ic_test_tester_present:
	call	ic_switch_off		; -> all pins 0
	halt				; if no tester attached, then we might read ula bytes 
					; => wait until ula out of screen$ area 
	call	io_sync_ibits		; -> io_bits_table[].in.new sollte jetzt nur Nullen enthalten
	
	exx
	ld	hl,io_bits_table+io_offset_in+io_offset_new
	ld	de,io_bits_data_size
	ld	b,6			; 6 table cells
	sub	a

iso3	or	(hl)			; table[].in.new = 0 ?
	jr	nz,iso4
	add	hl,de
	djnz	iso3

; 6x $00 -> ok!
	exx	
	and	a			; ret z
	ret

; byte != $00 -> error
iso4	push	af			; sp: the byte
	cp	255
	jr	nz,iso5			; byte is not $FF
	ld	a,6
	sub	b
	jr	nz,iso5			; abort not at first byte => tester present but broken
	pop	af			; drop
	
; Abort beim 1. Byte mit Wert $FF:
; dann wahrscheinlich kein Tester dran
	ld	hl,msg_no_tester
	ld	bc,msg_no_tester_size
	call	mem_push_data
iso6	ld	hl,id_error_msg
	call	mem_top_set_user
	ld	a,l			; id_error_msg
	ld	(errno),a
	and	a			; ret nz
	exx
	ret
	
; Tester seems to respond, but not all bits read back are '0':
iso5	ld	a,6
	sub	b			; b=6 <=> A8  ...  b=1 <=> A13  responds != $00
iso55	push	af			; sp: pin group number [0..5]
	ld	hl,msg_tester_broken
	ld	bc,msg_tester_broken_size
	call	mem_push_data
; patch error msg:
	pop	af			; pin group
	add	'0'
	ld	(IX+msg_tester_broken_group),a
	pop	af			; the byte
	ld	b,a
	call	calc_hex_char_no_exx
	ld	(IX+msg_tester_broken_lo),a
	ld	a,b
	call	calc_hex_char_hi_no_exx
	ld	(IX+msg_tester_broken_hi),a
	jr	iso6

msg_no_tester		defm	"Tester does not respond."
msg_no_tester_size	equ	$ - msg_no_tester

msg_tester_broken	defm	"Pin group X responds with $XX."
msg_tester_broken_size	equ	$ - msg_tester_broken
msg_tester_broken_group	equ	10	; offset inside msg
msg_tester_broken_lo	equ	28	; offset inside msg
msg_tester_broken_hi	equ	27	; offset inside msg



; ---------------------------------------------
; Switch Tester on:
; set pin_47 (Vcc) to 1
;
; in:  --
; out: --
; mod: af

ic_switch_on:
	ld	a,47
	call	ic_set_pin
	jp	io_sync_ibits
	


; ---------------------------------------------
; Switch Tester off:
; set all pins to 0
;
; in:  --
; out: --
; mod: af

ic_switch_off:
	exx
	
	sub	a			; a = 0
	ld	bc,all_ports
	out	(bc),a			; -> all off

	ld	hl,io_bits_table+io_offset_out+io_offset_new
	ld	de,io_bits_data_size
	ld	b,6			; 6 table cells

iso2	ld	(hl),a			; table[].out.new := 0
	add	hl,de
	djnz	iso2

	exx
	jp	io_sync_ibits






; ------------------------------------------------
;
;	I N T E R R U P T - R O U T I N E
;
; ------------------------------------------------



; ---------------------------------------------
; Display "0" or "1" at screenbyte address hl
;
; Overwrites entire 8x8 character cell
; Does not set attributes
;
; in:	c.bit(0)
;	hl -> top byte of character cell
; out:	--
; mod:	--

ic_render_pin_no_exx:
ic_render_pin:
	push	af
	push	hl
	push	de

	ld	de,char_0
	bit	0,c
	jr	z,$+4
	ld	e,char_1 % 256		; de -> char_0 or char_1

; 1. Byte ($00) einzeln poken
	;ld	a,(de)
	;ld	(hl),a
	ld	(hl),0

; dann Schleife bis erneut Byte = $00
icrp1	inc	e			; inc de 
	inc	h			; inc hl: row(n+1) = row(n)+256	
	ld	a,(de)
	ld	(hl),a
	and	a
	jr	nz,icrp1		; bis unterstes Byte == $00 kopiert wurde

	pop	de
	pop	hl
	pop	af
	ret	
	
#if ($-1)/256 != ($+8-1+8-1-1)/256
	defs	256 - $%256 + 1
#endif

char_0	equ	$-1
	;defb	%00000000
	defb	%00111100
	defb	%01000110
	defb	%01001010
	defb	%01010010
	defb	%01100010
	defb	%00111100
	defb	%00000000

char_1	equ	$-1
	;defb	%00000000
	defb	%00011000
	defb	%00111000
	defb	%01011000
	defb	%00011000
	defb	%00011000
	defb	%01111110
	defb	%00000000
	
	

; ---------------------------------------------
; Display "0" or "1" for group of 8 pins
; Renders only changed bits
; Uses rr to advance bit => used for leftside columns
;
; in:	hl -> io_pins table cell 
;	de -> screenbyte
;	a = valid bits mask
; out:	hl -> next cell = hl+2
; mod:	af

ic_render_8_pins_left_no_exx:
ic_render_8_pins_left:
	push	bc
	push	de

	ld	b,a			; b = valid bits
	ld	c,(hl)			; c = new value
	inc	hl
	ld	a,(hl)			; a = old value
	ld	(hl),c			; update old value cell
	inc	hl
	push	hl
	
	xor	c			; a = old ^ new = changed bits
	and	b			; a = valid pins only & cy=0
	ex	hl,de			; hl -> screenbyte
	ld	de,32			; de = screen row offset
	jr	icr1
	
icr2	rr	c			; next pin
	add	hl,de			; next character row & cy=0

icr1	rr	a			; next 'pin changed' flag  ((rr a not rra wg. z-flag))
	call	c,ic_render_pin_no_exx	; pin changed => draw it
	jr	nz,icr2			; still 'pin changed' flags set

	pop	hl
	pop	de
	pop	bc
	ret



; ---------------------------------------------
; Display "0" or "1" for group of 8 pins
; Renders only changed bits
; Uses rl to advance bit => used for rightside columns
;
; in:	hl -> io_pins table cell
;	de -> screenbyte
;	a = valid bits mask
; out:	hl -> prev cell = hl-2
; mod:	af

ic_render_8_pins_right_no_exx:
ic_render_8_pins_right:
	push	bc
	push	de
	push	hl

	ld	b,a			; b = valid bits
	ld	c,(hl)			; c = new value
	inc	hl
	ld	a,(hl)			; a = old value
	ld	(hl),c			; update old value cell
	
	xor	c			; a = old ^ new = changed bits
	and	b			; a = valid pins only & cy=0
	ex	hl,de			; hl -> screenbyte
	ld	de,32			; de = screen row offset
	sbc	hl,de
	
icr4	rlc	c			; next pin -> bit 0
	add	hl,de			; next character row & cy=0

	rl	a			; next 'pin changed' flag  ((rl a not rla wg. z-flag))
	call	c,ic_render_pin		; pin changed => draw it
	jr	nz,icr4			; still 'pin changed' flags set

	pop	hl
	pop	de
	pop	bc
	dec	hl
	dec	hl
	ret



; --------------------------------------------------------
; Interruptroutine
;
; Update displayed state if IC pins
; Renders changed pins only
; draws io_pins/2 pins per side
; draws 4 columns in total: 
;	left side:  out state to   test socket
;	left side:  in  state from test socket
;	right side: in  state from test socket
;	right side: out state to   test socket
; Uses data from io_pins table only
; Does not actually read state from tester
;
; in:	--
; out:	--
; mod:	af, bc, de, hl

irpt_pin_display:
	ld	a,(io_flags)
	bit	io_flag_irpt,a
	ret	z
	;jr	ic_update_all_pins



; ---------------------------------------------
; Update all 4 pin display columns
; Renders only changed bits
;
; in:	--
; out:	--
; mod:	af, bc, de, hl

ic_update_all_pins_no_exx:
ic_update_all_pins:

	ld	a,(io_pins)
	sra	a				; a = pins per side
	ret	z				; pins = 0

	ld	bc,io_bits_r +io_offset_in +io_bits_data_size*2	; bc -> right side table, last cell
	ld	hl,io_bits_l +io_offset_out			; hl -> left side table, first cell
	
	ld	d,$40				; de -> screen, start of upper block

icr5	push	bc				; (sp) -> rightside table cells

	ld	c,a				; a = c = remaining pins
	call	calc_rmask_no_exx
	ld	b,a				; a = b = mask	

	ld	e,ic_col_lout			; de -> screenbyte
	call	ic_render_8_pins_left_no_exx	; hl+=2

	ld	a,b				; a = mask
	ld	e,ic_col_lin			; de -> screenbyte
	call	ic_render_8_pins_left_no_exx	; hl+=2

	ex	hl,(sp)				; hl -> rightside table cells

	ld	a,c				; a = c = remaining pins		
	call	calc_lmask_no_exx
	ld	b,a				; a = b = mask	

	ld	e,ic_col_rin			; de -> screenbyte
	call	ic_render_8_pins_right_no_exx	; hl-=2

	ld	a,b				; a = mask
	ld	e,ic_col_rout			; de -> screenbyte
	call	ic_render_8_pins_right_no_exx	; hl-=2

	ex	hl,(sp)				; hl -> leftside table cells

	ld	a,d
	add	8
	ld	d,a				; de -> next screen block
	
	ld	a,c
	sub	8				; a = remaining pins

	pop	bc
	ret	z				; remaining pins = 0
	jr	nc,icr5				; remaining pins > 0
	ret					; remaining pins < 0
	






