Untitled

 avatar
unknown
c_cpp
5 months ago
16 kB
3
Indexable
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#include "armemu.h"

// Analysis functions

void analysis_init(struct analysis_st *ap)
{
    ap->i_count = 0;
    ap->dp_count = 0;
    ap->mem_count = 0;
    ap->b_count = 0;
    ap->b_taken = 0;
    ap->b_not_taken = 0;
}

// Project04: Print results of dynamic analysis
void analysis_print(struct analysis_st *ap)
{
    printf("=== Analysis\n");
    printf("I_count       = %d\n", ap->i_count);
    printf("DP_count      = %d (%.2f%%)\n", ap->dp_count,
           ((double)ap->dp_count / (double)ap->i_count) * 100.0);
    printf("SDT_count     = %d (%.2f%%)\n", ap->mem_count,
           ((double)ap->mem_count / (double)ap->i_count) * 100.0);
    printf("B_count       = %d (%.2f%%)\n", ap->b_count,
           ((double)ap->b_count / (double)ap->i_count) * 100.0);
    printf("B_taken       = %d (%.2f%%)\n", ap->b_taken,
           ((double)ap->b_taken / (double)ap->b_count) * 100.0);
    printf("B_not_taken   = %d (%.2f%%)\n", ap->b_not_taken,
           ((double)ap->b_not_taken / (double)ap->b_count) * 100.0);
}

// Project04: Print results of dynamic analysis and cache sim
void armemu_print(struct arm_state *asp)
{
    if (asp->analyze)
    {
        analysis_print(&(asp->analysis));
    }
    if (asp->cache_sim)
    {
        cache_print((&asp->cache));
    }
}

void armemu_init(struct arm_state *asp, uint32_t *func,
                 uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3)
{
    int i;

    // Zero out registers
    for (i = 0; i < NREGS; i += 1)
    {
        asp->regs[i] = 0;
    }

    // Zero out the CPSR
    asp->cpsr = 0;

    // Zero out the stack
    for (i = 0; i < STACK_SIZE; i += 1)
    {
        asp->stack[i] = 0;
    }

    // Initialize the Program Counter
    asp->regs[PC] = (uint32_t)func;

    // Initialize the Link Register to a sentinel value
    asp->regs[LR] = 0;

    // Initialize Stack Pointer to the logical bottom of the stack
    asp->regs[SP] = (uint32_t)&asp->stack[STACK_SIZE];

    // Initialize the first 4 arguments in emulated r0-r3
    asp->regs[0] = a0;
    asp->regs[1] = a1;
    asp->regs[2] = a2;
    asp->regs[3] = a3;

    // Project04: Initialize dynamic analysis
    analysis_init(&asp->analysis);

    // Project04: Initialize cache simulator
    cache_init(&asp->cache);
}

bool check_flags(struct arm_state *asp, unsigned int iw)
{
    uint32_t cond = (iw >> 28) & 0b1111;
    uint32_t z_flag = asp->cpsr >> 30 & 0b1;
    uint32_t n_flag = asp->cpsr >> 31 & 0b1;
    uint32_t v_flag = asp->cpsr >> 28 & 0b1;

    //EQ equal
    if (cond == 0b0000)
    {
        return z_flag == 1;
    }
    //NE not equal
    if (cond == 0b0001)
    {
        return z_flag == 0;
    }
    //GE greater or equal
    if (cond == 0b1010)
    {
        return (n_flag == v_flag);
    }
    //LT less than
    if (cond == 0b1011)
    {
        return (n_flag != v_flag);
    }
    //GT greater than
    if (cond == 0b1100)
    {
        return ((z_flag == 0) && (n_flag == v_flag));
    }
    //LE less or equal
    if (cond == 0b1101)
    {
        return ((z_flag == 1) || (n_flag != v_flag));
    }
    //AL always
    if (cond == 0b1110)
    {
        return true;
    }
    //not supported, default return false
    else
    {
        return false;
    }
}

