#!/usr/bin/python ## ## license:BSD-3-Clause ## copyright-holders:Vas Crabb from . import dbaccess from . import htmltmpl import cgi import inspect import json import mimetypes import os.path import re import sys import wsgiref.simple_server import wsgiref.util if sys.version_info >= (3, ): import urllib.parse as urlparse else: import urlparse class HandlerBase(object): STATUS_MESSAGE = { 400: 'Bad Request', 401: 'Unauthorized', 403: 'Forbidden', 404: 'Not Found', 405: 'Method Not Allowed', 500: 'Internal Server Error', 501: 'Not Implemented', 502: 'Bad Gateway', 503: 'Service Unavailable', 504: 'Gateway Timeout', 505: 'HTTP Version Not Supported' } def __init__(self, app, application_uri, environ, start_response, **kwargs): super(HandlerBase, self).__init__(**kwargs) self.app = app self.js_escape = app.js_escape self.application_uri = application_uri self.environ = environ self.start_response = start_response def error_page(self, code): yield htmltmpl.ERROR_PAGE.substitute(code=cgi.escape('%d' % code), message=cgi.escape(self.STATUS_MESSAGE[code])).encode('utf-8') class ErrorPageHandler(HandlerBase): def __init__(self, code, app, application_uri, environ, start_response, **kwargs): super(ErrorPageHandler, self).__init__(app=app, application_uri=application_uri, environ=environ, start_response=start_response, **kwargs) self.code = code self.start_response('%d %s' % (self.code, self.STATUS_MESSAGE[code]), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) def __iter__(self): return self.error_page(self.code) class AssetHandler(HandlerBase): def __init__(self, directory, app, application_uri, environ, start_response, **kwargs): super(AssetHandler, self).__init__(app=app, application_uri=application_uri, environ=environ, start_response=start_response, **kwargs) self.directory = directory self.asset = wsgiref.util.shift_path_info(environ) def __iter__(self): if not self.asset: self.start_response('403 %s' % (self.STATUS_MESSAGE[403], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(403) elif self.environ['PATH_INFO']: self.start_response('404 %s' % (self.STATUS_MESSAGE[404], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(404) else: path = os.path.join(self.directory, self.asset) if not os.path.isfile(path): self.start_response('404 %s' % (self.STATUS_MESSAGE[404], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(404) elif self.environ['REQUEST_METHOD'] != 'GET': self.start_response('405 %s' % (self.STATUS_MESSAGE[405], ), [('Content-type', 'text/html; charset=utf-8'), ('Accept', 'GET, HEAD, OPTIONS'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(405) else: try: f = open(path, 'rb') type, encoding = mimetypes.guess_type(path) self.start_response('200 OK', [('Content-type', type or 'application/octet-stream'), ('Cache-Control', 'public, max-age=3600')]) return wsgiref.util.FileWrapper(f) except: self.start_response('500 %s' % (self.STATUS_MESSAGE[500], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(500) class QueryPageHandler(HandlerBase): def __init__(self, app, application_uri, environ, start_response, **kwargs): super(QueryPageHandler, self).__init__(app=app, application_uri=application_uri, environ=environ, start_response=start_response, **kwargs) self.dbcurs = app.dbconn.cursor() def machine_href(self, shortname): return cgi.escape(urlparse.urljoin(self.application_uri, 'machine/%s' % (shortname, )), True) def sourcefile_href(self, sourcefile): return cgi.escape(urlparse.urljoin(self.application_uri, 'sourcefile/%s' % (sourcefile, )), True) class MachineRpcHandlerBase(QueryPageHandler): def __init__(self, app, application_uri, environ, start_response, **kwargs): super(MachineRpcHandlerBase, self).__init__(app=app, application_uri=application_uri, environ=environ, start_response=start_response, **kwargs) self.shortname = wsgiref.util.shift_path_info(environ) def __iter__(self): if not self.shortname: self.start_response('403 %s' % (self.STATUS_MESSAGE[403], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(403) elif self.environ['PATH_INFO']: self.start_response('404 %s' % (self.STATUS_MESSAGE[404], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(404) else: machine = self.dbcurs.get_machine_id(self.shortname) if machine is None: self.start_response('404 %s' % (self.STATUS_MESSAGE[404], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(404) elif self.environ['REQUEST_METHOD'] != 'GET': self.start_response('405 %s' % (self.STATUS_MESSAGE[405], ), [('Content-type', 'text/html; charset=utf-8'), ('Accept', 'GET, HEAD, OPTIONS'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(405) else: self.start_response('200 OK', [('Content-type', 'application/json; chearset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.data_page(machine) class MachineHandler(QueryPageHandler): def __init__(self, app, application_uri, environ, start_response, **kwargs): super(MachineHandler, self).__init__(app=app, application_uri=application_uri, environ=environ, start_response=start_response, **kwargs) self.shortname = wsgiref.util.shift_path_info(environ) def __iter__(self): if not self.shortname: # could probably list machines here or something self.start_response('403 %s' % (self.STATUS_MESSAGE[403], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(403) elif self.environ['PATH_INFO']: self.start_response('404 %s' % (self.STATUS_MESSAGE[404], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(404) else: machine_info = self.dbcurs.get_machine_info(self.shortname).fetchone() if not machine_info: self.start_response('404 %s' % (self.STATUS_MESSAGE[404], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(404) elif self.environ['REQUEST_METHOD'] != 'GET': self.start_response('405 %s' % (self.STATUS_MESSAGE[405], ), [('Content-type', 'text/html; charset=utf-8'), ('Accept', 'GET, HEAD, OPTIONS'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(405) else: self.start_response('200 OK', [('Content-type', 'text/html; chearset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.machine_page(machine_info) def machine_page(self, machine_info): id = machine_info['id'] description = machine_info['description'] yield htmltmpl.MACHINE_PROLOGUE.substitute( app=self.js_escape(cgi.escape(self.application_uri, True)), assets=self.js_escape(cgi.escape(urlparse.urljoin(self.application_uri, 'static'), True)), sourcehref=self.sourcefile_href(machine_info['sourcefile']), description=cgi.escape(description), shortname=cgi.escape(self.shortname), isdevice=cgi.escape('Yes' if machine_info['isdevice'] else 'No'), runnable=cgi.escape('Yes' if machine_info['runnable'] else 'No'), sourcefile=cgi.escape(machine_info['sourcefile'])).encode('utf-8') if machine_info['year'] is not None: yield ( ' Year:%s\n' \ ' Manufacturer:%s\n' % (cgi.escape(machine_info['year']), cgi.escape(machine_info['Manufacturer']))).encode('utf-8') if machine_info['cloneof'] is not None: parent = self.dbcurs.listfull(machine_info['cloneof']).fetchone() if parent: yield ( ' Parent Machine:%s (%s)\n' % (cgi.escape('%smachine/%s' % (self.application_uri, machine_info['cloneof']), True), cgi.escape(parent[1]), cgi.escape(machine_info['cloneof']))).encode('utf-8') else: yield ( ' Parent Machine:%s\n' % (cgi.escape('%smachine/%s' % (self.application_uri, machine_info['cloneof']), True), cgi.escape(machine_info['cloneof']))).encode('utf-8') if (machine_info['romof'] is not None) and (machine_info['romof'] != machine_info['cloneof']): parent = self.dbcurs.listfull(machine_info['romof']).fetchone() if parent: yield ( ' Parent ROM set:%s (%s)\n' % (cgi.escape('%smachine/%s' % (self.application_uri, machine_info['romof']), True), cgi.escape(parent[1]), cgi.escape(machine_info['romof']))).encode('utf-8') else: yield ( ' Parent Machine:%s\n' % (cgi.escape('%smachine/%s' % (self.application_uri, machine_info['romof']), True), cgi.escape(machine_info['romof']))).encode('utf-8') unemulated = [] imperfect = [] for feature, status, overall in self.dbcurs.get_feature_flags(id): if overall == 1: imperfect.append(feature) elif overall > 1: unemulated.append(feature) if (unemulated): unemulated.sort() yield( (' Unemulated Features:%s' + (', %s' * (len(unemulated) - 1)) + '\n') % tuple(unemulated)).encode('utf-8'); if (imperfect): yield( (' Imperfect Features:%s' + (', %s' * (len(imperfect) - 1)) + '\n') % tuple(imperfect)).encode('utf-8'); yield '\n'.encode('utf-8') # allow system BIOS selection haveoptions = False for name, desc, isdef in self.dbcurs.get_biossets(id): if not haveoptions: haveoptions = True; yield htmltmpl.MACHINE_OPTIONS_HEADING.substitute().encode('utf-8') yield htmltmpl.MACHINE_BIOS_PROLOGUE.substitute().encode('utf-8') yield htmltmpl.MACHINE_BIOS_OPTION.substitute( name=cgi.escape(name, True), description=cgi.escape(desc), isdefault=('yes' if isdef else 'no')).encode('utf-8') if haveoptions: yield '\n\n'.encode('utf-8') # placeholder for machine slots - populated by client-side JavaScript if self.dbcurs.count_slots(id): if not haveoptions: haveoptions = True yield htmltmpl.MACHINE_OPTIONS_HEADING.substitute().encode('utf-8') yield htmltmpl.MACHINE_SLOTS_PLACEHOLDER.substitute( machine=self.js_escape(self.shortname)).encode('utf=8') # list devices referenced by this system/device first = True for name, desc, src in self.dbcurs.get_devices_referenced(id): if first: yield \ '

