	title 'Tarbell - bank & move module for CP/M 3 linked BIOS'

; Copyright (c) 1983 Tarbell Electronics
; Version 1.1 4-13-83 Edwin E. Smith
; added @nbnks value for rtc setup routine in boot module 4-13-83

memory$manager	equ	20h	;base of tarbell memory manager ports

	cseg

	public ?move,?xmove,?bank,?mmtab,?ax16,?gndma
	public @nbnks,?rar4
	extrn @cbnk,@dma,@dbnk

	maclib z80

?mmtab:	; memory select table for Tarbell cpu memory manager
;
;DO NOT ALTER BANK 0
;
	db	00h,01h,02h,03h,04h,05h,06h,07h
	db	08h,09h,0ah,0bh,0ch,0dh,0eh,0fh		;bank 0
;
	db	10h,11h,12h,13h,14h,15h,16h,17h
	db	18h,19h,1ah,1bh,0ch,0dh,0eh,0fh		;bank 1
;
	db	20h,21h,22h,23h,24h,25h,26h,27H
	db	28h,29h,2ah,2bh,0cH,0dh,0eh,0fh		;bank 2
;
	db	30h,31h,32h,33h,34h,35h,36h,37h
	db	38h,39h,3ah,3bh,0ch,0dh,0eh,0fh		;bank 3
;
	db	1ch,1dh,1eh,1fh,2ch,2dh,2eh,2fh
	db	3ch,3dh,3eh,3fh,0ch,0dh,0eh,0fh		;bank 4
;
@nbnks	db	5	;total # of memory segments in the system
;

xflag	db	0	; flag to show next move is interbank
src$des	ds	2	; source and destination banks for ?xmove
desadd	ds	2	; destination address for interbank move
srcadd	ds	2	; source address for interbank move
mcount	ds	2	; byte count for interbank move
;
	ds	16	; setup 16 level local stack
newstk	equ	$
	ds	2	; 2 bytes safety pad
oldstk	ds	2	; old stack storage word
;

?xmove:		; next ?move call is interbank move
		; B = destination bank
		; C = source bank
	sbcd	src$des		;save source and destination
	mvi	a,0ffh
	sta	xflag		;flag to ?move routine
	ret

?move:
	lda	xflag		;test flag for interbank move
	ora	a
	jnz	interbank$move
	xchg			; we are passed source in DE and dest in HL
	ldir			; use Z80 block move instruction
	xchg			; need next addresses in same regs
	ret
interbank$move
	di			; disable interrupts
	sspd	oldstk		; save stack pointer
	lxi	sp,newstk	; use local stack
	shld	desadd		; save destination
	sded	srcadd		; save source
	sbcd	mcount		; save count
;setup source memory to overlay first 8k
	mov	a,d		;get high byte source address
	call	?rar4		;generate 4k block #
	mov	e,a
	lda	src$des		;get source bank #
	mvi	c,memory$manager	;memory manager port
	call	setport		;go setup 2 ports
;setup destination memory to overlay next 8k
	lda	desadd+1	;get destination address
	call	?rar4		;generate 4k block #
	mov	e,a
	lda	src$des+1	;get destination bank #
	inr	c		;increment to next memory manager port
	call	setport		;go setup next 2 ports
;now translate the addresses and do the move
	lhld	srcadd		;get source address
	mov	a,h
	ani	0fh		;clear upper nibble
	mov	h,a
	lded	desadd		;get destination address
	mov	a,d
	ani	0fh		;clear upper nibble
	ori	20h		;set to block #2
	mov	d,a
	lbcd	mcount		;get byte count
	ldir			; FINALLY
	lda	@cbnk		;get the current bank #
	call	?bank		;restore the memory
; now we must show de & hl to point to next real address
	lbcd	mcount		;get byte count
	lhld	srcadd		;get source address
	dad	b		;add together
	xchg			;put hl in de
	lhld	desadd		;get destination address
	dad	b		;add in byte count
	lxi	b,0		;clear byte count just in case
	mov	a,b
	sta	xflag		;clear interbank move flag
	lspd	oldstk		;restore stack pointer
	ei			;reenable interrupts
	ret			;return to cp/m
setport:
	call	?ax16		;multiply by 16
	ora	e		; or in 4k block #
	mov	e,a		;setup offset
	mvi	d,0
	lxi	h,?mmtab	;get table address
	dad	d		;add in offset
	mov	a,m		;get memory manager byte
	cma			;flip for mm chips
	outp	a		;output to memory manager
	inr	c		;increment to next port
	inx	h		;point to next mm byte
	mov	a,m		;get next block just in case
	cma			;flip for mm chips
	outp	a		;output to memory manager
	ret
?bank:
	push	h		;save HL
	push	b		;save BC
	call	?ax16		;multiply A reg times 16
	mov	c,a		;setup offset into memory table
	mvi	b,0		
	lxi	h,?mmtab	;initialize HL to memory table
	dad	b		;add in offset
	lxi	b,1000h+memory$manager	; B=count, C=base port
select$loop
	mov	a,m		;get memory manager byte
	cma			;flip for mm chips
	outp	a		;send it to memory manager
	inr	c		;increment port #
	inx	h		;increment table pointer
	djnz	select$loop	;loop till done
	pop	b
	pop	h
	ret

?ax16:	add	a		; * 2
	add	a		; * 4
	add	a		; * 8
	add	a		; * 16
	ret

?rar4:	ani	0f0h		;move upper nibble of
	rar			;A to lower nibble
	rar			;returns with upper
	rar			;nibble and carry cleared
	rar
	ret

	dseg
		;this routine resides below commonbase

?gndma:		;generate the physical address & extended address
		;for those disks capable of doing the transfer directly
		;returns with extended address in A , the dma address
		;in DE and the memory table pointer in HL.
		;regs used A,DE,HL.

	lda	@dma+1		;get high byte of dma address
	call	?rar4		;generate 4K block #
	mov	e,a
	lda	@dbnk		;get bank #
	call	?ax16
	ora	e		;generate table offset
	mov	e,a
	mvi	d,0
	lxi	h,?mmtab	;get table address
	dad	d		;add in offset
	lded	@dma		;get dma address
	mov	a,d
	ani	0fh		;mask upper nibble
	mov	d,a		;of dma address
	mov	a,m		;get memory manager byte
	ani	0fh		;mask address
	call	?ax16		;shift to upper nibble
	ora	d		;or in lower nibble
	mov	d,a
	mov	a,m		;get memory manager byte
	call	?rar4		;generate extended address
	ret

	end