void armemu_cmp(struct arm_state *asp, uint32_t iw)
{
    asp->analysis.dp_count += 1;
    uint32_t i_bit = (iw >> 25) & 0b1;
    uint32_t rn = (iw >> 16) & 0b1111;
    uint32_t rm = iw & 0b1111;
    uint32_t imm = iw & 0b11111111;
    uint32_t oper2;
    uint32_t result;
    int result2;
    uint32_t oper1;

    if (!i_bit)
    {
        oper2 = asp->regs[rm];
    }
    else
    {
        oper2 = imm;
    }
	oper1 = asp->regs[rn];

    result = asp->regs[rn] - oper2;
    result2 = asp->regs[rn] - oper2;

    //set overflow
    if (((oper1 << 31 == 0) && (oper2 << 31 == 0) && (result << 31 == 1)) || 
	((oper2 << 31 == 0) && (oper1 << 31 == 1) && (result2 > 0)))
    {
        asp->cpsr = asp->cpsr | 0b00010000000000000000000000000000;
    }
    else
    {
        asp->cpsr = asp->cpsr & 0b11101111111111111111111111111111;
    }
    //set carry
    if (oper2 > oper1)
    {
        asp->cpsr = asp->cpsr | 0b00100000000000000000000000000000;
    }
    else
    {
        asp->cpsr = asp->cpsr & 0b11011111111111111111111111111111;
    }
    //set zero, clear negative
    if (result == 0)
    {
        asp->cpsr = asp->cpsr | 0b01000000000000000000000000000000;
        asp->cpsr = asp->cpsr & 0b01111111111111111111111111111111;
    }
    //set negative, clear zero
    if (result2 < 0)
    {
        asp->cpsr = asp->cpsr | 0b10000000000000000000000000000000;
        asp->cpsr = asp->cpsr & 0b10111111111111111111111111111111;
    }
    //clear negative and zero
    if (result2 > 0)
    {
        asp->cpsr = asp->cpsr & 0b01111111111111111111111111111111;
        asp->cpsr = asp->cpsr & 0b10111111111111111111111111111111;
    }

    asp->regs[PC] = asp->regs[PC] + 4;
}

bool armemu_is_cmp(uint32_t iw)
{
    uint32_t dp_bits = (iw >> 26) & 0b11;
    uint32_t opcode = (iw >> 21) & 0b1111;

    return (dp_bits == 0b00) & (opcode == 0b1010);
}

bool armemu_is_bx(uint32_t iw)
{
    uint32_t bxcode;

    bxcode = (iw >> 4) & 0xFFFFFF;

    // 0x12fff1 == 0b000100101111111111110001
    return bxcode == 0x12fff1;
}

void armemu_bx(struct arm_state *asp, uint32_t iw)
{
    uint32_t rn = iw & 0b1111;

    // Project04: increment dynamic analysis
    asp->analysis.b_count += 1;
    asp->analysis.b_taken += 1;

    asp->regs[PC] = asp->regs[rn];
}

bool armemu_is_data_transfer(uint32_t iw)
{
    uint32_t check = (iw >> 26) & 0b11;
    return (check == 0b01);
}

