[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [openrisc] First steps



Hi Michael,

We have done a similar implementation to you using an Avnet
ADS-XLS-DEV-XE4000 development board (no MMU or cache) and using Xilinx
internal RAM written to via PCI bus.

Initially, we deliberately chose to use a very basic, hand-crafted machine
code 'HELLO WORLD' test program to test the hardware. This then rules out
software as a possible source of problems. Here it is, shown as a C array -
you can use a simple loop to copy it to the memory starting at 0x100. The
program will continuously spew out "HELLO WORLD!\r\n"

Some points:

* I have left in some additional code to light LEDs (shown by '(LED
code)') - ignore this.
* The UART is at 0x90000000 with 0x4 spacing between the registers (A[4:2]
on Wishbone bus tied to A[2:0] on UART)
* You may need to calculate a different baud rate divisor
* I am testing for LSR:THRE, which is set when the Tx FIFO is completely
empty (note that the data sheet for the Exar 16552 seems to contradict
itself, suggesting in one place that LSR:THRE is set when there is space in
the Tx FIFO, in another when the Tx FIFO is empty - not the same thing,
surely?). Anyway, you could also test for LSR:TEMT, which indicates an
underrun.

<code>
#define CODE_SIZE 63
static const uint32 s_au32Code[CODE_SIZE] = {
0x15000000, // l.nop
0x15000000, // l.nop
0x9c60fffc, // l.addi r3,r0, 0xfffc     # r3 <- 0xfffffffc (LED code)
0xa880ffff, // l.ori r4,r0, 0xffff      # LEDs all on (LED code)
0xd4032000, // l.sw 0x0(r3), r4         # Write to LEDs (LED code)
0x18209000, // l.movhi r1,0x9000
0xa8210000, // l.ori   r1,r1,0x0000     # Base address in r1 (l.ori is not
actually necessary)
0xa8400083, // l.ori   r2,r0,0x0083     # LCR:DLAB <- 1
0xd801100c, // l.sb 0xC(r1),r2
0xa8400082, // l.ori   r2,r0,0x0082     # Baud rate divisor : DLL <- 0x82
0xd8011000, // l.sb 0x0(r1),r2
0xa8400003, // l.ori   r2,r0,0x0003     # LCR:DLAB <- 0
0xd801100c, // l.sb 0xC(r1),r2
0xa8400048, // l.ori   r2,r0,0x0048     # THR <- "H"  <--- loop to here !
0xd8011000, // l.sb 0x0(r1),r2
0xa8400045, // l.ori   r2,r0,0x0045     # "E"
0xd8011000, // l.sb 0x0(r1),r2
0xa840004c, // l.ori   r2,r0,0x004C     # "L"
0xd8011000, // l.sb 0x0(r1),r2
0xa840004c, // l.ori   r2,r0,0x004C     # "L"
0xd8011000, // l.sb 0x0(r1),r2
0xa840004f, // l.ori   r2,r0,0x004F     # "0"
0xd8011000, // l.sb 0x0(r1),r2
0xa8400020, // l.ori   r2,r0,0x0020     # " "
0xd8011000, // l.sb 0x0(r1),r2
0xa8400057, // l.ori   r2,r0,0x0057     # "W"
0xd8011000, // l.sb 0x0(r1),r2
0xa840004f, // l.ori   r2,r0,0x004F     # "O"
0xd8011000, // l.sb 0x0(r1),r2
0xa8400052, // l.ori   r2,r0,0x0052     # "R"
0xd8011000, // l.sb 0x0(r1),r2
0xa840004c, // l.ori   r2,r0,0x004C     # "L"
0xd8011000, // l.sb 0x0(r1),r2
0xa8400044, // l.ori   r2,r0,0x0044     # "D"
0xd8011000, // l.sb 0x0(r1),r2
0xa8400021, // l.ori   r2,r0,0x0021     # "!"
0xd8011000, // l.sb 0x0(r1),r2
0xa840000d, // l.ori   r2,r0,0x000d     # <CR>
0xd8011000, // l.sb 0x0(r1),r2
0xa840000a, // l.ori   r2,r0,0x000a     # <LF>
0xd8011000, // l.sb 0x0(r1),r2
0x9c840001, // l.addi r4,r4,0x0001      # Increment r4 (LED code)
0xd4032000, // l.sw 0x0(r3), r4         # Write to LEDs (LED code)
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop
0x15000000, // l.nop                    # Pause
0x8c410014, // l.lbz   r2,0x14(r1)
0xa4420020, // l.andi  r2,r2,0x0020     # Test for LSR:THRE (or perhaps
LSR:TEMT (0x0040))
0xe4020000, // l.sfeq  r2,r0
0x13fffffd, // l.bf branch (-3 << 2)    # Loop until set
0x15000000, // l.nop (delay slot)
0x03ffffd0, // l.j (-48 <<2 )           # Loop to start of message
0x15000000  // l.nop (delay slot)
};
</code>

