/New Checking Program for CSD142 Ether Boards
/RWT Feb 1986

/This test works WITHOUT interrupts.
/It begins with a host link echo test, in which
/certain characters are intercepted and treated as
/instructions to executed a number of specific tests:

/ 'M' Memory Test
/ 'T' Ether transmit test
/ 'R' Ether Receive test

/The echo and memory tests do not assume the presence
/of working RAM, and hence hold their entire context
/in registers.  To achieve this, it has been necessary
/to exploit an unpublished feature of the Z80, namely
/that most instructions which access H or L will, if
/prefixed with the special instruction prefix 16_FD,
/which normally causes IY to be used instead of HL,
/will cause the appropriate half of IY to be used
/instead of H or L.

/Frig
withiy=16_fd

/Memory
/$if rom
base=0
low=16_1000
/$else
/base=16_1000
/low=16_2000
/$finish
size=low
delay=low+2
pointer=low+4
packet=low+8
high=16_4000

/Device addresses
dmaer=0
dmaet=2
dmalr=4
dmalt=6
dma=8
tc=16_10   /read-only (clears DMA TC interrupt)
int=16_10  /write-only interrupt enable (ltbe.lrdr.lrcr.dmatc)
lkc=16_20  /link control (read/write)
lkd=16_30  /link data
er=16_40   /read: data/control, write: filter/reset
ls=16_50   /(link status) read-only (rbf.rdr.rcr.0.0.0.0.tbe)
etd=16_50  /write-only: data into fifo
es=16_60   /read-only: (tcol.ta.tdone.rctrl.crce.rcol.ra.over)
et=16_60   /write-only: hold-off counter, reset

/Interrupt enable bits
tcintbit=8
rcintbit=4
rdintbit=2
teintbit=1

/DMA enable bits
erdmabit=1
etdmabit=2
lrdmabit=4
ltdmabit=8
tcbit=16_40

/NB: Interrupt vectors (for interest only)
/2 ltbe
/4 lrdr
/6 lrcr
/8 dmatc
/a etdone
/c erdone
/e overflow

/IO-package entry points
pdata=base+8
pctrl=base+16
rdata=base+16_18
rctrl=base+16_20
rsym=base+16_28

loc base+16_00; ld sp,high
           jp begin
loc base+16_08; jp xpdata
loc base+16_10; jp xpctrl
loc base+16_18; jp xrdata
loc base+16_20; jp xrctrl
loc base+16_28; jp xrsym
loc base+16_30; jp *+16_1000
loc base+16_38; jp *+16_1000
loc base+16_66; jp *+16_1000

/  I N I T I A L   E N T R Y

begin: ld a,halt
   ld (16_1030),a
   ld (16_1038),a
   ld (16_1066),a
   di
   jp rwait

/  E C H O   T E S T

twait:
   in a,ls       /Wait for LTBE
   rra
   jp nc,twait
rwait:
   in a,ls       /Wait for LRBF
   add a,a
   jp nc,rwait
   jp n,data        /LRDR=0: ->
   in a,lkc
   out lkc,a
   jp twait
data:
   in a,lkd
   cp 'T'
   jp z,transtest
   cp 'R'
   jp z,rectest
   cp 'M'
   jp z,memtest
   out lkd,a
   jp twait

/  M E M O R Y   T E S T

/   B Old pattern
/   C New pattern
/   D Long-term error count
/   E Short-term e c
/ IYH Picks                *NAUGHTY*
/ IYL Drops                *NAUGHTY*
/  IX Pointer
/  HL Counter

message:
  text "Memory test"
  0
memtest:
  ld hl,message
hello:
  in a,ls
  rra; jr nc,hello
  ld a,(hl); inc hl
  or a; jr z,startm
  out (lkd),a
  jr hello
startm:
  ld ix,low        /Clear store
  ld hl,high-low
