File:  [Net/2] / Net2 / arch / amiga / dev / grf_cc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:18:14 2018 UTC (8 years, 3 months ago) by root
Branches: NetBSD, MAIN
CVS tags: NetBSD09, HEAD
NetBSD 0.9

#include "grf.h"
#if NGRF > 0

/* Graphics routines for the AMIGA native custom chip set. */

#include "sys/param.h"
#include "sys/errno.h"

#include "grfioctl.h"
#include "grfvar.h"
#include "grf_ccreg.h"

#include "../include/cpu.h"
#include "../amiga/custom.h"


extern caddr_t CHIPMEMADDR;
extern caddr_t chipmem_steal ();

struct ccfb ccfb = {
	DEF_DISP_WIDTH, DEF_DISP_HEIGHT, DEF_DISP_X, DEF_DISP_Y, DEF_DISP_Z,
	0,
	DEF_FB_WIDTH, DEF_FB_HEIGHT, DEF_FB_X, DEF_FB_Y, DEF_FB_Z,
	DEF_COL0, DEF_COL1
};

/* Initialize one copper list.  We'll need two to make a nice interlaced display.  */

/* maximum size needed for a copper list (4 planes hires laced) */
#define COPENTS (4 * (2 * 4 + 2 + 1 + 2 + 2 + 2 + 16 * 1 + 1))

/* copper instructions */
#define MOVE(cl, reg, val)  \
	do { *cl++ = CUSTOM_OFS(reg); *cl++ = val; } while (0)
#define WAIT(cl, vp, hp, bfd, ve, he) \
	do { *cl++ = ((vp & 0xff)<<8)|(hp & 0xfe)|1; \
	*cl++ = (bfd<<15)|((ve & 0x7f)<<8)|(hp & 0xfe)|1; } while (0)
#define STOP(cl) \
	do { *cl++ = 0xffff; *cl++ = 0xffff; } while (0)

static void 
initcop (cop, othercop, shf, fb)
	u_short *cop;
	u_short *othercop;
	int	shf;
	struct ccfb *fb;
{
  long scrmem;
  int i;
  u_short c, strt, stop, *orig_cop = cop;

  /* get PA of display area */
  scrmem = (long) fb->fb - (long) CHIPMEMADDR;

  othercop = (u_short *) ((long)othercop - (long) CHIPMEMADDR);
  
  /* account for possible interlaced half-frame */
  if (shf)
    scrmem += fb->fb_width >> 3;
    
  /* account for oversized framebuffers */
  scrmem += (fb->fb_x >> 3) + (fb->fb_y * (fb->fb_width >> 3));  

  /* initialize bitplane pointers for all planes */
  /* remember offset in copperlist to patch later */
  if (! fb->bplstart_off)
    fb->bplstart_off = cop - orig_cop;
  for (i = 0; i < fb->disp_z; i++)
    {
      MOVE (cop, bplpth(i), scrmem >> 16);
      MOVE (cop, bplptl(i), scrmem & 0xffff);
      scrmem += (fb->fb_width >> 3) * fb->fb_height;
    }