Devices Referenced

\n' \ '\n' \ ' \n' \ ' \n' \ ' \n' \ ' \n'.encode('utf-8') first = False yield self.machine_row(name, desc, src) if not first: yield htmltmpl.SORTABLE_TABLE_EPILOGUE.substitute(id='tbl-dev-refs').encode('utf-8') # list slots where this device is an option first = True for name, desc, slot, opt, src in self.dbcurs.get_compatible_slots(id): if (first): yield \ '

Compatible Slots

\n' \ '
Short nameDescriptionSource file
\n' \ ' \n' \ ' \n' \ ' \n' \ ' \n'.encode('utf-8') first = False yield htmltmpl.COMPATIBLE_SLOT_ROW.substitute( machinehref=self.machine_href(name), sourcehref=self.sourcefile_href(src), shortname=cgi.escape(name), description=cgi.escape(desc), sourcefile=cgi.escape(src), slot=cgi.escape(slot), slotoption=cgi.escape(opt)).encode('utf-8') if not first: yield htmltmpl.SORTABLE_TABLE_EPILOGUE.substitute(id='tbl-comp-slots').encode('utf-8') # list systems/devices that reference this device first = True for name, desc, src in self.dbcurs.get_device_references(id): if first: yield \ '

Referenced By

\n' \ '
Short nameDescriptionSlotChoiceSource file
\n' \ ' \n' \ ' \n' \ ' \n' \ ' \n'.encode('utf-8') first = False yield self.machine_row(name, desc, src) if not first: yield htmltmpl.SORTABLE_TABLE_EPILOGUE.substitute(id='tbl-ref-by').encode('utf-8') yield '\n'.encode('utf-8') def machine_row(self, shortname, description, sourcefile): return (htmltmpl.MACHINE_ROW if description is not None else htmltmpl.EXCL_MACHINE_ROW).substitute( machinehref=self.machine_href(shortname), sourcehref=self.sourcefile_href(sourcefile), shortname=cgi.escape(shortname), description=cgi.escape(description or ''), sourcefile=cgi.escape(sourcefile or '')).encode('utf-8') class SourceFileHandler(QueryPageHandler): def __init__(self, app, application_uri, environ, start_response, **kwargs): super(SourceFileHandler, self).__init__(app=app, application_uri=application_uri, environ=environ, start_response=start_response, **kwargs) def __iter__(self): self.filename = self.environ['PATH_INFO'] if self.filename and (self.filename[0] == '/'): self.filename = self.filename[1:] if not self.filename: if self.environ['REQUEST_METHOD'] != 'GET': self.start_response('405 %s' % (self.STATUS_MESSAGE[405], ), [('Content-type', 'text/html; charset=utf-8'), ('Accept', 'GET, HEAD, OPTIONS'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(405) else: self.start_response('200 OK', [('Content-type', 'text/html; chearset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.sourcefile_listing_page(None) else: id = self.dbcurs.get_sourcefile_id(self.filename) if id is None: if ('*' not in self.filename) and ('?' not in self.filename) and ('?' not in self.filename): self.filename += '*' if self.filename[-1] == '/' else '/*' if not self.dbcurs.count_sourcefiles(self.filename): self.start_response('404 %s' % (self.STATUS_MESSAGE[404], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(404) elif self.environ['REQUEST_METHOD'] != 'GET': self.start_response('405 %s' % (self.STATUS_MESSAGE[405], ), [('Content-type', 'text/html; charset=utf-8'), ('Accept', 'GET, HEAD, OPTIONS'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(405) else: self.start_response('200 OK', [('Content-type', 'text/html; chearset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.sourcefile_listing_page(self.filename) else: self.start_response('404 %s' % (self.STATUS_MESSAGE[404], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(404) elif self.environ['REQUEST_METHOD'] != 'GET': self.start_response('405 %s' % (self.STATUS_MESSAGE[405], ), [('Content-type', 'text/html; charset=utf-8'), ('Accept', 'GET, HEAD, OPTIONS'), ('Cache-Control', 'public, max-age=3600')]) return self.error_page(405) else: self.start_response('200 OK', [('Content-type', 'text/html; chearset=utf-8'), ('Cache-Control', 'public, max-age=3600')]) return self.sourcefile_page(id) def sourcefile_listing_page(self, pattern): if not pattern: title = heading = 'All Source Files' else: heading = self.linked_title(pattern) title = 'Source Files: ' + cgi.escape(pattern) yield htmltmpl.SOURCEFILE_LIST_PROLOGUE.substitute( assets=cgi.escape(urlparse.urljoin(self.application_uri, 'static'), True), title=title, heading=heading).encode('utf-8') for filename, machines in self.dbcurs.get_sourcefiles(pattern): yield htmltmpl.SOURCEFILE_LIST_ROW.substitute( sourcefile=self.linked_title(filename, True), machines=cgi.escape('%d' % machines)).encode('utf-8') yield ' \n
Short nameDescriptionSource file
\n\n\n\n'.encode('utf-8') def sourcefile_page(self, id): yield htmltmpl.SOURCEFILE_PROLOGUE.substitute( assets=cgi.escape(urlparse.urljoin(self.application_uri, 'static'), True), filename=cgi.escape(self.filename), title=self.linked_title(self.filename)).encode('utf-8') first = True for machine_info in self.dbcurs.get_sourcefile_machines(id): if first: yield \ '\n' \ ' \n' \ ' \n' \ ' \n' \ ' \n' \ ' \n' \ ' \n' \ ' \n' \ ' \n' \ ' \n' \ ' \n' \ ' \n'.encode('utf-8') first = False yield self.machine_row(machine_info) if first: yield '

No machines found.

\n'.encode('utf-8') else: yield ' \n
Short nameDescriptionYearManufacturerRunnableParent
\n\n'.encode('utf-8') yield '\n\n'.encode('utf-8') def linked_title(self, filename, linkfinal=False): parts = filename.split('/') final = parts[-1] del parts[-1] uri = urlparse.urljoin(self.application_uri, 'sourcefile') title = '' for part in parts: uri = urlparse.urljoin(uri + '/', part) title += '{1}/'.format(cgi.escape(uri, True), cgi.escape(part)) if linkfinal: uri = urlparse.urljoin(uri + '/', final) return title + '{1}'.format(cgi.escape(uri, True), cgi.escape(final)) else: return title + final def machine_row(self, machine_info): return (htmltmpl.SOURCEFILE_ROW_PARENT if machine_info['cloneof'] is None else htmltmpl.SOURCEFILE_ROW_CLONE).substitute( machinehref=self.machine_href(machine_info['shortname']), parenthref=self.machine_href(machine_info['cloneof'] or '__invalid'), shortname=cgi.escape(machine_info['shortname']), description=cgi.escape(machine_info['description']), year=cgi.escape(machine_info['year'] or ''), manufacturer=cgi.escape(machine_info['manufacturer'] or ''), runnable=cgi.escape('Yes' if machine_info['runnable'] else 'No'), parent=cgi.escape(machine_info['cloneof'] or '')).encode('utf-8') class BiosRpcHandler(MachineRpcHandlerBase): def data_page(self, machine): result = { } for name, description, isdefault in self.dbcurs.get_biossets(machine): result[name] = { 'description': description, 'isdefault': True if isdefault else False } yield json.dumps(result).encode('utf-8') class FlagsRpcHandler(MachineRpcHandlerBase): def data_page(self, machine): result = { 'features': { } } for feature, status, overall in self.dbcurs.get_feature_flags(machine): detail = { } if status == 1: detail['status'] = 'imperfect' elif status > 1: detail['status'] = 'unemulated' if overall == 1: detail['overall'] = 'imperfect' elif overall > 1: detail['overall'] = 'unemulated' result['features'][feature] = detail yield json.dumps(result).encode('utf-8') class SlotsRpcHandler(MachineRpcHandlerBase): def data_page(self, machine): result = { 'defaults': { }, 'slots': { } } # get defaults and slot options for slot, default in self.dbcurs.get_slot_defaults(machine): result['defaults'][slot] = default prev = None for slot, option, shortname, description in self.dbcurs.get_slot_options(machine): if slot != prev: if slot in result['slots']: options = result['slots'][slot] else: options = { } result['slots'][slot] = options prev = slot options[option] = { 'device': shortname, 'description': description } # remove slots that come from default cards in other slots for slot in tuple(result['slots'].keys()): slot += ':' for candidate in tuple(result['slots'].keys()): if candidate.startswith(slot): del result['slots'][candidate] yield json.dumps(result).encode('utf-8') class MiniMawsApp(object): JS_ESCAPE = re.compile('([\"\'\\\\])') RPC_SERVICES = { 'bios': BiosRpcHandler, 'flags': FlagsRpcHandler, 'slots': SlotsRpcHandler } def __init__(self, dbfile, **kwargs): super(MiniMawsApp, self).__init__(**kwargs) self.dbconn = dbaccess.QueryConnection(dbfile) self.assetsdir = os.path.join(os.path.dirname(inspect.getfile(self.__class__)), 'assets') if not mimetypes.inited: mimetypes.init() def __call__(self, environ, start_response): application_uri = wsgiref.util.application_uri(environ) module = wsgiref.util.shift_path_info(environ) if module == 'machine': return MachineHandler(self, application_uri, environ, start_response) elif module == 'sourcefile': return SourceFileHandler(self, application_uri, environ, start_response) elif module == 'static': return AssetHandler(self.assetsdir, self, application_uri, environ, start_response) elif module == 'rpc': service = wsgiref.util.shift_path_info(environ) if not service: return ErrorPageHandler(403, self, application_uri, environ, start_response) elif service in self.RPC_SERVICES: return self.RPC_SERVICES[service](self, application_uri, environ, start_response) else: return ErrorPageHandler(404, self, application_uri, environ, start_response) elif not module: return ErrorPageHandler(403, self, application_uri, environ, start_response) else: return ErrorPageHandler(404, self, application_uri, environ, start_response) def js_escape(self, str): return self.JS_ESCAPE.sub('\\\\\\1', str).replace('\0', '\\0') def run_server(options): application = MiniMawsApp(options.database) server = wsgiref.simple_server.make_server(options.host, options.port, application) try: server.serve_forever() except KeyboardInterrupt: pass 644' href='#n644'>644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
/***************************************************************************

"Combat School" (also known as "Boot Camp") - (Konami GX611)

TODO:
- in combasc (and more generally the 007121) the number of sprites can be
  increased from 0x40 to 0x80. There is a hack in konamiic.c to handle that,
  but it is wrong. If you don't pass the Iron Man stage, a few sprites are
  left dangling on the screen.(*not a bug, 64 sprites are the maximum)
- it seems that to get correct target colors in firing range III we have to
  use the WRONG lookup table (the one for tiles instead of the one for
  sprites).
- in combascb, wrong sprite/char priority (see cpu head at beginning of arm
  wrestling, and heads in intermission after firing range III)
- hook up sound in bootleg (the current sound is a hack, making use of the
  Konami ROMset)
- understand how the trackball really works
- YM2203 pitch is wrong. Fixing it screws up the tempo.

  Update: 3MHz(24MHz/8) is the more appropriate clock speed for the 2203.
  It gives the correct pitch(ear subjective) compared to the official
  soundtrack albeit the music plays slow by about 10%.

  Execution timing of the Z80 is important because it maintains music tempo
  by polling the 2203's second timer. Even when working alone with no
  context-switch the chip shouldn't be running at 1.5MHz otherwise it won't
  keep the right pace. Similar Konmai games from the same period(mainevt,
  battlnts, flkatck...etc.) all have a 3.579545MHz Z80 for sound.

  In spite of adjusting clock speed polling is deemed inaccurate when
  interleaving is taken into account. A high resolution timer around the
  poll loop is probably the best bet. The driver sets its timer manually
  because strange enough, interleaving doesn't occur immediately when
  cpuexec_boost_interleave() is called. Speculations are TIME_NOWs could have
  been used as the timer durations to force instant triggering.


Credits:

    Hardware Info:
        Jose Tejada Gomez
        Manuel Abadia
        Cesareo Gutierrez

    MAME Driver:
        Phil Stroffolino
        Manuel Abadia

Memory Maps (preliminary):

***************************
* Combat School (bootleg) *
***************************

MAIN CPU:
---------
00c0-00c3   Objects control
0500        bankswitch control
0600-06ff   palette
0800-1fff   RAM
2000-2fff   Video RAM (banked)
3000-3fff   Object RAM (banked)
4000-7fff   Banked Area + IO + Video Registers
8000-ffff   ROM

SOUND CPU:
----------
0000-8000   ROM
8000-87ef   RAM
87f0-87ff   ???
9000-9001   YM2203
9008        ???
9800        OKIM5205?
a000        soundlatch?
a800        OKIM5205?
fffc-ffff   ???


        Notes about the sound systsem of the bootleg:
        ---------------------------------------------
        The positions 0x87f0-0x87ff are very important, it
        does work similar to a semaphore (same as a lot of
        vblank bits). For example in the init code, it writes
        zero to 0x87fa, then it waits to it 'll be different
        to zero, but it isn't written by this cpu. (shareram?)
        I have tried put here a K007232 chip, but it didn't
        work.

        Sound chips: OKI M5205 & YM2203

        We are using the other sound hardware for now.

****************************
* Combat School (Original) *
****************************

0000-005f   Video Registers (banked)
0400-0407   input ports
0408        coin counters
0410        bankswitch control
0600-06ff   palette
0800-1fff   RAM
2000-2fff   Video RAM (banked)
3000-3fff   Object RAM (banked)
4000-7fff   Banked Area + IO + Video Registers
8000-ffff   ROM

SOUND CPU:
----------
0000-8000   ROM
8000-87ff   RAM
9000        uPD7759
b000        uPD7759
c000        uPD7759
d000        soundlatch_r
e000-e001   YM2203


2008-08:
Dip location and recommended settings verified with the US manual

***************************************************************************/

#include "driver.h"
#include "cpu/hd6309/hd6309.h"
#include "cpu/z80/z80.h"
#include "sound/2203intf.h"
#include "sound/upd7759.h"

/* from video/combasc.c */
PALETTE_INIT( combasc );
PALETTE_INIT( combascb );
READ8_HANDLER( combasc_video_r );
WRITE8_HANDLER( combasc_video_w );
VIDEO_START( combasc );
VIDEO_START( combascb );

WRITE8_HANDLER( combascb_bankselect_w );
WRITE8_HANDLER( combasc_bankselect_w );
MACHINE_RESET( combasc );
MACHINE_RESET( combascb );
WRITE8_HANDLER( combasc_pf_control_w );
READ8_HANDLER( combasc_scrollram_r );
WRITE8_HANDLER( combasc_scrollram_w );

VIDEO_UPDATE( combascb );
VIDEO_UPDATE( combasc );
WRITE8_HANDLER( combasc_io_w );
WRITE8_HANDLER( combasc_vreg_w );




static WRITE8_HANDLER( combasc_coin_counter_w )
{
	/* b7-b3: unused? */
	/* b1: coin counter 2 */
	/* b0: coin counter 1 */

	coin_counter_w(0,data & 0x01);
	coin_counter_w(1,data & 0x02);
}

static READ8_HANDLER( trackball_r )
{
	static UINT8 pos[4],sign[4];

	if (offset == 0)
	{
		int i,dir[4];
		static const char *const tracknames[] = { "TRACK0_Y", "TRACK0_X", "TRACK1_Y", "TRACK1_X" };

		for (i = 0; i < 4; i++)
		{
			UINT8 curr;

			curr = input_port_read_safe(space->machine, tracknames[i], 0xff);

			dir[i] = curr - pos[i];
			sign[i] = dir[i] & 0x80;
			pos[i] = curr;
		}

		/* fix sign for orthogonal movements */
		if (dir[0] || dir[1])
		{
			if (!dir[0]) sign[0] = sign[1] ^ 0x80;
			if (!dir[1]) sign[1] = sign[0];
		}
		if (dir[2] || dir[3])
		{
			if (!dir[2]) sign[2] = sign[3] ^ 0x80;
			if (!dir[3]) sign[3] = sign[2];
		}
	}

	return sign[offset] | (pos[offset] & 0x7f);
}


/* the protection is a simple multiply */
static int prot[2];

static WRITE8_HANDLER( protection_w )
{
	prot[offset] = data;
}
static READ8_HANDLER( protection_r )
{
	return ((prot[0] * prot[1]) >> (offset * 8)) & 0xff;
}
static WRITE8_HANDLER( protection_clock_w )
{
	/* 0x3f is written here every time before accessing the other registers */
}


/****************************************************************************/

static WRITE8_HANDLER( combasc_sh_irqtrigger_w )
{
	cpu_set_input_line_and_vector(space->machine->cpu[1],0,HOLD_LINE,0xff);
}

static READ8_DEVICE_HANDLER( combasc_busy_r )
{
	return upd7759_busy_r(device) ? 1 : 0;
}

static WRITE8_DEVICE_HANDLER( combasc_play_w )
{
	upd7759_start_w(device, data & 2);
}

static WRITE8_DEVICE_HANDLER( combasc_voice_reset_w )
{
    upd7759_reset_w(device,data & 1);
}

static WRITE8_DEVICE_HANDLER( combasc_portA_w )
{
	/* unknown. always write 0 */
}

static emu_timer *combasc_interleave_timer;

static READ8_DEVICE_HANDLER ( combasc_ym2203_r )
{
	static int boost = 1;
	int status = ym2203_r(device,offset);

	if (cpu_get_pc(device->machine->cpu[1]) == 0x334)
	{
		if (boost)
		{
			boost = 0;
			timer_adjust_periodic(combasc_interleave_timer, attotime_zero, 0, cpu_clocks_to_attotime(device->machine->cpu[1],80));
		}
		else if (status & 2)
		{
			boost = 1;
			timer_adjust_oneshot(combasc_interleave_timer, attotime_zero, 0);
		}
	}

	return(status);
}

/****************************************************************************/

static ADDRESS_MAP_START( combasc_readmem, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0020, 0x005f) AM_READ(combasc_scrollram_r)
	AM_RANGE(0x0200, 0x0201) AM_READ(protection_r)
	AM_RANGE(0x0400, 0x0400) AM_READ_PORT("IN0")
	AM_RANGE(0x0401, 0x0401) AM_READ_PORT("DSW3")			/* DSW #3 */
	AM_RANGE(0x0402, 0x0402) AM_READ_PORT("DSW1")			/* DSW #1 */
	AM_RANGE(0x0403, 0x0403) AM_READ_PORT("DSW2")			/* DSW #2 */
	AM_RANGE(0x0404, 0x0407) AM_READ(trackball_r)			/* 1P & 2P controls / trackball */
	AM_RANGE(0x0600, 0x06ff) AM_READ(SMH_RAM)				/* palette */
	AM_RANGE(0x0800, 0x1fff) AM_READ(SMH_RAM)
	AM_RANGE(0x2000, 0x3fff) AM_READ(combasc_video_r)
	AM_RANGE(0x4000, 0x7fff) AM_READ(SMH_BANK1)				/* banked ROM area */
	AM_RANGE(0x8000, 0xffff) AM_READ(SMH_ROM)				/* ROM */
ADDRESS_MAP_END

static ADDRESS_MAP_START( combasc_writemem, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x0007) AM_WRITE(combasc_pf_control_w)
	AM_RANGE(0x0020, 0x005f) AM_WRITE(combasc_scrollram_w)
//  AM_RANGE(0x0060, 0x00ff) AM_WRITE(SMH_RAM)                 /* RAM */
	AM_RANGE(0x0200, 0x0201) AM_WRITE(protection_w)
	AM_RANGE(0x0206, 0x0206) AM_WRITE(protection_clock_w)
	AM_RANGE(0x0408, 0x0408) AM_WRITE(combasc_coin_counter_w)	/* coin counters */
	AM_RANGE(0x040c, 0x040c) AM_WRITE(combasc_vreg_w)
	AM_RANGE(0x0410, 0x0410) AM_WRITE(combasc_bankselect_w)
	AM_RANGE(0x0414, 0x0414) AM_WRITE(soundlatch_w)
	AM_RANGE(0x0418, 0x0418) AM_WRITE(combasc_sh_irqtrigger_w)
	AM_RANGE(0x041c, 0x041c) AM_WRITE(watchdog_reset_w)			/* watchdog reset? */
	AM_RANGE(0x0600, 0x06ff) AM_WRITE(SMH_RAM) AM_BASE(&paletteram)
	AM_RANGE(0x0800, 0x1fff) AM_WRITE(SMH_RAM)					/* RAM */
	AM_RANGE(0x2000, 0x3fff) AM_WRITE(combasc_video_w)
	AM_RANGE(0x4000, 0x7fff) AM_WRITE(SMH_ROM)					/* banked ROM area */
	AM_RANGE(0x8000, 0xffff) AM_WRITE(SMH_ROM)					/* ROM */
ADDRESS_MAP_END

static ADDRESS_MAP_START( combascb_readmem, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x04ff) AM_READ(SMH_RAM)
	AM_RANGE(0x0600, 0x06ff) AM_READ(SMH_RAM)	/* palette */
	AM_RANGE(0x0800, 0x1fff) AM_READ(SMH_RAM)
	AM_RANGE(0x2000, 0x3fff) AM_READ(combasc_video_r)
	AM_RANGE(0x4000, 0x7fff) AM_READ(SMH_BANK1)				/* banked ROM/RAM area */
	AM_RANGE(0x8000, 0xffff) AM_READ(SMH_ROM)				/* ROM */
ADDRESS_MAP_END

static ADDRESS_MAP_START( combascb_writemem, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x04ff) AM_WRITE(SMH_RAM)
	AM_RANGE(0x0500, 0x0500) AM_WRITE(combascb_bankselect_w)
	AM_RANGE(0x0600, 0x06ff) AM_WRITE(SMH_RAM) AM_BASE(&paletteram)
	AM_RANGE(0x0800, 0x1fff) AM_WRITE(SMH_RAM)
	AM_RANGE(0x2000, 0x3fff) AM_WRITE(combasc_video_w)
	AM_RANGE(0x4000, 0x7fff) AM_WRITE(SMH_BANK1) /* banked ROM/RAM area */
	AM_RANGE(0x8000, 0xffff) AM_WRITE(SMH_ROM)				/* ROM */
ADDRESS_MAP_END

#if 0
static ADDRESS_MAP_START( readmem_sound, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x7fff) AM_READ(SMH_ROM)					/* ROM */
	AM_RANGE(0x8000, 0x87ef) AM_READ(SMH_RAM)					/* RAM */
	AM_RANGE(0x87f0, 0x87ff) AM_READ(SMH_RAM)					/* ??? */
	AM_RANGE(0x9000, 0x9001) AM_DEVREAD("ym", ym2203_r)	/* YM 2203 */
	AM_RANGE(0x9008, 0x9009) AM_DEVREAD("ym", ym2203_r)	/* ??? */
	AM_RANGE(0xa000, 0xa000) AM_READ(soundlatch_r)				/* soundlatch_r? */
	AM_RANGE(0x8800, 0xfffb) AM_READ(SMH_ROM)					/* ROM? */
	AM_RANGE(0xfffc, 0xffff) AM_READ(SMH_RAM)					/* ??? */
ADDRESS_MAP_END

static ADDRESS_MAP_START( writemem_sound, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x7fff) AM_WRITE(SMH_ROM)				/* ROM */
	AM_RANGE(0x8000, 0x87ef) AM_WRITE(SMH_RAM)				/* RAM */
	AM_RANGE(0x87f0, 0x87ff) AM_WRITE(SMH_RAM)				/* ??? */
 	AM_RANGE(0x9000, 0x9001) AM_DEVWRITE("ym", ym2203_w)	/* YM 2203 */
	//AM_RANGE(0x9800, 0x9800) AM_WRITE(combasc_unknown_w_1)    /* OKIM5205? */
	//AM_RANGE(0xa800, 0xa800) AM_WRITE(combasc_unknown_w_2)    /* OKIM5205? */
	AM_RANGE(0x8800, 0xfffb) AM_WRITE(SMH_ROM)				/* ROM */
	AM_RANGE(0xfffc, 0xffff) AM_WRITE(SMH_RAM)				/* ??? */
ADDRESS_MAP_END
#endif

static ADDRESS_MAP_START( combasc_readmem_sound, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x7fff) AM_READ(SMH_ROM)					/* ROM */
	AM_RANGE(0x8000, 0x87ff) AM_READ(SMH_RAM)					/* RAM */
	AM_RANGE(0xb000, 0xb000) AM_DEVREAD("upd", combasc_busy_r)	/* upd7759 busy? */
	AM_RANGE(0xd000, 0xd000) AM_READ(soundlatch_r)				/* soundlatch_r? */
	AM_RANGE(0xe000, 0xe001) AM_DEVREAD("ym", combasc_ym2203_r)	/* YM 2203 intercepted */
ADDRESS_MAP_END

static ADDRESS_MAP_START( combasc_writemem_sound, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x7fff) AM_WRITE(SMH_ROM)				/* ROM */
	AM_RANGE(0x8000, 0x87ff) AM_WRITE(SMH_RAM)				/* RAM */
	AM_RANGE(0x9000, 0x9000) AM_DEVWRITE("upd", combasc_play_w)			/* upd7759 play voice */
	AM_RANGE(0xa000, 0xa000) AM_DEVWRITE("upd", upd7759_port_w)			/* upd7759 voice select */
	AM_RANGE(0xc000, 0xc000) AM_DEVWRITE("upd", combasc_voice_reset_w)	/* upd7759 reset? */
 	AM_RANGE(0xe000, 0xe001) AM_DEVWRITE("ym", ym2203_w)	/* YM 2203 */
ADDRESS_MAP_END


static INPUT_PORTS_START( common_inputs )
	PORT_START("IN0")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START1 )
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN1 )
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN2 )
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_COIN3 )
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )

	PORT_START("DSW3")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START2 )
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
	PORT_DIPNAME( 0x10, 0x10, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW3:1")
	PORT_DIPSETTING(	0x10, DEF_STR( Off ) )
	PORT_DIPSETTING(	0x00, DEF_STR( On )  )
	PORT_DIPUNKNOWN_DIPLOC( 0x20, 0x00, "SW3:2" )	/* Not Used according to the manual */
	PORT_SERVICE_DIPLOC( 0x40, IP_ACTIVE_LOW, "SW3:3" )
	PORT_DIPUNKNOWN_DIPLOC( 0x80, 0x00, "SW3:4" )	/* Not Used according to the manual */
INPUT_PORTS_END

static INPUT_PORTS_START( dips )
	PORT_START("DSW1")
	PORT_DIPNAME( 0x0f, 0x0f, DEF_STR( Coin_A ) ) PORT_DIPLOCATION("SW1:1,2,3,4")
	PORT_DIPSETTING(    0x02, DEF_STR( 4C_1C ) )
	PORT_DIPSETTING(    0x05, DEF_STR( 3C_1C ) )
	PORT_DIPSETTING(    0x08, DEF_STR( 2C_1C ) )
	PORT_DIPSETTING(    0x04, DEF_STR( 3C_2C ) )
	PORT_DIPSETTING(    0x01, DEF_STR( 4C_3C ) )
	PORT_DIPSETTING(    0x0f, DEF_STR( 1C_1C ) )
	PORT_DIPSETTING(    0x03, DEF_STR( 3C_4C ) )
	PORT_DIPSETTING(    0x07, DEF_STR( 2C_3C ) )
	PORT_DIPSETTING(    0x0e, DEF_STR( 1C_2C ) )
	PORT_DIPSETTING(    0x06, DEF_STR( 2C_5C ) )
	PORT_DIPSETTING(    0x0d, DEF_STR( 1C_3C ) )
	PORT_DIPSETTING(    0x0c, DEF_STR( 1C_4C ) )
	PORT_DIPSETTING(    0x0b, DEF_STR( 1C_5C ) )
	PORT_DIPSETTING(    0x0a, DEF_STR( 1C_6C ) )
	PORT_DIPSETTING(    0x09, DEF_STR( 1C_7C ) )
	PORT_DIPSETTING(    0x00, DEF_STR( Free_Play ) )
	PORT_DIPNAME( 0xf0, 0xf0, DEF_STR( Coin_B ) ) PORT_DIPLOCATION("SW1:5,6,7,8")
	PORT_DIPSETTING(    0x20, DEF_STR( 4C_1C ) )
	PORT_DIPSETTING(    0x50, DEF_STR( 3C_1C ) )
	PORT_DIPSETTING(    0x80, DEF_STR( 2C_1C ) )
	PORT_DIPSETTING(    0x40, DEF_STR( 3C_2C ) )
	PORT_DIPSETTING(    0x10, DEF_STR( 4C_3C ) )
	PORT_DIPSETTING(    0xf0, DEF_STR( 1C_1C ) )
	PORT_DIPSETTING(    0x30, DEF_STR( 3C_4C ) )
	PORT_DIPSETTING(    0x70, DEF_STR( 2C_3C ) )
	PORT_DIPSETTING(    0xe0, DEF_STR( 1C_2C ) )
	PORT_DIPSETTING(    0x60, DEF_STR( 2C_5C ) )
	PORT_DIPSETTING(    0xd0, DEF_STR( 1C_3C ) )
	PORT_DIPSETTING(    0xc0, DEF_STR( 1C_4C ) )
	PORT_DIPSETTING(    0xb0, DEF_STR( 1C_5C ) )
	PORT_DIPSETTING(    0xa0, DEF_STR( 1C_6C ) )
	PORT_DIPSETTING(    0x90, DEF_STR( 1C_7C ) )
	PORT_DIPSETTING(    0x00, "coin 2 invalidity" )

	PORT_START("DSW2")
	PORT_DIPUNKNOWN_DIPLOC( 0x01, 0x01, "SW2:1" )	/* Not Used according to the manual */
	PORT_DIPUNKNOWN_DIPLOC( 0x02, 0x02, "SW2:2" )	/* Not Used according to the manual */
	PORT_DIPNAME( 0x04, 0x00, DEF_STR( Cabinet ) ) PORT_DIPLOCATION("SW2:3")
	PORT_DIPSETTING(	0x00, DEF_STR( Upright ) )
	PORT_DIPSETTING(	0x04, DEF_STR( Cocktail ) )
	PORT_DIPUNKNOWN_DIPLOC( 0x08, 0x08, "SW2:4" )	/* Not Used according to the manual */
	PORT_DIPUNKNOWN_DIPLOC( 0x10, 0x10, "SW2:5" )	/* Not Used according to the manual */
	PORT_DIPNAME( 0x60, 0x40, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW2:6,7")
	PORT_DIPSETTING( 0x60, DEF_STR( Easy ) )
	PORT_DIPSETTING( 0x40, DEF_STR( Normal ) )
	PORT_DIPSETTING( 0x20, "Difficult" )
	PORT_DIPSETTING( 0x00, "Very Difficult" )
	PORT_DIPNAME( 0x80, 0x00, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW2:8")
	PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
	PORT_DIPSETTING( 0x00, DEF_STR( On ) )
INPUT_PORTS_END

static INPUT_PORTS_START( combasc )
	PORT_INCLUDE( dips )

	PORT_INCLUDE( common_inputs )

	PORT_START("IN1")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
INPUT_PORTS_END

static INPUT_PORTS_START( combasct )
	PORT_INCLUDE( dips )

	PORT_INCLUDE( common_inputs )

	/* trackball 1P */
	PORT_START("TRACK0_Y")
	PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(10) PORT_KEYDELTA(10) PORT_REVERSE PORT_PLAYER(1)

	PORT_START("TRACK0_X")
	PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(10) PORT_KEYDELTA(10) PORT_PLAYER(1)

	/* trackball 2P (not implemented yet) */
	PORT_START("TRACK1_Y")
	PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(10) PORT_KEYDELTA(10) PORT_REVERSE PORT_PLAYER(2)

	PORT_START("TRACK1_X")
	PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(10) PORT_KEYDELTA(10) PORT_PLAYER(2)
INPUT_PORTS_END

static INPUT_PORTS_START( combascb )
	PORT_INCLUDE( dips )

	PORT_MODIFY("DSW2")
	PORT_DIPUNKNOWN_DIPLOC( 0x04, 0x00, "SW2:3" )
	PORT_DIPNAME( 0x10, 0x00, DEF_STR( Allow_Continue ) ) PORT_DIPLOCATION("SW2:5")
	PORT_DIPSETTING(	0x10, DEF_STR( No ) )
	PORT_DIPSETTING(	0x00, DEF_STR( Yes ) )

	PORT_START("IN0")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START1 )
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN1 )
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN2 )
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START2 )

	PORT_START("IN1")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
INPUT_PORTS_END



static const gfx_layout gfxlayout =
{
	8,8,
	0x4000,
	4,
	{ 0,1,2,3 },
	{ 0, 4, 8, 12, 16, 20, 24, 28},
	{ 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
	32*8
};

static const gfx_layout tile_layout =
{
	8,8,
	0x2000, /* number of tiles */
	4,		/* bitplanes */
	{ 0*0x10000*8, 1*0x10000*8, 2*0x10000*8, 3*0x10000*8 }, /* plane offsets */
	{ 0,1,2,3,4,5,6,7 },
	{ 0*8,1*8,2*8,3*8,4*8,5*8,6*8,7*8 },
	8*8
};

static const gfx_layout sprite_layout =
{
	16,16,
	0x800,	/* number of sprites */
	4,		/* bitplanes */
	{ 3*0x10000*8, 2*0x10000*8, 1*0x10000*8, 0*0x10000*8 }, /* plane offsets */
	{
		0,1,2,3,4,5,6,7,
		16*8+0,16*8+1,16*8+2,16*8+3,16*8+4,16*8+5,16*8+6,16*8+7
	},
	{
		0*8,1*8,2*8,3*8,4*8,5*8,6*8,7*8,
		8*8,9*8,10*8,11*8,12*8,13*8,14*8,15*8
	},
	8*8*4
};

static GFXDECODE_START( combasc )
	GFXDECODE_ENTRY( "gfx1", 0x00000, gfxlayout, 0, 8*16 )
	GFXDECODE_ENTRY( "gfx2", 0x00000, gfxlayout, 0, 8*16 )
GFXDECODE_END

static GFXDECODE_START( combascb )
	GFXDECODE_ENTRY( "gfx1", 0x00000, tile_layout,   0, 8*16 )
	GFXDECODE_ENTRY( "gfx1", 0x40000, tile_layout,   0, 8*16 )
	GFXDECODE_ENTRY( "gfx2", 0x00000, sprite_layout, 0, 8*16 )
	GFXDECODE_ENTRY( "gfx2", 0x40000, sprite_layout, 0, 8*16 )
GFXDECODE_END

static const ym2203_interface ym2203_config =
{
	{
		AY8910_LEGACY_OUTPUT,
		AY8910_DEFAULT_LOADS,
		DEVCB_NULL,
		DEVCB_NULL,
		DEVCB_HANDLER(combasc_portA_w),
		DEVCB_NULL
	},
	NULL
};


/* combat school (original) */
static MACHINE_DRIVER_START( combasc )

	/* basic machine hardware */
	MDRV_CPU_ADD("maincpu", HD6309, 3000000*4)	/* 3 MHz? */
	MDRV_CPU_PROGRAM_MAP(combasc_readmem,combasc_writemem)
	MDRV_CPU_VBLANK_INT("screen", irq0_line_hold)

	MDRV_CPU_ADD("audiocpu", Z80,3579545)	/* 3.579545 MHz */
	MDRV_CPU_PROGRAM_MAP(combasc_readmem_sound,combasc_writemem_sound)

	MDRV_QUANTUM_TIME(HZ(1200))

	MDRV_MACHINE_RESET(combasc)

	/* video hardware */
	MDRV_SCREEN_ADD("screen", RASTER)
	MDRV_SCREEN_REFRESH_RATE(60)
	MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */)
	MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
	MDRV_SCREEN_SIZE(32*8, 32*8)
	MDRV_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 2*8, 30*8-1)

	MDRV_GFXDECODE(combasc)
	MDRV_PALETTE_LENGTH(8*16*16)

	MDRV_PALETTE_INIT(combasc)
	MDRV_VIDEO_START(combasc)
	MDRV_VIDEO_UPDATE(combasc)

	/* sound hardware */
	MDRV_SPEAKER_STANDARD_MONO("mono")

	MDRV_SOUND_ADD("ym", YM2203, 3000000)
	MDRV_SOUND_CONFIG(ym2203_config)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20)

	MDRV_SOUND_ADD("upd", UPD7759, UPD7759_STANDARD_CLOCK)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.70)
