
;Test program 2 for testing the Datatron paper tape punch
;
;Just punch the command line text on the punch

LDRLEN	equ	60	;6" leader and trailer

;**************
; CP/M Equates
;**************
;-------------------------------------------
;BDOS Entry Points and low-memory locations
;-------------------------------------------
WBOOT	equ	0000H		;JUMP TO BIOS WARM BOOT
WBOOTA	equ	WBOOT+1		;ADDRESS OF WARM BOOT
IOBYTE	equ	WBOOT+3
;CDISK	equ	WBOOT+4		;LOGIN DRIVE
BDOS	equ	WBOOT+5		;BDOS Entry Point

FCB	equ	WBOOT+5CH	;CP/M file control blk
FCBDR	equ	FCB		;Drive Descriptor
FCBFN	equ	FCB+1		;File name (8 chrs)
FCBFT	equ	FCB+9		;File Type (3 chrs)
FCBEXT	equ	FCB+12		;File extent within FCB
FCBCLR	equ	24		;# of bytes to clear,
				;starting at FCBEXT

COMBUF	equ	WBOOT+80H	;disk & cmd line buffer
USAREA	equ	WBOOT+100H	;User program area

BLKBUF	equ	COMBUF	;We reuse 128-byte CP/M cmd/disk
			;..buffer to buffer XMODEM blocks
;-------------------------------------------
; BDOS Function Codes, passed in register C
;-------------------------------------------
;BRESET	equ	0	;System Reset
BCONIN	equ	1	;Read Console Chr
BCONOT	equ	2	;Type Chr on Console
;BRDRIN	equ	3	;Read Reader Chr
;BPUNOT	equ	4	;Write Punch Chr
BPRINT	equ	9	;Print $-terminated String
BRDCON	equ	10	;Get Line from Console
BCONST	equ	11	;Console Status (<>0 IF CHR)
;BDRST	equ	13	;Reset Disk
BSDISK	equ	14	;select disk
BOPEN	equ	15	;Disk File Open
BCLOSE	equ	16	;Close disk file, FCB at de
BSERCH	equ	17	;Search dir for file, FCB at de
BDELET	equ	19	;delete file, FCB at (de)
BREAD	equ	20	;Read from Disk, 0=OK, <>0=EOF
BWRITE	equ	21	;Write next record, 0=OK, <>0=ERR
BMAKE	equ	22	;Make new file, 0FFH=BAD
BCDISK	equ	25	;get current disk
BSTDMA	equ	26	;Set disk buffer to (de)

;--------------------------------------------------------------
;88-4PIO Device 0 Equates
; (The 88-4PIO as up to 4 such devices, in sequential
; I/O addresses, four addresses each.)
;--------------------------------------------------------------
; 88-4PIO Device 0 Registers (Altair-standard addresses)	

P4CA0	equ	20H		;port 0 section A ctrl/status
P4DA0	equ	21H		;port 0 section A data
P4CB0	equ	22H		;port 0 section B ctrl/status
P4DB0	equ	23H		;port 0 section B data

; Control Register Initialization Value

P4INIT	equ	2Ch	
	;bit 0 low disables interrupts on C1
	;bit 1 low makes C1 an active-low input
	;bit 2 high deselects the DDR register
	;bits 5:3 = 101b causes a low-going pulse on C2A when
	;                the CPU INputs from Port A
	;                and causes a low-going pulse on C2B
	;                when the CPU OUTputs to Port B
	;bits 6 & 7 don't care 

; Status Register value

P4RDY	equ	10000000B	;Data/port ready

;******************
; ASCII Characters
;******************
LF	equ	0AH		;Linefeed
CR	equ	0DH		;Carriage return

;****************************
; Beginning of Code 
; Note: we use CP/M's stack.
;****************************
	ORG	USAREA		;normal place for CP/M programs

;*************************************************************
; Initialization
; Set up 4PIO device 0 as follows:
;   Port A:
;     input port
;     interrupts disabled
;     C1A signal is an inverting "data ready" input pin
;     C2A is an active-low read strobe signal
;   Port B:
;     output port
;     interrupts disabled
;     C1B signal is an inverting "port ready" input pin
;     C2B signal is an active-low write strobe signal
;*************************************************************
; Make 4PIO Port A an input port and Port B an output port

INIT4P:	xra	a
	out	P4CA0		;access Port A DDR
	out	P4DA0		;set Port A as input

	out	P4CB0		;access Port B DDR
	cma			;0FFh
	out	P4DB0		;set Port B as output

; Set up handshaking modes for the two ports

	mvi	a,P4INIT
	out	P4CA0
	out	P4CB0

; Brief help screen

	lxi	d,HLPMSG
	mvi	c,BPRINT
	call	BDOS

;-------------------------------------
; Main Loop
; 'C' sets continuous-punch mode
; 'S' sets single-punch mode
; 'Q' quits to CP/M
; '0' punches nulls continuously
; '1'-'8' punch one bit continuously
; anything else stops punching
;-------------------------------------

SINGLE:	lxi	d,SMODE
	mvi	c,BPRINT
	call	BDOS
	
	mvi	d,0		;single-punch mode

; get console character

IDLE:	push	d
	mvi	c,BCONIN
	call	BDOS
	pop	d
	cpi	'Q'		;quit?
	rz			;y: quit to CP/M

	cpi	'C'
	jnz	ID1

	lxi	d,CMODE
	mvi	c,BPRINT
	call	BDOS

	mvi	d,1		;continuous-punch mode
	jmp	IDLE

ID1:	cpi	'S'
	jz	SINGLE
	
	sui	'0'
	cpi	9
	jnc	IDLE		;ignore spurious chrs

; compute desired punch

	inr	a		;will go once too many
	mov	b,a
	xra	a
	stc

BINARY:	ral
	dcr	b
	jnz	BINARY

	rar		;went once too many
	mov	e,a	;e = chr to punch

; Punch specified bit. If d<> then punch continuously
; until the user types something.

PLOOP:	call	PUNBYT		;punch e

	push	d
	mvi	c,BCONST	;test for console chr
	call	BDOS
	pop	d

	ora	a		;console chr?
	jnz	IDLE		;y: get new character

	mov	a,d
	ora	a		;single-punch mode?
	jz	IDLE		;y: go get another chr

	jmp	PLOOP		;n: keep punching

;********************************************************
; Subroutine to punch one byte via 4PIO device 0, Port B
;
; Custom for the modified Datatron papertape punch, or
; any other punch that requires synchronization prior to
; writing data.
;
; On Entry:
;    e = character to punch
; On Exit:
;    e = punched chr
;********************************************************
PUNBYT:

; synchronize with the leading edge of ready

	in	P4DB0		;clear the handshake bit

PWAIT: 	in	P4CB0		;wait for the handshake
	ani	P4RDY		;..at start of punch phase
	jz	PWAIT

; immediately punch the data

	mov	a,e		;recover punch byte
	out	P4DB0		;write it to data port

	ret

;*********
; Strings
;*********
HLPMSG: db CR,LF,'Datatron Punch Tester',CR,LF
	db '0   Punch nulls',CR,LF
	db '1-8 Punch single bits',CR,LF
	db 'S   Single-punch mode',CR,LF
	db 'C   Continuous mode',CR,LF
	db 'Q   Quit',CR,LF,'$'

SMODE:	db 'Single-punch mode',CR,LF,'$'
CMODE:	db 'Continuous mode',CR,LF,'$'

	end

