From 1e6a43b273414c389943b0eaa8a5fbb28e41050b Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Tue, 11 Apr 2017 22:46:06 -0400 Subject: [PATCH] various improvements --- index.html | 4 +- .../examples/{music2.a => fractionalpitch.a} | 0 presets/vicdual/skeleton.sdcc | 17 ++++- src/emu.js | 3 + src/platform/galaxian.js | 2 +- src/platform/vicdual.js | 6 +- src/platform/williams.js | 3 +- src/worker/workermain.js | 73 ++++++++++++++++++- tools/midi2song.py | 39 ++++++---- 9 files changed, 119 insertions(+), 28 deletions(-) rename presets/vcs/examples/{music2.a => fractionalpitch.a} (100%) diff --git a/index.html b/index.html index afd04cb1..d69da0ba 100644 --- a/index.html +++ b/index.html @@ -206,8 +206,8 @@ div.bitmap_editor {
  • Atari VCS
  • VIC Dual
  • -
  • Midway 8080 B&W
  • -
  • Scramble hardware
  • +
  • Midway 8080
  • +
  • Scramble Hardware
  • Atari Color Vector (Z80)
  • Williams (Z80)
  • Williams Sound (Z80)
  • diff --git a/presets/vcs/examples/music2.a b/presets/vcs/examples/fractionalpitch.a similarity index 100% rename from presets/vcs/examples/music2.a rename to presets/vcs/examples/fractionalpitch.a diff --git a/presets/vicdual/skeleton.sdcc b/presets/vicdual/skeleton.sdcc index 2a3fed5d..a850b24e 100644 --- a/presets/vicdual/skeleton.sdcc +++ b/presets/vicdual/skeleton.sdcc @@ -92,11 +92,22 @@ word rand() { return lfsr; } -void wait_for_vsync() { - while (VSYNC != 0) lfsr++; // wait for VSYNC end - while (VSYNC == 0) lfsr++; // wait for VSYNC start +void delay(byte msec) { + while (msec--) { + while (TIMER500HZ != 0) lfsr++; + while (TIMER500HZ == 0) lfsr++; + } } +#define PE(fg,bg) (((fg)<<5) | ((bg)<<1)) + +const byte __at (0x4000) color_prom[32] = { + PE(7,0),PE(3,0),PE(1,0),PE(3,0),PE(6,0),PE(3,0),PE(2,0),PE(6,0), + PE(7,0),PE(3,0),PE(1,0),PE(3,0),PE(6,0),PE(3,0),PE(2,0),PE(6,0), + PE(7,0),PE(3,0),PE(1,0),PE(3,0),PE(6,0),PE(3,0),PE(2,0),PE(6,0), + PE(7,0),PE(3,0),PE(1,0),PE(3,0),PE(6,0),PE(3,0),PE(2,0),PE(6,0), +}; + #define LOCHAR 0x0 #define HICHAR 0xff diff --git a/src/emu.js b/src/emu.js index bdd87417..909828d0 100644 --- a/src/emu.js +++ b/src/emu.js @@ -626,6 +626,9 @@ var BaseZ80Platform = function() { onBreakpointHit(debugBreakState); } } + this.wasBreakpointHit = function() { + return debugBreakState != null; + } // TODO: lower bound of clock value this.step = function() { var self = this; diff --git a/src/platform/galaxian.js b/src/platform/galaxian.js index d600d25a..d3b128d6 100644 --- a/src/platform/galaxian.js +++ b/src/platform/galaxian.js @@ -2,7 +2,7 @@ var GALAXIAN_PRESETS = [ {id:'gfxtest.c', name:'Graphics Test'}, - {id:'shoot2.c', name:'Shoot-em-up Game'}, + {id:'shoot2.c', name:'Solarian Game'}, ]; var GALAXIAN_KEYCODE_MAP = makeKeycodeMap([ diff --git a/src/platform/vicdual.js b/src/platform/vicdual.js index 6cc29713..ecacd921 100644 --- a/src/platform/vicdual.js +++ b/src/platform/vicdual.js @@ -5,9 +5,9 @@ var VICDUAL_PRESETS = [ {id:'hello.c', name:'Hello World'}, {id:'gfxtest.c', name:'Graphics Test'}, {id:'soundtest.c', name:'Sound Test'}, - {id:'snake1.c', name:'Snake Game (Prototype)'}, - {id:'snake2.c', name:'Snake Game (Full)'}, - {id:'music.c', name:'Music Example'}, + {id:'snake1.c', name:'Siege Game (Prototype)'}, + {id:'snake2.c', name:'Siege Game (Full)'}, + {id:'music.c', name:'Music Player'}, ]; var VicDualPlatform = function(mainElement) { diff --git a/src/platform/williams.js b/src/platform/williams.js index 27f24d68..0a17117e 100644 --- a/src/platform/williams.js +++ b/src/platform/williams.js @@ -310,7 +310,8 @@ var WilliamsPlatform = function(mainElement, proto) { if (cpu.requestInterrupt) cpu.requestInterrupt(); } - self.runCPU(cpu, cpuCyclesPerFrame/4); + if (!self.wasBreakpointHit()) + self.runCPU(cpu, cpuCyclesPerFrame/4); video.updateFrame(0, 0, quarter*64, 0, 64, 304); } if (screenNeedsRefresh) { diff --git a/src/worker/workermain.js b/src/worker/workermain.js index 9d11393e..0abd84f7 100644 --- a/src/worker/workermain.js +++ b/src/worker/workermain.js @@ -84,12 +84,67 @@ function loadFilesystem(name) { console.log("Loaded "+name+" filesystem", fsMeta[name].files.length, 'files', fsBlob[name].size, 'bytes'); } +var ATARI_CFG = + "FEATURES {\nSTARTADDRESS: default = $9000;\n}\n" ++ "MEMORY {\n" ++ " ZP: start = $82, size = $7E;\n" ++ " RAM: start = $0200, size = $1e00;\n" ++ " ROM: start = $9000, size = $7000;\n" ++ " VEC: start = $FFFA, size = 6;\n" ++ "}\n" ++ "SEGMENTS {\n" ++ " CODE: load = ROM, type = ro, define = no;\n" ++ " DATA: load = RAM, type = rw, define = no;\n" ++ "ZEROPAGE: load = ZP, type = zp, define = no;\n" +//+ " VECTORS: load = VEC, type = ro, define = yes;" ++ "}\n" +; +/* ++ "SYMBOLS {\n" ++ " __STACKSIZE__: type = weak, value = $0800; # 2k stack\n" ++ " __RESERVED_MEMORY__: type = weak, value = $0000;\n" ++ " __STARTADDRESS__: type = export, value = %S;\n" ++ "}\n" ++ "MEMORY {\n" ++ " ZP: file = \"\", define = yes, start = $0082, size = $007E;\n" ++ " MAIN: file = %O, define = yes, start = %S, size = $BC20 - __STACKSIZE__ - __RESERVED_MEMORY__ - %S;\n" ++ "}\n" ++ "SEGMENTS {\n" ++ " ZEROPAGE: load = ZP, type = zp, optional = yes;\n" ++ " EXTZP: load = ZP, type = zp, optional = yes;\n" ++ " STARTUP: load = MAIN, type = ro, define = yes, optional = yes;\n" ++ " LOWCODE: load = MAIN, type = ro, define = yes, optional = yes;\n" ++ " ONCE: load = MAIN, type = ro, optional = yes;\n" ++ " CODE: load = MAIN, type = ro, define = yes;\n" ++ " RODATA: load = MAIN, type = ro, optional = yes;\n" ++ " DATA: load = MAIN, type = rw, optional = yes;\n" ++ " BSS: load = MAIN, type = bss, define = yes, optional = yes;\n" ++ " INIT: load = MAIN, type = bss, optional = yes;\n" ++ "}\n" ++ "FEATURES {\n" ++ " CONDES: type = constructor,\n" ++ " label = __CONSTRUCTOR_TABLE__,\n" ++ " count = __CONSTRUCTOR_COUNT__,\n" ++ " segment = ONCE;\n" ++ " CONDES: type = destructor,\n" ++ " label = __DESTRUCTOR_TABLE__,\n" ++ " count = __DESTRUCTOR_COUNT__,\n" ++ " segment = RODATA;\n" ++ " CONDES: type = interruptor,\n" ++ " label = __INTERRUPTOR_TABLE__,\n" ++ " count = __INTERRUPTOR_COUNT__,\n" ++ " segment = RODATA,\n" ++ " import = __CALLIRQ__;\n" ++ "}\n"; +*/ + // mount the filesystem at /share function setupFS(FS, name) { FS.mkdir('/share'); FS.mount(FS.filesystems['WORKERFS'], { packages: [{ metadata: fsMeta[name], blob: fsBlob[name] }] }, '/share'); + FS.writeFile("/vector-ataricolor.cfg", ATARI_CFG); } var DASM_MAIN_FILENAME = "main.a"; @@ -413,11 +468,14 @@ function assemblelinkCA65(code, platform, warnings) { printErr:print_fn, }); var FS = LD65['FS']; + var cfgfile = '/' + platform + '.cfg'; setupFS(FS, '65'); FS.writeFile("main.o", objout, {encoding:'binary'}); LD65.callMain(['--cfg-path', '/share/cfg', '--lib-path', '/share/lib', - '--start-addr', '0x6000', // TODO - '-t', platform, '-o', 'main', '-m', 'main.map', 'main.o', platform+'.lib']); + //'--start-addr', '0x6000', // TODO + '-C', cfgfile, + '-o', 'main', '-m', 'main.map', 'main.o', + 'apple2.lib']); var aout = FS.readFile("main", {encoding:'binary'}); var mapout = FS.readFile("main.map", {encoding:'utf8'}); var listing = parseCA65Listing(lstout, mapout); @@ -456,10 +514,17 @@ function compileCC65(code, platform) { var FS = CC65['FS']; setupFS(FS, '65'); FS.writeFile("main.c", code, {encoding:'utf8'}); - CC65.callMain(['-v', '-T', '-g', /*'-Cl',*/ '-Oirs', '-I', '/share/include', '-t', platform, "main.c"]); + CC65.callMain(['-v', '-T', '-g', /*'-Cl',*/ '-Oirs', '-I', '/share/include', "main.c"]); try { var asmout = FS.readFile("main.s", {encoding:'utf8'}); - return assemblelinkCA65(asmout, platform, errors); + var result = assemblelinkCA65(asmout, platform, errors); +/* + result.asmlines = result.lines; + result.lines = result.srclines; + result.srclines = null; +*/ +//console.log(result.intermediate.listing); + return result; } catch(e) { return {errors:errors}; } diff --git a/tools/midi2song.py b/tools/midi2song.py index c80e165e..8b438b28 100755 --- a/tools/midi2song.py +++ b/tools/midi2song.py @@ -1,16 +1,29 @@ #!/usr/bin/python -import sys, string, math +import sys, string, math, argparse import mido -min_note = 21 -max_note = 21+63 -max_voices = 3 -one_voice_per_channel = 0 -tempo = 48 -compress = 0 -transpose = 0 -coutput = 1 +parser = argparse.ArgumentParser() +parser.add_argument('-s', '--start', type=int, default=21, help="first MIDI note") +parser.add_argument('-n', '--num', type=int, default=21+63, help="number of notes") +parser.add_argument('-v', '--voices', type=int, default=3, help="number of voices") +parser.add_argument('-T', '--transpose', type=int, default=0, help="transpose by half-steps") +parser.add_argument('-t', '--tempo', type=int, default=48, help="tempo") +parser.add_argument('-o', '--one', action="store_true", help="one voice per channel") +parser.add_argument('-z', '--compress', action="store_true", help="compress song (experimental)") +parser.add_argument('-H', '--hex', action="store_true", help="hex output") +parser.add_argument('midifile', help="MIDI file") +parser.add_argument('midichannels', nargs='?', help="comma-separated list of MIDI channels, or -") +args = parser.parse_args() + +min_note = args.start +max_note = min_note + args.num +max_voices = args.voices +one_voice_per_channel = args.one +tempo = args.tempo +compress = args.compress +transpose = args.transpose +coutput = not args.hex # for 2600 #max_voices = 2 @@ -19,7 +32,7 @@ coutput = 1 #max_voices = 4 #one_voice_per_channel = 0 -fn = sys.argv[1] +fn = args.midifile mid = mido.MidiFile(fn) @@ -97,7 +110,7 @@ def channels_for_track(track): channels.add(msg.channel) return list(channels) -if len(sys.argv) < 3: +if not args.midichannels: print mid print mid.length, 'seconds' for i, track in enumerate(mid.tracks): @@ -105,14 +118,12 @@ if len(sys.argv) < 3: #for msg in track: # print(msg) else: - if len(sys.argv) > 3: - transpose = int(sys.argv[3]) gtime = 0 curtime = 0 nnotes = 0 nvoices = 0 curchans = 0 - channels = [int(x) for x in string.split(sys.argv[2], ',')] + channels = [int(x) for x in string.split(args.midichannels, ',')] print print "// %s %s" % (mid, channels) output = []