MACHINE_DRIVER_END

/* combat school (bootleg on different hardware) */
static MACHINE_DRIVER_START( combascb )

	/* basic machine hardware */
	MDRV_CPU_ADD("maincpu", HD6309, 3000000*4)	/* 3 MHz? */
	MDRV_CPU_PROGRAM_MAP(combascb_readmem,combascb_writemem)
	MDRV_CPU_VBLANK_INT("screen", irq0_line_hold)

	MDRV_CPU_ADD("audiocpu", Z80,3579545)	/* 3.579545 MHz */
	MDRV_CPU_PROGRAM_MAP(combasc_readmem_sound,combasc_writemem_sound) /* FAKE */

	MDRV_QUANTUM_TIME(HZ(1200))

	MDRV_MACHINE_RESET(combasc)

	/* video hardware */
	MDRV_SCREEN_ADD("screen", RASTER)
	MDRV_SCREEN_REFRESH_RATE(60)
	MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */)
	MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
	MDRV_SCREEN_SIZE(32*8, 32*8)
	MDRV_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 2*8, 30*8-1)

	MDRV_GFXDECODE(combascb)
	MDRV_PALETTE_LENGTH(8*16*16)

	MDRV_PALETTE_INIT(combascb)
	MDRV_VIDEO_START(combascb)
	MDRV_VIDEO_UPDATE(combascb)

	/* We are using the original sound subsystem */
	MDRV_SPEAKER_STANDARD_MONO("mono")

	MDRV_SOUND_ADD("ym", YM2203, 3000000)
	MDRV_SOUND_CONFIG(ym2203_config)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20)

	MDRV_SOUND_ADD("upd", UPD7759, UPD7759_STANDARD_CLOCK)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.70)