void armemu_data_transfer(struct arm_state *asp, uint32_t iw)
{

    asp->analysis.mem_count += 1;

    uint32_t rd = (iw >> 12) & 0b1111;
    uint32_t rn = (iw >> 16) & 0b1111;
    uint32_t offset_value;
    uint32_t i_bit = (iw >> 25) & 0b1;
    uint32_t l_bit = (iw >> 20) & 0b1;
    uint32_t b_bit = (iw >> 22) & 0b1;

    uint32_t rm;
    uint32_t transfer_value;

    //check if operand needs to be shifted
    if (i_bit == 1)
    {
        uint32_t shifttype = (iw >> 5) & 0b11;
        uint32_t rs = (iw >> 8) & 0b1111;
        uint32_t shiftamount;
        uint32_t oper2;
        if ((((iw >> 7) & 0b1) == 0) && (((iw >> 4) & 0b1) == 1))
        {
            shiftamount = asp->regs[rs];
        }
        else
        {
            shiftamount = (iw >> 7) & 0b11111;
        }
        rm = iw & 0b1111;
        oper2 = asp->regs[rm];
        offset_value = asp->regs[rm];
        //lsl, shift left
        if (shifttype == 0b00)
        {
            oper2 = oper2 << shiftamount;
        }
        //lsr, logical shift right
        else if (shifttype == 0b01)
        {
            oper2 = oper2 >> shiftamount;
        }
        //asr, arithmetic shift right
        else if (shifttype == 0b10)
        {
            if ((oper2 >> 31) == 1)
            {
                oper2 = oper2 >> shiftamount;
                uint32_t bitmask2 = 0b11111111111111111111111111111111;
                bitmask2 = bitmask2 - ((1 << (shiftamount)) - 1);
                oper2 = oper2 | bitmask2;
            }
            //rotate right??
            else
            {
                oper2 = oper2 >> shiftamount;
            }
        }
        offset_value = oper2;
    }
    //immediate operand
    else
    {
        offset_value = iw & 0b111111111111;
    }

    //check if load, then if as a byte
    if (l_bit == 1)
    {
        if ((b_bit == 1))
        {
            transfer_value = *((uint8_t *)(asp->regs[rn] + offset_value));
        }
        else
        {
            transfer_value = *((uint32_t *)(asp->regs[rn] + offset_value));
        }

        asp->regs[rd] = transfer_value;
    }
    //store
    else
    {
        transfer_value = asp->regs[rd];
        if (b_bit == 1)
        {
            *(uint8_t *)(asp->regs[rn] + offset_value) = transfer_value;
        }
        else
        {
            *(uint32_t *)(asp->regs[rn] + offset_value) = transfer_value;
        }
    }

    if (rd != PC)
    {
        asp->regs[PC] = asp->regs[PC] + 4;
    }
}

bool armemu_is_add(uint32_t iw)
{
    uint32_t dp_bits = (iw >> 26) & 0b11;
    uint32_t opcode = (iw >> 21) & 0b1111;

    return (dp_bits == 0b00) & (opcode == 0b0100);
}

bool armemu_is_mul(uint32_t iw)
{
    uint32_t check1 = (iw >> 22) & 0b111111;
    uint32_t check2 = (iw >> 4) & 0b1111;

    return (check1 == 0b000000) & (check2 == 0b1001);
}

bool armemu_is_mov(uint32_t iw)
{
    uint32_t dp_bits = (iw >> 26) & 0b11;
    uint32_t opcode = (iw >> 21) & 0b1111;

    return (dp_bits == 0b00) & (opcode == 0b1101);
}

bool armemu_is_branch(uint32_t iw)
{
    uint32_t check = (iw >> 25) & 0b101;

    return (check == 0b101);
}

void armemu_branch(struct arm_state *asp, uint32_t iw)
{
    uint32_t link_bit = (iw >> 24) & 0b1;
    uint32_t offset = iw & 0b111111111111111111111111;

    if ((offset >> 23) == 1)
    {
        offset = offset | 0b11111111000000000000000000000000;
    }

    offset = offset << 2;

    if (link_bit == 1)
    {
        asp->regs[LR] = asp->regs[PC] + 4;
    }
    asp->regs[PC] = asp->regs[PC] + (offset + 8);
}

