Zelex wrote:
How did you generate the Base64 (err, Base256? =D) encoded strings? Another program, or by hand?
Sorry about taking many days to notice your post. phpBB only sent me a notification of your first post, and I did not know about the second one. Or the third one.
Answer: Another program.
For each micro-op (each of those lines is one), a list of opcodes using that micro-op is built.
Code:
// $point = current micro-op ID, $plans = list of micro-ops required by all opcodes (the list is called a "plan")
$ops = Array();
foreach($plans as $op => $plan)
if(isset($plan[$point]))
$ops[$op] = $op;
Then the list is converted into a string by translating 8 bits at once using a character lookup array:
Code:
$ranges = Array();
for($n=0; $n*8<0x103; ++$n) //
$ranges[] = 0;
foreach($ops as $o)
$ranges[(int)($o / 8)] |= 1 << ($o % 8);
$s = '';
for($n=0; $n*8<0x103; ++$n) //
$s .= $rangebytetranslation[$ranges[$n]];
$s = '"'.$s.'"';
The lookup array (which determines which character maps into which byte) was built as follows:
Code:
$bitno = 0;
// Initial version, using BASE64 (6 bits per character):
$charset = " !";
for($c=0; $c<15; ++$c) $charset .= chr(65+$c); // A-O
for($c=0; $c<11; ++$c) $charset .= chr(80+$c); // P-Z
for($c=1; $c<10; ++$c) $charset .= chr(48+$c); // 0-9
for($c=0; $c<15; ++$c) $charset .= chr(97+$c); // a-o
for($c=0; $c<11; ++$c) $charset .= chr(112+$c); // p-z
// Figure out which kind of bytes we actually are going to need to present:
$rangebytetranslation = Array();
$rangebytes = Array();
foreach($points as $point => $code)
{
$ops = Array();
foreach($plans as $op => $plan) if(isset($plan[$point])) $ops[$op] = $op;
$ranges = Array();
for($n=0; $n*8<0x103; ++$n) $ranges[] = 0;
foreach($ops as $o) $ranges[(int)($o / 8)] |= 1 << ($o % 8);
foreach($ranges as $v) @$rangebytes[$v] += 1;
}
ksort($rangebytes); #$rangebytes = array_reverse($rangebytes, true);
By observing patterns within the bytes that need to be represented, I created an encoding which is easy to encode and relatively easy to decode.
Code:
// Assign a character for each of those distinct bytes.
$n=94;
$tab = ''; $firstn=-1;
foreach($rangebytes as $v=>$tmp)
{
if($v<=1) $c = 32+$v;
#elseif($v <= 26) $c = 64 + $v;
elseif($v < 64) $c = 40 + $v;
else { if($firstn<0) $firstn = $v;
$tab .= chr(32 + $v - $firstn);
$c = $n++; }//?
$rangebytetranslation[$v] = chr($c);//$charset[$n++];
}
By the way, here is a version that uses hexadecimal numeric constants, requiring no C++0x. One may guess why I did not use it in that video.
Code:
/* Decode address operand */
t(1,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, addr = 0xFFFA) // NMI vector location
t(2,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, addr = 0xFFFC) // Reset vector location
t(4,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001, addr = 0xFFFE) // Interrupt vector location
t(0,0xFAFFF0FA,0xFAFFF0FA,0xFAFFF0FA,0xFAFFF0FA,0xFAFFF0FA,0xFAFFF0FA,0xFAFFF0FB,0xFAFFF0FA, addr = RB(PC++))
t(0,0xF0F0000A,0xF0F0000A,0x3030000A,0x3030000A,0xF0F0000A,0xF0F0000A,0xF0F0000A,0xF0F0000A, d = X) // register index
t(0,0x0A0E0000,0x0A0E0000,0xCACE0000,0xCACE0000,0x0A0E0000,0x0A0E0000,0x0A0E0000,0x0A0E0000, d = Y)
t(0,0x00F0000A,0x00F0000A,0x00F0000A,0x00F0000A,0x00F0000A,0x00F0000A,0x00F0000A,0x00F0000A, addr=u8(addr+d); d=0; tick()) // add zeropage-index
t(0,0xFA00F000,0xFA00F000,0xFA00F000,0xFA00F000,0xFA00F000,0xFA00F000,0xFA00F001,0xFA00F000, addr=u8(addr); addr+=256*RB(PC++)) // absolute address
t(7,0x000E000A,0x000E000A,0x000E000A,0x000E000A,0x000E100A,0x000E000A,0x000E000A,0x000E000B, addr=RB(c=addr); addr+=256*RB(wrap(c,c+1)))// indirect w/ page wrap
t(0,0x32020000,0x32020000,0xFA0E0000,0x00000000,0x32020000,0x32020000,0x32020000,0x32020000, Misfire(addr, addr+d)) // abs. load: extra misread when cross-page
t(0,0xC80C0000,0xC80C0000,0x00000000,0xFA0E0000,0xC80C0000,0xC80C0000,0xC80C0000,0xC80C0000, RB(wrap(addr, addr+d)))// abs. store: always issue a misread
/* Load source operand */
t(0,0x00000000,0xAAAAAAAA,0x00000500,0xAAAAAAAA,0x00000C04,0xAAAAAFAE,0xAAAABEBE,0xAAAAAEAE, t &= A) // Many operations take A or X as operand. Some try in
t(0,0x00001111,0x00000C00,0x00000000,0xCCCCCCC8,0x00000000,0x00000000,0x00000000,0x00000000, t &= X) // error to take both; the outcome is an AND operation.
t(0,0x00000000,0x00001111,0x00000000,0x11101111,0x00000000,0x00000000,0x00000000,0x00000000, t &= Y) // sty,dey,iny,tya,cpy
t(0,0x00000000,0x00000000,0x0C000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, t &= S) // tsx, las
t(7,0x01010000,0x01010000,0x01010000,0x00010000,0x01010000,0x01010000,0x01010000,0x01010101, t &= P.raw|pbits; c = t)// php, flag test/set/clear, interrupts
t(0,0x00001011,0xAAAABABB,0x00000000,0x00000000,0x00000000,0xAAAAA2AA,0xAAAAB2BA,0xAAAAA2AA, c = t; t = 0xFF) // save as second operand
t(0,0xEAEEF0FA,0xEAEEF0FA,0xFAFEF0FA,0x00000000,0xEAEEE0EA,0xEAEEE0EA,0xEAEEF0FA,0xEAEEE0EA, t &= RB(addr+d)) // memory operand
t(0,0x00000A05,0x00000A05,0x00000A05,0x00000A05,0x00000A04,0x00000A04,0x00000A04,0x00000A04, t &= RB(PC++)) // immediate operand
/* Operations that mogrify memory operands directly */
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00001010,0x00000000, P.V = t & 0x40; P.N = t & 0x80) // bit
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0xC8CCCCCC,0x00000000,0xC8CCC4CC,0x00000000, sb = P.C) // rol,rla, ror,rra,arr
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000800,0x00000000,0xC8CCCCCC,0xC8CCCCCC, P.C = t & 0x80) // rol,rla, asl,slo,[arr,anc]
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0xC8CCC4CC,0xC8CCCCCC,0x00000000,0x00000000, P.C = t & 0x01) // lsr,sre, ror,rra,asr
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xC8CCC4CC,0xC8CCC4CC, t = (t << 1) | (sb << 0))
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0xC8CCCCCC,0xC8CCCCCC,0x00000000,0x00000000, t = (t >> 1) | (sb << 7))
t(0,0x00000000,0xC8CCC4C8,0x00000000,0x00000100,0x00000000,0x00000000,0x00000000,0x00000000, t = u8(t - 1)) // dec,dex,dey,dcp
t(0,0xC8CCC1C8,0x00000100,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, t = u8(t + 1)) // inc,inx,iny,isb
/* Store modified value (memory) */
t(0,0xC8CCC0C8,0xC8CCC0C8,0x00000000,0x22FEF0FA,0xC8CCC0C8,0xC8CCC0C8,0xC8CCC0C8,0xC8CCC0C8, WB(addr+d, t))
t(0,0x00000000,0x00000000,0x00000000,0xD8000000,0x00000000,0x00000000,0x00000000,0x00000000, WB(wrap(addr, addr+d), t &= ((addr+d) >> 8))) // [shx,shy,shs,sha?]
/* Some operations used up one clock cycle that we did not account for yet */
t(7,0xDDDCC5C8,0xDDDCC5C8,0x05000500,0x05000500,0xDDDCC5D9,0xDDDCC5D8,0xDDDCC5C9,0xDDDCD5D9, tick()) // nop,flag ops,inc,dec,shifts,stack,transregister,interrupts
/* Stack operations and unconditional jumps */
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000100,0x00000001,0x00000100,0x00000000, tick(); t = Pop()) // pla,plp,rti
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000000,0x00000000, RB(PC++); PC = Pop(); PC |= (Pop() << 8)) // rti,rts
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000, RB(PC++)) // rts
t(7,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001, d=PC+(op?-1:1); Push(d>>8); Push(d)) // jsr, interrupts
t(7,0x00000000,0x00000000,0x00000000,0x00000000,0x00001000,0x00001000,0x00000001,0x00000001, PC = addr) // jmp, jsr, interrupts
t(7,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000100,0x00000000,0x00000101, Push(t)) // pha, php, interrupts
/* Bitmasks */
t(7,0x01010000,0x01010000,0x01010000,0x00010000,0x01010000,0x01010000,0x01010000,0x01010001, t = 1)
t(0,0x01010000,0x01010000,0x00000000,0x00000000,0x00000000,0x00000000,0x00010000,0x00010000, t <<= 1)
t(7,0x01000000,0x01000000,0x01000000,0x00000000,0x01010000,0x01010000,0x00010000,0x00010001, t <<= 2)
t(0,0x00000000,0x00000000,0x01000000,0x00000000,0x00010000,0x00010000,0x00010000,0x00010000, t <<= 4)
t(0,0xAAAAAAAA,0x01000000,0x01000000,0x00000000,0x00000000,0x01000000,0x00000000,0x01000000, t = u8(~t)) // sbc, isb, clear flag
t(7,0x01000000,0x00000000,0x00000000,0x00000000,0x01000000,0x00000000,0x01000000,0xAAAAA2AB, t = c | t) // ora, slo, set flag
t(0,0x00010000,0x01010000,0x01010000,0x00010000,0x00010000,0x01010000,0xAAABB2BA,0x01010000, t = c & t) // and, bit, rla, clear/test flag
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xAAAAA2AA,0x00000000,0x00000000, t = c ^ t) // eor, sre
/* Conditional branches */
t(0,0x00010000,0x00000000,0x00010000,0x00000000,0x00010000,0x00000000,0x00010000,0x00000000, if(t) { tick(); Misfire(PC, addr = s8(addr) + PC); PC=addr; })
t(0,0x00000000,0x00010000,0x00000000,0x00010000,0x00000000,0x00010000,0x00000000,0x00010000, if(!t) { tick(); Misfire(PC, addr = s8(addr) + PC); PC=addr; })
/* Addition and subtraction */
t(0,0xAAAAAAAA,0x00000000,0x00000000,0x00000000,0xAAAAA2AA,0x00000000,0x00000000,0x00000000, c = t; t += A + P.C; P.V = (c^t) & (A^t) & 0x80; P.C = t & 0x100)
t(0,0x00001011,0xAAAABABB,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, t = c - t; P.C = ~t & 0x100) // cmp,cpx,cpy, dcp, sbx
/* Store modified value (register) */
t(0,0xAAAAAAAA,0x00000000,0xAAAAAAAA,0x01000C00,0xAAAAAFAE,0xAAAAAEAE,0xAAAAAEAE,0xAAAAAEAE, A = t)
t(0,0x00000100,0x00000C00,0xCCCCCCCC,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, X = t) // ldx, dex, tax, inx, tsx,lax,las,sbx
t(0,0x00000000,0x00000100,0x10101111,0x00000100,0x00000000,0x00000000,0x00000000,0x00000000, Y = t) // ldy, dey, tay, iny
t(0,0x00000000,0x00000000,0x08000000,0x0C000000,0x00000000,0x00000000,0x00000000,0x00000000, S = t) // txs, las, shs
t(7,0x01000000,0x01000000,0x01000000,0x00000000,0x01000000,0x01000001,0x01000100,0x01000001, P.raw = t & ~0x30) // plp, rti, flag set/clear
/* Generic status flag updates */
t(0,0xEAEEFBFB,0xEAEEFFFB,0xFEFEFFFF,0x01000D00,0xEAEEEFEE,0xEAEEEEEE,0xEAEEEEEE,0xEAEEEEEE, P.N = t & 0x80)
t(0,0xEAEEFBFB,0xEAEEFFFB,0xFEFEFFFF,0x01000D00,0xEAEEEFEE,0xEAEEEEEE,0xEAEEFEFE,0xEAEEEEEE, P.Z = u8(t) == 0)
t(0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000800,0x00000000,0x00000000,0x00000000, P.V = (((t >> 5)+1)&2)) // [arr]
It can be decoded like this:
Code:
// Define the opcode decoding matrix, which decides which micro-operations constitute
// any particular opcode. (Note: The PLA of 6502 works on a slightly different principle.)
const unsigned o8 = op / 32, o8m = 1u << (op%32);
#define t(w8,w7,w6,w5,w4,w3,w2,w1,w0,code) if( \
(o8<1?w0##u : o8<2?w1##u : o8<3?w2##u : o8<4?w3##u : \
o8<5?w4##u : o8<6?w5##u : o8<7?w6##u : o8<8?w7##u : w8##u) & o8m) { code; }