  /* modulo is one line for interlaced displays, plus difference between
     virtual and effective framebuffer size */
  MOVE (cop, bpl1mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3); 
  MOVE (cop, bpl2mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
  
  c =   0x8000 				/* HIRES */
      | ((fb->disp_z & 7) << 12)	/* bitplane use */
      | 0x0200				/* composite COLOR enable (whatever this is..) */
      | 0x0004;				/* LACE */
        
  MOVE (cop, bplcon0, c);
  
  /* these use pre-ECS register interpretation. Might want to go ECS ? */
  strt = (((fb->disp_y >> 1) & 0xff)<<8) | ((fb->disp_x >> 1) & 0xff);
  MOVE (cop, diwstrt, strt);
  stop = (((((fb->disp_y + fb->disp_height + 1-shf)>>1) & 0xff)<<8)
          | (((fb->disp_x + fb->disp_width)>>1) & 0xff));
  MOVE (cop, diwstop, stop);
  /* NOTE: default values for strt: 0x2c81, stop: 0xf4c1 */

  /* these are from from HW-manual.. */
  strt = ((strt & 0xff) - 9) >> 1;
  MOVE (cop, ddfstrt, strt);
  stop = strt + (((fb->disp_width >> 4) - 2) << 2);
  MOVE (cop, ddfstop, stop);

  /* setup interlaced display by constantly toggling between two copperlists */
  MOVE (cop, cop1lch, (long)othercop >> 16);
  MOVE (cop, cop1lcl, (long)othercop & 0xffff);

  for (i = 0; i < (1 << fb->disp_z); i++)
    MOVE (cop, color[i], fb->col[i]);

  /* wait forever */
  STOP (cop);
}


#ifdef DEBUG
void
dump_copperlist (cl)
    u_int *cl;
{
  while (*cl != 0xffffffff)
    {
      if (!(*cl & 0x00010000))
        printf ("MOVE (%x, %x)\t", *cl & 0xffff, *cl >> 16);
      else
        printf ("WAIT (%d, %d, %d, %d, %d)\t", *cl >> 24, (*cl & 0x00fe0000)>>16,
		(*cl & 0x8000)>> 15, (*cl & 0x7f00)>>8, (*cl & 0xfe));
      cl++;
    }
  printf ("STOP ()\n");

}
#endif


/*
 * Initialize hardware.
 * Must point g_display at a grfinfo structure describing the hardware.
 * Returns 0 if hardware not present, non-zero ow.
 */
cc_init(gp, ad)
	struct grf_softc *gp;
	struct amiga_device *ad;
{
  register struct ccfb *fb = &ccfb;
  struct grfinfo *gi = &gp->g_display;
  u_char *fbp, save;
  int fboff, fbsize;
  int s;

  /* if already initialized, fail */
  if (fb->fb)
    return 0;

  /* testing for the result is really redundant because chipmem_steal
     panics if it runs out of memory.. */
  fbsize = (fb->fb_width >> 3) * fb->fb_height * fb->fb_z;
  if (! (fb->fb = (u_char *) chipmem_steal (fbsize))
      || !(fb->cop1 = (u_short *) chipmem_steal (COPENTS))
      || !(fb->cop2 = (u_short *) chipmem_steal (COPENTS)))
    return 0;

  /* clear the display. bzero only likes regions up to 64k, so call multiple times */
  for (fboff = 0; fboff < fbsize; fboff += 64*1024)
    bzero (fb->fb + fboff, fbsize - fboff > 64*1024 ? 64*1024 : fbsize - fboff);

  initcop (fb->cop1, fb->cop2, 0, fb);
  initcop (fb->cop2, fb->cop1, 1, fb);

  /* Make sure no ex-sprites are streaking down the screen */
  {
    int i;
    for(i = 0;i < 8;i++)
      {
        custom.spr[i].data = 0;
        custom.spr[i].datb = 0;
      }
  }

  /* start the new display */
  /* disable these */
  custom.dmacon  = (DMAF_BLTDONE | DMAF_BLTNZERO | DMAF_BLITHOG | DMAF_BLITTER
		    | DMAF_SPRITE | DMAF_DISK
 		    | DMAF_AUD3 | DMAF_AUD2 | DMAF_AUD1 | DMAF_AUD0);
  /* enable these */
  custom.dmacon  = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER;

#if 0
  /* ok, this is a bit rough.. */
  s = splhigh ();
  /* load a first guess copperlist, verify later whether we got the right
     one */
  custom.cop1lc  = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
  custom.copjmp1 = 0;
  /* reset VBL */
  custom.intreq = INTF_VERTB;
  /* wait for VBL */
  while (! (custom.intreqr & INTF_VERTB)) ;
  /* reset VBL */
  custom.intreq = INTF_VERTB;
  /* now, in a safe location, set correct copperlist based on longframe/shortframe
     bit */
  if (custom.vposr & 0x8000)
    {
      custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
      custom.copjmp1 = 0;	/* strobe it */
    }
  else
    {
      custom.cop1lc = (void *) ((long)fb->cop2 - (long) CHIPMEMADDR);
      custom.copjmp1 = 0;
    }
  /* wait for another VBL and reset int, then go back to previous int level */
  while (! (custom.intreqr & INTF_VERTB)) ;
  custom.intreq = INTF_VERTB;
  splx (s);
#else
  s = splhigh();
  /* set up copper */
  custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
  custom.copjmp1 = 0;