void armemu_mov(struct arm_state *asp, uint32_t iw)
{
    asp->analysis.dp_count += 1;
    uint32_t i_bit = (iw >> 25) & 0b1;
    uint32_t rd = (iw >> 12) & 0b1111;
    uint32_t rm = iw & 0b1111;
    uint32_t imm = iw & 0b11111111;
    uint32_t oper2;
    uint32_t shiftamount;
    uint32_t shifttype = (iw >> 5) & 0b11;
    uint32_t rs = (iw >> 8) & 0b1111;

    //determine shift amount if shift is required
    if ((((iw >> 7) & 0b1) == 0) && (((iw >> 4) & 0b1) == 1))
    {
        shiftamount = asp->regs[rs];
    }
    else
    {
        shiftamount = (iw >> 7) & 0b11111;
    }

    if (!i_bit)
    {
        oper2 = asp->regs[rm];
        if (shifttype == 0b00)
        {
            oper2 = oper2 << shiftamount;
        }
        else if (shifttype == 0b01)
        {
            oper2 = oper2 >> shiftamount;
        }
        else if (shifttype == 0b10)
        {
            if ((oper2 >> 31) == 1)
            {
                oper2 = oper2 >> shiftamount;
                uint32_t bitmask2 = 0b11111111111111111111111111111111;
                bitmask2 = bitmask2 - ((1 << (shiftamount)) - 1);
                oper2 = oper2 | bitmask2;
            }
            else
            {
                oper2 = oper2 >> shiftamount;
            }
        }
    }
    else
    {
        oper2 = imm;
    }

    asp->regs[rd] = oper2;

    if (rd != PC)
    {
        asp->regs[PC] = asp->regs[PC] + 4;
    }
}

void armemu_add(struct arm_state *asp, uint32_t iw)
{
    uint32_t i_bit = (iw >> 25) & 0b1;
    uint32_t rn = (iw >> 16) & 0b1111;
    uint32_t rd = (iw >> 12) & 0b1111;
    uint32_t rm = iw & 0b1111;
    uint32_t imm = iw & 0b11111111;
    uint32_t oper2;

    // Project04: Increment analysis count
    asp->analysis.dp_count += 1;

    if (!i_bit)
    {
        oper2 = asp->regs[rm];
    }
    else
    {
        oper2 = imm;
    }

    asp->regs[rd] = asp->regs[rn] + oper2;

    if (rd != PC)
    {
        asp->regs[PC] = asp->regs[PC] + 4;
    }
}

void armemu_mul(struct arm_state *asp, uint32_t iw)
{
    asp->analysis.dp_count += 1;
    uint32_t a_bit = (iw >> 21) & 0b1;
    uint32_t rd = (iw >> 16) & 0b1111;
    uint32_t rn = (iw >> 12) & 0b1111;
    uint32_t rs = (iw >> 8) & 0b1111;
    uint32_t rm = iw & 0b1111;

    asp->regs[rd] = asp->regs[rm] * asp->regs[rs];
    if (a_bit)
    {
        asp->regs[rd] = asp->regs[rd] + asp->regs[rn];
    }

    if (rd != PC)
    {
        asp->regs[PC] = asp->regs[PC] + 4;
    }
}

void armemu_sub(struct arm_state *asp, uint32_t iw)
{
    asp->analysis.dp_count += 1;
    uint32_t i_bit = (iw >> 25) & 0b1;
    uint32_t rn = (iw >> 16) & 0b1111;
    uint32_t rd = (iw >> 12) & 0b1111;
    uint32_t rm = iw & 0b1111;
    uint32_t imm = iw & 0b11111111;
    uint32_t oper2;

    if (!i_bit)
    {
        oper2 = asp->regs[rm];
    }
    else
    {
        oper2 = imm;
    }

    asp->regs[rd] = asp->regs[rn] - oper2;

    if (rd != PC)
    {
        asp->regs[PC] = asp->regs[PC] + 4;
    }
}

