Can anyone build Lydux's Human68k toolchain?

Started by kamiboy, January 22, 2016, 09:21:51 PM

Previous topic - Next topic

kamiboy

So, here is the thing. Master Lydux has gone off of the grid it seems, and I've found a couple of bugs in his toolchain that prevents the use of some DOS and IOCTS library calls from C.

The source code for newlib, where the bugs are located, is here: https://github.com/Lydux/newlib-1.19.0-human68k

I can download the source code and fix the bugs, but I cannot build the damn thing since it requires linux.

So if anyone is capable of building newlib and willing to help I could fix the bugs I find and forward you the modified code so you can build a new corrected version of newlib for the benifit of maybe a handful of people among the 6+ billion currently on this planet. A worthy cause if I ever saw one.

elmer

Quote from: kamiboy on January 22, 2016, 09:21:51 PM
I can download the source code and fix the bugs, but I cannot build the damn thing since it requires linux.

I've built GCC 4.5 and 4.7 cross-compilers on Windows before, so I'm taking a look at building lydux's toolchain.

It would be nice if you can PM me your bug fix ... and then we'll see if I can get it all working.

FYI ... it should build on Windows if you install msys2 ... but getting the right compiler options can be a real PITA.

kamiboy

Remembering those dark days where I gave Linux a chance, because all the uncool kids were doing it, I am reminded how painful it was to get anything to work on it, let alone build. So I can only imagine how much more complex it might become trying to get it to workd under a fake a linux like environment.

I'll get those bug fixes done and send you a link in a day or two, cheers.

kamiboy

So, attached are the corrected files. They should be unzipped inside the libdos folder, overwriting the old files. That folder is pretty nestled in, but can easily be found if you do a search for it since it is the only folder named that.

Unzip, build, if you can, and reply here with the resulting "libdos.a" and you have done humanity an invaluable service. Seriously, you can lett Peter at the gates know you did this and you are shoe in, hell, even Charon will give you a free ride over the old river, and he is a stingy old codger.

elmer

Quote from: kamiboy on January 23, 2016, 05:20:53 PM
Remembering those dark days where I gave Linux a chance, because all the uncool kids were doing it, I am reminded how painful it was to get anything to work on it, let alone build. So I can only imagine how much more complex it might become trying to get it to workd under a fake a linux like environment.

The whole GNU build system can never be sufficiently damned-to-hell.

And "yes", it gets even more obscure when you're doing a mingw32 build on Windows.

Even more amusing is that older binutils and older GCC compilers won't even build properly anymore with the latest versions of GCC and their surrounding tools.

Luckily, I've already been through most of this while adding V810 processor support to GCC 4.7.

It'll take a few days of messing around to get lydux's modified source to compile ... so I'm afraid that you'll have to give me a little time.

kamiboy

#5
No rush, mate. Take your time. I sure as deuce always do.

It bears mentioning that I am only interested in a new libdos build, which is where the fixes are located. You can safely ignore anything falling outside of that.

elmer

Quote from: kamiboy on January 24, 2016, 06:23:51 AM
It bears mentioning that I am only interested in a new libdos build, which is where the fixes are located. You can safely ignore anything falling outside of that.

Part of my interest is in making sure that the X68000 toolchain can still be built on modern systems, and that it doesn't just become "stale" in the way that the old V810 GCC 2.95 toolchain did for the PC-FX.

Try-as-I-might, I just can't get lydux's GCC 4.6.2 compiling, so I've isolated his changes from the original binutils and GCC distributions, and updated them up to apply to newer versions.

I've got binutils 2.23.2 and GCC 4.7.4 compiling with his patches, now I just need to fix the errors in the newlib build process (something is wrong with the makefile and it is ignoring the libdos and libiocs directories).

Not there yet, but there's progress.

elmer

