/********************************* MFP.Z80 ************************************ /ETHERNET DIAGNOSTIC MONITOR STATION FIRMWARE PROGRAM. /W.I.WALKER MSC PROJECT 1984 /Chopped-down version - JHB 3/85 /INITIALISATION /Device addresses dmaer=0 / er channel addr reg dmaet=2 / et -------"-------- dmalr=4 /DMA registers lr -------"-------- dmalt=6 / lt -------"-------- dma=8 / setmode/status reg 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 /dma tc stop rcintbit=4 /receive control ready rdintbit=2 / " data " teintbit=1 /transmit empty /DMA enable bits erdmabit=1 /enable er channel etdmabit=2 / " et " lrdmabit=4 / " lr " ltdmabit=8 / " lt " tcbit=16_40 / " tc stop /ctrl chars str=1 /start recording stp=2 /stop recording tic=3 /timing signal stx=16_20 /start of data stream /Miscellaneous constants header=14 datamax=532 trailer=4 infobyte=4 maxpkt=header+datamax+trailer counter=maxpkt+1-1 ticsmax=10 buffsiz=16_2000 stksiz=16_200 /Variables area ram loc 16_1800 loc stksiz+. /locate stack stktop: var get,,lastget,,dbstart,,nextstrt,,nextblck,,addrsel,,recrd var tics,miss,tflag,ints /get: location of next byte to be sent to host /lastget: location following current bottom of buffer /dbstart: location at which next packet is to be buffered /nextstrt: used when calculating next dbstart /nextblock: location of next block to be created /addrsel: location of start of addr selection code /recrd: flag set to 1 if user requires recording /tics:counter incremented when a timing signal arrives /miss: flag set to 64 when block overwritten in buffer /tflag: flag set to 1 when a block for timing purposes must be built /ints: flag set to 1 when next packet is to be ignored dbufftop: loc buffsiz+. /locate buffer dbuffbot: loc maxpkt+infobyte+. /locate buffer overflow area ix /block format loc 0 var blcklen,,status,time,dest,,,,,,source,,,,,,type, /Initial entry area rom loc 16_1000 jp begin var maxblcksiz,,rcvmode,stat1,port1,stat2,port2 /user specified variables begin: di ld sp,#stktop /inactive loop inactive: in a,(ls) /wait for a ctrl char to arrive and 32 jr z,inactive in a,(lkc) xor str /if char = str then enable station jr nz,inactive /otherwise ignore /inform host that station is enabled call ltwait ld a,str out (lkc),a /initialise variables ld hl,#dbufftop+infobyte ld dbstart,hl ld nextstrt,hl ld hl,#dbufftop ld get,hl ld ix,get /set up address of first block ld nextblck,hl ld lastget,hl xor a ld tics,a /set tics to 0 ld tflag,a /clear tflag ld miss,a / " miss inc a ld ints,a /set ints to 1 ld recrd,a /set recrd to 1 /initialise dma controller exx; ex af,af /use a different register set for /interrupt processing ld hl,dbstart ld c,dmaer /reg c will always contain dmaer /so that it need never be loaded again out (c),hl /load initial start addr inc c ld de,16_4000+counter /load counter out (c),de dec c exx; ex af,af /swop register set /Initialise hardware ld a,16_80; out (er),a /reset receiver (sets overrun),accept all packets in a,(er) /(clears overrun) in a,(tc) /reset DMA interrupt ld a,erdmabit+tcbit /enable er channel and tc stop of dma cntrllr out (dma),a / /Set up interrupts ld a,tcintbit+rcintbit /enable tc and rc interrupts out (int),a / ld a,inttab>>8 /load high byte of interrupt table address ld i,a /into i reg im2 /set interrupt mode to 2 ei /MAIN PROGRAM LOOP idle: /loop while no blocks to be passed on to 68000. ld a,recrd /if stp has been received while sending or a /last block then jmp to stprec jp z,stprec / ld hl,nextblck / ld de,get /if nextblck and get not equal then there or a; sbc hl,de /is a block to be passed on so leave theloop jr z,idle / call ltwait /send stx to host to indicate start of block ld a,stx / out (lkc),a / ld hl,get call ltwait /pass 1st byte of block to link data ld a,(hl); inc hl /register out (lkd),a / ld e,a /load low byte of blcklen field into e call ltwait ld a,(hl); inc hl /pass 2nd byte of block to link data out (lkd),a /register ld d,a /load high byte of blcklen field into d dec de /de holds count of number of bytes in this dec de /block tobe passed on to 68000. /dec the 1st 2 bytes, /remainderdecremented after ldrwait send: call ltwait ld a,(hl); inc hl /pass next byte of block to link data out (lkd),a /register dec de /when de=0 then last byte of the block ld a,e; or 0 /has been passed on to the 68000 jr nz,send / ld a,d; or 0 / jr nz,send / ld get,hl /if get is not at end of buffer then return ld de,lastget /to idle or a; sbc hl,de / jp nz,idle / ld hl,#dbufftop /otherwise set get to top of the buffer ld get,hl /and return to idle jp idle / stprec: di /disable station call ltwait ld a,stp /inform host that station disabled out (lkc),a jp inactive /wait for next ctrl char to be received /INTERRUPT ROUTINES /receiver done interrupt interd: exx; ex af,af /swop register sets so that main program registers /are not corrupted xor a; out (dma),a /disable dma in a,(er) /clear interrupt ld a,ints /if ints=0 then packet received is valid so and 1 /jump to valid ld b,a /clear b if jumping to valid jp z,valid / xor a; ld ints,a /next packet should be ok so clear ints addrfail: ld a,tflag /if tflag is set then an empty timing xor 0 /block should be created to keep timing accurate jp nz,tblck /if packet invalid or addresses fail selection and ld hl,dbstart /tflag not set then buffer next packet at same location call resetdma exx; ex af,af; ei; ret /return to main program valid: in a,(es) /read ether status and only keep and 12 /crce and col bits or b /b will set dma o/r bit if such an event has occurred ld b,a /this byte will become the block status field ld a,stat1 ld e,a ld a,source /if source = specified addr then pass xor e jp z,addrpass ld a,dest /if dest = -----------"------------ xor e jp z,addrpass ld a,dest /if dest = broadcast addr then pass xor 0 jp z,addrpass jp addrfail /otherwise fail addrpass: ld a,miss /if miss=0 then do not set miss bit xor 0; jr z,noloss / ld a,time /but if miss is set then a block is being ld d,a /overwritten. the timing field of the overwritten ld a,tics /block must be added to the current value add a,d /of tics. ld time,a / ld a,status /the fifo o/f bit must be preserved and 1 / or b / or 64 /the miss bit in the status field must be set ld status,a / ld b,a / jp stsdone noloss: ld a,tics /load time field and status field ld time,a / ld a,b / ld status,a / stsdone: xor a /clear tflag and miss ld tflag,a / ld miss,a / ld tics,a /clear tics ld a,b /if dmaerr or empty bits set then blcklen and 144 /has already been calculated and dma start proposed jr nz,chk1strt /so jump to check start code in hl,(c) /now calculate where the next packet to be received ld de,infobyte-2 /is to be stored:add infobyte sub checksum or a; adc hl,de / ld nextstrt,hl / ld de,dbstart /calc length of block and set blcklen to it or a; sbc hl,de / ld blcklen,hl / ld de,maxblcksiz /check if block is longer than the max block length or a; sbc hl,de /if it is not then blcklen is ok so check nextstrt. jp n,chk1strt / ld blcklen,de /otherwise reset blcklen to maxblcksiz ld hl,dbstart /and reset nextstrt or a; adc hl,de / ld nextstrt,hl / chk1strt: ld de,nextstrt /first check for bottom of the buffer ld hl,#dbuffbot+infobyte /if nextstrt < dbuffbot then ok or a; sbc hl,de / jp p,chk2strt / ld hl,nextstrt /else set a marker (lastget) so that main ld de,infobyte /program loop knows when it must start or a; sbc hl,de /transfering bytes from the top of the buffer ld lastget,hl / ld hl,#dbufftop+infobyte /and set nextstrt to top of the buffer ld nextstrt,hl / chk2strt: ld de,nextstrt /now test whether a packet loaded from the next ld hl,get /start addr could possibly overwrite any or a; sbc hl,de /data not yet passed on to the 68000 jp n,rset1dma /if get < next start addr then not possible to overwrite ld de,maxpkt+infobyte /if get >= next start addr then or a; sbc hl,de /if distance between next start and get is jp p,rset1dma / > max packet length then not possible to overwrite ld a,64 /if the distance is < max packetsize then do not ld miss,a /change dbstart (thus overwritting the ld hl,dbstart /last packet received) and set miss flag jp rset2dma rset1dma: ld hl, nextstrt /reset dbstart and preserve it in hl ld dbstart,hl push hl ld de,infobyte or a; sbc hl,de ld nextblck,hl /set nextblck and ix reg to start of next block push hl / pop ix / pop hl / rset2dma: call resetdma / exx; ex af,af; ei; ret /return to main program /link receiver control ready interrupt intrcr: exx; ex af,af in a,(lkc) /read char received cp tic /jmp to piece of code that handles jr z,cctic /response to the char cp stp / jr z,ccstp / /if char not recognised then ignore it exx; ex af,af; ei; ret /return from interrupt /timing char received cctic: ld a,tics /increment tics inc a / ld tics,a / xor ticsmax /if tics=maxtics then a block must be built jr nz,rtn /otherwise return from interrupt in a,(es) /if ra bit in ether status reg is set (receiver and 2 /is active) then jump to setflag jp nz,setflg / xor a; out (dma),a /freeze the dma in de,(c) /if dbstart (in hl) and contents of dma addr reg are or a; sbc hl,de /different then a packet has just been received ld hl,dbstart / jp nz,retqck /but not yet processed so jump to retqck tblck: /create a small block for timing purposes only ld de,infobyte /load blcklen with infobyte as these will be the ld blcklen,de /only bytes in the block or a; adc hl,de /(hl=dbstart,de=infobyte).propose next dma start addr ld nextstrt,hl /so that timing block has only infobytes ld b,160 /set empty and timing bits for the status field jp addrpass /set status and time fields retqck: ld a,erdmabit+tcbit /reenable dma out (dma),a / setflg: ld a,1 /set tflag so that next packet to be processed ld tflag,a /will have timing bit in the status field set rtn: exx; ex af,af; ei; ret /recording to be stopped ccstp: xor a /set recrd to 0 ld recrd,a / exx; ex af,af; ei; ret /dma completion interrupt intdtc: exx; ex af,af /disable dma not required as this intrpt does it anyway in a,(tc) /clear interrupt ld a,ints /if ints=1 then packet is not valid so jump and 1 /to addrfail jp nz,addrfail / ld a,1 /set ints to 1 ld ints,a /so that next packet(end of this one) will be ignored ld b,2 /b will be used to set dma o/r bit in status field jp valid /now that b is set process as normal packet /fifo overflow interrupt intovf: exx; ex af,af xor a; out (dma),a /disable dma in a,(er) /clear interrupt ld a,ints /if ints=1 then packet is not valid so jump to addrfail and 1 / jp nz,addrfail / /create a small block to indicate packets lost ld a,1 /set ints to 1 ld ints,a /so that next packet received will be ignored ld de,infobyte /load blcklen with infobyte as they will be the only ld blcklen,de /bytes in this block or a; adc hl,de /(hl=dbstart) propose next dma start addr so that this ld nextstrt,hl /block only contains infobytes ld b,129 /b will be used to set fifo o/f and empty bits /in status field jp addrpass /set status field bits and check next dma start addr /Unsolicited interrupts intspu: halt /SUBROUTINES ltwait: in a,(ls) /if tbe bit in link status register rra /set then another character can be jr nc,ltwait /sent so return from routine ret resetdma: out (c),hl /load initial start addr inc c ld de,16_4000+counter out (c),de /load counter ld a,erdmabit+tcbit out (dma),a /enable er channel and tc stop dec c ret /(256-byte-aligned) interrupt table block 256-.&255 inttab: w intovf /ovf w interd /erd w intspu /etd w intdtc /dtc w intrcr /rcr w intspu /rdr w intspu /tbe w intspu /spu end