{Test program for Intel-82586-based APM local bus 10MHz Ethernet board} %externalintegerfnspec testsymbol %begin !option "-low-nocheck-nodiag-nons-nowarn" %option "-low-nons" ! ** IMPORTANT ** BYTE SEX ** ! The interface is wired for BYTE-FIDELITY, i.e. values which appear in ! consecutive byte locations as viewed by the 586 do so as viewed by the ! CPU as well. Since 82586 and 68010 have different byte sex this implies ! that values which are treated as 16-bit words have to have their bytes ! transposed in software, likewise for 32-bit words (which, incidentally, ! are invariably 24-bit addresses, in which only 17 bits are relevant). ! Memory layout ! The board contains 128 kbytes of dual ported memory, which appears at ! 040000:05FFFF in the CPU address space. Address consistency between 586 ! and CPU is achieved by ignoring the 586's seven high-order address bits. ! For example, the "System Configuration Pointer" record, which the 586 ! assumes is at FFFFF6, is actually at 05FFF6. The CA (Channel Attention) ! signal to the 586 is generated as a side effect of the CPU reading from ! any of the 16 highest-addressed bytes of the shared memory. ! NOTE: BASE is the middle of the memory, because of the 64k segmentation. ! All descriptors are kept in the upper half, data buffers are in the lower ! half and spill over into the upper. %routine phex1(%integer x) x = x&15; x = x+7 %if x>9; printsymbol(x+'0') %end %routine phex2(%integer x) phex1(x>>4); phex1(x) %end %routine phex4(%integer x) phex2(x>>8); phex2(x) %end %routine phex6(%integer x) phex4(x>>8); phex2(x) %end %routine phex(%integer x) phex4(x>>16); phex4(x) %end %ownbytearray my address (1:6) = 'F','R','E','D','-',16_14 %ownbytearray yr address (1:6) = 'F','R','E','D','-',16_14 ! Configuration constants %constinteger buffersize=1514, rxbuffers=64, txbuffers=20 ! Descriptors %constinteger none=16_ffff %recordformat scp fm {System Configuration Pointer} - (%byte sysbus, {Data bus width: 1 for 8-bit bus, 0 for 16-bit bus} ca, {Reading this generates Channel Attention} %integer *, iscp ad {address of ISCP (see below)} ) %recordformat iscp fm {Intermediate System Control Pointer} - (%byte busy, *, {cleared by 586 after reading SCB ad} %half scb offset, {Address of %integer scb base {SCB (see below)} ) %recordformat scb fm {System Control Block} - (%half status, command, cbl offset, rfa offset, crc errs, aln errs, rsc errs, ovr errs) ! Buffers %recordformat rxbuffer fm (%bytearray b(0:buffersize-1)) %recordformat txbuffer fm (%bytearray b(0:buffersize-1)) ! Buffer descriptors ! (the NEXT INDEX fields are for internal consistency checking purposes) %recordformat rxbd fm (%half count, next offset, %integer buffer ad, %half size, next index) %recordformat txbd fm (%half count, next offset, %integer buffer ad, %half next index) ! Receive Frame and Command descriptors ! (The LINK INDEX fields are for checking. ! The MCA setup command can take no more than 2 MC addresses ! without increasing the size of the descriptor; thus either ! all descriptors would need to be bigger (wasting space) or ! a separate special descriptor would need to be reserved for ! this function; depends on how many addresses are needed ! could be up to 64 if setting all filter bits.) %recordformat rfd fm - (%half status, command, link offset, desc offset, %bytearray dest, source(1:6), %half type, link index) %recordformat cmd fm - (%half status, command, link offset, ({Transmit} %half desc offset, %bytearray dest(1:6), %half type %or- {IA Setup} %bytearray ia(1:6) %or- {Configure} %byte config count, %bytearray config data(1:11) %or- {MCA Setup} %half mca byte count, %bytearray mca(1:12) %or- {TDR} %half time %or- {Dump} %half buffer offset), %half link index) %bytearrayname dumpbuf(0:169) %record(cmd fm)%name com @16_1070 {i.e. level 4} %integer interrupt handler %constinteger base=16_50000 {in middle of memory space} @(base-64*1024) %integerarray mem(0:32767) @(base-64*1024) - %record (rxbuffer fm) %array rx buffer (0:rxbuffers-1), %record (txbuffer fm) %array tx buffer (0:txbuffers-1), %record (rxbd fm) %array rxbd (0:rxbuffers-1), %record (txbd fm) %array txbd (0:txbuffers-1), %record (rfd fm) %array rfd (0:rxbuffers-1), %record (cmd fm) %array cmd (0:txbuffers-1), %integer old interrupt handler,nextr,nextc, %integer intcount,cxcount,frcount,cnrcount,rnrcount, %half intstatus, dummy {dummy MUST come last} @(base+16_FFF6) %record (scp fm) scp @(base+16_FFEE) %record (iscp fm) iscp @(base+16_FFDE) %record (scb fm) scb {Status/Command constants for SCB ** pre-swapped **} %constinteger - status mask = 16_00F0, cx = 16_0080, fr = 16_0040, cnr = 16_0020, rnr = 16_0010, cus mask = 16_0007, cus idle = 16_0000, cus suspended = 16_0001, cus ready = 16_0002, rus mask = 16_7000, rus idle = 16_0000, rus suspended = 16_1000, rus no resources = 16_2000, rus ready = 16_4000, cuc start = 16_0001, cuc resume = 16_0002, cuc suspend = 16_0003, cuc abort = 16_0004, ruc start = 16_1000, ruc resume = 16_2000, ruc suspend = 16_3000, ruc abort = 16_4000, reset = 16_8000 {Command/descriptor status bits ** pre-swapped **} %constinteger - done = 16_80, busy = 16_40, ok = 16_20, aborted = 16_10, el = 16_80, eof = 16_80, f bit = 16_40, s bit = 16_40, i bit = 16_20 {Command codes ** pre-swapped **} %constinteger - command nop = 16_0000, command ia setup = 16_0100, command configure = 16_0200, command multicast = 16_0300, command transmit = 16_0400, command tdr = 16_0500, command dump = 16_0600, command diagnose = 16_0700 %integerfn swap2(%integer a) ! Byte-sex-change a 2-byte word: AB <-> BA *rol.w #8,d0; *and.l #16_ffff,d0 %end %integerfn swap4(%integer a) ! Byte-sex-change a 4-byte word: ABCD <-> DCBA *rol.w #8,d0; *swap d0; *rol.w #8,d0 %end %integerfn offset(%name x) %result = swap2(addr(x)-base) %end %record(*)%map item at offset(%integer x) %result == nil %if x=none %result == record(swap2(x)+base) %end %routine channel attention *move.b scp_ca,d0 %end %routine ord(%integer i) write(i,0); i = 0 %if 11<=rem(i,100)<=13; i = rem(i,10) %if i=1 %then printstring("st") %else- %if i=2 %then printstring("nd") %else- %if i=3 %then printstring("rd") %else printstring("th") %end %routine receive frame %record(rfd fm)%name fdesc %record(rxbd fm)%name bdesc %record(rxbuffer fm)%name buffer==nil %integer i %owninteger active=0,count=1 %if active=0 %start active = 1; scb_command = scb_command ! ruc start; channel attention %return %finish fdesc == rfd(nextr) another: i = fdesc_status ord(count); printstring(" received frame ") phex4(offset(fdesc)); space; phex4(fdesc_linkoffset); space phex4(fdesc_descoffset); space bdesc == item at offset(fdesc_desc offset) buffer == record(swap4(bdesc_buffer ad)) %unless bdesc==nil phex4(bdesc_nextoffset) %and space %unless bdesc==nil printstring("s="); phex4(swap2(i)); printsymbol(':') printstring(" DUN") %if i&done#0 printstring(" BSY") %if i&busy#0 printstring(" OK") %if i&ok#0 printstring(" ABO") %if i&aborted#0 printstring(" CRC") %if i&8#0 printstring(" MAL") %if i&4#0 printstring(" NRE") %if i&2#0 printstring(" OVR") %if i&1#0 printstring(" RNT") %if i&16_8000#0 printstring(" NFL") %if i&16_4000#0 newline phex2(fdesc_dest(i)) %for i = 1,1,6; space phex2(fdesc_source(i)) %for i = 1,1,6; space phex4(fdesc_type) %if bdesc==nil %then printstring(" No data buffer used") %elsestart x: space; phex4(swap2(bdesc_count)) space %and phex2(buffer_b(i)) %for i = 0,1,14 %if bdesc_count&el=0 %start bdesc == item at offset(bdesc_next offset) buffer == record(swap4(bdesc_buffer ad)) newline; spaces(30); ->x %finish %finish newline %returnunless fdesc_status&done#0 count = count+1 fdesc_status = 0 nextr = rxbuffers %if nextr=0; nextr = nextr-1 fdesc == rfd(nextr); ->another %if fdesc_status&done#0 %end %routine check interrupts %owninteger crc=0,aln=0,rsc=0,ovr=0,errors=0 %owninteger ic=0,status=0 %returnif ic=intcount %and status=intstatus ic = intcount; status = intstatus ord(ic); printstring(" interrupt "); phex4(swap2(status)) printstring(" CX") %if status&cx#0 printstring(" FR") %if status&fr#0 printstring(" CNR") %if status&cnr#0 printstring(" RNR") %if status&rnr#0 printstring(", CU "); d0 = status&cusmask %if d0=cusidle %then printstring("IDL") %else- %if d0=cussuspended %then printstring("SUS") %else- %if d0=cusready %then printstring("BSY") %else- printstring("???") printstring(", RU "); d0 = status&rusmask %if d0=rusidle %then printstring("IDL") %else- %if d0=russuspended %then printstring("SUS") %else- %if d0=rusnoresources %then printstring("NRE") %else- %if d0=rusready %then printstring("RDY") %else- printstring("???") crc = swap2(scb_crcerrs) aln = swap2(scb_alnerrs) rsc = swap2(scb_rscerrs) ovr = swap2(scb_ovrerrs) %unless crc+aln+rsc+ovr=errors %start errors = crc+aln+rsc+ovr printstring(", CRC ALN RSC OVR: ") phex4(crc); space; phex4(aln); space; phex4(rsc); space; phex4(ovr) %finish newline receive frame %if rfd(nextr)_status&done#0 %end %owninteger seq=1480 %routine transmit frame %record(txbd fm)%name bdesc %record(txbuffer fm)%name buffer %owninteger count=1 %integer prev,status,i seq = seq+1 com == cmd(nextc) com_status = 0; com_command = command transmit ! sbit com_dest = yr address com_type = 16_1234+seq bdesc == txbd(nextc) com_desc offset = offset(bdesc) buffer == txbuffer(nextc) bdesc_count = eof+swap2(|2-seq|) buffer_b(i) = ((i+1)*17+seq)&255 %for i = 0,1,63 scb_command = cuc resume channel attention %cycle %cycle status = com_status; i = testsymbol %exitif status&done#0 %or i>=0 %repeat ord(count); printstring(" transmission ") phex4(swap2(status)); printsymbol(':') printstring(" DONE") %if status&done#0 printstring(" BSY") %if status&busy#0 printstring(" OK") %if status&ok#0 printstring(" ABO") %if status&aborted#0 printstring(" NCR,") %if status&16_4#0 printstring(" NCT,") %if status&16_2#0 printstring(" URN,") %if status&16_1#0 printstring(" DEF,") %if status&16_8000#0 printstring(" HBT,") %if status&16_4000#0 printstring(" TMC,") %if status&16_2000#0 printstring(" COL="); write(status>>8&15,0); newline %repeatuntil status&done#0 %or i='.' %returnif status&done=0 count = count+1 nextc = txbuffers %if nextc=0; nextc = nextc-1 %end %routine intercept interrupts %label this one interrupt handler = addr(this one) %return thisone: %option "-nocheck" *temp 0 *move.l d0,-(sp) *move.w scb_status,d0 *and.w #statusmask,d0 %if d0#0 %start *move.w scb_status,intstatus *or.w d0,scb_command cxcount = cxcount+1 %if d0&cx#0 frcount = frcount+1 %if d0&fr#0 cnrcount = cnrcount+1 %if d0&cnr#0 rnrcount = rnrcount+1 %if d0&rnr#0 intcount = intcount+1 *move.b scp_ca,d0 %finish *move.l (sp),d0 *move.l oldinterrupthandler,(sp) *rts end: %end %routine initialise %owninteger zero=0 {prevent CLR} %integer prev,i i = addr(scp)-addr(dummy) write(i,0); printstring(" spare bytes"); newline %stopif i<0 mem(i) = d7 %for i = 0,1,32767 i = addr(rxbd(0))-base printstring("Minimum descriptor offset: "); write(i,0); newline %stopif i<0 cxcount = 0; frcount = 0; cnrcount = 0; rnrcount = 0 intcount = 0; old interrupt handler = interrupt handler intercept interrupts prev = rxbuffers-1 %for i = 0,1,rxbuffers-1 %cycle rxbd(i) = 0 rxbd(i)_next index = prev rxbd(i)_next offset = offset(rxbd(prev)) rxbd(i)_buffer ad = swap4(addr(rxbuffer(i))) rxbd(i)_size = swap2(buffersize) rfd(i) = 0 rfd(i)_link index = prev rfd(i)_link offset = offset(rfd(prev)) rfd(i)_desc offset = none prev = i %repeat !!rxbd(0)_size = rxbd(0)_size!el !!rfd(0)_command = el rfd(prev)_desc offset = offset(rxbd(prev)) nextr = prev prev = txbuffers-1 %for i = 0,1,txbuffers-1 %cycle txbd(i) = 0 txbd(i)_count = eof txbd(i)_next index = prev txbd(i)_next offset = offset(txbd(prev)) txbd(i)_buffer ad = swap4(addr(txbuffer(i))) cmd(i) = 0 cmd(i)_command = command transmit ! sbit cmd(i)_link index = prev cmd(i)_link offset = offset(cmd(prev)) prev = i %repeat nextc = prev scb = 0 scb_cbl offset = offset(cmd(nextc)) scb_rfa offset = offset(rfd(nextr)) scb_command = 0 scb_command = cuc start iscp_scb base = swap4(base) iscp_scb offset = offset(scb) iscp_busy = 1 scp_iscp ad = swap4(addr(iscp)) scp_sysbus = zero com == cmd(nextc) com_command = command ia setup ! sbit com_ia = my address nextc = com_link index printstring("initialising"); newline channel attention %cycle; %repeatuntil iscp_busy#1 %or testsymbol>=0 printstring("busy="); phex2(iscp_busy); newline %end %integer i initialise %cycle i = testsymbol %if i<0 %start; check interrupts %elseif i='.'; scb_command = reset; channel attention; %exit %elseif i='r'; receiveframe %elseif i='t'; transmitframe %elseif i='a'; scb_command = cuc abort ! ruc abort; channel attention %elseif i='s'; scb_command = cuc start ! ruc start; channel attention %elseif i!32='n' %or i!32='x' %or i!32='c' com == cmd(nextc); nextc = com_link index com_command = command configure ! sbit com_config count = 12 com_config data(1) = 16_08 com_config data(2) = 16_80 com_config data(3) = 16_26 %if i!32='n' %start com_config data(3) = com_config data(3)+16_40 %elseif i!32='x' com_config data(3) = com_config data(3)+16_80 seq = -2 %else seq = 64 %finish com_config data(4) = 16_08 com_config data(5) = 16_60 com_config data(7) = 16_FA i = 0 %if i>='a'; i = 1 %unless i=0 com_config data(8) = i com_config data(10)= 16_40 scb_command = cuc resume channel attention %elseif i='d' com == cmd(nextc) com_command = command dump ! sbit com_buffer offset = offset(txbuffer(nextc)) dumpbuf == array(addr(item at offset(com_buffer offset))) scb_command = cuc resume nextc = com_link index channel attention %elseif i='e' %for i = 0,1,169 %cycle space %if i&1=0; phex2(dumpbuf(i)) newline %if i&15=15 %repeat; newline %elseif i='y' com == cmd(nextc); nextc = com_link index com_command = command diagnose ! sbit ! ibit scb_command = cuc resume channel attention %cycle %exitif testsymbol>=0 %or com_status&done#0 %repeat phex4(swap2(com_status)); newline %elseif i='z' com == cmd(nextc); nextc = com_link index com_command = command tdr ! sbit ! ibit scb_command = cuc resume channel attention %cycle %exitif testsymbol>=0 %or com_status&done#0 %repeat phex4(swap2(com_status)); space phex4(swap2(com_time)); newline %else; printsymbol(7); %finish %repeat interrupt handler = oldinterrupt handler %end