dptarget.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:41k
源码类别:

VxWorks

开发平台:

C/C++

  1. /*
  2. **  File:     dptarget.c
  3. **  Version:  1.0.1
  4. **
  5. **  Description: Target-side driver functions for NR5xx
  6. **
  7. **      Copyright (c) 1996 Applied Microsystems Corporation
  8. **                          All Rights Reserved
  9. **
  10. **  Modification History:
  11. **       10/04/96, MPH...Created from nrdrive.c
  12. **       01/20/97, MPH...Fixed nr_ReadBuf and nr_ProcessMsgs for PPC603
  13. **       02/04/97, MS....fixed numerous compiler warnings
  14. */
  15. #include "wdb/amc500/dpconfig.h"
  16. #include "wdb/amc500/dptarget.h"
  17. #include "wdb/amc500/dualport.h"
  18. /* Local definitions */
  19. #define DEBUG_ON False  /* Optional: Include nr_TestComm() if True */
  20. #ifndef NULL
  21. #define NULL  0
  22. #endif
  23. /* Private routines */
  24. STATIC void   nr_WriteInt     ( uInt16, uInt32, uInt16 );
  25. STATIC uInt16 nr_ReadInt      ( uInt16, uInt32 );
  26. STATIC void   nr_WriteBuf     ( uInt16, uChar*, uInt32, uInt16 );
  27. STATIC void   nr_ReadBuf      ( uInt16, uInt32, volatile uChar*, Int16 );
  28. STATIC Int16  nr_ProcessMsgs  ( uInt16 );
  29. STATIC Int16  nr_PutOOBMsg    ( uInt16, uInt16, char*, uInt16 );
  30. STATIC void   nr_Wait         ( DpChannel* );
  31. STATIC void   nr_WaitEnd      ( void );   
  32. /* Global data */
  33. STATIC DpChannel channels[DP_MAXCHANNELS];
  34. STATIC volatile  uChar RR_dummy; /* See dptarget.h for explanation */
  35. STATIC volatile  uChar dummy;  
  36. STATIC uChar     wait_ftn_buf[MAX_WAIT_FTN_SIZE]; /* For RAM-based wait ftn */
  37. STATIC Int16     emoffonwrite_set;
  38. /*
  39. **     Function:  nr_ReadByte
  40. **  Description:  Reads a byte from DP RAM
  41. **         Note:  With caching, we need to use a function
  42. **                Without caching, we can use a (faster) macro
  43. **      Warning:  Assumes 'cp' is valid
  44. **
  45. **  Parameters:
  46. **    cp          pointer-to-channel to read from
  47. **    addr        address for read
  48. **
  49. **  Returns:
  50. **     uChar from DP RAM
  51. */
  52. #if( nr_HasCache == True )
  53. uChar 
  54. nr_ReadByte(DpChannel *cp, uInt32 addr)
  55. {
  56.   register uChar ch;
  57.   nr_DataCacheOff();
  58.   ch = NR_READ_BYTE( (cp), (addr) );
  59.   nr_DataCacheOn();
  60.   return ch;
  61. }
  62. #else /* nr_HasCache == True */
  63. #define nr_ReadByte(cp,addr) NR_READ_BYTE( (cp), (addr) )
  64. #endif /* nr_HasCache == True */
  65. /*
  66. **     Function:  nr_WriteByte
  67. **  Description:  Writes a byte to DP RAM
  68. **         Note:  With caching, we need to use a function
  69. **                Without caching, we can use a (faster) macro
  70. **      Warning:  Assumes 'cp' is valid
  71. **
  72. **  Parameters:
  73. **    cp          pointer-to-channel to write to
  74. **    addr        address for write
  75. **
  76. **  Returns:
  77. **     note
  78. */
  79. #if( nr_HasCache == True )
  80. void
  81. nr_WriteByte(DpChannel *cp, uInt32 addr, uInt16 val)
  82. {
  83.   nr_DataCacheOff();
  84.   NR_WRITE_BYTE( (cp), (addr), (val) );
  85.   nr_DataCacheOn();
  86. }
  87. #else /* nr_HasCache == True */
  88. #define nr_WriteByte
  89. (cp, addr, val) { NR_WRITE_BYTE((cp), (uInt32)(addr), (uInt16)(val)); }
  90. #endif /* nr_HasCache == True */
  91. /*
  92. **  Macro: nr_InROM
  93. **  Description: Determines if an address is w/in NR emulation RAM
  94. **  Note: ROMSTART and ROMEND are defined in dpconfig.h
  95. **  Evaluates to TRUE if address is within NetROM overlay, otherwise FALSE
  96. */
  97. #define nr_InROM(adr) ((adr) >= (uInt32)ROMSTART && (adr) < (uInt32)ROMEND)
  98. /*
  99. **  Function: nr_ConfigDP
  100. **  Description: Configure dualport RAM communication structures
  101. **
  102. **  Parameters:
  103. **    base        First address of dualport RAM 
  104. **    width       Width of ROM(s) emulated: 1-8 bits 2-16 bits 4-32 bits
  105. **    index       Location of pod0 within podgroup
  106. **
  107. **  Returns:
  108. **   Err_BadLength   If MAX_WAIT_FTN_SIZE is too small to hold nr_Wait()
  109. **   Err_NoError     Otherwise
  110. */
  111. Int16
  112. nr_ConfigDP( uInt32 base, Int16 width, Int16 index )
  113. {
  114.     DpChannel *cp;
  115.     Int16 chan;
  116.     uInt32 tmp, pWait, wait_ftn_size; 
  117.     /* Calc size of nr_Wait for copy to RAM...will it fit? */
  118.     /* 'wait_ftn_size+3' because of 32bit align code, below */
  119.     wait_ftn_size = (uInt32)((uInt32)nr_WaitEnd - (uInt32)nr_Wait);
  120.     if( wait_ftn_size+3 > MAX_WAIT_FTN_SIZE )
  121.       return Err_BadLength;
  122.     if( wait_ftn_size < 10 )  /* Sanity check */
  123.       return Err_BadLength;
  124.     /* Copy nr_Wait routine to RAM */
  125.     pWait = (uInt32)wait_ftn_buf;
  126.     tmp = (uInt32) wait_ftn_buf & 0x03; /* force 32bit align */
  127.     if(tmp != 0)  pWait += (4 - tmp);
  128.     memcpy( (uChar*)pWait, (uChar*)nr_Wait, wait_ftn_size );
  129.     /* Load channel structs */
  130.     for( chan = 0; chan < DP_MAXCHANNELS; chan++ ) {
  131.       /* get a pointer to the channel */
  132.       cp = &channels[chan];
  133.       /* set the addresses for dualport ram */
  134.       cp->dpbase = base + chan * DP_CHAN_SIZE * width;
  135.       cp->dpbase_plus_index = cp->dpbase + index;  /* Time saver const */
  136.       cp->width = width;
  137.       cp->index = index;
  138.       /* rr_data_offset includes "index" to speed up RR_xxx macros */
  139.       /* For writes to Pods0-2, rr_data_offset will cause us to read */
  140.       /* from the next Pod.  For pod3, we'll read from pod0 area */
  141.       /* This is to avoid reading addresses that the hardware is */
  142.       /* latching for the RR protocol. */
  143.       if( 3 == chan ) {
  144. cp->rr_enable  = base + index + RR_ENABLE_ADR  * width;
  145. cp->rr_disable = base + index + RR_DISABLE_ADR * width;
  146.       }
  147.       else {
  148. cp->rr_enable  =  cp->dpbase 
  149.                        + index + RR_ENABLE_ADR  * width;
  150. cp->rr_disable =  cp->dpbase + DP_CHAN_SIZE * width
  151.                        + index + RR_DISABLE_ADR * width;
  152.       }
  153.       /* initialize the buffer system */
  154.       cp->txbuf.bufsize = 0;
  155.       cp->txbuf.index = 0;
  156.       cp->rxbuf.bufsize = 0;
  157.       cp->rxbuf.index = (-1);
  158.       /*      cp->numaccess = numaccesses; */
  159.       /* initialize the ack counter */
  160.       cp->rxackval = 0;
  161.       /* we can both read and write dualport */
  162.       cp->chanflags = CF_TXVALID | CF_RXVALID | CF_NOWAITIO;
  163.       /* start the receive area after the status/control area */
  164.       cp->rxbase = cp->rxlim = DP_MSGBASE;
  165.       cp->rx = (-1);
  166.       /* start the transmit area after the receive area */
  167.       cp->txbase = cp->tx = (DP_REC_MSGS + 1) * DPM_MSGSIZE;
  168.       cp->oobthresh = 0; /* xxx */
  169.       /* Points to RAM-based wait ftn; used w/ nr_SetMem() */
  170.       cp->wait_nr_done_ptr = (void (*)()) pWait;
  171.     } 
  172.     emoffonwrite_set = True;  /* Set emulate off on write */
  173.     /* This function will hang on the following line until the 
  174.     ** communication channel is up.  If you find that the code
  175.     ** is hanging here, either 1) NetROM is not configured correctly for
  176.     ** this debug channel; 2) config_dpram() was called with the wrong
  177.     ** parameters; or 3) the telnet session is not connecting to the 
  178.     ** NetROM debug port.
  179.     */
  180.     while( !nr_ChanReady(chan) ) {}
  181.     /* Request that NetROM synchronize comm buffers with the target */
  182.     nr_Resync(0);
  183.   return Err_NoError;
  184. }
  185. /*
  186. **  Function: nr_SetBlockIO
  187. **  Description:  This ftn affects nr_Getch(), nr_Putch() and nr_GetMsg()
  188. **                val == 0 --> non-blocking I/O
  189. **                val != 0 --> blocking I/O
  190. **
  191. **  Parameters:
  192. **    chan       channel to configure, 0-3
  193. **     val       0 for non-blocking, non-zero for blocking
  194. **
  195. **  Returns:
  196. **   Err_BadChan   if the chan is invalid (0,1,2,3 are valid on NR5xx)
  197. **   Err_NoError   otherwise
  198. */
  199. Int16
  200. nr_SetBlockIO( uInt16 chan, uInt16 val )
  201. {
  202.     register DpChannel *cp;
  203.     if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  204.       return Err_BadChan;
  205.     /* get a pointer to the channel */
  206.     cp = &channels[chan];
  207.     if(val == 0) {
  208.         cp->chanflags |= CF_NOWAITIO;
  209.     } else {
  210.         cp->chanflags &= ~CF_NOWAITIO;
  211.     }
  212.     return Err_NoError;
  213. }
  214. /*
  215. **  Function: nr_ChanReady
  216. **  Description:  Test to see if a chan is ready to transmit & receive
  217. **
  218. **  Parameters:
  219. **    chan       channel to test, 0-3
  220. **
  221. **  Returns:
  222. **   Err_BadChan   if chan is invalid (0,1,2,3 are valid on NR5xx)
  223. **   True          if the channel is ready
  224. **   False         if the channel is not ready
  225. */
  226. Int16
  227. nr_ChanReady( uInt16 chan )
  228. {
  229.   uChar val;
  230.   register DpChannel *cp;
  231.   if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  232.     return Err_BadChan;
  233.   /* get a pointer to the channel */
  234.   cp = &channels[chan];
  235.   /* check that the RX channel is active */
  236.   val = nr_ReadByte(cp, DP_RX);
  237.   if(val != nr_ReadByte(cp, DP_RX)) {
  238.     return False;
  239.   } else if(val != 1) {
  240.     return False;
  241.   }
  242.   /* check that the TX channel is active */
  243.   val = nr_ReadByte(cp, DP_TX);
  244.   if(val != nr_ReadByte(cp, DP_TX)){
  245.     return False;
  246.   } else if(val != 1) {
  247.     return False;
  248.   }
  249.   /* Channel is ready */
  250.   return True;
  251. }
  252. /*
  253. **  Function: nr_Poll
  254. **  Description: check if a character is waiting at the channel
  255. **
  256. **  Parameters:
  257. **    chan       channel to poll, 0-3
  258. **
  259. **  Returns:
  260. **    True          if there is a character waiting
  261. **    False         if there is NOT a character waiting
  262. **    Err_BadChan   if the chan is invalid (0,1,2,3 are valid on NR5xx)
  263. */
  264. Int16
  265. nr_Poll( uInt16 chan )
  266. {
  267.     DpChannel *cp;
  268.     BufIo *bp;
  269.     Int16 retval;
  270.     if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  271.       return Err_BadChan;
  272.     /* get a pointer to the channel */
  273.     cp = &channels[chan];
  274.     bp = &cp->rxbuf;
  275.     /* see if there is a character in this buffer */
  276.     if(bp->index < 0) {
  277.       /* poll for new buffers */
  278.       nr_ProcessMsgs(chan);
  279.       /* no, check for a new buffer arriving */
  280.       if(cp->rx !=  (-1) ) {
  281. retval = True;
  282.       } else {
  283. retval = False;
  284.       }
  285.     } else {
  286.       retval = True;
  287.     }
  288.     return(retval);
  289. }
  290. /*
  291. **  Function: nr_Getch
  292. **  Description: Gets one char from channel
  293. **
  294. **  Parameters:
  295. **    chan       channel to read from, 0-3
  296. **
  297. **  Returns:
  298. **   Err_WouldBlock   if channel is non-blocking and there is no char
  299. **   Err_BadChan      if the chan is invalid
  300. **   char             otherwise
  301. */
  302. Int16
  303. nr_Getch( uInt16 chan )
  304. {
  305.     DpChannel *cp;
  306.     BufIo *bp;
  307.     Int16 ch;
  308.     if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  309.       return Err_BadChan;
  310.     /* get a pointer to the channel */
  311.     cp = &channels[chan];
  312.     bp = &cp->rxbuf;
  313.     /* see if there is a character in this buffer */
  314.     if(bp->index < 0) {
  315.         /* wait for the buffer to become valid */
  316.         while(cp->rx ==  (-1) ) {
  317.             /* poll for new buffers */
  318.             nr_ProcessMsgs(chan);
  319.     /* did we get a message? */
  320.     if(cp->rx ==  (-1) ) {
  321. if(cp->chanflags & CF_NOWAITIO) return Err_WouldBlock;
  322. nr_YieldCPU();
  323.     }
  324.         }
  325.         /* make sure that the message is ready by reading the flags byte 
  326.  * of the next receive msg.  */
  327.         bp->flags = nr_ReadInt(chan, cp->rx + DPM_FLAGS);
  328. /* Re-read the flags because the NetROM may have been modifying 
  329.  * them while we read them. */
  330.         if(bp->flags != nr_ReadInt(chan, cp->rx + DPM_FLAGS)) {
  331.             /* read failed on the verify, NetROM must be writing */
  332.             bp->flags = nr_ReadInt(chan, cp->rx + DPM_FLAGS);
  333.         }
  334.         if((bp->flags & DPMSG_READY) == 0) {
  335.             return(Err_WouldBlock);
  336.         }
  337.         /* set up the i/o buffer for the message */
  338.         bp->bufsize = nr_ReadInt(chan, cp->rx + DPM_SIZE);
  339.         if(bp->bufsize > DP_DATA_SIZE) {
  340.             bp->bufsize = DP_DATA_SIZE;
  341.         }
  342.         nr_ReadBuf( chan, 
  343.     cp->rx + DPM_DATA, 
  344.     bp->buf, 
  345.     (Int16)(bp->bufsize) );
  346.         bp->index = 0;
  347.         /* return the buffer */
  348.         nr_WriteInt(chan,cp->rx+DPM_FLAGS,(uInt16)bp->flags & ~DPMSG_READY);
  349.         /* advance the read pointer */
  350.         if(bp->flags & DPMSG_WRAP) {
  351.             cp->rx = cp->rxbase;
  352.         } else {
  353.             cp->rx += DPM_MSGSIZE;
  354.         }
  355.         /* see if there are more messages waiting */
  356.         if(cp->rx == cp->rxlim) {
  357.             cp->rx = (-1);
  358.         }
  359.     }
  360.     /* extract the character */
  361.     ch = (Int16)bp->buf[bp->index++];
  362.     /* check whether we finished the buffer */
  363.     if(bp->index == bp->bufsize) {
  364.         /* invalidate the buffer */
  365.         bp->index = (-1);
  366.     }
  367.     return(ch);
  368. }
  369. /*
  370. **  Function: nr_Putch
  371. **  Description: send one character via dp protocol
  372. **
  373. **  Parameters:
  374. **    chan       channel to write to, 0-3
  375. **
  376. **  Returns:
  377. **    Err_NoError      if the char was sent successfully
  378. **    Err_WouldBlock   if we can't send the char
  379. **    Err_BadChan      if the chan is invalid
  380. */
  381. Int16
  382. nr_Putch( uInt16 chan, char ch )
  383. {
  384.     DpChannel *cp;
  385.     BufIo *bp;
  386.     if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  387.       return Err_BadChan;
  388.     /* get a pointer to the channel */
  389.     cp = &channels[chan];
  390.     bp = &cp->txbuf;
  391.     /* if the current tx channel is owned by the target, wait for it */
  392.     bp->flags = nr_ReadInt(chan, cp->tx + DPM_FLAGS);
  393.     if(bp->flags & DPMSG_READY) {
  394.         /* wait for the buffer */
  395.         while(1) {
  396.             bp->flags = nr_ReadInt(chan, cp->tx + DPM_FLAGS);
  397.             if(bp->flags != nr_ReadInt(chan, cp->tx + DPM_FLAGS)) {
  398.                 /* read failed on the verify, NetROM must be writing */
  399.                 continue;
  400.             }
  401.             if((bp->flags & DPMSG_READY) == 0) break;
  402.             if(cp->chanflags & CF_NOWAITIO) return( Err_WouldBlock );
  403.             nr_YieldCPU();
  404.         }
  405.         /* initialize the buffer structure */
  406.         bp->index = 0;
  407.         bp->bufsize = 0;
  408.     }
  409.     /* write the character into the buffer */
  410.     bp->buf[bp->index++] = ch;
  411.     bp->bufsize++;
  412.     /* if the buffer is full, send it */
  413.     if(bp->index == DP_DATA_SIZE) {
  414.         nr_FlushTX(chan);
  415.     }
  416.     return Err_NoError;
  417. }
  418. /*
  419. **  Function: nr_FlushTX
  420. **  Description: Transmits any chars pending in this channel
  421. **
  422. **  Parameters:
  423. **    chan       channel to flush, 0-3
  424. **
  425. **  Returns:
  426. **   Err_NoError   if successful
  427. **   Err_BadChan   if the chan is invalid
  428. */
  429. Int16
  430. nr_FlushTX( uInt16 chan )
  431. {
  432.     DpChannel *cp;
  433.     BufIo *bp;
  434.     if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  435.       return Err_BadChan;
  436.     /* get a pointer to the channel */
  437.     cp = &channels[chan];
  438.     bp = &cp->txbuf;
  439.     /* if we don't own the message or there's nothing in it, just return */
  440.     bp->flags = nr_ReadInt(chan, cp->tx + DPM_FLAGS);
  441.     if((bp->flags & DPMSG_READY) != 0 || bp->index == 0) {
  442.         return Err_NoError;
  443.     }
  444.     /* send the buffer */
  445.     nr_WriteInt(chan, cp->tx + DPM_SIZE, (uInt16)bp->bufsize);
  446.     nr_WriteBuf(chan, bp->buf, cp->tx + DPM_DATA, (Int16) bp->bufsize);
  447.     bp->flags &= DPMSG_WRAP;
  448.     nr_WriteInt(chan, cp->tx + DPM_FLAGS,
  449.         (uInt16)bp->flags | (DPMSG_READY|DPMSG_START|DPMSG_END));
  450.     /* notify NetROM that the buffer is ready */
  451.     dummy = nr_ReadByte(cp, DP_MRI);
  452.     /* advance the msg pointer */
  453.     if(bp->flags & DPMSG_WRAP) {
  454.         cp->tx = cp->txbase;
  455.     } else {
  456.         cp->tx += DPM_MSGSIZE;
  457.     }
  458.     /* clear the buffer structure */
  459.     bp->index = 0;
  460.     bp->bufsize = 0;
  461.     return Err_NoError;
  462. }
  463. /*
  464. **  Function: nr_GetMsg
  465. **  Description: This routine reads message from dualport ram.
  466. **      It returns different statuses, depending on whether or not
  467. **      message data is present, or the message overflows the buffer. 
  468. **      The number of bytes read into the  message buffer is changed
  469. **      by side effect. 
  470. ** 
  471. **  Parameters:
  472. **    chan        channel to read from, 0-3
  473. **    buf         buffer to read into
  474. **    len         number of bytes expected, or max bytes for this buffer
  475. **    bytesread   number of bytes actually received (nr_GetMsg will set this)
  476. **
  477. **  Returns:
  478. **   Err_BadChan           if the chan is invalid
  479. **   GM_NODATA             only returned when not in blocking I/O mode
  480. **   GM_MSGCOMPLETE
  481. **   GM_NOTDONE
  482. **   GM_MSGOVERFLOW
  483. */
  484. Int16
  485. nr_GetMsg( uInt16 chan, char* buf, uInt16 len, uInt16* bytesread )
  486. {
  487.     register DpChannel *cp;
  488.     Int16 done = 0;
  489.     Int16 nbytes = 0;
  490.     register uInt16 flags, size;
  491. #ifdef VETHER
  492.     Int16 msg_len = 0;
  493. #endif
  494.     if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  495.       return Err_BadChan;
  496.     /* get a pointer to the channel */
  497.     cp = &channels[chan];
  498.     /* look for the whole message */
  499.     while(done == 0) {
  500.         /* wait for the buffer to become valid */
  501.         while(cp->rx ==  (-1) ) {
  502.             /* poll for new buffers */
  503.             nr_ProcessMsgs(chan);
  504.     /* did we get a message? */
  505.     if(cp->rx ==  (-1) ) {
  506. #ifdef VETHER
  507. if((cp->chanflags & CF_NOWAITIO) || (nbytes == 0)) {
  508. #else
  509. if(cp->chanflags & CF_NOWAITIO) {
  510. #endif
  511.     *bytesread = nbytes;
  512.     return(nbytes == 0 ? GM_NODATA : GM_NOTDONE);
  513. }
  514. nr_YieldCPU();
  515.     }
  516.         }
  517. /* read the status and size of the new message block */
  518.         flags = nr_ReadInt(chan, cp->rx + DPM_FLAGS);
  519.         size =  nr_ReadInt(chan, cp->rx + DPM_SIZE);
  520. #ifdef VETHER
  521. /* get whole msg len from first pkt of msg */
  522. if (nbytes == 0) {
  523.     /* if ((flags & DPMSG_START) == 0)
  524.  printf("no START: %04x ", flags & 0xffff); */
  525.     msg_len = (size >> 6) | (flags & DPMSG_1K_BIT);
  526.     size = size & 0x3f;
  527. }
  528. #endif
  529. /* copy data into the buffer */
  530. if(size > len) {
  531.     *bytesread = nbytes;
  532.     return(GM_MSGOVERFLOW);
  533. }
  534.         nr_ReadBuf(chan, cp->rx + DPM_DATA, (uChar*)buf, (Int16)size);
  535.         /* return the buffer */
  536.         nr_WriteInt(chan, cp->rx + DPM_FLAGS, flags & ~DPMSG_READY);
  537. /* update our buffer pointers */
  538. buf += size;
  539. nbytes += size;
  540. len -= size;
  541.         /* advance the read pointer */
  542.         if(flags & DPMSG_WRAP) {
  543.             cp->rx = cp->rxbase;
  544.         } else {
  545.             cp->rx += DPM_MSGSIZE;
  546.         }
  547.         /* see if there are more messages waiting */
  548.         if(cp->rx == cp->rxlim) {
  549.             cp->rx = (-1);
  550.         }
  551. /* was this the end of the message? */
  552. if((flags & DPMSG_END) != 0) done = 1;
  553.     }
  554.     *bytesread = nbytes;
  555. #ifdef VETHER
  556.     if (nbytes != msg_len) {
  557. /* printf("chan_getmsg: 1st pkt len=%d, got %dn", msg_len, nbytes); */
  558. return(GM_NOTDONE);
  559.     } else 
  560. #endif
  561.      return(GM_MSGCOMPLETE);
  562. }
  563. /*
  564. **  Function: nr_PutMsg
  565. **  Description: send a message to NetROM
  566. **
  567. **  Parameters:
  568. **    chan       channel to write to, 0-3
  569. **    buf        buffer to xmit
  570. **    len        length of buffer to xmit
  571. **
  572. **  Returns:
  573. **   Err_NoError    if the message was sent successfully
  574. **   Err_NotReady   if NetROM is not ready to process messages
  575. **   Err_BadChan    if the chan is invalid
  576. */
  577. Int16
  578. nr_PutMsg( uInt16 chan, char *buf, uInt16 len )
  579. {
  580.     register DpChannel *cp;
  581.     register Int16 num_sent = 0;
  582.     uInt16 size, num_left = len, ovf_size;
  583.     register uInt16 flags;
  584.     if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  585.       return Err_BadChan;
  586.     if( !nr_ChanReady(chan) )   /* NetROM isn't ready to process msgs */
  587.       return Err_NotReady;
  588.     /* get a pointer to the channel */
  589.     cp = &channels[chan];
  590.     while(num_sent < len) {
  591.       /* wait for the buffer */
  592.       while(1) {
  593. flags = nr_ReadInt(chan, cp->tx + DPM_FLAGS);
  594. if(flags != nr_ReadInt(chan, cp->tx + DPM_FLAGS)) {
  595.   /* read failed on the verify, NetROM must be writing */
  596.   continue;
  597. }
  598. if((flags & DPMSG_READY) == 0) 
  599.   break;
  600. else
  601.   {
  602.   nr_YieldCPU(); 
  603.   }
  604.       }
  605.       /* get the number of bytes to send in DP struct and overflow */
  606.       if(num_left >= DP_DATA_SIZE) {
  607. size = DP_DATA_SIZE;
  608. if (num_left >= MAX_MSG_SIZE)
  609.   ovf_size = MAX_OVF_MSG_SIZE;
  610. else
  611.   ovf_size = num_left - DP_DATA_SIZE;
  612.       } else {
  613. size = num_left;
  614. ovf_size = 0;
  615.       }
  616.       /* fill the currently available DP buffer */
  617.       /* Put full msg size in upper bits of first size field */
  618.       if (num_sent == 0) { 
  619. nr_WriteInt(chan, cp->tx + DPM_SIZE, (len << 6) | size);
  620.       } else
  621. nr_WriteInt(chan, cp->tx + DPM_SIZE, size); 
  622.       nr_WriteBuf(chan, (uChar*)buf, cp->tx + DPM_DATA, size);
  623.       /* get the flags to write */
  624.       flags = (flags & DPMSG_WRAP) | DPMSG_READY;
  625.       if(num_sent == 0) {
  626. flags |= DPMSG_START;
  627. /* or in 1K bit of msg len */
  628. flags =  flags | (len & DPMSG_1K_BIT); 
  629.       }
  630.       num_sent += size;
  631.       num_left -= size;
  632.       if(num_sent >= len) 
  633. flags |= DPMSG_END;
  634.       nr_WriteInt(chan, cp->tx + DPM_FLAGS, flags);
  635.       /* notify NetROM that the buffer is ready */
  636.       dummy = nr_ReadByte(cp, DP_MRI);
  637.       /* adjust pointers */
  638.       buf += size;
  639.       /* advance the msg pointer */
  640.       if(flags & DPMSG_WRAP) {
  641. cp->tx    = cp->txbase;
  642. cp->txovf = cp->txovfbase;
  643.       } else {
  644. cp->tx    += DPM_MSGSIZE;
  645. cp->txovf += MAX_OVF_MSG_SIZE;
  646.       }
  647.     }
  648.     return Err_NoError;
  649. }
  650. /*
  651. **  Function: nr_Resync
  652. **  Description: Requests that NetROM clear out TX & RX buffers for all chans
  653. **               Blocks until NetROM is finished
  654. **      Note: nr_Resync must be paired with nr_ConfigDP; if not, 
  655. **            NetROM and the target will get out of sync
  656. **
  657. **  Parameters:
  658. **    chan       channel to use for resync
  659. **
  660. **  Returns:
  661. **    Err_BadChan     if channel is not in range 0 <= chan < MAXCHANNELS
  662. **    Err_NotReady    if NetROM is not ready to process requests
  663. **    Err_NoError     otherwise
  664. */
  665. Int16
  666. nr_Resync( uInt16 chan )
  667. {
  668.   register DpChannel *cp;
  669.   if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  670.     return Err_BadChan;
  671.   if( !nr_ChanReady(chan) )   /* Avoid hang if NetROM is not ready */
  672.     return Err_NotReady;
  673.   cp = &channels[chan];
  674.   nr_WriteByte( cp, DP_NR_DONE, False ); /* Force flag to False */
  675.   /* Request that NetROM resync the chans */
  676.   do{
  677.     nr_WriteByte(cp, DP_OOBFLAG, OOBFLAG_RESYNC );
  678.   } while( nr_ReadByte(cp, DP_OOBFLAG) != OOBFLAG_RESYNC );
  679.   /* Notify NetROM that the it has something to read */
  680.   dummy = nr_ReadByte(cp, DP_MRI);
  681.   /* Block until NetROM finishes the resync */
  682.   /* If your code hangs here, NetROM is not resyncing when asked to */
  683.   while( False == nr_ReadByte(cp, DP_NR_DONE) ) {}
  684.   return Err_NoError;
  685. }
  686. /*
  687. **  Function: nr_Reset
  688. **  Description: Requests that NetROM reset the target
  689. **
  690. **  Parameters:
  691. **    chan       channel used for reset message 
  692. **
  693. **  Returns:
  694. **   Err_NoError     if the OOB msg was sent successfully
  695. **   Err_NotReady    if NetROM is not ready to process messages
  696. **   Err_BadChan     if the chan is invalid (0,1,2,3 are valid on NR5xx)
  697. */
  698. Int16
  699. nr_Reset( uInt16 chan )
  700. {
  701.   return nr_PutOOBMsg(chan, DP_OOB_RESET, NULL, 0);
  702. }
  703. /*
  704. **  Function: nr_IntAck
  705. **  Description: Acknowledges a previous interrupt to the target
  706. **               
  707. **  Parameters:
  708. **    chan       channel to acknowledge interrupt on
  709. **
  710. **  Returns:
  711. **   Err_NoError     if the OOB msg was sent successfully
  712. **   Err_NotReady    if NetROM is not ready to process messages
  713. **   Err_BadChan     if the chan is invalid (0,1,2,3 are valid on NR5xx)
  714. */
  715. Int16
  716. nr_IntAck( uInt16 chan )
  717. {
  718.   return nr_PutOOBMsg(chan, DP_OOB_INTACK, NULL, 0);
  719. }
  720. /*
  721. **  Function: nr_Cputs
  722. **  Description: Puts a string to the NetROM console; the
  723. **               message won't be transmitted to the host
  724. **
  725. **  Parameters:
  726. **    chan       channel to write message through
  727. **    len        length of message, less than 56
  728. **
  729. **  Returns:
  730. **   Err_NoError     if the OOB msg was sent successfully
  731. **   Err_NotReady    if NetROM is not ready to process messages
  732. **   Err_BadChan     if the chan is invalid (0,1,2,3 are valid on NR5xx)
  733. **   Err_BadLength   if the "size" of the buffer is too big
  734. **   Err_BadCommand  if the command is invalid
  735. */
  736. Int16
  737. nr_Cputs( uInt16 chan, char *buf, uInt16 len )
  738. {
  739.   char localbuf[60];
  740.   if(len > 55) return Err_BadLength;
  741.   /* Ensure zero-termination */
  742.   memcpy( (uChar*)localbuf, (uChar*)buf, len );
  743.   localbuf[len] = NULL;
  744.   return nr_PutOOBMsg(chan, DP_OOB_CPUTS, localbuf, len+1);
  745. }
  746. #if (READONLY_TARGET == True )
  747. /*
  748. **  Function: nr_SetMem
  749. **  Description: Requests that NetROM set a block of overlay memory
  750. **  Note: 1. target must run from RAM while NetROM sets the memory
  751. **        2. Total msg size = len+6 = len+sizeof(addr)+sizeof(len)
  752. **
  753. **  Parameters:
  754. **    chan       channel to write to
  755. **    addr       start address for write
  756. **    buf        data to write
  757. **    len        length of buf; must be less than 54 bytes
  758. **
  759. **  Returns:
  760. **   Err_NoError      if successful
  761. **   Err_BadLength    if length is invalid; max block size is 54 bytes
  762. **   Err_BadChan      if the chan is invalid
  763. **   Err_BadAddress   if the address is invalid, i.e. outside ROM
  764. */
  765. Int16
  766. nr_SetMem( uInt16 chan, uInt32 addr, char* buf, uInt16 len )
  767. {
  768.   DpSetMemBuf setmem_buf;
  769.   register DpChannel *cp;
  770.   uInt16 size;
  771.   if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  772.     return Err_BadChan;
  773.   if( len == 0 || len > DP_DATA_SIZE-6 )  /* Invalid length! */
  774.     return Err_BadLength;
  775.   if( !nr_InROM(addr) )  /* Invalid address! */
  776.     return Err_BadAddress;
  777.   addr -= (uInt32)ROMSTART;   /* NetROM references addresses from ROMSTART */
  778.   cp = &channels[chan]; /* Get a pointer to the channel */
  779.   setmem_buf.addr = swap32(addr); /* Fix big/little -endian */
  780.   memcpy( setmem_buf.data, (uChar*)buf, len );
  781.   size = len + 4; /* buf length + sizeof(addr) */
  782.   if(emoffonwrite_set == True) {
  783.     nr_PutOOBMsg(chan, DP_OOB_EMOFFONWRITE, NULL, 0);
  784.     emoffonwrite_set = False;
  785.   }
  786.   /* The following nr_PutOOBMsg call should be atomic 
  787.   ** If it is not, make sure that you don't write other messages 
  788.   ** to this channel after you've begun the SetMem sequence! 
  789.   */
  790.   nr_InterruptsOFF();
  791.   nr_PutOOBMsg(chan, DP_OOB_SETMEM, (char*)&setmem_buf, size);
  792.   nr_InterruptsON();
  793.   return Err_NoError;
  794. }
  795. #else /* READONLY_TARGET != True */
  796. /*
  797. **  Function: nr_SetMem
  798. **  Description: Sets a block of overlay memory, up to 54 bytes
  799. **               This target can write its own memory.
  800. **               length, channel, and address are checked to
  801. **               keep this routine consisten with the read-only version
  802. **
  803. **  Parameters:
  804. **    chan       channel to write to
  805. **    addr       start address for write
  806. **    buf        data to write
  807. **    len        length of buf; must be less than 54 bytes
  808. **
  809. **  Returns:
  810. **   Err_NoError      if successful
  811. **   Err_BadLength    if length is invalid
  812. **   Err_BadChan      if the chan is invalid
  813. **   Err_BadAddress   if the address is invalid, i.e. outside ROM
  814. */
  815. Int16
  816. nr_SetMem( uInt16 chan, uInt32 addr, char *buf, uInt16 len )
  817. {
  818.   if( !nr_InROM(addr) )  /* Invalid address! */
  819.     return Err_BadAddress;
  820.   if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  821.     return Err_BadChan;
  822.   if( len == 0 || len > DP_DATA_SIZE-6 )  /* Invalid length! */
  823.     return Err_BadLength;
  824.   memcpy( (uChar*)addr, (uChar*)buf, (long)len );
  825. }
  826. #endif /* READONLY_TARGET == True */
  827. /*
  828. **  Function: nr_SetEmOffOnWrite
  829. **  Parameters:
  830. **
  831. **  Description: After calling this, NetROM will set emulation off
  832. **               before writing to PodMem.  See nr_SetMem().
  833. **               The default, set in nr_ConfigDP(), is
  834. **               emoffonwrite_set = False.
  835. **  Returns:
  836. */
  837. void
  838. nr_SetEmOffOnWrite(void)
  839. {
  840.   emoffonwrite_set = True; 
  841. }
  842. /*
  843. **  Function: nr_WriteInt
  844. **  Description: Writes a uInt16 to dp RAM
  845. **    Warning:  Assumes 'chan' is valid!
  846. **
  847. **  Parameters:
  848. **    chan       channel to write to
  849. **    addr       start address for write
  850. **    val        data to write
  851. **
  852. **  Returns:
  853. */
  854. STATIC void
  855. nr_WriteInt( uInt16 chan, uInt32 addr, register uInt16 val )
  856. {
  857.   register DpChannel *cp = &channels[chan];
  858.   register uInt16 valLSB = (uInt16)val & 0xFF;
  859.   register uInt16 valMSB = (uInt16)(val >> 8) & 0xFF;
  860.   /* Write in network byte order, LSB first 
  861.   ** This avoids writing the message-ready bit before other flags,
  862.   ** which could lead to garbled messages.  Make sure that the
  863.   ** write succeeded--NetROM and target may have been in contention.
  864.   */
  865.   do  {
  866.     nr_WriteByte(cp, addr + 1, valLSB );
  867.     nr_WriteByte(cp, addr, valMSB );
  868.   } while (val != nr_ReadInt(chan, addr) );
  869. }
  870. /*
  871. **  Function: nr_ReadInt
  872. **  Description: Reads a uInt16 from DP RAM
  873. **  Warning: Assumes 'chan' is valid
  874. **
  875. **  Parameters:
  876. **    chan       channel to read from
  877. **    addr       start address for read
  878. **
  879. **  Returns:
  880. **     Int16 from DP RAM
  881. */
  882. STATIC uInt16
  883. nr_ReadInt( uInt16 chan, uInt32 addr )
  884. {
  885.   register uInt16 val;
  886.   register DpChannel *cp = &channels[chan];
  887.   /* read the msb first, in case it contains flags */
  888.   val = (uChar)nr_ReadByte(cp, addr);
  889.   val <<= 8;
  890.   val += (uChar)nr_ReadByte(cp, addr + 1);
  891.   /* return, in host byte order */
  892.   return(val);
  893. }
  894. /*
  895. **  Function: nr_WriteBuf
  896. **  Description: Copies bytes to dual-port RAM
  897. **  Warning: Assumes 'chan' is valid
  898. **
  899. **  Parameters:
  900. **    chan       channel to write to
  901. **    src        data to write
  902. **    addr       start address for write
  903. **    len        length of buf
  904. **
  905. **  Returns:
  906. */
  907. STATIC void
  908. nr_WriteBuf( uInt16 chan, uChar *src, uInt32 addr, uInt16 len )
  909. {
  910.     register Int16 i;
  911.     register DpChannel *cp = &channels[chan];
  912. #if (nr_HasCache != True && READONLY_TARGET == False)
  913.     register Int16 inc;
  914.     register volatile uChar *dst;
  915. #endif
  916. #if (nr_HasCache == True && READONLY_TARGET == False) /* RW tgt with cache */
  917.     for(i = 0; i < len; i++) {
  918.       nr_WriteByte(cp, addr++, *src);
  919.       src++;
  920.     }
  921. #elif (READONLY_TARGET == True)  /* Read only tgt, either way */
  922.     RR_ENABLE(cp, addr);            /* Enable RR & latch start addr */
  923.     for(i = 0; i < len; i++) {
  924.       RR_WRITE_BYTE(cp, *src);     /* Write & autoincrement dest addr */
  925.       src++;
  926.     }
  927.     RR_DISABLE(cp);
  928. #else                            /* RW tgt without cache */
  929.     inc = cp->width;
  930.     dst = (volatile uChar *)(cp->dpbase + (cp->width * addr) + cp->index);
  931.     for(i = 0; i < len; i++) {
  932.         *dst = *src;
  933.         dst += inc;
  934.         src++;
  935.     }
  936. #endif
  937. }
  938. /*
  939. **  Function: nr_ReadBuf
  940. **  Description: Copies bytes from dualport RAM
  941. **
  942. **  Parameters:
  943. **    chan       channel to read from
  944. **    addr       start address for read
  945. **    buf        buffer to read into
  946. **    len        length of buf
  947. **
  948. **  Returns:
  949. */
  950. STATIC void
  951. nr_ReadBuf( uInt16 chan, uInt32 addr, volatile uChar *buf, Int16 len )
  952. {
  953.     register Int16 i;
  954.     volatile uChar ch;
  955.     register DpChannel *cp = &channels[chan];
  956.     for(i = 0; i < len; i++, buf++, addr++) {
  957.       *buf = (ch = nr_ReadByte(cp, addr));
  958.     }
  959. }
  960. /*
  961. **  Function: nr_PutOOBMsg
  962. **  Description: sends out-of-band message to NetROM
  963. **
  964. **  Parameters:
  965. **    chan       channel to write to
  966. **    cmd        command number, see dptarget.h for commands
  967. **    buf        data, if any, required by this command
  968. **    size       size of buf; must be less than 58 bytes
  969. **
  970. **  Returns:
  971. **   Err_NoError     if the OOB msg was sent successfully
  972. **   Err_NotReady    if NetROM is not ready to process messages
  973. **   Err_BadChan     if the chan is invalid (0,1,2,3 are valid on NR5xx)
  974. **   Err_BadLength   if the "size" of the buffer is too big
  975. **   Err_BadCommand  if the command is invalid
  976. */
  977. STATIC Int16
  978. nr_PutOOBMsg( uInt16 chan, uInt16 cmd, register char *buf, uInt16 size )
  979. {
  980.   register DpChannel *cp;
  981.   uInt16 flags;
  982.   if( !nr_ChanReady(chan) )  /* NetROM not ready */
  983.     return Err_NotReady;
  984.   if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  985.     return Err_BadChan;
  986.   if( size > DP_DATA_SIZE-2 )  /* Includes cmd and buf */
  987.     return Err_BadLength;
  988.   if( cmd > DP_OOB_MAXCMD ) /* Invalid command! */
  989.     return Err_BadCommand;
  990.   /* get a pointer to the channel */
  991.   cp = &channels[chan];
  992.   /* Wait for the buffer */
  993.   while(1) {
  994.     flags = nr_ReadInt(chan, cp->tx + DPM_FLAGS);
  995.     
  996.     if(flags != nr_ReadInt(chan, cp->tx + DPM_FLAGS)) {
  997.       /* read failed on the verify, NetROM must be writing */
  998.       continue;
  999.     }
  1000.     if((flags & DPMSG_READY) == 0) 
  1001.       break;
  1002.     nr_YieldCPU(); 
  1003.   }
  1004.   /* Write size field to DP buf */
  1005.   nr_WriteInt(chan, cp->tx + DPM_SIZE, size+sizeof(cmd));
  1006.   /* Write out-of-band command number to DP buf */
  1007.   nr_WriteInt(chan, cp->tx + DPM_OOB_CMD, cmd);
  1008.   if( size > 0 )
  1009.     nr_WriteBuf(chan, (uChar*)buf, cp->tx + DPM_OOBDATA, size);
  1010.   /* Write flags for OOB msg */
  1011.   /* If doing SetMEM, do _not_ set Ready flag! */
  1012.   flags = (flags & DPMSG_WRAP) | DPMSG_OOB | DPMSG_START | DPMSG_END;
  1013.   if( DP_OOB_SETMEM != cmd )
  1014.     flags |= DPMSG_READY;
  1015.   nr_WriteInt(chan, cp->tx + DPM_FLAGS, flags);
  1016.   /* Notify NetROM that the buffer is ready, unless it's nr_SetMem */
  1017.   /* nr_SetMem will read DP_MRI from a routine in RAM */
  1018.   if( DP_OOB_SETMEM != cmd )
  1019.     dummy = nr_ReadByte(cp, DP_MRI);
  1020.   else
  1021.     (*(cp->wait_nr_done_ptr))(cp);    /* Wait in RAM until NR is finished */
  1022.   /* Advance the msg pointer */
  1023.   if(flags & DPMSG_WRAP) {
  1024.     cp->tx    = cp->txbase;
  1025.     cp->txovf = cp->txovfbase;
  1026.   } else {
  1027.     cp->tx    += DPM_MSGSIZE;
  1028.     cp->txovf += MAX_OVF_MSG_SIZE;
  1029.   }
  1030.   return Err_NoError;
  1031. }
  1032. /*
  1033. **  Function: nr_Wait
  1034. **  Note: 1. This ftn must run from RAM
  1035. **        2. nr_WaitEnd()   must be defined immediately after nr_Wait
  1036. **        3. (2) assumes that the compiler keeps ftns in order
  1037. **  Description: Finishes writing OOB_SetMem msg, waits for NR to
  1038. **               write memory, then exits
  1039. **
  1040. **  Parameters:
  1041. **    cp         Pointer to channel to use
  1042. **
  1043. **  Returns:
  1044. */
  1045. STATIC void
  1046. nr_Wait( DpChannel *cp )
  1047. {
  1048.   uChar flagsMSB;
  1049.   /* Warning: cp is assumed to be valid  */
  1050.   do{
  1051.     nr_WriteByte( cp, DP_NR_DONE, False ); /* Force flag to False */
  1052.   } while( nr_ReadByte(cp, DP_NR_DONE) != False );
  1053.   /* Finish writing flags: write READY bit */
  1054.   /* Assumes Ready-bit is in MSB */
  1055.   flagsMSB = nr_ReadByte(cp, cp->tx + DPM_FLAGS); 
  1056.   flagsMSB |= (DPMSG_READY >> 8);              
  1057.   nr_WriteByte(cp, cp->tx + DPM_FLAGS, flagsMSB );
  1058.   dummy = nr_ReadByte(cp, DP_MRI); /* Ask NR to process messages */
  1059.   /* Wait for NetROM to finish the PodMem write 
  1060.   ** Note: when emulation is OFF, target will see 0xFF in 
  1061.   ** this location.  This is not a problem, because the target
  1062.   ** will hang in wait loop, below, until the flag == True.
  1063.   ** Flag will equal True after NetROM sets it True and turns
  1064.   ** emulation back on.
  1065.   **
  1066.   **   If your code is hanging here, NetROM is not completing
  1067.   **   its write to Pod memory
  1068.   */
  1069.   while( nr_ReadByte( cp, DP_NR_DONE ) != True ) {}
  1070. }
  1071. /*
  1072. **  Function: nr_WaitEnd
  1073. **  Description: This empty ftn marks the end of nr_Wait()
  1074. **  Note: wait_fnt_end() must be defined immediately after nr_Wait
  1075. **
  1076. **  Parameters:
  1077. **
  1078. **  Returns:
  1079. */
  1080. STATIC void 
  1081. nr_WaitEnd( void )
  1082. {
  1083. }
  1084. /*
  1085. **  Function: nr_ProcessMsgs
  1086. **  Description: Processes any messages received from NetROM
  1087. **
  1088. **  Parameters:
  1089. **    chan         Channel to process
  1090. **
  1091. **  Returns:
  1092. **   Err_BadChan    if the chan is invalid
  1093. **   Err_NoError    otherwise
  1094. */
  1095. STATIC Int16 
  1096. nr_ProcessMsgs( uInt16 chan )
  1097. {
  1098.     register DpChannel *cp;
  1099.     register uInt16 flags;
  1100.     if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  1101.       return Err_BadChan;
  1102.     /* get a pointer to the channel */
  1103.     cp = &channels[chan];
  1104.     /* a received message indicator */
  1105.     while(cp->rx != cp->rxlim) {
  1106.         flags = nr_ReadInt(chan, cp->rxlim + DPM_FLAGS);
  1107.         if(flags != nr_ReadInt(chan, cp->rxlim + DPM_FLAGS)) {
  1108.                 /* NetROM must be writing, try again */
  1109.                 continue;
  1110.         }
  1111.         if(flags & DPMSG_READY) {
  1112.   /* a new message is ready */
  1113.   if(cp->rx ==  (-1) ) {
  1114.     /* record that the message is ready to be read */
  1115.     cp->rx = cp->rxlim;
  1116.   }
  1117.   /* advance the read limit pointer */
  1118.   if(flags & DPMSG_WRAP) {
  1119.     cp->rxlim = cp->rxbase;
  1120.   } else {
  1121.     cp->rxlim += DPM_MSGSIZE;
  1122.   }
  1123.         } else {
  1124.   /* no more messages */
  1125.   break;
  1126.         }
  1127.     }
  1128.     return Err_NoError;
  1129. }
  1130. #if (DEBUG_ON == True)
  1131. /*
  1132. ** Function:    nr_TestComm
  1133. ** Description: Determines if NR Comm is working
  1134. ** Notes:
  1135. ** 1. Tests 1 through 6 test low-level reads & writes to dualport RAM
  1136. **    Before executing the tests, execute a 'fill 0 dpmem' and a 
  1137. **    'tgtreset' on NetROM.
  1138. **    After executing the tests, verify their success by typing
  1139. **    'di dpmem 0x50 0x80' at the NetROM prompt.  Your NetROM display 
  1140. **    should look like:
  1141. **  
  1142. **  0050  6e72 5f57 7269 7465 - 4279 7465 0000 0000    nr_WriteByte....
  1143. **  0060  6e72 5f52 6561 6442 - 7974 6500 0000 0000    nr_ReadByte.....
  1144. **  0070  6e72 5f57 7269 7465 - 496e 7420 0000 0000    nr_WriteInt ....
  1145. **  0080  0000 0000 0000 0000 - 0000 0000 0000 0000    ................
  1146. **  0090  6e72 5f52 6561 6449 - 6e74 2020 0000 0000    nr_ReadInt  ....
  1147. **  00a0  6e72 5f57 7269 7465 - 4275 6600 0000 0000    nr_WriteBuf.....
  1148. **  00b0  6e72 5f52 6561 6442 - 7566 2000 0000 0000    nr_ReadBuf .....
  1149. **
  1150. ** 2. Tests 7 and higher test higher-level char and msg passing thru DP RAM
  1151. **    for these tests, you'll need to telnet to 
  1152. **    the NetROM debugport (1235 is the default)
  1153. **    Example: telnet netrom 1235
  1154. **    The name of the function tested should appear in the telnet window.
  1155. **
  1156. **  Parameters:
  1157. **    chan        Channel to test, 0-3
  1158. **    lastTest    See tests, below to select
  1159. **    endian      0 for Intel (little-endian), 1 for Motorola (big-endian)
  1160. **
  1161. **  Returns:
  1162. **    Err_BadChan  if chan is invalid 
  1163. **    Err_NoError  otherwise
  1164. */
  1165. Int16 nr_TestComm( uInt16 chan, uInt16 lastTest, uInt16 endian )
  1166. {
  1167.   Int32 i,j;
  1168.   uChar ch;
  1169.   uChar testNum = 1;
  1170.   static char *wb_buf = "nr_WriteByte";
  1171.   static char *rb_buf = "nr_ReadByte";
  1172.   static char *wi_buf[2] = {"rnW_iretnI t", "nr_WriteInt "}; /* intel, mot */
  1173.   static char *ri_buf[2] = {"rnR_aeIdtn  ", "nr_ReadInt  "}; /* intel, mot */
  1174.   static char *wbuf = "nr_WriteBuf";
  1175.   static char *rbuf = "nr_ReadBuf ";
  1176.   static char *putch_buf = "rnnnnr_Putchrn";
  1177.   static  char putmsg_buf[1024] = "rnnr_PutMsgrn";
  1178.   char* getch_buf = "rnnr_Getch testrn";
  1179.   char* getmsg_buf = "rnnr_GetMsg testrn";
  1180.   char* query_buf = "Type a message, then press <ret> rn";
  1181.   char buf[81]; 
  1182.   uInt16 bytesread; 
  1183.   DpChannel *cp;
  1184.   BufIo *bp;
  1185.   if( chan >= DP_MAXCHANNELS )  /* Invalid channel! */
  1186.     return Err_BadChan;
  1187.   /* get a pointer to the channel */
  1188.   cp = &channels[chan];
  1189.   bp = &cp->txbuf;
  1190.   /* Test 1
  1191.   ** Test nr_ConfigDP params & nr_WriteByte
  1192.   ** Write 'nr_WriteByte ' to DPRAM, starting at DP_BASE + 0x50
  1193.   ** Assuming your hardware is correctly installed, and 
  1194.   ** this test fails, either you are calling nr_ConfigP with the
  1195.   ** wrong parameters, or your NetROM is not set up correctly
  1196.   */
  1197.   for(i=0; i<strlen(wb_buf); i++) {
  1198.     nr_WriteByte(cp, 0x50+i, wb_buf[i]); 
  1199.   } 
  1200.   if(testNum++ >= lastTest) return Err_NoError;
  1201.   /* Test 2
  1202.   ** Test nr_ReadByte macro
  1203.   ** Read nr_WriteByte, convert, write nr_ReadByte
  1204.   */
  1205.   for(i=0; i<strlen(rb_buf); i++ ) {
  1206.     ch = nr_ReadByte(cp, 0x50+i) + rb_buf[i] - wb_buf[i];
  1207.     nr_WriteByte(cp, 0x60+i, ch);
  1208.   }
  1209.   if(testNum++ >= lastTest) return Err_NoError;
  1210.   /* Test 3
  1211.   ** Test nr_WriteInt ftn
  1212.   ** Write 'nr_WriteInt'
  1213.   */
  1214.   for(i=0; i<strlen(wi_buf[endian]); i+=2) {
  1215.     nr_WriteInt(chan, 0x70+i, *(uInt16*)(&wi_buf[endian][i] ));
  1216.   }
  1217.   if(testNum++ >= lastTest) return Err_NoError;
  1218.   /* Test 4
  1219.   ** Test nr_ReadInt ftn 
  1220.   ** Read nr_WriteInt, convert, write as nr_ReadInt
  1221.   */
  1222.   for(i=0; i<strlen(wi_buf[endian]); i+=2) {
  1223.     j = nr_ReadInt(chan, 0x70+i)
  1224.       + *(uInt16*)(&ri_buf[endian][i])
  1225.       - *(uInt16*)(&wi_buf[endian][i]);
  1226.     nr_WriteInt(chan, 0x90+i, j );
  1227.   }
  1228.   if(testNum++ >= lastTest) return Err_NoError;
  1229.   /* Test 5
  1230.   ** Test nr_WriteBuf ftn 
  1231.   ** Write 'nr_WriteBuf'
  1232.   */
  1233.   nr_WriteBuf( chan, (uChar*)wbuf, 0xA0, strlen(wbuf) );
  1234.   if(testNum++ >= lastTest) return Err_NoError;
  1235.   /* Test 6
  1236.   ** Test nr_ReadBuf ftn 
  1237.   ** Read 'nr_WriteBuf', convert, then write 'nr_ReadBuf'
  1238.   */
  1239.   nr_ReadBuf( 0, 0xA0, (uChar*)buf, sizeof(buf) );
  1240.   for(i=0; i<strlen(rbuf); i++ )
  1241.     rbuf[i] = buf[i] + rbuf[i] - wbuf[i];
  1242.   nr_WriteBuf( 0, (uChar*)rbuf, 0xB0, strlen(rbuf) );
  1243.   if(testNum++ >= lastTest) return Err_NoError;
  1244.   /* Test 7
  1245.   ** Test nr_Putch ftn and nr_FlushTX ftn
  1246.   ** Send the chars 'n' 'r' '_' 'P' 'u' 't' 'c' 'h' to the NR debug port
  1247.   ** Do you see 'nr_Putch' on the debug window?
  1248.   */
  1249.   for( i=0; i<strlen(putch_buf); i++) 
  1250.     nr_Putch(chan, putch_buf[i]);
  1251.   nr_FlushTX(0);
  1252.   if(testNum++ >= lastTest) return Err_NoError;
  1253.   /* Test 8
  1254.   **  Test nr_PutMsg ftn
  1255.   ** Send the message "nr_PutMsgrn"
  1256.   */
  1257.   nr_PutMsg( chan, putmsg_buf, strlen(putmsg_buf) );
  1258.   if(testNum++ >= lastTest) return Err_NoError;
  1259.   /* Test 9
  1260.   ** Test nr_OOBMsg ftn via nr_Cputs
  1261.   ** You will see "nr_Cputs working" in the NetROM console window on NR5xx
  1262.   ** On NR4xx, OOB msgs pass thru like normal in-band msgs
  1263.   */
  1264.   nr_Cputs( chan, "nr_Cputsrn", 10 );
  1265.   if(testNum++ >= lastTest) return Err_NoError;
  1266.   /* Test A
  1267.   ** Test nr_GetMsg ftn
  1268.   ** Get user input, then echo.
  1269.   */
  1270.   nr_SetBlockIO(chan, True);
  1271.   nr_PutMsg(chan, getmsg_buf, strlen(getmsg_buf) );
  1272.   nr_PutMsg(chan, query_buf, strlen(query_buf) );
  1273.   nr_GetMsg(chan, buf, 80, &bytesread );
  1274.   nr_PutMsg(chan, buf, bytesread );
  1275.   if(testNum++ >= lastTest) return Err_NoError;
  1276.   /* Test B
  1277.   ** Test nr_Getch ftn
  1278.   ** Get user input, then echo.
  1279.   */
  1280.   nr_PutMsg(chan, getch_buf, strlen(getch_buf) );
  1281.   nr_PutMsg(chan, query_buf, strlen(query_buf) );
  1282.   do{
  1283.     ch = nr_Getch(chan);
  1284.     if(ch > 0)nr_Putch(chan, ch);
  1285.   }while( ch != 'n' );
  1286.   nr_FlushTX(chan); 
  1287.   if(testNum++ >= lastTest) return Err_NoError;
  1288.   /* Test C
  1289.   ** Test nr_SetMem ftn
  1290.   ** Write "SetMem"
  1291.   ** Note: Move address so that SetMem writes to regular podmem,
  1292.   **       NOT dualport RAM!  Don't stomp code or data!
  1293.   */
  1294.   nr_SetMem( 0, ROMSTART + 0x2000, "SetMem", 6 );
  1295.   if(testNum++ >= lastTest) return Err_NoError;
  1296.   /* Test D
  1297.   ** Stress test nr_PutMsg ftn
  1298.   ** Send 1k buffer 100 times
  1299.   */
  1300.   nr_PutMsg(0, "rn*** nr_PutMsg Stress Test ***rnrn", 36);
  1301.     for(j=0; j<=1023; j++) {
  1302.       if( (j%2) ) putmsg_buf[j] = ' ';
  1303.       else      putmsg_buf[j] = 0x08;  /* BS */
  1304.     }
  1305.   putmsg_buf[0] = ' '; putmsg_buf[1] = '[';  
  1306.   putmsg_buf[6] = ']'; putmsg_buf[7] = ' ';
  1307.   for(i=1; i <= 9000; i++) {
  1308.     int a,b,c,d;
  1309.     a = i/1000;
  1310.     b = (i - a*1000)/100;
  1311.     c = (i - a*1000 - b*100)/10;
  1312.     d = (i - a*1000 - b*100 - c*10);
  1313.     putmsg_buf[2] = '0' + a;
  1314.     putmsg_buf[3] = '0' + b;
  1315.     putmsg_buf[4] = '0' + c;
  1316.     putmsg_buf[5] = '0' + d;
  1317.     nr_PutMsg( chan, putmsg_buf, 1024);
  1318.   }
  1319.   return Err_NoError;
  1320. }
  1321. #else /* DEBUG_ON */
  1322. Int16 nr_TestComm( uInt16 chan, uInt16 lastTest, uInt16 endian )
  1323. {
  1324.   return -1;
  1325. }
  1326. #endif /* DEBUG_ON */