src/mess/machine/3do.c
| r854 | r855 | |
| 2 | 2 | #include "driver.h" |
| 3 | 3 | #include "includes/3do.h" |
| 4 | 4 | |
| 5 | | /* |
| 6 | | registers to be located: |
| 7 | | - SCOBCTL0 - Spryte engine control word |
| 8 | | - REGCTL0 - Modulo for reading source frame buffer data and writing spryte image data |
| 9 | | bit0 G1 = 32 for CFBD read buffer |
| 10 | | bit1 Undefined, set to 0. |
| 11 | | bit2 G1 = 256 for CFBD read buffer |
| 12 | | bit3 G1 = 1024 for CFBD read buffer |
| 13 | | bit4 G2 = 64 for CFBD read buffer |
| 14 | | bit5 G2 = 128 for CFBD read buffer |
| 15 | | bit6 G2 = 256 for CFBD read buffer |
| 16 | | bit7 Undefined, set to 0. |
| 17 | | bit8 G1 = 32 for destination buffer |
| 18 | | bit9 Undefined, set to 0. |
| 19 | | bit10 G1 = 256 for destination buffer |
| 20 | | bit11 G1 = 1024 for destination buffer |
| 21 | | bit12 G2 = 64 for destination buffer |
| 22 | | bit13 G2 = 128 for destination buffer |
| 23 | | bit14 G2 = 256 for destination buffer |
| 24 | | bit15 Undefined, set to 0 |
| 25 | | - REGCTL1 - X and Y clip values |
| 26 | | bit26-16 - max Y |
| 27 | | bit10-0 - max x |
| 28 | | - REGCTL2 - Read base address. Address of the upper left corner pixel of the source frame buffer. |
| 29 | | - REGCTL3 - Write base address. Address of the upper left corner pixel of the destination buffer. |
| 30 | | - XYPOSH |
| 31 | | - XYPOSL |
| 32 | | - DXYH |
| 33 | | - DXYL |
| 34 | | - DDXYH |
| 35 | | - DDXYL |
| 36 | | - PPMPC |
| 37 | | - pixel count register |
| 38 | | |
| 39 | | Spryte engine uses 8 DMA registers: |
| 40 | | - 0 = current scob address |
| 41 | | - 1 = next scob address |
| 42 | | - 2 = pip address |
| 43 | | - 3 = spryte base address |
| 44 | | - 4 = engine a fetch address |
| 45 | | - 5 = engine a length |
| 46 | | - 6 = engine b fetch address |
| 47 | | - 7 = engine b length |
| 48 | | |
| 49 | | Sprite engine registers: |
| 50 | | - SPRSTRT - Start spryte engine (sets Spryte-ON flipflop) |
| 51 | | - SPRSTOP - Stop spryte engine, everything gets reset. |
| 52 | | - SPRPAUS - Pause spryte engine when it's done with the current spryte (sets pause flipflop). |
| 53 | | - SPRCNTU - Continue after pause of spryte engine. |
| 54 | | When interrupt is present, pause flipflop is set |
| 55 | | */ |
| 56 | | |
| 57 | 5 | typedef struct { |
| 58 | 6 | UINT32 revision; |
| 59 | 7 | UINT32 memory_configuration; |
| r854 | r855 | |
| 63 | 11 | UINT32 dummy; |
| 64 | 12 | } CLIO; |
| 65 | 13 | |
| 66 | | static UINT32 unk_318_data_0 = 0; |
| 14 | //static UINT32 unk_318_data_0 = 0; |
| 67 | 15 | static MADAM madam; |
| 68 | 16 | static CLIO clio; |
| 69 | 17 | |
| r854 | r855 | |
| 122 | 70 | */ |
| 123 | 71 | READ32_HANDLER( unk_318_r ) { |
| 124 | 72 | logerror( "%08X: UNK_318 read offset = %08X\n", activecpu_get_pc(), offset ); |
| 73 | #if 0 |
| 125 | 74 | switch( offset ) { |
| 126 | 75 | case 0: /* Boot ROM checks here and expects to read 1, 0, 1, 0 in the lowest bit */ |
| 127 | 76 | unk_318_data_0 ^= 1; |
| 128 | 77 | return unk_318_data_0; |
| 129 | 78 | } |
| 79 | #endif |
| 130 | 80 | return 0; |
| 131 | 81 | } |
| 132 | 82 | |
| 133 | | WRITE32_HANDLER( unk_318_w ) { |
| 83 | WRITE32_HANDLER( unk_318_w ) |
| 84 | { |
| 134 | 85 | logerror( "%08X: UNK_318 write offset = %08X, data = %08X, mask = %08X\n", activecpu_get_pc(), offset, data, mem_mask ); |
| 135 | | switch( offset ) { |
| 136 | | case 0: /* Boot ROM writes 03180000 here and then starts reading some things */ |
| 86 | |
| 87 | switch( offset ) |
| 88 | { |
| 89 | case 0: /* Boot ROM writes 03180000 here and then starts reading some things */ |
| 90 | { |
| 91 | /* disable ROM overlay */ |
| 92 | memory_set_bank(1, 0); |
| 93 | } |
| 137 | 94 | break; |
| 138 | 95 | } |
| 139 | 96 | } |
| 140 | 97 | |
| 141 | 98 | |
| 142 | | /* |
| 143 | | I think this is the spryte engine - WP |
| 144 | | */ |
| 99 | |
| 145 | 100 | READ32_HANDLER( vram_sport_r ) { |
| 146 | 101 | logerror( "%08X: VRAM SPORT read offset = %08X\n", activecpu_get_pc(), offset ); |
| 147 | 102 | switch( offset ) { |
| r854 | r855 | |
| 189 | 144 | } |
| 190 | 145 | } |
| 191 | 146 | |
| 192 | | void madam_init( void ) { |
| 147 | void madam_init( void ) |
| 148 | { |
| 193 | 149 | memset( &madam, 0, sizeof(MADAM) ); |
| 194 | 150 | madam.revision = 0x00000001; |
| 195 | 151 | } |
| 196 | 152 | |
| 197 | 153 | |
| 198 | | READ32_HANDLER( clio_r ) { |
| 154 | READ32_HANDLER( clio_r ) |
| 155 | { |
| 199 | 156 | logerror( "%08X: CLIO read offset = %08X\n", activecpu_get_pc(), offset ); |
| 157 | |
| 158 | switch( offset ) |
| 159 | { |
| 160 | case 0x0a: return 0x40; break; |
| 161 | case 0x0d: |
| 162 | { |
| 163 | static UINT32 irq_sequence[3] = { 0, 4, 12 }; |
| 164 | static int counter = 0; |
| 165 | |
| 166 | return irq_sequence[(counter++)%3]; |
| 167 | } |
| 168 | break; |
| 169 | } |
| 200 | 170 | return 0; |
| 201 | 171 | } |
| 202 | 172 | |
| 203 | | WRITE32_HANDLER( clio_w ) { |
| 173 | WRITE32_HANDLER( clio_w ) |
| 174 | { |
| 204 | 175 | logerror( "%08X: CLIO write offset = %08X, data = %08X, mask = %08X\n", activecpu_get_pc(), offset, data, mem_mask ); |
| 205 | | switch( offset ) { |
| 206 | | case 0x0A: /* 03400028 - bits 0,1, and 6 are tested (irq sources?) */ |
| 176 | |
| 177 | switch( offset ) |
| 178 | { |
| 179 | case 0x0A: /* 03400028 - bits 0,1, and 6 are tested (irq sources?) */ |
| 207 | 180 | break; |
| 208 | | case 0x0B: /* 0340002C - ?? during boot 0000000B is written here counter reload related?? */ |
| 181 | |
| 182 | case 0x0B: /* 0340002C - ?? during boot 0000000B is written here counter reload related?? */ |
| 209 | 183 | break; |
| 184 | |
| 185 | case 0x88: /* set timer frequency */ |
| 186 | |
| 187 | break; |
| 210 | 188 | } |
| 211 | 189 | } |
| 212 | 190 | |
| 213 | | void clio_init( void ) { |
| 191 | void clio_init( void ) |
| 192 | { |
| 214 | 193 | memset( &clio, 0, sizeof(CLIO) ); |
| 215 | 194 | } |
| 216 | 195 | |
src/mess/machine/amigacd.c
| r0 | r855 | |
| 1 | /***************************************************************************
|
| 2 | |
| 3 | Amiga cdrom controller emulation
|
| 4 |
|
| 5 | Notes:
|
| 6 | Many thanks to Toni Willem for all the help and information about the
|
| 7 | DMAC controller.
|
| 8 | |
| 9 | ***************************************************************************/
|
| 10 | |
| 11 | #include "mame.h"
|
| 12 | #include "driver.h"
|
| 13 | #include "amiga.h"
|
| 14 | #include "amigacd.h"
|
| 15 | #include "machine/6526cia.h"
|
| 16 | #include "machine/wd33c93.h"
|
| 17 | #include "tpi6525.h"
|
| 18 | #include "matsucd.h"
|
| 19 | |
| 20 | #define VERBOSE_DMAC 0
|
| 21 | |
| 22 | #if VERBOSE_DMAC
|
| 23 | #define LOG logerror
|
| 24 | #else
|
| 25 | INLINE void dummy_log( const char *a, ... ) {}
|
| 26 | #define LOG dummy_log
|
| 27 | #endif
|
| 28 | |
| 29 | /* constants */
|
| 30 | #define CD_SECTOR_TIME (1000/((300*1024)/2048)) /* 2X CDROM sector time in msec (300KBps) */
|
| 31 | |
| 32 | /***************************************************************************
|
| 33 | |
| 34 | DMAC
|
| 35 |
|
| 36 | ***************************************************************************/
|
| 37 | |
| 38 | /*
|
| 39 | * value to go into DAWR
|
| 40 | */
|
| 41 | #define DAWR_ATZSC 3 /* according to A3000T service-manual */
|
| 42 | |
| 43 | /*
|
| 44 | * bits defined for CNTR
|
| 45 | */
|
| 46 | #define CNTR_TCEN (1<<7) /* Terminal Count Enable */
|
| 47 | #define CNTR_PREST (1<<6) /* Perp Reset (not implemented :-((( ) */
|
| 48 | #define CNTR_PDMD (1<<5) /* Perp Device Mode Select (1=SCSI,0=XT/AT) */
|
| 49 | #define CNTR_INTEN (1<<4) /* Interrupt Enable */
|
| 50 | #define CNTR_DDIR (1<<3) /* Device Direction. 1==rd host, wr to perp */
|
| 51 | |
| 52 | /*
|
| 53 | * bits defined for ISTR
|
| 54 | */
|
| 55 | #define ISTR_INTX (1<<8) /* XT/AT Interrupt pending */
|
| 56 | #define ISTR_INT_F (1<<7) /* Interrupt Follow */
|
| 57 | #define ISTR_INTS (1<<6) /* SCSI Peripheral Interrupt */
|
| 58 | #define ISTR_E_INT (1<<5) /* End-Of-Process Interrupt */
|
| 59 | #define ISTR_INT_P (1<<4) /* Interrupt Pending */
|
| 60 | #define ISTR_UE_INT (1<<3) /* Under-Run FIFO Error Interrupt */
|
| 61 | #define ISTR_OE_INT (1<<2) /* Over-Run FIFO Error Interrupt */
|
| 62 | #define ISTR_FF_FLG (1<<1) /* FIFO-Full Flag */
|
| 63 | #define ISTR_FE_FLG (1<<0) /* FIFO-Empty Flag */
|
| 64 | |
| 65 | typedef struct
|
| 66 | {
|
| 67 | UINT16 istr; /* Interrupt Status Register (R) */
|
| 68 | UINT16 cntr; /* Control Register (RW) */
|
| 69 | UINT32 wtc; /* Word Transfer Count Register (RW) */
|
| 70 | UINT32 acr; /* Address Count Register (RW) */
|
| 71 | UINT16 dawr; /* DACK Width Register (W) */
|
| 72 | mame_timer *dma_timer;
|
| 73 | } _dmac_data;
|
| 74 | |
| 75 | static _dmac_data dmac_data;
|
| 76 | |
| 77 | static void check_interrupts( void )
|
| 78 | {
|
| 79 | /* if interrupts are disabled, bail */
|
| 80 | if ( (dmac_data.cntr & CNTR_INTEN) == 0 )
|
| 81 | return;
|
| 82 |
|
| 83 | /* if no interrupts are pending, bail */
|
| 84 | if ( (dmac_data.istr & ISTR_INT_P) == 0 )
|
| 85 | return;
|
| 86 |
|
| 87 | /* otherwise, generate the IRQ */
|
| 88 | amiga_custom_w(REG_INTREQ, 0x8000 | INTENA_PORTS, 0);
|
| 89 | }
|
| 90 | |
| 91 | static TIMER_CALLBACK(dmac_dma_proc)
|
| 92 | {
|
| 93 | while( dmac_data.wtc > 0 )
|
| 94 | {
|
| 95 | UINT16 dat16;
|
| 96 | UINT8 dat8;
|
| 97 | |
| 98 | if ( matsucd_get_next_byte( &dat8 ) < 0 )
|
| 99 | break;
|
| 100 | |
| 101 | dat16 = dat8;
|
| 102 |
|
| 103 | if ( matsucd_get_next_byte( &dat8 ) < 0 )
|
| 104 | break;
|
| 105 | |
| 106 | dat16 <<= 8;
|
| 107 | dat16 |= dat8;
|
| 108 | |
| 109 | amiga_chip_ram_w(dmac_data.acr, dat16);
|
| 110 | |
| 111 | dmac_data.acr += 2;
|
| 112 | dmac_data.wtc--;
|
| 113 | }
|
| 114 |
|
| 115 | if ( dmac_data.wtc > 0 )
|
| 116 | {
|
| 117 | matsucd_read_next_block();
|
| 118 | mame_timer_adjust( dmac_data.dma_timer, MAME_TIME_IN_MSEC( CD_SECTOR_TIME ), 0, time_zero );
|
| 119 | }
|
| 120 | else
|
| 121 | {
|
| 122 | dmac_data.istr |= ISTR_INT_P | ISTR_E_INT;
|
| 123 | check_interrupts();
|
| 124 | }
|
| 125 | }
|
| 126 | |
| 127 | static READ16_HANDLER( amiga_dmac_r )
|
| 128 | {
|
| 129 | offset &= 0xff;
|
| 130 | |
| 131 | switch( offset )
|
| 132 | {
|
| 133 | case 0x20:
|
| 134 | {
|
| 135 | UINT8 v = dmac_data.istr;
|
| 136 | LOG( "DMAC: PC=%08x - ISTR Read(%04x)\n", activecpu_get_pc(), dmac_data.istr );
|
| 137 |
|
| 138 | dmac_data.istr &= ~0x0f;
|
| 139 | return v;
|
| 140 | }
|
| 141 | break;
|
| 142 | |
| 143 | case 0x21:
|
| 144 | {
|
| 145 | LOG( "DMAC: PC=%08x - CNTR Read(%04x)\n", activecpu_get_pc(), dmac_data.cntr );
|
| 146 | return dmac_data.cntr;
|
| 147 | }
|
| 148 | break;
|
| 149 | |
| 150 | case 0x40: /* wtc hi */
|
| 151 | {
|
| 152 | LOG( "DMAC: PC=%08x - WTC HI Read\n", activecpu_get_pc() );
|
| 153 | return (dmac_data.wtc >> 16);
|
| 154 | }
|
| 155 | break;
|
| 156 |
|
| 157 | case 0x41: /* wtc lo */
|
| 158 | {
|
| 159 | LOG( "DMAC: PC=%08x - WTC LO Read\n", activecpu_get_pc() );
|
| 160 | return dmac_data.wtc;
|
| 161 | }
|
| 162 | break;
|
| 163 | |
| 164 | case 0x42: /* acr hi */
|
| 165 | {
|
| 166 | LOG( "DMAC: PC=%08x - ACR HI Read\n", activecpu_get_pc() );
|
| 167 | return (dmac_data.acr >> 16);
|
| 168 | }
|
| 169 | break;
|
| 170 |
|
| 171 | case 0x43: /* acr lo */
|
| 172 | {
|
| 173 | LOG( "DMAC: PC=%08x - ACR LO Read\n", activecpu_get_pc() );
|
| 174 | return dmac_data.acr;
|
| 175 | }
|
| 176 | break;
|
| 177 | |
| 178 | case 0x48: /* wd33c93 SCSI expansion */
|
| 179 | case 0x49:
|
| 180 | {
|
| 181 | LOG( "DMAC: PC=%08x - WD33C93 Read(%d)\n", activecpu_get_pc(), offset & 1 );
|
| 182 | return 0x00; /* Not available without SCSI expansion */
|
| 183 | }
|
| 184 | break;
|
| 185 | |
| 186 | case 0x50:
|
| 187 | {
|
| 188 | LOG( "DMAC: PC=%08x - CDROM RESP Read\n", activecpu_get_pc() );
|
| 189 | return matsucd_response_r();
|
| 190 | }
|
| 191 | break;
|
| 192 | |
| 193 | case 0x51: /* XT IO */
|
| 194 | case 0x52:
|
| 195 | case 0x53:
|
| 196 | {
|
| 197 | LOG( "DMAC: PC=%08x - XT IO Read(%d)\n", activecpu_get_pc(), (offset & 3)-1 );
|
| 198 | return 0xff;
|
| 199 | }
|
| 200 | break;
|
| 201 | |
| 202 | case 0x58: /* TPI6525 */
|
| 203 | case 0x59:
|
| 204 | case 0x5A:
|
| 205 | case 0x5B:
|
| 206 | case 0x5C:
|
| 207 | case 0x5D:
|
| 208 | case 0x5E:
|
| 209 | case 0x5F:
|
| 210 | case 0x60:
|
| 211 | case 0x61:
|
| 212 | case 0x62:
|
| 213 | case 0x63:
|
| 214 | case 0x64:
|
| 215 | case 0x65:
|
| 216 | case 0x66:
|
| 217 | case 0x67:
|
| 218 | {
|
| 219 | LOG( "DMAC: PC=%08x - TPI6525 Read(%d)\n", activecpu_get_pc(), (offset - 0x58) );
|
| 220 | return tpi6525_0_port_r(offset - 0x58);
|
| 221 | }
|
| 222 | break;
|
| 223 | |
| 224 | case 0x70: /* DMA start strobe */
|
| 225 | {
|
| 226 | LOG( "DMAC: PC=%08x - DMA Start Strobe\n", activecpu_get_pc() );
|
| 227 | mame_timer_adjust( dmac_data.dma_timer, MAME_TIME_IN_MSEC( CD_SECTOR_TIME ), 0, time_zero );
|
| 228 | }
|
| 229 | break;
|
| 230 | |
| 231 | case 0x71: /* DMA stop strobe */
|
| 232 | {
|
| 233 | LOG( "DMAC: PC=%08x - DMA Stop Strobe\n", activecpu_get_pc() );
|
| 234 | mame_timer_reset( dmac_data.dma_timer, time_never );
|
| 235 | }
|
| 236 | break;
|
| 237 | |
| 238 | case 0x72: /* Clear IRQ strobe */
|
| 239 | {
|
| 240 | LOG( "DMAC: PC=%08x - IRQ Clear Strobe\n", activecpu_get_pc() );
|
| 241 | dmac_data.istr &= ~ISTR_INT_P;
|
| 242 | }
|
| 243 | break;
|
| 244 | |
| 245 | case 0x74: /* Flush strobe */
|
| 246 | {
|
| 247 | LOG( "DMAC: PC=%08x - Flush Strobe\n", activecpu_get_pc() );
|
| 248 | dmac_data.istr |= ISTR_FE_FLG;
|
| 249 | }
|
| 250 | break;
|
| 251 | |
| 252 | default:
|
| 253 | logerror( "DMAC-READ: PC=%08x, offset = %02x\n", activecpu_get_pc(), offset );
|
| 254 | break;
|
| 255 | }
|
| 256 |
|
| 257 | return 0;
|
| 258 | }
|
| 259 | |
| 260 | static WRITE16_HANDLER( amiga_dmac_w )
|
| 261 | {
|
| 262 | offset &= 0xff;
|
| 263 | |
| 264 | switch( offset )
|
| 265 | {
|
| 266 | case 0x21: /* control write */
|
| 267 | {
|
| 268 | LOG( "DMAC: PC=%08x - CNTR Write(%04x)\n", activecpu_get_pc(), data );
|
| 269 | dmac_data.cntr = data;
|
| 270 | check_interrupts();
|
| 271 | }
|
| 272 | break;
|
| 273 | |
| 274 | case 0x40: /* wtc hi */
|
| 275 | {
|
| 276 | LOG( "DMAC: PC=%08x - WTC HI Write - data = %04x\n", activecpu_get_pc(), data );
|
| 277 | dmac_data.wtc &= 0x0000ffff;
|
| 278 | dmac_data.wtc |= ((UINT32)data) << 16;
|
| 279 | }
|
| 280 | break;
|
| 281 |
|
| 282 | case 0x41: /* wtc lo */
|
| 283 | {
|
| 284 | LOG( "DMAC: PC=%08x - WTC LO Write - data = %04x\n", activecpu_get_pc(), data );
|
| 285 | dmac_data.wtc &= 0xffff0000;
|
| 286 | dmac_data.wtc |= data;
|
| 287 | }
|
| 288 | break;
|
| 289 | |
| 290 | case 0x42: /* acr hi */
|
| 291 | {
|
| 292 | LOG( "DMAC: PC=%08x - ACR HI Write - data = %04x\n", activecpu_get_pc(), data );
|
| 293 | dmac_data.acr &= 0x0000ffff;
|
| 294 | dmac_data.acr |= ((UINT32)data) << 16;
|
| 295 | }
|
| 296 | break;
|
| 297 |
|
| 298 | case 0x43: /* acr lo */
|
| 299 | {
|
| 300 | LOG( "DMAC: PC=%08x - ACR LO Write - data = %04x\n", activecpu_get_pc(), data );
|
| 301 | dmac_data.acr &= 0xffff0000;
|
| 302 | dmac_data.acr |= data;
|
| 303 | }
|
| 304 | break;
|
| 305 | |
| 306 | case 0x47: /* dawr */
|
| 307 | {
|
| 308 | LOG( "DMAC: PC=%08x - DAWR Write - data = %04x\n", activecpu_get_pc(), data );
|
| 309 | dmac_data.dawr = data;
|
| 310 | }
|
| 311 | break;
|
| 312 | |
| 313 | case 0x48: /* wd33c93 SCSI expansion */
|
| 314 | case 0x49:
|
| 315 | {
|
| 316 | LOG( "DMAC: PC=%08x - WD33C93 Write(%d) - data = %04x\n", activecpu_get_pc(), offset & 1, data );
|
| 317 | /* Not available without SCSI expansion */
|
| 318 | }
|
| 319 | break;
|
| 320 | |
| 321 | case 0x50:
|
| 322 | {
|
| 323 | LOG( "DMAC: PC=%08x - CDROM CMD Write - data = %04x\n", activecpu_get_pc(), data );
|
| 324 | matsucd_command_w( data );
|
| 325 | }
|
| 326 | break;
|
| 327 | |
| 328 | case 0x58: /* TPI6525 */
|
| 329 | case 0x59:
|
| 330 | case 0x5A:
|
| 331 | case 0x5B:
|
| 332 | case 0x5C:
|
| 333 | case 0x5D:
|
| 334 | case 0x5E:
|
| 335 | case 0x5F:
|
| 336 | case 0x60:
|
| 337 | case 0x61:
|
| 338 | case 0x62:
|
| 339 | case 0x63:
|
| 340 | case 0x64:
|
| 341 | case 0x65:
|
| 342 | case 0x66:
|
| 343 | case 0x67:
|
| 344 | {
|
| 345 | LOG( "DMAC: PC=%08x - TPI6525 Write(%d) - data = %04x\n", activecpu_get_pc(), (offset - 0x58), data );
|
| 346 | tpi6525_0_port_w(offset - 0x58, data);
|
| 347 | }
|
| 348 | break;
|
| 349 | |
| 350 | case 0x70: /* DMA start strobe */
|
| 351 | {
|
| 352 | LOG( "DMAC: PC=%08x - DMA Start Strobe\n", activecpu_get_pc() );
|
| 353 | mame_timer_adjust( dmac_data.dma_timer, MAME_TIME_IN_MSEC( CD_SECTOR_TIME ), 0, time_zero );
|
| 354 | }
|
| 355 | break;
|
| 356 | |
| 357 | case 0x71: /* DMA stop strobe */
|
| 358 | {
|
| 359 | LOG( "DMAC: PC=%08x - DMA Stop Strobe\n", activecpu_get_pc() );
|
| 360 | mame_timer_reset( dmac_data.dma_timer, time_never );
|
| 361 | }
|
| 362 | break;
|
| 363 | |
| 364 | case 0x72: /* Clear IRQ strobe */
|
| 365 | {
|
| 366 | LOG( "DMAC: PC=%08x - IRQ Clear Strobe\n", activecpu_get_pc() );
|
| 367 | dmac_data.istr &= ~ISTR_INT_P;
|
| 368 | }
|
| 369 | break;
|
| 370 | |
| 371 | case 0x74: /* Flush Strobe */
|
| 372 | {
|
| 373 | LOG( "DMAC: PC=%08x - Flush Strobe\n", activecpu_get_pc() );
|
| 374 | dmac_data.istr |= ISTR_FE_FLG;
|
| 375 | }
|
| 376 | break;
|
| 377 | |
| 378 | default:
|
| 379 | logerror( "DMAC-WRITE: PC=%08x, offset = %02x, data = %04x\n", activecpu_get_pc(), offset, data );
|
| 380 | break;
|
| 381 | }
|
| 382 | }
|
| 383 | |
| 384 | /***************************************************************************
|
| 385 | |
| 386 | Autoconfig
|
| 387 |
|
| 388 | ***************************************************************************/
|
| 389 | |
| 390 | static void dmac_install(offs_t base)
|
| 391 | {
|
| 392 | memory_install_read16_handler(0, ADDRESS_SPACE_PROGRAM, base, base + 0xFFFF, 0, 0, amiga_dmac_r);
|
| 393 | memory_install_write16_handler(0, ADDRESS_SPACE_PROGRAM, base, base + 0xFFFF, 0, 0, amiga_dmac_w);
|
| 394 | }
|
| 395 | |
| 396 | static void dmac_uninstall(offs_t base)
|
| 397 | {
|
| 398 | memory_install_read16_handler(0, ADDRESS_SPACE_PROGRAM, base, base + 0xFFFF, 0, 0, MRA16_UNMAP);
|
| 399 | memory_install_write16_handler(0, ADDRESS_SPACE_PROGRAM, base, base + 0xFFFF, 0, 0, MWA16_UNMAP);
|
| 400 | }
|
| 401 | |
| 402 | static amiga_autoconfig_device dmac_device =
|
| 403 | {
|
| 404 | 0, /* link into free memory list */
|
| 405 | 0, /* ROM vector offset valid */
|
| 406 | 0, /* multiple devices on card */
|
| 407 | 1, /* number of 64k pages */
|
| 408 | 3, /* product number (DMAC) */
|
| 409 | 0, /* prefer 8MB address space */
|
| 410 | 0, /* can be shut up */
|
| 411 | 0x0202, /* manufacturers number (Commodore) */
|
| 412 | 0, /* serial number */
|
| 413 | 0, /* ROM vector offset */
|
| 414 | NULL, /* interrupt control read */
|
| 415 | NULL, /* interrupt control write */
|
| 416 | dmac_install, /* memory installation */
|
| 417 | dmac_uninstall /* memory uninstallation */
|
| 418 | };
|
| 419 | |
| 420 | /***************************************************************************
|
| 421 | |
| 422 | TPI6525
|
| 423 |
|
| 424 | ***************************************************************************/
|
| 425 | |
| 426 | static int tp6525_portc_r( void )
|
| 427 | {
|
| 428 | int ret = 0;
|
| 429 |
|
| 430 | if ( (tpi6525[0].c.ddr & 0x04) == 0 ) /* if pin 2 is set to input */
|
| 431 | {
|
| 432 | ret |= matsucd_stch_r() ? 0x00 : 0x04; /* read status change signal */
|
| 433 | }
|
| 434 |
|
| 435 | if ( (tpi6525[0].c.ddr & 0x08) == 0 ) /* if pin 3 is set to input */
|
| 436 | ret |= matsucd_sten_r() ? 0x08 : 0x00; /* read enable signal */
|
| 437 |
|
| 438 | return ret;
|
| 439 | }
|
| 440 | |
| 441 | static void tp6525_portb_w( int data )
|
| 442 | {
|
| 443 | if ( tpi6525[0].b.ddr & 0x01 ) /* if pin 0 is set to output */
|
| 444 | matsucd_cmd_w( data & 1 ); /* write to the /CMD signal */
|
| 445 |
|
| 446 | if ( tpi6525[0].b.ddr & 0x02 ) /* if pin 1 is set to output */
|
| 447 | matsucd_enable_w( data & 2 ); /* write to the /ENABLE signal */
|
| 448 | }
|
| 449 | |
| 450 | static mame_timer *tp6525_delayed_timer;
|
| 451 | |
| 452 | static TIMER_CALLBACK(tp6525_delayed_irq)
|
| 453 | {
|
| 454 | (void)param;
|
| 455 |
|
| 456 | if ( (CUSTOM_REG(REG_INTREQ) & INTENA_PORTS) == 0 )
|
| 457 | {
|
| 458 | amiga_custom_w(REG_INTREQ, 0x8000 | INTENA_PORTS, 0);
|
| 459 | }
|
| 460 | else
|
| 461 | {
|
| 462 | mame_timer_adjust( tp6525_delayed_timer, MAME_TIME_IN_MSEC(1), 0, time_zero );
|
| 463 | }
|
| 464 | }
|
| 465 | |
| 466 | static void tp6525_irq( int level )
|
| 467 | {
|
| 468 | LOG( "TPI6525 Interrupt: level = %d\n", level);
|
| 469 |
|
| 470 | if ( level )
|
| 471 | {
|
| 472 | if ( (CUSTOM_REG(REG_INTREQ) & INTENA_PORTS) == 0 )
|
| 473 | {
|
| 474 | amiga_custom_w(REG_INTREQ, 0x8000 | INTENA_PORTS, 0);
|
| 475 | }
|
| 476 | else
|
| 477 | {
|
| 478 | /* we *have to* deliver the irq, so if we can't, delay it and try again later */
|
| 479 | mame_timer_adjust( tp6525_delayed_timer, MAME_TIME_IN_MSEC(1), 0, time_zero );
|
| 480 | }
|
| 481 | }
|
| 482 | }
|
| 483 | |
| 484 | static void cdrom_status_enabled( int level )
|
| 485 | {
|
| 486 | /* PC3 on the 6525 */
|
| 487 | tpi6525_0_irq3_level( level );
|
| 488 | }
|
| 489 | |
| 490 | static void cdrom_status_change( int level )
|
| 491 | {
|
| 492 | /* invert */
|
| 493 | level = level ? 0 : 1;
|
| 494 |
|
| 495 | /* PC2 on the 6525 */
|
| 496 | tpi6525_0_irq2_level( level );
|
| 497 | }
|
| 498 | |
| 499 | static void cdrom_subcode_ready( int level )
|
| 500 | {
|
| 501 | /* PC1 on the 6525 */
|
| 502 | tpi6525_0_irq1_level( level );
|
| 503 | }
|
| 504 | |
| 505 | void amigacd_init( void )
|
| 506 | {
|
| 507 | /* initialize the dmac */
|
| 508 | memset( &dmac_data, 0, sizeof( dmac_data ) );
|
| 509 |
|
| 510 | dmac_data.dma_timer = mame_timer_alloc(dmac_dma_proc);
|
| 511 | tp6525_delayed_timer = mame_timer_alloc(tp6525_delayed_irq);
|
| 512 |
|
| 513 | /* initialize the 6525 TPI */
|
| 514 | tpi6525_0_reset();
|
| 515 |
|
| 516 | tpi6525[0].a.read = NULL;
|
| 517 | tpi6525[0].b.read = NULL;
|
| 518 | tpi6525[0].c.read = tp6525_portc_r;
|
| 519 |
|
| 520 | tpi6525[0].a.output = NULL;
|
| 521 | tpi6525[0].b.output = tp6525_portb_w;
|
| 522 | tpi6525[0].c.output = NULL;
|
| 523 |
|
| 524 | tpi6525[0].interrupt.output = tp6525_irq;
|
| 525 | tpi6525[0].ca.output = NULL;
|
| 526 | tpi6525[0].cb.output = NULL;
|
| 527 |
|
| 528 | /* initialize the cdrom */
|
| 529 | matsucd_init();
|
| 530 | matsucd_set_status_enabled_callback( cdrom_status_enabled );
|
| 531 | matsucd_set_status_changed_callback( cdrom_status_change );
|
| 532 | matsucd_set_subcode_ready_callback( cdrom_subcode_ready );
|
| 533 |
|
| 534 | /* set up DMAC with autoconfig */
|
| 535 | amiga_add_autoconfig( &dmac_device );
|
| 536 | }
|
src/mess/machine/matsucd.c
| r0 | r855 | |
| 1 | /***************************************************************************
|
| 2 | |
| 3 | Matsushita/Panasonic CDR521/522 type CDROM drive emulation
|
| 4 |
|
| 5 | Notes:
|
| 6 | This version implements the drive found in Amiga CDTV. There are
|
| 7 | different drives supporting this command-set (look in the sbpcd driver
|
| 8 | in Linux for examples). Most drives support the exact same command
|
| 9 | structure, but the command numbers differ. Eventually this driver
|
| 10 | can be expanded with support for the other drives as needed.
|
| 11 | |
| 12 | ***************************************************************************/
|
| 13 | |
| 14 | #include "mame.h"
|
| 15 | #include "driver.h"
|
| 16 | #include "devices/chd_cd.h"
|
| 17 | #include "sound/cdda.h"
|
| 18 | |
| 19 | |
| 20 | #define MATSU_STATUS_READY ( 1 << 0 ) /* driver ready */
|
| 21 | #define MATSU_STATUS_DOORLOCKED ( 1 << 1 ) /* door locked */
|
| 22 | #define MATSU_STATUS_PLAYING ( 1 << 2 ) /* drive playing */
|
| 23 | #define MATSU_STATUS_SUCCESS ( 1 << 3 ) /* last command was succesful */
|
| 24 | #define MATSU_STATUS_ERROR ( 1 << 4 ) /* last command failed */
|
| 25 | #define MATSU_STATUS_MOTOR ( 1 << 5 ) /* spinning */
|
| 26 | #define MATSU_STATUS_MEDIA ( 1 << 6 ) /* media present (in caddy or tray) */
|
| 27 | #define MATSU_STATUS_DOORCLOSED ( 1 << 7 ) /* tray status */
|
| 28 | |
| 29 | typedef struct
|
| 30 | {
|
| 31 | UINT8 enabled; /* /ENABLE - Unit enabled */
|
| 32 | UINT8 cmd_signal; /* /CMD - Command mode */
|
| 33 | UINT8 stch_signal; /* /STCH - Status Changed */
|
| 34 | UINT8 sten_signal; /* /STEN - Status Enabled */
|
| 35 | UINT8 scor_signal; /* /STEN - Subcode Ready */
|
| 36 | UINT8 input[16];
|
| 37 | UINT8 input_pos;
|
| 38 | UINT8 output[16];
|
| 39 | UINT8 output_pos;
|
| 40 | UINT8 output_len;
|
| 41 | UINT8 status;
|
| 42 | UINT8 motor;
|
| 43 | UINT16 sector_size;
|
| 44 | UINT32 lba;
|
| 45 | UINT16 num_blocks;
|
| 46 | UINT16 xfer_offset;
|
| 47 | UINT8 sector_buffer[CD_MAX_SECTOR_DATA];
|
| 48 | UINT8 cdda_set;
|
| 49 | void (*sten_cb)( int level ); /* Status enabled callback */
|
| 50 | void (*stch_cb)( int level ); /* Status changed callback */
|
| 51 | void (*scor_cb)( int level ); /* Subcode ready callback */
|
| 52 | cdrom_file *cdrom;
|
| 53 | mame_timer *frame_timer;
|
| 54 | } matsucd;
|
| 55 | |
| 56 | static matsucd cd;
|
| 57 | |
| 58 | #define MSF2LBA(msf) (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff))
|
| 59 | #define LBA2MSF(lba) (((lba / (75 * 60)) << 16) | (((lba / 75) % 60) << 8) | (lba % 75))
|
| 60 | |
| 61 | static TIMER_CALLBACK(matsu_subcode_proc);
|
| 62 | |
| 63 | void matsucd_init( void )
|
| 64 | {
|
| 65 | memset(&cd, 0, sizeof( matsucd ) );
|
| 66 |
|
| 67 | cd.cdrom = mess_cd_get_cdrom_file_by_number(0);
|
| 68 |
|
| 69 | cd.frame_timer = mame_timer_alloc(matsu_subcode_proc);
|
| 70 |
|
| 71 | cd.stch_signal = 1;
|
| 72 | }
|
| 73 | |
| 74 | void matsucd_set_status_enabled_callback( void (*sten_cb)( int level ) )
|
| 75 | {
|
| 76 | /* add the callback for status enabled signal */
|
| 77 | cd.sten_cb = sten_cb;
|
| 78 | }
|
| 79 | |
| 80 | void matsucd_set_status_changed_callback( void (*stch_cb)( int level ) )
|
| 81 | {
|
| 82 | /* add the callback for status changed signal */
|
| 83 | cd.stch_cb = stch_cb;
|
| 84 | }
|
| 85 | |
| 86 | void matsucd_set_subcode_ready_callback( void (*scor_cb)( int level ) )
|
| 87 | {
|
| 88 | /* add the callback for subcode ready signal */
|
| 89 | cd.scor_cb = scor_cb;
|
| 90 | }
|
| 91 | |
| 92 | static int matsucd_getsector_type( void )
|
| 93 | {
|
| 94 | switch( cd.sector_size )
|
| 95 | {
|
| 96 | case 2048: return CD_TRACK_MODE1; break;
|
| 97 | case 2324: return CD_TRACK_MODE2_FORM2; break;
|
| 98 | case 2336: return CD_TRACK_MODE2; break;
|
| 99 | case 2352: return CD_TRACK_MODE2_RAW; break;
|
| 100 | |
| 101 | default: logerror( "MATSUCD: Sector size %d unsupported!\n", cd.sector_size ); break;
|
| 102 | }
|
| 103 |
|
| 104 | return CD_TRACK_RAW_DONTCARE;
|
| 105 | }
|
| 106 | |
| 107 | void matsucd_read_next_block( void )
|
| 108 | {
|
| 109 | cd.xfer_offset = 0;
|
| 110 |
|
| 111 | if ( cd.num_blocks )
|
| 112 | {
|
| 113 | cd.lba++;
|
| 114 | cd.num_blocks--;
|
| 115 | |
| 116 | if (!cdrom_read_data(cd.cdrom, cd.lba, cd.sector_buffer, matsucd_getsector_type()))
|
| 117 | {
|
| 118 | logerror( "MATSUCD - Warning: Read error on CD!\n" );
|
| 119 | }
|
| 120 | }
|
| 121 | }
|
| 122 | |
| 123 | int matsucd_get_next_byte( UINT8 *data )
|
| 124 | {
|
| 125 | /* no more data to read on this sector */
|
| 126 | if ( cd.xfer_offset >= cd.sector_size )
|
| 127 | return -1;
|
| 128 |
|
| 129 | if ( data )
|
| 130 | *data = cd.sector_buffer[cd.xfer_offset++];
|
| 131 |
|
| 132 | return 0;
|
| 133 | }
|
| 134 | |
| 135 | static void matsucd_cdda_stop( void )
|
| 136 | {
|
| 137 | int cddanum = cdda_num_from_cdrom(cd.cdrom);
|
| 138 |
|
| 139 | if (cddanum != -1)
|
| 140 | {
|
| 141 | cdda_stop_audio(cddanum);
|
| 142 | mame_timer_reset( cd.frame_timer, time_never );
|
| 143 | }
|
| 144 | }
|
| 145 | |
| 146 | static void matsucd_cdda_play( UINT32 lba, UINT32 num_blocks )
|
| 147 | {
|
| 148 | int cddanum = cdda_num_from_cdrom(cd.cdrom);
|
| 149 | if (cddanum != -1)
|
| 150 | {
|
| 151 | cdda_start_audio(cddanum, lba, num_blocks);
|
| 152 | mame_timer_adjust( cd.frame_timer, MAME_TIME_IN_HZ( 75 ), 0, time_zero );
|
| 153 | }
|
| 154 | }
|
| 155 | |
| 156 | static void matsucd_cdda_pause( int pause )
|
| 157 | {
|
| 158 | int cddanum = cdda_num_from_cdrom(cd.cdrom);
|
| 159 | if (cddanum != -1)
|
| 160 | {
|
| 161 | cdda_pause_audio(cddanum, pause);
|
| 162 | |
| 163 | if ( pause )
|
| 164 | {
|
| 165 | mame_timer_reset( cd.frame_timer, time_never );
|
| 166 | }
|
| 167 | else
|
| 168 | {
|
| 169 | mame_timer_adjust( cd.frame_timer, MAME_TIME_IN_HZ( 75 ), 0, time_zero );
|
| 170 | }
|
| 171 | }
|
| 172 | }
|
| 173 | |
| 174 | static UINT8 matsucd_cdda_getstatus( UINT32 *lba )
|
| 175 | {
|
| 176 | int cddanum = cdda_num_from_cdrom(cd.cdrom);
|
| 177 |
|
| 178 | if ( lba ) *lba = 0;
|
| 179 |
|
| 180 | if (cddanum != -1)
|
| 181 | {
|
| 182 | if (cdda_audio_active(cddanum))
|
| 183 | {
|
| 184 | if ( lba ) *lba = cdda_get_audio_lba(cddanum);
|
| 185 | |
| 186 | if (cdda_audio_paused(cddanum))
|
| 187 | {
|
| 188 | return 0x12; /* audio paused */
|
| 189 | }
|
| 190 | else
|
| 191 | {
|
| 192 | return 0x11; /* audio in progress */
|
| 193 | }
|
| 194 | }
|
| 195 | else if (cdda_audio_ended(cddanum))
|
| 196 | {
|
| 197 | return 0x13; /* audio ended */
|
| 198 | }
|
| 199 | }
|
| 200 |
|
| 201 | return 0x15; /* no audio status */
|
| 202 | }
|
| 203 | |
| 204 | void matsucd_enable_w( int level )
|
| 205 | {
|
| 206 | cd.enabled = ( level ) ? 0 : 1;
|
| 207 | }
|
| 208 | |
| 209 | void matsucd_cmd_w( int level )
|
| 210 | {
|
| 211 | cd.cmd_signal = ( level ) ? 0 : 1;
|
| 212 | }
|
| 213 | |
| 214 | int matsucd_stch_r( void )
|
| 215 | {
|
| 216 | return cd.stch_signal ? 0 : 1;
|
| 217 | }
|
| 218 | |
| 219 | int matsucd_sten_r( void )
|
| 220 | {
|
| 221 | return cd.sten_signal ? 0 : 1;
|
| 222 | }
|
| 223 | |
| 224 | int matsucd_scor_r( void )
|
| 225 | {
|
| 226 | return cd.scor_signal ? 0 : 1;
|
| 227 | }
|
| 228 | |
| 229 | static void update_status_enable( int level )
|
| 230 | {
|
| 231 | cd.sten_signal = level;
|
| 232 |
|
| 233 | if ( cd.sten_cb )
|
| 234 | {
|
| 235 | (*cd.sten_cb)(cd.sten_signal);
|
| 236 | }
|
| 237 | }
|
| 238 | |
| 239 | static void update_status_changed( int level )
|
| 240 | {
|
| 241 | cd.stch_signal = level;
|
| 242 |
|
| 243 | if ( cd.stch_cb )
|
| 244 | {
|
| 245 | (*cd.stch_cb)(cd.stch_signal);
|
| 246 | }
|
| 247 | }
|
| 248 | |
| 249 | static void update_subcode_ready( int level )
|
| 250 | {
|
| 251 | cd.scor_signal = level;
|
| 252 |
|
| 253 | if ( cd.scor_cb )
|
| 254 | {
|
| 255 | (*cd.scor_cb)(cd.scor_signal);
|
| 256 | }
|
| 257 | }
|
| 258 | |
| 259 | static TIMER_CALLBACK(matsucd_set_status_end)
|
| 260 | {
|
| 261 | update_status_changed( 1 );
|
| 262 | }
|
| 263 | |
| 264 | static void matsucd_set_status( UINT8 status )
|
| 265 | {
|
| 266 | if ( status != cd.status )
|
| 267 | {
|
| 268 | cd.status = status;
|
| 269 | |
| 270 | if ( cd.stch_signal != 0 )
|
| 271 | {
|
| 272 | update_status_changed( 0 );
|
| 273 | mame_timer_set( MAME_TIME_IN_MSEC(1), 0, matsucd_set_status_end );
|
| 274 | }
|
| 275 | }
|
| 276 | }
|
| 277 | |
| 278 | static TIMER_CALLBACK(matsu_subcode_proc)
|
| 279 | {
|
| 280 | int cddanum = cdda_num_from_cdrom(cd.cdrom);
|
| 281 |
|
| 282 | (void)param;
|
| 283 |
|
| 284 | if (cddanum != -1)
|
| 285 | {
|
| 286 | UINT8 s = matsucd_cdda_getstatus(NULL);
|
| 287 | UINT8 newstatus = cd.status;
|
| 288 | |
| 289 | if ( s == 0x11 || s == 0x12 )
|
| 290 | {
|
| 291 | if ( s == 0x11 )
|
| 292 | {
|
| 293 | update_subcode_ready( 1 );
|
| 294 | update_subcode_ready( 0 );
|
| 295 | }
|
| 296 |
|
| 297 | newstatus |= MATSU_STATUS_PLAYING;
|
| 298 |
|
| 299 | mame_timer_adjust( cd.frame_timer, MAME_TIME_IN_HZ( 75 ), 0, time_zero );
|
| 300 | }
|
| 301 | else
|
| 302 | {
|
| 303 | newstatus &= ~MATSU_STATUS_PLAYING;
|
| 304 | }
|
| 305 | |
| 306 | matsucd_set_status( newstatus );
|
| 307 | }
|
| 308 | }
|
| 309 | |
| 310 | static void matsucd_command_error( void )
|
| 311 | {
|
| 312 | UINT8 newstatus = cd.status;
|
| 313 | |
| 314 | newstatus &= ~MATSU_STATUS_SUCCESS;
|
| 315 | newstatus |= MATSU_STATUS_ERROR;
|
| 316 |
|
| 317 | matsucd_set_status( newstatus );
|
| 318 | }
|
| 319 | |
| 320 | static void matsucd_complete_cmd( UINT8 len )
|
| 321 | {
|
| 322 | UINT8 newstatus = cd.status;
|
| 323 |
|
| 324 | cd.input_pos = 0;
|
| 325 | cd.output_pos = 0;
|
| 326 | cd.output_len = len;
|
| 327 |
|
| 328 | newstatus &= ~MATSU_STATUS_ERROR;
|
| 329 | newstatus |= MATSU_STATUS_SUCCESS;
|
| 330 |
|
| 331 | matsucd_set_status( newstatus );
|
| 332 |
|
| 333 | update_status_enable( 1 );
|
| 334 | update_status_enable( 0 );
|
| 335 | }
|
| 336 | |
| 337 | UINT8 matsucd_response_r( void )
|
| 338 | {
|
| 339 | UINT8 v = cd.output[cd.output_pos++];
|
| 340 |
|
| 341 | if ( cd.output_pos < cd.output_len )
|
| 342 | {
|
| 343 | update_status_enable( 1 );
|
| 344 | update_status_enable( 0 );
|
| 345 | }
|
| 346 |
|
| 347 | return v;
|
| 348 | }
|
| 349 | |
| 350 | void matsucd_command_w( UINT8 data )
|
| 351 | {
|
| 352 | UINT8 cmd;
|
| 353 |
|
| 354 | /* make sure we're enabled */
|
| 355 | if ( cd.enabled == 0 )
|
| 356 | return;
|
| 357 |
|
| 358 | /* make sure /CMD is asserted */
|
| 359 | if ( cd.cmd_signal == 0 )
|
| 360 | return;
|
| 361 |
|
| 362 | if ( cd.cdda_set == 0 )
|
| 363 | {
|
| 364 | if ( cd.cdrom )
|
| 365 | cdda_set_cdrom(0, cd.cdrom);
|
| 366 | |
| 367 | cd.cdda_set = 1;
|
| 368 | }
|
| 369 |
|
| 370 | cd.input[cd.input_pos++] = data;
|
| 371 | |
| 372 | cmd = cd.input[0];
|
| 373 |
|
| 374 | switch( cmd )
|
| 375 | {
|
| 376 | case 0x01: /* seek */
|
| 377 | {
|
| 378 | if ( cd.input_pos < 7 )
|
| 379 | return;
|
| 380 | |
| 381 | /* stop CDDA audio if necessary */
|
| 382 | matsucd_cdda_stop();
|
| 383 |
|
| 384 | cd.motor = 1;
|
| 385 | |
| 386 | memset( cd.output, 0, 6 );
|
| 387 | matsucd_complete_cmd( 0 );
|
| 388 | }
|
| 389 | break;
|
| 390 | |
| 391 | case 0x02: /* read sectors */
|
| 392 | {
|
| 393 | if ( cd.input_pos < 7 )
|
| 394 | return;
|
| 395 |
|
| 396 | /* stop CDDA audio if necessary */
|
| 397 | matsucd_cdda_stop();
|
| 398 | |
| 399 | /* LBA */
|
| 400 | cd.lba = cd.input[1];
|
| 401 | cd.lba <<= 8;
|
| 402 | cd.lba |= cd.input[2];
|
| 403 | cd.lba <<= 8;
|
| 404 | cd.lba |= cd.input[3];
|
| 405 |
|
| 406 | /* Number of blocks */
|
| 407 | cd.num_blocks = cd.input[4];
|
| 408 | cd.num_blocks <<= 8;
|
| 409 | cd.num_blocks |= cd.input[5];
|
| 410 |
|
| 411 | /* Reset transfer count */
|
| 412 | cd.xfer_offset = 0;
|
| 413 |
|
| 414 | /* go ahead and cache the first block */
|
| 415 | if (!cdrom_read_data(cd.cdrom, cd.lba, cd.sector_buffer, matsucd_getsector_type()))
|
| 416 | {
|
| 417 | logerror( "MATSUCD - Warning: Read error on CD!\n" );
|
| 418 | matsucd_command_error();
|
| 419 | return;
|
| 420 | }
|
| 421 |
|
| 422 | cd.motor = 1;
|
| 423 | |
| 424 | memset( cd.output, 0, 6 );
|
| 425 | matsucd_complete_cmd( 0 );
|
| 426 | }
|
| 427 | break;
|
| 428 | |
| 429 | case 0x04: /* motor on */
|
| 430 | {
|
| 431 | if ( cd.input_pos < 7 )
|
| 432 | return;
|
| 433 | |
| 434 | cd.motor = 1;
|
| 435 | |
| 436 | memset( cd.output, 0, 6 );
|
| 437 | matsucd_complete_cmd( 0 );
|
| 438 | }
|
| 439 | break;
|
| 440 | |
| 441 | case 0x05: /* motor off */
|
| 442 | {
|
| 443 | if ( cd.input_pos < 7 )
|
| 444 | return;
|
| 445 | |
| 446 | /* stop CDDA audio if necessary */
|
| 447 | matsucd_cdda_stop();
|
| 448 |
|
| 449 | cd.motor = 0;
|
| 450 | |
| 451 | memset( cd.output, 0, 6 );
|
| 452 | matsucd_complete_cmd( 0 );
|
| 453 | }
|
| 454 | break;
|
| 455 | |
| 456 | case 0x09: /* play audio cd, LBA mode */
|
| 457 | {
|
| 458 | UINT32 lba, numblocks;
|
| 459 |
|
| 460 | if ( cd.input_pos < 7 )
|
| 461 | return;
|
| 462 |
|
| 463 | lba = cd.input[1];
|
| 464 | lba <<= 8;
|
| 465 | lba |= cd.input[2];
|
| 466 | lba <<= 8;
|
| 467 | lba |= cd.input[3];
|
| 468 |
|
| 469 | numblocks = cd.input[4];
|
| 470 | numblocks <<= 8;
|
| 471 | numblocks |= cd.input[5];
|
| 472 | numblocks <<= 8;
|
| 473 | numblocks |= cd.input[6];
|
| 474 |
|
| 475 | matsucd_cdda_play( lba, numblocks );
|
| 476 |
|
| 477 | cd.motor = 1;
|
| 478 | |
| 479 | memset( cd.output, 0, 6 );
|
| 480 | matsucd_complete_cmd( 0 );
|
| 481 | }
|
| 482 | break;
|
| 483 | |
| 484 | case 0x0a: /* play audio cd, MSF mode */
|
| 485 | {
|
| 486 | UINT32 start, end, lba_start, lba_end;
|
| 487 |
|
| 488 | if ( cd.input_pos < 7 )
|
| 489 | return;
|
| 490 |
|
| 491 | start = cd.input[1];
|
| 492 | start <<= 8;
|
| 493 | start |= cd.input[2];
|
| 494 | start <<= 8;
|
| 495 | start |= cd.input[3];
|
| 496 |
|
| 497 | end = cd.input[4];
|
| 498 | end <<= 8;
|
| 499 | end |= cd.input[5];
|
| 500 | end <<= 8;
|
| 501 | end |= cd.input[6];
|
| 502 |
|
| 503 | lba_start = MSF2LBA( start );
|
| 504 | lba_end = MSF2LBA( end );
|
| 505 |
|
| 506 | if ( end == 0xffffff )
|
| 507 | {
|
| 508 | lba_end = cdrom_get_track_start(cd.cdrom,cdrom_get_last_track(cd.cdrom)-1);
|
| 509 | lba_end += cdrom_get_toc(cd.cdrom)->tracks[cdrom_get_last_track(cd.cdrom)-1].frames;
|
| 510 | }
|
| 511 |
|
| 512 | if ( lba_end <= lba_start )
|
| 513 | {
|
| 514 | matsucd_cdda_stop();
|
| 515 | }
|
| 516 | else
|
| 517 | {
|
| 518 | matsucd_cdda_play( lba_start, lba_end - lba_start );
|
| 519 | cd.motor = 1;
|
| 520 | }
|
| 521 |
|
| 522 | memset( cd.output, 0, 6 );
|
| 523 | matsucd_complete_cmd( 0 );
|
| 524 | }
|
| 525 | break;
|
| 526 | |
| 527 | case 0x0b: /* play audio track and index */
|
| 528 | {
|
| 529 | UINT8 track_start = cd.input[1];
|
| 530 | UINT8 index_start = cd.input[2];
|
| 531 | UINT8 track_end = cd.input[3];
|
| 532 | UINT8 index_end = cd.input[4];
|
| 533 | UINT32 lba_start, lba_end;
|
| 534 |
|
| 535 | /* TODO: Add index support once the CDDA engine supports it */
|
| 536 | (void)index_start;
|
| 537 | (void)index_end;
|
| 538 |
|
| 539 | /* sanitize values */
|
| 540 | if ( track_start == 0 ) track_start++;
|
| 541 | if ( track_end > cdrom_get_last_track(cd.cdrom) )
|
| 542 | track_end = cdrom_get_last_track(cd.cdrom);
|
| 543 | |
| 544 | /* find the start and stop positions */
|
| 545 | lba_start = cdrom_get_track_start(cd.cdrom,track_start-1);
|
| 546 | lba_end = cdrom_get_track_start(cd.cdrom,track_end-1);
|
| 547 |
|
| 548 | lba_end += cdrom_get_toc(cd.cdrom)->tracks[track_end-1].frames;
|
| 549 |
|
| 550 | if ( lba_end <= lba_start )
|
| 551 | {
|
| 552 | matsucd_cdda_stop();
|
| 553 | }
|
| 554 | else
|
| 555 | {
|
| 556 | matsucd_cdda_play( lba_start, lba_end - lba_start );
|
| 557 | cd.motor = 1;
|
| 558 | }
|
| 559 |
|
| 560 | memset( cd.output, 0, 6 );
|
| 561 | matsucd_complete_cmd( 0 );
|
| 562 | }
|
| 563 | break;
|
| 564 | |
| 565 | case 0x81: /* status read */
|
| 566 | {
|
| 567 | UINT8 newstatus = cd.status;
|
| 568 |
|
| 569 | newstatus &= MATSU_STATUS_SUCCESS | MATSU_STATUS_ERROR | MATSU_STATUS_PLAYING;
|
| 570 | newstatus |= MATSU_STATUS_READY;
|
| 571 |
|
| 572 | if (cd.cdrom)
|
| 573 | {
|
| 574 | newstatus |= MATSU_STATUS_MEDIA;
|
| 575 | }
|
| 576 |
|
| 577 | if (cd.motor)
|
| 578 | newstatus |= MATSU_STATUS_MOTOR;
|
| 579 |
|
| 580 | cd.output[0] = newstatus;
|
| 581 |
|
| 582 | matsucd_set_status( newstatus );
|
| 583 |
|
| 584 | matsucd_complete_cmd( 1 );
|
| 585 | }
|
| 586 | break;
|
| 587 | |
| 588 | case 0x82: /* error read */
|
| 589 | {
|
| 590 | if ( cd.input_pos < 7 )
|
| 591 | return;
|
| 592 |
|
| 593 | memset( cd.output, 0, 6 );
|
| 594 | matsucd_complete_cmd( 6 );
|
| 595 | }
|
| 596 | break;
|
| 597 | |
| 598 | case 0x84: /* set mode */
|
| 599 | {
|
| 600 | if ( cd.input_pos < 7 )
|
| 601 | return;
|
| 602 | |
| 603 | cd.sector_size = cd.input[2];
|
| 604 | cd.sector_size <<= 8;
|
| 605 | cd.sector_size |= cd.input[3];
|
| 606 |
|
| 607 | memset( cd.output, 0, 6 );
|
| 608 | matsucd_complete_cmd( 0 );
|
| 609 | }
|
| 610 | break;
|
| 611 | |
| 612 | case 0x87: /* read SUBQ */
|
| 613 | {
|
| 614 | int msfmode;
|
| 615 | UINT32 lba;
|
| 616 | UINT8 track;
|
| 617 | |
| 618 | if ( cd.input_pos < 7 )
|
| 619 | return;
|
| 620 |
|
| 621 | msfmode = (cd.input[1] & 0x02) ? 1 : 0;
|
| 622 | |
| 623 | memset( cd.output, 0, 13 );
|
| 624 |
|
| 625 | cd.output[0] = matsucd_cdda_getstatus( &lba );
|
| 626 |
|
| 627 | if ( lba > 0 )
|
| 628 | {
|
| 629 | UINT32 disk_pos;
|
| 630 | UINT32 track_pos;
|
| 631 | |
| 632 | track = cdrom_get_track(cd.cdrom, lba);
|
| 633 | |
| 634 | cd.output[1] = cdrom_get_adr_control(cd.cdrom, track);
|
| 635 | cd.output[2] = track+1;
|
| 636 | cd.output[3] = 0; /* index */
|
| 637 |
|
| 638 | disk_pos = lba;
|
| 639 | if ( msfmode ) disk_pos = LBA2MSF(disk_pos);
|
| 640 |
|
| 641 | cd.output[4] = (disk_pos >> 24) & 0xff;
|
| 642 | cd.output[5] = (disk_pos >> 16) & 0xff;
|
| 643 | cd.output[6] = (disk_pos >> 8) & 0xff;
|
| 644 | cd.output[7] = (disk_pos) & 0xff;
|
| 645 |
|
| 646 | track_pos = lba - cdrom_get_track_start(cd.cdrom, track);
|
| 647 | if ( msfmode ) track_pos = LBA2MSF(track_pos);
|
| 648 |
|
| 649 | cd.output[8] = (track_pos >> 24) & 0xff;
|
| 650 | cd.output[9] = (track_pos >> 16) & 0xff;
|
| 651 | cd.output[10] = (track_pos >> 8) & 0xff;
|
| 652 | cd.output[11] = (track_pos) & 0xff;
|
| 653 |
|
| 654 | /* TODO: UPC flag at offset 12 */
|
| 655 | cd.output[12] = 0;
|
| 656 | }
|
| 657 |
|
| 658 | matsucd_complete_cmd( 13 );
|
| 659 | }
|
| 660 | break;
|
| 661 | |
| 662 | case 0x89: /* read disk info */
|
| 663 | {
|
| 664 | UINT32 end;
|
| 665 |
|
| 666 | if ( cd.input_pos < 7 )
|
| 667 | return;
|
| 668 |
|
| 669 | memset( cd.output, 0, 5 );
|
| 670 |
|
| 671 | cd.output[0] = cdrom_get_last_track(cd.cdrom) ? 1 : 0;
|
| 672 | cd.output[1] = cdrom_get_last_track(cd.cdrom);
|
| 673 | end = cdrom_get_track_start(cd.cdrom,cd.output[1]-1);
|
| 674 | end += cdrom_get_toc(cd.cdrom)->tracks[cd.output[1]-1].frames;
|
| 675 | end = LBA2MSF(end);
|
| 676 | cd.output[2] = (end >> 16) & 0xff;
|
| 677 | cd.output[3] = (end >> 8) & 0xff;
|
| 678 | cd.output[4] = (end) & 0xff;
|
| 679 |
|
| 680 | matsucd_complete_cmd( 5 );
|
| 681 | }
|
| 682 | break;
|
| 683 | |
| 684 | case 0x8a: /* read toc */
|
| 685 | {
|
| 686 | UINT8 track;
|
| 687 | int msfmode;
|
| 688 | UINT32 track_start;
|
| 689 |
|
| 690 | if ( cd.input_pos < 7 )
|
| 691 | return;
|
| 692 |
|
| 693 | /* stop CDDA audio if necessary */
|
| 694 | matsucd_cdda_stop();
|
| 695 | |
| 696 | track = cd.input[2];
|
| 697 | msfmode = (cd.input[1] & 0x02) ? 1 : 0;
|
| 698 | |
| 699 | if ( cd.cdrom == NULL )
|
| 700 | {
|
| 701 | logerror( "MATSUCD - Warning: Reading TOC without a CD!\n" );
|
| 702 | matsucd_command_error();
|
| 703 | return;
|
| 704 | }
|
| 705 |
|
| 706 | if ( track > cdrom_get_last_track(cd.cdrom) )
|
| 707 | {
|
| 708 | logerror( "MATSUCD - Warning: Reading invalid track entry from TOC!\n" );
|
| 709 | matsucd_command_error();
|
| 710 | return;
|
| 711 | }
|
| 712 |
|
| 713 | memset( cd.output, 0, 7 );
|
| 714 |
|
| 715 | track_start = cdrom_get_track_start(cd.cdrom, track > 0 ? (track-1) : track );
|
| 716 | if ( msfmode ) track_start = LBA2MSF( track_start );
|
| 717 | |
| 718 | cd.output[1] = cdrom_get_adr_control(cd.cdrom, track > 0 ? (track-1) : track);
|
| 719 | cd.output[2] = track;
|
| 720 | cd.output[3] = (track == 0 ) ? cdrom_get_last_track(cd.cdrom) : 0;
|
| 721 | cd.output[4] = (track_start >> 24) & 0xff;
|
| 722 | cd.output[5] = (track_start >> 16) & 0xff;
|
| 723 | cd.output[6] = (track_start >> 8) & 0xff;
|
| 724 | cd.output[7] = (track_start) & 0xff;
|
| 725 |
|
| 726 | cd.motor = 1;
|
| 727 |
|
| 728 | matsucd_complete_cmd( 8 );
|
| 729 | }
|
| 730 | break;
|
| 731 | |
| 732 | case 0x8b: /* pause audio */
|
| 733 | {
|
| 734 | if ( cd.input_pos < 7 )
|
| 735 | return;
|
| 736 |
|
| 737 | matsucd_cdda_pause( (cd.input[1] == 0) ? 1 : 0 );
|
| 738 | memset( cd.output, 0, 7 );
|
| 739 | matsucd_complete_cmd( 0 );
|
| 740 | }
|
| 741 | break;
|
| 742 | |
| 743 | case 0xa3: /* front panel */
|
| 744 | {
|
| 745 | if ( cd.input_pos < 7 )
|
| 746 | return;
|
| 747 |
|
| 748 | /* TODO: ??? */
|
| 749 | |
| 750 | memset( cd.output, 0, 7 );
|
| 751 | matsucd_complete_cmd( 0 );
|
| 752 | }
|
| 753 | break;
|
| 754 | |
| 755 | default:
|
| 756 | logerror( "MATSUCD: Unknown/inimplemented command %08x\n", cmd );
|
| 757 | break;
|
| 758 | }
|
| 759 | }
|
src/mess/drivers/3do.c
| r854 | r855 | |
| 99 | 99 | /* The 3DO has an ARM6 core which is a bit different from the current |
| 100 | 100 | ARM cpu cores. This define 'hack' can be removed once the ARM6 core |
| 101 | 101 | is fully supported. */ |
| 102 | | #define CPU_ARM6 CPU_ARM |
| 102 | #define CPU_ARM6 CPU_ARM7 |
| 103 | 103 | |
| 104 | 104 | #define X1_CLOCK 50000000 |
| 105 | 105 | #define X2_CLOCK_PAL 59000000 |
| r854 | r855 | |
| 110 | 110 | UINT32 *vram; |
| 111 | 111 | |
| 112 | 112 | static ADDRESS_MAP_START( 3do_mem, ADDRESS_SPACE_PROGRAM, 32) |
| 113 | | AM_RANGE(0x00000000, 0x001FFFFF) AM_RAM AM_BASE(&dram) /* DRAM */ |
| 113 | AM_RANGE(0x00000000, 0x001FFFFF) AM_RAMBANK(1) AM_BASE(&dram) /* DRAM */ |
| 114 | 114 | AM_RANGE(0x00200000, 0x002FFFFF) AM_RAM AM_BASE(&vram) /* VRAM */ |
| 115 | | AM_RANGE(0x03000000, 0x030FFFFF) AM_ROMBANK(1) /* BIOS */ |
| 115 | AM_RANGE(0x03000000, 0x030FFFFF) AM_ROMBANK(2) /* BIOS */ |
| 116 | 116 | AM_RANGE(0x03140000, 0x0315FFFF) AM_READWRITE(nvarea_r, nvarea_w) /* NVRAM */ |
| 117 | 117 | AM_RANGE(0x03180000, 0x031FFFFF) AM_READWRITE(unk_318_r, unk_318_w) /* ???? */ |
| 118 | | AM_RANGE(0x03200000, 0x032FFFFF) AM_READWRITE(vram_sport_r, vram_sport_w) /* special vram access1/spryte engine? */ |
| 118 | AM_RANGE(0x03200000, 0x032FFFFF) AM_READWRITE(vram_sport_r, vram_sport_w) /* special vram access1 */ |
| 119 | 119 | AM_RANGE(0x03300000, 0x033FFFFF) AM_READWRITE(madam_r, madam_w) /* address decoder */ |
| 120 | 120 | AM_RANGE(0x03400000, 0x034FFFFF) AM_READWRITE(clio_r, clio_w) /* io controller */ |
| 121 | 121 | ADDRESS_MAP_END |
| r854 | r855 | |
| 123 | 123 | INPUT_PORTS_START( 3do ) |
| 124 | 124 | INPUT_PORTS_END |
| 125 | 125 | |
| 126 | | MACHINE_RESET( 3do ) { |
| 127 | | memory_set_bankptr( 1, memory_region( REGION_USER1 ) ); |
| 128 | | /* Copy BIOS ROM data to DRAM */ |
| 129 | | memcpy( dram, memory_region( REGION_USER1 ), memory_region_length( REGION_USER1 ) ); |
| 126 | MACHINE_RESET( 3do ) |
| 127 | { |
| 128 | memory_set_bankptr(2,memory_region(REGION_USER1)); |
| 129 | |
| 130 | /* configure overlay */ |
| 131 | memory_configure_bank(1, 0, 1, dram, 0); |
| 132 | memory_configure_bank(1, 1, 1, memory_region(REGION_USER1), 0); |
| 133 | |
| 134 | /* start with overlay enabled */ |
| 135 | memory_set_bank(1, 1); |
| 136 | |
| 130 | 137 | madam_init(); |
| 131 | 138 | clio_init(); |
| 132 | 139 | } |
| r854 | r855 | |
| 166 | 173 | MACHINE_DRIVER_END |
| 167 | 174 | |
| 168 | 175 | ROM_START(3do) |
| 169 | | ROM_REGION( 0x100000, REGION_USER1, 0 ) |
| 176 | ROM_REGION32_BE( 0x100000, REGION_USER1, 0 ) |
| 170 | 177 | ROM_SYSTEM_BIOS( 0, "panafz10", "Panasonic FZ-10 R.E.A.L. 3DO Interactive Multiplayer" ) |
| 171 | 178 | ROMX_LOAD( "panafz10.bin", 0x000000, 0x100000, CRC(58242cee) SHA1(3c912300775d1ad730dc35757e279c274c0acaad), ROM_BIOS(1) ) |
| 172 | 179 | ROM_SYSTEM_BIOS( 1, "goldstar", "Goldstar 3DO Interactive Multiplayer v1.01m" ) |
| r854 | r855 | |
| 180 | 187 | ROM_END |
| 181 | 188 | |
| 182 | 189 | ROM_START(3do_pal) |
| 183 | | ROM_REGION( 0x100000, REGION_USER1, 0 ) |
| 190 | ROM_REGION32_BE( 0x100000, REGION_USER1, 0 ) |
| 184 | 191 | ROM_SYSTEM_BIOS( 0, "panafz10", "Panasonic FZ-10 R.E.A.L. 3DO Interactive Multiplayer" ) |
| 185 | 192 | ROMX_LOAD( "panafz10.bin", 0x000000, 0x100000, CRC(58242cee) SHA1(3c912300775d1ad730dc35757e279c274c0acaad), ROM_BIOS(1) ) |
| 186 | 193 | ROM_SYSTEM_BIOS( 1, "goldstar", "Goldstar 3DO Interactive Multiplayer v1.01m" ) |
src/mess/drivers/amiga.c
| r854 | r855 | |
| 14 | 14 | If we didn't map any, then we still put a mirror, but where fast-mem |
| 15 | 15 | would commence ($C00000). |
| 16 | 16 | |
| 17 | | |
| 18 | | TODO: |
| 19 | | - Reverse and add the DMAC DMA/CD-ROM controller for CDTV |
| 20 | | |
| 21 | 17 | ***************************************************************************/ |
| 22 | 18 | |
| 23 | 19 | #include "driver.h" |
| r854 | r855 | |
| 26 | 22 | #include "includes/amiga.h" |
| 27 | 23 | #include "machine/amigafdc.h" |
| 28 | 24 | #include "machine/amigakbd.h" |
| 25 | #include "machine/amigacd.h" |
| 29 | 26 | #include "machine/msm6242.h" |
| 30 | 27 | #include "devices/chd_cd.h" |
| 31 | 28 | #include "inputx.h" |
| r854 | r855 | |
| 87 | 84 | |
| 88 | 85 | static ADDRESS_MAP_START(cdtv_mem, ADDRESS_SPACE_PROGRAM, 16) |
| 89 | 86 | AM_RANGE(0x000000, 0x0fffff) AM_RAMBANK(1) AM_BASE(&amiga_chip_ram) AM_SIZE(&amiga_chip_ram_size) |
| 90 | | AM_RANGE(0x100000, 0x9fffff) AM_NOP |
| 91 | 87 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE(amiga_cia_r, amiga_cia_w) |
| 92 | 88 | AM_RANGE(0xdc0000, 0xdc003f) AM_READWRITE(amiga_clock_r, amiga_clock_w); |
| 93 | 89 | AM_RANGE(0xdc8000, 0xdc87ff) AM_RAM AM_BASE(&generic_nvram16) AM_SIZE(&generic_nvram_size) |
| r854 | r855 | |
| 216 | 212 | MDRV_CPU_PROGRAM_MAP(cdtv_mem, 0) |
| 217 | 213 | |
| 218 | 214 | MDRV_NVRAM_HANDLER(generic_0fill) |
| 215 | |
| 216 | MDRV_SOUND_ADD( CDDA, 0 ) |
| 217 | MDRV_SOUND_ROUTE( 0, "left", 1.0 ) |
| 218 | MDRV_SOUND_ROUTE( 1, "right", 1.0 ) |
| 219 | 219 | MACHINE_DRIVER_END |
| 220 | 220 | |
| 221 | 221 | static MACHINE_DRIVER_START( a1000n ) |
| r854 | r855 | |
| 352 | 352 | { |
| 353 | 353 | static const amiga_machine_interface amiga_intf = |
| 354 | 354 | { |
| 355 | | FAT_ANGUS_CHIP_RAM_MASK, |
| 355 | ECS_CHIP_RAM_MASK, |
| 356 | 356 | amiga_cia_0_portA_r, NULL, /* CIA0 port A & B read */ |
| 357 | 357 | amiga_cia_0_portA_w, NULL, /* CIA0 port A & B write */ |
| 358 | 358 | NULL, NULL, /* CIA1 port A & B read */ |
| r854 | r855 | |
| 370 | 370 | /* set up memory */ |
| 371 | 371 | memory_configure_bank(1, 0, 1, amiga_chip_ram, 0); |
| 372 | 372 | memory_configure_bank(1, 1, 1, memory_region(REGION_USER1), 0); |
| 373 | |
| 374 | /* initialize the cdrom controller */ |
| 375 | amigacd_init(); |
| 373 | 376 | } |
| 374 | 377 | |
| 375 | 378 | /*************************************************************************** |
| r854 | r855 | |
| 464 | 467 | COMP( 1985, a1000p, a1000n, 0, a1000p, amiga, amiga, amiga, "Commodore Business Machines Co.", "Commodore Amiga 1000 (PAL-OCS)", GAME_COMPUTER | GAME_IMPERFECT_GRAPHICS ) |
| 465 | 468 | COMPB( 1987, a500n, 0, amiga, 0, ntsc, amiga, amiga, amiga, "Commodore Business Machines Co.", "Commodore Amiga 500 (NTSC-OCS)", GAME_COMPUTER | GAME_IMPERFECT_GRAPHICS ) |
| 466 | 469 | COMPB( 1987, a500p, a500n, amiga, 0, pal, amiga, amiga, amiga, "Commodore Business Machines Co.", "Commodore Amiga 500 (PAL-OCS)", GAME_COMPUTER | GAME_IMPERFECT_GRAPHICS ) |
| 467 | | COMP( 1991, cdtv, 0, 0, cdtv, amiga, cdtv, cdtv, "Commodore Business Machines Co.", "Commodore Amiga CDTV (NTSC)", GAME_NOT_WORKING ) |
| 470 | COMP( 1991, cdtv, 0, 0, cdtv, amiga, cdtv, cdtv, "Commodore Business Machines Co.", "Commodore Amiga CDTV 1.0 (NTSC)", GAME_COMPUTER | GAME_IMPERFECT_GRAPHICS ) |