  /* reset vertical blank interrupt */
  custom.intreq = INTF_VERTB;

  /* wait for vertical blank interrupt */
  while ((custom.intreqr & INTF_VERTB) != INTF_VERTB)
	;

  /* set bitplane pointers based on LOF/SHF bit */
  if (custom.vposr & 0x8000)
    {
      custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
      custom.copjmp1 = 0;
    }
  else
    {
      custom.cop1lc = (void *) ((long)fb->cop2 - (long) CHIPMEMADDR);
      custom.copjmp1 = 0;
    }
  splx (s);
#endif

  /* tame the blitter. Copying one word onto itself should put it into
     a consistent state. This is black magic... */
  custom.bltapt =
    custom.bltbpt =
      custom.bltcpt =
        custom.bltdpt = 0;
  custom.bltamod =
    custom.bltbmod =
      custom.bltcmod =
        custom.bltdmod = 0;
  custom.bltafwm =
    custom.bltalwn = 0xffff;
  custom.bltcon0 = 0x09f0;
  custom.bltcon1 = 0;
  custom.bltsize = 1;

  /* enable VBR interrupts. This is also done in the serial driver, but it
     really belongs here.. */
  custom.intena = INTF_SETCLR | INTF_VERTB;

#if 0
#ifdef DEBUG
  /* prove the display is up.. */
  for (fboff = 0; fboff < fbsize; fboff++)
    {
      fb->fb[fboff] = 0xff;
      DELAY(10);
    }
  for (fboff = 0; fboff < fbsize; fboff++)
    {
      fb->fb[fboff] = 0;
      DELAY(10);
    }
#endif
#endif

  gi->gd_regaddr = (caddr_t) fb;	/* XXX */
  gi->gd_regsize = 0;

  gi->gd_fbaddr  = fb->fb - (u_char *) CHIPMEMADDR;
  gi->gd_fbsize  = fbsize;
  
  gi->gd_colors  = 1 << fb->fb_z;
  gi->gd_planes  = fb->fb_z;
  
  gi->gd_fbwidth  = fb->fb_width;
  gi->gd_fbheight = fb->fb_height;
  gi->gd_fbx	  = fb->fb_x;
  gi->gd_fby	  = fb->fb_y;
  gi->gd_dwidth   = fb->disp_width;
  gi->gd_dheight  = fb->disp_height;
  gi->gd_dx	  = fb->disp_x;
  gi->gd_dy	  = fb->disp_y;
  
  gp->g_regkva = 0;	/* builtin */
  gp->g_fbkva  = fb->fb;
  
  return(1);
}

cc_config(gp, di)
	register struct grf_softc *gp;
	struct grfdyninfo *di;
{
  register struct ccfb *fb = &ccfb;
  struct grfinfo *gi = &gp->g_display;
  u_char *fbp, save;
  int fboff, fbsize;
  int s;

  /* bottom missing... */

}

/*
 * Change the mode of the display.
 * Right now all we can do is grfon/grfoff.
 * Return a UNIX error number or 0 for success.
 */
cc_mode(gp, cmd, arg)
	register struct grf_softc *gp;
	int cmd;
	void *arg;
{
  switch (cmd)
    {
    case GM_GRFON:
      custom.dmacon  = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER;
      return 0;
      
    case GM_GRFOFF:
      custom.dmacon  = DMAF_RASTER | DMAF_COPPER;
      return 0;
      
    case GM_GRFCONFIG:
      return cc_config (gp, (struct grfdyninfo *) arg);

    default:
      break;
    }
    
  return EINVAL;
}

#endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.