clearloop:
  ld (ix),0
  inc ix; dec hl
  ld a,h; or l
  jp nz,clearloop
  ld c,0           /Set Oldpat=0 (later)
  ld de,0          /Clear error counts
  ld iy,0          /Clear pick/drop
mainloop:
  ld b,c
  ld a,b; rlca     /Work out new pattern
  xor 1; ld c,a
  ld ix,low
  ld hl,high-low
testloop:
  ld a,b
  xor (ix)       /Check old pattern
  jp z,longok    /OK ->
  and b
  withiy; or l   /Record picks
  withiy; ld l,a
  ld a,b; cpl; ld b,a
  cpl; xor (ix)  /Re-read (!)
  and b
  withiy; or h   /Record drops
  withiy; ld h,a
  ld a,b; cpl; ld b,a
  inc d          /Bump error count
  jp nz,longok   /But not past 255
  ld d,255
longok:
  ld a,c
  ld (ix),a      /Write and
  xor (ix)       /check new pattern
  jp z,shortok   /OK ->
  and c
  withiy; or l
  withiy; ld l,a
  ld a,c; cpl; ld c,a
  cpl; xor (ix)
  and c
  withiy; or h
  withiy; ld h,a
  ld a,c; cpl; ld c,a
  inc e
  jp nz,longok
  ld e,255
shortok:
  inc ix          /Bump pointer
  dec hl          /Count down
  ld a,h; or l    /Done?
  jp nz,testloop  /No ->
wtre: in a,ls /write results to link
  rra; jr nc,wtre
  ld a,b         /First Oldpat
  out lkc,a
wtb: in a,ls
  rra; jr nc,wtb
  ld a,c         /Then Newpat
  out lkd,a
wtc: in a,ls
  rra; jr nc,wtc
  ld a,d         /Then Long errcount
  out lkd,a
wtd: in a,ls
  rra; jr nc,wtd
  ld a,e         /Then Short errcount
  out lkd,a
wte: in a,ls
  rra; jr nc,wte
  withiy; ld a,h /Then Picks
  out lkd,a
wth: in a,ls
  rra; jr nc,wth
  withiy; ld a,l /Then Drops
  out lkd,a
wtl: in a,ls
  rra; jr nc,wtl
  jp mainloop

/ T R A N S M I T   T E S T

/Any data characters received are appended to the packet.
/On receipt of a control character, its low-order 2 bits
/are inspected, and the following action is taken:
/0: Reset data character packet buffer pointer
/1: Set packet size (next 2 data characters)
/2: Send one packet
/3: Loop packet transmission (next char specifies delay)

transtest:
  ld hl,16
  ld (size),hl
  ld hl,16_6666
  ld (packet),hl
  ld hl,16_9999
  ld (packet+12),hl
  ld hl,'I'<<8+'H'
  ld (packet+14),hl
  ld hl,0
  ld (delay),hl
  ld (packet+2),hl
  ld (packet+4),hl
  ld (packet+8),hl
  ld (packet+10),hl
txreset:
  ld hl,packet
  ld (pointer),hl
txidle:
  call rsym
  jr cy,txctrl
  ld hl,(pointer)
  ld (hl),a
  inc hl
  ld (pointer),hl
  jr txidle
txctrl:
  and 3
  jr z,txreset
  cp 1
  jr z,txsize
  cp 2
  jr nz,txloop
  call txone
  jr txidle
txsize:
  call rsym
  ld (size+1),a
  call rsym
  ld (size),a
txloop:
  call txone
  ld hl,(delay)
txdelay:
  dec hl
  ld a,h
  or l
  jr nz,txdelay
  jr txloop

txone:
  ld c,dmaet
  ld hl,packet
  out (c),hl
  inc c
  ld hl,(size)
  ld de,16_7fff
  add hl,de
  out (c),hl
  ld a,tcbit+etdmabit
  out (dma),a
