• De-obfuscated Oscar Toledo's 8080 emulator

    From Ed Batalha@21:1/5 to All on Tue Feb 7 21:21:53 2023
    Hi all,

    I have de-obfuscated Oscar Toledo's emulator [1].

    I started out by running the C pre-processor to expand the '#defines'
    then adjusting some formatting.

    The whole emulator runs inside a 'for' loop. The initialisation inside
    the 'for' opens all the files and loads the 64Kbytes of memory from file C.
    The halt instruction (hlt, 0x76), 118) stops the emulator when
    encountered so it is used in the 'for' loop exit condition.
    The bulk of the work is done in the 3rd clause of the for loop.

    We see a succession of ...?...?...?...?... ... ...:...:...:...:...
    K&R 2nd edition has this to say about the ? operator:
    "
    expr1 ? expr2 : expr3
    the expression expr1 is evaluated first. If it is non-zero (true), then
    the expression expr2 is evaluated, and it is the value of the
    conditional expression. Otherwise expr3 is evaluated, and that is the
    value Only one of expr2 and expr3 is evaluated.
    "

    The way Oscar Toledo did it is: if the 8080 instruction he got from the
    memory array makes 'expr1' evaluate to zero then the program flows sends
    it to evaluate 'expr3'.
    Once I realised that, I started matching the first '?' to the last ':'
    and writing those clue comments "/*001*/" up and down the file and
    continued from there until I had all of them done. Next was the
    formatting related to all those commas. To help me identify which 8080
    opcode was being done I looked at a 8080 manual where one of the pages
    is a summary of all of them. Lots of decimal to binary to hex
    conversions later and I had all opcodes identified.
    As I went along I also added comments.

    After all that, one comes to the conclusion that the emulator is really
    simple and easy to understand and just really nice to study.

    Some of the things I really like:
    - all in one file
    - small variable names
    - no unnecessary functions and function calls

    [1] https://nanochess.org/emulator.html


    (note: my newsgroup client wraps lines at 72 columns. Some editing may
    be required if you want to use the code below.)

    #include <stdio.h>

    unsigned char o[10],l[78114],*c=l,*k=l+64506; // 0xFBFA
    e,V,v,u,x,y,z,Z;

    main(r,U)char**U;
    {

    for(
    v =fopen(((u =fopen(((e =fopen(((r-2?0:(V
    =fopen((1[U]),"rb+")),"C")),"rb+")
    ,system("stty raw -echo min 0")
    ,fread(l,78114,1,e)
    ,fclose((e)),
    "B")),"rb+"),"A")),"rb+")
    // At the end of initialisation
    // v file pointer to file A
    // u file pointer to file B
    // V file pointer to file in the command line
    // array l contains contents of File C (why 78114?)
    ;
    118-(x=*c++) // 0x76 stop instruction, exits for loop
    // the x variable contains the current 8080 opcode being evaluated
    // the c variable is the current program counter
    /*
    o[0] = B register o[1] = C register
    o[2] = D register o[3] = E register
    o[4] = H register o[5] = L register
    o[6] = Flags o[7] = A or accumulator
    O[8] = SP high byte o[9] = SP low byte

    DB 00 Reads key pressed status
    DB 01 Reads key
    DB 02 Reads byte from file (Carry=EOF)
    D3 xx Writes byte from acc. to console
    ED ED 02 Reads sector (128 bytes)
    ED ED 03 Writes sector (128 bytes)
    */

    ;
    /*001*/ (y=x/8%8,z=(x&199)-4 )? // 4 INR increment register
    // y=0 -> B
    // y=1 -> C
    // y=2 -> D
    // y=3 -> E
    // y=4 -> H
    // y=5 -> L
    // y=6 -> MEMORY POINTED BY HL
    // y=7 -> A

    /*002*/ (z-= 1 )? // 5 DCR decrement register pair

    /*003*/ (z-= 1 )? // 6 MVI move immediate

    /*004*/ (z-= 186 )? // 192 RETURN ON FLAG FAMILY
    // y=0 -> RNZ
    // y=1 -> RZ
    // y=2 -> RNC
    // y=3 -> RC
    // y=4 -> RPO
    // y=5 -> RPE
    // y=6 -> RP
    // y=7 -> RM

    /*005*/ (z-= 2 )? // 194 JUMP ON FLAG FAMILY
    // y=0 -> RNZ
    // y=1 -> RZ
    // y=2 -> RNC
    // y=3 -> RC
    // y=4 -> RPO
    // y=5 -> RPE
    // y=6 -> RP
    // y=7 -> RM

    /*006*/ (z-= 2 )? // 196 CALL ON FLAG FAMILY
    // y=0 -> RNZ
    // y=1 -> RZ
    // y=2 -> RNC
    // y=3 -> RC
    // y=4 -> RPO
    // y=5 -> RPE
    // y=6 -> RP
    // y=7 -> RM

    /*007*/ (z-= 3 )? // 199 RST Restart
    // y=0 -> JUMP TO ADDR 0
    // y=1 -> JUMP TO ADDR 8
    // y=2 -> JUMP TO ADDR 16
    // y=3 -> JUMP TO ADDR 24
    // y=4 -> JUMP TO ADDR 32
    // y=5 -> JUMP TO ADDR 40
    // y=6 -> JUMP TO ADDR 48
    // y=7 -> JUMP TO ADDR 56

    /*008*/ (z-= 0,r=(y>5)*2+y,z=(x&207)-1 )? // 1 LXI load register pair
    immediate
    // y=0 -> BC
    // y=2 -> DE
    // y=4 -> HL
    // y=6 -> SP

    /*009*/ (z-= 2 )? // 3 INX increment register pair
    // y=0 -> BC
    // y=2 -> DE
    // y=4 -> HL
    // y=6 -> SP

    /*010*/ (z-= 6 )? // 9 DAD add register pair to HL
    // y=1 -> BC
    // y=3 -> DE
    // y=5 -> HL
    // y=7 -> SP

    /*011*/ (z-= 2 )? // 11 DCX increment register pair
    // y=0 -> BC
    // y=2 -> DE
    // y=4 -> HL
    // y=6 -> SP

    /*012*/ (z-= 182 )? // 193 POP register pair from STACK
    // y=0 -> BC
    // y=2 -> DE
    // y=4 -> HL
    // y=6 -> A and Flags

    /*013*/ (z-= 4)? // 197 PUSH register pair to STACK
    // y=0 -> BC
    // y=2 -> DE
    // y=4 -> HL
    // y=6 -> A and Flags

    /*014*/ x/8!=16+0&198+0*8!=x? // 128 ADD r add register to A or 198
    ADI add immediate to A
    /*015*/ x/8!=16+1&198+1*8!=x? // 136 ADC r add register to A with
    carry 206 ACI add immediate to A with carry
    /*016*/ x/8!=16+2&198+2*8!=x? // 144 SUB r subtract register 214 SUI
    subract immediate from A
    /*017*/ x/8!=16+3&198+3*8!=x? // 152 SBB r subtract register with
    borrow 222 SUB subract immediate from A with borrow
    /*018*/ x/8!=16+4&198+4*8!=x? // 160 ANA r and register with A 230 ANI
    and immediate with A
    /*019*/ x/8!=16+5&198+5*8!=x? // 168 XRA r exclusive or register with
    A 238 XRI exclusive or immediate with A
    /*020*/ x/8!=16+6&198+6*8!=x? // 176 ORA r or register with A 246 ORI
    or immediate with A
    /*021*/ x/8!=16+7&198+7*8!=x? // 184 CMP r compare register with A 254
    CPI compare immediate with A

    /*022*/ (z=x-2 )? // 2 STAX B store A indirect
    /*023*/ (z-= 5 )? // 7 RLC rotate A left
    /*024*/ (z-= 3 )? // 10 LDAX B load A indirect
    /*025*/ (z-= 5 )? // 15 RRC rotate A right
    /*026*/ (z-= 3 )? // 18 STAX D store A indirect
    /*027*/ (z-= 5 )? // 23 RAL rotate A left through carry
    /*028*/ (z-= 3 )? // 26 LDAX D load A indirect
    /*029*/ (z-= 5 )? // 31 RAR rotate A right through carry
    /*030*/ (z-= 3 )? // 34 SHLD store H and L direct
    /*031*/ (z-= 5 )? // 39 DAA decimal adjust A
    /*032*/ (z-= 3 )? // 42 LHLD load H and L direct
    /*033*/ (z-= 5 )? // 47 CMA complement A
    /*034*/ (z-= 3 )? // 50 STA store A direct
    /*035*/ (z-= 5 )? // 55 STC set carry
    /*036*/ (z-= 3 )? // 58 LDA load A direct
    /*037*/ (z-= 5 )? // 63 CMC complement carry
    /*038*/ (z-= 3 +129 )? // 195 JMP jump unconditional
    /*039*/ (z-= 6 )? // 201 RET return
    /*040*/ (z-= 4 )? // 205 CALL Call unconditional
    /*041*/ (z-= 6 )? // 211 0xD3 OUT Output
    /*042*/ (z-= 8 )? // 219 0xDB IN Input
    /*043*/ (z-= 8 )? // 227 XTHL exchange top of stack with HL /*044*/ (z-= 6 )? // 233 PCHL HL to program counter
    /*045*/ (z-= 2 )? // 235 XCHG exchange HL with DE
    /*046*/ (z-= 2 )? // 237 0xED - read or write sectors to disk /*047*/ (z-= 12)? // 249 SPHL HL to stack pointer
    /*048*/ x/64-1? // 64 MOV r1,r2 MOV M,r MOV r,M
    /*NO */ ((0 )):
    /*048*/ (( // 64 MOV r1,r2 MOV M,r MOV r,M
    *((7&y)-6?&o[y&7]:&l[o[5]+256*o[5 -1]])=*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    )):
    /*047*/ (( // 249 SPHL HL to stack pointer
    9[o]=*((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]])
    ,8[o]=*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]])
    )):
    /*046*/ (( // 237 0xED - read or write sectors to disk
    237==*c++? // 2nd also 0xED? Skip it
    ((int (*)())(2-*c++?fwrite:fread)) //if 3rd byte is 2
    read, otherwise write
    (l+*k+1[k]*256,128,1,(fseek(y=5[k]-1?u:v // 0=A:, 1=B:
    ,((3[k]|4[k]<<8)<<7|2[k])<<7
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=0)
    ,y
    )
    )
    :0
    )):
    // 0[k] = FBFA - Low source/target address
    // 1[k] = FBFB - High source/target
    address
    // 2[k] = FBFC - Sector (0-127)
    // 3[k] = FBFD - Cylinder (low byte)
    // 4[k] = FBFE - Cylinder (high byte)
    // 5[k] = FBFF - Drive (1/2)

    /*045*/ (( // 235 XCHG exchange HL with DE
    y=*((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]])
    ,z=*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]])
    ,*((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]])=*((7&3)-6?&o[3&7]:&l[o[5]+256*o[5 -1]])
    ,*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]])=*((7&2)-6?&o[2&7]:&l[o[5]+256*o[5 -1]])
    ,*((7&3)-6?&o[3&7]:&l[o[5]+256*o[5 -1]])=y
    ,*((7&2)-6?&o[2&7]:&l[o[5]+256*o[5 -1]])=z
    )):
    /*044*/ (( // 233 PCHL HL to program counter
    c=l+o[5]+256*o[5 -1]
    )):
    /*043*/ (( // 227 XTHL exchange top of stack with HL
    y=l[x=o[9]+256*o[9 -1]]
    ,z=l[++x]
    ,x[l]=*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]])
    ,l[--x]=*((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]])
    ,*((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]])=y
    ,*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]])=z
    )):
    /*042*/ (( // 219 IN Input
    2-*c?Z||read(0,&Z,1)
    ,1&*c++?*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=Z,Z=0
    :(*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=!!Z)
    :(c++
    ,*((7&7)-6?&o[7&7]
    :&l[o[5]+256*o[5 -1]]
    )
    =r=V?fgetc(V):-1
    ,6[o]=6[o]&~1|r<0
    )
    )):
    /*041*/ (( // 211 OUT Output
    ++c,write(1,&7[o],1)
    )):
    /*040*/ (( // 205 CALL Call unconditional
    z=c+2-l
    ,254>(9[o]-=2)||--8[o],l[o[9]+256*o[9 -1]]=z
    ,l[1+o[9]+256*o[9 -1]]=z>>8
    ,c=l+(c+=2,0[c-2]|1[c-2]<<8)
    )):
    /*039*/ (( // 201 RET return
    z=l[o[9]+256*o[9 -1]]|l[o[9]+256*o[9
    -1]+1]<<8,1<(9[o]+=2)||++8[o]
    ,c=l+z
    )):
    /*038*/ (( // 195 JMP jump unconditional
    c=l+(c+=2,0[c-2]|1[c-2]<<8)
    )):
    /*037*/ (( // 63 CMC complement carry
    6[o]^=1
    )):
    /*036*/ (( // 58 LDA load A direct
    *((7&7)-6?&o[7&7]:&l[o[5]+256*o[5
    -1]])=(c+=2,0[c-2]|1[c-2]<<8)[l]
    )):
    /*035*/ (( // 55 STC set carry
    6[o]|=1
    )):
    /*034*/ (( // 50 STA store A direct
    (c+=2,0[c-2]|1[c-2]<<8)[l]=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5
    -1]])
    )):
    /*033*/ (( // 47 CMA complement A
    *((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=~*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    )):
    /*032*/ (( // 42 LHLD load H and L direct
    *((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]])=l[x=(c+=2,0[c-2]|1[c-2]<<8)]
    ,*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]])=l[++x]
    )):
    /*031*/ (( // 39 DAA decimal adjust A
    6[o]|=6[o]&16|9<*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])%16?*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])+=6
    ,16:0
    ,z=6[o]|=1&6[o]|*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])>159?*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])+=96
    ,1:0
    ,y=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    ,6[o]=6[o]<<8>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*030*/ (( // 34 SHLD store H and L direct

    l[x=(c+=2,0[c-2]|1[c-2]<<8)]=*((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]])
    ,l[++x]=*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]])
    )):
    /*029*/ (( // 31 RAR rotate A right through carry
    x=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])%2
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])/2+6[o]%2*128,6[o]=6[o]&~1|x
    )):
    /*028*/ (( // 26 LDAX D load A indirect
    *((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=l[o[3]+256*o[3 -1]]
    )):
    /*027*/ (( // 23 RAL rotate A left through carry
    x=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]]) /128
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])*2+6[o]%2,6[o]=6[o]&~1|x
    )):
    /*026*/ (( // 18 STAX D store A indirect
    l[o[3]+256*o[3 -1]]=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    )):
    /*025*/ (( // 15 RRC rotate A right
    6[o]=6[o]&~1|1&*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])/2|*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])<<7
    )):
    /*024*/ (( // 10 LDAX B load A indirect
    *((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=l[o[1]+256*o[1 -1]]
    )):
    /*023*/ (( // 7 RLC rotate A left
    6[o]=~1&6[o]|*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])>>7
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])*2|*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])>>7
    )):
    /*022*/ (( // 2 STAX B store A indirect
    l[o[1]+256*o[1 -1]]=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    )):
    /*021*/ (( // 184 CMP r compare register with A 254 CPI compare
    immediate with A
    x=64&x?*c++:*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    , y =y=(z=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])%16 - x%16 - 0
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])- x - 0
    )
    ,6[o]=y>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*020*/ (( // 176 ORA r or register with A 246 ORI or immediate with A
    x=64&x?*c++:*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    , z=0
    ,y=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])|=x
    ,6[o]=y>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*019*/ (( // 168 XRA r exclusive or register with A 238 XRI exclusive
    or immediate with A
    x=64&x?*c++:*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    , z=0
    ,y=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])^=x
    ,6[o]=y>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*018*/ (( // 160 ANA r and register with A 230 ANI and immediate with A
    x=64&x?*c++:*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    , z=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])*2|2*x
    ,y=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])&=x
    ,6[o]=y>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*017*/ (( // 152 SBB r subtract register with borrow 222 SUB subract
    immediate from A with borrow
    x=64&x?*c++:*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    , *((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    =y=(z=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])%16 - x%16 -
    6[o]%2
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])- x - 6[o]%2
    )
    ,6[o]=y>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*016*/ (( // 144 SUB r subtract register 214 SUI subract immediate from A
    x=64&x?*c++:*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    , *((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    =y=(z=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])%16 - x%16 - 0
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])- x - 0
    )
    ,6[o]=y>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*015*/ (( // 136 ADC r add register to A with carry 206 ACI add
    immediate to A with carry
    x=64&x?*c++:*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    , *((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    =y=(z=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])%16 + x%16
    + 6[o]%2
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])+ x + 6[o]%2
    )
    ,6[o]=y>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*014*/ (( // 128 ADD r add register to A or 198 ADI add immediate to A
    x=64&x?*c++:*((7&x)-6?&o[x&7]:&l[o[5]+256*o[5 -1]])
    , *((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])
    =y=
    (z=*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])%16 + x%16 + 0
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])+ x + 0
    )
    ,6[o]=y>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*013*/ (( // PUSH B, PUSH D, PUSH H, PUSH PSW
    z=r-8?o[r+1]+256*o[r+1
    -1]:6[o]|*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])<<8
    ,254>(9[o]-=2)||--8[o]
    ,l[o[9]+256*o[9 -1]]=z
    ,l[1+o[9]+256*o[9 -1]]=z>>8
    )):
    /*012*/ (( // POP B, POP D, POP H, POP PSW
    z=l[o[9]+256*o[9 -1]]|l[o[9]+256*o[9 -1]+1]<<8
    ,1<(9[o]+=2)||++8[o]
    ,r-8?o[r+1]=z,r[o]=z>>8
    :( 6[o]=~40&z|2
    ,*((7&7)-6?&o[7&7]:&l[o[5]+256*o[5 -1]])=z>>8
    )
    )):
    /*011*/ (( // DCX
    r[o]--||--o[r-1]
    )):
    /*010*/ (( // DAD
    *((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]]) // L register
    =z=*((7&5)-6?&o[5&7]:&l[o[5]+256*o[5 -1]])+r[o]
    ,*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]]) //H register
    =z=*((7&4)-6?&o[4&7]:&l[o[5]+256*o[5 -1]])+o[r-1]+z/256
    ,6[o]=~1&6[o]|z>>8 // update carry flag if needed
    )):
    /*009*/ (( // INX
    ++o[r+1]||r[o]++
    )):
    /*008*/ (( //LXI
    o[r+1]=*c++
    ,r[o]=*c++
    )):
    /*007*/ (( // RST Restart
    z=c-l
    ,254>(9[o]-=2)||--8[o]
    ,l[o[9]+256*o[9 -1]]=z
    ,l[1+o[9]+256*o[9 -1]]=z>>8
    ,c=y*8+l
    )):
    /*006*/ (( // CALL ON FLAG FAMILY
    x=(c+=2,0[c-2]|1[c-2]<<8)
    ,(y&1?~6[o]:6[o])>>"\6\0\2\7"[y/2]&1?0: //Test flags
    ( z=c-l
    ,254>(9[o]-=2)||--8[o] // Update SP
    ,l[o[9]+256*o[9 -1]]=z // Update STACK with return
    address
    ,l[1+o[9]+256*o[9 -1]]=z>>8 // Update STACK with return
    address
    ,c=l+x // update PC
    )
    )):
    /*005*/ (( // JUMP ON FLAG FAMILY
    x=(c+=2,0[c-2]|1[c-2]<<8) // wow!! index 0 and index 1 to
    the array of bytes pointed by c-2
    ,(y&1?~6[o]:6[o])>>"\6\0\2\7"[y/2]&1?0:( c=l+x)
    )):
    /*004*/ (( // RETURN ON FLAG FAMILY
    (y&1?~6[o]:6[o])
    >>"\6\0\2\7"[y/2]&1?0: //wow, an array of chars
    indexed. This tests each flag
    ( z=l[o[9]+256*o[9 -1]]|l[o[9]+256*o[9 -1]+1]<<8 // z=
    value pointed by the stack pointer
    ,1<(9[o]+=2)||++8[o] // update SP
    ,c=l+z // Update PC
    )
    )):
    /*003*/ (( // MVI
    *((7&y)-6?&o[y&7]:&l[o[5]+256*o[5 -1]])=*c++
    )):
    /*002*/ (( // DCR
    r=y
    ,x=0
    ,*((7&r)-6?&o[r&7]:&l[o[5]+256*o[5 -1]])
    =y
    =(z=*((7&y)-6?&o[y&7]:&l[o[5]+256*o[5 -1]])%16 - x%16 - 1
    ,*((7&y)-6?&o[y&7]:&l[o[5]+256*o[5 -1]])- x - 1
    )
    ,6[o]=6[o]<<8>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    )):
    /*001*/ (( // INR
    r=y
    ,x=0
    ,*((7&r)-6?&o[r&7]:&l[o[5]+256*o[5 -1]])
    =y
    =(z=*((7&y)-6?&o[y&7]:&l[o[5]+256*o[5 -1]])%16 + x%16 + 1
    ,*((7&y)-6?&o[y&7]:&l[o[5]+256*o[5 -1]])+ x + 1
    )
    ,6[o]=6[o]<<8>>8&1|128&y|!(y&255)*64|16&z|2
    ,y^=y>>4
    ,y^=y<<2
    ,y^=~y>>1
    ,6[o]|=y&4
    ))
    );
    system("stty cooked echo");
    fclose(((fclose(((V?fclose((V)):0,u))),v)));

    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence Woodman@21:1/5 to Ed Batalha on Wed Feb 8 01:23:52 2023
    On Tuesday, 7 February 2023 at 21:21:55 UTC, Ed Batalha wrote:
    I have de-obfuscated Oscar Toledo's emulator [1].

    I started out by running the C pre-processor to expand the '#defines'
    then adjusting some formatting.

    The whole emulator runs inside a 'for' loop. The initialisation inside
    the 'for' opens all the files and loads the 64Kbytes of memory from file C. The halt instruction (hlt, 0x76), 118) stops the emulator when
    encountered so it is used in the 'for' loop exit condition.
    The bulk of the work is done in the 3rd clause of the for loop.

    [SNIP]

    Great work. I had a quick go at compiling it but have run out of time
    to get it to compile - fixing the wordwrap got a bit complicated for the
    time I had.

    Nevertheless, with the aid of your notes it was interesting to work
    through. I've got a thing for small emulators and indeed am working
    on a PDP-8 emulator at the moment.

    Best wishes


    Lorry


    ---
    XCCP: A Shell Extension for CP/M https://techtinkering.com/articles/xccp-a-shell-extension-for-cpm/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)