MACHINE_DRIVER_END



ROM_START( combasc )
	ROM_REGION( 0x40000, "maincpu", 0 ) /* 6309 code */
	ROM_LOAD( "611g01.rom", 0x30000, 0x08000, CRC(857ffffe) SHA1(de7566d58314df4b7fdc07eb31a3f9bdd12d1a73) )
	ROM_CONTINUE(           0x08000, 0x08000 )
	ROM_LOAD( "611g02.rom", 0x10000, 0x20000, CRC(9ba05327) SHA1(ea03845fb49d18ac4fca97cfffce81db66b9967b) )
	/* extra 0x8000 for banked RAM */

	ROM_REGION( 0x10000 , "audiocpu", 0 ) /* sound CPU */
	ROM_LOAD( "611g03.rom", 0x00000, 0x08000, CRC(2a544db5) SHA1(94a97c3c54bf13ccc665aa5057ac6b1d700fae2d) )

	ROM_REGION( 0x80000, "gfx1", ROMREGION_DISPOSE )
	ROM_LOAD16_BYTE( "611g07.rom",    0x00000, 0x40000, CRC(73b38720) SHA1(e109eb78aea464127d813284ca040e8d719599e3) )
	ROM_LOAD16_BYTE( "611g08.rom",    0x00001, 0x40000, CRC(46e7d28c) SHA1(1ece7fac954204ac35d00f3d573964fcf82dcf77) )

	ROM_REGION( 0x80000, "gfx2", ROMREGION_DISPOSE )
	ROM_LOAD16_BYTE( "611g11.rom",    0x00000, 0x40000, CRC(69687538) SHA1(4349a1c052a759acdf7259f8bf8c5c9489b788f2) )
	ROM_LOAD16_BYTE( "611g12.rom",    0x00001, 0x40000, CRC(9c6bf898) SHA1(eafc227b4e7df0c652ec7d78784c039c35965fdc) )

	ROM_REGION( 0x0400, "proms", 0 )
	ROM_LOAD( "611g06.h14",  0x0000, 0x0100, CRC(f916129a) SHA1(d5e4a8a3baab8fcdac86ef5182858cede1abf040) ) /* sprites lookup table */
	ROM_LOAD( "611g05.h15",  0x0100, 0x0100, CRC(207a7b07) SHA1(f4e638e7f182e5228a062b243406d0ceaaa5bfdc) ) /* chars lookup table */
	ROM_LOAD( "611g10.h6",   0x0200, 0x0100, CRC(f916129a) SHA1(d5e4a8a3baab8fcdac86ef5182858cede1abf040) ) /* sprites lookup table */
	ROM_LOAD( "611g09.h7",   0x0300, 0x0100, CRC(207a7b07) SHA1(f4e638e7f182e5228a062b243406d0ceaaa5bfdc) ) /* chars lookup table */

	ROM_REGION( 0x20000, "upd", 0 )	/* uPD7759 data */
	ROM_LOAD( "611g04.rom",  0x00000, 0x20000, CRC(2987e158) SHA1(87c5129161d3be29a339083349807e60b625c3f7) )

	ROM_REGION( 0x0600, "plds", ROMREGION_DISPOSE )
	ROM_LOAD( "ampal16l8.e7", 0x0000, 0x0104, CRC(300a9936) SHA1(a4a87e93f41392fc7d7d8601d7187d87b9f9ab01) )
	ROM_LOAD( "pal16r6.16d",  0x0200, 0x0104, NO_DUMP ) /* PAL is read protected */
	ROM_LOAD( "pal20l8.8h",   0x0400, 0x0144, NO_DUMP ) /* PAL is read protected */