txwait:
  in a,(es)
  ld b,a
  and 16_a0
  jr z,txwait
  xor a
  out (dma),a
  out (et),a
  ld c,dmaet
  in hl,(c)
  ld de,-packet
  add hl,de
  ld a,b
  call pctrl
  ld a,h
  call pdata
  ld a,l
  call pdata
  ret

/ R E C E I V E   T E S T

/On receipt of a control character, the
/station address filter is set to that value.
/On receipt of a data character '*', a receive loop
/is entered, in which all received packets are fully
/displayed.
/On receipt of a data character '*', a receive loop
/is entered in which all received packets are only
/partially displayed.
/On receipt of any other data character, one packet
/is received and displayed.

rectest:
  ld a,16_80        /Default: promiscuous mode
ssa:
  out (er),a        /set station address, freeze rx
  in a,(er)         /unfreeze rx, reset overflow
rxidle:
  call rsym
  jr cy,ssa         /control char ->
  cp '?'
  jr z,partloop
  cp '*'
  jr z,fullloop
  call fullone
  jr rxidle
fullloop: call fullone
  jr fullloop
partloop: call partone
  jr partloop

/Partial receipt displays:
/One control char denoting ether status,
/followed by a number of data characters:
/dma packet length (2 chars),
/first two and last two packet chars.
/Full receipt displays:
/Ctrl char: ether status, data chars:
/DMA length (2 chars),
/Entire packet.

partone: call getone
  ld a,d
  call pctrl
  ld a,h
  call pdata
  ld a,l
  call pdata
  ld a,(packet)
  call pdata
  ld a,(packet+1)
  call pdata
  ld de,packet-4
  add hl,de
  ld a,(hl)
  call pdata
  inc hl
  ld a,(hl)
  call pdata
  inc hl
  ld a,(hl)
  call pdata
  inc hl
  ld a,(hl)
  call pdata
  ret

fullone: call getone
  ld a,d
  call pctrl
  ld a,h
  call pdata
  ld a,l
  call pdata
  ld bc,hl
  ld hl,packet-1
showloop:
  ld a,b
  or c
  ret z
  dec bc
  inc hl
  ld a,(hl)
  call pdata
  jr showloop

/Get one packet.
/Return with D = ether status,
/ HL = packet length (as indicated by DMA)
getone:
  ld c,dmaer        /set up DMA channel
  ld hl,packet         /packet buffer start address
  out (c),hl
  inc c
  ld hl,16_47ff     /input mode, 2048 bytes
  out (c),hl
  ld a,tcbit+erdmabit
  out (dma),a       /enable dma
rxwait:
  in a,(es)
  ld d,a
  and 16_11         /wait for done or overflow
  jr z,rxwait
  xor a
  out (dma),a       /stop dma
  in a,(er)         /read ether control char
  ld e,a
  ld c,dmaer
  in hl,(c)         /read dma address
  ld bc,-packet
  add hl,bc
  ld a,h
  or l
  ret nz            /non-empty packet =>
  ld a,d
  cp 16_10
  ret nz            /error status =>
  jr getone         /try again ->

/ I / O   P A C K A G E

/Send one data character from A
xpdata: out lkd,a
  push af
xpwait: in a,ls
  rra; jp nc,xpwait
  pop af
  ret

/Send one control character from A
xpctrl: out lkc,a
  push af
  jp xpwait

/Read one data or control char into A
xrsym: in a,ls
  add a,a; jp nc,xrsym
  add a,a; ccf
  jp nc,gotd
  jp gotc

/Read one control character into A
xrc0: in a,lkd
xrctrl: in a,ls
  add a,a; jp nc,xrctrl
  jp n,xrc0          /Skip data ->
gotc: in a,lkc
  ret

/Read one data character into A
xrd0: in a,lkc
xrdata: in a,ls
  add a,a; jp nc,xrdata
  jp p,xrd0          /Skip control ->
gotd: in a,lkd
  ret

  end
