diff --git a/doc/notes.txt b/doc/notes.txt index 1478d060..05b7aab6 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -128,6 +128,7 @@ TODO: - nes debug view toolbar - support NES_HEADER_16K? - PPU/TIA register write visualization + - show cur/tmp vram addresses - NES crt should mark raster pos when debugging - OAMDMA in profiler? (haltCycles) - JSNES diff --git a/presets/atari7800/sprites.dasm b/presets/atari7800/sprites.dasm new file mode 100644 index 00000000..6e8735ab --- /dev/null +++ b/presets/atari7800/sprites.dasm @@ -0,0 +1,440 @@ +; Atari 7800 sprite sample +; Written by Daniel Boris (dboris@home.com) +; +; Assemble with DASM +; + + processor 6502 + +; ************ Hardware Adresses *************************** + +INPTCTRL equ $01 ;Input control +AUDC0 equ $15 ;Audio Control Channel 0 +AUDC1 equ $16 ;Audio Control Channel 1 +AUDF0 equ $17 ;Audio Frequency Channel 0 +AUDF1 equ $18 ;Audio Frequency Channel 1 +AUDV0 equ $19 ;Audio Volume Channel 0 +AUDV1 equ $1A ;Audio Volume Channel 1 +INPT0 equ $08 ;Paddle Control Input 0 +INPT1 equ $09 ;Paddle Control Input 1 +INPT2 equ $0A ;Paddle Control Input 2 +INPT3 equ $0B ;Paddle Control Input 3 +INPT4 equ $0C ;Player 0 Fire Button Input +INPT5 equ $0D ;Player 1 Fire Button Input + +BACKGRND equ $20 ;Background Color +P0C1 equ $21 ;Palette 0 - Color 1 +P0C2 equ $22 ;Palette 0 - Color 2 +P0C3 equ $23 ;Palette 0 - Color 3 +WSYNC equ $20 ;Wait For Sync +P1C1 equ $21 ;Palette 1 - Color 1 +P1C2 equ $22 ;Palette 1 - Color 2 +P1C3 equ $23 ;Palette 1 - Color 3 +MSTAT equ $28 ;Maria Status +P2C1 equ $29 ;Palette 2 - Color 1 +P2C2 equ $2A ;Palette 2 - Color 2 +P2C3 equ $2B ;Palette 2 - Color 3 +DPPH equ $2C ;Display List List Pointer High +P3C1 equ $2D ;Palette 3 - Color 1 +P3C2 equ $2E ;Palette 3 - Color 2 +P3C3 equ $2F ;Palette 3 - Color 3 +DPPL equ $30 ;Display List List Pointer Low +P4C1 equ $31 ;Palette 4 - Color 1 +P4C2 equ $32 ;Palette 4 - Color 2 +P4C3 equ $33 ;Palette 4 - Color 3 +CHARBASE equ $34 ;Character Base Address +P5C1 equ $35 ;Palette 5 - Color 1 +P5C2 equ $36 ;Palette 5 - Color 2 +P5C3 equ $37 ;Palette 5 - Color 3 +OFFSET equ $38 ;Unused - Store zero here +P6C1 equ $39 ;Palette 6 - Color 1 +P6C2 equ $3A ;Palette 6 - Color 2 +P6C3 equ $3B ;Palette 6 - Color 3 +CTRL equ $3C ;Maria Control Register +P7C1 equ $3D ;Palette 7 - Color 1 +P7C2 equ $3E ;Palette 7 - Color 2 +P7C3 equ $3F ;Palette 7 - Color 3 + +SWCHA equ $280 ;P0, P1 Joystick Directional Input +SWCHB equ $282 ;Console Switches +CTLSWA equ $281 ;I/O Control for SCHWA +CTLSWB equ $283 ;I/O Control for SCHWB + + SEG.U data + + +;******* Vairables ******************************** + + org $40 + +xpos ds.b 1 ;X Position of sprite +ypos ds.b 1 ;Y Position of sprite +temp ds.b 1 +dlpnt ds.w 1 +dlend ds.b 12 ;Index of end of each DL + + + + +;********************************************************** + + SEG code + + org $4000 ;Start of code + +START + sei ;Disable interrupts + cld ;Clear decimal mode + + +;******** Atari recommended startup procedure + + lda #$07 + sta INPTCTRL ;Lock into 7800 mode + lda #$7F + sta CTRL ;Disable DMA + lda #$00 + sta OFFSET + sta INPTCTRL + ldx #$FF ;Reset stack pointer + txs + +;************** Clear zero page and hardware ****** + + ldx #$40 + lda #$00 +crloop1 + sta $00,x ;Clear zero page + sta $100,x ;Clear page 1 + inx + bne crloop1 + +;************* Clear RAM ************************** + + ldy #$00 ;Clear Ram + lda #$18 ;Start at $1800 + sta $81 + lda #$00 + sta $80 +crloop3 + lda #$00 + sta ($80),y ;Store data + iny ;Next byte + bne crloop3 ;Branch if not done page + inc $81 ;Next page + lda $81 + cmp #$20 ;End at $1FFF + bne crloop3 ;Branch if not + + ldy #$00 ;Clear Ram + lda #$22 ;Start at $2200 + sta $81 + lda #$00 + sta $80 +crloop4 + lda #$00 + sta ($80),y ;Store data + iny ;Next byte + bne crloop4 ;Branch if not done page + inc $81 ;Next page + lda $81 + cmp #$27 ;End at $27FF + bne crloop4 ;Branch if not + + ldx #$00 + lda #$00 +crloop5 ;Clear 2100-213F + sta $2100,x + inx + cpx #$40 + bne crloop5 + +;************* Build DLL ******************* + +; 20 blank lines + + ldx #$00 + lda #$4F ;16 lines + sta $1800,x + inx + lda #$21 ;$2100 = blank DL + sta $1800,x + inx + lda #$00 + sta $1800,x + inx + lda #$44 ;4 lines + sta $1800,x + inx + lda #$21 + sta $1800,x + inx + lda #$00 + sta $1800,x + inx + +; 192 mode lines divided into 12 regions + + ldy #$00 +DLLloop2 + lda #$4F ;16 lines + sta $1800,x + inx + lda DLPOINTH,y + sta $1800,x + inx + lda DLPOINTL,y + sta $1800,x + inx + iny + cpy #$0D ;12 DLL entries + bne DLLloop2 + + +; 26 blank lines + + lda #$4F ;16 lines + sta $1800,x + inx + lda #$21 ;$2100 = blank DL + sta $1800,x + inx + lda #$00 + sta $1800,x + inx + lda #$4A ;10 lines + sta $1800,x + inx + lda #$21 + sta $1800,x + inx + lda #$00 + sta $1800,x + + +;***************** Setup Maria Registers **************** + + lda #$18 ;DLL at $1800 + sta DPPH + lda #$00 + sta DPPL + lda #$18 ;Setup Palette 0 + sta P0C1 + lda #$38 + sta P0C2 + lda #$58 + sta P0C3 + lda #$43 ;Enable DMA + sta CTRL + lda #$00 ;Setup ports to read mode + sta CTLSWA + sta CTLSWB + + lda #$40 ;Set initial X position of sprite + sta xpos + +mainloop + lda MSTAT ;Wait for VBLANK + and #$80 + beq mainloop + + lda SWCHA ;Read stick + and #$80 ;Pushed Right? + bne skip1 + ldx xpos ;Move sprite to right + inx + stx xpos +skip1 + lda SWCHA ;Read stick + and #$40 ;Pushed Left? + bne skip2 + ldx xpos ;Move sprite to left + dex + stx xpos +skip2 + lda SWCHA ;Read stick + and #$20 ;Pushed Down? + bne skip3 + ldx ypos ;Move sprite down + cpx #176 + beq skip3 ;Don't move if we are at the bottom + inx + stx ypos +skip3 + lda SWCHA ;Read stick + and #$10 ;Pushed Up? + bne skip4 + ldx ypos ;Move sprite up + beq skip4 ;Don't move if we are at the top + dex + stx ypos +skip4 + +;********************** reset DL ends ****************** + + ldx #$0C + lda #$00 +dlclearloop + dex + sta dlend,x + bne dlclearloop + + +;******************** build DL entries ********************* + + lda ypos ;Get Y position + and #$F0 + lsr ;Divide by 16 + lsr + lsr + lsr + tax + lda DLPOINTL,x ;Get pointer to DL that this sprite starts in + sta dlpnt + lda DLPOINTH,x + sta dlpnt+1 + + ;Create DL entry for upper part of sprite + + ldy dlend,x ;Get the index to the end of this DL + lda #$00 + sta (dlpnt),y ;Low byte of data address + iny + lda #$40 ;Mode 320x1 + sta (dlpnt),y + iny + lda ypos + and #$0F + ora #$a0 + sta (dlpnt),y + iny + lda #$1F ;Palette 0, 1 byte wide + sta (dlpnt),y + iny + lda xpos ;Horizontal position + sta (dlpnt),y + sty dlend,x + + lda ypos + and #$0F ;See if sprite is entirely within this region + beq doneDL ;branch if it is + + ;Create DL entry for lower part of sprite + + inx ;Next region + lda DLPOINTL,x ;Get pointer to next DL + sta dlpnt + lda DLPOINTH,x + sta dlpnt+1 + ldy dlend,x ;Get the index to the end of this DL + lda #$00 + sta (dlpnt),y + iny + lda #$40 ;Mode 320x1 + sta (dlpnt),y + iny + lda ypos + and #$0F + eor #$0F + sta temp + lda #$a0 + clc + sbc temp + sta (dlpnt),y + iny + lda #$1F ;Palette 0, 1 byte wide + sta (dlpnt),y + iny + lda xpos ;Horizontal position + sta (dlpnt),y + sty dlend,x +doneDL + +;************** add DL end entry on each DL ***************************** + + ldx #$0C +dlendloop + dex + lda DLPOINTL,x + sta dlpnt + lda DLPOINTH,x + sta dlpnt+1 + ldy dlend,x + iny + lda #$00 + sta (dlpnt),y + txa + bne dlendloop + +vbloop + lda MSTAT ;Wait for VBLANK to end + and #$80 + bne vbloop + + jmp mainloop ;Loop + +redraw + + +NMI + RTI + +IRQ + RTI + + +;Pointers to the DLs + +DLPOINTH + .byte $22,$22,$22,$22,$23,$23,$23,$23,$24,$24,$24,$24 +DLPOINTL + .byte $00,$40,$80,$C0,$00,$40,$80,$C0,$00,$40,$80,$C0 + + + + +;************** Graphic Data ***************************** + org $a000 + .byte %00111100 + org $a100 + .byte %00111100 + org $a200 + .byte %01000010 + org $a300 + .byte %01000010 + org $a400 + .byte %10011001 + org $a500 + .byte %10011001 + org $a600 + .byte %10100101 + org $a700 + .byte %10100101 + org $a800 + .byte %10000001 + org $a900 + .byte %10000001 + org $aA00 + .byte %10100101 + org $aB00 + .byte %10100101 + org $aC00 + .byte %01000010 + org $aD00 + .byte %01000010 + org $aE00 + .byte %00111100 + org $aF00 + .byte %00111100 + + +;************** Cart reset vector ************************** + + org $fff8 + .byte $FF ;Region verification + .byte $87 ;ROM start $4000 + .word #NMI + .word #START + .word #IRQ + + diff --git a/src/pixed/pixeleditor.ts b/src/pixed/pixeleditor.ts index 3aa3d995..fff7c135 100644 --- a/src/pixed/pixeleditor.ts +++ b/src/pixed/pixeleditor.ts @@ -60,7 +60,8 @@ type PixelEditorMessage = { ///////////////// -var pixel_re = /([0#]?)([x$%]|\d'h)([0-9a-f]+)|(\d'b)([01]+)/gim; +// 0xabcd, #$abcd, 5'010101, 0b010101, etc +var pixel_re = /([0#]?)([x$%]|\d'h)([0-9a-f]+)|(\d'b|0b)([01]+)/gim; function convertToHexStatements(s:string) : string { // convert 'hex ....' asm format diff --git a/src/platform/atari7800.ts b/src/platform/atari7800.ts new file mode 100644 index 00000000..5c1f5af0 --- /dev/null +++ b/src/platform/atari7800.ts @@ -0,0 +1,345 @@ +"use strict"; + +import { Platform, Base6502Platform, BaseMAMEPlatform, getOpcodeMetadata_6502, getToolForFilename_6502 } from "../baseplatform"; +import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM, getMousePos } from "../emu"; +import { hex, lzgmini, stringToByteArray, lpad, rpad, rgb2bgr } from "../util"; +import { MasterAudio, POKEYDeviceChannel, newPOKEYAudio } from "../audio"; + +declare var jt; // for 6502 + +var Atari7800_PRESETS = [ + {id:'sprites.dasm', name:'Sprites (ASM)'}, +]; + +const Atari7800_KEYCODE_MAP = makeKeycodeMap([ + [Keys.VK_SPACE, 0, 0], + [Keys.VK_ENTER, 0, 0], +]); + +// http://www.ataripreservation.org/websites/freddy.offenga/megazine/ISSUE5-PALNTSC.html +const CLK = 3579545; +const cpuFrequency = 1789772; +const linesPerFrame = 262; +const colorClocksPerLine = 228*2; +const romLength = 0xc000; + +class Atari7800Platform extends Base6502Platform implements Platform { + + mainElement : HTMLElement; + cpu; + ram : Uint8Array; + rom : Uint8Array; + bios : Uint8Array; + bus; + video; + audio; + timer : AnimationTimer; + inputs = new Uint8Array(4); + scanline : number = 0; + + constructor(mainElement : HTMLElement) { + super(); + this.mainElement = mainElement; + } + + getPresets() { + return Atari7800_PRESETS; + } + + start() { + this.cpu = new jt.M6502(); + this.ram = new Uint8Array(0x2800 - 0x1600); + this.bios = new Uint8Array(0x1000); // TODO + // TODO: TIA access wastes a cycle + this.bus = { + read: newAddressDecoder([ + [0x0040, 0x00ff, 0xffff, (a) => { return this.ram[a]; }], + [0x0140, 0x01ff, 0xffff, (a) => { return this.ram[a]; }], + [0x1800, 0x27ff, 0xffff, (a) => { return this.ram[a - 0x1600]; }], + [0x4000, 0xffff, 0xffff, (a) => { return this.rom ? this.rom[a - 0x4000] : 0; }], + //[0xf000, 0xffff, 0xfff, (a) => { return this.bios ? this.bios[a] : 0; }], + ]), + write: newAddressDecoder([ + [0x0040, 0x00ff, 0xffff, (a,v) => { this.ram[a] = v; }], + [0x0140, 0x01ff, 0xffff, (a,v) => { this.ram[a] = v; }], + [0x1800, 0x27ff, 0xffff, (a,v) => { this.ram[a - 0x1600] = v; }], + ]), + }; + this.cpu.connectBus(this.bus); + // create video/audio + this.video = new RasterVideo(this.mainElement, 320, 192); + this.audio = newPOKEYAudio(1); + this.video.create(); + setKeyboardFromMap(this.video, this.inputs, Atari7800_KEYCODE_MAP, (o,key,code,flags) => { + // TODO + }); + this.timer = new AnimationTimer(60, this.nextFrame.bind(this)); + } + + advance(novideo : boolean) { + var idata = this.video.getFrameData(); + var iofs = 0; + var debugCond = this.getDebugCallback(); + var rgb; + var freeClocks = 0; + // load controls + // TODO + //gtia.regs[0x10] = inputs[0] ^ 1; + // visible lines + for (var sl=0; sl 0) { + freeClocks--; + if (debugCond && debugCond()) { + debugCond = null; + i = 999; + sl = 999; + break; + } + this.cpu.clockPulse(); + } + } + } + // update video frame + if (!novideo) { + this.video.updateFrame(); + // set background/border color + let bkcol = 0; //gtia.regs[COLBK]; + $(this.video.canvas).css('background-color', COLORS_WEB[bkcol]); + } + } + + loadROM(title, data) { + this.rom = padBytes(data, romLength); + this.reset(); + } + + loadBIOS(title, data) { + this.bios = padBytes(data, 0x1000); + this.reset(); + } + + isRunning() { + return this.timer.isRunning(); + } + + pause() { + this.timer.stop(); + this.audio.stop(); + } + + resume() { + this.timer.start(); + this.audio.start(); + } + + reset() { + this.cpu.reset(); + /* + // execute until out of BIOS + for (var i=0; i<20000; i++) { + this.cpu.clockPulse(); + if (this.getCPUState().PC < 0xf000) + break; + } + */ + } + + readAddress(addr : number) { + return (addr < 0x1800 ? this.ram[addr] : this.bus.read(addr)) | 0; + } + + loadState(state) { + this.unfixPC(state.c); + this.cpu.loadState(state.c); + this.fixPC(state.c); + this.ram.set(state.b); + this.loadControlsState(state); + } + + saveState() { + return { + c:this.getCPUState(), + b:this.ram.slice(0), + in:this.inputs.slice(0) + }; + } + + loadControlsState(state) { + this.inputs.set(state.in); + } + + saveControlsState() { + return { + in:this.inputs.slice(0) + }; + } + + getCPUState() { + return this.fixPC(this.cpu.saveState()); + } + + getRasterScanline() { + return this.scanline; + } + + /* + getDebugCategories() { + return super.getDebugCategories().concat(['ANTIC','GTIA']); + } + getDebugInfo(category, state) { + switch (category) { + case 'ANTIC': return ANTIC.stateToLongString(state.antic); + case 'GTIA': return GTIA.stateToLongString(state.gtia); + default: return super.getDebugInfo(category, state); + } + } + */ +} + +/// + +const ATARI_NTSC_RGB = [ + 0x000000, // 00 + 0x404040, // 02 + 0x6c6c6c, // 04 + 0x909090, // 06 + 0xb0b0b0, // 08 + 0xc8c8c8, // 0A + 0xdcdcdc, // 0C + 0xf4f4f4, // 0E + 0x004444, // 10 + 0x106464, // 12 + 0x248484, // 14 + 0x34a0a0, // 16 + 0x40b8b8, // 18 + 0x50d0d0, // 1A + 0x5ce8e8, // 1C + 0x68fcfc, // 1E + 0x002870, // 20 + 0x144484, // 22 + 0x285c98, // 24 + 0x3c78ac, // 26 + 0x4c8cbc, // 28 + 0x5ca0cc, // 2A + 0x68b4dc, // 2C + 0x78c8ec, // 2E + 0x001884, // 30 + 0x183498, // 32 + 0x3050ac, // 34 + 0x4868c0, // 36 + 0x5c80d0, // 38 + 0x7094e0, // 3A + 0x80a8ec, // 3C + 0x94bcfc, // 3E + 0x000088, // 40 + 0x20209c, // 42 + 0x3c3cb0, // 44 + 0x5858c0, // 46 + 0x7070d0, // 48 + 0x8888e0, // 4A + 0xa0a0ec, // 4C + 0xb4b4fc, // 4E + 0x5c0078, // 50 + 0x74208c, // 52 + 0x883ca0, // 54 + 0x9c58b0, // 56 + 0xb070c0, // 58 + 0xc084d0, // 5A + 0xd09cdc, // 5C + 0xe0b0ec, // 5E + 0x780048, // 60 + 0x902060, // 62 + 0xa43c78, // 64 + 0xb8588c, // 66 + 0xcc70a0, // 68 + 0xdc84b4, // 6A + 0xec9cc4, // 6C + 0xfcb0d4, // 6E + 0x840014, // 70 + 0x982030, // 72 + 0xac3c4c, // 74 + 0xc05868, // 76 + 0xd0707c, // 78 + 0xe08894, // 7A + 0xeca0a8, // 7C + 0xfcb4bc, // 7E + 0x880000, // 80 + 0x9c201c, // 82 + 0xb04038, // 84 + 0xc05c50, // 86 + 0xd07468, // 88 + 0xe08c7c, // 8A + 0xeca490, // 8C + 0xfcb8a4, // 8E + 0x7c1800, // 90 + 0x90381c, // 92 + 0xa85438, // 94 + 0xbc7050, // 96 + 0xcc8868, // 98 + 0xdc9c7c, // 9A + 0xecb490, // 9C + 0xfcc8a4, // 9E + 0x5c2c00, // A0 + 0x784c1c, // A2 + 0x906838, // A4 + 0xac8450, // A6 + 0xc09c68, // A8 + 0xd4b47c, // AA + 0xe8cc90, // AC + 0xfce0a4, // AE + 0x2c3c00, // B0 + 0x485c1c, // B2 + 0x647c38, // B4 + 0x809c50, // B6 + 0x94b468, // B8 + 0xacd07c, // BA + 0xc0e490, // BC + 0xd4fca4, // BE + 0x003c00, // C0 + 0x205c20, // C2 + 0x407c40, // C4 + 0x5c9c5c, // C6 + 0x74b474, // C8 + 0x8cd08c, // CA + 0xa4e4a4, // CC + 0xb8fcb8, // CE + 0x003814, // D0 + 0x1c5c34, // D2 + 0x387c50, // D4 + 0x50986c, // D6 + 0x68b484, // D8 + 0x7ccc9c, // DA + 0x90e4b4, // DC + 0xa4fcc8, // DE + 0x00302c, // E0 + 0x1c504c, // E2 + 0x347068, // E4 + 0x4c8c84, // E6 + 0x64a89c, // E8 + 0x78c0b4, // EA + 0x88d4cc, // EC + 0x9cece0, // EE + 0x002844, // F0 + 0x184864, // F2 + 0x306884, // F4 + 0x4484a0, // F6 + 0x589cb8, // F8 + 0x6cb4d0, // FA + 0x7ccce8, // FC + 0x8ce0fc // FE +]; + +var COLORS_RGBA = new Uint32Array(256); +var COLORS_WEB = []; +for (var i=0; i<256; i++) { + COLORS_RGBA[i] = ATARI_NTSC_RGB[i>>1] | 0xff000000; + COLORS_WEB[i] = "#"+hex(rgb2bgr(ATARI_NTSC_RGB[i>>1]),6); +} + +/// + +PLATFORMS['atari7800'] = Atari7800Platform; diff --git a/src/ui.ts b/src/ui.ts index 4b3d4260..f0195c7a 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -292,7 +292,6 @@ function reloadProject(id:string) { function getSkeletonFile(fileid:string) : Promise { var ext = platform.getToolForFilename(fileid); - // TODO: .mame return $.get( "presets/"+getBasePlatform(platform_id)+"/skeleton."+ext, 'text').catch((e) => { alertError("Could not load skeleton for " + platform_id + "/" + ext + "; using blank file"); }); @@ -693,7 +692,7 @@ function get8bitworkshopLink(linkqs : string, fn : string) { } function _downloadCassetteFile(e) { - if (current_output == null) { // TODO + if (current_output == null) { alertError("Please fix errors before exporting."); return true; } @@ -730,7 +729,6 @@ function _revertFile(e) { var wnd = projectWindows.getActive(); if (wnd && wnd.setText) { var fn = projectWindows.getActiveID(); - // TODO: .mame $.get( "presets/"+getBasePlatform(platform_id)+"/"+fn, (text) => { bootbox.confirm("Reset '" + fn + "' to default?", (ok) => { if (ok) { @@ -739,7 +737,6 @@ function _revertFile(e) { }); }, 'text') .fail(() => { - // TODO: delete file alertError("Can only revert built-in files."); }); } else { @@ -1250,7 +1247,6 @@ function _recordVideo() { else if (canvas.style.transform.indexOf("rotate(90deg)") >= 0) rotate = 1; } - // TODO: recording indicator? var gif = new GIF({ workerScript: 'gif.js/dist/gif.worker.js', workers: 4, @@ -1288,7 +1284,6 @@ function _recordVideo() { }; f(); }); - //TODO? return true; } export function setFrameRateUI(fps:number) { @@ -1643,7 +1638,7 @@ function installErrorHandler() { if (error instanceof EmuHalt || msgstr.indexOf("CPU STOP") >= 0) { showErrorAlert([ {msg:msgstr, line:0} ]); uiDebugCallback(platform.saveState()); - setDebugButtonState("pause", "stopped"); // TODO? + setDebugButtonState("pause", "stopped"); } else { // send exception msg to GA var msg = msgstr; diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts index 23c14fd7..7407615f 100644 --- a/src/worker/workermain.ts +++ b/src/worker/workermain.ts @@ -259,6 +259,11 @@ var PLATFORM_PARAMS = { data_size: 50, stack_end: 0x4fce, }, + 'atari7800': { + define: '__ATARI7800__', + cfgfile: 'atari7800.cfg', + libargs: ['atari7800.lib'], + }, }; PLATFORM_PARAMS['coleco.mame'] = PLATFORM_PARAMS['coleco'];