mirror of
https://github.com/libretro/PUAE.git
synced 2024-11-26 17:40:38 +00:00
2.7.0 part1
This commit is contained in:
parent
f4abf5efc2
commit
a0d31440ab
1
compile
Symbolic link
1
compile
Symbolic link
@ -0,0 +1 @@
|
||||
/usr/local/Cellar/automake/1.14/share/automake-1.14/compile
|
2154
src/gfxboard.c
Normal file
2154
src/gfxboard.c
Normal file
File diff suppressed because it is too large
Load Diff
23
src/include/gfxboard.h
Normal file
23
src/include/gfxboard.h
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
extern addrbank gfxboard_bank_memory;
|
||||
extern addrbank gfxboard_bank_registers;
|
||||
|
||||
extern void gfxboard_init_memory (void);
|
||||
extern void gfxboard_init_memory_p4_z2 (void);
|
||||
extern void gfxboard_init_registers (void);
|
||||
extern void gfxboard_free (void);
|
||||
extern void gfxboard_reset (void);
|
||||
extern void gfxboard_vsync_handler (void);
|
||||
extern bool gfxboard_is_z3 (int);
|
||||
extern bool gfxboard_is_registers (int);
|
||||
extern int gfxboard_get_vram_min (int);
|
||||
extern int gfxboard_get_vram_max (int);
|
||||
extern bool gfxboard_need_byteswap (int type);
|
||||
extern double gfxboard_get_vsync (void);
|
||||
extern void gfxboard_refresh (void);
|
||||
extern bool gfxboard_toggle (int mode);
|
||||
extern int gfxboard_num_boards (int type);
|
||||
|
||||
#define GFXBOARD_UAE_Z2 0
|
||||
#define GFXBOARD_UAE_Z3 1
|
||||
#define GFXBOARD_HARDWARE 2
|
3122
src/qemuvga/cirrus_vga.c
Normal file
3122
src/qemuvga/cirrus_vga.c
Normal file
File diff suppressed because it is too large
Load Diff
223
src/qemuvga/cirrus_vga_rop.h
Normal file
223
src/qemuvga/cirrus_vga_rop.h
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* QEMU Cirrus CLGD 54xx VGA Emulator.
|
||||
*
|
||||
* Copyright (c) 2004 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
STATIC_INLINE void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
|
||||
{
|
||||
*dst = ROP_FN(*dst, src);
|
||||
}
|
||||
|
||||
STATIC_INLINE void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
|
||||
{
|
||||
*dst = ROP_FN(*dst, src);
|
||||
}
|
||||
|
||||
STATIC_INLINE void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
|
||||
{
|
||||
*dst = ROP_FN(*dst, src);
|
||||
}
|
||||
|
||||
#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
|
||||
#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
|
||||
#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
|
||||
#undef ROP_FN
|
||||
|
||||
static void
|
||||
glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
|
||||
#if 0
|
||||
/* Invalid test! TW */
|
||||
if (dstpitch < 0 || srcpitch < 0) {
|
||||
/* is 0 valid? srcpitch == 0 could be useful */
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < (bltwidth & ~3); x += 4) {
|
||||
ROP_OP_32((uint32_t*)dst, *((uint32_t*)src));
|
||||
dst += 4;
|
||||
src += 4;
|
||||
}
|
||||
for (; x < bltwidth; x++) {
|
||||
ROP_OP(dst, *src);
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
dstpitch += bltwidth;
|
||||
srcpitch += bltwidth;
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < (bltwidth & ~3); x += 4) {
|
||||
dst -= 3;
|
||||
src -= 3;
|
||||
ROP_OP_32((uint32_t*)dst, *((uint32_t*)src));
|
||||
dst -= 1;
|
||||
src -= 1;
|
||||
}
|
||||
for (; x < bltwidth; x++) {
|
||||
ROP_OP(dst, *src);
|
||||
dst--;
|
||||
src--;
|
||||
}
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
uint8_t p;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x++) {
|
||||
p = *dst;
|
||||
ROP_OP(&p, *src);
|
||||
if (p != s->vga.gr[0x34]) *dst = p;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
uint8_t p;
|
||||
dstpitch += bltwidth;
|
||||
srcpitch += bltwidth;
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x++) {
|
||||
p = *dst;
|
||||
ROP_OP(&p, *src);
|
||||
if (p != s->vga.gr[0x34]) *dst = p;
|
||||
dst--;
|
||||
src--;
|
||||
}
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
uint8_t p1, p2;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x+=2) {
|
||||
p1 = *dst;
|
||||
p2 = *(dst+1);
|
||||
ROP_OP(&p1, *src);
|
||||
ROP_OP(&p2, *(src + 1));
|
||||
if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
|
||||
*dst = p1;
|
||||
*(dst+1) = p2;
|
||||
}
|
||||
dst+=2;
|
||||
src+=2;
|
||||
}
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
uint8_t p1, p2;
|
||||
dstpitch += bltwidth;
|
||||
srcpitch += bltwidth;
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x+=2) {
|
||||
p1 = *(dst-1);
|
||||
p2 = *dst;
|
||||
ROP_OP(&p1, *(src - 1));
|
||||
ROP_OP(&p2, *src);
|
||||
if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
|
||||
*(dst-1) = p1;
|
||||
*dst = p2;
|
||||
}
|
||||
dst-=2;
|
||||
src-=2;
|
||||
}
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
#define DEPTH 8
|
||||
#include "cirrus_vga_rop2.h"
|
||||
|
||||
#define DEPTH 16
|
||||
#include "cirrus_vga_rop2.h"
|
||||
|
||||
#define DEPTH 24
|
||||
#include "cirrus_vga_rop2.h"
|
||||
|
||||
#define DEPTH 32
|
||||
#include "cirrus_vga_rop2.h"
|
||||
|
||||
#undef ROP_NAME
|
||||
#undef ROP_OP
|
||||
#undef ROP_OP_16
|
||||
#undef ROP_OP_32
|
283
src/qemuvga/cirrus_vga_rop2.h
Normal file
283
src/qemuvga/cirrus_vga_rop2.h
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* QEMU Cirrus CLGD 54xx VGA Emulator.
|
||||
*
|
||||
* Copyright (c) 2004 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if DEPTH == 8
|
||||
#define PUTPIXEL() ROP_OP(&d[0], col)
|
||||
#elif DEPTH == 16
|
||||
#define PUTPIXEL() ROP_OP_16((uint16_t *)&d[0], col)
|
||||
#elif DEPTH == 24
|
||||
#define PUTPIXEL() ROP_OP(&d[0], col); \
|
||||
ROP_OP(&d[1], (col >> 8)); \
|
||||
ROP_OP(&d[2], (col >> 16))
|
||||
#elif DEPTH == 32
|
||||
#define PUTPIXEL() ROP_OP_32(((uint32_t *)&d[0]), col)
|
||||
#else
|
||||
#error unsupported DEPTH
|
||||
#endif
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint8_t *d;
|
||||
int x, y, pattern_y, pattern_pitch, pattern_x;
|
||||
unsigned int col;
|
||||
const uint8_t *src1;
|
||||
#if DEPTH == 24
|
||||
int skipleft = s->vga.gr[0x2f] & 0x1f;
|
||||
#else
|
||||
int skipleft = (s->vga.gr[0x2f] & 0x07) * (DEPTH / 8);
|
||||
#endif
|
||||
|
||||
#if DEPTH == 8
|
||||
pattern_pitch = 8;
|
||||
#elif DEPTH == 16
|
||||
pattern_pitch = 16;
|
||||
#else
|
||||
pattern_pitch = 32;
|
||||
#endif
|
||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
pattern_x = skipleft;
|
||||
d = dst + skipleft;
|
||||
src1 = src + pattern_y * pattern_pitch;
|
||||
for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
#if DEPTH == 8
|
||||
col = src1[pattern_x];
|
||||
pattern_x = (pattern_x + 1) & 7;
|
||||
#elif DEPTH == 16
|
||||
col = ((uint16_t *)(src1 + pattern_x))[0];
|
||||
pattern_x = (pattern_x + 2) & 15;
|
||||
#elif DEPTH == 24
|
||||
{
|
||||
const uint8_t *src2 = src1 + pattern_x * 3;
|
||||
col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
|
||||
pattern_x = (pattern_x + 1) & 7;
|
||||
}
|
||||
#else
|
||||
col = ((uint32_t *)(src1 + pattern_x))[0];
|
||||
pattern_x = (pattern_x + 4) & 31;
|
||||
#endif
|
||||
PUTPIXEL();
|
||||
d += (DEPTH / 8);
|
||||
}
|
||||
pattern_y = (pattern_y + 1) & 7;
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: srcpitch is ignored */
|
||||
static void
|
||||
glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint8_t *d;
|
||||
int x, y;
|
||||
unsigned bits, bits_xor;
|
||||
unsigned int col;
|
||||
unsigned bitmask;
|
||||
unsigned index;
|
||||
#if DEPTH == 24
|
||||
int dstskipleft = s->vga.gr[0x2f] & 0x1f;
|
||||
int srcskipleft = dstskipleft / 3;
|
||||
#else
|
||||
int srcskipleft = s->vga.gr[0x2f] & 0x07;
|
||||
int dstskipleft = srcskipleft * (DEPTH / 8);
|
||||
#endif
|
||||
|
||||
if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
|
||||
bits_xor = 0xff;
|
||||
// Color expansion + transparency: fgcol, not bgcol. TW.
|
||||
col = s->cirrus_blt_fgcol;
|
||||
} else {
|
||||
bits_xor = 0x00;
|
||||
col = s->cirrus_blt_fgcol;
|
||||
}
|
||||
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
bitmask = 0x80 >> srcskipleft;
|
||||
bits = *src++ ^ bits_xor;
|
||||
d = dst + dstskipleft;
|
||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
if ((bitmask & 0xff) == 0) {
|
||||
bitmask = 0x80;
|
||||
bits = *src++ ^ bits_xor;
|
||||
}
|
||||
index = (bits & bitmask);
|
||||
if (index) {
|
||||
PUTPIXEL();
|
||||
}
|
||||
d += (DEPTH / 8);
|
||||
bitmask >>= 1;
|
||||
}
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint32_t colors[2];
|
||||
uint8_t *d;
|
||||
int x, y;
|
||||
unsigned bits;
|
||||
unsigned int col;
|
||||
unsigned bitmask;
|
||||
int srcskipleft = s->vga.gr[0x2f] & 0x07;
|
||||
int dstskipleft = srcskipleft * (DEPTH / 8);
|
||||
|
||||
colors[0] = s->cirrus_blt_bgcol;
|
||||
colors[1] = s->cirrus_blt_fgcol;
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
bitmask = 0x80 >> srcskipleft;
|
||||
bits = *src++;
|
||||
d = dst + dstskipleft;
|
||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
if ((bitmask & 0xff) == 0) {
|
||||
bitmask = 0x80;
|
||||
bits = *src++;
|
||||
}
|
||||
col = colors[!!(bits & bitmask)];
|
||||
PUTPIXEL();
|
||||
d += (DEPTH / 8);
|
||||
bitmask >>= 1;
|
||||
}
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint8_t *d;
|
||||
int x, y, bitpos, pattern_y;
|
||||
unsigned int bits, bits_xor;
|
||||
unsigned int col;
|
||||
#if DEPTH == 24
|
||||
int dstskipleft = s->vga.gr[0x2f] & 0x1f;
|
||||
int srcskipleft = dstskipleft / 3;
|
||||
#else
|
||||
int srcskipleft = s->vga.gr[0x2f] & 0x07;
|
||||
int dstskipleft = srcskipleft * (DEPTH / 8);
|
||||
#endif
|
||||
|
||||
if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
|
||||
bits_xor = 0xff;
|
||||
// Color expansion + transparency: fgcol, not bgcol. TW.
|
||||
col = s->cirrus_blt_fgcol;
|
||||
} else {
|
||||
bits_xor = 0x00;
|
||||
col = s->cirrus_blt_fgcol;
|
||||
}
|
||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
bits = src[pattern_y] ^ bits_xor;
|
||||
bitpos = 7 - srcskipleft;
|
||||
d = dst + dstskipleft;
|
||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
if ((bits >> bitpos) & 1) {
|
||||
PUTPIXEL();
|
||||
}
|
||||
d += (DEPTH / 8);
|
||||
bitpos = (bitpos - 1) & 7;
|
||||
}
|
||||
pattern_y = (pattern_y + 1) & 7;
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint32_t colors[2];
|
||||
uint8_t *d;
|
||||
int x, y, bitpos, pattern_y;
|
||||
unsigned int bits;
|
||||
unsigned int col;
|
||||
int srcskipleft = s->vga.gr[0x2f] & 0x07;
|
||||
int dstskipleft = srcskipleft * (DEPTH / 8);
|
||||
|
||||
colors[0] = s->cirrus_blt_bgcol;
|
||||
colors[1] = s->cirrus_blt_fgcol;
|
||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
bits = src[pattern_y];
|
||||
bitpos = 7 - srcskipleft;
|
||||
d = dst + dstskipleft;
|
||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
col = colors[(bits >> bitpos) & 1];
|
||||
PUTPIXEL();
|
||||
d += (DEPTH / 8);
|
||||
bitpos = (bitpos - 1) & 7;
|
||||
}
|
||||
pattern_y = (pattern_y + 1) & 7;
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState *s,
|
||||
uint8_t *dst, int dst_pitch,
|
||||
int width, int height)
|
||||
{
|
||||
uint8_t *d, *d1;
|
||||
uint32_t col;
|
||||
int x, y;
|
||||
|
||||
col = s->cirrus_blt_fgcol;
|
||||
|
||||
d1 = dst;
|
||||
for(y = 0; y < height; y++) {
|
||||
d = d1;
|
||||
for(x = 0; x < width; x += (DEPTH / 8)) {
|
||||
PUTPIXEL();
|
||||
d += (DEPTH / 8);
|
||||
}
|
||||
d1 += dst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEPTH
|
||||
#undef PUTPIXEL
|
102
src/qemuvga/cirrus_vga_template.h
Normal file
102
src/qemuvga/cirrus_vga_template.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* QEMU Cirrus VGA Emulator templates
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if DEPTH == 8
|
||||
#define BPP 1
|
||||
#elif DEPTH == 15 || DEPTH == 16
|
||||
#define BPP 2
|
||||
#elif DEPTH == 32
|
||||
#define BPP 4
|
||||
#else
|
||||
#error unsupported depth
|
||||
#endif
|
||||
|
||||
static void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
|
||||
const uint8_t *src1,
|
||||
int poffset, int w,
|
||||
unsigned int color0,
|
||||
unsigned int color1,
|
||||
unsigned int color_xor)
|
||||
{
|
||||
const uint8_t *plane0, *plane1;
|
||||
int x, b0, b1;
|
||||
uint8_t *d;
|
||||
|
||||
d = d1;
|
||||
plane0 = src1;
|
||||
plane1 = src1 + poffset;
|
||||
for (x = 0; x < w; x++) {
|
||||
b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
|
||||
b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
|
||||
#if DEPTH == 8
|
||||
switch (b0 | (b1 << 1)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
d[0] ^= color_xor;
|
||||
break;
|
||||
case 2:
|
||||
d[0] = color0;
|
||||
break;
|
||||
case 3:
|
||||
d[0] = color1;
|
||||
break;
|
||||
}
|
||||
#elif DEPTH == 16
|
||||
switch (b0 | (b1 << 1)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
((uint16_t *)d)[0] ^= color_xor;
|
||||
break;
|
||||
case 2:
|
||||
((uint16_t *)d)[0] = color0;
|
||||
break;
|
||||
case 3:
|
||||
((uint16_t *)d)[0] = color1;
|
||||
break;
|
||||
}
|
||||
#elif DEPTH == 32
|
||||
switch (b0 | (b1 << 1)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
((uint32_t *)d)[0] ^= color_xor;
|
||||
break;
|
||||
case 2:
|
||||
((uint32_t *)d)[0] = color0;
|
||||
break;
|
||||
case 3:
|
||||
((uint32_t *)d)[0] = color1;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
#error unsupported depth
|
||||
#endif
|
||||
d += BPP;
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEPTH
|
||||
#undef BPP
|
53
src/qemuvga/pixel_ops.h
Normal file
53
src/qemuvga/pixel_ops.h
Normal file
@ -0,0 +1,53 @@
|
||||
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
|
||||
}
|
||||
|
||||
static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
|
||||
}
|
||||
|
||||
static inline unsigned int rgb_to_pixel15bgr(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3);
|
||||
}
|
||||
|
||||
static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
|
||||
}
|
||||
|
||||
static inline unsigned int rgb_to_pixel16bgr(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3);
|
||||
}
|
||||
|
||||
static inline unsigned int rgb_to_pixel24(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
static inline unsigned int rgb_to_pixel24bgr(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g,
|
||||
unsigned int b)
|
||||
{
|
||||
return (b << 16) | (g << 8) | r;
|
||||
}
|
902
src/qemuvga/qemumemory.h
Normal file
902
src/qemuvga/qemumemory.h
Normal file
@ -0,0 +1,902 @@
|
||||
/*
|
||||
* Physical memory management API
|
||||
*
|
||||
* Copyright 2011 Red Hat, Inc. and/or its affiliates
|
||||
*
|
||||
* Authors:
|
||||
* Avi Kivity <avi@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct MemoryRegionOps MemoryRegionOps;
|
||||
typedef struct MemoryRegionPortio MemoryRegionPortio;
|
||||
typedef struct MemoryRegionMmio MemoryRegionMmio;
|
||||
|
||||
/* Must match *_DIRTY_FLAGS in cpu-all.h. To be replaced with dynamic
|
||||
* registration.
|
||||
*/
|
||||
#define DIRTY_MEMORY_VGA 0
|
||||
#define DIRTY_MEMORY_CODE 1
|
||||
#define DIRTY_MEMORY_MIGRATION 3
|
||||
|
||||
struct MemoryRegionMmio {
|
||||
CPUReadMemoryFunc *read[3];
|
||||
CPUWriteMemoryFunc *write[3];
|
||||
};
|
||||
|
||||
/* Internal use; thunks between old-style IORange and MemoryRegions. */
|
||||
typedef struct MemoryRegionIORange MemoryRegionIORange;
|
||||
struct MemoryRegionIORange {
|
||||
IORange iorange;
|
||||
//MemoryRegion *mr;
|
||||
hwaddr offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* Memory region callbacks
|
||||
*/
|
||||
struct MemoryRegionOps {
|
||||
/* Read from the memory region. @addr is relative to @mr; @size is
|
||||
* in bytes. */
|
||||
uint64_t (*read)(void *opaque,
|
||||
hwaddr addr,
|
||||
unsigned size);
|
||||
/* Write to the memory region. @addr is relative to @mr; @size is
|
||||
* in bytes. */
|
||||
void (*write)(void *opaque,
|
||||
hwaddr addr,
|
||||
uint64_t data,
|
||||
unsigned size);
|
||||
|
||||
enum device_endian endianness;
|
||||
/* Guest-visible constraints: */
|
||||
struct {
|
||||
/* If nonzero, specify bounds on access sizes beyond which a machine
|
||||
* check is thrown.
|
||||
*/
|
||||
unsigned min_access_size;
|
||||
unsigned max_access_size;
|
||||
/* If true, unaligned accesses are supported. Otherwise unaligned
|
||||
* accesses throw machine checks.
|
||||
*/
|
||||
bool unaligned;
|
||||
/*
|
||||
* If present, and returns #false, the transaction is not accepted
|
||||
* by the device (and results in machine dependent behaviour such
|
||||
* as a machine check exception).
|
||||
*/
|
||||
bool (*accepts)(void *opaque, hwaddr addr,
|
||||
unsigned size, bool is_write);
|
||||
} valid;
|
||||
/* Internal implementation constraints: */
|
||||
struct {
|
||||
/* If nonzero, specifies the minimum size implemented. Smaller sizes
|
||||
* will be rounded upwards and a partial result will be returned.
|
||||
*/
|
||||
unsigned min_access_size;
|
||||
/* If nonzero, specifies the maximum size implemented. Larger sizes
|
||||
* will be done as a series of accesses with smaller sizes.
|
||||
*/
|
||||
unsigned max_access_size;
|
||||
/* If true, unaligned accesses are supported. Otherwise all accesses
|
||||
* are converted to (possibly multiple) naturally aligned accesses.
|
||||
*/
|
||||
bool unaligned;
|
||||
} impl;
|
||||
#if 0
|
||||
/* If .read and .write are not present, old_portio may be used for
|
||||
* backwards compatibility with old portio registration
|
||||
*/
|
||||
const MemoryRegionPortio *old_portio;
|
||||
/* If .read and .write are not present, old_mmio may be used for
|
||||
* backwards compatibility with old mmio registration
|
||||
*/
|
||||
const MemoryRegionMmio old_mmio;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct CoalescedMemoryRange CoalescedMemoryRange;
|
||||
typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
|
||||
|
||||
typedef struct MemoryRegion {
|
||||
/* All fields are private - violators will be prosecuted */
|
||||
void *opaque;
|
||||
#if 0
|
||||
const MemoryRegionOps *ops;
|
||||
MemoryRegion *parent;
|
||||
Int128 size;
|
||||
hwaddr addr;
|
||||
void (*destructor)(MemoryRegion *mr);
|
||||
ram_addr_t ram_addr;
|
||||
bool subpage;
|
||||
bool terminates;
|
||||
bool readable;
|
||||
bool ram;
|
||||
bool readonly; /* For RAM regions */
|
||||
bool enabled;
|
||||
bool rom_device;
|
||||
bool warning_printed; /* For reservations */
|
||||
bool flush_coalesced_mmio;
|
||||
MemoryRegion *alias;
|
||||
hwaddr alias_offset;
|
||||
unsigned priority;
|
||||
bool may_overlap;
|
||||
QTAILQ_HEAD(subregions, MemoryRegion) subregions;
|
||||
QTAILQ_ENTRY(MemoryRegion) subregions_link;
|
||||
QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coalesced;
|
||||
const char *name;
|
||||
uint8_t dirty_log_mask;
|
||||
unsigned ioeventfd_nb;
|
||||
MemoryRegionIoeventfd *ioeventfds;
|
||||
#endif
|
||||
} MemoryRegion;
|
||||
|
||||
struct MemoryRegionPortio {
|
||||
uint32_t offset;
|
||||
uint32_t len;
|
||||
unsigned size;
|
||||
IOPortReadFunc *read;
|
||||
IOPortWriteFunc *write;
|
||||
};
|
||||
|
||||
#define PORTIO_END_OF_LIST() { }
|
||||
|
||||
/**
|
||||
* AddressSpace: describes a mapping of addresses to #MemoryRegion objects
|
||||
*/
|
||||
typedef struct AddressSpace AddressSpace;
|
||||
struct AddressSpace {
|
||||
/* All fields are private. */
|
||||
const char *name;
|
||||
MemoryRegion *root;
|
||||
struct FlatView *current_map;
|
||||
int ioeventfd_nb;
|
||||
struct MemoryRegionIoeventfd *ioeventfds;
|
||||
struct AddressSpaceDispatch *dispatch;
|
||||
#if 0
|
||||
QTAILQ_ENTRY(AddressSpace) address_spaces_link;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* MemoryRegionSection: describes a fragment of a #MemoryRegion
|
||||
*
|
||||
* @mr: the region, or %NULL if empty
|
||||
* @address_space: the address space the region is mapped in
|
||||
* @offset_within_region: the beginning of the section, relative to @mr's start
|
||||
* @size: the size of the section; will not exceed @mr's boundaries
|
||||
* @offset_within_address_space: the address of the first byte of the section
|
||||
* relative to the region's address space
|
||||
* @readonly: writes to this section are ignored
|
||||
*/
|
||||
typedef struct MemoryRegionSection MemoryRegionSection;
|
||||
struct MemoryRegionSection {
|
||||
MemoryRegion *mr;
|
||||
AddressSpace *address_space;
|
||||
hwaddr offset_within_region;
|
||||
uint64_t size;
|
||||
hwaddr offset_within_address_space;
|
||||
bool readonly;
|
||||
};
|
||||
|
||||
typedef struct MemoryListener MemoryListener;
|
||||
|
||||
/**
|
||||
* MemoryListener: callbacks structure for updates to the physical memory map
|
||||
*
|
||||
* Allows a component to adjust to changes in the guest-visible memory map.
|
||||
* Use with memory_listener_register() and memory_listener_unregister().
|
||||
*/
|
||||
struct MemoryListener {
|
||||
void (*begin)(MemoryListener *listener);
|
||||
void (*commit)(MemoryListener *listener);
|
||||
void (*region_add)(MemoryListener *listener, MemoryRegionSection *section);
|
||||
void (*region_del)(MemoryListener *listener, MemoryRegionSection *section);
|
||||
void (*region_nop)(MemoryListener *listener, MemoryRegionSection *section);
|
||||
void (*log_start)(MemoryListener *listener, MemoryRegionSection *section);
|
||||
void (*log_stop)(MemoryListener *listener, MemoryRegionSection *section);
|
||||
void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section);
|
||||
void (*log_global_start)(MemoryListener *listener);
|
||||
void (*log_global_stop)(MemoryListener *listener);
|
||||
#if 0
|
||||
void (*eventfd_add)(MemoryListener *listener, MemoryRegionSection *section,
|
||||
bool match_data, uint64_t data, EventNotifier *e);
|
||||
void (*eventfd_del)(MemoryListener *listener, MemoryRegionSection *section,
|
||||
bool match_data, uint64_t data, EventNotifier *e);
|
||||
void (*coalesced_mmio_add)(MemoryListener *listener, MemoryRegionSection *section,
|
||||
hwaddr addr, hwaddr len);
|
||||
void (*coalesced_mmio_del)(MemoryListener *listener, MemoryRegionSection *section,
|
||||
hwaddr addr, hwaddr len);
|
||||
#endif
|
||||
/* Lower = earlier (during add), later (during del) */
|
||||
unsigned priority;
|
||||
AddressSpace *address_space_filter;
|
||||
#if 0
|
||||
QTAILQ_ENTRY(MemoryListener) link;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* memory_region_init: Initialize a memory region
|
||||
*
|
||||
* The region typically acts as a container for other memory regions. Use
|
||||
* memory_region_add_subregion() to add subregions.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized
|
||||
* @name: used for debugging; not visible to the user or ABI
|
||||
* @size: size of the region; any subregions beyond this size will be clipped
|
||||
*/
|
||||
void memory_region_init(MemoryRegion *mr,
|
||||
const char *name,
|
||||
uint64_t size);
|
||||
/**
|
||||
* memory_region_init_io: Initialize an I/O memory region.
|
||||
*
|
||||
* Accesses into the region will cause the callbacks in @ops to be called.
|
||||
* if @size is nonzero, subregions will be clipped to @size.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized.
|
||||
* @ops: a structure containing read and write callbacks to be used when
|
||||
* I/O is performed on the region.
|
||||
* @opaque: passed to to the read and write callbacks of the @ops structure.
|
||||
* @name: used for debugging; not visible to the user or ABI
|
||||
* @size: size of the region.
|
||||
*/
|
||||
void memory_region_init_io(MemoryRegion *mr,
|
||||
const MemoryRegionOps *ops,
|
||||
void *opaque,
|
||||
const char *name,
|
||||
uint64_t size);
|
||||
|
||||
/**
|
||||
* memory_region_init_ram: Initialize RAM memory region. Accesses into the
|
||||
* region will modify memory directly.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized.
|
||||
* @name: the name of the region.
|
||||
* @size: size of the region.
|
||||
*/
|
||||
void memory_region_init_ram(MemoryRegion *mr,
|
||||
const char *name,
|
||||
uint64_t size);
|
||||
|
||||
/**
|
||||
* memory_region_init_ram_ptr: Initialize RAM memory region from a
|
||||
* user-provided pointer. Accesses into the
|
||||
* region will modify memory directly.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized.
|
||||
* @name: the name of the region.
|
||||
* @size: size of the region.
|
||||
* @ptr: memory to be mapped; must contain at least @size bytes.
|
||||
*/
|
||||
void memory_region_init_ram_ptr(MemoryRegion *mr,
|
||||
const char *name,
|
||||
uint64_t size,
|
||||
void *ptr);
|
||||
|
||||
/**
|
||||
* memory_region_init_alias: Initialize a memory region that aliases all or a
|
||||
* part of another memory region.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized.
|
||||
* @name: used for debugging; not visible to the user or ABI
|
||||
* @orig: the region to be referenced; @mr will be equivalent to
|
||||
* @orig between @offset and @offset + @size - 1.
|
||||
* @offset: start of the section in @orig to be referenced.
|
||||
* @size: size of the region.
|
||||
*/
|
||||
void memory_region_init_alias(MemoryRegion *mr,
|
||||
const char *name,
|
||||
MemoryRegion *orig,
|
||||
hwaddr offset,
|
||||
uint64_t size);
|
||||
|
||||
/**
|
||||
* memory_region_init_rom_device: Initialize a ROM memory region. Writes are
|
||||
* handled via callbacks.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized.
|
||||
* @ops: callbacks for write access handling.
|
||||
* @name: the name of the region.
|
||||
* @size: size of the region.
|
||||
*/
|
||||
void memory_region_init_rom_device(MemoryRegion *mr,
|
||||
const MemoryRegionOps *ops,
|
||||
void *opaque,
|
||||
const char *name,
|
||||
uint64_t size);
|
||||
|
||||
/**
|
||||
* memory_region_init_reservation: Initialize a memory region that reserves
|
||||
* I/O space.
|
||||
*
|
||||
* A reservation region primariy serves debugging purposes. It claims I/O
|
||||
* space that is not supposed to be handled by QEMU itself. Any access via
|
||||
* the memory API will cause an abort().
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized
|
||||
* @name: used for debugging; not visible to the user or ABI
|
||||
* @size: size of the region.
|
||||
*/
|
||||
void memory_region_init_reservation(MemoryRegion *mr,
|
||||
const char *name,
|
||||
uint64_t size);
|
||||
/**
|
||||
* memory_region_destroy: Destroy a memory region and reclaim all resources.
|
||||
*
|
||||
* @mr: the region to be destroyed. May not currently be a subregion
|
||||
* (see memory_region_add_subregion()) or referenced in an alias
|
||||
* (see memory_region_init_alias()).
|
||||
*/
|
||||
void memory_region_destroy(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_size: get a memory region's size.
|
||||
*
|
||||
* @mr: the memory region being queried.
|
||||
*/
|
||||
uint64_t memory_region_size(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_is_ram: check whether a memory region is random access
|
||||
*
|
||||
* Returns %true is a memory region is random access.
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
bool memory_region_is_ram(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_is_romd: check whether a memory region is ROMD
|
||||
*
|
||||
* Returns %true is a memory region is ROMD and currently set to allow
|
||||
* direct reads.
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
#if 0
|
||||
static inline bool memory_region_is_romd(MemoryRegion *mr)
|
||||
{
|
||||
return mr->rom_device && mr->readable;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* memory_region_name: get a memory region's name
|
||||
*
|
||||
* Returns the string that was used to initialize the memory region.
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
const char *memory_region_name(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_is_logging: return whether a memory region is logging writes
|
||||
*
|
||||
* Returns %true if the memory region is logging writes
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
bool memory_region_is_logging(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_is_rom: check whether a memory region is ROM
|
||||
*
|
||||
* Returns %true is a memory region is read-only memory.
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
bool memory_region_is_rom(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_get_ram_ptr: Get a pointer into a RAM memory region.
|
||||
*
|
||||
* Returns a host pointer to a RAM memory region (created with
|
||||
* memory_region_init_ram() or memory_region_init_ram_ptr()). Use with
|
||||
* care.
|
||||
*
|
||||
* @mr: the memory region being queried.
|
||||
*/
|
||||
void *memory_region_get_ram_ptr(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_set_log: Turn dirty logging on or off for a region.
|
||||
*
|
||||
* Turns dirty logging on or off for a specified client (display, migration).
|
||||
* Only meaningful for RAM regions.
|
||||
*
|
||||
* @mr: the memory region being updated.
|
||||
* @log: whether dirty logging is to be enabled or disabled.
|
||||
* @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
|
||||
* %DIRTY_MEMORY_VGA.
|
||||
*/
|
||||
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
|
||||
|
||||
/**
|
||||
* memory_region_get_dirty: Check whether a range of bytes is dirty
|
||||
* for a specified client.
|
||||
*
|
||||
* Checks whether a range of bytes has been written to since the last
|
||||
* call to memory_region_reset_dirty() with the same @client. Dirty logging
|
||||
* must be enabled.
|
||||
*
|
||||
* @mr: the memory region being queried.
|
||||
* @addr: the address (relative to the start of the region) being queried.
|
||||
* @size: the size of the range being queried.
|
||||
* @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
|
||||
* %DIRTY_MEMORY_VGA.
|
||||
*/
|
||||
bool memory_region_get_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
hwaddr size, unsigned client);
|
||||
|
||||
/**
|
||||
* memory_region_set_dirty: Mark a range of bytes as dirty in a memory region.
|
||||
*
|
||||
* Marks a range of bytes as dirty, after it has been dirtied outside
|
||||
* guest code.
|
||||
*
|
||||
* @mr: the memory region being dirtied.
|
||||
* @addr: the address (relative to the start of the region) being dirtied.
|
||||
* @size: size of the range being dirtied.
|
||||
*/
|
||||
void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
hwaddr size);
|
||||
|
||||
/**
|
||||
* memory_region_test_and_clear_dirty: Check whether a range of bytes is dirty
|
||||
* for a specified client. It clears them.
|
||||
*
|
||||
* Checks whether a range of bytes has been written to since the last
|
||||
* call to memory_region_reset_dirty() with the same @client. Dirty logging
|
||||
* must be enabled.
|
||||
*
|
||||
* @mr: the memory region being queried.
|
||||
* @addr: the address (relative to the start of the region) being queried.
|
||||
* @size: the size of the range being queried.
|
||||
* @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
|
||||
* %DIRTY_MEMORY_VGA.
|
||||
*/
|
||||
bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
hwaddr size, unsigned client);
|
||||
/**
|
||||
* memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
|
||||
* any external TLBs (e.g. kvm)
|
||||
*
|
||||
* Flushes dirty information from accelerators such as kvm and vhost-net
|
||||
* and makes it available to users of the memory API.
|
||||
*
|
||||
* @mr: the region being flushed.
|
||||
*/
|
||||
void memory_region_sync_dirty_bitmap(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_reset_dirty: Mark a range of pages as clean, for a specified
|
||||
* client.
|
||||
*
|
||||
* Marks a range of pages as no longer dirty.
|
||||
*
|
||||
* @mr: the region being updated.
|
||||
* @addr: the start of the subrange being cleaned.
|
||||
* @size: the size of the subrange being cleaned.
|
||||
* @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
|
||||
* %DIRTY_MEMORY_VGA.
|
||||
*/
|
||||
void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
hwaddr size, unsigned client);
|
||||
|
||||
/**
|
||||
* memory_region_set_readonly: Turn a memory region read-only (or read-write)
|
||||
*
|
||||
* Allows a memory region to be marked as read-only (turning it into a ROM).
|
||||
* only useful on RAM regions.
|
||||
*
|
||||
* @mr: the region being updated.
|
||||
* @readonly: whether rhe region is to be ROM or RAM.
|
||||
*/
|
||||
void memory_region_set_readonly(MemoryRegion *mr, bool readonly);
|
||||
|
||||
/**
|
||||
* memory_region_rom_device_set_readable: enable/disable ROM readability
|
||||
*
|
||||
* Allows a ROM device (initialized with memory_region_init_rom_device() to
|
||||
* to be marked as readable (default) or not readable. When it is readable,
|
||||
* the device is mapped to guest memory. When not readable, reads are
|
||||
* forwarded to the #MemoryRegion.read function.
|
||||
*
|
||||
* @mr: the memory region to be updated
|
||||
* @readable: whether reads are satisified directly (%true) or via callbacks
|
||||
* (%false)
|
||||
*/
|
||||
void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable);
|
||||
|
||||
/**
|
||||
* memory_region_set_coalescing: Enable memory coalescing for the region.
|
||||
*
|
||||
* Enabled writes to a region to be queued for later processing. MMIO ->write
|
||||
* callbacks may be delayed until a non-coalesced MMIO is issued.
|
||||
* Only useful for IO regions. Roughly similar to write-combining hardware.
|
||||
*
|
||||
* @mr: the memory region to be write coalesced
|
||||
*/
|
||||
void memory_region_set_coalescing(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_add_coalescing: Enable memory coalescing for a sub-range of
|
||||
* a region.
|
||||
*
|
||||
* Like memory_region_set_coalescing(), but works on a sub-range of a region.
|
||||
* Multiple calls can be issued coalesced disjoint ranges.
|
||||
*
|
||||
* @mr: the memory region to be updated.
|
||||
* @offset: the start of the range within the region to be coalesced.
|
||||
* @size: the size of the subrange to be coalesced.
|
||||
*/
|
||||
void memory_region_add_coalescing(MemoryRegion *mr,
|
||||
hwaddr offset,
|
||||
uint64_t size);
|
||||
|
||||
/**
|
||||
* memory_region_clear_coalescing: Disable MMIO coalescing for the region.
|
||||
*
|
||||
* Disables any coalescing caused by memory_region_set_coalescing() or
|
||||
* memory_region_add_coalescing(). Roughly equivalent to uncacheble memory
|
||||
* hardware.
|
||||
*
|
||||
* @mr: the memory region to be updated.
|
||||
*/
|
||||
void memory_region_clear_coalescing(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_set_flush_coalesced: Enforce memory coalescing flush before
|
||||
* accesses.
|
||||
*
|
||||
* Ensure that pending coalesced MMIO request are flushed before the memory
|
||||
* region is accessed. This property is automatically enabled for all regions
|
||||
* passed to memory_region_set_coalescing() and memory_region_add_coalescing().
|
||||
*
|
||||
* @mr: the memory region to be updated.
|
||||
*/
|
||||
void memory_region_set_flush_coalesced(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_clear_flush_coalesced: Disable memory coalescing flush before
|
||||
* accesses.
|
||||
*
|
||||
* Clear the automatic coalesced MMIO flushing enabled via
|
||||
* memory_region_set_flush_coalesced. Note that this service has no effect on
|
||||
* memory regions that have MMIO coalescing enabled for themselves. For them,
|
||||
* automatic flushing will stop once coalescing is disabled.
|
||||
*
|
||||
* @mr: the memory region to be updated.
|
||||
*/
|
||||
void memory_region_clear_flush_coalesced(MemoryRegion *mr);
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* memory_region_add_eventfd: Request an eventfd to be triggered when a word
|
||||
* is written to a location.
|
||||
*
|
||||
* Marks a word in an IO region (initialized with memory_region_init_io())
|
||||
* as a trigger for an eventfd event. The I/O callback will not be called.
|
||||
* The caller must be prepared to handle failure (that is, take the required
|
||||
* action if the callback _is_ called).
|
||||
*
|
||||
* @mr: the memory region being updated.
|
||||
* @addr: the address within @mr that is to be monitored
|
||||
* @size: the size of the access to trigger the eventfd
|
||||
* @match_data: whether to match against @data, instead of just @addr
|
||||
* @data: the data to match against the guest write
|
||||
* @fd: the eventfd to be triggered when @addr, @size, and @data all match.
|
||||
**/
|
||||
void memory_region_add_eventfd(MemoryRegion *mr,
|
||||
hwaddr addr,
|
||||
unsigned size,
|
||||
bool match_data,
|
||||
uint64_t data,
|
||||
EventNotifier *e);
|
||||
|
||||
/**
|
||||
* memory_region_del_eventfd: Cancel an eventfd.
|
||||
*
|
||||
* Cancels an eventfd trigger requested by a previous
|
||||
* memory_region_add_eventfd() call.
|
||||
*
|
||||
* @mr: the memory region being updated.
|
||||
* @addr: the address within @mr that is to be monitored
|
||||
* @size: the size of the access to trigger the eventfd
|
||||
* @match_data: whether to match against @data, instead of just @addr
|
||||
* @data: the data to match against the guest write
|
||||
* @fd: the eventfd to be triggered when @addr, @size, and @data all match.
|
||||
*/
|
||||
void memory_region_del_eventfd(MemoryRegion *mr,
|
||||
hwaddr addr,
|
||||
unsigned size,
|
||||
bool match_data,
|
||||
uint64_t data,
|
||||
EventNotifier *e);
|
||||
#endif
|
||||
/**
|
||||
* memory_region_add_subregion: Add a subregion to a container.
|
||||
*
|
||||
* Adds a subregion at @offset. The subregion may not overlap with other
|
||||
* subregions (except for those explicitly marked as overlapping). A region
|
||||
* may only be added once as a subregion (unless removed with
|
||||
* memory_region_del_subregion()); use memory_region_init_alias() if you
|
||||
* want a region to be a subregion in multiple locations.
|
||||
*
|
||||
* @mr: the region to contain the new subregion; must be a container
|
||||
* initialized with memory_region_init().
|
||||
* @offset: the offset relative to @mr where @subregion is added.
|
||||
* @subregion: the subregion to be added.
|
||||
*/
|
||||
void memory_region_add_subregion(MemoryRegion *mr,
|
||||
hwaddr offset,
|
||||
MemoryRegion *subregion);
|
||||
/**
|
||||
* memory_region_add_subregion_overlap: Add a subregion to a container
|
||||
* with overlap.
|
||||
*
|
||||
* Adds a subregion at @offset. The subregion may overlap with other
|
||||
* subregions. Conflicts are resolved by having a higher @priority hide a
|
||||
* lower @priority. Subregions without priority are taken as @priority 0.
|
||||
* A region may only be added once as a subregion (unless removed with
|
||||
* memory_region_del_subregion()); use memory_region_init_alias() if you
|
||||
* want a region to be a subregion in multiple locations.
|
||||
*
|
||||
* @mr: the region to contain the new subregion; must be a container
|
||||
* initialized with memory_region_init().
|
||||
* @offset: the offset relative to @mr where @subregion is added.
|
||||
* @subregion: the subregion to be added.
|
||||
* @priority: used for resolving overlaps; highest priority wins.
|
||||
*/
|
||||
void memory_region_add_subregion_overlap(MemoryRegion *mr,
|
||||
hwaddr offset,
|
||||
MemoryRegion *subregion,
|
||||
unsigned priority);
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* memory_region_get_ram_addr: Get the ram address associated with a memory
|
||||
* region
|
||||
*
|
||||
* DO NOT USE THIS FUNCTION. This is a temporary workaround while the Xen
|
||||
* code is being reworked.
|
||||
*/
|
||||
ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* memory_region_del_subregion: Remove a subregion.
|
||||
*
|
||||
* Removes a subregion from its container.
|
||||
*
|
||||
* @mr: the container to be updated.
|
||||
* @subregion: the region being removed; must be a current subregion of @mr.
|
||||
*/
|
||||
void memory_region_del_subregion(MemoryRegion *mr,
|
||||
MemoryRegion *subregion);
|
||||
/*
|
||||
* memory_region_set_enabled: dynamically enable or disable a region
|
||||
*
|
||||
* Enables or disables a memory region. A disabled memory region
|
||||
* ignores all accesses to itself and its subregions. It does not
|
||||
* obscure sibling subregions with lower priority - it simply behaves as
|
||||
* if it was removed from the hierarchy.
|
||||
*
|
||||
* Regions default to being enabled.
|
||||
*
|
||||
* @mr: the region to be updated
|
||||
* @enabled: whether to enable or disable the region
|
||||
*/
|
||||
void memory_region_set_enabled(MemoryRegion *mr, bool enabled);
|
||||
|
||||
/*
|
||||
* memory_region_set_address: dynamically update the address of a region
|
||||
*
|
||||
* Dynamically updates the address of a region, relative to its parent.
|
||||
* May be used on regions are currently part of a memory hierarchy.
|
||||
*
|
||||
* @mr: the region to be updated
|
||||
* @addr: new address, relative to parent region
|
||||
*/
|
||||
void memory_region_set_address(MemoryRegion *mr, hwaddr addr);
|
||||
|
||||
/*
|
||||
* memory_region_set_alias_offset: dynamically update a memory alias's offset
|
||||
*
|
||||
* Dynamically updates the offset into the target region that an alias points
|
||||
* to, as if the fourth argument to memory_region_init_alias() has changed.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be updated; should be an alias.
|
||||
* @offset: the new offset into the target memory region
|
||||
*/
|
||||
void memory_region_set_alias_offset(MemoryRegion *mr,
|
||||
hwaddr offset);
|
||||
|
||||
/**
|
||||
* memory_region_find: locate a MemoryRegion in an address space
|
||||
*
|
||||
* Locates the first #MemoryRegion within an address space given by
|
||||
* @address_space that overlaps the range given by @addr and @size.
|
||||
*
|
||||
* Returns a #MemoryRegionSection that describes a contiguous overlap.
|
||||
* It will have the following characteristics:
|
||||
* .@offset_within_address_space >= @addr
|
||||
* .@offset_within_address_space + .@size <= @addr + @size
|
||||
* .@size = 0 iff no overlap was found
|
||||
* .@mr is non-%NULL iff an overlap was found
|
||||
*
|
||||
* @address_space: a top-level (i.e. parentless) region that contains
|
||||
* the region to be found
|
||||
* @addr: start of the area within @address_space to be searched
|
||||
* @size: size of the area to be searched
|
||||
*/
|
||||
MemoryRegionSection memory_region_find(MemoryRegion *address_space,
|
||||
hwaddr addr, uint64_t size);
|
||||
|
||||
/**
|
||||
* memory_region_section_addr: get offset within MemoryRegionSection
|
||||
*
|
||||
* Returns offset within MemoryRegionSection
|
||||
*
|
||||
* @section: the memory region section being queried
|
||||
* @addr: address in address space
|
||||
*/
|
||||
STATIC_INLINE hwaddr
|
||||
memory_region_section_addr(MemoryRegionSection *section,
|
||||
hwaddr addr)
|
||||
{
|
||||
addr -= section->offset_within_address_space;
|
||||
addr += section->offset_within_region;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* memory_global_sync_dirty_bitmap: synchronize the dirty log for all memory
|
||||
*
|
||||
* Synchronizes the dirty page log for an entire address space.
|
||||
* @address_space: a top-level (i.e. parentless) region that contains the
|
||||
* memory being synchronized
|
||||
*/
|
||||
void memory_global_sync_dirty_bitmap(MemoryRegion *address_space);
|
||||
|
||||
/**
|
||||
* memory_region_transaction_begin: Start a transaction.
|
||||
*
|
||||
* During a transaction, changes will be accumulated and made visible
|
||||
* only when the transaction ends (is committed).
|
||||
*/
|
||||
void memory_region_transaction_begin(void);
|
||||
|
||||
/**
|
||||
* memory_region_transaction_commit: Commit a transaction and make changes
|
||||
* visible to the guest.
|
||||
*/
|
||||
void memory_region_transaction_commit(void);
|
||||
|
||||
/**
|
||||
* memory_listener_register: register callbacks to be called when memory
|
||||
* sections are mapped or unmapped into an address
|
||||
* space
|
||||
*
|
||||
* @listener: an object containing the callbacks to be called
|
||||
* @filter: if non-%NULL, only regions in this address space will be observed
|
||||
*/
|
||||
void memory_listener_register(MemoryListener *listener, AddressSpace *filter);
|
||||
|
||||
/**
|
||||
* memory_listener_unregister: undo the effect of memory_listener_register()
|
||||
*
|
||||
* @listener: an object containing the callbacks to be removed
|
||||
*/
|
||||
void memory_listener_unregister(MemoryListener *listener);
|
||||
|
||||
/**
|
||||
* memory_global_dirty_log_start: begin dirty logging for all regions
|
||||
*/
|
||||
void memory_global_dirty_log_start(void);
|
||||
|
||||
/**
|
||||
* memory_global_dirty_log_stop: end dirty logging for all regions
|
||||
*/
|
||||
void memory_global_dirty_log_stop(void);
|
||||
|
||||
#if 0
|
||||
void mtree_info(fprintf_function mon_printf, void *f);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* address_space_init: initializes an address space
|
||||
*
|
||||
* @as: an uninitialized #AddressSpace
|
||||
* @root: a #MemoryRegion that routes addesses for the address space
|
||||
*/
|
||||
void address_space_init(AddressSpace *as, MemoryRegion *root);
|
||||
|
||||
|
||||
/**
|
||||
* address_space_destroy: destroy an address space
|
||||
*
|
||||
* Releases all resources associated with an address space. After an address space
|
||||
* is destroyed, its root memory region (given by address_space_init()) may be destroyed
|
||||
* as well.
|
||||
*
|
||||
* @as: address space to be destroyed
|
||||
*/
|
||||
void address_space_destroy(AddressSpace *as);
|
||||
|
||||
/**
|
||||
* address_space_rw: read from or write to an address space.
|
||||
*
|
||||
* @as: #AddressSpace to be accessed
|
||||
* @addr: address within that address space
|
||||
* @buf: buffer with the data transferred
|
||||
* @is_write: indicates the transfer direction
|
||||
*/
|
||||
void address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
|
||||
int len, bool is_write);
|
||||
|
||||
/**
|
||||
* address_space_write: write to address space.
|
||||
*
|
||||
* @as: #AddressSpace to be accessed
|
||||
* @addr: address within that address space
|
||||
* @buf: buffer with the data transferred
|
||||
*/
|
||||
void address_space_write(AddressSpace *as, hwaddr addr,
|
||||
const uint8_t *buf, int len);
|
||||
|
||||
/**
|
||||
* address_space_read: read from an address space.
|
||||
*
|
||||
* @as: #AddressSpace to be accessed
|
||||
* @addr: address within that address space
|
||||
* @buf: buffer with the data transferred
|
||||
*/
|
||||
void address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len);
|
||||
|
||||
/* address_space_map: map a physical memory region into a host virtual address
|
||||
*
|
||||
* May map a subset of the requested range, given by and returned in @plen.
|
||||
* May return %NULL if resources needed to perform the mapping are exhausted.
|
||||
* Use only for reads OR writes - not for read-modify-write operations.
|
||||
* Use cpu_register_map_client() to know when retrying the map operation is
|
||||
* likely to succeed.
|
||||
*
|
||||
* @as: #AddressSpace to be accessed
|
||||
* @addr: address within that address space
|
||||
* @plen: pointer to length of buffer; updated on return
|
||||
* @is_write: indicates the transfer direction
|
||||
*/
|
||||
void *address_space_map(AddressSpace *as, hwaddr addr,
|
||||
hwaddr *plen, bool is_write);
|
||||
|
||||
/* address_space_unmap: Unmaps a memory region previously mapped by address_space_map()
|
||||
*
|
||||
* Will also mark the memory as dirty if @is_write == %true. @access_len gives
|
||||
* the amount of memory that was actually read or written by the caller.
|
||||
*
|
||||
* @as: #AddressSpace used
|
||||
* @addr: address within that address space
|
||||
* @len: buffer length as returned by address_space_map()
|
||||
* @access_len: amount of data actually transferred
|
||||
* @is_write: indicates the transfer direction
|
||||
*/
|
||||
void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
|
||||
int is_write, hwaddr access_len);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
126
src/qemuvga/qemuuaeglue.c
Normal file
126
src/qemuvga/qemuuaeglue.c
Normal file
@ -0,0 +1,126 @@
|
||||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#include "qemuuaeglue.h"
|
||||
#include "vga_int.h"
|
||||
|
||||
|
||||
void memory_region_transaction_begin(void)
|
||||
{
|
||||
}
|
||||
void memory_region_transaction_commit(void)
|
||||
{
|
||||
}
|
||||
void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr, hwaddr size)
|
||||
{
|
||||
}
|
||||
void memory_region_add_subregion(MemoryRegion *mr,
|
||||
hwaddr offset,
|
||||
MemoryRegion *subregion)
|
||||
{
|
||||
}
|
||||
void memory_region_add_subregion_overlap(MemoryRegion *mr,
|
||||
hwaddr offset,
|
||||
MemoryRegion *subregion,
|
||||
unsigned priority)
|
||||
{
|
||||
}
|
||||
void memory_region_del_subregion(MemoryRegion *mr,
|
||||
MemoryRegion *subregion)
|
||||
{
|
||||
}
|
||||
void memory_region_destroy(MemoryRegion *mr)
|
||||
{
|
||||
}
|
||||
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
|
||||
{
|
||||
}
|
||||
void memory_region_init(MemoryRegion *mr,
|
||||
const char *name,
|
||||
uint64_t size)
|
||||
{
|
||||
}
|
||||
void memory_region_set_flush_coalesced(MemoryRegion *mr)
|
||||
{
|
||||
}
|
||||
uint64_t memory_region_size(MemoryRegion *mr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
|
||||
{
|
||||
}
|
||||
void memory_region_set_coalescing(MemoryRegion *mr)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t le16_to_cpu(uint16_t v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
uint32_t le32_to_cpu(uint32_t v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
void graphic_hw_update(QemuConsole *con)
|
||||
{
|
||||
}
|
||||
void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
|
||||
int dst_x, int dst_y, int w, int h)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_flush_coalesced_mmio_buffer(void)
|
||||
{
|
||||
}
|
||||
|
||||
QEMUClock *vm_clock;
|
||||
enum vga_retrace_method vga_retrace_method_value = VGA_RETRACE_DUMB;
|
||||
|
||||
int64_t qemu_get_clock_ns(QEMUClock *clock)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int64_t qemu_get_clock_ms(QEMUClock *clock)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday (&tv, NULL);
|
||||
return (uae_u64)tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
int64_t get_ticks_per_sec(void)
|
||||
{
|
||||
return 1000000;
|
||||
}
|
||||
|
||||
|
||||
void portio_list_init(PortioList *piolist,
|
||||
const struct MemoryRegionPortio *callbacks,
|
||||
void *opaque, const char *name)
|
||||
{
|
||||
}
|
||||
void portio_list_destroy(PortioList *piolist)
|
||||
{
|
||||
}
|
||||
void portio_list_add(PortioList *piolist,
|
||||
struct MemoryRegion *address_space,
|
||||
uint32_t addr)
|
||||
{
|
||||
}
|
||||
void portio_list_del(PortioList *piolist)
|
||||
{
|
||||
}
|
||||
|
||||
void dpy_text_cursor(QemuConsole *con, int x, int y)
|
||||
{
|
||||
}
|
||||
void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
|
||||
{
|
||||
}
|
||||
void dpy_text_resize(QemuConsole *con, int w, int h)
|
||||
{
|
||||
}
|
||||
void dpy_gfx_replace_surface(QemuConsole *con,
|
||||
DisplaySurface *surface)
|
||||
{
|
||||
}
|
285
src/qemuvga/qemuuaeglue.h
Normal file
285
src/qemuvga/qemuuaeglue.h
Normal file
@ -0,0 +1,285 @@
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//#define DEBUG_VGA_REG
|
||||
//#define DEBUG_VGA
|
||||
|
||||
extern void write_log (const char *, ...);
|
||||
|
||||
#ifndef glue
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
#endif
|
||||
|
||||
#ifndef likely
|
||||
#if __GNUC__ < 3
|
||||
#define __builtin_expect(x, n) (x)
|
||||
#endif
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#define container_of(address, type, field) ((type *)( \
|
||||
(PCHAR)(address) - \
|
||||
(ULONG_PTR)(&((type *)0)->field)))
|
||||
#define STATIC_INLINE static __forceinline
|
||||
|
||||
#define snprintf c99_snprintf
|
||||
inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
|
||||
{
|
||||
int count = -1;
|
||||
|
||||
if (size != 0)
|
||||
count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
inline int c99_snprintf(char* str, size_t size, const char* format, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#ifndef container_of
|
||||
/*#define container_of(ptr, type, member) ({ \
|
||||
const typeof(((type *) 0)->member) *__mptr = (ptr); \
|
||||
(type *) ((char *) __mptr - offsetof(type, member));}) */
|
||||
#define container_of(ptr, type, member) \
|
||||
((type *) ((char *)(ptr) - offsetof(type, member)))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ABS
|
||||
#define ABS(x) abs(x)
|
||||
#endif
|
||||
|
||||
#define g_free free
|
||||
#define g_malloc malloc
|
||||
#define g_new(type, num) ((type*)calloc(sizeof(type),num))
|
||||
|
||||
enum device_endian {
|
||||
DEVICE_NATIVE_ENDIAN,
|
||||
DEVICE_BIG_ENDIAN,
|
||||
DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
enum vga_retrace_method {
|
||||
VGA_RETRACE_DUMB,
|
||||
VGA_RETRACE_PRECISE
|
||||
};
|
||||
extern enum vga_retrace_method vga_retrace_method_value;
|
||||
|
||||
typedef uint32_t QEMUClock;
|
||||
extern QEMUClock *vm_clock;
|
||||
int64_t qemu_get_clock_ns(QEMUClock *clock);
|
||||
int64_t qemu_get_clock_ms(QEMUClock *clock);
|
||||
int64_t get_ticks_per_sec(void);
|
||||
|
||||
#define isa_mem_base 0
|
||||
|
||||
#define QemuConsole uint32_t
|
||||
#define console_ch_t uint8_t
|
||||
typedef struct GraphicHwOps {
|
||||
void (*invalidate)(void *opaque);
|
||||
void (*gfx_update)(void *opaque);
|
||||
void (*text_update)(void *opaque, console_ch_t *text);
|
||||
void (*update_interval)(void *opaque, uint64_t interval);
|
||||
} GraphicHwOps;
|
||||
|
||||
#define VMStateDescription uint32_t
|
||||
#define hwaddr uint32_t
|
||||
#define ram_addr_t uint32_t
|
||||
|
||||
typedef struct DisplaySurface {
|
||||
void *bah;
|
||||
} DisplaySurface;
|
||||
|
||||
uint16_t le16_to_cpu(uint16_t v);
|
||||
uint32_t le32_to_cpu(uint32_t v);
|
||||
|
||||
static inline void cpu_to_32wu(uint32_t *p, uint32_t v)
|
||||
{
|
||||
}
|
||||
|
||||
void graphic_hw_update(QemuConsole *con);
|
||||
void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
|
||||
int dst_x, int dst_y, int w, int h);
|
||||
void qemu_console_resize(QemuConsole *con, int width, int height);
|
||||
DisplaySurface *qemu_console_surface(QemuConsole *con);
|
||||
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
int linesize, uint8_t *data,
|
||||
bool byteswap);
|
||||
int surface_stride(DisplaySurface *s);
|
||||
uint8_t *surface_data(DisplaySurface *s);
|
||||
int is_surface_bgr(DisplaySurface *surface);
|
||||
|
||||
static inline int is_buffer_shared(DisplaySurface *surface)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
|
||||
void dpy_text_cursor(QemuConsole *con, int x, int y);
|
||||
void dpy_text_update(QemuConsole *con, int x, int y, int w, int h);
|
||||
void dpy_text_resize(QemuConsole *con, int w, int h);
|
||||
void dpy_gfx_replace_surface(QemuConsole *con,
|
||||
DisplaySurface *surface);
|
||||
|
||||
static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
|
||||
{
|
||||
if (!(ch & 0xff))
|
||||
ch |= ' ';
|
||||
*dest = ch;
|
||||
}
|
||||
|
||||
void qemu_flush_coalesced_mmio_buffer(void);
|
||||
|
||||
int surface_bits_per_pixel(DisplaySurface *s);
|
||||
int surface_bytes_per_pixel(DisplaySurface *s);
|
||||
|
||||
typedef struct PortioList {
|
||||
const struct MemoryRegionPortio *ports;
|
||||
struct MemoryRegion *address_space;
|
||||
unsigned nr;
|
||||
struct MemoryRegion **regions;
|
||||
struct MemoryRegion **aliases;
|
||||
void *opaque;
|
||||
const char *name;
|
||||
} PortioList;
|
||||
|
||||
void portio_list_init(PortioList *piolist,
|
||||
const struct MemoryRegionPortio *callbacks,
|
||||
void *opaque, const char *name);
|
||||
void portio_list_destroy(PortioList *piolist);
|
||||
void portio_list_add(PortioList *piolist,
|
||||
struct MemoryRegion *address_space,
|
||||
uint32_t addr);
|
||||
void portio_list_del(PortioList *piolist);
|
||||
|
||||
|
||||
typedef struct IORange IORange;
|
||||
typedef struct IORangeOps IORangeOps;
|
||||
|
||||
struct IORangeOps {
|
||||
void (*read)(IORange *iorange, uint64_t offset, unsigned width,
|
||||
uint64_t *data);
|
||||
void (*write)(IORange *iorange, uint64_t offset, unsigned width,
|
||||
uint64_t data);
|
||||
void (*destructor)(IORange *iorange);
|
||||
};
|
||||
|
||||
typedef struct IORange {
|
||||
const IORangeOps *ops;
|
||||
uint64_t base;
|
||||
uint64_t len;
|
||||
} IORange;
|
||||
|
||||
typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
|
||||
typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
|
||||
|
||||
typedef void CPUWriteMemoryFunc(void *opaque, hwaddr addr, uint32_t value);
|
||||
typedef uint32_t CPUReadMemoryFunc(void *opaque, hwaddr addr);
|
||||
|
||||
#include "qemumemory.h"
|
||||
#include "pixel_ops.h"
|
||||
|
||||
|
||||
static inline uint32_t lduw_raw(void *p)
|
||||
{
|
||||
return ((uint32_t*)p)[0];
|
||||
}
|
||||
|
||||
typedef void QEMUResetHandler(void *opaque);
|
||||
void qemu_register_reset(QEMUResetHandler *func, void *opaque);
|
||||
|
||||
#include "vga_int.h"
|
||||
|
||||
// ID
|
||||
#define CIRRUS_ID_CLGD5422 (0x23<<2)
|
||||
#define CIRRUS_ID_CLGD5426 (0x24<<2)
|
||||
#define CIRRUS_ID_CLGD5424 (0x25<<2)
|
||||
#define CIRRUS_ID_CLGD5428 (0x26<<2)
|
||||
#define CIRRUS_ID_CLGD5430 (0x28<<2)
|
||||
#define CIRRUS_ID_CLGD5434 (0x2A<<2)
|
||||
#define CIRRUS_ID_CLGD5436 (0x2B<<2)
|
||||
#define CIRRUS_ID_CLGD5446 (0x2E<<2)
|
||||
|
||||
typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
|
||||
uint8_t * dst, const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight);
|
||||
typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
|
||||
uint8_t *dst, int dst_pitch, int width, int height);
|
||||
|
||||
typedef struct CirrusVGAState {
|
||||
VGACommonState vga;
|
||||
|
||||
MemoryRegion cirrus_vga_io;
|
||||
MemoryRegion cirrus_linear_io;
|
||||
MemoryRegion cirrus_linear_bitblt_io;
|
||||
MemoryRegion cirrus_mmio_io;
|
||||
MemoryRegion pci_bar;
|
||||
bool linear_vram; /* vga.vram mapped over cirrus_linear_io */
|
||||
MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
|
||||
MemoryRegion low_mem; /* always mapped, overridden by: */
|
||||
MemoryRegion cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */
|
||||
uint32_t cirrus_addr_mask;
|
||||
uint32_t linear_mmio_mask;
|
||||
uint8_t cirrus_shadow_gr0;
|
||||
uint8_t cirrus_shadow_gr1;
|
||||
uint8_t cirrus_hidden_dac_lockindex;
|
||||
uint8_t cirrus_hidden_dac_data;
|
||||
uint32_t cirrus_bank_base[2];
|
||||
uint32_t cirrus_bank_limit[2];
|
||||
uint8_t cirrus_hidden_palette[48];
|
||||
uint32_t hw_cursor_x;
|
||||
uint32_t hw_cursor_y;
|
||||
int cirrus_blt_pixelwidth;
|
||||
int cirrus_blt_width;
|
||||
int cirrus_blt_height;
|
||||
int cirrus_blt_dstpitch;
|
||||
int cirrus_blt_srcpitch;
|
||||
uint32_t cirrus_blt_fgcol;
|
||||
uint32_t cirrus_blt_bgcol;
|
||||
uint32_t cirrus_blt_dstaddr;
|
||||
uint32_t cirrus_blt_srcaddr;
|
||||
uint8_t cirrus_blt_mode;
|
||||
uint8_t cirrus_blt_modeext;
|
||||
cirrus_bitblt_rop_t cirrus_rop;
|
||||
#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
|
||||
uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
|
||||
uint8_t *cirrus_srcptr;
|
||||
uint8_t *cirrus_srcptr_end;
|
||||
uint32_t cirrus_srccounter;
|
||||
/* hwcursor display state */
|
||||
int last_hw_cursor_size;
|
||||
int last_hw_cursor_x;
|
||||
int last_hw_cursor_y;
|
||||
int last_hw_cursor_y_start;
|
||||
int last_hw_cursor_y_end;
|
||||
int real_vram_size; /* XXX: suppress that */
|
||||
int total_vram_size;
|
||||
int device_id;
|
||||
int bustype;
|
||||
int valid_memory_config;
|
||||
} CirrusVGAState;
|
||||
|
||||
void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
|
||||
MemoryRegion *system_memory,
|
||||
MemoryRegion *system_io);
|
||||
|
2433
src/qemuvga/vga.c
Normal file
2433
src/qemuvga/vga.c
Normal file
File diff suppressed because it is too large
Load Diff
159
src/qemuvga/vga.h
Normal file
159
src/qemuvga/vga.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* linux/include/video/vga.h -- standard VGA chipset interaction
|
||||
*
|
||||
* Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
|
||||
*
|
||||
* Copyright history from vga16fb.c:
|
||||
* Copyright 1999 Ben Pfaff and Petr Vandrovec
|
||||
* Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
|
||||
* Based on VESA framebuffer (c) 1998 Gerd Knorr
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file COPYING in the main directory of this
|
||||
* archive for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __linux_video_vga_h__
|
||||
#define __linux_video_vga_h__
|
||||
|
||||
/* Some of the code below is taken from SVGAlib. The original,
|
||||
unmodified copyright notice for that code is below. */
|
||||
/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */
|
||||
/* */
|
||||
/* This library is free software; you can redistribute it and/or */
|
||||
/* modify it without any restrictions. This library is distributed */
|
||||
/* in the hope that it will be useful, but without any warranty. */
|
||||
|
||||
/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
|
||||
/* partially copyrighted (C) 1993 by Hartmut Schirmer */
|
||||
|
||||
/* VGA data register ports */
|
||||
#define VGA_CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */
|
||||
#define VGA_CRT_DM 0x3B5 /* CRT Controller Data Register - mono emulation */
|
||||
#define VGA_ATT_R 0x3C1 /* Attribute Controller Data Read Register */
|
||||
#define VGA_ATT_W 0x3C0 /* Attribute Controller Data Write Register */
|
||||
#define VGA_GFX_D 0x3CF /* Graphics Controller Data Register */
|
||||
#define VGA_SEQ_D 0x3C5 /* Sequencer Data Register */
|
||||
#define VGA_MIS_R 0x3CC /* Misc Output Read Register */
|
||||
#define VGA_MIS_W 0x3C2 /* Misc Output Write Register */
|
||||
#define VGA_FTC_R 0x3CA /* Feature Control Read Register */
|
||||
#define VGA_IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
|
||||
#define VGA_IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
|
||||
#define VGA_PEL_D 0x3C9 /* PEL Data Register */
|
||||
#define VGA_PEL_MSK 0x3C6 /* PEL mask register */
|
||||
|
||||
/* EGA-specific registers */
|
||||
#define EGA_GFX_E0 0x3CC /* Graphics enable processor 0 */
|
||||
#define EGA_GFX_E1 0x3CA /* Graphics enable processor 1 */
|
||||
|
||||
/* VGA index register ports */
|
||||
#define VGA_CRT_IC 0x3D4 /* CRT Controller Index - color emulation */
|
||||
#define VGA_CRT_IM 0x3B4 /* CRT Controller Index - mono emulation */
|
||||
#define VGA_ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
|
||||
#define VGA_GFX_I 0x3CE /* Graphics Controller Index */
|
||||
#define VGA_SEQ_I 0x3C4 /* Sequencer Index */
|
||||
#define VGA_PEL_IW 0x3C8 /* PEL Write Index */
|
||||
#define VGA_PEL_IR 0x3C7 /* PEL Read Index */
|
||||
|
||||
/* standard VGA indexes max counts */
|
||||
#define VGA_CRT_C 0x19 /* Number of CRT Controller Registers */
|
||||
#define VGA_ATT_C 0x15 /* Number of Attribute Controller Registers */
|
||||
#define VGA_GFX_C 0x09 /* Number of Graphics Controller Registers */
|
||||
#define VGA_SEQ_C 0x05 /* Number of Sequencer Registers */
|
||||
#define VGA_MIS_C 0x01 /* Number of Misc Output Register */
|
||||
|
||||
/* VGA misc register bit masks */
|
||||
#define VGA_MIS_COLOR 0x01
|
||||
#define VGA_MIS_ENB_MEM_ACCESS 0x02
|
||||
#define VGA_MIS_DCLK_28322_720 0x04
|
||||
#define VGA_MIS_ENB_PLL_LOAD (0x04 | 0x08)
|
||||
#define VGA_MIS_SEL_HIGH_PAGE 0x20
|
||||
|
||||
/* VGA CRT controller register indices */
|
||||
#define VGA_CRTC_H_TOTAL 0
|
||||
#define VGA_CRTC_H_DISP 1
|
||||
#define VGA_CRTC_H_BLANK_START 2
|
||||
#define VGA_CRTC_H_BLANK_END 3
|
||||
#define VGA_CRTC_H_SYNC_START 4
|
||||
#define VGA_CRTC_H_SYNC_END 5
|
||||
#define VGA_CRTC_V_TOTAL 6
|
||||
#define VGA_CRTC_OVERFLOW 7
|
||||
#define VGA_CRTC_PRESET_ROW 8
|
||||
#define VGA_CRTC_MAX_SCAN 9
|
||||
#define VGA_CRTC_CURSOR_START 0x0A
|
||||
#define VGA_CRTC_CURSOR_END 0x0B
|
||||
#define VGA_CRTC_START_HI 0x0C
|
||||
#define VGA_CRTC_START_LO 0x0D
|
||||
#define VGA_CRTC_CURSOR_HI 0x0E
|
||||
#define VGA_CRTC_CURSOR_LO 0x0F
|
||||
#define VGA_CRTC_V_SYNC_START 0x10
|
||||
#define VGA_CRTC_V_SYNC_END 0x11
|
||||
#define VGA_CRTC_V_DISP_END 0x12
|
||||
#define VGA_CRTC_OFFSET 0x13
|
||||
#define VGA_CRTC_UNDERLINE 0x14
|
||||
#define VGA_CRTC_V_BLANK_START 0x15
|
||||
#define VGA_CRTC_V_BLANK_END 0x16
|
||||
#define VGA_CRTC_MODE 0x17
|
||||
#define VGA_CRTC_LINE_COMPARE 0x18
|
||||
#define VGA_CRTC_REGS VGA_CRT_C
|
||||
|
||||
/* VGA CRT controller bit masks */
|
||||
#define VGA_CR11_LOCK_CR0_CR7 0x80 /* lock writes to CR0 - CR7 */
|
||||
#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
|
||||
|
||||
/* VGA attribute controller register indices */
|
||||
#define VGA_ATC_PALETTE0 0x00
|
||||
#define VGA_ATC_PALETTE1 0x01
|
||||
#define VGA_ATC_PALETTE2 0x02
|
||||
#define VGA_ATC_PALETTE3 0x03
|
||||
#define VGA_ATC_PALETTE4 0x04
|
||||
#define VGA_ATC_PALETTE5 0x05
|
||||
#define VGA_ATC_PALETTE6 0x06
|
||||
#define VGA_ATC_PALETTE7 0x07
|
||||
#define VGA_ATC_PALETTE8 0x08
|
||||
#define VGA_ATC_PALETTE9 0x09
|
||||
#define VGA_ATC_PALETTEA 0x0A
|
||||
#define VGA_ATC_PALETTEB 0x0B
|
||||
#define VGA_ATC_PALETTEC 0x0C
|
||||
#define VGA_ATC_PALETTED 0x0D
|
||||
#define VGA_ATC_PALETTEE 0x0E
|
||||
#define VGA_ATC_PALETTEF 0x0F
|
||||
#define VGA_ATC_MODE 0x10
|
||||
#define VGA_ATC_OVERSCAN 0x11
|
||||
#define VGA_ATC_PLANE_ENABLE 0x12
|
||||
#define VGA_ATC_PEL 0x13
|
||||
#define VGA_ATC_COLOR_PAGE 0x14
|
||||
|
||||
#define VGA_AR_ENABLE_DISPLAY 0x20
|
||||
|
||||
/* VGA sequencer register indices */
|
||||
#define VGA_SEQ_RESET 0x00
|
||||
#define VGA_SEQ_CLOCK_MODE 0x01
|
||||
#define VGA_SEQ_PLANE_WRITE 0x02
|
||||
#define VGA_SEQ_CHARACTER_MAP 0x03
|
||||
#define VGA_SEQ_MEMORY_MODE 0x04
|
||||
|
||||
/* VGA sequencer register bit masks */
|
||||
#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */
|
||||
#define VGA_SR01_SCREEN_OFF 0x20 /* bit 5: Screen is off */
|
||||
#define VGA_SR02_ALL_PLANES 0x0F /* bits 3-0: enable access to all planes */
|
||||
#define VGA_SR04_EXT_MEM 0x02 /* bit 1: allows complete mem access to 256K */
|
||||
#define VGA_SR04_SEQ_MODE 0x04 /* bit 2: directs system to use a sequential addressing mode */
|
||||
#define VGA_SR04_CHN_4M 0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
|
||||
|
||||
/* VGA graphics controller register indices */
|
||||
#define VGA_GFX_SR_VALUE 0x00
|
||||
#define VGA_GFX_SR_ENABLE 0x01
|
||||
#define VGA_GFX_COMPARE_VALUE 0x02
|
||||
#define VGA_GFX_DATA_ROTATE 0x03
|
||||
#define VGA_GFX_PLANE_READ 0x04
|
||||
#define VGA_GFX_MODE 0x05
|
||||
#define VGA_GFX_MISC 0x06
|
||||
#define VGA_GFX_COMPARE_MASK 0x07
|
||||
#define VGA_GFX_BIT_MASK 0x08
|
||||
|
||||
/* VGA graphics controller bit masks */
|
||||
#define VGA_GR06_GRAPHICS_MODE 0x01
|
||||
|
||||
#endif /* __linux_video_vga_h__ */
|
216
src/qemuvga/vga_int.h
Normal file
216
src/qemuvga/vga_int.h
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* QEMU internal VGA defines.
|
||||
*
|
||||
* Copyright (c) 2003-2004 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef HW_VGA_INT_H
|
||||
#define HW_VGA_INT_H 1
|
||||
|
||||
#if 0
|
||||
#include <hw/hw.h>
|
||||
#include "qapi/error.h"
|
||||
#include "exec/memory.h"
|
||||
#endif
|
||||
|
||||
#define ST01_V_RETRACE 0x08
|
||||
#define ST01_DISP_ENABLE 0x01
|
||||
|
||||
#define VBE_DISPI_MAX_XRES 16000
|
||||
#define VBE_DISPI_MAX_YRES 12000
|
||||
#define VBE_DISPI_MAX_BPP 32
|
||||
|
||||
#define VBE_DISPI_INDEX_ID 0x0
|
||||
#define VBE_DISPI_INDEX_XRES 0x1
|
||||
#define VBE_DISPI_INDEX_YRES 0x2
|
||||
#define VBE_DISPI_INDEX_BPP 0x3
|
||||
#define VBE_DISPI_INDEX_ENABLE 0x4
|
||||
#define VBE_DISPI_INDEX_BANK 0x5
|
||||
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
|
||||
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
|
||||
#define VBE_DISPI_INDEX_X_OFFSET 0x8
|
||||
#define VBE_DISPI_INDEX_Y_OFFSET 0x9
|
||||
#define VBE_DISPI_INDEX_NB 0xa /* size of vbe_regs[] */
|
||||
#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa /* read-only, not in vbe_regs */
|
||||
|
||||
#define VBE_DISPI_ID0 0xB0C0
|
||||
#define VBE_DISPI_ID1 0xB0C1
|
||||
#define VBE_DISPI_ID2 0xB0C2
|
||||
#define VBE_DISPI_ID3 0xB0C3
|
||||
#define VBE_DISPI_ID4 0xB0C4
|
||||
#define VBE_DISPI_ID5 0xB0C5
|
||||
|
||||
#define VBE_DISPI_DISABLED 0x00
|
||||
#define VBE_DISPI_ENABLED 0x01
|
||||
#define VBE_DISPI_GETCAPS 0x02
|
||||
#define VBE_DISPI_8BIT_DAC 0x20
|
||||
#define VBE_DISPI_LFB_ENABLED 0x40
|
||||
#define VBE_DISPI_NOCLEARMEM 0x80
|
||||
|
||||
#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
|
||||
|
||||
#define CH_ATTR_SIZE (160 * 100)
|
||||
#define VGA_MAX_HEIGHT 2048
|
||||
|
||||
struct vga_precise_retrace {
|
||||
int64_t ticks_per_char;
|
||||
int64_t total_chars;
|
||||
int htotal;
|
||||
int hstart;
|
||||
int hend;
|
||||
int vstart;
|
||||
int vend;
|
||||
int freq;
|
||||
};
|
||||
|
||||
union vga_retrace {
|
||||
struct vga_precise_retrace precise;
|
||||
};
|
||||
|
||||
struct VGACommonState;
|
||||
typedef uint8_t (* vga_retrace_fn)(struct VGACommonState *s);
|
||||
typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
|
||||
|
||||
typedef struct VGACommonState {
|
||||
MemoryRegion *legacy_address_space;
|
||||
uint8_t *vram_ptr;
|
||||
MemoryRegion vram;
|
||||
MemoryRegion vram_vbe;
|
||||
uint32_t vram_size;
|
||||
uint32_t vram_size_mb; /* property */
|
||||
uint32_t latch;
|
||||
MemoryRegion *chain4_alias;
|
||||
uint8_t sr_index;
|
||||
uint8_t sr[256];
|
||||
uint8_t gr_index;
|
||||
uint8_t gr[256];
|
||||
uint8_t ar_index;
|
||||
uint8_t ar[21];
|
||||
int ar_flip_flop;
|
||||
uint8_t cr_index;
|
||||
uint8_t cr[256]; /* CRT registers */
|
||||
uint8_t msr; /* Misc Output Register */
|
||||
uint8_t fcr; /* Feature Control Register */
|
||||
uint8_t st00; /* status 0 */
|
||||
uint8_t st01; /* status 1 */
|
||||
uint8_t dac_state;
|
||||
uint8_t dac_sub_index;
|
||||
uint8_t dac_read_index;
|
||||
uint8_t dac_write_index;
|
||||
uint8_t dac_cache[3]; /* used when writing */
|
||||
int dac_8bit;
|
||||
uint8_t palette[768];
|
||||
int32_t bank_offset;
|
||||
int (*get_bpp)(struct VGACommonState *s);
|
||||
void (*get_offsets)(struct VGACommonState *s,
|
||||
uint32_t *pline_offset,
|
||||
uint32_t *pstart_addr,
|
||||
uint32_t *pline_compare);
|
||||
void (*get_resolution)(struct VGACommonState *s,
|
||||
int *pwidth,
|
||||
int *pheight);
|
||||
/* bochs vbe state */
|
||||
uint16_t vbe_index;
|
||||
uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
|
||||
uint32_t vbe_start_addr;
|
||||
uint32_t vbe_line_offset;
|
||||
uint32_t vbe_bank_mask;
|
||||
int vbe_mapped;
|
||||
/* display refresh support */
|
||||
QemuConsole *con;
|
||||
uint32_t font_offsets[2];
|
||||
int graphic_mode;
|
||||
uint8_t shift_control;
|
||||
uint8_t double_scan;
|
||||
uint32_t line_offset;
|
||||
uint32_t line_compare;
|
||||
uint32_t start_addr;
|
||||
uint32_t plane_updated;
|
||||
uint32_t last_line_offset;
|
||||
uint8_t last_cw, last_ch;
|
||||
uint32_t last_width, last_height; /* in chars or pixels */
|
||||
uint32_t last_scr_width, last_scr_height; /* in pixels */
|
||||
uint32_t last_depth; /* in bits */
|
||||
uint8_t cursor_start, cursor_end;
|
||||
bool cursor_visible_phase;
|
||||
int64_t cursor_blink_time;
|
||||
uint32_t cursor_offset;
|
||||
unsigned int (*rgb_to_pixel)(unsigned int r,
|
||||
unsigned int g, unsigned b);
|
||||
const GraphicHwOps *hw_ops;
|
||||
bool full_update_text;
|
||||
bool full_update_gfx;
|
||||
/* hardware mouse cursor support */
|
||||
uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
|
||||
void (*cursor_invalidate)(struct VGACommonState *s);
|
||||
void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
|
||||
/* tell for each page if it has been updated since the last time */
|
||||
uint32_t last_palette[256];
|
||||
uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
|
||||
/* retrace */
|
||||
vga_retrace_fn retrace;
|
||||
vga_update_retrace_info_fn update_retrace_info;
|
||||
union vga_retrace retrace_info;
|
||||
uint8_t is_vbe_vmstate;
|
||||
} VGACommonState;
|
||||
|
||||
STATIC_INLINE int c6_to_8(int v)
|
||||
{
|
||||
int b;
|
||||
v &= 0x3f;
|
||||
b = v & 1;
|
||||
return (v << 2) | (b << 1) | b;
|
||||
}
|
||||
|
||||
void vga_common_init(VGACommonState *s);
|
||||
void vga_init(VGACommonState *s, MemoryRegion *address_space,
|
||||
MemoryRegion *address_space_io, bool init_vga_ports);
|
||||
MemoryRegion *vga_init_io(VGACommonState *s,
|
||||
const MemoryRegionPortio **vga_ports,
|
||||
const MemoryRegionPortio **vbe_ports);
|
||||
void vga_common_reset(VGACommonState *s);
|
||||
|
||||
void vga_sync_dirty_bitmap(VGACommonState *s);
|
||||
void vga_dirty_log_start(VGACommonState *s);
|
||||
void vga_dirty_log_stop(VGACommonState *s);
|
||||
|
||||
extern const VMStateDescription vmstate_vga_common;
|
||||
uint32_t vga_ioport_read(void *opaque, uint32_t addr);
|
||||
void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr);
|
||||
void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val);
|
||||
void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
|
||||
|
||||
int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
|
||||
|
||||
void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
|
||||
uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr);
|
||||
void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val);
|
||||
void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val);
|
||||
|
||||
extern const uint8_t sr_mask[8];
|
||||
extern const uint8_t gr_mask[16];
|
||||
|
||||
#define VGABIOS_FILENAME "vgabios.bin"
|
||||
#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
|
||||
|
||||
extern const MemoryRegionOps vga_mem_ops;
|
||||
|
||||
#endif
|
459
src/qemuvga/vga_template.h
Normal file
459
src/qemuvga/vga_template.h
Normal file
@ -0,0 +1,459 @@
|
||||
/*
|
||||
* QEMU VGA Emulator templates
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if DEPTH == 8
|
||||
#define BPP 1
|
||||
#define PIXEL_TYPE uint8_t
|
||||
#elif DEPTH == 15 || DEPTH == 16
|
||||
#define BPP 2
|
||||
#define PIXEL_TYPE uint16_t
|
||||
#elif DEPTH == 32
|
||||
#define BPP 4
|
||||
#define PIXEL_TYPE uint32_t
|
||||
#else
|
||||
#error unsupport depth
|
||||
#endif
|
||||
|
||||
#ifdef BGR_FORMAT
|
||||
#define PIXEL_NAME glue(DEPTH, bgr)
|
||||
#else
|
||||
#define PIXEL_NAME DEPTH
|
||||
#endif /* BGR_FORMAT */
|
||||
|
||||
#if DEPTH != 15 && !defined(BGR_FORMAT)
|
||||
|
||||
static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
|
||||
uint32_t font_data,
|
||||
uint32_t xorcol,
|
||||
uint32_t bgcol)
|
||||
{
|
||||
#if BPP == 1
|
||||
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
|
||||
#elif BPP == 2
|
||||
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
|
||||
#else
|
||||
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol)
|
||||
{
|
||||
uint32_t font_data, xorcol;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol)
|
||||
{
|
||||
uint32_t font_data, xorcol;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d,
|
||||
expand4to8[font_data >> 4],
|
||||
xorcol, bgcol);
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
|
||||
expand4to8[font_data & 0x0f],
|
||||
xorcol, bgcol);
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol, int dup9)
|
||||
{
|
||||
uint32_t font_data, xorcol, v;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
#if BPP == 1
|
||||
cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
|
||||
v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
|
||||
cpu_to_32wu(((uint32_t *)d)+1, v);
|
||||
if (dup9)
|
||||
((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
|
||||
else
|
||||
((uint8_t *)d)[8] = bgcol;
|
||||
|
||||
#elif BPP == 2
|
||||
cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
|
||||
cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
|
||||
cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
|
||||
v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
|
||||
cpu_to_32wu(((uint32_t *)d)+3, v);
|
||||
if (dup9)
|
||||
((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
|
||||
else
|
||||
((uint16_t *)d)[8] = bgcol;
|
||||
#else
|
||||
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
|
||||
v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[7] = v;
|
||||
if (dup9)
|
||||
((uint32_t *)d)[8] = v;
|
||||
else
|
||||
((uint32_t *)d)[8] = bgcol;
|
||||
#endif
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4 color mode
|
||||
*/
|
||||
static void glue(vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
((PIXEL_TYPE *)d)[0] = palette[v >> 12];
|
||||
((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
|
||||
|
||||
v = expand2[GET_PLANE(data, 1)];
|
||||
v |= expand2[GET_PLANE(data, 3)] << 2;
|
||||
((PIXEL_TYPE *)d)[4] = palette[v >> 12];
|
||||
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#if BPP == 1
|
||||
#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
|
||||
#elif BPP == 2
|
||||
#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
|
||||
#else
|
||||
#define PUT_PIXEL2(d, n, v) \
|
||||
((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4 color mode, dup2 horizontal
|
||||
*/
|
||||
static void glue(vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
PUT_PIXEL2(d, 0, palette[v >> 12]);
|
||||
PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
|
||||
|
||||
v = expand2[GET_PLANE(data, 1)];
|
||||
v |= expand2[GET_PLANE(data, 3)] << 2;
|
||||
PUT_PIXEL2(d, 4, palette[v >> 12]);
|
||||
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += BPP * 16;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode
|
||||
*/
|
||||
static void glue(vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
v |= expand4[GET_PLANE(data, 2)] << 2;
|
||||
v |= expand4[GET_PLANE(data, 3)] << 3;
|
||||
((PIXEL_TYPE *)d)[0] = palette[v >> 28];
|
||||
((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
|
||||
((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
|
||||
((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
|
||||
((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
|
||||
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode, dup2 horizontal
|
||||
*/
|
||||
static void glue(vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
v |= expand4[GET_PLANE(data, 2)] << 2;
|
||||
v |= expand4[GET_PLANE(data, 3)] << 3;
|
||||
PUT_PIXEL2(d, 0, palette[v >> 28]);
|
||||
PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
|
||||
PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
|
||||
PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
|
||||
PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
|
||||
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += BPP * 16;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 256 color mode, double pixels
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
static void glue(vga_draw_line8d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
PUT_PIXEL2(d, 0, palette[s[0]]);
|
||||
PUT_PIXEL2(d, 1, palette[s[1]]);
|
||||
PUT_PIXEL2(d, 2, palette[s[2]]);
|
||||
PUT_PIXEL2(d, 3, palette[s[3]]);
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* standard 256 color mode
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
static void glue(vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
((PIXEL_TYPE *)d)[0] = palette[s[0]];
|
||||
((PIXEL_TYPE *)d)[1] = palette[s[1]];
|
||||
((PIXEL_TYPE *)d)[2] = palette[s[2]];
|
||||
((PIXEL_TYPE *)d)[3] = palette[s[3]];
|
||||
((PIXEL_TYPE *)d)[4] = palette[s[4]];
|
||||
((PIXEL_TYPE *)d)[5] = palette[s[5]];
|
||||
((PIXEL_TYPE *)d)[6] = palette[s[6]];
|
||||
((PIXEL_TYPE *)d)[7] = palette[s[7]];
|
||||
d += BPP * 8;
|
||||
s += 8;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DEPTH != 15 */
|
||||
|
||||
|
||||
/* XXX: optimize */
|
||||
|
||||
/*
|
||||
* 15 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 15 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 24 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line24_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
r = s[0];
|
||||
g = s[1];
|
||||
b = s[2];
|
||||
#else
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
#endif
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
|
||||
s += 3;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 32 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line32_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 32 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
|
||||
memcpy(d, s, width * 4);
|
||||
#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
r = s[1];
|
||||
g = s[2];
|
||||
b = s[3];
|
||||
#else
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
#endif
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
|
||||
s += 4;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef PUT_PIXEL2
|
||||
#undef DEPTH
|
||||
#undef BPP
|
||||
#undef PIXEL_TYPE
|
||||
#undef PIXEL_NAME
|
||||
#undef BGR_FORMAT
|
676
src/scsitape.c
Normal file
676
src/scsitape.c
Normal file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* UAE - The Un*x Amiga Emulator
|
||||
*
|
||||
* SCSI tape emulation
|
||||
*
|
||||
* Copyright 2013 Toni Wilen
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysconfig.h"
|
||||
#include "sysdeps.h"
|
||||
|
||||
#include "options.h"
|
||||
#include "filesys.h"
|
||||
#include "scsi.h"
|
||||
#include "blkdev.h"
|
||||
#include "zfile.h"
|
||||
#include "memory.h"
|
||||
#include "a2091.h"
|
||||
#include "fsdb.h"
|
||||
|
||||
int log_tapeemu = 1;
|
||||
|
||||
#define TAPE_INDEX _T("index.tape")
|
||||
|
||||
static struct scsi_data_tape *tapeunits[MAX_FILESYSTEM_UNITS];
|
||||
|
||||
static bool notape (struct scsi_data_tape *tape)
|
||||
{
|
||||
return tape->tape_dir[0] == 0 || tape->nomedia;
|
||||
}
|
||||
|
||||
static int rl (uae_u8 *p)
|
||||
{
|
||||
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
|
||||
}
|
||||
static void wl (uae_u8 *p, int v)
|
||||
{
|
||||
p[0] = v >> 24;
|
||||
p[1] = v >> 16;
|
||||
p[2] = v >> 8;
|
||||
p[3] = v;
|
||||
}
|
||||
|
||||
void tape_free (struct scsi_data_tape *tape)
|
||||
{
|
||||
if (!tape)
|
||||
return;
|
||||
zfile_fclose (tape->zf);
|
||||
zfile_fclose (tape->index);
|
||||
zfile_closedir_archive (tape->zd);
|
||||
xfree(tape);
|
||||
for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
|
||||
if (tapeunits[i] == tape)
|
||||
tapeunits[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void tape_init (int unit, struct scsi_data_tape *tape, const TCHAR *tape_directory, bool readonly)
|
||||
{
|
||||
TCHAR path[MAX_DPATH];
|
||||
|
||||
memset (tape, 0, sizeof (struct scsi_data_tape));
|
||||
_tcscpy (tape->tape_dir, tape_directory);
|
||||
|
||||
tape->blocksize = 512;
|
||||
tape->wp = readonly;
|
||||
tape->beom = -1;
|
||||
tape->nomedia = false;
|
||||
tape->unloaded = false;
|
||||
|
||||
if (my_existsdir (tape->tape_dir)) {
|
||||
tape->realdir = true;
|
||||
} else {
|
||||
tape->zd = zfile_opendir_archive (tape_directory);
|
||||
//tape->zd = zfile_opendir_archive (tape_directory, ZFD_ARCHIVE | ZFD_NORECURSE);
|
||||
if (!tape->zd)
|
||||
tape->nomedia = true;
|
||||
}
|
||||
|
||||
_tcscpy (path, tape_directory);
|
||||
_tcscat (path, FSDB_DIR_SEPARATOR_S);
|
||||
_tcscat (path, TAPE_INDEX);
|
||||
tape->index = zfile_fopen (path, _T("rb"), ZFD_NORMAL);
|
||||
if (tape->index)
|
||||
write_log (_T("TAPEEMU INDEX: '%s'\n"), path);
|
||||
tapeunits[unit] = tape;
|
||||
}
|
||||
|
||||
struct scsi_data_tape *tape_alloc (int unitnum, const TCHAR *tape_directory, bool readonly)
|
||||
{
|
||||
struct scsi_data_tape *tape = xcalloc (struct scsi_data_tape, 1);
|
||||
|
||||
tape_init (unitnum, tape, tape_directory, readonly);
|
||||
return tape;
|
||||
}
|
||||
|
||||
void tape_media_change (int unitnum, struct uaedev_config_info *ci)
|
||||
{
|
||||
struct scsi_data_tape *tape = tapeunits[unitnum];
|
||||
if (!tape)
|
||||
return;
|
||||
tape_init (unitnum, tape, ci->rootdir, ci->readonly);
|
||||
}
|
||||
|
||||
bool tape_get_info (int unitnum, struct device_info *di)
|
||||
{
|
||||
struct scsi_data_tape *tape = tapeunits[unitnum];
|
||||
memset (di, 0, sizeof (struct device_info));
|
||||
if (!tape)
|
||||
return false;
|
||||
di->media_inserted = notape (tape) == false;
|
||||
_tcscpy (di->label, tape->tape_dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void tape_rewind (struct scsi_data_tape *tape)
|
||||
{
|
||||
zfile_fclose (tape->zf);
|
||||
tape->zf = NULL;
|
||||
my_closedir (tape->od);
|
||||
tape->file_number = 0;
|
||||
tape->file_offset = 0;
|
||||
tape->od = NULL;
|
||||
tape->beom = -1;
|
||||
if (tape->index)
|
||||
zfile_fseek (tape->index, 0, SEEK_SET);
|
||||
if (tape->zd)
|
||||
zfile_resetdir_archive (tape->zd);
|
||||
}
|
||||
|
||||
static void erase (struct scsi_data_tape *tape)
|
||||
{
|
||||
struct my_opendir_s *od;
|
||||
if (!tape->realdir)
|
||||
return;
|
||||
tape_rewind (tape);
|
||||
od = my_opendir (tape->tape_dir);
|
||||
if (od) {
|
||||
for (;;) {
|
||||
TCHAR path[MAX_DPATH], filename[MAX_DPATH];
|
||||
if (!my_readdir (od, filename))
|
||||
break;
|
||||
TCHAR *ext = _tcsrchr (filename, '.');
|
||||
if (ext && !_tcsicmp (ext, _T(".tape"))) {
|
||||
_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, filename);
|
||||
if (my_existsfile (path))
|
||||
my_unlink (path);
|
||||
}
|
||||
}
|
||||
my_closedir (od);
|
||||
}
|
||||
}
|
||||
|
||||
static bool next_file (struct scsi_data_tape *tape)
|
||||
{
|
||||
zfile_fclose (tape->zf);
|
||||
tape->zf = NULL;
|
||||
tape->file_offset = 0;
|
||||
if (tape->index) {
|
||||
TCHAR path[MAX_DPATH];
|
||||
TCHAR name[256];
|
||||
name[0] = 0;
|
||||
zfile_fgets (name, sizeof name / sizeof (TCHAR), tape->index);
|
||||
my_trim (name);
|
||||
if (name[0] == 0)
|
||||
goto end;
|
||||
_tcscpy (path, tape->tape_dir);
|
||||
_tcscat (path, FSDB_DIR_SEPARATOR_S);
|
||||
_tcscat (path, name);
|
||||
tape->zf = zfile_fopen (path, _T("rb"), ZFD_NORMAL);
|
||||
write_log (_T("TAPEEMU: File '%s'\n"), path);
|
||||
} else if (tape->realdir) {
|
||||
TCHAR path[MAX_DPATH], filename[MAX_DPATH];
|
||||
if (tape->od == NULL)
|
||||
tape->od = my_opendir (tape->tape_dir);
|
||||
if (!tape->od) {
|
||||
tape_free (tape);
|
||||
goto end;
|
||||
}
|
||||
for (;;) {
|
||||
if (!my_readdir (tape->od, filename))
|
||||
goto end;
|
||||
if (_tcsicmp (filename, TAPE_INDEX))
|
||||
continue;
|
||||
_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, filename);
|
||||
if (!my_existsfile (path))
|
||||
continue;
|
||||
tape->zf = zfile_fopen (path, _T("rb"), 0);
|
||||
if (!tape->zf)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (tape->zf)
|
||||
write_log (_T("TAPEEMU DIR: File '%s'\n"), zfile_getname (tape->zf));
|
||||
} else {
|
||||
tape->zf = zfile_readdir_archive_open (tape->zd, _T("rb"));
|
||||
if (tape->zf)
|
||||
write_log (_T("TAPEEMU ARC: File '%s'\n"), zfile_getname (tape->zf));
|
||||
}
|
||||
if (tape->zf) {
|
||||
tape->file_number++;
|
||||
return true;
|
||||
}
|
||||
end:
|
||||
write_log (_T("TAPEEMU: end of tape\n"));
|
||||
tape->beom = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int tape_read (struct scsi_data_tape *tape, uae_u8 *scsi_data, int len, bool *eof)
|
||||
{
|
||||
int got;
|
||||
|
||||
*eof = false;
|
||||
if (tape->beom > 0) {
|
||||
*eof = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!tape->zf) {
|
||||
tape_rewind (tape);
|
||||
if (!next_file (tape))
|
||||
return -1;
|
||||
}
|
||||
zfile_fseek (tape->zf, tape->file_offset, SEEK_SET);
|
||||
got = zfile_fread (scsi_data, 1, len, tape->zf);
|
||||
tape->file_offset += got;
|
||||
if (got < len) {
|
||||
*eof = true;
|
||||
next_file (tape);
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
static int tape_write (struct scsi_data_tape *tape, uae_u8 *scsi_data, int len)
|
||||
{
|
||||
TCHAR path[MAX_DPATH], numname[30];
|
||||
int exists;
|
||||
|
||||
if (!tape->realdir)
|
||||
return -1;
|
||||
_stprintf (numname, _T("%05d.tape"), tape->file_number);
|
||||
_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, numname);
|
||||
exists = my_existsfile (path);
|
||||
struct zfile *zf = zfile_fopen (path, _T("a+b"), 0);
|
||||
if (!zf)
|
||||
return -1;
|
||||
zfile_fseek (zf, 0, SEEK_END);
|
||||
len = zfile_fwrite (scsi_data, 1, len, zf);
|
||||
zfile_fclose (zf);
|
||||
if (!exists) {
|
||||
_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, TAPE_INDEX);
|
||||
zf = zfile_fopen (path, _T("a+b"), 0);
|
||||
if (zf) {
|
||||
zfile_fputs (zf, numname);
|
||||
zfile_fputs (zf, _T("\n"));
|
||||
}
|
||||
zfile_fclose (zf);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int scsi_tape_emulate (struct scsi_data_tape *tape, uae_u8 *cmdbuf, int scsi_cmd_len,
|
||||
uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len)
|
||||
{
|
||||
uae_s64 len;
|
||||
int lr = 0, ls = 0;
|
||||
int scsi_len = -1;
|
||||
int status = 0;
|
||||
int lun;
|
||||
bool eof;
|
||||
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU: %02X.%02X.%02X.%02X.%02X.%02X\n"),
|
||||
cmdbuf[0], cmdbuf[1], cmdbuf[2], cmdbuf[3], cmdbuf[4], cmdbuf[5]);
|
||||
|
||||
if (cmdbuf[0] == 3) {
|
||||
if (tape->beom == -1)
|
||||
s[9] |= 0x8; // beginning of media
|
||||
if (tape->beom == 1)
|
||||
s[2] |= 0x40; // end of media
|
||||
if (*sense_len < 0x12)
|
||||
*sense_len = 0x12;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*reply_len = *sense_len = 0;
|
||||
memset (r, 0, 256);
|
||||
memset (s, 0, 256);
|
||||
s[0] = 0x70;
|
||||
|
||||
lun = cmdbuf[1] >> 5;
|
||||
if (cmdbuf[0] != 0x03 && cmdbuf[0] != 0x12 && lun) {
|
||||
status = 2; /* CHECK CONDITION */
|
||||
s[0] = 0x70;
|
||||
s[2] = 5; /* ILLEGAL REQUEST */
|
||||
s[12] = 0x25; /* INVALID LUN */
|
||||
ls = 0x12;
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (cmdbuf[0])
|
||||
{
|
||||
case 0x00: /* TEST UNIT READY */
|
||||
if (notape (tape))
|
||||
goto notape;
|
||||
if (tape->unloaded)
|
||||
goto unloaded;
|
||||
scsi_len = 0;
|
||||
break;
|
||||
|
||||
case 0x19: /* ERASE */
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU ERASE\n"));
|
||||
if (notape (tape))
|
||||
goto notape;
|
||||
if (tape->unloaded)
|
||||
goto unloaded;
|
||||
if (tape->wp)
|
||||
goto writeprot;
|
||||
erase (tape);
|
||||
tape_rewind (tape);
|
||||
tape->beom = 1;
|
||||
scsi_len = 0;
|
||||
break;
|
||||
|
||||
case 0x1b: /* LOAD/UNLOAD */
|
||||
{
|
||||
bool load = (cmdbuf[4] & 1) != 0;
|
||||
bool ret = (cmdbuf[4] & 2) != 0;
|
||||
bool eot = (cmdbuf[4] & 4) != 0;
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU LOAD/UNLOAD %d:%d:%d\n"), eot, ret, load);
|
||||
if (notape (tape))
|
||||
goto notape;
|
||||
if (load && eot)
|
||||
goto errreq;
|
||||
tape_rewind (tape);
|
||||
tape->unloaded = !load;
|
||||
if (eot) {
|
||||
tape->beom = 1;
|
||||
} else {
|
||||
tape->beom = -1;
|
||||
}
|
||||
scsi_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01: /* REWIND */
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU: REWIND. IMMED=%d\n"), cmdbuf[1] & 1);
|
||||
if (notape (tape))
|
||||
goto notape;
|
||||
if (tape->unloaded)
|
||||
goto unloaded;
|
||||
tape_rewind (tape);
|
||||
scsi_len = 0;
|
||||
break;
|
||||
|
||||
case 0x11: /* SPACE */
|
||||
{
|
||||
int code = cmdbuf[1] & 15;
|
||||
int count = rl (cmdbuf + 1) & 0xffffff;
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU: SPACE code=%d count=%d\n"), code, count);
|
||||
if (notape (tape))
|
||||
goto notape;
|
||||
if (tape->unloaded)
|
||||
goto unloaded;
|
||||
if (code >= 2)
|
||||
goto errreq;
|
||||
if (code == 1) {
|
||||
if (!next_file (tape))
|
||||
goto endoftape;
|
||||
}
|
||||
scsi_len = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10: /* WRITE FILEMARK */
|
||||
len = rl (cmdbuf + 1) & 0xffffff;
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU WRITE FILEMARK %d\n"), len);
|
||||
if (notape (tape))
|
||||
goto notape;
|
||||
if (tape->unloaded)
|
||||
goto unloaded;
|
||||
if (tape->wp)
|
||||
goto writeprot;
|
||||
if (len > 0) {
|
||||
tape->file_number++;
|
||||
tape_write (tape, scsi_data, 0);
|
||||
}
|
||||
scsi_len = 0;
|
||||
break;
|
||||
|
||||
case 0x0a: /* WRITE (6) */
|
||||
len = rl (cmdbuf + 1) & 0xffffff;
|
||||
if (cmdbuf[1] & 1)
|
||||
len *= tape->blocksize;
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU WRITE %d (%d, %d)\n"), len, rl (cmdbuf + 1) & 0xffffff, cmdbuf[1] & 1);
|
||||
if (notape (tape))
|
||||
goto notape;
|
||||
if (tape->unloaded)
|
||||
goto unloaded;
|
||||
if (tape->wp)
|
||||
goto writeprot;
|
||||
if (tape->beom < 0)
|
||||
tape->beom = 0;
|
||||
scsi_len = tape_write (tape, scsi_data, len);
|
||||
if (scsi_len < 0)
|
||||
goto writeprot;
|
||||
break;
|
||||
|
||||
case 0x08: /* READ (6) */
|
||||
len = rl (cmdbuf + 1) & 0xffffff;
|
||||
if (cmdbuf[1] & 1)
|
||||
len *= tape->blocksize;
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU READ %d (%d, %d)\n"), len, rl (cmdbuf + 1) & 0xffffff, cmdbuf[1] & 1);
|
||||
if (notape (tape))
|
||||
goto notape;
|
||||
if (tape->unloaded)
|
||||
goto unloaded;
|
||||
if (tape->beom < 0)
|
||||
tape->beom = 0;
|
||||
scsi_len = tape_read (tape, scsi_data, len, &eof);
|
||||
if (log_tapeemu)
|
||||
write_log (_T("-> READ %d bytes\n"), scsi_len);
|
||||
if ((cmdbuf[1] & 1) && scsi_len > 0 && scsi_len < len) {
|
||||
int gap = tape->blocksize - (scsi_len & (tape->blocksize - 1));
|
||||
if (gap > 0 && gap < tape->blocksize)
|
||||
memset (scsi_data + scsi_len, 0, gap);
|
||||
scsi_len += tape->blocksize - 1;
|
||||
scsi_len &= ~(tape->blocksize - 1);
|
||||
}
|
||||
if (scsi_len < 0) {
|
||||
tape->beom = 2;
|
||||
status = SCSI_STATUS_CHECK_CONDITION;
|
||||
s[0] = 0x80 | 0x70;
|
||||
s[2] = 8; /* BLANK CHECK */
|
||||
if (cmdbuf[1] & 1)
|
||||
wl (&s[3], len / tape->blocksize);
|
||||
else
|
||||
wl (&s[3], len);
|
||||
s[12] = 0;
|
||||
s[13] = 2; /* End-of-partition/medium detected */
|
||||
ls = 0x12;
|
||||
} else if (eof) {
|
||||
status = SCSI_STATUS_CHECK_CONDITION;
|
||||
s[0] = 0x80 | 0x70; // Valid + code
|
||||
s[2] = 0x80 | 0; /* File Mark Detected + NO SENSE */
|
||||
if (cmdbuf[1] & 1)
|
||||
wl (&s[3], (len - scsi_len) / tape->blocksize);
|
||||
else
|
||||
wl (&s[3], len);
|
||||
s[12] = 0;
|
||||
s[13] = 1; /* File Mark detected */
|
||||
ls = 0x12;
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU READ FILE END, %d remaining\n"), len - scsi_len);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x5a: // MODE SENSE(10)
|
||||
case 0x1a: /* MODE SENSE(6) */
|
||||
{
|
||||
uae_u8 *p;
|
||||
int maxlen;
|
||||
bool pcodeloop = false;
|
||||
bool sense10 = cmdbuf[0] == 0x5a;
|
||||
int totalsize, bdsize;
|
||||
int pc = cmdbuf[2] >> 6;
|
||||
int pcode = cmdbuf[2] & 0x3f;
|
||||
int dbd = cmdbuf[1] & 8;
|
||||
if (cmdbuf[0] == 0x5a)
|
||||
dbd = 1;
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU MODE SENSE PC=%d CODE=%d DBD=%d\n"), pc, pcode, dbd);
|
||||
p = r;
|
||||
if (sense10) {
|
||||
totalsize = 8 - 2;
|
||||
maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
|
||||
p[2] = 0;
|
||||
p[3] = 0;
|
||||
p[4] = 0;
|
||||
p[5] = 0;
|
||||
p[6] = 0;
|
||||
p[7] = 0;
|
||||
p += 8;
|
||||
} else {
|
||||
totalsize = 4 - 1;
|
||||
maxlen = cmdbuf[4];
|
||||
p[1] = 0;
|
||||
p[2] = tape->wp ? 0x80 : 0;
|
||||
p[3] = 0;
|
||||
p += 4;
|
||||
}
|
||||
bdsize = 0;
|
||||
if (!dbd) {
|
||||
wl(p + 0, 0);
|
||||
wl(p + 4, tape->blocksize);
|
||||
bdsize = 8;
|
||||
p += bdsize;
|
||||
}
|
||||
if (pcode)
|
||||
goto errreq;
|
||||
if (sense10) {
|
||||
totalsize += bdsize;
|
||||
r[6] = bdsize >> 8;
|
||||
r[7] = bdsize & 0xff;
|
||||
r[0] = totalsize >> 8;
|
||||
r[1] = totalsize & 0xff;
|
||||
} else {
|
||||
totalsize += bdsize;
|
||||
r[3] = bdsize & 0xff;
|
||||
r[0] = totalsize & 0xff;
|
||||
}
|
||||
lr = totalsize + 1;
|
||||
if (lr > maxlen)
|
||||
lr = maxlen;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x55: // MODE SELECT(10)
|
||||
case 0x15: // MODE SELECT(6)
|
||||
{
|
||||
uae_u8 *p;
|
||||
bool mode10 = cmdbuf[0] == 0x55;
|
||||
int nb = 0, bl = 512;
|
||||
p = scsi_data + 4;
|
||||
if (mode10)
|
||||
p += 4;
|
||||
if (scsi_data[3] >= 8) {
|
||||
nb = rl (p) & 0xffffff;
|
||||
bl = rl (p + 4) & 0xffffff;
|
||||
}
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU MODE SELECT BUFM=%d BDL=%d Density=%d NB=%d BL=%d\n"), (scsi_data[2] & 0x10) != 0, scsi_data[3], p[0], nb, bl);
|
||||
if (nb || bl != 512)
|
||||
goto err;
|
||||
scsi_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x05: /* READ BLOCK LIMITS */
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU READ BLOCK LIMITS\n"));
|
||||
r[0] = 0;
|
||||
r[1] = 0;
|
||||
r[2] = 2; // 0x200 = 512
|
||||
r[3] = 0;
|
||||
r[4] = 2; // 0x200 = 512
|
||||
r[5] = 0;
|
||||
lr = 6;
|
||||
break;
|
||||
|
||||
case 0x16: /* RESERVE UNIT */
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU RESERVE UNIT\n"));
|
||||
scsi_len = 0;
|
||||
break;
|
||||
|
||||
case 0x17: /* RELEASE UNIT */
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU RELEASE UNIT\n"));
|
||||
scsi_len = 0;
|
||||
break;
|
||||
|
||||
case 0x1e: /* PREVENT/ALLOW MEDIUM REMOVAL */
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU PREVENT/ALLOW MEDIUM REMOVAL\n"));
|
||||
scsi_len = 0;
|
||||
break;
|
||||
|
||||
case 0x12: /* INQUIRY */
|
||||
{
|
||||
if (log_tapeemu)
|
||||
write_log (_T("TAPEEMU INQUIRY\n"));
|
||||
if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
|
||||
goto err;
|
||||
len = cmdbuf[4];
|
||||
if (cmdbuf[1] >> 5) {
|
||||
r[0] = 0x7f;
|
||||
} else {
|
||||
r[0] = INQ_SEQD;
|
||||
}
|
||||
r[1] |= 0x80; // removable
|
||||
r[2] = 2; /* supports SCSI-2 */
|
||||
r[3] = 2; /* response data format */
|
||||
r[4] = 32; /* additional length */
|
||||
r[7] = 0;
|
||||
scsi_len = lr = len < 36 ? len : 36;
|
||||
r[2] = 2;
|
||||
r[3] = 2;
|
||||
char *s = ua (_T("UAE"));
|
||||
memcpy (r + 8, s, strlen (s));
|
||||
xfree (s);
|
||||
s = ua (_T("SCSI TAPE"));
|
||||
memcpy (r + 16, s, strlen (s));
|
||||
xfree (s);
|
||||
s = ua (_T("0.1"));
|
||||
memcpy (r + 32, s, strlen (s));
|
||||
xfree (s);
|
||||
for (int i = 8; i < 36; i++) {
|
||||
if (r[i] == 0)
|
||||
r[i] = 32;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
write_log (_T("TAPEEMU: unsupported scsi command 0x%02X\n"), cmdbuf[0]);
|
||||
err:
|
||||
status = SCSI_STATUS_CHECK_CONDITION;
|
||||
s[0] = 0x70;
|
||||
s[2] = SCSI_SK_ILLEGAL_REQ;
|
||||
s[12] = SCSI_INVALID_COMMAND;
|
||||
ls = 0x12;
|
||||
break;
|
||||
writeprot:
|
||||
status = 2; /* CHECK CONDITION */
|
||||
s[0] = 0x70;
|
||||
s[2] = 7; /* DATA PROTECT */
|
||||
s[12] = 0x27; /* WRITE PROTECTED */
|
||||
ls = 0x12;
|
||||
break;
|
||||
errreq:
|
||||
lr = -1;
|
||||
status = SCSI_STATUS_CHECK_CONDITION;
|
||||
s[0] = 0x70;
|
||||
s[2] = SCSI_SK_ILLEGAL_REQ;
|
||||
s[12] = SCSI_INVALID_FIELD;
|
||||
ls = 0x12;
|
||||
break;
|
||||
endoftape:
|
||||
status = SCSI_STATUS_CHECK_CONDITION;
|
||||
s[0] = 0x70;
|
||||
s[2] = SCSI_SK_MED_ERR;
|
||||
s[12] = 0;
|
||||
s[13] = 2; /* End-of-partition/medium detected */
|
||||
ls = 0x12;
|
||||
break;
|
||||
unloaded:
|
||||
status = SCSI_STATUS_CHECK_CONDITION;
|
||||
s[0] = 0x70;
|
||||
s[2] = SCSI_SK_NOT_READY;
|
||||
s[12] = SCSI_NOT_READY;
|
||||
ls = 0x12;
|
||||
break;
|
||||
notape:
|
||||
status = SCSI_STATUS_CHECK_CONDITION;
|
||||
s[0] = 0x70;
|
||||
s[2] = SCSI_SK_NOT_READY;
|
||||
s[12] = SCSI_MEDIUM_NOT_PRESENT;
|
||||
ls = 0x12;
|
||||
break;
|
||||
}
|
||||
*data_len = scsi_len;
|
||||
*reply_len = lr;
|
||||
*sense_len = ls;
|
||||
if (ls > 0) {
|
||||
if (tape->beom == 1)
|
||||
s[2] |= 0x40;
|
||||
if (tape->beom == -1)
|
||||
s[9] |= 0x8;
|
||||
if (log_tapeemu) {
|
||||
write_log (_T("TAPEEMU SENSE: "));
|
||||
for (int i = 0; i < ls; i++)
|
||||
write_log (_T("%02X."), s[i]);
|
||||
write_log (_T("\n"));
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
Loading…
Reference in New Issue
Block a user