mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 11:02:59 -04:00
1820 lines
56 KiB
C
1820 lines
56 KiB
C
/* $Id: sun-cgtwo.c,v 1.8 2010/06/05 19:18:05 fredette Exp $ */
|
|
|
|
/* machine/sun/sun-cgtwo.c - Sun cgtwo emulation: */
|
|
|
|
/*
|
|
* Copyright (c) 2003, 2004, 2005 Matt Fredette
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <tme/common.h>
|
|
_TME_RCSID("$Id: sun-cgtwo.c,v 1.8 2010/06/05 19:18:05 fredette Exp $");
|
|
|
|
/* includes: */
|
|
#include <tme/machine/sun.h>
|
|
#include <tme/generic/bus-device.h>
|
|
#include <tme/generic/fb.h>
|
|
#include "sun-fb.h"
|
|
|
|
/* macros: */
|
|
|
|
/* cgtwo types: */
|
|
#define TME_SUNCG2_TYPE_NULL (0)
|
|
#define TME_SUNCG2_TYPE_SUN3 (1)
|
|
|
|
/* a cgtwo has eight planes: */
|
|
#define TME_SUNCG2_PLANE_MAX (8)
|
|
|
|
/* every rasterop unit has its alternate, prime registers: */
|
|
#define TME_SUNCG2_ROPC_PRIME (9)
|
|
|
|
/* every so many CSR reads, we fake a retrace: */
|
|
#define TME_SUNCG2_CYCLE_RETRACE (10)
|
|
|
|
/* this gives the index into the entire colormap of a pixel's
|
|
intensity for a given primary: */
|
|
#define TME_SUNCG2_CMAP_INDEX(pixel, primary) ((((primary) - TME_SUNCG2_REG_CMAP_R) / sizeof(tme_uint16_t)) + (pixel))
|
|
|
|
/* this gives a pixel's intensity for a given primary: */
|
|
#define TME_SUNCG2_CMAP_VALUE(suncg2, pixel, primary) \
|
|
(tme_betoh_u16((suncg2)->tme_suncg2_cmap_raw[TME_SUNCG2_CMAP_INDEX(pixel, primary)]) & 0xff)
|
|
|
|
/* a plane bitmap has one bit per pixel: */
|
|
#define TME_SUNCG2_REG_BITMAP(x) (0x000000 + (TME_SUNCG2_SIZ_BITMAP * (x)))
|
|
#define TME_SUNCG2_SIZ_BITMAP ((1024 * 1024) / 8)
|
|
|
|
/* the pixmap has one byte per pixel: */
|
|
#define TME_SUNCG2_REG_PIXMAP (0x100000)
|
|
#define TME_SUNCG2_SIZ_PIXMAP (1024 * 1024)
|
|
|
|
/* the raster op data: */
|
|
#define TME_SUNCG2_REG_ROP_DATA (0x200000)
|
|
|
|
/* register offsets and sizes. many registers are decoded at all
|
|
size-aligned addresses within a 4KB page: */
|
|
#define TME_SUNCG2_SIZ_REG_PAGE (0x001000)
|
|
#define TME_SUNCG2_REG_ROPC_UNIT(x) (0x300000 + ((x) * TME_SUNCG2_SIZ_REG_PAGE))
|
|
#define TME_SUNCG2_REG_ROPC_UNIT_PRIME(x) (TME_SUNCG2_REG_ROPC_UNIT(x) + 0x000800)
|
|
#define TME_SUNCG2_REG_CSR (0x309000)
|
|
#define TME_SUNCG2_REG_PLANE_MASK (0x30a000)
|
|
#define TME_SUNCG2_REG_SUN2_PAN_HI (0x30b000)
|
|
#define TME_SUNCG2_REG_SUN3_DOUBLE_BUF (0x30b000)
|
|
#define TME_SUNCG2_REG_SUN2_ZOOM (0x30c000)
|
|
#define TME_SUNCG2_REG_SUN3_DMA_BASE (0x30c000)
|
|
#define TME_SUNCG2_REG_SUN2_PAN_LO (0x30d000)
|
|
#define TME_SUNCG2_REG_SUN3_DMA_WIDTH (0x30d000)
|
|
#define TME_SUNCG2_REG_SUN2_ZOOM_VAR (0x30e000)
|
|
#define TME_SUNCG2_REG_SUN3_FRAME_COUNT (0x30e000)
|
|
#define TME_SUNCG2_REG_INTVEC (0x30f000)
|
|
#define TME_SUNCG2_REG_CMAP_R (0x310000)
|
|
#define TME_SUNCG2_REG_CMAP_G (0x310200)
|
|
#define TME_SUNCG2_REG_CMAP_B (0x310400)
|
|
#define TME_SUNCG2_SIZ_REGS (0x310600)
|
|
|
|
/* the bits in the Control/Status register: */
|
|
#define TME_SUNCG2_CSR_ENABLE_VIDEO (0x0001)
|
|
#define TME_SUNCG2_CSR_CMAP_UPDATE (0x0002)
|
|
#define TME_SUNCG2_CSR_INT_ENABLE (0x0004)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_MASK (0x0038)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_PRWWRD (0x0000)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_SRWPIX (0x0008)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_PWWWRD (0x0010)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_SWWPIX (0x0018)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_PRRWRD (0x0020)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_PRWPIX (0x0028)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_PWRWRD (0x0030)
|
|
#define TME_SUNCG2_CSR_ROP_MODE_PWWPIX (0x0038)
|
|
#define TME_SUNCG2_CSR_INT_ACTIVE (0x0040)
|
|
#define TME_SUNCG2_CSR_RETRACE (0x0080)
|
|
#define TME_SUNCG2_CSR_SIZE_MASK_SUN2 (0x0f00)
|
|
#define TME_SUNCG2_CSR_SIZE_MASK_SUN3 (0x0100)
|
|
#define TME_SUNCG2_CSR_SIZE_1152_900 (0x0000)
|
|
#define TME_SUNCG2_CSR_SIZE_1024_1024 (0x0100)
|
|
|
|
/* the raster ops: */
|
|
#define TME_SUNCG2_ROP_SRC (0xcc)
|
|
#define TME_SUNCG2_ROP_DST (0xaa)
|
|
#define TME_SUNCG2_ROP_NOT(x) ((x) ^ 0xff)
|
|
|
|
/* the callout flags: */
|
|
#define TME_SUNCG2_CALLOUT_CHECK (0)
|
|
#define TME_SUNCG2_CALLOUT_RUNNING TME_BIT(0)
|
|
#define TME_SUNCG2_CALLOUTS_MASK (-2)
|
|
#define TME_SUNCG2_CALLOUT_MODE_CHANGE TME_BIT(1)
|
|
#define TME_SUNCG2_CALLOUT_INT TME_BIT(2)
|
|
|
|
/* state flags: */
|
|
#define TME_SUNCG2_FLAG_INVALID_DISPLAYED TME_BIT(0)
|
|
#define TME_SUNCG2_FLAG_INVALID_PIXMAP TME_BIT(1)
|
|
#define TME_SUNCG2_FLAG_INVALID_BITMAPS TME_BIT(2)
|
|
#define TME_SUNCG2_FLAG_CALLOUT_THREAD_RUNNING TME_BIT(3)
|
|
|
|
/* structures: */
|
|
|
|
/* the card: */
|
|
struct tme_suncg2 {
|
|
|
|
/* our simple bus device header: */
|
|
struct tme_bus_device tme_suncg2_device;
|
|
#define tme_suncg2_element tme_suncg2_device.tme_bus_device_element
|
|
|
|
/* the mutex protecting the card: */
|
|
tme_mutex_t tme_suncg2_mutex;
|
|
|
|
/* the rwlock protecting the card: */
|
|
tme_rwlock_t tme_suncg2_rwlock;
|
|
|
|
/* the framebuffer connection: */
|
|
struct tme_fb_connection *tme_suncg2_fb_connection;
|
|
|
|
/* the callout flags: */
|
|
int tme_suncg2_callout_flags;
|
|
|
|
/* the type of the cgtwo: */
|
|
tme_uint32_t tme_suncg2_type;
|
|
|
|
/* the size of the bwtwo: */
|
|
tme_uint32_t tme_suncg2_size;
|
|
|
|
/* the number of displayed pixels: */
|
|
tme_uint32_t tme_suncg2_pixel_count;
|
|
|
|
/* the raw memory: */
|
|
tme_uint8_t *tme_suncg2_raw_memory;
|
|
|
|
/* the displayed memory: */
|
|
tme_uint8_t *tme_suncg2_displayed_memory;
|
|
|
|
/* the rasterop registers: */
|
|
struct {
|
|
tme_uint16_t tme_suncg2_ropc_dest;
|
|
tme_uint16_t tme_suncg2_ropc_source1;
|
|
tme_uint16_t tme_suncg2_ropc_source2;
|
|
tme_uint16_t tme_suncg2_ropc_pattern;
|
|
tme_uint16_t tme_suncg2_ropc_mask1;
|
|
tme_uint16_t tme_suncg2_ropc_mask2;
|
|
tme_uint16_t tme_suncg2_ropc_ena_shift;
|
|
tme_uint16_t tme_suncg2_ropc_op;
|
|
tme_uint16_t tme_suncg2_ropc_width;
|
|
tme_uint16_t tme_suncg2_ropc_opcount;
|
|
tme_uint16_t tme_suncg2_ropc_decoderout;
|
|
tme_uint16_t tme_suncg2_ropc_x11;
|
|
tme_uint16_t tme_suncg2_ropc_x12;
|
|
tme_uint16_t tme_suncg2_ropc_x13;
|
|
tme_uint16_t tme_suncg2_ropc_x14;
|
|
tme_uint16_t tme_suncg2_ropc_x15;
|
|
} tme_suncg2_ropc[TME_SUNCG2_ROPC_PRIME * 2];
|
|
|
|
/* our csr: */
|
|
tme_uint16_t tme_suncg2_csr;
|
|
|
|
/* our interrupt vector: */
|
|
tme_uint16_t tme_suncg2_intvec;
|
|
|
|
/* our plane mask: */
|
|
tme_uint16_t tme_suncg2_plane_mask;
|
|
|
|
/* the raw colormap: */
|
|
tme_uint16_t tme_suncg2_cmap_raw[(1 << TME_SUNCG2_PLANE_MAX) * 3];
|
|
|
|
/* the cooked colormap: */
|
|
tme_uint8_t tme_suncg2_cmap[(1 << TME_SUNCG2_PLANE_MAX) * 3];
|
|
|
|
/* if this is zero, the next CSR read will have the retrace bit set: */
|
|
unsigned int tme_suncg2_cycle_retrace;
|
|
|
|
/* if this is TME_SUNCG2_PLANE_MAX, we are displaying the pixmap,
|
|
else we are displaying this plane's bitmap: */
|
|
unsigned int tme_suncg2_bitmap_mode_plane;
|
|
|
|
/* state flags: */
|
|
unsigned int tme_suncg2_flags;
|
|
|
|
/* any outstanding TLBs: */
|
|
struct tme_token *tme_suncg2_tlb_tokens[4];
|
|
unsigned int tme_suncg2_tlb_head;
|
|
|
|
/* a rasterop buffered SRC value: */
|
|
tme_uint16_t tme_suncg2_rop_src_buffer;
|
|
};
|
|
|
|
/* globals: */
|
|
|
|
#ifndef TME_NO_LOG
|
|
static const char *_tme_suncg2_ropc_regs[] =
|
|
{ "dest",
|
|
"source1",
|
|
"source2",
|
|
"pattern",
|
|
"mask1",
|
|
"mask2",
|
|
"ena_shift",
|
|
"op",
|
|
"width",
|
|
"opcount",
|
|
"decoderout",
|
|
"x11",
|
|
"x12",
|
|
"x13",
|
|
"x14",
|
|
"x15",
|
|
};
|
|
#endif /* !TME_NO_LOG */
|
|
|
|
/* this invalidates any outstanding TLBs: */
|
|
static void
|
|
_tme_suncg2_tlb_invalidate(struct tme_suncg2 *suncg2, struct tme_bus_tlb *tlb_valid)
|
|
{
|
|
unsigned int tlb_i;
|
|
struct tme_token *token_valid;
|
|
struct tme_token *token;
|
|
|
|
token_valid = NULL;
|
|
if (tlb_valid != NULL) {
|
|
token_valid = tlb_valid->tme_bus_tlb_token;
|
|
}
|
|
|
|
for (tlb_i = 0; tlb_i < TME_ARRAY_ELS(suncg2->tme_suncg2_tlb_tokens); tlb_i++) {
|
|
token = suncg2->tme_suncg2_tlb_tokens[tlb_i];
|
|
suncg2->tme_suncg2_tlb_tokens[tlb_i] = NULL;
|
|
if (token != NULL
|
|
&& token != token_valid) {
|
|
tme_token_invalidate(token);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* this adds an outstanding TLB: */
|
|
static void
|
|
_tme_suncg2_tlb_add(struct tme_suncg2 *suncg2, struct tme_bus_tlb *tlb_valid)
|
|
{
|
|
struct tme_token *token_valid;
|
|
struct tme_token *token;
|
|
|
|
token_valid = tlb_valid->tme_bus_tlb_token;
|
|
|
|
token = suncg2->tme_suncg2_tlb_tokens[suncg2->tme_suncg2_tlb_head % TME_ARRAY_ELS(suncg2->tme_suncg2_tlb_tokens)];
|
|
if (token != NULL
|
|
&& token != token_valid) {
|
|
tme_token_invalidate(token);
|
|
}
|
|
suncg2->tme_suncg2_tlb_tokens[suncg2->tme_suncg2_tlb_head % TME_ARRAY_ELS(suncg2->tme_suncg2_tlb_tokens)] = token_valid;
|
|
suncg2->tme_suncg2_tlb_head++;
|
|
}
|
|
|
|
/* this validates the bitmaps: */
|
|
static void
|
|
_tme_suncg2_validate_bitmaps(struct tme_suncg2 *suncg2, struct tme_bus_tlb *tlb)
|
|
{
|
|
const tme_uint32_t *pixmap_pointer;
|
|
tme_uint32_t pixmap;
|
|
tme_uint32_t pixmap_resid;
|
|
tme_uint32_t bitmaps_lo;
|
|
tme_uint32_t bitmaps_hi;
|
|
tme_uint8_t *bitmap_pointer;
|
|
|
|
/* if the bitmaps are invalid: */
|
|
if (suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_BITMAPS) {
|
|
|
|
/* the pixmap must not be invalid: */
|
|
assert (!(suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_PIXMAP));
|
|
|
|
/* invalidate any outstanding TLBs: */
|
|
_tme_suncg2_tlb_invalidate(suncg2, tlb);
|
|
|
|
/* if we are displaying the pixmap: */
|
|
if (suncg2->tme_suncg2_bitmap_mode_plane == TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* if the displayed memory is not invalid: */
|
|
if (!(suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_DISPLAYED)) {
|
|
|
|
/* copy the displayed memory back into the pixmap: */
|
|
memcpy((suncg2->tme_suncg2_raw_memory
|
|
+ TME_SUNCG2_REG_PIXMAP),
|
|
suncg2->tme_suncg2_displayed_memory,
|
|
TME_SUNCG2_SIZ_PIXMAP);
|
|
}
|
|
}
|
|
|
|
/* otherwise, we're displaying a bitmap: */
|
|
else {
|
|
|
|
/* the displayed memory must be invalid: */
|
|
assert (suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_DISPLAYED);
|
|
}
|
|
|
|
/* start in the pixmap: */
|
|
pixmap_pointer = (tme_uint32_t *) (suncg2->tme_suncg2_raw_memory + TME_SUNCG2_REG_PIXMAP + TME_SUNCG2_SIZ_PIXMAP);
|
|
pixmap_resid = TME_SUNCG2_SIZ_PIXMAP;
|
|
pixmap = 0;
|
|
|
|
/* start in the bitmaps: */
|
|
bitmap_pointer = suncg2->tme_suncg2_raw_memory + TME_SUNCG2_REG_BITMAP(0) + TME_SUNCG2_SIZ_BITMAP;
|
|
bitmaps_lo = 0;
|
|
bitmaps_hi = 0;
|
|
|
|
/* do the translation: */
|
|
do {
|
|
|
|
/* if the pixmap data is empty, reload it: */
|
|
if (__tme_predict_false((pixmap_resid % sizeof(pixmap)) == 0)) {
|
|
pixmap = *(--pixmap_pointer);
|
|
pixmap = tme_betoh_u32(pixmap);
|
|
}
|
|
|
|
/* translate another pixel's bits into the bitmaps: */
|
|
bitmaps_lo >>= 1;
|
|
if (pixmap & TME_BIT(0)) bitmaps_lo |= 0x00000080;
|
|
if (pixmap & TME_BIT(1)) bitmaps_lo |= 0x00008000;
|
|
if (pixmap & TME_BIT(2)) bitmaps_lo |= 0x00800000;
|
|
if (pixmap & TME_BIT(3)) bitmaps_lo |= 0x80000000;
|
|
bitmaps_hi >>= 1;
|
|
if (pixmap & TME_BIT(4)) bitmaps_hi |= 0x00000080;
|
|
if (pixmap & TME_BIT(5)) bitmaps_hi |= 0x00008000;
|
|
if (pixmap & TME_BIT(6)) bitmaps_hi |= 0x00800000;
|
|
if (pixmap & TME_BIT(7)) bitmaps_hi |= 0x80000000;
|
|
|
|
/* we have translated another pixel: */
|
|
pixmap >>= 8;
|
|
pixmap_resid--;
|
|
|
|
/* after every eight pixels, we have another eight bytes of bitmap
|
|
data to write out: */
|
|
if (__tme_predict_false((pixmap_resid % 8) == 0)) {
|
|
bitmap_pointer--;
|
|
bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 0] = TME_FIELD_MASK_EXTRACTU(bitmaps_lo, 0x000000ff);
|
|
bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 1] = TME_FIELD_MASK_EXTRACTU(bitmaps_lo, 0x0000ff00);
|
|
bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 2] = TME_FIELD_MASK_EXTRACTU(bitmaps_lo, 0x00ff0000);
|
|
bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 3] = TME_FIELD_MASK_EXTRACTU(bitmaps_lo, 0xff000000);
|
|
bitmaps_lo = 0;
|
|
bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 4] = TME_FIELD_MASK_EXTRACTU(bitmaps_hi, 0x000000ff);
|
|
bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 5] = TME_FIELD_MASK_EXTRACTU(bitmaps_hi, 0x0000ff00);
|
|
bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 6] = TME_FIELD_MASK_EXTRACTU(bitmaps_hi, 0x00ff0000);
|
|
bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 7] = TME_FIELD_MASK_EXTRACTU(bitmaps_hi, 0xff000000);
|
|
bitmaps_hi = 0;
|
|
}
|
|
|
|
/* loop while we have pixmap bytes remaining: */
|
|
} while (pixmap_resid > 0);
|
|
|
|
/* the bitmaps are no longer invalid: */
|
|
suncg2->tme_suncg2_flags &= ~TME_SUNCG2_FLAG_INVALID_BITMAPS;
|
|
}
|
|
|
|
/* otherwise, the bitmaps are valid: */
|
|
else {
|
|
|
|
/* if our caller needs the actual raw bitmap memory valid
|
|
(indicated by tlb == NULL): */
|
|
if (tlb == NULL) {
|
|
|
|
/* invalidate any outstanding TLBs: */
|
|
_tme_suncg2_tlb_invalidate(suncg2, NULL);
|
|
|
|
/* if we're displaying a bitmap: */
|
|
if (suncg2->tme_suncg2_bitmap_mode_plane != TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* if the displayed memory is not invalid: */
|
|
if (!(suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_DISPLAYED)) {
|
|
|
|
/* copy the displayed memory back into the bitmap: */
|
|
memcpy((suncg2->tme_suncg2_raw_memory
|
|
+ TME_SUNCG2_REG_BITMAP(suncg2->tme_suncg2_bitmap_mode_plane)),
|
|
suncg2->tme_suncg2_displayed_memory,
|
|
TME_SUNCG2_SIZ_BITMAP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* this validates the pixmap: */
|
|
static void
|
|
_tme_suncg2_validate_pixmap(struct tme_suncg2 *suncg2, struct tme_bus_tlb *tlb)
|
|
{
|
|
tme_uint32_t *pixmap_pointer;
|
|
tme_uint32_t pixmap;
|
|
tme_uint32_t pixmap_resid;
|
|
tme_uint32_t bitmaps_lo;
|
|
tme_uint32_t bitmaps_hi;
|
|
const tme_uint8_t *bitmap_pointer;
|
|
|
|
/* if the pixmap is invalid: */
|
|
if (suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_PIXMAP) {
|
|
|
|
/* the bitmaps must not be invalid: */
|
|
assert (!(suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_BITMAPS));
|
|
|
|
/* invalidate any outstanding TLBs: */
|
|
_tme_suncg2_tlb_invalidate(suncg2, tlb);
|
|
|
|
/* if we are displaying a bitmap: */
|
|
if (suncg2->tme_suncg2_bitmap_mode_plane != TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* if the displayed memory is not invalid: */
|
|
if (!(suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_DISPLAYED)) {
|
|
|
|
/* copy the displayed memory back into the bitmap: */
|
|
memcpy((suncg2->tme_suncg2_raw_memory
|
|
+ TME_SUNCG2_REG_BITMAP(suncg2->tme_suncg2_bitmap_mode_plane)),
|
|
suncg2->tme_suncg2_displayed_memory,
|
|
TME_SUNCG2_SIZ_BITMAP);
|
|
}
|
|
}
|
|
|
|
/* otherwise, we're displaying the pixmap: */
|
|
else {
|
|
|
|
/* the displayed memory must be invalid: */
|
|
assert (suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_DISPLAYED);
|
|
}
|
|
|
|
/* start in the pixmap: */
|
|
pixmap_pointer = (tme_uint32_t *) (suncg2->tme_suncg2_raw_memory + TME_SUNCG2_REG_PIXMAP);
|
|
pixmap_resid = TME_SUNCG2_SIZ_PIXMAP;
|
|
pixmap = 0;
|
|
|
|
/* start in the bitmaps: */
|
|
bitmap_pointer = suncg2->tme_suncg2_raw_memory + TME_SUNCG2_REG_BITMAP(0);
|
|
bitmaps_lo = 0;
|
|
bitmaps_hi = 0;
|
|
|
|
/* do the translation: */
|
|
do {
|
|
|
|
/* if the bitmap data is empty, reload it: */
|
|
if (__tme_predict_false((pixmap_resid % 8) == 0)) {
|
|
bitmaps_lo
|
|
= ((((tme_uint32_t) bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 0]) << 0)
|
|
| (((tme_uint32_t) bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 1]) << 8)
|
|
| (((tme_uint32_t) bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 2]) << 16)
|
|
| (((tme_uint32_t) bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 3]) << 24));
|
|
bitmaps_hi
|
|
= ((((tme_uint32_t) bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 4]) << 0)
|
|
| (((tme_uint32_t) bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 5]) << 8)
|
|
| (((tme_uint32_t) bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 6]) << 16)
|
|
| (((tme_uint32_t) bitmap_pointer[TME_SUNCG2_SIZ_BITMAP * 7]) << 24));
|
|
bitmap_pointer++;
|
|
}
|
|
|
|
/* we are about to translate another pixel: */
|
|
pixmap <<= 8;
|
|
pixmap_resid--;
|
|
|
|
/* translate another pixel's bits from the bitmaps: */
|
|
if (bitmaps_lo & 0x00000080) pixmap |= TME_BIT(0);
|
|
if (bitmaps_lo & 0x00008000) pixmap |= TME_BIT(1);
|
|
if (bitmaps_lo & 0x00800000) pixmap |= TME_BIT(2);
|
|
if (bitmaps_lo & 0x80000000) pixmap |= TME_BIT(3);
|
|
bitmaps_lo <<= 1;
|
|
if (bitmaps_hi & 0x00000080) pixmap |= TME_BIT(4);
|
|
if (bitmaps_hi & 0x00008000) pixmap |= TME_BIT(5);
|
|
if (bitmaps_hi & 0x00800000) pixmap |= TME_BIT(6);
|
|
if (bitmaps_hi & 0x80000000) pixmap |= TME_BIT(7);
|
|
bitmaps_hi <<= 1;
|
|
|
|
/* if the pixmap data is full, write it: */
|
|
if (__tme_predict_false((pixmap_resid % sizeof(pixmap)) == 0)) {
|
|
*(pixmap_pointer++) = tme_htobe_u32(pixmap);
|
|
pixmap = 0;
|
|
}
|
|
|
|
/* loop while we have pixmap bytes remaining: */
|
|
} while (pixmap_resid > 0);
|
|
|
|
/* the pixmap is no longer invalid, but the bitmaps are: */
|
|
suncg2->tme_suncg2_flags &= ~TME_SUNCG2_FLAG_INVALID_PIXMAP;
|
|
}
|
|
|
|
/* otherwise, the pixmap is valid: */
|
|
else {
|
|
|
|
/* if our caller needs the actual raw pixmap memory valid
|
|
(indicated by tlb == NULL): */
|
|
if (tlb == NULL) {
|
|
|
|
/* invalidate any outstanding TLBs: */
|
|
_tme_suncg2_tlb_invalidate(suncg2, NULL);
|
|
|
|
/* if we're displaying the pixmap: */
|
|
if (suncg2->tme_suncg2_bitmap_mode_plane == TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* if the displayed memory is not invalid: */
|
|
if (!(suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_DISPLAYED)) {
|
|
|
|
/* copy the displayed memory back into the pixmap: */
|
|
memcpy((suncg2->tme_suncg2_raw_memory
|
|
+ TME_SUNCG2_REG_PIXMAP),
|
|
suncg2->tme_suncg2_displayed_memory,
|
|
TME_SUNCG2_SIZ_PIXMAP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* this validates the displayed memory: */
|
|
static void
|
|
_tme_suncg2_validate_displayed(struct tme_suncg2 *suncg2, struct tme_bus_tlb *tlb)
|
|
{
|
|
|
|
/* if the displayed memory is invalid: */
|
|
if (suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_INVALID_DISPLAYED) {
|
|
|
|
/* if we're displaying the pixmap: */
|
|
if (suncg2->tme_suncg2_bitmap_mode_plane == TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* validate the pixmap: */
|
|
_tme_suncg2_validate_pixmap(suncg2, tlb);
|
|
|
|
/* copy the pixmap into the displayed memory: */
|
|
memcpy(suncg2->tme_suncg2_displayed_memory,
|
|
(suncg2->tme_suncg2_raw_memory
|
|
+ TME_SUNCG2_REG_PIXMAP),
|
|
TME_SUNCG2_SIZ_PIXMAP);
|
|
}
|
|
|
|
/* otherwise, we're displaying a bitmap: */
|
|
else {
|
|
|
|
/* validate the bitmaps: */
|
|
_tme_suncg2_validate_bitmaps(suncg2, tlb);
|
|
|
|
/* copy the bitmap into the displayed memory: */
|
|
memcpy(suncg2->tme_suncg2_displayed_memory,
|
|
(suncg2->tme_suncg2_raw_memory
|
|
+ TME_SUNCG2_REG_BITMAP(suncg2->tme_suncg2_bitmap_mode_plane)),
|
|
TME_SUNCG2_SIZ_BITMAP);
|
|
}
|
|
|
|
/* the displayed memory is no longer invalid: */
|
|
suncg2->tme_suncg2_flags &= ~TME_SUNCG2_FLAG_INVALID_DISPLAYED;
|
|
}
|
|
}
|
|
|
|
/* this handles a mode change callout: */
|
|
static int
|
|
_tme_suncg2_mode_change(struct tme_suncg2 *suncg2)
|
|
{
|
|
struct tme_fb_connection *conn_fb_other;
|
|
struct tme_fb_connection *conn_fb;
|
|
unsigned int pixel_i;
|
|
unsigned int mono_mask;
|
|
tme_uint32_t color0;
|
|
tme_uint32_t color1;
|
|
tme_uint32_t color;
|
|
unsigned int bitmap_mode_plane;
|
|
unsigned int color_i;
|
|
int rc;
|
|
|
|
/* this makes a color for a pixel: */
|
|
#define _TME_SUNCG2_PIXEL_COLOR(pixel) \
|
|
((TME_SUNCG2_CMAP_VALUE(suncg2, pixel, TME_SUNCG2_REG_CMAP_G) << 0) \
|
|
| (TME_SUNCG2_CMAP_VALUE(suncg2, pixel, TME_SUNCG2_REG_CMAP_R) << 8) \
|
|
| (TME_SUNCG2_CMAP_VALUE(suncg2, pixel, TME_SUNCG2_REG_CMAP_B) << 16))
|
|
|
|
/* if we are to display a bitmap, the color for pixmap pixel zero
|
|
must be the color for bitmap pixel zero, and the color for pixmap
|
|
pixel 255 must be the color for bitmap pixel one: */
|
|
color0 = _TME_SUNCG2_PIXEL_COLOR(0);
|
|
color1 = _TME_SUNCG2_PIXEL_COLOR(255);
|
|
|
|
/* we don't know what the monochrome mask is yet: */
|
|
mono_mask = 0xff;
|
|
|
|
/* loop over the other pixels: */
|
|
for (pixel_i = 1; pixel_i < 255; pixel_i++) {
|
|
|
|
/* get the color for this pixel: */
|
|
color = _TME_SUNCG2_PIXEL_COLOR(pixel_i);
|
|
|
|
/* if this matches color0: */
|
|
if (color == color0) {
|
|
|
|
/* any set bits in this pixel number can't be in the monochrome
|
|
mask: */
|
|
mono_mask &= ~pixel_i;
|
|
}
|
|
|
|
/* else, if this matches color1: */
|
|
else if (color == color1) {
|
|
|
|
/* any clear bits in this pixel number can't be in the
|
|
monochrome mask: */
|
|
mono_mask &= pixel_i;
|
|
}
|
|
|
|
/* otherwise, this is some other color: */
|
|
else {
|
|
|
|
/* we can't be in bitmap mode: */
|
|
mono_mask = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if the monochrome mask is zero, we must display the pixmap, else
|
|
we display the bitmap corresponding to the least significant set
|
|
bit in the monochrome mask: */
|
|
if (mono_mask == 0
|
|
|| (mono_mask & (mono_mask - 1)) != 0) {
|
|
bitmap_mode_plane = TME_SUNCG2_PLANE_MAX;
|
|
}
|
|
else {
|
|
for (bitmap_mode_plane = 0;
|
|
(mono_mask & 1) == 0;
|
|
bitmap_mode_plane++, mono_mask >>= 1);
|
|
}
|
|
|
|
#undef _TME_SUNCG2_PIXEL_COLOR
|
|
|
|
/* get both sides of the framebuffer connection: */
|
|
conn_fb_other = suncg2->tme_suncg2_fb_connection;
|
|
conn_fb = (struct tme_fb_connection *) conn_fb_other->tme_fb_connection.tme_connection_other;
|
|
|
|
/* if we are displaying the pixmap: */
|
|
if (bitmap_mode_plane == TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* the pixmap is eight bits deep: */
|
|
conn_fb->tme_fb_connection_depth = TME_SUNCG2_PLANE_MAX;
|
|
conn_fb->tme_fb_connection_bits_per_pixel = TME_SUNCG2_PLANE_MAX;
|
|
|
|
/* recook the colormap: */
|
|
for (color_i = 0;
|
|
color_i < TME_ARRAY_ELS(suncg2->tme_suncg2_cmap_raw);
|
|
color_i++) {
|
|
suncg2->tme_suncg2_cmap[color_i] = tme_betoh_u16(suncg2->tme_suncg2_cmap_raw[color_i]);
|
|
}
|
|
}
|
|
|
|
/* otherwise, we can display a bitmap: */
|
|
else {
|
|
|
|
/* a bitmap is one bit deep: */
|
|
conn_fb->tme_fb_connection_depth = 1;
|
|
conn_fb->tme_fb_connection_bits_per_pixel = 1;
|
|
|
|
/* cook the monochrome colormap: */
|
|
suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(0, TME_SUNCG2_REG_CMAP_G)] = TME_SUNCG2_CMAP_VALUE(suncg2, 0, TME_SUNCG2_REG_CMAP_G);
|
|
suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(0, TME_SUNCG2_REG_CMAP_R)] = TME_SUNCG2_CMAP_VALUE(suncg2, 0, TME_SUNCG2_REG_CMAP_R);
|
|
suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(0, TME_SUNCG2_REG_CMAP_B)] = TME_SUNCG2_CMAP_VALUE(suncg2, 0, TME_SUNCG2_REG_CMAP_B);
|
|
suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(1, TME_SUNCG2_REG_CMAP_G)] = TME_SUNCG2_CMAP_VALUE(suncg2, 255, TME_SUNCG2_REG_CMAP_G);
|
|
suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(1, TME_SUNCG2_REG_CMAP_R)] = TME_SUNCG2_CMAP_VALUE(suncg2, 255, TME_SUNCG2_REG_CMAP_R);
|
|
suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(1, TME_SUNCG2_REG_CMAP_B)] = TME_SUNCG2_CMAP_VALUE(suncg2, 255, TME_SUNCG2_REG_CMAP_B);
|
|
}
|
|
|
|
/* if the display is changing: */
|
|
if (bitmap_mode_plane != suncg2->tme_suncg2_bitmap_mode_plane) {
|
|
|
|
/* log the change: */
|
|
tme_log(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
100, TME_OK,
|
|
(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
"display changing from plane %u to plane %u",
|
|
suncg2->tme_suncg2_bitmap_mode_plane,
|
|
bitmap_mode_plane));
|
|
|
|
/* if we were displaying the pixmap, validate the pixmap, else
|
|
validate the bitmaps, to copy the current displayed memory back
|
|
into the raw memory: */
|
|
if (suncg2->tme_suncg2_bitmap_mode_plane == TME_SUNCG2_PLANE_MAX) {
|
|
_tme_suncg2_validate_pixmap(suncg2, NULL);
|
|
}
|
|
else {
|
|
_tme_suncg2_validate_bitmaps(suncg2, NULL);
|
|
}
|
|
|
|
/* invalidate any outstanding TLBs: */
|
|
_tme_suncg2_tlb_invalidate(suncg2, NULL);
|
|
|
|
/* set the display: */
|
|
suncg2->tme_suncg2_bitmap_mode_plane = bitmap_mode_plane;
|
|
|
|
/* free any previously allocated memory: */
|
|
if (suncg2->tme_suncg2_displayed_memory != NULL) {
|
|
tme_free(suncg2->tme_suncg2_displayed_memory);
|
|
}
|
|
|
|
/* allocate memory for our framebuffer connection: */
|
|
rc = tme_fb_xlat_alloc_src(conn_fb);
|
|
assert (rc == TME_OK);
|
|
suncg2->tme_suncg2_displayed_memory = conn_fb->tme_fb_connection_buffer;
|
|
|
|
/* the displayed memory is now invalid: */
|
|
suncg2->tme_suncg2_flags |= TME_SUNCG2_FLAG_INVALID_DISPLAYED;
|
|
}
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* do the callout: */
|
|
rc = (conn_fb_other != NULL
|
|
? ((*conn_fb_other->tme_fb_connection_mode_change)
|
|
(conn_fb_other))
|
|
: TME_OK);
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/* the suncg2 callout function. it must be called with the mutex locked: */
|
|
static void
|
|
_tme_suncg2_callout(struct tme_suncg2 *suncg2, int new_callouts)
|
|
{
|
|
int callouts, later_callouts;
|
|
int rc;
|
|
|
|
/* add in any new callouts: */
|
|
suncg2->tme_suncg2_callout_flags |= new_callouts;
|
|
|
|
/* if this function is already running in another thread, simply
|
|
return now. the other thread will do our work: */
|
|
if (suncg2->tme_suncg2_callout_flags
|
|
& TME_SUNCG2_CALLOUT_RUNNING) {
|
|
return;
|
|
}
|
|
|
|
/* callouts are now running: */
|
|
suncg2->tme_suncg2_callout_flags
|
|
|= TME_SUNCG2_CALLOUT_RUNNING;
|
|
|
|
/* assume that we won't need any later callouts: */
|
|
later_callouts = 0;
|
|
|
|
/* loop while callouts are needed: */
|
|
for (; ((callouts
|
|
= suncg2->tme_suncg2_callout_flags)
|
|
& TME_SUNCG2_CALLOUTS_MASK); ) {
|
|
|
|
/* clear the needed callouts: */
|
|
suncg2->tme_suncg2_callout_flags
|
|
= (callouts
|
|
& ~TME_SUNCG2_CALLOUTS_MASK);
|
|
callouts
|
|
&= TME_SUNCG2_CALLOUTS_MASK;
|
|
|
|
/* if we need a mode change: */
|
|
if (callouts & TME_SUNCG2_CALLOUT_MODE_CHANGE) {
|
|
|
|
/* call out the mode change: */
|
|
rc = _tme_suncg2_mode_change(suncg2);
|
|
|
|
/* if the callout failed: */
|
|
if (rc != TME_OK) {
|
|
|
|
/* remember that this callout should be attempted again at
|
|
some later time: */
|
|
later_callouts |= TME_SUNCG2_CALLOUT_MODE_CHANGE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* put in any later callouts, and clear that callouts are running: */
|
|
suncg2->tme_suncg2_callout_flags = later_callouts;
|
|
}
|
|
|
|
/* the callout thread: */
|
|
static void
|
|
_tme_suncg2_callout_thread(void *_suncg2)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = _suncg2;
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* the callout thread is no longer running: */
|
|
suncg2->tme_suncg2_flags &= ~TME_SUNCG2_FLAG_CALLOUT_THREAD_RUNNING;
|
|
|
|
/* make any callouts: */
|
|
_tme_suncg2_callout(suncg2, 0);
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
}
|
|
|
|
/* this is called before the framebuffer's display is updated: */
|
|
static int
|
|
_tme_suncg2_update(struct tme_fb_connection *conn_fb)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = conn_fb->tme_fb_connection.tme_connection_element->tme_element_private;
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* validate the displayed memory: */
|
|
_tme_suncg2_validate_displayed(suncg2, NULL);
|
|
|
|
/* if we still need callouts, and the callout thread isn't running,
|
|
start it: */
|
|
if ((suncg2->tme_suncg2_callout_flags & TME_SUNCG2_CALLOUTS_MASK) != 0
|
|
&& !(suncg2->tme_suncg2_flags & TME_SUNCG2_FLAG_CALLOUT_THREAD_RUNNING)) {
|
|
tme_thread_create(_tme_suncg2_callout_thread, suncg2);
|
|
suncg2->tme_suncg2_flags |= TME_SUNCG2_FLAG_CALLOUT_THREAD_RUNNING;
|
|
}
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* the suncg2 displayed memory bus cycle handler: */
|
|
static int
|
|
_tme_suncg2_bus_cycle_displayed(void *_suncg2, struct tme_bus_cycle *cycle_init)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
unsigned int plane_i;
|
|
tme_bus_addr32_t address_first;
|
|
tme_bus_addr32_t address_last;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = (struct tme_suncg2 *) _suncg2;
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* if we're displaying the pixmap: */
|
|
plane_i = suncg2->tme_suncg2_bitmap_mode_plane;
|
|
if (plane_i == TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* the displayed memory is the pixmap memory: */
|
|
address_first = TME_SUNCG2_REG_PIXMAP;
|
|
address_last = TME_SUNCG2_REG_PIXMAP + suncg2->tme_suncg2_pixel_count - 1;
|
|
}
|
|
|
|
/* otherwise, we're in bitmap mode: */
|
|
else {
|
|
|
|
/* the displayed memory is the displayed bitmap memory: */
|
|
address_first = TME_SUNCG2_REG_BITMAP(plane_i);
|
|
address_last = address_first + (suncg2->tme_suncg2_pixel_count / 8) - 1;
|
|
}
|
|
|
|
/* run the cycle: */
|
|
tme_bus_cycle_xfer_memory(cycle_init,
|
|
(suncg2->tme_suncg2_displayed_memory
|
|
- address_first),
|
|
address_last);
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* no faults: */
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* the suncg2 raw memory bus cycle handler: */
|
|
static int
|
|
_tme_suncg2_bus_cycle_raw(void *_suncg2, struct tme_bus_cycle *cycle_init)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = (struct tme_suncg2 *) _suncg2;
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* run the cycle: */
|
|
tme_bus_cycle_xfer_memory(cycle_init,
|
|
(suncg2->tme_suncg2_raw_memory
|
|
- TME_SUNCG2_REG_BITMAP(0)),
|
|
(TME_SUNCG2_REG_PIXMAP
|
|
+ TME_SUNCG2_SIZ_PIXMAP
|
|
- 1));
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* no faults: */
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* this catches unsupported rasterop configurations: */
|
|
static void
|
|
_tme_suncg2_rop_unsupported(struct tme_suncg2 *suncg2)
|
|
{
|
|
/* nothing */
|
|
}
|
|
|
|
/* this does a raster op: */
|
|
static tme_uint16_t
|
|
_tme_suncg2_rop_op(struct tme_suncg2 *suncg2,
|
|
unsigned int ropc_unit,
|
|
tme_uint16_t src,
|
|
tme_uint16_t dst)
|
|
{
|
|
switch ((tme_uint8_t) suncg2->tme_suncg2_ropc[ropc_unit].tme_suncg2_ropc_op) {
|
|
default:
|
|
_tme_suncg2_rop_unsupported(suncg2);
|
|
/* FALLTHROUGH */
|
|
case (TME_SUNCG2_ROP_SRC): return (src);
|
|
case (TME_SUNCG2_ROP_NOT(TME_SUNCG2_ROP_DST)): return (~dst);
|
|
}
|
|
}
|
|
|
|
/* the bus cycle handler for the rasterop data: */
|
|
static int
|
|
_tme_suncg2_bus_cycle_rop_data(void *_suncg2, struct tme_bus_cycle *cycle_init)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
tme_uint32_t address;
|
|
tme_uint32_t address_aligned;
|
|
tme_uint16_t data;
|
|
tme_uint8_t src;
|
|
tme_uint8_t dst;
|
|
tme_uint8_t pixel;
|
|
int supported;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = (struct tme_suncg2 *) _suncg2;
|
|
|
|
/* decode the address: */
|
|
address
|
|
= (cycle_init->tme_bus_cycle_address
|
|
- TME_SUNCG2_REG_ROP_DATA);
|
|
address_aligned
|
|
= (address & (((tme_uint32_t) 0) - sizeof(tme_uint16_t)));
|
|
|
|
/* assume that this access is unsupported: */
|
|
supported = FALSE;
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* if this is a read: */
|
|
if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
|
|
|
|
/* dispatch on the rop mode: */
|
|
switch (suncg2->tme_suncg2_csr & TME_SUNCG2_CSR_ROP_MODE_MASK) {
|
|
|
|
default:
|
|
_tme_suncg2_rop_unsupported(suncg2);
|
|
data = 0;
|
|
break;
|
|
|
|
/* the single pixel, LD_SRC write, LD_DST write, mode: */
|
|
case TME_SUNCG2_CSR_ROP_MODE_SWWPIX:
|
|
|
|
/* this mode has partial support: */
|
|
supported = TRUE;
|
|
|
|
/* XXX FIXME does a load reset the state? */
|
|
|
|
/* just load two pixels from the pixmap: */
|
|
_tme_suncg2_validate_pixmap(suncg2, NULL);
|
|
data = (suncg2->tme_suncg2_raw_memory[TME_SUNCG2_REG_PIXMAP + address_aligned]
|
|
& ((tme_uint8_t) suncg2->tme_suncg2_plane_mask));
|
|
data = ((data << 8)
|
|
| (suncg2->tme_suncg2_raw_memory[TME_SUNCG2_REG_PIXMAP + address_aligned + 1]
|
|
& ((tme_uint8_t) suncg2->tme_suncg2_plane_mask)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* do the bus cycle: */
|
|
tme_bus_cycle_xfer_reg(cycle_init,
|
|
&data,
|
|
TME_BUS16_LOG2);
|
|
|
|
/* get the data: */
|
|
data = (((cycle_init->tme_bus_cycle_size == sizeof(tme_uint16_t)
|
|
|| (address % sizeof(tme_uint16_t)) == 1)
|
|
? data
|
|
: (data >> 8))
|
|
& (0xffff >> (sizeof(tme_uint16_t) - cycle_init->tme_bus_cycle_size)));
|
|
|
|
/* log the cycle: */
|
|
tme_log(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
100, TME_OK,
|
|
(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
((cycle_init->tme_bus_cycle_size == sizeof(tme_uint16_t))
|
|
? "rop data offset 0x%05x size 16bits %s 0x%04x"
|
|
: "rop data offset 0x%05x size 8bits %s 0x%02x"),
|
|
address,
|
|
((cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE)
|
|
? "<-"
|
|
: "->"),
|
|
data));
|
|
|
|
/* if this is a write: */
|
|
if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
|
|
|
|
/* dispatch on the rop mode: */
|
|
switch (suncg2->tme_suncg2_csr & TME_SUNCG2_CSR_ROP_MODE_MASK) {
|
|
|
|
default:
|
|
_tme_suncg2_rop_unsupported(suncg2);
|
|
break;
|
|
|
|
/* the single pixel, LD_SRC write, LD_DST write, mode: */
|
|
case TME_SUNCG2_CSR_ROP_MODE_SWWPIX:
|
|
|
|
/* this mode has partial support: */
|
|
supported = TRUE;
|
|
|
|
/* validate the pixmap: */
|
|
_tme_suncg2_validate_pixmap(suncg2, NULL);
|
|
|
|
/* the current pixel value is DST: */
|
|
dst = suncg2->tme_suncg2_raw_memory[TME_SUNCG2_REG_PIXMAP + address];
|
|
|
|
/* the current source buffer is SRC: */
|
|
src = suncg2->tme_suncg2_rop_src_buffer;
|
|
|
|
/* make the new pixel value: */
|
|
pixel = _tme_suncg2_rop_op(suncg2,
|
|
8,
|
|
src,
|
|
dst);
|
|
|
|
/* store the pixel: */
|
|
suncg2->tme_suncg2_raw_memory[TME_SUNCG2_REG_PIXMAP + address]
|
|
= ((dst & ((tme_uint8_t) (~suncg2->tme_suncg2_plane_mask)))
|
|
| (pixel & ((tme_uint8_t) suncg2->tme_suncg2_plane_mask)));
|
|
|
|
/* the displayed memory is now invalid: */
|
|
suncg2->tme_suncg2_flags |= TME_SUNCG2_FLAG_INVALID_DISPLAYED;
|
|
|
|
/* load the source buffer: */
|
|
suncg2->tme_suncg2_rop_src_buffer = data;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if this cycle was unsupported, abort: */
|
|
if (__tme_predict_false(!supported)) {
|
|
_tme_suncg2_rop_unsupported(suncg2);
|
|
}
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* no faults: */
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* the bus cycle handler for the registers: */
|
|
static int
|
|
_tme_suncg2_bus_cycle_regs(void *_suncg2, struct tme_bus_cycle *cycle_init)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
tme_bus_addr32_t address;
|
|
tme_uint16_t *reg;
|
|
tme_uint16_t reg_old, reg_new;
|
|
tme_uint16_t junk;
|
|
unsigned int ropc_unit;
|
|
unsigned int ropc_unit_prime;
|
|
unsigned int ropc_reg;
|
|
int new_callouts;
|
|
|
|
/* assume we won't need any new callouts: */
|
|
new_callouts = 0;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = (struct tme_suncg2 *) _suncg2;
|
|
|
|
/* coarsely decode the address: */
|
|
address
|
|
= (cycle_init->tme_bus_cycle_address
|
|
& (((tme_bus_addr32_t) 0)
|
|
- TME_SUNCG2_SIZ_REG_PAGE));
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* the rasterop registers go from [TME_SUNCG2_REG_ROPC_UNIT(0)..TME_SUNCG2_REG_CSR): */
|
|
assert (address >= TME_SUNCG2_REG_ROPC_UNIT(0));
|
|
if (address < TME_SUNCG2_REG_CSR) {
|
|
|
|
/* get the rasterop unit number: */
|
|
ropc_unit = (address - TME_SUNCG2_REG_ROPC_UNIT(0)) / TME_SUNCG2_SIZ_REG_PAGE;
|
|
|
|
/* see if this is the prime registers: */
|
|
ropc_unit_prime
|
|
= ((cycle_init->tme_bus_cycle_address & (TME_SUNCG2_SIZ_REG_PAGE / 2))
|
|
? TME_SUNCG2_ROPC_PRIME
|
|
: 0);
|
|
|
|
/* get the register number: */
|
|
ropc_reg
|
|
= ((cycle_init->tme_bus_cycle_address
|
|
% sizeof(suncg2->tme_suncg2_ropc[ropc_unit_prime + ropc_unit]))
|
|
/ sizeof(tme_uint16_t));
|
|
|
|
/* get a pointer to the single register: */
|
|
reg = (((tme_uint16_t *) &suncg2->tme_suncg2_ropc[ropc_unit_prime + ropc_unit]) + ropc_reg);
|
|
|
|
/* do the bus cycle: */
|
|
tme_bus_cycle_xfer_reg(cycle_init,
|
|
reg,
|
|
TME_BUS16_LOG2);
|
|
|
|
#ifndef TME_NO_LOG
|
|
/* log the transfer: */
|
|
tme_log(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
100, TME_OK,
|
|
(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
"ropc unit %u%s reg %s %s 0x%04x",
|
|
ropc_unit,
|
|
(ropc_unit_prime
|
|
? " PRIME"
|
|
: ""),
|
|
_tme_suncg2_ropc_regs[ropc_reg],
|
|
((cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE)
|
|
? "<-"
|
|
: "->"),
|
|
*reg));
|
|
#endif /* !TME_NO_LOG */
|
|
}
|
|
|
|
/* the CSR is the entire page at TME_SUNCG2_REG_CSR: */
|
|
else if (address == TME_SUNCG2_REG_CSR) {
|
|
|
|
/* if this is a read: */
|
|
if ((cycle_init->tme_bus_cycle_type & TME_BUS_CYCLE_READ) != 0) {
|
|
|
|
/* if it's time to set the retrace bit, set it: */
|
|
if (suncg2->tme_suncg2_cycle_retrace-- == 0) {
|
|
suncg2->tme_suncg2_csr |= TME_SUNCG2_CSR_RETRACE;
|
|
suncg2->tme_suncg2_cycle_retrace = TME_SUNCG2_CYCLE_RETRACE;
|
|
}
|
|
|
|
/* otherwise, clear it: */
|
|
else {
|
|
suncg2->tme_suncg2_csr &= ~TME_SUNCG2_CSR_RETRACE;
|
|
}
|
|
}
|
|
|
|
/* do the bus cycle: */
|
|
reg_old = suncg2->tme_suncg2_csr;
|
|
tme_bus_cycle_xfer_reg(cycle_init,
|
|
&suncg2->tme_suncg2_csr,
|
|
TME_BUS16_LOG2);
|
|
reg_new = suncg2->tme_suncg2_csr;
|
|
|
|
/* put back the unchanging bits: */
|
|
reg_new
|
|
= ((reg_new
|
|
& ~(TME_SUNCG2_CSR_INT_ACTIVE
|
|
| TME_SUNCG2_CSR_RETRACE
|
|
| 0xff00))
|
|
| (reg_old
|
|
& (TME_SUNCG2_CSR_INT_ACTIVE
|
|
| TME_SUNCG2_CSR_RETRACE
|
|
| 0xff00)));
|
|
suncg2->tme_suncg2_csr = reg_new;
|
|
|
|
/* log the transfer: */
|
|
tme_log(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
100, TME_OK,
|
|
(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
"csr %s 0x%04x",
|
|
((cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE)
|
|
? "<-"
|
|
: "->"),
|
|
reg_new));
|
|
|
|
/* we do not support these bits: */
|
|
if ((reg_new
|
|
^ reg_old)
|
|
& TME_SUNCG2_CSR_INT_ENABLE) {
|
|
abort();
|
|
}
|
|
|
|
/* if the cmap update bit is transitioning from a zero to a one,
|
|
we need a mode change: */
|
|
if ((reg_old & TME_SUNCG2_CSR_CMAP_UPDATE) == 0
|
|
&& (reg_new & TME_SUNCG2_CSR_CMAP_UPDATE) != 0) {
|
|
new_callouts |= TME_SUNCG2_CALLOUT_MODE_CHANGE;
|
|
}
|
|
}
|
|
|
|
/* if this is the interrupt vector: */
|
|
else if (address == TME_SUNCG2_REG_INTVEC) {
|
|
tme_bus_cycle_xfer_reg(cycle_init,
|
|
&suncg2->tme_suncg2_intvec,
|
|
TME_BUS16_LOG2);
|
|
}
|
|
|
|
/* if this is the plane mask: */
|
|
else if (address == TME_SUNCG2_REG_PLANE_MASK) {
|
|
|
|
/* do the bus cycle: */
|
|
tme_bus_cycle_xfer_reg(cycle_init,
|
|
&suncg2->tme_suncg2_plane_mask,
|
|
TME_BUS16_LOG2);
|
|
|
|
/* log the transfer: */
|
|
tme_log(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
100, TME_OK,
|
|
(&suncg2->tme_suncg2_element->tme_element_log_handle,
|
|
"plane mask %s 0x%04x",
|
|
((cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE)
|
|
? "<-"
|
|
: "->"),
|
|
suncg2->tme_suncg2_plane_mask));
|
|
}
|
|
|
|
/* XXX FIXME - the sun3 PROM zeroes the cg3 DMA base register,
|
|
the cg3 double buffer register, the cg3 DMA width register,
|
|
and the cg3 frame count registers: */
|
|
else if (address == TME_SUNCG2_REG_SUN3_DMA_BASE
|
|
|| address == TME_SUNCG2_REG_SUN3_DOUBLE_BUF
|
|
|| address == TME_SUNCG2_REG_SUN3_DMA_WIDTH
|
|
|| address == TME_SUNCG2_REG_SUN3_FRAME_COUNT) {
|
|
tme_bus_cycle_xfer_reg(cycle_init,
|
|
&junk,
|
|
TME_BUS16_LOG2);
|
|
}
|
|
|
|
/* XXX FIXME - this is a partial implementation: */
|
|
else {
|
|
abort();
|
|
}
|
|
|
|
/* make any new callouts: */
|
|
_tme_suncg2_callout(suncg2, new_callouts);
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* no faults: */
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* the bus cycle handler for the suncg2 colormap registers: */
|
|
static int
|
|
_tme_suncg2_bus_cycle_cmap(void *_suncg2, struct tme_bus_cycle *cycle_init)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = (struct tme_suncg2 *) _suncg2;
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* run the cycle: */
|
|
tme_bus_cycle_xfer_memory(cycle_init,
|
|
(((tme_uint8_t *) suncg2->tme_suncg2_cmap_raw)
|
|
- TME_SUNCG2_REG_CMAP_R),
|
|
TME_SUNCG2_SIZ_REGS - 1);
|
|
|
|
/* if this is a write and colormap updates are enabled, we need to
|
|
call out a mode change. we don't make the callout now, assuming
|
|
that more writes to the colormap are coming soon. we will
|
|
eventually make the callout when the framebuffer updates: */
|
|
if ((cycle_init->tme_bus_cycle_type & TME_BUS_CYCLE_WRITE)
|
|
&& (suncg2->tme_suncg2_csr
|
|
& TME_SUNCG2_CSR_CMAP_UPDATE)) {
|
|
suncg2->tme_suncg2_callout_flags |= TME_SUNCG2_CALLOUT_MODE_CHANGE;
|
|
}
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* no faults: */
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* the suncg2 TLB filler: */
|
|
static int
|
|
_tme_suncg2_tlb_fill(void *_suncg2, struct tme_bus_tlb *tlb,
|
|
tme_bus_addr_t address_wider, unsigned int cycles)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
tme_uint8_t *memory;
|
|
tme_bus_addr32_t address;
|
|
tme_bus_addr32_t address_first;
|
|
tme_bus_addr32_t address_last;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = (struct tme_suncg2 *) _suncg2;
|
|
|
|
/* initialize the TLB entry: */
|
|
tme_bus_tlb_initialize(tlb);
|
|
|
|
/* get the normal-width address: */
|
|
address = address_wider;
|
|
assert (address == address_wider);
|
|
|
|
/* the fast reading and writing rwlock: */
|
|
tlb->tme_bus_tlb_rwlock = &suncg2->tme_suncg2_rwlock;
|
|
|
|
/* allow reading and writing: */
|
|
tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
|
|
|
|
/* our bus cycle handler private data: */
|
|
tlb->tme_bus_tlb_cycle_private = _suncg2;
|
|
|
|
/* lock the mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* we require a connection: */
|
|
assert (suncg2->tme_suncg2_fb_connection != NULL);
|
|
assert (suncg2->tme_suncg2_displayed_memory != NULL);
|
|
|
|
/* if this address falls in a bitmap: */
|
|
if ((TME_SUNCG2_REG_BITMAP(0)
|
|
<= address)
|
|
&& (address
|
|
< TME_SUNCG2_REG_BITMAP(TME_SUNCG2_PLANE_MAX))) {
|
|
|
|
/* the cycle handler: */
|
|
tlb->tme_bus_tlb_cycle = _tme_suncg2_bus_cycle_raw;
|
|
|
|
/* if we're displaying the pixmap: */
|
|
if (suncg2->tme_suncg2_bitmap_mode_plane == TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* validate the bitmaps: */
|
|
_tme_suncg2_validate_bitmaps(suncg2, tlb);
|
|
|
|
/* this TLB entry covers all of the bitmap memory: */
|
|
address_first = TME_SUNCG2_REG_BITMAP(0);
|
|
address_last = TME_SUNCG2_REG_PIXMAP - 1;
|
|
memory = suncg2->tme_suncg2_raw_memory + address_first;
|
|
|
|
/* the displayed memory is now invalid: */
|
|
suncg2->tme_suncg2_flags |= TME_SUNCG2_FLAG_INVALID_DISPLAYED;
|
|
}
|
|
|
|
/* otherwise, we're displaying a bitmap: */
|
|
else {
|
|
|
|
/* calculate the first and last addresses of the displayed
|
|
memory: */
|
|
address_first = TME_SUNCG2_REG_BITMAP(suncg2->tme_suncg2_bitmap_mode_plane);
|
|
address_last = address_first + (suncg2->tme_suncg2_pixel_count / 8) - 1;
|
|
|
|
/* if this address is before the displayed memory, this TLB
|
|
entry covers from the beginning of the bitmap memory up to
|
|
the displayed memory: */
|
|
if (address < address_first) {
|
|
address_last = address_first - 1;
|
|
address_first = TME_SUNCG2_REG_BITMAP(0);
|
|
memory = suncg2->tme_suncg2_raw_memory + address_first;
|
|
|
|
/* validate the bitmaps: */
|
|
_tme_suncg2_validate_bitmaps(suncg2, tlb);
|
|
}
|
|
|
|
/* otherwise, if this address is after the displayed memory,
|
|
this TLB entry covers from right after the displayed memory
|
|
to the end of the bitmap memory: */
|
|
else if (address > address_last) {
|
|
address_first = address_last + 1;
|
|
address_last = TME_SUNCG2_REG_PIXMAP - 1;
|
|
memory = suncg2->tme_suncg2_raw_memory + address_first;
|
|
|
|
/* validate the bitmaps: */
|
|
_tme_suncg2_validate_bitmaps(suncg2, tlb);
|
|
}
|
|
|
|
/* otherwise, this address is in the displayed memory: */
|
|
else {
|
|
memory = suncg2->tme_suncg2_displayed_memory;
|
|
tlb->tme_bus_tlb_cycle = _tme_suncg2_bus_cycle_displayed;
|
|
|
|
/* validate the displayed memory: */
|
|
_tme_suncg2_validate_displayed(suncg2, tlb);
|
|
}
|
|
}
|
|
|
|
/* the address range: */
|
|
tlb->tme_bus_tlb_addr_first = address_first;
|
|
tlb->tme_bus_tlb_addr_last = address_last;
|
|
|
|
/* this TLB entry allows fast reading and fast writing: */
|
|
tlb->tme_bus_tlb_emulator_off_read = memory - address_first;
|
|
tlb->tme_bus_tlb_emulator_off_write = memory - address_first;
|
|
|
|
/* add this TLB entry: */
|
|
_tme_suncg2_tlb_add(suncg2, tlb);
|
|
|
|
/* the pixmap is now invalid: */
|
|
suncg2->tme_suncg2_flags |= TME_SUNCG2_FLAG_INVALID_PIXMAP;
|
|
}
|
|
|
|
/* if this address falls in the pixmap: */
|
|
else if ((TME_SUNCG2_REG_PIXMAP
|
|
<= address)
|
|
&& (address
|
|
< (TME_SUNCG2_REG_PIXMAP + TME_SUNCG2_SIZ_PIXMAP))) {
|
|
|
|
/* the cycle handler: */
|
|
tlb->tme_bus_tlb_cycle = _tme_suncg2_bus_cycle_raw;
|
|
|
|
/* if we're displaying the pixmap: */
|
|
if (suncg2->tme_suncg2_bitmap_mode_plane == TME_SUNCG2_PLANE_MAX) {
|
|
|
|
/* calculate the first and last addresses of the displayed memory: */
|
|
address_first = TME_SUNCG2_REG_PIXMAP;
|
|
address_last = TME_SUNCG2_REG_PIXMAP + suncg2->tme_suncg2_pixel_count - 1;
|
|
|
|
/* if this address is after the displayed memory, we're in the pad: */
|
|
if (address > address_last) {
|
|
address_first = address_last + 1;
|
|
address_last = TME_SUNCG2_REG_PIXMAP + TME_SUNCG2_SIZ_PIXMAP - 1;
|
|
memory = suncg2->tme_suncg2_raw_memory + address_first;
|
|
|
|
/* validate the pixmap: */
|
|
_tme_suncg2_validate_pixmap(suncg2, tlb);
|
|
}
|
|
|
|
/* otherwise, this address is in the displayed memory: */
|
|
else {
|
|
memory = suncg2->tme_suncg2_displayed_memory;
|
|
tlb->tme_bus_tlb_cycle = _tme_suncg2_bus_cycle_displayed;
|
|
|
|
/* validate the displayed memory: */
|
|
_tme_suncg2_validate_displayed(suncg2, tlb);
|
|
}
|
|
}
|
|
|
|
/* otherwise, we're displaying a bitmap: */
|
|
else {
|
|
|
|
/* validate the pixmap: */
|
|
_tme_suncg2_validate_pixmap(suncg2, tlb);
|
|
|
|
/* this TLB covers all of pixmap memory: */
|
|
address_first = TME_SUNCG2_REG_PIXMAP;
|
|
address_last = TME_SUNCG2_REG_PIXMAP + TME_SUNCG2_SIZ_PIXMAP - 1;
|
|
memory = suncg2->tme_suncg2_raw_memory + address_first;
|
|
|
|
/* the displayed memory is now invalid: */
|
|
suncg2->tme_suncg2_flags |= TME_SUNCG2_FLAG_INVALID_DISPLAYED;
|
|
}
|
|
|
|
/* the address range: */
|
|
tlb->tme_bus_tlb_addr_first = address_first;
|
|
tlb->tme_bus_tlb_addr_last = address_last;
|
|
|
|
/* this TLB entry allows fast reading and fast writing: */
|
|
tlb->tme_bus_tlb_emulator_off_read = memory - address_first;
|
|
tlb->tme_bus_tlb_emulator_off_write = memory - address_first;
|
|
|
|
/* add this TLB entry: */
|
|
_tme_suncg2_tlb_add(suncg2, tlb);
|
|
|
|
/* the bitmaps are now invalid: */
|
|
suncg2->tme_suncg2_flags |= TME_SUNCG2_FLAG_INVALID_BITMAPS;
|
|
}
|
|
|
|
/* if this address falls in the rasterop data: */
|
|
else if ((TME_SUNCG2_REG_ROP_DATA
|
|
<= address)
|
|
&& (address
|
|
< TME_SUNCG2_REG_ROPC_UNIT(0))) {
|
|
|
|
/* the cycle handler: */
|
|
tlb->tme_bus_tlb_cycle = _tme_suncg2_bus_cycle_rop_data;
|
|
|
|
/* this TLB entry covers this range: */
|
|
tlb->tme_bus_tlb_addr_first = TME_SUNCG2_REG_ROP_DATA;
|
|
tlb->tme_bus_tlb_addr_last = (TME_SUNCG2_REG_ROPC_UNIT(0) - 1);
|
|
|
|
/* this TLB entry cannot allow fast reading or fast writing, since
|
|
this is the rasterop data: */
|
|
}
|
|
|
|
/* if this address falls in the registers: */
|
|
else if ((TME_SUNCG2_REG_ROPC_UNIT(0)
|
|
<= address)
|
|
&& (address
|
|
< TME_SUNCG2_REG_CMAP_R)) {
|
|
|
|
/* the cycle handler: */
|
|
tlb->tme_bus_tlb_cycle = _tme_suncg2_bus_cycle_regs;
|
|
|
|
/* this TLB entry covers this range: */
|
|
tlb->tme_bus_tlb_addr_first = TME_SUNCG2_REG_ROPC_UNIT(0);
|
|
tlb->tme_bus_tlb_addr_last = (TME_SUNCG2_REG_CMAP_R - 1);
|
|
|
|
/* this TLB entry cannot allow fast reading or fast writing, since
|
|
these are registers: */
|
|
}
|
|
|
|
/* if this address falls in the colormap registers: */
|
|
else if ((TME_SUNCG2_REG_CMAP_R
|
|
<= address)
|
|
&& (address
|
|
<= (TME_SUNCG2_SIZ_REGS
|
|
- 1))) {
|
|
|
|
/* the cycle handler: */
|
|
tlb->tme_bus_tlb_cycle = _tme_suncg2_bus_cycle_cmap;
|
|
|
|
/* this TLB entry covers this range: */
|
|
tlb->tme_bus_tlb_addr_first = TME_SUNCG2_REG_CMAP_R;
|
|
tlb->tme_bus_tlb_addr_last = TME_SUNCG2_SIZ_REGS - 1;
|
|
|
|
/* this TLB entry allows fast reading: */
|
|
tlb->tme_bus_tlb_emulator_off_read
|
|
= (((tme_uint8_t *) suncg2->tme_suncg2_cmap_raw)
|
|
- TME_SUNCG2_REG_CMAP_R);
|
|
}
|
|
|
|
/* XXX FIXME - this is a partial implementation: */
|
|
else {
|
|
abort();
|
|
}
|
|
|
|
/* unlock the mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* this makes a new framebuffer connection: */
|
|
static int
|
|
_tme_suncg2_connection_make(struct tme_connection *conn, unsigned int state)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
struct tme_fb_connection *conn_fb;
|
|
struct tme_fb_connection *conn_fb_other;
|
|
int rc;
|
|
|
|
/* recover our data structures: */
|
|
suncg2 = conn->tme_connection_element->tme_element_private;
|
|
conn_fb = (struct tme_fb_connection *) conn;
|
|
conn_fb_other = (struct tme_fb_connection *) conn->tme_connection_other;
|
|
|
|
/* both sides must be framebuffer connections: */
|
|
assert(conn->tme_connection_type == TME_CONNECTION_FRAMEBUFFER);
|
|
assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_FRAMEBUFFER);
|
|
|
|
/* lock our mutex: */
|
|
tme_mutex_lock(&suncg2->tme_suncg2_mutex);
|
|
|
|
/* once the connection is made, we know whether or not the other
|
|
side of the connection is supplying specific memory that it wants
|
|
us to use, or if we should allocate memory ourselves: */
|
|
if (conn_fb->tme_fb_connection_buffer == NULL) {
|
|
rc = tme_fb_xlat_alloc_src(conn_fb);
|
|
assert (rc == TME_OK);
|
|
}
|
|
suncg2->tme_suncg2_displayed_memory = conn_fb->tme_fb_connection_buffer;
|
|
|
|
/* invalidate any outstanding TLBs: */
|
|
_tme_suncg2_tlb_invalidate(suncg2, NULL);
|
|
|
|
/* the displayed memory is now invalid: */
|
|
suncg2->tme_suncg2_flags |= TME_SUNCG2_FLAG_INVALID_DISPLAYED;
|
|
|
|
/* we're always set up to answer calls across the connection, so we
|
|
only have to do work when the connection has gone full, namely
|
|
taking the other side of the connection: */
|
|
if (state == TME_CONNECTION_FULL) {
|
|
|
|
/* save our connection: */
|
|
suncg2->tme_suncg2_fb_connection = conn_fb_other;
|
|
}
|
|
|
|
/* unlock our mutex: */
|
|
tme_mutex_unlock(&suncg2->tme_suncg2_mutex);
|
|
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* this breaks a connection: */
|
|
static int
|
|
_tme_suncg2_connection_break(struct tme_connection *conn, unsigned int state)
|
|
{
|
|
abort();
|
|
}
|
|
|
|
/* this makes a new connection side for a suncg2: */
|
|
static int
|
|
_tme_suncg2_connections_new(struct tme_element *element,
|
|
const char * const *args,
|
|
struct tme_connection **_conns,
|
|
char **_output)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
struct tme_fb_connection *conn_fb;
|
|
struct tme_connection *conn;
|
|
int rc;
|
|
|
|
/* recover our data structure: */
|
|
suncg2 = (struct tme_suncg2 *) element->tme_element_private;
|
|
|
|
/* make the generic bus device connection side: */
|
|
rc = tme_bus_device_connections_new(element, args, _conns, _output);
|
|
if (rc != TME_OK) {
|
|
return (rc);
|
|
}
|
|
|
|
/* if we don't have a framebuffer connection, make one: */
|
|
if (suncg2->tme_suncg2_fb_connection == NULL) {
|
|
|
|
/* allocate the new framebuffer connection: */
|
|
conn_fb = tme_new0(struct tme_fb_connection, 1);
|
|
conn = &conn_fb->tme_fb_connection;
|
|
|
|
/* fill in the generic connection: */
|
|
conn->tme_connection_next = *_conns;
|
|
conn->tme_connection_type = TME_CONNECTION_FRAMEBUFFER;
|
|
conn->tme_connection_score = tme_fb_connection_score;
|
|
conn->tme_connection_make = _tme_suncg2_connection_make;
|
|
conn->tme_connection_break = _tme_suncg2_connection_break;
|
|
|
|
/* fill in the framebuffer connection: */
|
|
conn_fb->tme_fb_connection_mode_change = NULL;
|
|
conn_fb->tme_fb_connection_update = _tme_suncg2_update;
|
|
|
|
/* height and width: */
|
|
conn_fb->tme_fb_connection_width = tme_sunfb_size_width(suncg2->tme_suncg2_size);
|
|
conn_fb->tme_fb_connection_height = tme_sunfb_size_height(suncg2->tme_suncg2_size);
|
|
|
|
/* we are color: */
|
|
conn_fb->tme_fb_connection_class = TME_FB_XLAT_CLASS_COLOR;
|
|
conn_fb->tme_fb_connection_depth = TME_SUNCG2_PLANE_MAX;
|
|
conn_fb->tme_fb_connection_bits_per_pixel = TME_SUNCG2_PLANE_MAX;
|
|
|
|
/* we skip no pixels at the start of the scanline: */
|
|
conn_fb->tme_fb_connection_skipx = 0;
|
|
|
|
/* we pad to 32-bit boundaries: */
|
|
conn_fb->tme_fb_connection_scanline_pad = 32;
|
|
|
|
/* we are big-endian: */
|
|
conn_fb->tme_fb_connection_order = TME_ENDIAN_BIG;
|
|
|
|
/* we don't allocate memory until the connection is made, in case
|
|
the other side of the connection wants to provide us with a
|
|
specific memory region to use (maybe we're on a system with a
|
|
real cgtwo and we can write directly to its buffer): */
|
|
conn_fb->tme_fb_connection_buffer = NULL;
|
|
|
|
/* our pixels don't have subfields: */
|
|
conn_fb->tme_fb_connection_mask_g = 0;
|
|
conn_fb->tme_fb_connection_mask_r = 0;
|
|
conn_fb->tme_fb_connection_mask_b = 0;
|
|
|
|
/* intensities are eight bits and index mapped: */
|
|
conn_fb->tme_fb_connection_map_bits = (8 * sizeof(suncg2->tme_suncg2_cmap[0]));
|
|
conn_fb->tme_fb_connection_map_g = &suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(0, TME_SUNCG2_REG_CMAP_G)];
|
|
conn_fb->tme_fb_connection_map_r = &suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(0, TME_SUNCG2_REG_CMAP_R)];
|
|
conn_fb->tme_fb_connection_map_b = &suncg2->tme_suncg2_cmap[TME_SUNCG2_CMAP_INDEX(0, TME_SUNCG2_REG_CMAP_B)];
|
|
|
|
/* return the connection side possibility: */
|
|
*_conns = conn;
|
|
}
|
|
|
|
/* done: */
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* the new sun cgtwo function: */
|
|
int
|
|
tme_sun_cgtwo(struct tme_element *element, const char * const *args, char **_output)
|
|
{
|
|
struct tme_suncg2 *suncg2;
|
|
tme_uint32_t cg2_type;
|
|
tme_uint32_t cg2_size;
|
|
int arg_i;
|
|
int usage;
|
|
|
|
/* check our arguments: */
|
|
usage = 0;
|
|
cg2_type = TME_SUNCG2_TYPE_NULL;
|
|
cg2_size = TME_SUNFB_SIZE_1152_900;
|
|
arg_i = 1;
|
|
for (;;) {
|
|
|
|
/* the framebuffer type: */
|
|
if (TME_ARG_IS(args[arg_i + 0], "type")) {
|
|
if (TME_ARG_IS(args[arg_i + 1], "sun3")) {
|
|
cg2_type = TME_SUNCG2_TYPE_SUN3;
|
|
}
|
|
else {
|
|
usage = TRUE;
|
|
break;
|
|
}
|
|
arg_i += 2;
|
|
}
|
|
|
|
/* the framebuffer size: */
|
|
else if (TME_ARG_IS(args[arg_i + 0], "size")) {
|
|
cg2_size = tme_sunfb_size(args[arg_i + 1]);
|
|
if (cg2_size != TME_SUNFB_SIZE_1152_900
|
|
&& cg2_size != TME_SUNFB_SIZE_1024_1024) {
|
|
usage = TRUE;
|
|
break;
|
|
}
|
|
arg_i += 2;
|
|
}
|
|
|
|
/* if we ran out of arguments: */
|
|
else if (args[arg_i] == NULL) {
|
|
break;
|
|
}
|
|
|
|
/* otherwise this is a bad argument: */
|
|
else {
|
|
tme_output_append_error(_output,
|
|
"%s %s, ",
|
|
args[arg_i],
|
|
_("unexpected"));
|
|
usage = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* a cgtwo type must have been given: */
|
|
if (cg2_type == TME_SUNCG2_TYPE_NULL) {
|
|
usage = TRUE;
|
|
}
|
|
|
|
if (usage) {
|
|
tme_output_append_error(_output,
|
|
"%s %s type sun3 [ size { 1152x900 | 1024x1024 } ]",
|
|
_("usage:"),
|
|
args[0]);
|
|
return (EINVAL);
|
|
}
|
|
|
|
/* start the suncg2 structure: */
|
|
suncg2 = tme_new0(struct tme_suncg2, 1);
|
|
suncg2->tme_suncg2_element = element;
|
|
tme_mutex_init(&suncg2->tme_suncg2_mutex);
|
|
tme_rwlock_init(&suncg2->tme_suncg2_rwlock);
|
|
|
|
/* set the cgtwo type: */
|
|
suncg2->tme_suncg2_type = cg2_type;
|
|
|
|
/* set the cgtwo size: */
|
|
suncg2->tme_suncg2_size = cg2_size;
|
|
|
|
/* start displaying the pixmap: */
|
|
suncg2->tme_suncg2_bitmap_mode_plane = TME_SUNCG2_PLANE_MAX;
|
|
|
|
/* set our initial CSR: */
|
|
suncg2->tme_suncg2_csr
|
|
= (TME_SUNCG2_CSR_ENABLE_VIDEO
|
|
| (cg2_size == TME_SUNFB_SIZE_1024_1024
|
|
? TME_SUNCG2_CSR_SIZE_1024_1024
|
|
: TME_SUNCG2_CSR_SIZE_1152_900));
|
|
|
|
/* if this is a sun3 cgtwo: */
|
|
if (cg2_type == TME_SUNCG2_TYPE_SUN3) {
|
|
/* nothing to do */
|
|
}
|
|
|
|
/* calculate the pixel count: */
|
|
suncg2->tme_suncg2_pixel_count
|
|
= (tme_sunfb_size_width(cg2_size)
|
|
* tme_sunfb_size_height(cg2_size));
|
|
|
|
/* allocate the raw memory: */
|
|
suncg2->tme_suncg2_raw_memory
|
|
= tme_new0(tme_uint8_t, TME_SUNCG2_REG_PIXMAP + TME_SUNCG2_SIZ_PIXMAP);
|
|
|
|
/* initialize our simple bus device descriptor: */
|
|
suncg2->tme_suncg2_device.tme_bus_device_element = element;
|
|
suncg2->tme_suncg2_device.tme_bus_device_tlb_fill = _tme_suncg2_tlb_fill;
|
|
suncg2->tme_suncg2_device.tme_bus_device_address_last = TME_SUNCG2_SIZ_REGS - 1;
|
|
|
|
/* fill the element: */
|
|
element->tme_element_private = suncg2;
|
|
element->tme_element_connections_new = _tme_suncg2_connections_new;
|
|
|
|
return (TME_OK);
|
|
}
|