ROM_END

ROM_START( combasct )
	ROM_REGION( 0x40000, "maincpu", 0 ) /* 6309 code */
	ROM_LOAD( "g01.rom",     0x30000, 0x08000, CRC(489c132f) SHA1(c717195f89add4be4a21ecc1ddd58361b0ab4a74) )
	ROM_CONTINUE(            0x08000, 0x08000 )
	ROM_LOAD( "611g02.rom",  0x10000, 0x20000, CRC(9ba05327) SHA1(ea03845fb49d18ac4fca97cfffce81db66b9967b) )
	/* extra 0x8000 for banked RAM */

	ROM_REGION( 0x10000 , "audiocpu", 0 ) /* sound CPU */
	ROM_LOAD( "611g03.rom", 0x00000, 0x08000, CRC(2a544db5) SHA1(94a97c3c54bf13ccc665aa5057ac6b1d700fae2d) )

	ROM_REGION( 0x80000, "gfx1", ROMREGION_DISPOSE )
	ROM_LOAD16_BYTE( "611g07.rom",    0x00000, 0x40000, CRC(73b38720) SHA1(e109eb78aea464127d813284ca040e8d719599e3) )
	ROM_LOAD16_BYTE( "611g08.rom",    0x00001, 0x40000, CRC(46e7d28c) SHA1(1ece7fac954204ac35d00f3d573964fcf82dcf77) )

	ROM_REGION( 0x80000, "gfx2", ROMREGION_DISPOSE )
	ROM_LOAD16_BYTE( "611g11.rom",    0x00000, 0x40000, CRC(69687538) SHA1(4349a1c052a759acdf7259f8bf8c5c9489b788f2) )
	ROM_LOAD16_BYTE( "611g12.rom",    0x00001, 0x40000, CRC(9c6bf898) SHA1(eafc227b4e7df0c652ec7d78784c039c35965fdc) )

	ROM_REGION( 0x0400, "proms", 0 )
	ROM_LOAD( "611g06.h14",  0x0000, 0x0100, CRC(f916129a) SHA1(d5e4a8a3baab8fcdac86ef5182858cede1abf040) ) /* sprites lookup table */
	ROM_LOAD( "611g05.h15",  0x0100, 0x0100, CRC(207a7b07) SHA1(f4e638e7f182e5228a062b243406d0ceaaa5bfdc) ) /* chars lookup table */
	ROM_LOAD( "611g10.h6",   0x0200, 0x0100, CRC(f916129a) SHA1(d5e4a8a3baab8fcdac86ef5182858cede1abf040) ) /* sprites lookup table */
	ROM_LOAD( "611g09.h7",   0x0300, 0x0100, CRC(207a7b07) SHA1(f4e638e7f182e5228a062b243406d0ceaaa5bfdc) ) /* chars lookup table */

	ROM_REGION( 0x20000, "upd", 0 )	/* uPD7759 data */
	ROM_LOAD( "611g04.rom",  0x00000, 0x20000, CRC(2987e158) SHA1(87c5129161d3be29a339083349807e60b625c3f7) )