Quote from: elmer on January 25, 2016, 04:33:33 AM
I've got binutils 2.23.2 and GCC 4.7.4 compiling with his patches, now I just need to fix the errors in the newlib build process (something is wrong with the makefile and it is ignoring the libdos and libiocs directories).

I really, really, really hate GNU autotools!!!

It's all compiling now, so here are the libs with your fixes ...

https://www.dropbox.com/s/ql5pc0wzb77z0y4/human68k-libs-kamiboy.zip?dl=0

They've been compiled with binutils 2.23.2 and GCC 4.7.4, but I don't see why they wouldn't work with your current GCC 4.6.2 setup.

I've included versions of the libs both with and without your fixes just so that you can confirm that they're building correctly (i.e. the old libs should fail in an identical way to what you're seeing now).

If you have a problem using the libs (old or new), then I can send you the entire toolchain binaries, and I can always rebuild with binutils 2.22.

Good luck, and please let me know if these work for you (or not).

elmer

Quote from: elmer on January 25, 2016, 04:33:33 AM
Try-as-I-might, I just can't get lydux's GCC 4.6.2 compiling, so I've isolated his changes from the original binutils and GCC distributions, and updated them up to apply to newer versions.

FYI ... for anyone else trying to build the lydux's version of GCC, the problem seems to be related to this post in the "Cross-Human68k toolchain" thread ...


Quote from: AnimaInCorpore on May 27, 2014, 10:58:00 PM
Quote from: lydux on May 27, 2014, 10:05:11 PM
Ok. Do you know if it's an Ubuntu specific or a generic GCC 4.8 issue ?

I am not really sure but it seems to be a GCC 4.8 issue. It was a crash like the one reported here: http://sourceforge.net/p/mspgcc/bugs/362/

I get the very same segfault when building lydux's old GCC 4.6.2/4.6.3 with the current GCC 5.3.0, which is why I've updated his patches to build on GCC 4.7.4 instead.

kamiboy

Elmer I can confirm that with the new doslib I can build. Unfortunately the function that I went through all this trouble for "_dos_files", does not seem to work. Or I do not understand how to use it. Calling it causes a program access fault.

Whether the function is not working correctly, or I am not using it correctly none can say.

elmer

Quote from: kamiboy on January 25, 2016, 08:57:41 AM
Elmer I can confirm that with the new doslib I can build. Unfortunately the function that I went through all this trouble for "_dos_files", does not seem to work. Or I do not understand how to use it. Calling it causes a program access fault.

Whether the function is not working correctly, or I am not using it correctly none can say.

I wish that I could help, but I don't even have an emulated X68000 set up yet.

It's going to be months before I get time to even begin doing some X68000 coding.  :-[

An access fault like that sounds like you're either trashing the stack, or, more likely, that those offsets that you've put into the "fixed" _dos_files code aren't actually correct.

But it could also easily be that my compiled library isn't pushing the C parameters on the stack in the same way as lydux's GCC4.6.2.

Are you able to call other dos functions correctly?

kamiboy

Yeah, I tested other functions in the library, and they work fine. To be honest I do not understand anything of 68000 assembler programming. My bug fixes were nothing more than renaming some labels that I discovered to be wrong, and the cause of some functions in the library not being available. Whether the functions themselves being correct or not I could not say, since I do not understand the assembly code, and even if I did there is the lack of documentation to wrangle with.

I wish we could get Lydux himself to materialize and shine some light on the subject.

exodusmodules

#12
Quote from: kamiboy on January 25, 2016, 05:41:36 PM
Yeah, I tested other functions in the library, and they work fine. To be honest I do not understand anything of 68000 assembler programming. My bug fixes were nothing more than renaming some labels that I discovered to be wrong, and the cause of some functions in the library not being available. Whether the functions themselves being correct or not I could not say, since I do not understand the assembly code, and even if I did there is the lack of documentation to wrangle with.

I wish we could get Lydux himself to materialize and shine some light on the subject.

If gaining knowledge of Motorola 68000 assembly is what you need, then you have an entire community of people here to help you, including me.

EDIT: See that the compiler issue was solved lol. Do you have the assembly sources? Upload them and I'll see what I can do.

kamiboy

Some of the assembly sources are already attached a few posts up. The one of interest is files.s or dos_files.s, I forget which.

But same behaviour with the closely related exfiles.s

If you want the full source go to the github link a few more links above and search for the doslib folder.

I could totally learn 68000 assembly if I put in the time or effort, but, well, you know how it is.

elmer

#14
Quote from: kamiboy on January 25, 2016, 05:41:36 PM
Yeah, I tested other functions in the library, and they work fine.

Thanks, that's good to know.

Since it's not the new compiler that's messing things up, then it's almost-certainly going to be the parameter-passing in the functions that you've "fixed".

The access fault makes it sound like the pointers that you're grabbing off the C stack and then pushing back on for the Human68k dos call, are being grabbed  from the wrong stack offset, and end up being "bad" pointers.

I can't just fix it myself since I'd need to trace through the code in a debugger to see the stack contents, but I'm sure that there's someone here that could do that for you.

If you can get the source code fixed, I can build you an updated library anytime.


Quote from: exodusmodules on January 26, 2016, 01:51:16 AM
EDIT: See that the compiler issue was solved lol. Do you have the assembly sources? Upload them and I'll see what I can do.

The source to the function fixes are earlier in this thread "libdos.zip".

And it looks like there may be some fixes out there to get GCC 4.6.2 compiling again ... but if GCC 4.7.4 is working fine, then I don't see much reason to spend the time to go backwards, unless someone can suggest one.


Quote from: kamiboy on January 26, 2016, 02:57:04 AM
I could totally learn 68000 assembly if I put in the time or effort, but, well, you know how it is.

If you know any other processor's assembly language, then you'll find the 68000 really, really easy (and pleasant).

If you're a high-level-language-only guy, then any assembly is going to be a nasty shock ... but it's something that I'd really recommend if you're interested in developing for 1980s/early-1990s machines like the X68000.

kamiboy

Once upon a time I dabbled in x86 assembly programming, so I know a bit. Also the stack thing you mentioned exactly mirrors my own suspicions. I would need to study 68000 assembly, stack argument passing etc in order to be able to draw any further conclusions, but I rather allocate my efforts elsewhere right now.

Also, remembering my days with assembly I would never want to program anything complex in that language. I strongly prefer to C in that regard, if you are smart about it you can get pretty good performance even on low end CPU's, and the code is much more easily human readable.

kamiboy

So, I decided to take a brief look at the library code for the _dos_files(...) function call. As expected my understanding of 68000 assembly is too feeble to be able to figure out why the function causes a segment fault.

| int _dos_files (struct _dos_filbuf *, const char *, int);
.text
.even
.global _dos_filbuf
.type _dos_filbuf,@function
_dos_filbuf:
   move.w   %sp@(14), %sp@-
   move.l   %sp@(10), %sp@-
   move.l   %sp@(10), %sp@-
   .short   0xff4e
   lea   %sp@(10), %sp
   rts


Seems all the function does is pop some values off of the stack and moving them to other parts of the stack.

the whole ".short   0xff4e" I do not understand. 0xff4e is the identifier for the doscall, but I am not sure how it is supposed to be used. Can anyone shed light on this? Below is the section about the "files" dos function.

----

$FF4E ; FILES(FILEBUF,NAMEPTR,PTR) Search for files (first file only)

Example:
   MOVE.W   #ATR,-(SP)
   PEA   NAMEPTR
   PEA   FILBUF
   DC.W   _FILES
   LEA   10(SP),SP
   ...
NAMEPTR:DC.B   '*.DOC',0

FILBUF:   DC.B   ATR
   DC.B   DRIVENO
   DC.W   DIRCLS
   DC.W   DIRFAT
   DC.W   DIRSEC
   DC.W   DIRPOS
   DC.B   FILENAME(8)
   DC.B   EXT(3)
   DC.B   ATR
   DC.W   TIME
   DC.W   DATE
   DC.L   FILELEN
   DC.B   PACKEDNAME(18,3),0
   * Total: 53 bytes

Returns:
   D0.L   Error code

Searches for a file (specified by NAMEPTR) which has the attributes
given by ATR, and writes its information to the FILEBUF buffer.

Wild cards are permitted for NAMEPTR.

The meaning of each ATR bit is as follows.
When 2 or more bits are set, upon searching either of those bits,
the operation ends (OR)

The individual bits of ATR are defined as follows:
15 to 06 : Ignored
05 : A - Archive
04 : D - Directory name
03 : V - Volume name
02 : S - System file
01 : H - Hidden file
00 : R - Read-only file

If multiple attributes are specified, any of them will satisfy the
search criteria, if found. For example, if ATR is 6, this subroutine
will search for files that have the S bit and/or H bit set.

Note that you cannot restore the stack with a single ADDQ.L
after this call returns; it is recommended to use LEA instead.


elmer

Quotethe whole ".short   0xff4e" I do not understand. 0xff4e is the identifier for the doscall, but I am not sure how it is supposed to be used. Can anyone shed light on this? Below is the section about the "files" dos function.

It causes a "line-f" unimplemented-instruction trap (as does executing any instruction in the range $Fxxx).

It's just a 68000 trick to switch into supervisor mode and call a function.

Human68k just puts an exception handler int the "line-f" exception vector and then takes a look at the instruction to itself to see what you wanted it to do.

Just think of it as a shorthand for an assembly "jsr", or a C "function()".


QuoteSeems all the function does is pop some values off of the stack and moving them to other parts of the stack.

Yes, that's all that it is doing.

On entry ...

sp+12 int32_t
sp+08 const char *
sp+04 struct _dos_filbuf *
sp+00 return address


After "move.w %sp@(14), %sp@-" ...

sp+14 int32_t
sp+10 const char *
sp+06 struct _dos_filbuf *
sp+02 return address
sp+00 int16_t


After "move.l %sp@(10), %sp@-" ...

sp+18 int32_t
sp+14 const char *
sp+10 struct _dos_filbuf *
sp+06 return address
sp+04 int16_t
sp+00 const char *


After "move.l %sp@(10), %sp@-" ...

sp+22 int32_t
sp+18 const char *
sp+14 struct _dos_filbuf *
sp+10 return address
sp+08 int16_t
sp+04 const char *
sp+00 struct _dos_filbuf *



So, assuming that the compiler is pushing the parameters on in the right order ... that should work.

Are you sure that you've allocated enough space for _dos_filbuf? And that the filename that you pass in is correct?

kamiboy

It is a search function, so no matter what file name you pass in it should not result in a crash. I'll attach a sample of my code later.

What puzzles me though is that the library function seems to take its third parameter as an int, but only pushes one word half copy of it on the stack for the dos call function, since it expects a word.

Why wouldn't the library function also just accept that parameter as a short? Why copy the parameters at all, they are already on the stack, couldn't the dos call happen immediately without copying?

Does he not need to pop all elements on the stack prior to the rts instruction at the end so the remaining item on the stack is the return instruction address?

kamiboy


elmer

#20
Quote from: kamiboy on February 03, 2016, 04:24:29 AM
It is a search function, so no matter what file name you pass in it should not result in a crash. I'll attach a sample of my code later.

Not everyone (including Hudson) writes code as well as you.

QuoteWhat puzzles me though is that the library function seems to take its third parameter as an int, but only pushes one word half copy of it on the stack for the dos call function, since it expects a word.

That just a sloppy definition by whoever created the libdos library (it might have come from the old public-domain X68000 "libc" source).

That's the sort of thing that should be cleared-up with stdint.h types.


QuoteWhy wouldn't the library function also just accept that parameter as a short?

The assembly language assumes that it has been passed as a 32-bit value. You'd have to change both the assembly-language, and the C prototype.


QuoteWhy copy the parameters at all, they are already on the stack, couldn't the dos call happen immediately without copying?

Because there's a "return" address in the way.


QuoteDoes he not need to pop all elements on the stack prior to the rts instruction at the end so the remaining item on the stack is the return instruction address?

???

The "lea %sp@(10), %sp" pops all of the values that are passed to the Human68k _dos function.

The parameters that are passed to the assembly-language shim by the C code are cleaned-up on return from the function by a "lea %sp@(12), %sp" that the compiler generates.

Horribly inefficient ... but that's because the Human68k calling interface was designed for assembly-language programming and not C programming.

**************

BTW ... are you ABSOLUTELY sure that you are allowed to pass in "A:\*.*" as a filename to that particular Human68k function?

It looks to me like it was probably designed to only work on the contents of the current directory (that you set with _dos_chdir).

kamiboy

#21
I think you are correct about _dos_chdir, I had noticed that myself. But that is not the problem because I just found out what was wrong.

On a whim I decided to declare the struct as a pointer, then allocate memory for it using malloc, instead of using a local variable.

Calling files with the address of the allocated memory now no longer causes a segment fault. I guess the memory space of the struct will not be valid for use by the dos function unless it is decalred using malloc.

Anyway, thanks for the help.

elmer

When compiling the source that you posted with my new GCC 4.7.4 cross-compiler, I get this error ...

$ human68k-gcc main.c
main.c: In function 'main':
main.c:11:21: error: storage size of 'fbuffer' isn't known



That's because at line 11, you've got ...

  struct _dos_filbuf fbuffer;


You've made a typo.

The structure defined in <dos.h> is called "dos_filbuf" and not "_dos_filbuf".

I guess that lydux's GCC 4.6.2 saw that as a definition of a new structure "_dos_filbuf" with a zero size.

So when you pass that to _dos_files(), it ends up overwriting 53 bytes of your stack space, and BOOM!

Basically, you made a small mistake, and the compiler should have caught it ... but it didn't.

Wow, GCC 4.6 was not a good release!

kamiboy

Dang, that explains everything. I knew I should have done a printf of the struct size as a test.

This is why you should be careful when working with struct variables that require the struct parameter as part of a new variable definition. When I make structs I make sure you can define an instance by just using the struct variabel name alone, without the need for the struct parameter.

The way struct definitions work in c has always baffled me, really.

Oh, well, it is always the tiny obvious mistakes that end up eating days of your time.

kamiboy

Ok, it turns out that was not actually the problem. I just fixed my code with the proper name of the variable and the same problem persists.

It seems the reason why my previous code was not throwing up errors was because in my dos.h there actually was a struct named _dos_filebuf

It was declared as jus a copy paste of dos_filebuf, so they were interchangable in the code.

I am sure I made that copy while trying to figure out the reason for the crash and forgot to remove it.

It is removed now, and my code corrected to use the proper struct but the crash persists when I use a locally allocated struct, but vanishes when I use a pointer allocated with malloc.

My theory is that perhaps the addressing scheme of local variables work differently. Maybe they use 16bit addresses. Or maybe the address space of local variables are not accessible by dos functions. I don't know enough about how the 68000 cpu, human68k or the gnu compiler to make a qualified guess.

Bottom line, when using this function use malloc allocated structs.

elmer

Quote from: kamiboy on February 03, 2016, 06:00:06 PM
Ok, it turns out that was not actually the problem. I just fixed my code with the proper name of the variable and the same problem persists.

Dang, there goes a good theory!   :-[

I guess that I'll have to actually trace through the compiled code in XM6Pro to see what's going wrong.

kamiboy

Not for my sake, I can use the function now that I figured how to make it happy.

elmer

Quote from: kamiboy on February 04, 2016, 03:25:06 AM
Not for my sake, I can use the function now that I figured how to make it happy.

But you're relying on "voodoo magic" to make it work ... that's not good.

There's nothing special about "local" (i.e. stack-based) variables on a 68000 CPU ... there must be a simple explanation.

And here it is in the compiled code ...

main:   link %fp,#-56
        pea 16:w
        pea .LC0
        moveq #-53,%d0
        addl %fp,%d0
        movel %d0,%sp@-
        jsr dos_files
        lea %sp@(12),%sp


The culprit is the "moveq #-53,%d0" instruction, which gives fbuffer an odd-byte aligned address when it's passed to dos_files().

That causes a bus-access error when used to read 16-bit and 32-bit values from the structure.

That's a classic structure alignment error, cause by the dos_filbuf being declared as 53 bytes long instead of 54 bytes long.

You just need to add alignment info to the structure declarations in <dos.h> ...

struct dos_dpbptr {
   unsigned char   drive;
   unsigned char   unit;
   unsigned short   byte;
   unsigned char   sec;
   unsigned char   shift;
   unsigned short   fatsec;
   unsigned char   fatcount;
   unsigned char   fatlen;
   unsigned short   dircount;
   unsigned short   datasec;
   unsigned short   maxfat;
   unsigned short   dirsec;
   int      driver;
   unsigned char   ide;
   unsigned char   flg;
   struct dos_dpbptr *next;
   unsigned short   dirfat;
   char      dirbuf[64];
} __attribute__((__packed__)) __attribute__ ((aligned (2)));

struct dos_filbuf {
   unsigned char   searchatr;
   unsigned char   driveno;
   unsigned long   dirsec;
   unsigned short   dirlft;
   unsigned short   dirpos;
   char      filename[8];
   char      ext[3];
   unsigned char   atr;
   unsigned short   time;
   unsigned short   date;
   unsigned int   filelen;
   char      name[23];
} __attribute__((__packed__)) __attribute__ ((aligned (2)));

struct dos_exfilbuf {
   unsigned char   searchatr;
   unsigned char   driveno;
   unsigned long   dirsec;
   unsigned short   dirlft;
   unsigned short   dirpos;
   char      filename[8];
   char      ext[3];
   unsigned char   atr;
   unsigned short   time;
   unsigned short   date;
   unsigned int   filelen;
   char      name[23];
   char      drive[2];
   char      path[65];
   char      unused[21];
} __attribute__((__packed__)) __attribute__ ((aligned (2)));


You're not seeing the problem when you "malloc" the buffer because all "malloc"'d memory is at least 2-byte aligned (probably 4-byte).

kamiboy

And that solves the adventure of the misaligned struct, it was NOT quite elementary.

The reason why this alignment is necessary goes above my head, and honestly these kinds of esoteric bugs are the stuff og nightmares.

neozeed

I'd love to help!



.I'm starting to get in a 68000 mood again

kamiboy

What exactly can you help with? Would be good to know your area of x68000 expertise.

mikewolak

I've recently built the human68k 4.6.2 cross compiler and compiled the 1st 2 DMA example listed in the Inside X68000 book. The first example seems to work but the second example uses some functions that are not included in the cross compiler.

From what I can tell in the 4.6.2 cross-compiler, the dos.h and iocs.h functions are prefixed with _ (underscores), for example the original Inside 68000 code calls SUPER(0) which I believe maps to _dos_super(0) however there's a call to screen(1,3,1,1), does anyone know what that maps to in the cross-compiler? My guess was _iocs_b_consol(1,3,1,1) but I get the same crash after the example runs for 15-20 seconds on my X68030 even if I comment out that line.

Below is the example I am working with (transcribed from pages 66-69 of the Inside X68000 book). It's been slightly modified to work with GCC 4.6.2


/* * List 3: Rectangular area transfer of
  * graphics screen using link array chain mode. *
 * XC does not support volatile, so
 * insert the following line: disable volatile by *
 * #define volatile */

#include <dos.h>
#include <iocs.h>

struct DMAREG {
    unsigned char  csr;
    unsigned char  cer;
    unsigned short spare1;
    unsigned char  dcr;
    unsigned char  ocr;
    unsigned char  scr;
    unsigned char  ccr;
    unsigned short spare2;
    unsigned short mtc;
    unsigned char  *mar;
    unsigned long  spare3;
    unsigned char  *dar;
    unsigned short spare4;
    unsigned short btc;
    unsigned char  *bar;
    unsigned long  spare5;
    unsigned char  spare6;
    unsigned char  nlv;
    unsigned char  spare7;
    unsigned char  elv;
    unsigned char  spare8;
    unsigned char  mfc;
    unsigned short spare9;
    unsigned char  spare10;
    unsigned char  cpr;
    unsigned short spare11;
    unsigned char  spare12;
    unsigned char  dfc;
    unsigned long  spare13;
    unsigned short spare14;
    unsigned char  spare15;
    unsigned char  bfc;
    unsigned long  spare16;
    unsigned char  spare17;
    unsigned char  gcr;
};

struct XFRINF {
    unsigned short *adrs;
    unsigned short length;
};

struct XFRINF xfr_inf[512];

unsigned short databuf[256*256];
volatile struct DMAREG *dma;
unsigned short src_data;

int  main();
void init_screen();
void dma_box();
void dma_setup();
void dma_start();
void wait_complete();
void clear_flag();


int  main()
{
    int i;
    _iocs_b_consol(1,3,1,1);
    /* screen(1,3,1,1);  */
    _dos_super(0);
    /* SUPER(0); */
    init_screen();
    for(i=0;i<255;i+=4)
        dma_box(databuf,255-i,i,511-i,i+256,0xffff);

    return(0);
}

void init_screen()
{
    unsigned short *vram, *buf;
    unsigned int i,h,s,v;
    vram = (unsigned short *) 0xc00000;
    for(i=0; i<512*512;i++) {
        s = i&0x1f;
        v = (i>>5) & 0x1f;
        h = ((i>>10) % 0xc0);
        *vram++ = _iocs_hsvtorgb (h,s,v);
    }

    vram = (unsigned short *) 0xc00000;
    buf = databuf;
    for(i=0; i<256*256; i++)
        *buf++ = *vram++;
}

void dma_box(buf, x1, y1, x2, y2, col)
    unsigned short *buf;
    unsigned int x1,y1,x2,y2,col;
 {
    int i,xlen,ylen;
    unsigned short *sadrs;
    xlen = x2 - x1;
    ylen = y2 - y1;
    src_data = col;
    sadrs = (unsigned short *) 0xc00000;
    sadrs += 512*y1+x1;

    for(i=0; i<=ylen; i++, sadrs+=512) {
        xfr_inf[i].adrs = sadrs;
        xfr_inf[i].length = xlen;
    }
    dma = (struct DMAREG*) 0xe84080;
    clear_flag();
    dma_setup(buf,ylen+1);
    dma_start();
    wait_complete();
    clear_flag();
 }   

void dma_setup(bufadrs, links)
    unsigned short *bufadrs;
    unsigned int    links;
 {
    dma->dcr = 0x08;
    dma->ocr = 0x99;
    dma->scr = 0x05;
    dma->ccr = 0x00;
    dma->cpr = 0x03;
    dma->mfc = 0x05;
    dma->dfc = 0x05;
    dma->bfc = 0x05;

    dma->btc = links;
    dma->dar = (unsigned char *) bufadrs;
    dma->bar = (unsigned char *) xfr_inf;
}

void dma_start()
{
    dma->ccr |= 0x80;
}

void wait_complete()
{
    while(!(dma->csr & 0x90));
}

void clear_flag()
{
    dma->csr = 0xff;
}