For your other questions, you can use the binutils 'or32-uclinux-objdump' to
do a disassembly of an 'a.out', and 'or32-uclinux-objcopy' to convert it to
other formats, including binary.

There is a sort of 'newbie FAQ' based on my experiences which I put together
at http://www.asisi.co.uk/or1k.html for the tools and simulator, but it
doesn't cover this stuff yet. I will add it in at some point.

Robert Cragie, Design Engineer
_______________________________________________________________
Jennic Ltd, Furnival Street, Sheffield, S1 4QT,  UK
http://www.jennic.com  Tel: +44 (0) 114 281 2655
_______________________________________________________________

> -----Original Message-----
> From: owner-openrisc@opencores.org
> [mailto:owner-openrisc@opencores.org]On Behalf Of Igor Mohor(opencores)
> Sent: 22 April 2003 09:19
> To: openrisc@opencores.org
> Subject: RE: [openrisc] First steps
>
>
> Hi.
>
> The opencores uart16550 has internal buffer and you can write/send up to
> 16 bytes without waiting for the previous transmission to end.
>
> Regards,
> 	Igor
>
> > -----Original Message-----
> > From: owner-openrisc@opencores.org
> [mailto:owner-openrisc@opencores.org]
> > On Behalf Of Jim Dempsey
> > Sent: Monday, April 21, 2003 8:58 PM
> > To: openrisc@opencores.org
> > Subject: Re: [openrisc] First steps
> >
> > You cannot output the "next" character to the UART until the UART is
> ready
> > to receive the next character. I am not familiar with this particular
> > UART.
> > Many UART designs include a holding register and a shift register.
> You
> > typicaly can place the next character to write into the holding
> register
> > while the shift register is outputing the current character. This
> gives
> > you
> > 1 byte of buffer. The UART design usualy has one status bit for the
> shift
> > register busy and one status bit for the holding register ready (or
> busy).
> > Your code will need to test for the holding register ready/busy bit.
> Look
> > at
> > the design to find the register offset and bit value.
> >
> > >   while (1)  {
> >     while((*pControlPort) & HOLDING_REGISTER_BUSY)
> >         continue;
> > >     *pDataPort = 'H';       /* Send hello forever */
> >     while((*pControlPort) & HOLDING_REGISTER_BUSY)
> >         continue;
> > >     *pDataPort = 'e';
> >     while((*pControlPort) & HOLDING_REGISTER_BUSY)
> >         continue;
> > >     *pDataPort = 'l';
> >     while((*pControlPort) & HOLDING_REGISTER_BUSY)
> >         continue;
> > >     *pDataPort = 'l';
> >     while((*pControlPort) & HOLDING_REGISTER_BUSY)
> >         continue;
> > >     *pDataPort = 'o';
> >     while((*pControlPort) & HOLDING_REGISTER_BUSY)
> >         continue;
> > >     *pDataPort = '\r';
> >     while((*pControlPort) & HOLDING_REGISTER_BUSY)
> >         continue;
> >     *pDataPort = '\n';
> > >   }
> >
> > Note the inclusion of LineFeed as well.
> > If the Holding register flag is inverted then you must also invert the
> > test.
> >
> > Jim Dempsey
> >
> > ----- Original Message -----
> > From: "Michael McAllister" <mmcallister@annapmicro.com>
> > To: <openrisc@opencores.org>
> > Sent: Monday, April 21, 2003 8:37 AM
> > Subject: [openrisc] First steps
> >
> >
> > > I am working on getting the OpenRISC 1200 (ORPsoc from the Xess
> Xsv-800
> > > demo) running on a Virtex 2000E-based FPGA board.  This board also
> has
> > > SRAM & a serial port.  The hardware & firmware guys have
> successfully
> > > synthesized and place & routed the microprocessor in the Viretx FPGA
> > > with the UART IP Core and w/o the MMU; it's my job to get the s/w
> > > working.
> > >
> > > I have the ability to read & write SRAM from a host computer,
> > > independent of the FPGA.  My thought was to get a "hello world" kind
> of
> > > program running by loading the program into the FPGA board's SRAM,
> > > loading the FPGA with the OpenRISC processor, taking the processor
> out
> > > of reset, and seeing it write HELLO out to the serial port in an
> endless
> > > loop.  For this initial test, I thought it might be easier if I
> write
> > > some code that directly sets up the UART, and NOT try to get uCLinux
> up
> > > and running right away (though that is the eventual goal).
> > >
> > > I am told by the firmware guy that the UART is at address 0x90h.  I
> have
> > > recompiled the GNU tools & DDD & uCLinux & uclibc, etc, on a Linux
> box.
> > > I am wondering if I can just write a simple 'C' program:
> > >
> > > #define SERIAL_PORT_DATA    0x00000090ul   /* Serial Prot Data
> Register
> > > */
> > > #define SERIAL_PORT_CONTROL 0x00000093ul   /* Line Control Register
> > > (LCR) */
> > >
> > > int main ()
> > > {
> > >   char *pDataPort;
> > >   char *pControlPort;
> > >
> > >   pControlPort = SERIAL_PORT_CONTROL;
> > >   pDataPort    = SERIAL_PORT_DATA;
> > >
> > >   *pControlPort = 0x10; /* Set the LCR divisor latch (DL) bit */
> > >   *(pDataPort+2)= 0x0;
> > >   *(pDataPort+1)= 0x41; /* LSB of DL is set; internal counter starts
> */
> > >   *pControlPort = 0x0;  /* Clear the LCR divisor latch bit */
> > >
> > >   while (1)  {
> > >     *pDataPort = 'H';       /* Send hello forever */
> > >     *pDataPort = 'e';
> > >     *pDataPort = 'l';
> > >     *pDataPort = 'l';
> > >     *pDataPort = 'o';
> > >     *pDataPort = '\r';
> > >   }
> > >
> > >   return(0);
> > > }
> > >
> > > Load it into the SRAM, and see it start writing data to the output
> TX
> > > line?
> > >
> > > Any ideas if this will work?  What intermediary steps must be done
> to
> > > the "a.out" ELF file from gcc... is there a utility to convert it to
> > > plain old machine code that can be directly executed? Is there a
> "newbie
> > > FAQ"?  If not, I am volunteering to write one about my experiences.
> > >
> > >
> > > Sincerely,
> > > Michael McAllister
> > >
> > > --
> > > To unsubscribe from openrisc mailing list please visit
> > http://www.opencores.org/mailinglists.shtml
> >
> > --
> > To unsubscribe from openrisc mailing list please visit
> > http://www.opencores.org/mailinglists.shtml
>
> --
> To unsubscribe from openrisc mailing list please visit
> http://www.opencores.org/mailinglists.shtml
>

--
To unsubscribe from openrisc mailing list please visit http://www.opencores.org/mailinglists.shtml