ROM_END

ROM_START( combascj )
	ROM_REGION( 0x40000, "maincpu", 0 ) /* 6309 code */
	ROM_LOAD( "611p01.a14",  0x30000, 0x08000, CRC(d748268e) SHA1(91588b6a0d3af47065204b980a56544a9f29b6d9) )
	ROM_CONTINUE(            0x08000, 0x08000 )
	ROM_LOAD( "611g02.rom",  0x10000, 0x20000, CRC(9ba05327) SHA1(ea03845fb49d18ac4fca97cfffce81db66b9967b) )
	/* extra 0x8000 for banked RAM */

	ROM_REGION( 0x10000 , "audiocpu", 0 ) /* sound CPU */
	ROM_LOAD( "611g03.rom", 0x00000, 0x08000, CRC(2a544db5) SHA1(94a97c3c54bf13ccc665aa5057ac6b1d700fae2d) )

	ROM_REGION( 0x80000, "gfx1", ROMREGION_DISPOSE )
	ROM_LOAD16_BYTE( "611g07.rom",    0x00000, 0x40000, CRC(73b38720) SHA1(e109eb78aea464127d813284ca040e8d719599e3) )
	ROM_LOAD16_BYTE( "611g08.rom",    0x00001, 0x40000, CRC(46e7d28c) SHA1(1ece7fac954204ac35d00f3d573964fcf82dcf77) )

	ROM_REGION( 0x80000, "gfx2", ROMREGION_DISPOSE )
	ROM_LOAD16_BYTE( "611g11.rom",    0x00000, 0x40000, CRC(69687538) SHA1(4349a1c052a759acdf7259f8bf8c5c9489b788f2) )
	ROM_LOAD16_BYTE( "611g12.rom",    0x00001, 0x40000, CRC(9c6bf898) SHA1(eafc227b4e7df0c652ec7d78784c039c35965fdc) )

	ROM_REGION( 0x0400, "proms", 0 )
	ROM_LOAD( "611g06.h14",  0x0000, 0x0100, CRC(f916129a) SHA1(d5e4a8a3baab8fcdac86ef5182858cede1abf040) ) /* sprites lookup table */
	ROM_LOAD( "611g05.h15",  0x0100, 0x0100, CRC(207a7b07) SHA1(f4e638e7f182e5228a062b243406d0ceaaa5bfdc) ) /* chars lookup table */
	ROM_LOAD( "611g10.h6",   0x0200, 0x0100, CRC(f916129a) SHA1(d5e4a8a3baab8fcdac86ef5182858cede1abf040) ) /* sprites lookup table */
	ROM_LOAD( "611g09.h7",   0x0300, 0x0100, CRC(207a7b07) SHA1(f4e638e7f182e5228a062b243406d0ceaaa5bfdc) ) /* chars lookup table */

	ROM_REGION( 0x20000, "upd", 0 )	/* uPD7759 data */
	ROM_LOAD( "611g04.rom",  0x00000, 0x20000, CRC(2987e158) SHA1(87c5129161d3be29a339083349807e60b625c3f7) )