void armemu_revsub(struct arm_state *asp, uint32_t iw)
{
    asp->analysis.dp_count += 1;
    uint32_t i_bit = (iw >> 25) & 0b1;
    uint32_t rn = (iw >> 16) & 0b1111;
    uint32_t rd = (iw >> 12) & 0b1111;
    uint32_t rm = iw & 0b1111;
    uint32_t imm = iw & 0b11111111;
    uint32_t oper2;

    if (!i_bit)
    {
        oper2 = asp->regs[rm];
    }
    else
    {
        oper2 = imm;
    }

    asp->regs[rd] = oper2 - asp->regs[rn];

    if (rd != PC)
    {
        asp->regs[PC] = asp->regs[PC] + 4;
    }
}

bool armemu_is_sub(uint32_t iw)
{
    uint32_t dp_bits = (iw >> 26) & 0b11;
    uint32_t opcode = (iw >> 21) & 0b1111;

    return (dp_bits == 0b00) & (opcode == 0b0010);
}

bool armemu_is_rsub(uint32_t iw)
{
    uint32_t dp_bits = (iw >> 26) & 0b11;
    uint32_t opcode = (iw >> 21) & 0b1111;

    return (dp_bits == 0b00) & (opcode == 0b0011);
}

bool armemu_is_and(uint32_t iw)
{
    uint32_t dp_bits = (iw >> 26) & 0b11;
    uint32_t opcode = (iw >> 21) & 0b1111;

    return (dp_bits == 0b00) & (opcode == 0b0000);
}

void armemu_and(struct arm_state *asp, uint32_t iw)
{
    asp->analysis.dp_count += 1;
    uint32_t i_bit = (iw >> 25) & 0b1;
    uint32_t rn = (iw >> 16) & 0b1111;
    uint32_t rd = (iw >> 12) & 0b1111;
    uint32_t rm = iw & 0b1111;
    uint32_t imm = iw & 0b11111111;
    uint32_t oper2;

    if (!i_bit)
    {
        oper2 = asp->regs[rm];
    }
    else
    {
        oper2 = imm;
    }

    asp->regs[rd] = asp->regs[rn] & oper2;

    if (rd != PC)
    {
        asp->regs[PC] = asp->regs[PC] + 4;
    }
}

void armemu_one(struct arm_state *asp)
{

    /* Project04: get instruction word from instruction cache
       instead of the PC pointer directly
       uint32_t iw = *((uint32_t *) asp->regs[PC]);
    */
    uint32_t iw = cache_lookup(&asp->cache, asp->regs[PC]);

    asp->analysis.i_count += 1;

    // Order matters: more constrained to least constrained
    if (armemu_is_bx(iw))
    {
        armemu_bx(asp, iw);
    }
    else if (armemu_is_mul(iw))
    {
        armemu_mul(asp, iw);
    }
    else if (armemu_is_branch(iw))
    {
        asp->analysis.b_count += 1;
        if (check_flags(asp, iw))
        {
            asp->analysis.b_taken += 1;
            armemu_branch(asp, iw);
        }
        else
        {
            asp->analysis.b_not_taken += 1;
            asp->regs[PC] = asp->regs[PC] + 4;
        }
    }
    else if (armemu_is_mov(iw))
    {
        armemu_mov(asp, iw);
    }
    else if (armemu_is_cmp(iw))
    {
        armemu_cmp(asp, iw);
    }
    else if (armemu_is_sub(iw))
    {
        armemu_sub(asp, iw);
    }
    else if (armemu_is_rsub(iw))
    {
        armemu_revsub(asp, iw);
    }
    else if (armemu_is_and(iw))
    {
        armemu_and(asp, iw);
    }
    else if (armemu_is_add(iw))
    {
        armemu_add(asp, iw);
    }
    else if (armemu_is_data_transfer(iw))
    {
        armemu_data_transfer(asp, iw);
    }
    else
    {
        printf("armemu_one() invalid instruction\n");
        exit(-1);
    }
}

int armemu(struct arm_state *asp)
{
    while (asp->regs[PC] != 0)
    {
        armemu_one(asp);
    }

    return (int)asp->regs[0];
}
Editor is loading...
Leave a Comment