@program me:@@prof verbs = {}; keys = {}; for o in [#0..max_object()] if (valid(o)) for i in [1..length(v = verbs(o))] verbs = {@verbs, tostr(o, ":", v[i], " ", t = prof_seconds(o, i))}; keys = {@keys, t}; endfor endif endfor verbs = $list_utils:sort(verbs, keys); keys = $list_utils:sort(keys); for i in [1..length(keys)] if (keys[i]) notify(player, verbs[i]); endif endfor . "stop doing a linear search of the memory bus mappings for every access @rmprop mb.pagemap @prop mb.pagemap {} @rmverb mb:build_pagemap tnt @verb mb:build_pagemap tnt @program mb:build_pagemap this.pagemap = {}; for i in [0..255] address = i * 256; try {offset, chip} = this:find_chip_and_address(address); start = address - offset; this.pagemap = {@this.pagemap, {chip, start}}; except (E_RANGE) this.pagemap = {@this.pagemap, {E_RANGE, 0}}; endtry endfor . @program mb:"get_byte" (location) page = location / 256; {chip, start} = this.pagemap[page + 1]; if (chip == E_RANGE) if (this.forgiving) return 0; else raise(E_RANGE); endif endif return chip:get_byte(location - start); return; try pair = this:find_chip_and_address(location); except (E_RANGE) if (this.forgiving) return 0; else raise(E_RANGE); endif endtry return pair[2]:get_byte(pair[1]); . "only s_i_n every ten instructions @program 6502:"run" this none none player:tell("Starting ", this:dname(), "."); this.task = task_id(); this.exception = 0; count = 0; while (!this.exception) this.last_pc = this.pc; if (this.pc in this.breakpoints) this.exception = 1; break; endif this:do_instruction(); count = count + 1; if (count >= 10) $command_utils:suspend_if_needed(0); count = 0; endif endwhile this.task = 0; player:tell(this:dnamec(), " stopped."); this:look_self(); . "this get_word stuff is stupid, it didn't help at all "the theory was that we could guarantee that page 0 and stack addresses weren't going to cross page boundaries and we could legitimately ask a single chip for a word @rmverb 6502:"get_word_0_page" @verb 6502:"get_word_0_page get_word_1_page" (location) @program 6502:get_word_0_page (location) return this.memory:get_word_same_page(location); . @rmverb mb:get_word_same_page @verb mb:get_word_same_page (location) @program mb:get_word_same_page (location) page = location / 256; {chip, start} = this.pagemap[page + 1]; if (chip == E_RANGE) if (this.forgiving) return 0; else raise(E_RANGE); endif endif return chip:get_word(location - start); . @rmverb gmc:get_word @verb gmc:get_word (location) @program gmc:get_word (location) return this.cells[location+1] + this.cells[location+2] * 256; . @rmverb a2rom:get_word @verb a2rom:get_word (location) @program a2rom:get_word (location) return this:get_byte(location) + this:get_byte(location + 1) * 256; . @program 6502:ea_idy m = this:get_word_0_page(this:read_op_arg()); this.ea = m + this.y; . @program 6502:ea_idx m = (this:read_op_arg() + this.x) % 256; this.ea = this:get_word_0_page(m); . @program 6502:pull_word sp = this.sp; sp = sp + 2; if (sp >= 256) sp = sp - 256; endif this.sp = sp; return this:get_word_1_page(sp); . "this saves a WHOLE SECOND OR TWO from FORI=1TO500; it of course needs mods to the generated opcode_bcs_rel verbs too. @program 6502:core_branch (take) if (take) offset = this:read_op_arg(); if (offset >= 128) offset = offset - 256; endif this.pc = this.pc + offset; else this.pc = this.pc + 1; endif . "this saves another FOUR SECONDS. Avoiding consing strings for every instruction is obviously good, and I forget whether the verb cache likes == char*s better, but that might help too. @rmprop 6502.opcode_expanded @prop 6502.opcode_expanded @rmverb 6502:build_second_opcode_table @verb 6502:build_second_opcode_table tnt @program 6502:build_second_opcode_table ox = {}; for op in (this.opcodes) fullstring = "opcode_" + op; ox = {@ox, fullstring}; endfor this.opcode_expanded = ox; . @program 6502:do_instruction opcode = this:get_byte(this.pc); this.pc = this.pc + 1; this:(this.opcode_expanded[opcode + 1])(); return; // opcode_name = this.opcodes_expanded[opcode + 1]; . "This is another two to four seconds. $math_utils:XOR etc are awfully slow for 8-bit ops. @rmprop 6502.AND_table @rmprop 6502.OR_table @rmprop 6502.XOR_table @prop 6502.AND_table {} @prop 6502.OR_table {} @prop 6502.XOR_table {} @rmverb 6502:build_bitwise_tables @verb 6502:build_bitwise_tables tnt @program 6502:build_bitwise_tables and_table = {}; or_table = {}; xor_table = {}; for i in [0..15] for j in [0..15] $command_utils:suspend_if_needed(5, "...", i, " ", j); and_table = {@and_table, $math_utils:AND(i, j)}; or_table = {@or_table, $math_utils:OR(i, j)}; xor_table = {@xor_table, $math_utils:XOR(i, j)}; endfor endfor this.AND_table = and_table; this.OR_table = or_table; this.XOR_table = xor_table; . @rmverb 6502:AND @verb "6502:AND OR XOR" (x, y) @program 6502:AND (x, y) table = this.(verb + "_table"); return table[x%16 + (y % 16)*16 + 1] + table[x/16 + (y/16)*16 + 1] * 16; . @program 6502:"core_eor" this none this m = this:get_ea(); res = this:XOR(this.a, m); this.a = res; this:status_nz(res); . @program 6502:"core_and" this none this m = this:get_ea(); res = this:AND(this.a, m); this.a = res; this:status_nz(res); . @program 6502:"core_ora" this none this m = this:get_ea(); res = this:OR(this.a, m); this.a = res; this:status_nz(res); . "turning up maxticks from 300,000/150,000 to 3,000,000/1,500,000 didn't help much at all, I wonder if I should do a manual version of suspend_if_needed in 6502:run @program 6502:"run" this none none player:tell("Starting ", this:dname(), "."); this.task = task_id(); this.exception = 0; count = 0; while (!this.exception) this.last_pc = this.pc; if (this.pc in this.breakpoints) this.exception = 1; break; endif this:do_instruction(); count = count + 1; if (count >= 10) count = 0; if (ticks_left() < 4000) $command_utils:suspend_if_needed(0); endif endif endwhile this.task = 0; player:tell(this:dnamec(), " stopped."); this:look_self(); . "That didn't help at all, as far as I can tell. "named args might really suck. let's try removing them from the big hotspot @program 6502:"get_byte" this none this return this.memory:get_byte(args[1]); . "and now we have to bump up the idle detection threshold @program ah:"read_keystrobe" (address) "Usage: :read_keystrobe()"; ""; if (address == 16) this.key_val = this.key_val % 128; return this.key_val; endif if (time() != this.last_read_time) this.read_count = 0; this.last_read_time = time(); endif this.read_count = this.read_count + 1; if (this.read_count > 20 && !this.queued_keys) player:tell("waiting for key..."); suspend(5); endif if (this.key_val / 128) return this.key_val; endif if (length(this.queued_keys) > 0) key = this.queued_keys[1]; this.last_key = key; this.queued_keys = this.queued_keys[2..$]; this.key_val = key + 128; return this.key_val; endif return this.key_val; . @program a2rom:"get_byte" (location) if (location in this.patches) "NOP"; return 234; endif triple = this.cells[location / 3 + 1]; offset = location % 3; if (offset == 0) return triple / 65536; elseif (offset == 1) return triple / 256 % 256; else return triple % 256; endif . @create gmc named romclone @set romclone.size to 12288 zero romclone @prop romclone.source #241 @verb romclone:load_from_source tnt @program romclone:load_from_source for n in [0..this.size-1] this:set_byte(n, this.source:get_byte(n)); $command_utils:suspend_if_needed(0, n); endfor . @verb romclone:set_byte tnt @program romclone:set_byte . "forgot to get rid of a $math_utils:AND @program 6502:"core_bit" this none this m = this:get_ea(); res = this:AND(m, this.a); this.p_z = res == 0; m7 = m / 128; m6 = m / 64 % 2; this.p_n = m7; this.p_v = m6; . @program mb:"set_byte" (location, value) if (value != value % 256) raise(E_INVARG); endif page = location / 256; {chip, start} = this.pagemap[page + 1]; if (chip == E_RANGE) if (this.forgiving) return; else raise(E_RANGE); endif endif chip:set_byte(location - start, value); return; try pair = this:find_chip_and_address(location); except (E_RANGE) if (this.forgiving) return 0; else raise(E_RANGE); endif endtry pair[2]:set_byte(pair[1], value); . @program gmc:get_byte () return this.cells[args[1] + 1]; . @program 6502:"do_instruction" this none this opcode = this:get_byte(pc = this.pc); this.pc = pc + 1; this:(this.opcode_expanded[opcode + 1])(); return; "opcode_name = this.opcodes_expanded[opcode + 1];"; .