ROM_END

ROM_START( bootcamp )
	ROM_REGION( 0x40000, "maincpu", 0 ) /* 6309 code */
	ROM_LOAD( "xxx-v01.12a", 0x30000, 0x08000, CRC(c10dca64) SHA1(f34de26e998b1501e430d46e96cdc58ebc68481e) )
	ROM_CONTINUE(            0x08000, 0x08000 )
	ROM_LOAD( "611g02.rom",  0x10000, 0x20000, CRC(9ba05327) SHA1(ea03845fb49d18ac4fca97cfffce81db66b9967b) )
	/* extra 0x8000 for banked RAM */

	ROM_REGION( 0x10000 , "audiocpu", 0 ) /* sound CPU */
	ROM_LOAD( "611g03.rom", 0x00000, 0x08000, CRC(2a544db5) SHA1(94a97c3c54bf13ccc665aa5057ac6b1d700fae2d) )

	ROM_REGION( 0x80000, "gfx1", ROMREGION_DISPOSE )
	ROM_LOAD16_BYTE( "611g07.rom",    0x00000, 0x40000, CRC(73b38720) SHA1(e109eb78aea464127d813284ca040e8d719599e3) )
	ROM_LOAD16_BYTE( "611g08.rom",    0x00001, 0x40000, CRC(46e7d28c) SHA1(1ece7fac954204ac35d00f3d573964fcf82dcf77) )

	ROM_REGION( 0x80000, "gfx2", ROMREGION_DISPOSE )
	ROM_LOAD16_BYTE( "611g11.rom",    0x00000, 0x40000, CRC(69687538) SHA1(4349a1c052a759acdf7259f8bf8c5c9489b788f2) )
	ROM_LOAD16_BYTE( "611g12.rom",    0x00001, 0x40000, CRC(9c6bf898) SHA1(eafc227b4e7df0c652ec7d78784c039c35965fdc) )

	ROM_REGION( 0x0400, "proms", 0 )
	ROM_LOAD( "611g06.h14",  0x0000, 0x0100, CRC(f916129a) SHA1(d5e4a8a3baab8fcdac86ef5182858cede1abf040) ) /* sprites lookup table */
	ROM_LOAD( "611g05.h15",  0x0100, 0x0100, CRC(207a7b07) SHA1(f4e638e7f182e5228a062b243406d0ceaaa5bfdc) ) /* chars lookup table */
	ROM_LOAD( "611g10.h6",   0x0200, 0x0100, CRC(f916129a) SHA1(d5e4a8a3baab8fcdac86ef5182858cede1abf040) ) /* sprites lookup table */
	ROM_LOAD( "611g09.h7",   0x0300, 0x0100, CRC(207a7b07) SHA1(f4e638e7f182e5228a062b243406d0ceaaa5bfdc) ) /* chars lookup table */

    ROM_REGION( 0x20000, "upd", 0 )	/* uPD7759 data */
	ROM_LOAD( "611g04.rom",  0x00000, 0x20000, CRC(2987e158) SHA1(87c5129161d3be29a339083349807e60b625c3f7) )
