Seeing how Instructions get Translated (Computer Architecture)

后端 未结 6 1503
面向向阳花
面向向阳花 2021-02-01 09:27

Little bit of a confusing question. But Im really looking for learning some low level programming. Thing is, Dev boards like Arduino/Etc. really hide alot of whats going on.

6条回答
  •  野的像风
    2021-02-01 09:32

    Here is an example framework for a very simple 6502 instruction set simulator (since you mentioned 6502 more than once). it starts with a simple 6502 program, and these are the only instructions that I am going to demonstrate, but even with a program like this you can get an understanding and have some instant gratification of seeing something work.

       and #$00
       ora #$01
     top:
       rol
       bcc top
       and #$00
    

    Yes, I am well aware that I am not booting the simulator properly. I am assuming this binary is based at address zero, using the xa65 assembler (apt-get install xa65). The binary after being assembled is:

    hexdump -C a.o65 
    00000000  29 00 09 01 2a 90 fd 29  00                       |)...*..).|
    00000009
    

    and this is the simple, reduced instruction, simulator

    #include 
    #include 
    #include 
    
    FILE *fp;
    
    #define MEMMASK 0xFFFF
    unsigned char mem[MEMMASK+1];
    
    unsigned short pc;
    unsigned short dest;
    unsigned char a;
    unsigned char x;
    unsigned char y;
    unsigned char sr;
    unsigned char sp;
    unsigned char opcode;
    unsigned char operand;
    
    unsigned char temp;
    
    int main ( void )
    {
        memset(mem,0xFF,sizeof(mem)); //if we execute a 0xFF just exit
    
        fp=fopen("a.o65","rb");
        if(fp==NULL) return(1);
        fread(mem,1,sizeof(mem),fp);
        fclose(fp);
    
        //reset the cpu
        pc=0; //I know this is not right!
        a=0;
        x=0;
        y=0;
        sr=0;
        sp=0;
        //go
        while(1)
        {
            opcode=mem[pc];
            printf("\n0x%04X: 0x%02X\n",pc,opcode);
            pc++;
            if(opcode==0x29) //and
            {
                operand=mem[pc];
                printf("0x%04X: 0x%02X\n",pc,operand);
                pc++;
                printf("and #$%02X\n",operand);
                a&=operand;
                if(a==0) sr|=2; else sr&=(~2);
                sr&=0x7F; sr|=a&0x80;
                printf("a = $%02X sr = $%02X\n",a,sr);
                continue;
            }
            if(opcode==0x09) //ora
            {
                operand=mem[pc];
                printf("0x%04X: 0x%02X\n",pc,operand);
                pc++;
                printf("ora #$%02X\n",operand);
                a|=operand;
                if(a==0) sr|=2; else sr&=(~2);
                sr&=0x7F; sr|=a&0x80;
                printf("a = $%02X sr = $%02X\n",a,sr);
                continue;
            }
            if(opcode==0x2A) //rol
            {
                printf("rol\n");
                temp=a;
                a<<=1;
                a|=sr&0x01;
                sr&=(~0x01); if(temp&0x80) sr|=0x01;
                if(a==0) sr|=2; else sr&=(~2);
                sr&=0x7F; sr|=a&0x80;
                printf("a = $%02X sr = $%02X\n",a,sr);
                continue;
            }
            if(opcode==0x90) //bcc
            {
                operand=mem[pc];
                printf("0x%04X: 0x%02X\n",pc,operand);
                pc++;
                dest=operand;
                if(dest&0x80) dest|=0xFF00;
                dest+=pc;
                printf("bcc #$%04X\n",dest);
                if(sr&1)
                {
                }
                else
                {
                    pc=dest;
                }
                continue;
            }
            printf("UNKNOWN OPCODE\n");
            break;
        }
        return(0);
    }
    

    and the simulator output for that simple program.

    0x0000: 0x29
    0x0001: 0x00
    and #$00
    a = $00 sr = $02
    
    0x0002: 0x09
    0x0003: 0x01
    ora #$01
    a = $01 sr = $00
    
    0x0004: 0x2A
    rol
    a = $02 sr = $00
    
    0x0005: 0x90
    0x0006: 0xFD
    bcc #$0004
    
    0x0004: 0x2A
    rol
    a = $04 sr = $00
    
    0x0005: 0x90
    0x0006: 0xFD
    bcc #$0004
    
    0x0004: 0x2A
    rol
    a = $08 sr = $00
    
    0x0005: 0x90
    0x0006: 0xFD
    bcc #$0004
    
    0x0004: 0x2A
    rol
    a = $10 sr = $00
    
    0x0005: 0x90
    0x0006: 0xFD
    bcc #$0004
    
    0x0004: 0x2A
    rol
    a = $20 sr = $00
    
    0x0005: 0x90
    0x0006: 0xFD
    bcc #$0004
    
    0x0004: 0x2A
    rol
    a = $40 sr = $00
    
    0x0005: 0x90
    0x0006: 0xFD
    bcc #$0004
    
    0x0004: 0x2A
    rol
    a = $80 sr = $80
    
    0x0005: 0x90
    0x0006: 0xFD
    bcc #$0004
    
    0x0004: 0x2A
    rol
    a = $00 sr = $03
    
    0x0005: 0x90
    0x0006: 0xFD
    bcc #$0004
    
    0x0007: 0x29
    0x0008: 0x00
    and #$00
    a = $00 sr = $03
    
    0x0009: 0xFF
    UNKNOWN OPCODE
    

    the full 6502 instruction set is a long weekend minimums worth of work if you write it from scratch, as you figure stuff out you may end up restarting the project a few times, perfectly natural. The hardware (in general, not necessarily 6502) for a processor isnt all that much different in concept to what happens in a simulator. You have to get the instruction, decode the instruction, fetch the operands, execute, and save the results. Just like with doing this in software, in hardware you can create interesting ways to make it faster or smaller or whatever your goal might be.

    6502 is still a big project if you implement the whole thing, not as big as z80, but things like risc16 is maybe half an hour to understand and write the whole simulator (then another half hour to make an assembler). the pic12, 14, or 16 is more work than risc16 but not too much more, can bang through it quickly and is an educational experience with how simple the design is. the pdp11 and msp430 are no doubt related somehow, both well documented (all of the ones I mention are well documented) and nicely/mostly orthogonal and the risc like decoding is a different experience than the cisc like 6502/z80/x86. (pdp11 is supported natively by gcc/gnu tools). Mips is super simple if you can work your algorithm around the branch defer slot.

    good luck, have fun...

提交回复
热议问题