summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/lynx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/machine/lynx.c')
-rw-r--r--src/mess/machine/lynx.c2144
1 files changed, 0 insertions, 2144 deletions
diff --git a/src/mess/machine/lynx.c b/src/mess/machine/lynx.c
deleted file mode 100644
index b68b2b6c0d3..00000000000
--- a/src/mess/machine/lynx.c
+++ /dev/null
@@ -1,2144 +0,0 @@
-// license:GPL-2.0+
-// copyright-holders:Peter Trauner
-/******************************************************************************
- PeT mess@utanet.at 2000,2001
-******************************************************************************/
-
-#include "emu.h"
-#include "includes/lynx.h"
-#include "cpu/m6502/m65sc02.h"
-
-
-#define PAD_UP 0x80
-#define PAD_DOWN 0x40
-#define PAD_LEFT 0x20
-#define PAD_RIGHT 0x10
-
-
-/****************************************
-
- Graphics Drawing
-
-****************************************/
-
-/* modes from blitter command */
-enum {
- BACKGROUND = 0,
- BACKGROUND_NO_COLL,
- BOUNDARY_SHADOW,
- BOUNDARY,
- NORMAL_SPRITE,
- NO_COLL,
- XOR_SPRITE,
- SHADOW
-};
-
-UINT8 lynx_state::lynx_read_ram(UINT16 address)
-{
- UINT8 result = 0x00;
- if (address <= 0xfbff)
- result = m_mem_0000[address - 0x0000];
- else if (address <= 0xfcff)
- result = m_mem_fc00[address - 0xfc00];
- else if (address <= 0xfdff)
- result = m_mem_fd00[address - 0xfd00];
- else if (address <= 0xfff7)
- result = m_mem_fe00[address - 0xfe00];
- else if (address >= 0xfffa)
- result = m_mem_fffa[address - 0xfffa];
- return result;
-}
-
-void lynx_state::lynx_write_ram(UINT16 address, UINT8 data)
-{
- if (address <= 0xfbff)
- m_mem_0000[address - 0x0000] = data;
- else if (address <= 0xfcff)
- m_mem_fc00[address - 0xfc00] = data;
- else if (address <= 0xfdff)
- m_mem_fd00[address - 0xfd00] = data;
- else if (address <= 0xfff7)
- m_mem_fe00[address - 0xfe00] = data;
- else if (address >= 0xfffa)
- m_mem_fffa[address - 0xfffa] = data;
-}
-
-/* The pen numbers range from '0' to 'F. Pen numbers '1' through 'D' are always collidable and opaque. The other
-ones have different behavior depending on the sprite type: there are 8 types of sprites, each has different
-characteristics relating to some or all of their pen numbers.
-
-* Shadow Error: The hardware is missing an inverter in the 'shadow' generator. This causes sprite types that
-did not invoke shadow to now invoke it and vice versa. The only actual functionality loss is that 'exclusive or'
-sprites and 'background' sprites will have shadow enabled.
-
-The sprite types relate to specific hardware functions according to the following table:
-
-
- -------------------------- SHADOW
- | ----------------------- BOUNDARY_SHADOW
- | | -------------------- NORMAL_SPRITE
- | | | ----------------- BOUNDARY
- | | | | -------------- BACKGROUND (+ shadow, due to bug in 'E' pen)
- | | | | | ----------- BACKGROUND_NO_COLL
- | | | | | | -------- NO_COLL
- | | | | | | | ----- XOR_SPRITE (+ shadow, due to bug in 'E' pen)
- | | | | | | | |
- 1 0 1 0 1 1 1 1 F is opaque
- 0 0 1 1 0 0 0 0 E is collideable
- 0 0 1 1 0 0 0 0 0 is opaque and collideable
- 1 1 1 1 0 0 0 1 allow collision detect
- 1 1 1 1 1 0 0 1 allow coll. buffer access
- 0 0 0 0 0 0 0 1 exclusive-or the data
-*/
-
-inline void lynx_state::lynx_plot_pixel(const int mode, const INT16 x, const int y, const int color)
-{
- UINT8 back;
- UINT16 screen;
- UINT16 colbuf;
-
- m_blitter.everon = TRUE;
- screen = m_blitter.screen + y * 80 + x / 2;
- colbuf = m_blitter.colbuf + y * 80 + x / 2;
-
- /* a note on timing: The hardware packs the pixel data and updates the screen and collision buffer a byte at a time.
- Thus the buffer update for two pixels takes 3 memory accesses for a normal sprite (write to screen buffer, read/write to collision buffer).
- +1 memory access for palette fetch?
- */
-
- switch (mode&0x7)
- {
- case NORMAL_SPRITE:
- /* A sprite may be set to 'normal'. This means that pen number '0' will be transparent and
- non-collideable. All other pens will be opaque and collideable */
- if (color == 0)
- break;
- if (!(x & 0x01)) /* Upper nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0x0f) | (color << 4));
- m_blitter.memory_accesses++;
-
- if(m_blitter.sprite_collide && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4));
- m_blitter.memory_accesses += 2;
- if ((back >> 4) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- }
- m_blitter.memory_accesses++;
- }
- else /* Lower nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0xf0) | color);
-
- if(m_blitter.sprite_collide && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr));
- if ((back & 0x0f) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- }
- }
- break;
-
- case BOUNDARY:
- /* A sprite may be set to 'boundary'. This is a 'normal' sprite with the exception that pen
- number 'F' is transparent (and still collideable). */
- if (color == 0)
- break;
- if (!(x & 0x01)) /* Upper nibble */
- {
- if (color != 0x0f)
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0x0f) | (color << 4));
- m_blitter.memory_accesses++;
- }
- if(m_blitter.sprite_collide && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4));
- if ((back >> 4) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- m_blitter.memory_accesses += 2;
- }
- m_blitter.memory_accesses++;
- }
- else /* Lower nibble */
- {
- if (color != 0x0f)
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0xf0) | color);
- }
- if(m_blitter.sprite_collide && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr));
- if ((back & 0x0f) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- }
- }
- break;
-
- case SHADOW:
- /* A sprite may be set to 'shadow'. This is a 'normal' sprite with the exception that pen
- number 'E' is non-collideable (but still opaque) */
- if (color == 0)
- break;
- if (!(x & 0x01)) /* Upper nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0x0f) | (color << 4));
- m_blitter.memory_accesses++;
-
- if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4));
- if ((back >> 4) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- m_blitter.memory_accesses += 2;
- }
- m_blitter.memory_accesses++;
- }
- else /* Lower nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0xf0) | color);
-
- if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr));
- if ((back & 0x0f) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- }
- }
- break;
-
- case BOUNDARY_SHADOW:
- /* This sprite is a 'normal' sprite with the characteristics of both 'boundary'
- and 'shadow'. That is, pen number 'F' is transparent (and still collideable) and
- pen number 'E' is non-collideable (but still opaque). */
- if (color == 0)
- break;
- if (!(x & 0x01)) /* Upper nibble */
- {
- if (color != 0x0f)
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0x0f) | (color << 4));
- m_blitter.memory_accesses++;
- }
- if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4));
- if ((back >> 4) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- m_blitter.memory_accesses += 2;
- }
- m_blitter.memory_accesses++;
- }
- else /* Lower nibble */
- {
- if (color != 0x0f)
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0xf0) | color);
- }
- if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr));
- if ((back & 0x0f) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- }
- }
- break;
-
- case BACKGROUND:
- /* A sprite may be set to 'background'. This sprite will overwrite the contents of the video and
- collision buffers. Pens '0' and 'F' are no longer transparent. This sprite is used to initialize
- the buffers at the start of a 'painting'. Additionally, no collision detection is done, and no write
- to the collision depository occurs. The 'E' error will cause the pen number 'E' to be non-collideable
- and therefore not clear the collision buffer */
- if (!(x & 0x01)) /* Upper nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0x0f) | (color << 4));
- m_blitter.memory_accesses++;
-
- if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4));
- m_blitter.memory_accesses++;
- }
- m_blitter.memory_accesses++;
- }
- else /* Lower nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0xf0) | color);
-
- if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr));
- }
- }
- break;
-
- case BACKGROUND_NO_COLL:
- /* This is a 'background' sprite with the exception that no activity occurs in the collision buffer */
- if (!(x & 0x01)) /* Upper nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0x0f) | (color << 4));
- m_blitter.memory_accesses++;
- m_blitter.memory_accesses++;
- }
- else /* Lower nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0xf0) | color);
- }
- break;
-
- case NO_COLL:
- /* A sprite may be set to 'non-collideable'. This means that it will have no affect on the contents of
- the collision buffer and all other collision activities are overridden (pen 'F' is not collideable). */
- if (color == 0)
- break;
- if (!(x & 0x01)) /* Upper nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0x0f) | (color << 4));
- m_blitter.memory_accesses++;
- m_blitter.memory_accesses++;
- }
- else /* Lower nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, (back & 0xf0) | color);
- }
- break;
-
- case XOR_SPRITE:
- /* This is a 'normal' sprite with the exception that the data from the video buffer is exclusive-ored
- with the sprite data and written back out to the video buffer. Collision activity is 'normal'. The 'E'
- error will cause the pen number 'E' to be non-collideable and therefore not react with the collision
- buffer */
- if (color == 0)
- break;
- if (!(x & 0x01)) /* Upper nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, back^(color << 4));
- m_blitter.memory_accesses += 2;
- if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4));
- if ((back >> 4) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- m_blitter.memory_accesses += 2;
- }
- m_blitter.memory_accesses++;
- }
- else /* Lower nibble */
- {
- back = lynx_read_ram(screen);
- lynx_write_ram(screen, back^color);
- if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide))
- {
- back = lynx_read_ram(colbuf);
- lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr));
- if ((back & 0x0f) > m_blitter.fred)
- m_blitter.fred = back >> 4;
- }
- }
- break;
- }
-}
-
-void lynx_state::lynx_blit_do_work( const int y, const int xdir, const int bits_per_pixel, const int mask )
-{
- int next_line_addr,i,j;
- int xi, bits, color;
- UINT16 width_accum, buffer;
-
- next_line_addr = lynx_read_ram(m_blitter.bitmap); // offset to second sprite line
- width_accum = (xdir == 1) ? m_blitter.width_offset : 0;
- m_blitter.memory_accesses++;
-
- for (xi = m_blitter.x_pos - m_blitter.xoff, bits = 0, buffer = 0, j = 1; j < next_line_addr;j++)
- {
- buffer = (buffer << 8) | lynx_read_ram(m_blitter.bitmap + j);
- bits += 8; // current bits in buffer
- m_blitter.memory_accesses++;
-
- for ( ; bits > bits_per_pixel; bits -= bits_per_pixel) // last data packet at end of scanline is not rendered (qix, blulght)
- {
- color = m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask];
- width_accum += m_blitter.width;
- for (i = 0; i < (width_accum>>8); i++, xi += xdir)
- {
- if ((xi >= 0) && (xi < 160))
- {
- lynx_plot_pixel(m_blitter.mode, xi, y, color);
- }
- }
- width_accum &= 0xff;
- }
- }
-}
-
-void lynx_state::lynx_blit_rle_do_work( const INT16 y, const int xdir, const int bits_per_pixel, const int mask )
-{
- int i;
- int xi;
- int buffer, bits, j;
- int literal_data, count, color;
- UINT16 width_accum;
-
- width_accum = (xdir == 1) ? m_blitter.width_offset : 0;
- for( bits = 0, j = 0, buffer = 0, xi = m_blitter.x_pos - m_blitter.xoff; ; ) /* through the rle entries */
- {
- if (bits < 5 + bits_per_pixel) /* under 7 bits no complete entry */
- {
- j++;
- if (j >= lynx_read_ram(m_blitter.bitmap))
- return;
-
- bits += 8;
- buffer = (buffer << 8) | lynx_read_ram(m_blitter.bitmap + j);
- m_blitter.memory_accesses++;
- }
-
- literal_data = (buffer >> (bits - 1)) & 0x01;
- bits--;
- count = (buffer >> (bits - 4)) & 0x0f; // repeat count (packed) or pixel count (literal)
- bits -= 4;
-
- if (literal_data) /* count of different pixels */
- {
- for ( ; count >= 0; count--)
- {
- if (bits < bits_per_pixel)
- {
- j++;
- if (j >= lynx_read_ram(m_blitter.bitmap))
- return;
- bits += 8;
- buffer = (buffer << 8) | lynx_read_ram(m_blitter.bitmap + j);
- m_blitter.memory_accesses++;
- }
-
- color = m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask];
- bits -= bits_per_pixel;
- width_accum += m_blitter.width;
- for (i = 0; i < (width_accum>>8); i++, xi += xdir)
- {
- if ((xi >= 0) && (xi < 160))
- lynx_plot_pixel(m_blitter.mode, xi, y, color);
- }
- width_accum &= 0xff;
- }
- }
- else /* count of same pixels */
- {
- if (count == 0) // 4 bit count value of zero indicates end-of-line in a packed sprite
- return;
-
- if (bits < bits_per_pixel)
- {
- j++;
- if (j >= lynx_read_ram(m_blitter.bitmap))
- return;
- bits += 8;
- buffer = (buffer << 8) | lynx_read_ram(m_blitter.bitmap + j);
- m_blitter.memory_accesses++;
- }
-
- color = m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask];
- bits -= bits_per_pixel;
-
- for ( ; count>=0; count--)
- {
- width_accum += m_blitter.width;
- for (i = 0; i < (width_accum >> 8); i++, xi += xdir)
- {
- if ((xi >= 0) && (xi < 160))
- lynx_plot_pixel(m_blitter.mode, xi, y, color);
- }
- width_accum &= 0xff;
- }
- }
- }
-}
-
-void lynx_state::lynx_blit_lines()
-{
- static const int lynx_color_masks[4] = { 0x01, 0x03, 0x07, 0x0f };
- INT16 y;
- int i;
- int ydir = 0, xdir = 0;
- int flip = 0;
-
- m_blitter.everon = FALSE;
-
- switch (m_blitter.spr_ctl1 & 0x03) /* Initial drawing direction */
- {
- case 0: // Down/Right (quadrant 0)
- xdir = 1;
- ydir = 1;
- flip = 0;
- break;
- case 1: // Down/Left (blockout) (quadrant 3)
- xdir = -1;
- ydir = 1;
- flip = 3;
- break;
- case 2: // Up/Right (fat bobby) (quadrant 1)
- xdir = 1;
- ydir = -1;
- flip = 1;
- break;
- case 3: // Up/Left (quadrant 2)
- xdir = -1;
- ydir = -1;
- flip = 2;
- break;
- }
-
- if (m_blitter.spr_ctl0 & 0x20) /* Horizontal Flip */
- {
- xdir *= -1;
- }
-
- if (m_blitter.spr_ctl0 & 0x10) /* Vertical Flip */
- {
- ydir *= -1;
- }
-
- // Set height accumulator based on drawing direction
- m_blitter.height_accumulator = (ydir == 1) ? m_blitter.height_offset : 0x00;
-
- // loop through lines, next line offset of zero indicates end of sprite
- for (y = m_blitter.y_pos - m_blitter.yoff; (i = lynx_read_ram(m_blitter.bitmap)); m_blitter.bitmap += i)
- {
- m_blitter.memory_accesses++;
-
- if (i == 1) // draw next quadrant
- {
- // centered sprites sprdemo3, fat bobby, blockout
- switch (flip & 0x03)
- {
- case 0:
- case 2:
- ydir *= -1;
- m_blitter.y_pos += ydir;
- break;
- case 1:
- case 3:
- xdir *= -1;
- m_blitter.x_pos += xdir;
- break;
- }
- flip++;
- y = m_blitter.y_pos - m_blitter.yoff;
- m_blitter.height_accumulator = (ydir == 1) ? m_blitter.height_offset : 0x00;
- continue;
- }
-
- m_blitter.height_accumulator += m_blitter.height;
- for (int j = 0; j < (m_blitter.height_accumulator >> 8); j++, y += ydir)
- {
- if (y >= 0 && y < 102)
- {
- if (m_blitter.use_rle)
- lynx_blit_rle_do_work(y, xdir, m_blitter.line_color + 1, lynx_color_masks[m_blitter.line_color]);
- else
- lynx_blit_do_work(y, xdir, m_blitter.line_color + 1, lynx_color_masks[m_blitter.line_color]);
- }
- m_blitter.width += (INT16)m_blitter.stretch;
- if (m_blitter.vstretch) // doesn't seem to be used
- {
- m_blitter.height += (INT16)m_blitter.stretch;
- logerror("vertical stretch enabled");
- }
- m_blitter.tilt_accumulator += m_blitter.tilt;
- m_blitter.x_pos += (m_blitter.tilt_accumulator>>8);
- m_blitter.tilt_accumulator &= 0xff;
- }
- m_blitter.height_accumulator &= 0xff;
- }
-}
-
-void lynx_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch (id)
- {
- case TIMER_BLITTER:
- lynx_blitter_timer(ptr, param);
- break;
- case TIMER_SHOT:
- lynx_timer_shot(ptr, param);
- break;
- case TIMER_UART_LOOPBACK:
- lynx_uart_loopback_timer(ptr, param);
- break;
- case TIMER_UART:
- lynx_uart_timer(ptr, param);
- break;
- default:
- assert_always(FALSE, "Unknown id in lynx_state::device_timer");
- }
-}
-
-TIMER_CALLBACK_MEMBER(lynx_state::lynx_blitter_timer)
-{
- m_blitter.busy=0; // blitter finished
- m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
-}
-
-/*
- control 0
- bit 7,6: 00 2 color
- 01 4 color
- 11 8 colors?
- 11 16 color
- bit 5,4: 00 right down
- 01 right up
- 10 left down
- 11 left up
-
-#define SHADOW (0x07)
-#define XORSHADOW (0x06)
-#define NONCOLLIDABLE (0x05)
-#define NORMAL (0x04)
-#define BOUNDARY (0x03)
-#define BOUNDARYSHADOW (0x02)
-#define BKGRNDNOCOL (0x01)
-#define BKGRND (0x00)
-
- control 1
- bit 7: 0 bitmap rle encoded
- 1 not encoded
- bit 3: 0 color info with command
- 1 no color info with command
-
-#define RELHVST (0x30)
-#define RELHVS (0x20)
-#define RELHV (0x10)
-
-#define SKIPSPRITE (0x04)
-
-#define DUP (0x02)
-#define DDOWN (0x00)
-#define DLEFT (0x01)
-#define DRIGHT (0x00)
-
-
- coll
-#define DONTCOLLIDE (0x20)
-
- word next
- word data
- word x
- word y
- word width
- word height
-
- pixel c0 90 20 0000 datapointer x y 0100 0100 color (8 colorbytes)
- 4 bit direct?
- datapointer 2 10 0
- 98 (0 colorbytes)
-
- box c0 90 20 0000 datapointer x y width height color
- datapointer 2 10 0
-
- c1 98 00 4 bit direct without color bytes (raycast)
-
- 40 10 20 4 bit rle (sprdemo2)
-
- line c1 b0 20 0000 datapointer x y 0100 0100 stretch tilt:x/y color (8 color bytes)
- or
- line c0 b0 20 0000 datapointer x y 0100 0100 stretch tilt:x/y color
- datapointer 2 11 0
-
- text ?(04) 90 20 0000 datapointer x y width height color
- datapointer 2 10 0
-
- stretch: hsize adder
- tilt: hpos adder
-
-*/
-
-void lynx_state::lynx_blitter()
-{
- static const int lynx_colors[4] = { 2, 4, 8, 16 };
- UINT8 palette_offset;
- UINT8 coldep;
- int colors;
-
- m_blitter.busy = 1; // blitter working
- m_blitter.memory_accesses = 0;
-
- // Last SCB is indicated by zero in the high byte of SCBNEXT
- while (m_blitter.scb_next & 0xff00)
- {
- m_blitter.stretch = 0;
- m_blitter.tilt = 0;
- m_blitter.tilt_accumulator = 0;
-
- m_blitter.scb = m_blitter.scb_next; // current scb
- m_blitter.scb_next = lynx_read_ram(m_blitter.scb + SCB_SCBNEXT) | (lynx_read_ram(m_blitter.scb + SCB_SCBNEXT + 1) << 8); // next scb
- m_blitter.spr_ctl0 = lynx_read_ram(m_blitter.scb + SCB_SPRCTL0);
- m_blitter.spr_ctl1 = lynx_read_ram(m_blitter.scb + SCB_SPRCTL1);
- m_blitter.spr_coll = lynx_read_ram(m_blitter.scb + SCB_SPRCOLL);
- m_blitter.memory_accesses += 5;
-
- if(!(m_blitter.spr_ctl1 & 0x04)) // sprite will be processed (if sprite is skipped first 5 bytes are still copied to suzy)
- {
- m_blitter.bitmap = lynx_read_ram(m_blitter.scb + SCB_SPRDLINE) | (lynx_read_ram(m_blitter.scb + SCB_SPRDLINE + 1) << 8);
- m_blitter.x_pos = lynx_read_ram(m_blitter.scb + SCB_HPOSSTRT) | (lynx_read_ram(m_blitter.scb + SCB_HPOSSTRT + 1) << 8);
- m_blitter.y_pos = lynx_read_ram(m_blitter.scb + SCB_VPOSSTRT) | (lynx_read_ram(m_blitter.scb + SCB_VPOSSTRT + 1) << 8);
- m_blitter.memory_accesses += 6;
-
- switch(m_blitter.spr_ctl1 & 0x30) // reload sprite scaling
- {
- case 0x30: // width, height, tilt, stretch
- m_blitter.tilt = lynx_read_ram(m_blitter.scb + SCB_TILT) | (lynx_read_ram(m_blitter.scb + SCB_TILT + 1) << 8);
- m_blitter.memory_accesses+=2;
- case 0x20: // width, height, stretch
- m_blitter.stretch = lynx_read_ram(m_blitter.scb + SCB_STRETCH) | (lynx_read_ram(m_blitter.scb + SCB_STRETCH + 1) << 8);
- m_blitter.memory_accesses+=2;
- case 0x10: // width, height
- m_blitter.width = lynx_read_ram(m_blitter.scb + SCB_SPRHSIZ) | (lynx_read_ram(m_blitter.scb + SCB_SPRHSIZ + 1) << 8);
- m_blitter.height = lynx_read_ram(m_blitter.scb + SCB_SPRVSIZ) | (lynx_read_ram(m_blitter.scb + SCB_SPRVSIZ + 1) << 8);
- m_blitter.memory_accesses+=4;
- }
-
- if(!(m_blitter.spr_ctl1 & 0x08)) // reload palette
- {
- if (m_blitter.spr_ctl1 & 0x30)
- palette_offset = 0x0b + 2*(((m_blitter.spr_ctl1 & 0x30)>>4) + 1); // palette data offset depends on width, height, etc. reloading
- else
- palette_offset = 0x0b;
-
- colors = lynx_colors[m_blitter.spr_ctl0 >> 6];
-
- for (int i = 0; i < colors / 2; i++)
- {
- m_blitter.color[i * 2] = lynx_read_ram(m_blitter.scb + palette_offset + i) >> 4;
- m_blitter.color[i * 2 + 1 ] = lynx_read_ram(m_blitter.scb + palette_offset + i) & 0x0f;
- m_blitter.memory_accesses++;
- }
- }
- }
-
-
- if (!(m_blitter.spr_ctl1 & 0x04)) // if 0, we skip this sprite
- {
- m_blitter.colpos = m_blitter.scb + (m_suzy.data[COLLOFFL] | (m_suzy.data[COLLOFFH]<<8));
- m_blitter.mode = m_blitter.spr_ctl0 & 0x07;
- m_blitter.use_rle = m_blitter.spr_ctl1 & 0x80 ? 0 : 1;
- m_blitter.line_color = (m_blitter.spr_ctl0 >> 6) & 0x03;
-
- m_blitter.sprite_collide = !(m_blitter.spr_coll & 0x20);
- m_blitter.spritenr = m_blitter.spr_coll & 0x0f;
- m_blitter.fred = 0;
-
- /* Draw Sprite */
- lynx_blit_lines();
-
- if (m_blitter.sprite_collide && !(m_blitter.no_collide))
- {
- switch (m_blitter.mode)
- {
- case BOUNDARY_SHADOW:
- case BOUNDARY:
- case NORMAL_SPRITE:
- case XOR_SPRITE:
- case SHADOW:
- lynx_write_ram(m_blitter.colpos, m_blitter.fred);
- break;
- }
- }
-
- if (m_suzy.data[SPRGO] & 0x04) // Everon enabled
- {
- coldep = lynx_read_ram(m_blitter.colpos);
- if (!m_blitter.everon)
- coldep |= 0x80;
- else
- coldep &= 0x7f;
- lynx_write_ram(m_blitter.colpos, coldep);
- }
- }
- }
-
- timer_set(m_maincpu->cycles_to_attotime(m_blitter.memory_accesses), TIMER_BLITTER);
-}
-
-
-/****************************************
-
- Suzy Emulation
-
-****************************************/
-
-
-/* Math bugs of the original hardware:
-
-- in signed multiply, the hardware thinks that 8000 is a positive number
-- in signed multiply, the hardware thinks that 0 is a negative number. This is not an immediate
-problem for a multiply by zero, since the answer will be re-negated to the correct polarity of
-zero. However, since it will set the sign flag, you can not depend on the sign flag to be correct
-if you just load the lower byte after a multiply by zero.
-- in divide, the remainder will have 2 possible errors, depending on its actual value (no further
-notes on these errors available) */
-
-void lynx_state::lynx_divide()
-{
- UINT32 left;
- UINT16 right;
- UINT32 res, mod;
- /*
- Hardware divide:
- EFGH
- * NP
- ----------------
- ABCD
- Remainder (JK)LM
- */
-
- left = m_suzy.data[MATH_H] | (m_suzy.data[MATH_G] << 8) | (m_suzy.data[MATH_F] << 16) | (m_suzy.data[MATH_E] << 24);
- right = m_suzy.data[MATH_P] | (m_suzy.data[MATH_N] << 8);
-
- m_suzy.accumulate_overflow = FALSE;
- if (right == 0)
- {
- m_suzy.accumulate_overflow = TRUE; /* during divisions, this bit is used to detect denominator = 0 */
- res = 0xffffffff;
- mod = 0; //?
- }
- else
- {
- res = left / right;
- mod = left % right;
- }
-// logerror("coprocessor %8x / %8x = %4x\n", left, right, res);
- m_suzy.data[MATH_D] = res & 0xff;
- m_suzy.data[MATH_C] = res >> 8;
- m_suzy.data[MATH_B] = res >> 16;
- m_suzy.data[MATH_A] = res >> 24;
-
- m_suzy.data[MATH_M] = mod & 0xff;
- m_suzy.data[MATH_L] = mod >> 8;
- m_suzy.data[MATH_K] = 0; // documentation states the hardware sets these to zero on divides
- m_suzy.data[MATH_J] = 0;
-}
-
-void lynx_state::lynx_multiply()
-{
- UINT16 left, right;
- UINT32 res, accu;
- /*
- Hardware multiply:
- AB
- * CD
- ----------------
- EFGH
- Accumulate JKLM
- */
- m_suzy.accumulate_overflow = FALSE;
-
- left = m_suzy.data[MATH_B] | (m_suzy.data[MATH_A] << 8);
- right = m_suzy.data[MATH_D] | (m_suzy.data[MATH_C] << 8);
-
- res = left * right;
-
- if (m_suzy.signed_math)
- {
- if (!(m_sign_AB + m_sign_CD)) /* different signs */
- res = (res ^ 0xffffffff) + 1;
- }
-
- m_suzy.data[MATH_H] = res & 0xff;
- m_suzy.data[MATH_G] = res >> 8;
- m_suzy.data[MATH_F] = res >> 16;
- m_suzy.data[MATH_E] = res >> 24;
-
- if (m_suzy.accumulate)
- {
- accu = m_suzy.data[MATH_M] | m_suzy.data[MATH_L] << 8 | m_suzy.data[MATH_K] << 16 | m_suzy.data[MATH_J] << 24;
- accu += res;
-
- if (accu < res)
- m_suzy.accumulate_overflow = TRUE;
-
- m_suzy.data[MATH_M] = accu;
- m_suzy.data[MATH_L] = accu >> 8;
- m_suzy.data[MATH_K] = accu >> 16;
- m_suzy.data[MATH_J] = accu >> 24;
- }
-}
-
-READ8_MEMBER(lynx_state::suzy_read)
-{
- UINT8 value = 0, input;
-
- switch (offset)
- {
- case TILTACUML:
- return m_blitter.tilt_accumulator & 0xff;
- case TILTACUMH:
- return m_blitter.tilt_accumulator>>8;
- case HOFFL:
- return m_blitter.xoff & 0xff;
- case HOFFH:
- return m_blitter.xoff>>8;
- case VOFFL:
- return m_blitter.yoff & 0xff;
- case VOFFH:
- return m_blitter.yoff>>8;
- case VIDBASL:
- return m_blitter.screen & 0xff;
- case VIDBASH:
- return m_blitter.screen>>8;
- case COLLBASL:
- return m_blitter.colbuf & 0xff;
- case COLLBASH:
- return m_blitter.colbuf>>8;
- case SCBNEXTL:
- return m_blitter.scb_next & 0xff;
- case SCBNEXTH:
- return m_blitter.scb_next>>8;
- case SPRDLINEL:
- return m_blitter.bitmap & 0xff;
- case SPRDLINEH:
- return m_blitter.bitmap>>8;
- case HPOSSTRTL:
- return m_blitter.x_pos & 0xff;
- case HPOSSTRTH:
- return m_blitter.x_pos>>8;
- case VPOSSTRTL:
- return m_blitter.y_pos & 0xff;
- case VPOSSTRTH:
- return m_blitter.y_pos>>8;
- case SPRHSIZL:
- return m_blitter.width & 0xff;
- case SPRHSIZH:
- return m_blitter.width>>8;
- case SPRVSIZL:
- return m_blitter.height & 0xff;
- case SPRVSIZH:
- return m_blitter.height>>8;
- case STRETCHL:
- return m_blitter.stretch & 0xff;
- case STRETCHH:
- return m_blitter.stretch>>8;
- case TILTL:
- return m_blitter.tilt & 0xff;
- case TILTH:
- return m_blitter.tilt>>8;
- // case SPRDOFFL:
- // case SPRVPOSL:
- // case COLLOFFL:
- case VSIZACUML:
- return m_blitter.height_accumulator & 0xff;
- case VSIZACUMH:
- return m_blitter.height_accumulator>>8;
- case HSIZOFFL:
- return m_blitter.width_offset & 0xff;
- case HSIZOFFH:
- return m_blitter.width_offset>>8;
- case VSIZOFFL:
- return m_blitter.height_offset & 0xff;
- case VSIZOFFH:
- return m_blitter.height_offset>>8;
- case SCBADRL:
- return m_blitter.scb & 0xff;
- case SCBADRH:
- return m_blitter.scb>>8;
- //case PROCADRL:
- case SUZYHREV:
- return 0x01; // must not be 0 for correct power up
- case SPRSYS:
- // math busy, last carry, unsafe access, and stop on current sprite bits not implemented.
- if (m_suzy.accumulate_overflow)
- value |= 0x40;
- if (m_blitter.vstretch)
- value |= 0x10;
- if (m_blitter.lefthanded)
- value |= 0x08;
- if (m_blitter.busy)
- value |= 0x01;
- break;
- case JOYSTICK:
- input = ioport("JOY")->read();
- switch (m_rotate)
- {
- case 1:
- value = input;
- input &= 0x0f;
- if (value & PAD_UP) input |= PAD_LEFT;
- if (value & PAD_LEFT) input |= PAD_DOWN;
- if (value & PAD_DOWN) input |= PAD_RIGHT;
- if (value & PAD_RIGHT) input |= PAD_UP;
- break;
- case 2:
- value = input;
- input &= 0x0f;
- if (value & PAD_UP) input |= PAD_RIGHT;
- if (value & PAD_RIGHT) input |= PAD_DOWN;
- if (value & PAD_DOWN) input |= PAD_LEFT;
- if (value & PAD_LEFT) input |= PAD_UP;
- break;
- }
- if (m_blitter.lefthanded)
- {
- value = input & 0x0f;
- if (input & PAD_UP) value |= PAD_DOWN;
- if (input & PAD_DOWN) value |= PAD_UP;
- if (input & PAD_LEFT) value |= PAD_RIGHT;
- if (input & PAD_RIGHT) value |= PAD_LEFT;
- }
- else
- value = input;
- break;
- case SWITCHES:
- value = ioport("PAUSE")->read();
- break;
- case RCART:
- if (m_cart->exists())
- value = m_cart->read_rom(space, (m_suzy.high * m_granularity) + m_suzy.low);
- else
- value = 0;
- m_suzy.low = (m_suzy.low + 1) & (m_granularity - 1);
- break;
- //case RCART_BANK1: /* we need bank 1 emulation!!! */
- case SPRCTL0:
- case SPRCTL1:
- case SPRCOLL:
- case SPRINIT:
- case SUZYBUSEN:
- case SPRGO:
- logerror("read from write only register %x\n", offset);
- value = 0;
- break;
- default:
- value = m_suzy.data[offset];
- }
- //logerror("suzy read %.2x %.2x\n",offset,value);
- return value;
-}
-
-WRITE8_MEMBER(lynx_state::suzy_write)
-{
- m_suzy.data[offset] = data;
- //logerror("suzy write %.2x %.2x\n",offset,data);
- /* Additional effects of a write */
- /* Even addresses are the LSB. Any CPU write to an LSB in 0x00-0x7f will set the MSB to 0. */
- /* This in particular holds for math quantities: Writing to B (0x54), D (0x52),
- F (0x62), H (0x60), K (0x6e) or M (0x6c) will force a '0' to be written to A (0x55),
- C (0x53), E (0x63), G (0x61), J (0x6f) or L (0x6d) respectively */
- if ((offset < 0x80) && !(offset & 0x01))
- m_suzy.data[offset + 1] = 0;
-
- switch(offset)
- {
- //case TMPADRL:
- //case TMPADRH:
- case TILTACUML:
- m_blitter.tilt_accumulator = data; // upper byte forced to zero see above.
- break;
- case TILTACUMH:
- m_blitter.tilt_accumulator &= 0xff;
- m_blitter.tilt_accumulator |= data<<8;
- break;
- case HOFFL:
- m_blitter.xoff = data;
- break;
- case HOFFH:
- m_blitter.xoff &= 0xff;
- m_blitter.xoff |= data<<8;
- break;
- case VOFFL:
- m_blitter.yoff = data;
- break;
- case VOFFH:
- m_blitter.yoff &= 0xff;
- m_blitter.yoff |= data<<8;
- break;
- case VIDBASL:
- m_blitter.screen = data;
- break;
- case VIDBASH:
- m_blitter.screen &= 0xff;
- m_blitter.screen |= data<<8;
- break;
- case COLLBASL:
- m_blitter.colbuf = data;
- break;
- case COLLBASH:
- m_blitter.colbuf &= 0xff;
- m_blitter.colbuf |= data<<8;
- break;
- case SCBNEXTL:
- m_blitter.scb_next = data;
- break;
- case SCBNEXTH:
- m_blitter.scb_next &= 0xff;
- m_blitter.scb_next |= data<<8;
- break;
- case SPRDLINEL:
- m_blitter.bitmap = data;
- break;
- case SPRDLINEH:
- m_blitter.bitmap &= 0xff;
- m_blitter.bitmap |= data<<8;
- break;
- case HPOSSTRTL:
- m_blitter.x_pos = data;
- case HPOSSTRTH:
- m_blitter.x_pos &= 0xff;
- m_blitter.x_pos |= data<<8;
- case VPOSSTRTL:
- m_blitter.y_pos = data;
- case VPOSSTRTH:
- m_blitter.y_pos &= 0xff;
- m_blitter.y_pos |= data<<8;
- case SPRHSIZL:
- m_blitter.width = data;
- break;
- case SPRHSIZH:
- m_blitter.width &= 0xff;
- m_blitter.width |= data<<8;
- break;
- case SPRVSIZL:
- m_blitter.height = data;
- break;
- case SPRVSIZH:
- m_blitter.height &= 0xff;
- m_blitter.height |= data<<8;
- break;
- case STRETCHL:
- m_blitter.stretch = data;
- break;
- case STRETCHH:
- m_blitter.stretch &= 0xff;
- m_blitter.stretch |= data<<8;
- break;
- case TILTL:
- m_blitter.tilt = data;
- break;
- case TILTH:
- m_blitter.tilt &= 0xff;
- m_blitter.tilt |= data<<8;
- break;
- // case SPRDOFFL:
- // case SPRVPOSL:
- // case COLLOFFL:
- case VSIZACUML:
- m_blitter.height_accumulator = data;
- break;
- case VSIZACUMH:
- m_blitter.height_accumulator &= 0xff;
- m_blitter.height_accumulator |= data<<8;
- break;
- case HSIZOFFL:
- m_blitter.width_offset = data;
- break;
- case HSIZOFFH:
- m_blitter.width_offset &= 0xff;
- m_blitter.width_offset |= data<<8;
- break;
- case VSIZOFFL:
- m_blitter.height_offset = data;
- break;
- case VSIZOFFH:
- m_blitter.height_offset &= 0xff;
- m_blitter.height_offset |= data<<8;
- break;
- case SCBADRL:
- m_blitter.scb = data;
- break;
- case SCBADRH:
- m_blitter.scb &= 0xff;
- m_blitter.scb |= data<<8;
- break;
- //case PROCADRL:
-
- /* Writing to M (0x6c) will also clear the accumulator overflow bit */
- case MATH_M:
- m_suzy.accumulate_overflow = FALSE;
- break;
- case MATH_C:
- /* If we are going to perform a signed multiplication, we store the sign and convert the number
- to an unsigned one */
- if (m_suzy.signed_math)
- {
- UINT16 factor, temp;
- factor = m_suzy.data[MATH_D] | (m_suzy.data[MATH_C] << 8);
- if ((factor - 1) & 0x8000) /* here we use -1 to cover the math bugs on the sign of 0 and 0x8000 */
- {
- temp = (factor ^ 0xffff) + 1;
- m_sign_CD = - 1;
- m_suzy.data[MATH_D] = temp & 0xff;
- m_suzy.data[MATH_C] = temp >> 8;
- }
- else
- m_sign_CD = 1;
- }
- break;
- case MATH_D:
- /* Documentation states that writing to the MATH_D will set MATH_C to zero but not update the sign flag.
- Implementing the sign detection as described in the documentation causes Stun Runners to not work.
- Either the sign error in the docs is not as described or writing to the lower byte does update the sign flag.
- Here I assume the sign flag gets updated. */
- if (data)
- m_sign_CD = 1;
- break;
- /* Writing to A will start a 16 bit multiply */
- /* If we are going to perform a signed multiplication, we also store the sign and convert the
- number to an unsigned one */
- case MATH_A:
- if (m_suzy.signed_math)
- {
- UINT16 factor, temp;
- factor = m_suzy.data[MATH_B] | (m_suzy.data[MATH_A] << 8);
- if ((factor - 1) & 0x8000) /* here we use -1 to cover the math bugs on the sign of 0 and 0x8000 */
- {
- temp = (factor ^ 0xffff) + 1;
- m_sign_AB = - 1;
- m_suzy.data[MATH_B] = temp & 0xff;
- m_suzy.data[MATH_A] = temp >> 8;
- }
- else
- m_sign_AB = 1;
- }
- lynx_multiply();
- break;
- /* Writing to E will start a 16 bit divide */
- case MATH_E:
- lynx_divide();
- break;
- case SPRCTL0:
- m_blitter.spr_ctl0 = data;
- break;
- case SPRCTL1:
- m_blitter.spr_ctl1 = data;
- break;
- case SPRCOLL:
- m_blitter.spr_coll = data;
- break;
- case SUZYBUSEN:
- logerror("write to SUSYBUSEN %x \n", data);
- break;
- case SPRSYS:
- m_suzy.signed_math = (data & 0x80) ? 1:0;
- m_suzy.accumulate = (data & 0x40) ? 1:0;
- m_blitter.no_collide = (data & 0x20) ? 1:0;
- m_blitter.vstretch = (data & 0x10) ? 1:0;
- m_blitter.lefthanded = (data & 0x08) ? 1:0;
- // unsafe access clear and sprite engine stop request are not enabled
- if (data & 0x02) logerror("sprite engine stop request\n");
- break;
- case SPRGO:
- if ((data & 0x01) && m_suzy.data[SUZYBUSEN])
- {
- //m_blitter.time = machine().time();
- lynx_blitter();
- }
- break;
- case JOYSTICK:
- case SWITCHES:
- logerror("warning: write to read-only button registers\n");
- break;
- }
-}
-
-
-/****************************************
-
- Mikey emulation
-
-****************************************/
-
-/*
- 0xfd0a r sync signal?
- 0xfd81 r interrupt source bit 2 vertical refresh
- 0xfd80 w interrupt quit
- 0xfd87 w bit 1 !clr bit 0 blocknumber clk
- 0xfd8b w bit 1 blocknumber hi B
- 0xfd94 w 0
- 0xfd95 w 4
- 0xfda0-f rw farben 0..15
- 0xfdb0-f rw bit0..3 farben 0..15
-*/
-
-
-/*
-DISPCTL EQU $FD92 ; set to $D by INITMIKEY
-
-; B7..B4 0
-; B3 1 EQU color
-; B2 1 EQU 4 bit mode
-; B1 1 EQU flip screen
-; B0 1 EQU video DMA enabled
-*/
-
-void lynx_state::lynx_draw_line()
-{
- int x, y;
- UINT16 j; // clipping needed!
- UINT8 byte;
- UINT16 *line;
-
-
- // calculate y: first three lines are vblank,
- y = 101-m_timer[2].counter;
- // Documentation states lower two bits of buffer address are ignored (thus 0xfffc mask)
- j = (m_mikey.disp_addr & 0xfffc) + y * 160 / 2;
-
- if (m_mikey.data[0x92] & 0x02)
- {
- j -= 160 * 102 / 2 - 1;
- line = &m_bitmap_temp.pix16(102 - 1 - y);
- for (x = 160 - 2; x >= 0; j++, x -= 2)
- {
- byte = lynx_read_ram(j);
- line[x + 1] = m_lynx_palette[(byte >> 4) & 0x0f];
- line[x + 0] = m_lynx_palette[(byte >> 0) & 0x0f];
- }
- }
- else
- {
- line = &m_bitmap_temp.pix16(y);
- for (x = 0; x < 160; j++, x += 2)
- {
- byte = lynx_read_ram(j);
- line[x + 0] = m_lynx_palette[(byte >> 4) & 0x0f];
- line[x + 1] = m_lynx_palette[(byte >> 0) & 0x0f];
- }
- }
-}
-
-/****************************************
-
- Timers
-
-****************************************/
-
-/*
-HCOUNTER EQU TIMER0
-VCOUNTER EQU TIMER2
-SERIALRATE EQU TIMER4
-
-TIM_BAKUP EQU 0 ; backup-value (count+1)
-TIM_CNTRL1 EQU 1 ; timer-control register
-TIM_CNT EQU 2 ; current counter
-TIM_CNTRL2 EQU 3 ; dynamic control
-
-; TIM_CNTRL1
-TIM_IRQ EQU %10000000 ; enable interrupt (not TIMER4 !)
-TIM_RESETDONE EQU %01000000 ; reset timer done
-TIM_MAGMODE EQU %00100000 ; nonsense in Lynx !!
-TIM_RELOAD EQU %00010000 ; enable reload
-TIM_COUNT EQU %00001000 ; enable counter
-TIM_LINK EQU %00000111
-; link timers (0->2->4 / 1->3->5->7->Aud0->Aud1->Aud2->Aud3->1
-TIM_64us EQU %00000110
-TIM_32us EQU %00000101
-TIM_16us EQU %00000100
-TIM_8us EQU %00000011
-TIM_4us EQU %00000010
-TIM_2us EQU %00000001
-TIM_1us EQU %00000000
-
-;TIM_CNTRL2 (read-only)
-; B7..B4 unused
-TIM_DONE EQU %00001000 ; set if timer's done; reset with TIM_RESETDONE
-TIM_LAST EQU %00000100 ; last clock (??)
-TIM_BORROWIN EQU %00000010
-TIM_BORROWOUT EQU %00000001
-*/
-
-#define NR_LYNX_TIMERS 8
-
-
-
-
-void lynx_state::lynx_timer_init(int which)
-{
- memset(&m_timer[which], 0, sizeof(LYNX_TIMER));
- m_timer[which].timer = timer_alloc(TIMER_SHOT);
-
- save_item(NAME(m_timer[which].bakup), which);
- save_item(NAME(m_timer[which].cntrl1), which);
- save_item(NAME(m_timer[which].cntrl2), which);
- save_item(NAME(m_timer[which].counter), which);
- save_item(NAME(m_timer[which].timer_active), which);
-}
-
-void lynx_state::lynx_timer_signal_irq(int which)
-{
- if ((m_timer[which].cntrl1 & 0x80) && (which != 4)) // if interrupts are enabled and timer != 4
- {
- m_mikey.data[0x81] |= (1 << which); // set interupt poll register
- m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
- m_maincpu->set_input_line(M65SC02_IRQ_LINE, ASSERT_LINE);
- }
- switch (which) // count down linked timers
- {
- case 0:
- switch (m_timer[2].counter)
- {
- case 104:
- break;
- case 103:
- m_mikey.vb_rest = 1;
- break;
- case 102:
- m_mikey.disp_addr = m_mikey.data[0x94] | (m_mikey.data[0x95] << 8);
- break;
- case 101:
- m_mikey.vb_rest = 0;
- lynx_draw_line();
- break;
- default:
- lynx_draw_line();
- }
- lynx_timer_count_down(2);
- break;
- case 2:
- copybitmap(m_bitmap, m_bitmap_temp, 0, 0, 0, 0, machine().first_screen()->cliprect());
- lynx_timer_count_down(4);
- break;
- case 1:
- lynx_timer_count_down(3);
- break;
- case 3:
- lynx_timer_count_down(5);
- break;
- case 5:
- lynx_timer_count_down(7);
- break;
- case 7:
- m_sound->count_down(0);
- break;
- }
-}
-
-void lynx_state::lynx_timer_count_down(int which)
-{
- if ((m_timer[which].cntrl1 & 0x0f) == 0x0f) // count and linking enabled
- {
- if (m_timer[which].counter > 0)
- {
- m_timer[which].counter--;
- //m_timer[which].borrow_in = 1;
- return;
- }
- if (m_timer[which].counter == 0)
- {
- if (m_timer[which].cntrl2 & 0x01) // borrow out
- {
- lynx_timer_signal_irq(which);
- if (m_timer[which].cntrl1 & 0x10) // if reload enabled
- {
- m_timer[which].counter = m_timer[which].bakup;
- }
- else
- {
- m_timer[which].cntrl2 |= 8; // set timer done
- }
- m_timer[which].cntrl2 &= ~0x01; // clear borrow out
- }
- else
- m_timer[which].cntrl2 |= 0x01; // set borrow out
- return;
- }
- }
- else
- {
- //m_timer[which].borrow_in = 0;
- m_timer[which].cntrl2 &= ~0x01;
- }
-}
-
-UINT32 lynx_state::lynx_time_factor(int val)
-{
- switch(val)
- {
- case 0: return 1000000;
- case 1: return 500000;
- case 2: return 250000;
- case 3: return 125000;
- case 4: return 62500;
- case 5: return 31250;
- case 6: return 15625;
- default: fatalerror("invalid value\n");
- }
-}
-
-TIMER_CALLBACK_MEMBER(lynx_state::lynx_timer_shot)
-{
- lynx_timer_signal_irq(param);
- if (!(m_timer[param].cntrl1 & 0x10)) // if reload not enabled
- {
- m_timer[param].timer_active = 0;
- m_timer[param].cntrl2 |= 8; // set timer done
- }
- else
- {
- attotime t = (attotime::from_hz(lynx_time_factor(m_timer[param].cntrl1 & 0x07)) * (m_timer[param].bakup + 1));
- m_timer[param].timer->adjust(t, param);
- }
-}
-
-UINT8 lynx_state::lynx_timer_read(int which, int offset)
-{
- UINT8 value = 0;
-
- switch (offset)
- {
- case 0:
- value = m_timer[which].bakup;
- break;
- case 1:
- value = m_timer[which].cntrl1;
- break;
- case 2:
- if ((m_timer[which].cntrl1 & 0x07) == 0x07) // linked timer
- {
- value = m_timer[which].counter;
- }
- else
- {
- if ( m_timer[which].timer_active )
- {
- value = (UINT8) (m_timer[which].timer->remaining().as_ticks(1000000>>(m_timer[which].cntrl1 & 0x07)));
- value -= value ? 1 : 0;
- }
- }
- break;
-
- case 3:
- value = m_timer[which].cntrl2;
- break;
- }
- // logerror("timer %d read %x %.2x\n", which, offset, value);
- return value;
-}
-
-void lynx_state::lynx_timer_write(int which, int offset, UINT8 data)
-{
- //logerror("timer %d write %x %.2x\n", which, offset, data);
- attotime t;
-
- if ( m_timer[which].timer_active && ((m_timer[which].cntrl1 & 0x07) != 0x07))
- {
- m_timer[which].counter = (UINT8) (m_timer[which].timer->remaining().as_ticks(1000000>>(m_timer[which].cntrl1 & 0x07)));
- m_timer[which].counter -= (m_timer[which].counter) ? 1 : 0;
- }
-
- switch (offset)
- {
- case 0:
- m_timer[which].bakup = data;
- break;
- case 1:
- m_timer[which].cntrl1 = data;
- if (data & 0x40) // reset timer done
- m_timer[which].cntrl2 &= ~0x08;
- break;
- case 2:
- m_timer[which].counter = data;
- break;
- case 3:
- m_timer[which].cntrl2 = (m_timer[which].cntrl2 & ~0x08) | (data & 0x08);
- break;
- }
-
- /* Update timers */
- //if ( offset < 3 )
- //{
- m_timer[which].timer->reset();
- m_timer[which].timer_active = 0;
- if ((m_timer[which].cntrl1 & 0x08) && !(m_timer[which].cntrl2 & 0x08)) // if enable count
- {
- if ((m_timer[which].cntrl1 & 0x07) != 0x07) // if not set to link mode
- {
- t = (attotime::from_hz(lynx_time_factor(m_timer[which].cntrl1 & 0x07)) * (m_timer[which].counter + 1));
- m_timer[which].timer->adjust(t, which);
- m_timer[which].timer_active = 1;
- }
- }
- //}
-}
-
-
-/****************************************
-
- UART Emulation
-
-****************************************/
-
-
-void lynx_state::lynx_uart_reset()
-{
- memset(&m_uart, 0, sizeof(m_uart));
-}
-
-TIMER_CALLBACK_MEMBER(lynx_state::lynx_uart_loopback_timer)
-{
- m_uart.received = FALSE;
-}
-
-TIMER_CALLBACK_MEMBER(lynx_state::lynx_uart_timer)
-{
- if (m_uart.buffer_loaded)
- {
- m_uart.data_to_send = m_uart.buffer;
- m_uart.buffer_loaded = FALSE;
- timer_set(attotime::from_usec(11*16), TIMER_UART);
- }
- else
- {
- m_uart.sending = FALSE;
- m_uart.received = TRUE;
- m_uart.data_received = m_uart.data_to_send;
- timer_set(attotime::from_usec(11*16), TIMER_UART_LOOPBACK);
- if (m_uart.serctl & 0x40)
- {
- m_mikey.data[0x81] |= 0x10;
- m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
- m_maincpu->set_input_line(M65SC02_IRQ_LINE, ASSERT_LINE);
- }
- }
-
- if (m_uart.serctl & 0x80)
- {
- m_mikey.data[0x81] |= 0x10;
- m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
- m_maincpu->set_input_line(M65SC02_IRQ_LINE, ASSERT_LINE);
- }
-}
-
-READ8_MEMBER(lynx_state::lynx_uart_r)
-{
- UINT8 value = 0x00;
- switch (offset)
- {
- case 0x8c:
- if (!m_uart.buffer_loaded)
- value |= 0x80;
- if (m_uart.received)
- value |= 0x40;
- if (!m_uart.sending)
- value |= 0x20;
- break;
-
- case 0x8d:
- value = m_uart.data_received;
- break;
- }
- logerror("uart read %.2x %.2x\n", offset, value);
- return value;
-}
-
-WRITE8_MEMBER(lynx_state::lynx_uart_w)
-{
- logerror("uart write %.2x %.2x\n", offset, data);
- switch (offset)
- {
- case 0x8c:
- m_uart.serctl = data;
- break;
-
- case 0x8d:
- if (m_uart.sending)
- {
- m_uart.buffer = data;
- m_uart.buffer_loaded = TRUE;
- }
- else
- {
- m_uart.sending = TRUE;
- m_uart.data_to_send = data;
- // timing not accurate, baude rate should be calculated from timer 4 backup value and clock rate
- timer_set(attotime::from_usec(11*16), TIMER_UART);
- }
- break;
- }
-}
-
-
-/****************************************
-
- Mikey memory handlers
-
-****************************************/
-
-
-READ8_MEMBER(lynx_state::mikey_read)
-{
- UINT8 direction, value = 0x00;
-
- switch (offset)
- {
- case 0x00: case 0x01: case 0x02: case 0x03:
- case 0x04: case 0x05: case 0x06: case 0x07:
- case 0x08: case 0x09: case 0x0a: case 0x0b:
- case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- case 0x10: case 0x11: case 0x12: case 0x13:
- case 0x14: case 0x15: case 0x16: case 0x17:
- case 0x18: case 0x19: case 0x1a: case 0x1b:
- case 0x1c: case 0x1d: case 0x1e: case 0x1f:
- value = lynx_timer_read(offset >> 2, offset & 0x03);
- break;
-
- case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
- case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
- case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
- case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
- case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x50:
- value = m_sound->read(space, offset);
- break;
-
- case 0x80:
- case 0x81:
- value = m_mikey.data[0x81]; // both registers access the same interupt status byte
- // logerror( "mikey read %.2x %.2x\n", offset, value );
- break;
-
- case 0x84:
- case 0x85:
- value = 0x00;
- break;
-
- case 0x86:
- value = 0x80;
- break;
-
- case 0x88:
- value = 0x01;
- break;
-
- case 0x8b:
- direction = m_mikey.data[0x8a];
- value |= (direction & 0x01) ? (m_mikey.data[offset] & 0x01) : 0x01; // External Power input
- value |= (direction & 0x02) ? (m_mikey.data[offset] & 0x02) : 0x00; // Cart Address Data output (0 turns cart power on)
- value |= (direction & 0x04) ? (m_mikey.data[offset] & 0x04) : 0x04; // noexp input
- // REST read returns actual rest state anded with rest output bit
- value |= (direction & 0x08) ? (((m_mikey.data[offset] & 0x08) && (m_mikey.vb_rest)) ? 0x00 : 0x08) : 0x00; // rest output
- value |= (direction & 0x10) ? (m_mikey.data[offset] & 0x10) : 0x10; // audin input
- /* Hack: we disable COMLynx */
- value |= 0x04;
- /* B5, B6 & B7 are not used */
- break;
-
- case 0x8c:
- case 0x8d:
- value = lynx_uart_r(space, offset, mem_mask);
- break;
-
- default:
- value = m_mikey.data[offset];
- //logerror( "mikey read %.2x %.2x\n", offset, value );
- }
- return value;
-}
-
-WRITE8_MEMBER(lynx_state::mikey_write)
-{
- switch (offset)
- {
- case 0x00: case 0x01: case 0x02: case 0x03:
- case 0x04: case 0x05: case 0x06: case 0x07:
- case 0x08: case 0x09: case 0x0a: case 0x0b:
- case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- case 0x10: case 0x11: case 0x12: case 0x13:
- case 0x14: case 0x15: case 0x16: case 0x17:
- case 0x18: case 0x19: case 0x1a: case 0x1b:
- case 0x1c: case 0x1d: case 0x1e: case 0x1f:
- lynx_timer_write(offset >> 2, offset & 3, data);
- return;
-
- case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
- case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
- case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
- case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
- case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x50:
- m_sound->write(space, offset, data);
- return;
-
- case 0x80:
- m_mikey.data[0x81] &= ~data; // clear interrupt source
- // logerror("mikey write %.2x %.2x\n", offset, data);
- if (!m_mikey.data[0x81])
- m_maincpu->set_input_line(M65SC02_IRQ_LINE, CLEAR_LINE);
- break;
-
- /* Is this correct? */ // Notes say writing to register will result in interupt being triggered.
- case 0x81:
- m_mikey.data[0x81] |= data;
- if (data)
- {
- m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
- m_maincpu->set_input_line(M65SC02_IRQ_LINE, ASSERT_LINE);
- logerror("direct write to interupt register\n");
- }
- break;
-
- case 0x87:
- m_mikey.data[offset] = data;
- if (data & 0x02) // Power (1 = on)
- {
- if (data & 0x01) // Cart Address Strobe
- {
- m_suzy.high <<= 1;
- if (m_mikey.data[0x8b] & 0x02)
- m_suzy.high |= 1;
- m_suzy.high &= 0xff;
- m_suzy.low = 0;
- }
- }
- else
- {
- m_suzy.high = 0;
- m_suzy.low = 0;
- }
- break;
-
- case 0x8c: case 0x8d:
- lynx_uart_w(space, offset, data);
- break;
-
- case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
- case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
- case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
- case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
- m_mikey.data[offset] = data;
-
- /* RED = 0xb- & 0x0f, GREEN = 0xa- & 0x0f, BLUE = (0xb- & 0xf0) >> 4 */
- m_lynx_palette[offset & 0x0f] = m_palette->pen(
- ((m_mikey.data[0xb0 + (offset & 0x0f)] & 0x0f)) |
- ((m_mikey.data[0xa0 + (offset & 0x0f)] & 0x0f) << 4) |
- ((m_mikey.data[0xb0 + (offset & 0x0f)] & 0xf0) << 4));
- break;
-
- /* TODO: properly implement these writes */
- case 0x8b:
- m_mikey.data[offset] = data;
- if (m_mikey.data[0x8a] & 0x10)
- logerror("Trying to enable bank 1 write. %d\n", m_mikey.data[offset] & 0x10);
- break;
-
- //case 0x90: // SDONEACK - Suzy Done Acknowledge
- case 0x91: // CPUSLEEP - CPU Bus Request Disable
- m_mikey.data[offset] = data;
- if (!data && m_blitter.busy)
- {
- m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
- /* A write of '0' to this address will reset the CPU bus request flip flop */
- }
- break;
- case 0x94: case 0x95:
- m_mikey.data[offset]=data;
- break;
- case 0x9c: case 0x9d: case 0x9e:
- m_mikey.data[offset]=data;
- logerror("Mtest%d write: %x\n", offset&0x3, data);
- break;
-
- default:
- m_mikey.data[offset]=data;
- //logerror("mikey write %.2x %.2x\n",offset,data);
- break;
- }
-}
-
-/****************************************
-
- Init / Config
-
-****************************************/
-
-READ8_MEMBER(lynx_state::lynx_memory_config_r)
-{
- return m_memory_config;
-}
-
-WRITE8_MEMBER(lynx_state::lynx_memory_config_w)
-{
- /* bit 7: hispeed, uses page mode accesses (4 instead of 5 cycles )
- * when these are safe in the cpu */
- m_memory_config = data;
-
- if (data & 1)
- {
- space.install_readwrite_bank(0xfc00, 0xfcff, "bank1");
- membank("bank1")->set_base(m_mem_fc00);
- }
- else
- space.install_readwrite_handler(0xfc00, 0xfcff, read8_delegate(FUNC(lynx_state::suzy_read),this), write8_delegate(FUNC(lynx_state::suzy_write),this));
-
- if (data & 2)
- {
- space.install_readwrite_bank(0xfd00, 0xfdff, "bank2");
- membank("bank2")->set_base(m_mem_fd00);
- }
- else
- space.install_readwrite_handler(0xfd00, 0xfdff, read8_delegate(FUNC(lynx_state::mikey_read),this), write8_delegate(FUNC(lynx_state::mikey_write),this));
-
- membank("bank3")->set_entry((data & 4) ? 1 : 0);
- membank("bank4")->set_entry((data & 8) ? 1 : 0);
-}
-
-void lynx_state::machine_reset()
-{
- lynx_memory_config_w(m_maincpu->space(AS_PROGRAM), 0, 0);
-
- m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
- m_maincpu->set_input_line(M65SC02_IRQ_LINE, CLEAR_LINE);
-
- memset(&m_suzy, 0, sizeof(m_suzy));
- memset(&m_mikey, 0, sizeof(m_mikey));
-
- m_suzy.data[0x88] = 0x01;
- m_suzy.data[0x90] = 0x00;
- m_suzy.data[0x91] = 0x00;
- m_mikey.data[0x80] = 0x00;
- m_mikey.data[0x81] = 0x00;
- m_mikey.data[0x88] = 0x01;
- m_mikey.data[0x8a] = 0x00;
- m_mikey.data[0x8c] = 0x00;
- m_mikey.data[0x90] = 0x00;
- m_mikey.data[0x92] = 0x00;
-
- lynx_uart_reset();
-
- // hack to allow current object loading to work
-#if 0
- lynx_timer_write( this, 0, 0, 160 ); // set backup value (hpos) = 160
- lynx_timer_write( this, 0, 1, 0x10 | 0x8 | 0 ); // enable count, enable reload, 1us period
- lynx_timer_write( this, 2, 0, 105 ); // set backup value (vpos) = 102
- lynx_timer_write( this, 2, 1, 0x10 | 0x8 | 7 ); // enable count, enable reload, link
-#endif
-
- render_target *target = machine().render().first_target();
- target->set_view(m_rotate);
-}
-
-void lynx_state::lynx_postload()
-{
- lynx_memory_config_w(m_maincpu->space(AS_PROGRAM), 0, m_memory_config);
-}
-
-void lynx_state::machine_start()
-{
- m_bitmap_temp.allocate(160,102,0,0);
-
- // save driver variables
- save_item(NAME(m_memory_config));
- save_item(NAME(m_sign_AB));
- save_item(NAME(m_sign_CD));
- save_item(NAME(m_lynx_palette));
- save_item(NAME(m_rotate));
- // save blitter variables
- save_item(NAME(m_blitter.screen));
- save_item(NAME(m_blitter.colbuf));
- save_item(NAME(m_blitter.colpos));
- save_item(NAME(m_blitter.xoff));
- save_item(NAME(m_blitter.yoff));
- save_item(NAME(m_blitter.mode));
- save_item(NAME(m_blitter.spr_coll));
- save_item(NAME(m_blitter.spritenr));
- save_item(NAME(m_blitter.x_pos));
- save_item(NAME(m_blitter.y_pos));
- save_item(NAME(m_blitter.width));
- save_item(NAME(m_blitter.height));
- save_item(NAME(m_blitter.tilt_accumulator));
- save_item(NAME(m_blitter.width_accumulator));
- save_item(NAME(m_blitter.height_accumulator));
- save_item(NAME(m_blitter.width_offset));
- save_item(NAME(m_blitter.height_offset));
- save_item(NAME(m_blitter.stretch));
- save_item(NAME(m_blitter.tilt));
- save_item(NAME(m_blitter.color));
- save_item(NAME(m_blitter.bitmap));
- save_item(NAME(m_blitter.use_rle));
- save_item(NAME(m_blitter.line_color));
- save_item(NAME(m_blitter.spr_ctl0));
- save_item(NAME(m_blitter.spr_ctl1));
- save_item(NAME(m_blitter.scb));
- save_item(NAME(m_blitter.scb_next));
- save_item(NAME(m_blitter.sprite_collide));
- save_item(NAME(m_blitter.everon));
- save_item(NAME(m_blitter.fred));
- save_item(NAME(m_blitter.memory_accesses));
- save_item(NAME(m_blitter.no_collide));
- save_item(NAME(m_blitter.vstretch));
- save_item(NAME(m_blitter.lefthanded));
- save_item(NAME(m_blitter.busy));
- // save suzy variables
- save_item(NAME(m_suzy.data));
- save_item(NAME(m_suzy.high));
- save_item(NAME(m_suzy.low));
- save_item(NAME(m_suzy.signed_math));
- save_item(NAME(m_suzy.accumulate));
- save_item(NAME(m_suzy.accumulate_overflow));
- // save mikey variables
- save_item(NAME(m_mikey.data));
- save_item(NAME(m_mikey.disp_addr));
- save_item(NAME(m_mikey.vb_rest));
- // save uart variables
- save_item(NAME(m_uart.serctl));
- save_item(NAME(m_uart.data_received));
- save_item(NAME(m_uart.data_to_send));
- save_item(NAME(m_uart.buffer));
- save_item(NAME(m_uart.received));
- save_item(NAME(m_uart.sending));
- save_item(NAME(m_uart.buffer_loaded));
-
- machine().save().register_postload(save_prepost_delegate(FUNC(lynx_state::lynx_postload), this));
-
- membank("bank3")->configure_entry(0, memregion("maincpu")->base() + 0x0000);
- membank("bank3")->configure_entry(1, m_mem_fe00);
- membank("bank4")->configure_entry(0, memregion("maincpu")->base() + 0x01fa);
- membank("bank4")->configure_entry(1, m_mem_fffa);
-
- for (int i = 0; i < NR_LYNX_TIMERS; i++)
- lynx_timer_init(i);
-}
-
-
-/****************************************
-
- Image handling
-
-****************************************/
-
-int lynx_state::lynx_verify_cart (char *header, int kind)
-{
- if (kind)
- {
- if (strncmp("BS93", &header[6], 4))
- {
- logerror("This is not a valid Lynx image\n");
- return IMAGE_VERIFY_FAIL;
- }
- }
- else
- {
- if (strncmp("LYNX", &header[0], 4))
- {
- if (!strncmp("BS93", &header[6], 4))
- {
- logerror("This image is probably a Quickload image with .lnx extension\n");
- logerror("Try to load it with -quickload\n");
- }
- else
- logerror("This is not a valid Lynx image\n");
- return IMAGE_VERIFY_FAIL;
- }
- }
-
- return IMAGE_VERIFY_PASS;
-}
-
-DEVICE_IMAGE_LOAD_MEMBER( lynx_state, lynx_cart )
-{
- /* Lynx carts have 19 address lines, the upper 8 used for bank select. The lower
- 11 bits are used to address data within the selected bank. Valid bank sizes are 256,
- 512, 1024 or 2048 bytes. Commercial roms use all 256 banks.*/
- UINT32 size = m_cart->common_get_size("rom");
- UINT16 gran = 0;
-
- if (image.software_entry() == NULL)
- {
- // check for lnx header
- const char *filetype = image.filetype();
- if (!core_stricmp(filetype, "lnx"))
- {
- // 64 byte header
- // LYNX
- // intelword lower counter size
- // 0 0 1 0
- // 32 chars name
- // 22 chars manufacturer
- UINT8 header[0x40];
- image.fread(header, 0x40);
-
- // Check the image
- if (lynx_verify_cart((char*)header, LYNX_CART) == IMAGE_VERIFY_FAIL)
- return IMAGE_INIT_FAIL;
-
- /* 2008-10 FP: According to Handy source these should be page_size_bank0. Are we using
- it correctly in MESS? Moreover, the next two values should be page_size_bank1. We should
- implement this as well */
- gran = header[4] | (header[5] << 8);
-
- logerror ("%s %dkb cartridge with %dbyte granularity from %s\n", header + 10, size / 1024, gran, header + 42);
- size -= 0x40;
- }
- }
-
- m_cart->rom_alloc(size, GENERIC_ROM8_WIDTH, ENDIANNESS_LITTLE);
- m_cart->common_load_rom(m_cart->get_rom_base(), size, "rom");
-
- // set-up granularity
- if (image.software_entry() == NULL)
- {
- const char *filetype = image.filetype();
- if (!core_stricmp(filetype, "lnx")) // from header
- m_granularity = gran;
- else if (!core_stricmp(filetype, "lyx"))
- {
- /* 2008-10 FP: FIXME: .lyx file don't have an header, hence they miss "lynx_granularity"
- (see above). What if bank 0 has to be loaded elsewhere? And what about bank 1?
- These should work with most .lyx files, but we need additional info on raw cart images */
- if (size == 0x20000)
- m_granularity = 0x0200;
- else if (size == 0x80000)
- m_granularity = 0x0800;
- else
- m_granularity = 0x0400;
- }
- }
- else
- {
- if (size > 0xffff) // 64,128,256,512k cartridges
- m_granularity = size >> 8;
- else
- m_granularity = 0x400; // Homebrew roms not using all 256 banks (T-Tris) (none currently in softlist)
- }
-
- // set-up rotation from softlist
- if (image.software_entry() != NULL)
- {
- const char *rotate = image.get_feature("rotation");
- m_rotate = 0;
- if (rotate)
- {
- if (!core_stricmp(rotate, "RIGHT"))
- m_rotate = 1;
- else if (!core_stricmp(rotate, "LEFT"))
- m_rotate = 2;
- }
-
- }
-
- return IMAGE_INIT_PASS;
-}