ROM_END

ROM_START( combascb )
	ROM_REGION( 0x40000, "maincpu", 0 ) /* 6809 code */
	ROM_LOAD( "combat.002",	 0x30000, 0x08000, CRC(0996755d) SHA1(bb6bbbf7ab3b5fab5e1c6cebc7b3f0d720493c3b) )
	ROM_CONTINUE(            0x08000, 0x08000 )
	ROM_LOAD( "combat.003",	 0x10000, 0x10000, CRC(229c93b2) SHA1(ac3fd3df1bb5f6a461d0d1423c50568348ef69df) )
	ROM_LOAD( "combat.004",	 0x20000, 0x10000, CRC(a069cb84) SHA1(f49f70afb17df46b16f5801ef42edb0706730723) )
	/* extra 0x8000 for banked RAM */

	ROM_REGION( 0x10000 , "audiocpu", 0 ) /* sound CPU */
	ROM_LOAD( "combat.001",  0x00000, 0x10000, CRC(61456b3b) SHA1(320db628283dd1bec465e95020d1a1158e6d6ae4) )
	ROM_LOAD( "611g03.rom",  0x00000, 0x08000, CRC(2a544db5) SHA1(94a97c3c54bf13ccc665aa5057ac6b1d700fae2d) ) /* FAKE - from Konami set! */

	ROM_REGION( 0x80000, "gfx1", ROMREGION_DISPOSE | ROMREGION_INVERT )
	ROM_LOAD( "combat.006",  0x00000, 0x10000, CRC(8dc29a1f) SHA1(564dd7c6acff34db93b8e300dda563f5f38ba159) ) /* tiles, bank 0 */
	ROM_LOAD( "combat.008",  0x10000, 0x10000, CRC(61599f46) SHA1(cfd79a88bb496773daf207552c67f595ee696bc4) )
	ROM_LOAD( "combat.010",  0x20000, 0x10000, CRC(d5cda7cd) SHA1(140db6270c3f358aa27013db3bb819a48ceb5142) )
	ROM_LOAD( "combat.012",  0x30000, 0x10000, CRC(ca0a9f57) SHA1(d6b3daf7c34345bb2f64068d480bd51d7bb36e4d) )
	ROM_LOAD( "combat.005",  0x40000, 0x10000, CRC(0803a223) SHA1(67d4162385dd56d5396e181070bfa6760521eb45) ) /* tiles, bank 1 */
	ROM_LOAD( "combat.007",  0x50000, 0x10000, CRC(23caad0c) SHA1(0544cde479c6d4192da5bb4b6f0e2e75d09663c3) )
	ROM_LOAD( "combat.009",  0x60000, 0x10000, CRC(5ac80383) SHA1(1e89c371a92afc000d593daebda4156952a15244) )
	ROM_LOAD( "combat.011",  0x70000, 0x10000, CRC(cda83114) SHA1(12d2a9f694287edb3bb0ee7a8ba0e0724dad8e1f) )

	ROM_REGION( 0x80000, "gfx2", ROMREGION_DISPOSE | ROMREGION_INVERT )
	ROM_LOAD( "combat.013",  0x00000, 0x10000, CRC(4bed2293) SHA1(3369de47d4ba041d9f17a18dcca2af7ac9f8bc0c) ) /* sprites, bank 0 */
	ROM_LOAD( "combat.015",  0x10000, 0x10000, CRC(26c41f31) SHA1(f8eb7d0729a21a0dd92ce99c9cda0cde9526b861) )
	ROM_LOAD( "combat.017",  0x20000, 0x10000, CRC(6071e6da) SHA1(ba5f8e83b07faaffc564d3568630e17efdb5a09f) )
	ROM_LOAD( "combat.019",  0x30000, 0x10000, CRC(3b1cf1b8) SHA1(ff4de37c051bcb374c44d1b99006ff6ff5e1f927) )
	ROM_LOAD( "combat.014",  0x40000, 0x10000, CRC(82ea9555) SHA1(59bf7836938ce9e3242d1cca754de8dbe85bbfb7) ) /* sprites, bank 1 */
	ROM_LOAD( "combat.016",  0x50000, 0x10000, CRC(2e39bb70) SHA1(a6c4acd93cc803e987de6e18fbdc5ce4634b14a8) )
	ROM_LOAD( "combat.018",  0x60000, 0x10000, CRC(575db729) SHA1(6b1676da4f24fc90c77262789b6cc116184ab912) )
	ROM_LOAD( "combat.020",  0x70000, 0x10000, CRC(8d748a1a) SHA1(4386e14e19b91e053033dde2a13019bc6d8e1d5a) )

	ROM_REGION( 0x0200, "proms", 0 )
	ROM_LOAD( "prom.d10",    0x0000, 0x0100, CRC(265f4c97) SHA1(76f1b75a593d3d77ef6173a1948f842d5b27d418) ) /* sprites lookup table */
	ROM_LOAD( "prom.c11",    0x0100, 0x0100, CRC(a7a5c0b4) SHA1(48bfc3af40b869599a988ebb3ed758141bcfd4fc) ) /* priority? */

	ROM_REGION( 0x20000, "upd", 0 )	/* uPD7759 data */
	ROM_LOAD( "611g04.rom",  0x00000, 0x20000, CRC(2987e158) SHA1(87c5129161d3be29a339083349807e60b625c3f7) )	/* FAKE - from Konami set! */
ROM_END



static void combasc_init_common(running_machine *machine)
{
	combasc_interleave_timer = timer_alloc(machine, NULL, NULL);
}

static DRIVER_INIT( combasct )
{
	combasc_init_common(machine);
}

static DRIVER_INIT( combasc )
{
	/* joystick instead of trackball */
	memory_install_read_port_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x0404, 0x0404, 0, 0, "IN1");

	combasc_init_common(machine);
}

static DRIVER_INIT( combascb )
{
	combasc_init_common(machine);
}



GAME( 1988, combasc,  0,       combasc,  combasc,  combasc,  ROT0, "Konami", "Combat School (joystick)", 0 )
GAME( 1987, combasct, combasc, combasc,  combasct, combasct, ROT0, "Konami", "Combat School (trackball)", 0 )
GAME( 1987, combascj, combasc, combasc,  combasct, combasct, ROT0, "Konami", "Combat School (Japan trackball)", 0 )
GAME( 1987, bootcamp, combasc, combasc,  combasct, combasct, ROT0, "Konami", "Boot Camp", 0 )
GAME( 1988, combascb, combasc, combascb, combascb, combascb, ROT0, "bootleg", "Combat School (bootleg)", GAME_IMPERFECT_COLORS )