From 39288a6d59759b1a57ba00b845a01c7973f37c09 Mon Sep 17 00:00:00 2001 From: m8pple Date: Thu, 16 Oct 2014 13:44:26 +0100 Subject: Initial push. --- src/shared/mips_mem_ram.cpp | 112 ++++++++++++++++++ src/shared/mips_test_framework.cpp | 234 +++++++++++++++++++++++++++++++++++++ 2 files changed, 346 insertions(+) create mode 100644 src/shared/mips_mem_ram.cpp create mode 100644 src/shared/mips_test_framework.cpp (limited to 'src') diff --git a/src/shared/mips_mem_ram.cpp b/src/shared/mips_mem_ram.cpp new file mode 100644 index 0000000..276388b --- /dev/null +++ b/src/shared/mips_mem_ram.cpp @@ -0,0 +1,112 @@ +/* This file is an implementation of the functions + defined in mips_mem.h. It is designed to be + linked against something which needs an implementation + of a RAM device following that memory mapping + interface. +*/ +#include "mips_mem.h" + +#include +#include + +struct mips_mem_provider +{ + uint32_t length; + uint32_t blockSize; + uint8_t *data; +}; + +extern "C" mips_mem_h mips_mem_create_ram( + uint32_t cbMem, //!< Total number of bytes of ram + uint32_t blockSize //!< Granularity in bytes +){ + uint8_t *data=(uint8_t*)malloc(cbMem); + if(data==0) + return 0; + + struct mips_mem_provider *mem=(struct mips_mem_provider*)malloc(sizeof(struct mips_mem_provider)); + if(mem==0){ + free(data); + return 0; + } + + mem->length=cbMem; + mem->blockSize=blockSize; + mem->data=data; + + return mem; +} + +static mips_error mips_mem_read_write( + bool write, + mips_mem_h mem, + uint32_t address, + uint32_t length, + uint8_t *dataOut +) +{ + if(mem==0) + return mips_ErrorInvalidHandle; + + if(0 != (address%mem->blockSize) ){ + return mips_ExceptionInvalidAlignment; + } + if(0 != ((address+length)%mem->blockSize)){ + return mips_ExceptionInvalidAlignment; + } + if((address+length) > mem->length){ // A subtle bug here, maybe? + return mips_ExceptionInvalidAddress; + } + + if(write){ + for(unsigned i=0; idata[address+i]=dataOut[i]; + } + }else{ + for(unsigned i=0; idata[address+i]; + } + } + return mips_Success; +} + +mips_error mips_mem_read( + mips_mem_h mem, //!< Handle to target memory + uint32_t address, //!< Byte address to start transaction at + uint32_t length, //!< Number of bytes to transfer + uint8_t *dataOut //!< Receives the target bytes +) +{ + return mips_mem_read_write( + false, // we want to read + mem, + address, + length, + dataOut + ); +} + +mips_error mips_mem_write( + mips_mem_h mem, //! Handle to target memory + uint32_t address, //! Byte address to start transaction at + uint32_t length, //! Number of bytes to transfer + const uint8_t *dataIn //! Receives the target bytes +) +{ + return mips_mem_read_write( + true, // we want to write + mem, + address, + length, + (uint8_t*)dataIn + ); +} + +void mips_mem_free(mips_mem_h mem) +{ + if(mem){ + free(mem->data); + mem->data=0; + free(mem); + } +} diff --git a/src/shared/mips_test_framework.cpp b/src/shared/mips_test_framework.cpp new file mode 100644 index 0000000..b575fa1 --- /dev/null +++ b/src/shared/mips_test_framework.cpp @@ -0,0 +1,234 @@ +/* This file is an implementation of the functions + defined in mips_test.h. It is designed to be + linked against something which implements the + functions from mips_cpu.h and mips_mem.h, plus + some sort of main program to run the tests. +*/ +#include "mips_test.h" + +#include +#include +#include +#include +#include +#include + +static bool sg_started=false; + +struct test_info_t +{ + int testId; + std::string instruction; + int status; + std::string message; +}; + +static std::vector sg_tests; + +struct instr_info_t +{ + const char *instruction; + const char *description; +}; + +static const instr_info_t sg_instructionsArray[]= +{ + {"", "Tests of things other than intructions."}, + {"ADD","Add (with overflow)"}, + {"ADDI","Add immediate (with overflow)"}, + {"ADDIU","Add immediate unsigned (no overflow)"}, + {"ADDU","Add unsigned (no overflow)"}, + {"AND","Bitwise and"}, + {"ANDI","Bitwise and immediate"}, + {"BEQ","Branch on equal"}, + {"BGEZ","Branch on greater than or equal to zero"}, + {"BGEZAL","Branch on greater than or equal to zero and link"}, + {"BGTZ","Branch on greater than zero"}, + {"BLEZ","Branch on less than or equal to zero"}, + {"BLTZ","Branch on less than zero"}, + {"BLTZAL","Branch on less than zero and link"}, + {"BNE","Branch on not equal"}, + {"DIV","Divide"}, + {"DIVU","Divide unsigned"}, + {"J","Jump"}, + {"JAL","Jump and link"}, + {"JR","Jump register"}, + {"LB","Load byte"}, + {"LBU","Load byte unsigned"}, + {"LUI","Load upper immediate"}, + {"LW","Load word"}, + {"LWL","Load word left"}, + {"LWR","Load word right"}, + {"MFHI","Move from HI"}, + {"MFLO","Move from LO"}, + {"MULT","Multiply"}, + {"MULTU","Multiply unsigned"}, + {"OR","Bitwise or"}, + {"ORI","Bitwise or immediate"}, + {"SB","Store byte"}, + {"SH","Store half-word"}, + {"SLL","Shift left logical"}, + {"SLLV","Shift left logical variable"}, + {"SLT","Set on less than (signed)"}, + {"SLTI","Set on less than immediate (signed)"}, + {"SLTIU","Set on less than immediate unsigned"}, + {"SLTU","Set on less than unsigned"}, + {"SRA","Shift right arithmetic"}, + {"SRL","Shift right logical"}, + {"SRLV","Shift right logical variable"}, + {"SUB","Subtract"}, + {"SUBU","Subtract unsigned"}, + {"SW","Store word"}, + {"XOR","Bitwise exclusive or"}, + {"XORI","Bitwise exclusive or immediate"} +}; +static const unsigned sg_instructionsCount = sizeof(sg_instructionsArray)/sizeof(sg_instructionsArray[0]); + +static std::set sg_knownInstructions; + + +extern "C" void mips_test_begin_suite() +{ + if(sg_started){ + fprintf(stderr, "Error:mips_test_begin_suite - Test suite has already been started\n"); + exit(1); + } + + // Build up a list of known instruction names + for(unsigned i=0; i0){ + if(sg_tests.back().status == -1){ + fprintf(stderr, "Error:mips_test_begin_test - Attempt to start new test of '%s', but previous test with id %u has not been completed.\n", instruction, sg_tests.back().testId); + exit(1); + } + } + + int testId=sg_tests.size(); + + test_info_t info; + info.testId=testId; + + info.instruction=instruction; // We want the string in upper case (shouting!) + std::transform(info.instruction.begin(), info.instruction.end(), info.instruction.begin(), ::toupper); + + if(sg_knownInstructions.find(info.instruction)==sg_knownInstructions.end()){ + fprintf(stderr, "Warning:mips_test_begin_test - Unknown instruction '%s', might want to check the spelling.\n", instruction); + } + + info.status=-1; + sg_tests.push_back(info); + + return testId; +} + +extern "C" void mips_test_end_test(int testId, int passed, const char *msg) +{ + if(!sg_started){ + fprintf(stderr, "Error:mips_test_finish_test - Test suite has not been started with mips_test_begin_suite."); + exit(1); + } + + if(sg_tests.size()==0){ + fprintf(stderr, "Error:mips_test_finish_test - No tests have been started.\n"); + exit(1); + } + if(sg_tests.back().testId!=testId){ + fprintf(stderr, "Error:mips_test_finish_test - Attempt to finish test %u, but last test started was %u.\n", testId, sg_tests.back().testId); + exit(1); + } + if(sg_tests.back().status!=-1){ + fprintf(stderr, "Error:mips_test_finish_test - Attempt to finish test %u, but it already finished with status %u.\n", testId, sg_tests.back().status); + exit(1); + } + + sg_tests.back().status=passed ? 1 : 0; + if(msg){ + sg_tests.back().message=msg; + } +} + + +extern "C" void mips_test_end_suite() +{ + if(!sg_started){ + fprintf(stderr, "Error:mips_test_finish_suite - Test suite has not been started with mips_test_begin_suite.\n"); + exit(1); + } + if(sg_tests.size()==0){ + fprintf(stderr, "Error:mips_test_finish_suite - No tests have been executed.\n"); + exit(1); + } + if(sg_tests.back().status==-1){ + fprintf(stderr, "Error:mips_test_finish_suite - The final test has not been completed yet.\n"); + exit(1); + } + + // Now we will go through an collect some statistics about what happened + + // Build a map from instruction name to a pair of (tests,passed) + typedef std::map > stats_t; + stats_t statistics; + + for(unsigned i=0; ifirst; + int total=it->second.first; + int passed=it->second.second; + + totalTested++; + if(passed==0){ + totalNotWorking++; + }else if(passed