diff options
author | Thi Tran <thi@us.ibm.com> | 2012-01-13 10:29:25 -0600 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2012-02-07 13:49:45 -0600 |
commit | 859335d953a59c25de64a414c344d0a22d0911cb (patch) | |
tree | c606dbbbe0cbbfa3275ca0d644ac417e258b84b9 /src | |
parent | 0f454c096f27c06cb93ad442c0e14fc734464867 (diff) | |
download | talos-hostboot-859335d953a59c25de64a414c344d0a22d0911cb.tar.gz talos-hostboot-859335d953a59c25de64a414c344d0a22d0911cb.zip |
Initial VSBE Supports
Fixed test case failure
Change-Id: Ie388aebddacba99dfc6cc04e5fe98f0e8ca8b4bd
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/520
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
57 files changed, 19775 insertions, 11 deletions
diff --git a/src/build/trace/tracepp b/src/build/trace/tracepp index dfeda9d55..bc570aeb8 100755 --- a/src/build/trace/tracepp +++ b/src/build/trace/tracepp @@ -163,7 +163,7 @@ while(defined($opt = shift @ARGV)) { # an object or archive, ignore this but give it to cc push @ccopts, $opt; print "found object/archive '$opt'\n" if $debug; - } elsif ($opt =~ m/\.c[xp]*$/i) { + } elsif ($opt =~ m/\.c[cxp]*$/i) { # the source file(s). we should only get one if (defined $source) { print STDERR "don't know to handle two source files, aborting\n"; diff --git a/src/include/usr/initservice/initsvcreasoncodes.H b/src/include/usr/initservice/initsvcreasoncodes.H index 77428c770..077aedabf 100644 --- a/src/include/usr/initservice/initsvcreasoncodes.H +++ b/src/include/usr/initservice/initsvcreasoncodes.H @@ -65,7 +65,8 @@ enum InitServiceModuleID START_I2C_ERRL_ID = 0x19, START_INTR_ERRL_ID = 0x1A, START_SPD_ERRL_ID = 0x1B, - + START_FAPIPOREVE_ERRL_ID = 0x1C, + START_POREVE_ERRL_ID = 0x1D, // Internal InitService codes INITSVC_START_TASK_MOD_ID = 0x20, diff --git a/src/makefile b/src/makefile index 517fcb9b3..ddd9dc6ca 100644 --- a/src/makefile +++ b/src/makefile @@ -49,21 +49,27 @@ BASE_MODULES = trace errl devicefw scom xscom initservice taskargs \ EXTENDED_MODULES = targeting ecmddatabuffer fapi hwp plat \ extinitsvc istepdisp hwas fsi fsiscom i2c intr \ - spd dmi_training + spd dmi_training fapiporeve poreve DIRECT_BOOT_MODULES = example RUNTIME_MODULES = + TESTCASE_MODULES = cxxtest testerrl testdevicefw testsyslib \ testscom testxscom testtargeting testinitservice testkernel \ testhwpf testecmddatabuffer initsvctasktest2 testcxxtest \ - testpnor testi2c testfsi testvfs testhwas testintr testspd + testpnor testi2c testfsi testvfs testhwas testintr testspd \ + testpore RELOCATABLE_IMAGE_LDFLAGS = -pie --export-dynamic hbicore_OBJECTS = ${BASE_OBJECTS} ${DIRECT_BOOT_OBJECTS} ${STUB_TESTCASE_OBJECT} hbicore_MODULES = ${BASE_MODULES} ${DIRECT_BOOT_MODULES} hbicore_EXTENDED_MODULES = ${EXTENDED_MODULES} -hbicore_DATA_MODULES = sample.if dimmspd.dat +#@todo - Temporary workaround +# The sbe_pnor.bin is manually built from CVS SBE procedure files in CVS then copy +# into HostBoot for now. HostBoot build team will have a process of building sbe_pnor +# image later. +hbicore_DATA_MODULES = sample.if dimmspd.dat sbe_pnor.bin hbicore_LIDNUMBER = 80f00100 diff --git a/src/usr/initservice/extinitsvc/extinitsvctasks.H b/src/usr/initservice/extinitsvc/extinitsvctasks.H index c21f218ef..ca783b488 100644 --- a/src/usr/initservice/extinitsvc/extinitsvctasks.H +++ b/src/usr/initservice/extinitsvc/extinitsvctasks.H @@ -178,15 +178,11 @@ const TaskInfo g_exttaskinfolist[] = { } }, - - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // NOTE: libistepdisp.so needs to always be last in this list!! - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /** * @brief External interrupt resource provider */ { - "libintr.so", // tasknmae + "libintr.so", // taskname NULL, // no ptr to fnct { START_TASK, // task type @@ -196,6 +192,35 @@ const TaskInfo g_exttaskinfolist[] = { }, /** + * @brief VSBE FAPI interface code library. + */ + { + "libfapiporeve.so" , // taskname + NULL, // no pointer to fn + { + INIT_TASK, // task type + EXT_IMAGE, // Extended Module + START_FAPIPOREVE_ERRL_ID // module id + } + }, + + /** + * @brief VSBE code library + */ + { + "libporeve.so" , // taskname + NULL, // no pointer to fn + { + INIT_TASK, // task type + EXT_IMAGE, // Extended Module + START_POREVE_ERRL_ID // module id + } + }, + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // NOTE: libistepdisp.so needs to always be last in this list!! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + /** * @brief IStep Dispatcher task, runs ISteps * * diff --git a/src/usr/makefile b/src/usr/makefile index 71365d0c1..60a40d488 100644 --- a/src/usr/makefile +++ b/src/usr/makefile @@ -27,6 +27,6 @@ OBJS = module_init.o SUBDIRS = example.d trace.d cxxtest.d testcore.d errl.d devicefw.d \ scom.d xscom.d targeting.d initservice.d hwpf.d \ ecmddatabuffer.d pnor.d i2c.d vfs.d fsi.d hwas.d fsiscom.d \ - intr.d spd.d + intr.d spd.d pore.d include ${ROOTPATH}/config.mk diff --git a/src/usr/pore/fapiporeve/fapiPoreVe.C b/src/usr/pore/fapiporeve/fapiPoreVe.C new file mode 100644 index 000000000..bf44a6102 --- /dev/null +++ b/src/usr/pore/fapiporeve/fapiPoreVe.C @@ -0,0 +1,749 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/fapiporeve/fapiPoreVe.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// -*- mode: C++; c-file-style: "linux"; -*- +// $Id: fapiPoreVe.C,v 1.22 2012/01/09 20:55:27 jeshua Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/fapiPoreVe.C,v $ +//------------------------------------------------------------------------------ +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! TITLE : fapiPoreVe.C +// *! DESCRIPTION : Creates and runs a PoreVe +// *! OWNER NAME : Jeshua Smith Email: jeshua@us.ibm.com +// *! BACKUP NAME : John Bordovsky Email: johnb@us.ibm.com +// #! ADDITIONAL COMMENTS : +// +// The purpose of this procedure is to initialize and run a PoreVe +// +// Assume: Any memory images and start state desired are passed in +// +// Procedure Summary: +// Create new PoreVe (pass in master target) +// Reset the PoreVe (pass in slave target) +// Install start state, if passed in +// Install hooks +// Install each memory image passed in +// Set entry point +// Set break point +// Run the requested number of instructions +// Extract end state +// Destroy PoreVe +// + + + +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "poreve.H" +#include <fapi.H> +#include "fapiPoreVeArg.H" + +//For hooks +#ifndef __HOSTBOOT_MODULE +#include <dlfcn.h> +#endif +#include "hookmanager.H" + +#ifdef FAPIECMD +extern "C" { +#endif + +using namespace vsbe; + +const uint32_t MBOX_SBEVITAL_0x0005001C = 0x0005001C; + + +//****************************************************************************** +// fapiPoreVe function +//****************************************************************************** +fapi::ReturnCode fapiPoreVe( + const fapi::Target i_target, + std::list<uint64_t> & io_sharedObjectArgs) + +{ + fapi::ReturnCode rc; //JDS TODO - set initial values + PoreVe *poreve = NULL; + FapiPoreVeOtherArg *pOtherArg = NULL; + + //---------------------------------------------------------------------- + // Find the PORE type + //---------------------------------------------------------------------- + std::list<uint64_t>::iterator itr; + for( itr = io_sharedObjectArgs.begin(); + (itr != io_sharedObjectArgs.end()) && (poreve == NULL); + itr++ ) + { + FapiPoreVeArg *arg = reinterpret_cast<FapiPoreVeArg *>(*itr); + + //---------------------------------------------------------------------- + // Use PORE type and pdbgArg to create poreve + //---------------------------------------------------------------------- + if( arg->iv_type == ARG_OTHER ) + { + FapiPoreVeOtherArg *thisArg = (FapiPoreVeOtherArg *)arg; + pOtherArg = thisArg; + fapi::Target masterTarget = i_target; //JDS TODO - get this from an attribute + poreve = PoreVe::create( thisArg->iv_poreType, + masterTarget, + thisArg->iv_pdbgArgs ); + } + } + if( poreve == NULL ) + { + FAPI_ERR( "Failed to create poreve\n" ); + rc = 0xDEAD0000; + } + + + //---------------------------------------------------------------------- + // Reset the PoreVe and set slave target + //---------------------------------------------------------------------- + if( rc.ok() ) { + poreve->reset( i_target ); + } + + //---------------------------------------------------------------------- + // Parse the arguments + //---------------------------------------------------------------------- + FapiPoreVeStateArg *stateArg = NULL; + for( itr = io_sharedObjectArgs.begin(); + (itr != io_sharedObjectArgs.end()) && rc.ok(); itr++ ) + { + FapiPoreVeArg *arg = reinterpret_cast<FapiPoreVeArg *>(*itr); + + //---------------------------------------------------------------------- + // Install the start state (if passed in) + //---------------------------------------------------------------------- + if( arg->iv_type == ARG_STATE ) + { + stateArg = (FapiPoreVeStateArg *)arg; + if( stateArg->iv_installState ) + { + PoreState * p_state = (PoreState *)stateArg->iv_data; + +#ifndef __HOSTBOOT_MODULE + if( p_state == NULL ) + { + p_state = new PoreState(); + stateArg->iv_data=p_state; + char* state_rc; + int linenum = 0; + + stateArg->iv_fd = fopen( stateArg->iv_filename, "r" ); + if( stateArg->iv_fd == NULL ) + { + FAPI_ERR( "Failed to open state file %s\n", stateArg->iv_filename ); + rc = 0xDEAD4321; + } + else + { + do + { + char line[200]; + state_rc = fgets( line, sizeof(line), stateArg->iv_fd ); + linenum++; + if( state_rc != NULL ) + { + //Get register name + char* reg = strtok( line, " =" ); + + PoreRegisterOffset reg_offset; + if( strcmp( reg, "PORE_STATUS" ) == 0 ) { + reg_offset = PORE_STATUS; + } else if( strcmp( reg, "PORE_CONTROL" ) == 0 ) { + reg_offset = PORE_CONTROL; + } else if( strcmp( reg, "PORE_RESET" ) == 0 ) { + reg_offset = PORE_RESET; + } else if( strcmp( reg, "PORE_ERROR_MASK" ) == 0 ) { + reg_offset = PORE_ERROR_MASK; + } else if( strcmp( reg, "PORE_PRV_BASE_ADDR0" ) == 0 ) { + reg_offset = PORE_PRV_BASE_ADDR0; + } else if( strcmp( reg, "PORE_PRV_BASE_ADDR1" ) == 0 ) { + reg_offset = PORE_PRV_BASE_ADDR1; + } else if( strcmp( reg, "PORE_OCI_MEMORY_BASE_ADDR0" ) == 0 ) { + reg_offset = PORE_OCI_MEMORY_BASE_ADDR0; + } else if( strcmp( reg, "PORE_OCI_MEMORY_BASE_ADDR1" ) == 0 ) { + reg_offset = PORE_OCI_MEMORY_BASE_ADDR1; + } else if( strcmp( reg, "PORE_TABLE_BASE_ADDR" ) == 0 ) { + reg_offset = PORE_TABLE_BASE_ADDR; + } else if( strcmp( reg, "PORE_EXE_TRIGGER" ) == 0 ) { + reg_offset = PORE_EXE_TRIGGER; + } else if( strcmp( reg, "PORE_SCRATCH0" ) == 0 ) { + reg_offset = PORE_SCRATCH0; + } else if( strcmp( reg, "PORE_SCRATCH1" ) == 0 ) { + reg_offset = PORE_SCRATCH1; + } else if( strcmp( reg, "PORE_SCRATCH2" ) == 0 ) { + reg_offset = PORE_SCRATCH2; + } else if( strcmp( reg, "PORE_IBUF_01" ) == 0 ) { + reg_offset = PORE_IBUF_01; + } else if( strcmp( reg, "PORE_IBUF_2" ) == 0 ) { + reg_offset = PORE_IBUF_2; + } else if( strcmp( reg, "PORE_DBG0" ) == 0 ) { + reg_offset = PORE_DBG0; + } else if( strcmp( reg, "PORE_DBG1" ) == 0 ) { + reg_offset = PORE_DBG1; + } else if( strcmp( reg, "PORE_PC_STACK0" ) == 0 ) { + reg_offset = PORE_PC_STACK0; + } else if( strcmp( reg, "PORE_PC_STACK1" ) == 0 ) { + reg_offset = PORE_PC_STACK1; + } else if( strcmp( reg, "PORE_PC_STACK2" ) == 0 ) { + reg_offset = PORE_PC_STACK2; + } else if( strcmp( reg, "PORE_ID_FLAGS" ) == 0 ) { + reg_offset = PORE_ID_FLAGS; + } else if( strcmp( reg, "PORE_DATA0" ) == 0 ) { + reg_offset = PORE_DATA0; + } else if( strcmp( reg, "PORE_MEM_RELOC" ) == 0 ) { + reg_offset = PORE_MEM_RELOC; + } else if( strcmp( reg, "PORE_I2C_E0_PARAM" ) == 0 ) { + reg_offset = PORE_I2C_E0_PARAM; + } else if( strcmp( reg, "PORE_I2C_E1_PARAM" ) == 0 ) { + reg_offset = PORE_I2C_E1_PARAM; + } else if( strcmp( reg, "PORE_I2C_E2_PARAM" ) == 0 ) { + reg_offset = PORE_I2C_E2_PARAM; + } else if( strcmp( reg, "PORE_HIDDEN_STATE_0" ) == 0) { + reg_offset = PORE_HIDDEN_STATE_0; + } else if( strcmp( reg, "PORE_HIDDEN_STATE_1" ) == 0) { + reg_offset = PORE_HIDDEN_STATE_1; + } else if( strcmp( reg, "PORE_HIDDEN_STATE_2" ) == 0) { + reg_offset = PORE_HIDDEN_STATE_2; + } else if( strcmp( reg, "PORE_HIDDEN_STATE_3" ) == 0) { + reg_offset = PORE_HIDDEN_STATE_3; + } else if( strcmp( reg, "PORE_HIDDEN_STATE_4" ) == 0) { + reg_offset = PORE_HIDDEN_STATE_4; + } else { + FAPI_ERR("Unknown reg name %s on line %i\n", + reg, linenum ); + reg = NULL; + } //strcmp reg vs regname + + if( reg != NULL ) + { + //get the register value + char* value = strtok( NULL, " =" ); + if( value != NULL ) + { + uint64_t value_64 = strtoull( value, NULL, 16 ); + ModelError me = p_state->put( reg_offset, value_64 ); + FAPI_INF( "Set %s(0x%X) to 0x%llX\n", reg, reg_offset, value_64 ); + if( me != ME_SUCCESS ) + { + FAPI_ERR( "Model error parsing state. Errno(%i)\n", + (int)me); + } + } + else + { + FAPI_ERR( "Error parsing value of %s on line %i\n", + reg, linenum ); + } + } //if reg != NULL + } //if state_rc != NULL + } while ( state_rc != NULL ); //able to read a line + fclose( stateArg->iv_fd ); + } //able to open statefile + } + else + { + FAPI_INF( "State pointer was passed in, so not reading state from file\n" ); + } +#endif + + ModelError me = poreve->iv_pore.installState( *p_state ); + if( me != ME_SUCCESS ) + { + FAPI_ERR( "Model error installing state. Errno(%i)\n", (int)me); + rc = 0xDEAD1400 | me; + } + } //if install state + } //end state arg processing + + //---------------------------------------------------------------------- + // Install hooks + //---------------------------------------------------------------------- + else if( arg->iv_type == ARG_HOOKS ) + { +#ifndef __HOSTBOOT_MODULE + FapiPoreVeHooksArg *thisArg = (FapiPoreVeHooksArg *)arg; + + //Load hooks (note: this must be done after poreve is created) + void *handle = dlopen( thisArg->iv_filename, RTLD_NOW); + if (handle == 0) + { + FAPI_ERR( "dlopen() failed; See dlerror() string below\n%s\n", + dlerror()); + FAPI_ERR( "Failed to load hooks file\n" ); + rc = 0xDEAD0002; + } + else + { + FAPI_INF( "Loaded hooks file %s\n", thisArg->iv_filename ); + poreve->iv_pore.enableAddressHooks(true); + } +#endif + } + + //---------------------------------------------------------------------- + // Install each memory image passed in + // (OTPROM, PNOR, SEEPROM, MAINMEM, SRAM) + //---------------------------------------------------------------------- + else + { + FapiPoreVeMemArg *thisArg = (FapiPoreVeMemArg *)arg; + + //OTPROM + if( thisArg->iv_type == ARG_OTPROM ) + { + poreve->iv_otpromMemory.map( thisArg->iv_base, + thisArg->iv_size, + (ACCESS_MODE_READ), + thisArg->iv_data, + thisArg->iv_crcEnable ); + } + + //PNOR + else if( thisArg->iv_type == ARG_PNOR ) + { + poreve->iv_pnorMemory.map( thisArg->iv_base, + thisArg->iv_size, + (ACCESS_MODE_READ|ACCESS_MODE_WRITE), + thisArg->iv_data, + thisArg->iv_crcEnable ); + } + + //SEEPROM + else if( thisArg->iv_type == ARG_SEEPROM ) + { + poreve->iv_seepromMemory.map( thisArg->iv_base, + thisArg->iv_size, + (ACCESS_MODE_READ), + thisArg->iv_data, + thisArg->iv_crcEnable ); + } + + //MAINMEM + else if( thisArg->iv_type == ARG_MAINMEM ) + { + poreve->iv_mainMemory.map( thisArg->iv_base, + thisArg->iv_size, + (ACCESS_MODE_READ|ACCESS_MODE_WRITE), + thisArg->iv_data, + thisArg->iv_crcEnable ); + } + + //SRAM + else if( thisArg->iv_type == ARG_SRAM ) + { + poreve->iv_sramMemory.map( thisArg->iv_base, + thisArg->iv_size, + (ACCESS_MODE_READ|ACCESS_MODE_WRITE), + thisArg->iv_data, + thisArg->iv_crcEnable ); + } + + //Unknown type + else if( thisArg->iv_type != ARG_OTHER ) + { + FAPI_ERR( "Got an arg of an unknown type\n"); + rc = 0xDEAD0005; + } + } //end memory args + } //end parse options + + //---------------------------------------------------------------------- + // Set entry point + //---------------------------------------------------------------------- + if( pOtherArg->iv_entryPoint != NULL ) + { + FAPI_INF( "Looking up entry point %s\n", pOtherArg->iv_entryPoint ); + + GlobalSymbolInfo epInfo; + bool symbolFound = false; + HookError he = HookManager::findGlobalSymbol( + pOtherArg->iv_entryPoint, + symbolFound, + epInfo); + if( !symbolFound || (he != HOOK_OK) ) + { + FAPI_ERR( "Failed to find entry point \"%s\" in hooks file\n", + pOtherArg->iv_entryPoint); + rc = 0xDEAD2000 | he; + HookManager::report(); + } + else + { + //Make sure entry point is a valid type + if( epInfo.iv_type != 'T' ) + { + FAPI_ERR( "Entry point is of ivalid type %c\n", epInfo.iv_type ); + rc = 0xDEAD0007; + } + else + { + //Set PC to the entry point + ModelError me = + poreve->iv_pore.setPc( epInfo.iv_address ); + if( me != ME_SUCCESS ) + { + FAPI_ERR( "Model error setting PC. Errno(%i)\n", (int)me); + rc = 0xDEAD1000 | me; + } + } + } + } + + //---------------------------------------------------------------------- + // Set breakpoint + //---------------------------------------------------------------------- + if( pOtherArg->iv_breakpoint != NULL ) + { + FAPI_INF( "Looking up breakpoint %s\n", pOtherArg->iv_breakpoint ); + + GlobalSymbolInfo bpInfo; + bool symbolFound = false; + HookError he = HookManager::findGlobalSymbol( + pOtherArg->iv_breakpoint, + symbolFound, + bpInfo); + if( !symbolFound || (he != HOOK_OK) ) + { + FAPI_ERR( "Failed to find breakpoint \"%s\" in hooks file\n", + pOtherArg->iv_breakpoint); + rc = 0xDEAD2000 | he; + HookManager::report(); + } + else + { + //Make sure break point is a valid type + if( bpInfo.iv_type != 'T' ) + { + FAPI_ERR( "Break point is of ivalid type %c\n", bpInfo.iv_type ); + rc = 0xDEAD0007; + } + else + { + //Set the break point + ModelError me = + poreve->iv_pore.setBreakpoint( bpInfo.iv_address ); + if( me != ME_SUCCESS ) + { + FAPI_ERR( "Model error setting breakpoint. Errno(%i)\n", + (int)me); + rc = 0xDEAD1000 | me; + } + } + } + } + + //---------------------------------------------------------------------- + // Set MRR + //---------------------------------------------------------------------- + if( pOtherArg->iv_mrr != 0 ) + { + FAPI_INF( "Setting MRR to 0x%llX\n", pOtherArg->iv_mrr ); + + ModelError me = poreve->iv_pore.registerWrite( vsbe::PORE_MEM_RELOC, + pOtherArg->iv_mrr & 0x00000003fffffc00ull, sizeof(uint64_t) ); + if( me != ME_SUCCESS ) + { + FAPI_ERR( "Model error setting MRR. Errno(%i)\n", (int)me); + rc = 0xDEAD3000 | me; + } + } + + //---------------------------------------------------------------------- + // Run the requested number of instructions + //---------------------------------------------------------------------- + if( rc.ok() ) { + uint64_t o_actualNumInstructionsRun = 0; + int runStatus = poreve->run( pOtherArg->iv_instructionCount, + o_actualNumInstructionsRun ); + FAPI_INF( "PORE ran %llu instructions, and returned status 0x%X\n", + o_actualNumInstructionsRun, runStatus); + + if( runStatus != 0 ) + { + //Parse out each status bit + if( runStatus & PORE_STATUS_HALTED ) + { + FAPI_INF( "PORE is stopped at a HALT instruction\n"); + runStatus &= ~PORE_STATUS_HALTED; + + //Check the SBE VITAL reg halt code for success + uint64_t data_64; + int pib_rc; + ModelError me; + me = poreve->getscom(MBOX_SBEVITAL_0x0005001C, data_64, pib_rc); + + if( me == ME_SUCCESS ) + { + if( pib_rc == 0 ) + { + //Bits 12:15 are halt code; code 0xF = success + uint32_t haltcode = (data_64 >> 48) & 0x0000000F; + if( haltcode != 0xF ) + { + FAPI_ERR( "Halt code is 0x%x (ERROR)\n", haltcode ); + rc = 0xDEAD6660 | haltcode; + } + else + { + FAPI_INF( "Halt code is 0x%x (SUCCESS)\n",haltcode); + rc = 0; + } + } + else + { + FAPI_ERR("PIB error getting halt code (error code %i)\n", + pib_rc ); + rc = 0xDEAD6650 | pib_rc; + } + } + else + { + FAPI_ERR( "Model error getting halt code (me=0x%x)\n", me ); + rc = 0xDEAD6500 | me; + } + } + if( runStatus & PORE_STATUS_ERROR_HALT ) + { + FAPI_ERR( "PORE is stopped due to an architected error\n"); + runStatus &= ~PORE_STATUS_ERROR_HALT; + rc = 0xDEAD7777; + } + if( runStatus & PORE_STATUS_HARDWARE_STOP ) + { + FAPI_INF( "PORE is stopped\n"); + runStatus &= ~PORE_STATUS_HARDWARE_STOP; + } + if( runStatus & PORE_STATUS_BREAKPOINT ) + { + FAPI_INF( "PORE is stopped at a breakpoint\n"); + runStatus &= ~PORE_STATUS_BREAKPOINT; + } + if( runStatus & PORE_STATUS_TRAP ) + { + FAPI_INF( "PORE is stopped at a TRAP instruction\n"); + runStatus &= ~PORE_STATUS_TRAP; + } + if( runStatus & PORE_STATUS_MODEL_ERROR ) + { + FAPI_ERR( "PORE is stopped due to a modeling error\n"); + runStatus &= ~PORE_STATUS_MODEL_ERROR; + rc = 0xDEAD0003; //JDS TODO - create a real return code + } + if( runStatus & PORE_STATUS_DEBUG_STOP ) + { + FAPI_INF( "PORE is stopped due to a user request (probably a hook)\n"); + runStatus &= ~PORE_STATUS_DEBUG_STOP; + } + //If we still have bits set, we missed something + if( runStatus ) + { + FAPI_ERR( "PORE is stopped with an unknown status code:0x%X\n", + runStatus); + rc = 0xDEAD0004; //JDS TODO - create a real return code + } + } else { //runStatus == 0 + FAPI_IMP( "PORE ran the requested number of instructions without hitting any stop conditions\n"); + } + + if( (pOtherArg->iv_instructionCount != RUN_UNLIMITED) && + (pOtherArg->iv_instructionCount != o_actualNumInstructionsRun) ) + { + FAPI_IMP( "PORE only ran %llu of the %llu instructions you requested\n", + o_actualNumInstructionsRun, + pOtherArg->iv_instructionCount ); + } + } //if( rc.ok() ) + + //---------------------------------------------------------------------- + // Extract end state + //---------------------------------------------------------------------- + if( stateArg != NULL && stateArg->iv_extractState ) + { + ModelError me; + PoreState * p_state = (PoreState *)stateArg->iv_data; + + if( p_state == NULL ) + { + p_state = new PoreState(); + } + me = poreve->iv_pore.extractState( *p_state ); + +#ifndef __HOSTBOOT_MODULE + stateArg->iv_fd = fopen( stateArg->iv_filename, "w" ); + if( stateArg->iv_fd == NULL ) { + FAPI_ERR( "Unable to write state to \"%s\"\n", + stateArg->iv_filename ); + rc = 0xDEAD1550; + } else { + uint64_t data_64; + +#define printreg(offset, reg) \ + me = p_state->get(offset, data_64); if (me != 0) break; \ + fprintf( stateArg->iv_fd, reg, data_64 ); + + do + { + printreg(vsbe::PORE_STATUS, "PORE_STATUS = 0x%llX\n" ); + printreg(vsbe::PORE_CONTROL, "PORE_CONTROL = 0x%llX\n" ); + printreg(vsbe::PORE_RESET, "PORE_RESET = 0x%llX\n" ); + printreg(vsbe::PORE_ERROR_MASK, "PORE_ERROR_MASK = 0x%llX\n" ); + printreg(vsbe::PORE_PRV_BASE_ADDR0, "PORE_PRV_BASE_ADDR0 = 0x%llX\n" ); + printreg(vsbe::PORE_PRV_BASE_ADDR1, "PORE_PRV_BASE_ADDR1 = 0x%llX\n" ); + printreg(vsbe::PORE_OCI_MEMORY_BASE_ADDR0, "PORE_OCI_MEMORY_BASE_ADDR0 = 0x%llX\n" ); + printreg(vsbe::PORE_OCI_MEMORY_BASE_ADDR1, "PORE_OCI_MEMORY_BASE_ADDR1 = 0x%llX\n" ); + printreg(vsbe::PORE_TABLE_BASE_ADDR, "PORE_TABLE_BASE_ADDR = 0x%llX\n" ); + printreg(vsbe::PORE_EXE_TRIGGER, "PORE_EXE_TRIGGER = 0x%llX\n" ); + printreg(vsbe::PORE_SCRATCH0, "PORE_SCRATCH0 = 0x%llX\n" ); + printreg(vsbe::PORE_SCRATCH1, "PORE_SCRATCH1 = 0x%llX\n" ); + printreg(vsbe::PORE_SCRATCH2, "PORE_SCRATCH2 = 0x%llX\n" ); + printreg(vsbe::PORE_IBUF_01, "PORE_IBUF_01 = 0x%llX\n" ); + printreg(vsbe::PORE_IBUF_2, "PORE_IBUF_2 = 0x%llX\n" ); + printreg(vsbe::PORE_DBG0, "PORE_DBG0 = 0x%llX\n" ); + printreg(vsbe::PORE_DBG1, "PORE_DBG1 = 0x%llX\n" ); + printreg(vsbe::PORE_PC_STACK0, "PORE_PC_STACK0 = 0x%llX\n" ); + printreg(vsbe::PORE_PC_STACK1, "PORE_PC_STACK1 = 0x%llX\n" ); + printreg(vsbe::PORE_PC_STACK2, "PORE_PC_STACK2 = 0x%llX\n" ); + printreg(vsbe::PORE_ID_FLAGS, "PORE_ID_FLAGS = 0x%llX\n" ); + printreg(vsbe::PORE_DATA0, "PORE_DATA0 = 0x%llX\n" ); + printreg(vsbe::PORE_MEM_RELOC, "PORE_MEM_RELOC = 0x%llX\n" ); + printreg(vsbe::PORE_I2C_E0_PARAM, "PORE_I2C_E0_PARAM = 0x%llX\n" ); + printreg(vsbe::PORE_I2C_E1_PARAM, "PORE_I2C_E1_PARAM = 0x%llX\n" ); + printreg(vsbe::PORE_I2C_E2_PARAM, "PORE_I2C_E2_PARAM = 0x%llX\n" ); + printreg(vsbe::PORE_HIDDEN_STATE_0, "PORE_HIDDEN_STATE_0 = 0x%llX\n" ); + printreg(vsbe::PORE_HIDDEN_STATE_1, "PORE_HIDDEN_STATE_1 = 0x%llX\n" ); + printreg(vsbe::PORE_HIDDEN_STATE_2, "PORE_HIDDEN_STATE_2 = 0x%llX\n" ); + printreg(vsbe::PORE_HIDDEN_STATE_3, "PORE_HIDDEN_STATE_3 = 0x%llX\n" ); + printreg(vsbe::PORE_HIDDEN_STATE_4, "PORE_HIDDEN_STATE_4 = 0x%llX\n" ); + } while (0); + stateArg->iv_data=p_state; + fclose( stateArg->iv_fd ); + } + +#endif + if( me != ME_SUCCESS ) + { + FAPI_ERR( "Model error extracting state. Errno(%i)\n", (int)me); + rc = 0xDEAD1600 | me; + } + } //if extract state + + //---------------------------------------------------------------------- + // Destroy PoreVe + //---------------------------------------------------------------------- + delete poreve; + + return rc; +} //end function + +#ifdef FAPIECMD +} //end extern C +#endif + +/* +*************** Do not edit this area *************** +This section is automatically updated by CVS when you check in this file. +Be sure to create CVS comments when you commit so that they are included here. + +$Log: fapiPoreVe.C,v $ +Revision 1.22 2012/01/09 20:55:27 jeshua +Don't include file-related code for hostboot + +Revision 1.21 2011/12/07 22:30:46 jeshua +Initial MRR support + +Revision 1.20 2011/11/17 18:17:59 jeshua +Fixed state handling so it works with hostboot (hopefully) + +Revision 1.19 2011/11/02 23:24:44 bcbrock +Changes required for portability to HBI environment + +Revision 1.18 2011/10/14 21:36:58 bcbrock +Added an enumeration of hidden state variables for fapiPoreVe + +Revision 1.17 2011/10/06 19:29:34 jeshua +Use poreve->getscom to check sbe vital + +Revision 1.16 2011/09/29 22:37:59 jeshua +Fixed some copy-paste problems in the break point code +Added a halt code check when the POREVE stops on a halt + +Revision 1.15 2011/09/08 16:03:28 jeshua +Return an rc on an error_halt status + +Revision 1.14 2011/09/02 20:54:13 jeshua +Open file for reading when installing state, close it after, open for writing when dumping state, close it after + +Revision 1.13 2011/09/02 19:57:06 jeshua +Added state install and extract support + +Revision 1.12 2011/07/13 19:13:34 jeshua +Enabled writing of the PNOR at John B's request + +Revision 1.11 2011/07/12 16:40:13 jeshua +Breakpoint support + +Revision 1.10 2011/07/08 23:52:22 jeshua +Updated for FAPI changes + +Revision 1.9 2011/07/07 20:33:32 jeshua +Entry point is no longer in the hooks file + +Revision 1.8 2011/06/06 20:47:09 jeshua +Removed workaround for setting the PC + +Revision 1.7 2011/06/03 19:49:55 jeshua +Use the create funcion instead of new + +Revision 1.6 2011/06/03 14:51:13 jeshua +Preliminary support for pdbg + +Revision 1.5 2011/05/24 19:34:07 jeshua +Updated register read + +Revision 1.4 2011/05/23 16:24:49 jeshua +Updated for new findGlobalSymbol signature + +Revision 1.3 2011/05/20 13:52:12 jeshua +Fixed hook handling +Added entryPoint handling + +Revision 1.2 2011/05/16 13:14:34 jeshua +Updated comments +Added hooks code from Bishop +Renamed InstructionCountArg to OtherArg, and added PORE type into it +Use bitwise AND when checking runStatus + +Revision 1.1 2011/05/11 19:57:29 jeshua +Initial version + + + + +*/ +/* Local Variables: */ +/* c-basic-offset: 4 */ +/* End: */ diff --git a/src/usr/pore/fapiporeve/fapiPoreVeArg.C b/src/usr/pore/fapiporeve/fapiPoreVeArg.C new file mode 100644 index 000000000..43deb3499 --- /dev/null +++ b/src/usr/pore/fapiporeve/fapiPoreVeArg.C @@ -0,0 +1,265 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/fapiporeve/fapiPoreVeArg.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// -*- mode: C++; c-file-style: "linux"; -*- +// $Id: fapiPoreVeArg.C,v 1.16 2012/01/09 20:55:57 jeshua Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/fapiPoreVeArg.C,v $ +//------------------------------------------------------------------------------ +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! TITLE : fapiPoreVeArg.C +// *! DESCRIPTION : Defines the arg struct to pass to fapiPoreVe +// *! OWNER NAME : Jeshua Smith Email: jeshua@us.ibm.com +// *! BACKUP NAME : John Bordovsky Email: johnb@us.ibm.com +// #! ADDITIONAL COMMENTS : +// +// + +#include "fapiPoreVeArg.H" +#include <fapi.H> + +#ifndef __HOSTBOOT_MODULE +//For file mapping +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> + +//For hooks +#include <dlfcn.h> +#endif + +using namespace vsbe; + +FapiPoreVeArg::FapiPoreVeArg( const FapiPoreVeArg_t i_type ) : + iv_type(i_type) +{ +} + +FapiPoreVeArg::~FapiPoreVeArg( ) +{ +} + +#ifndef __HOSTBOOT_MODULE +FapiPoreVeMemArg::FapiPoreVeMemArg( const FapiPoreVeArg_t i_type, + const char* const i_filename, + const uint32_t i_base ) : + FapiPoreVeArg(i_type), + iv_base(i_base), + iv_filename(i_filename), + iv_fd(open(i_filename, O_RDONLY)), + iv_crcEnable(true) +{ + uint32_t rc = 0; + + if( iv_fd < 0 ) { + FAPI_ERR( "Failed to open %s file\n", iv_filename ); + rc = BAD_ERROR_CODE; + } else { + iv_size = lseek( iv_fd, 0, SEEK_END ); + if( iv_size == (size_t)((off_t)-1) ) { + FAPI_ERR( "Failed to determine the size of %s file\n", iv_filename ); + } else { + if( (iv_type == ARG_SRAM) || (iv_type == ARG_MAINMEM) || + (iv_type == ARG_PNOR) || (iv_type == ARG_SEEPROM) ) { + iv_data = mmap( 0, iv_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, iv_fd, 0 ); + } else { + iv_data = mmap( 0, iv_size, PROT_READ, MAP_PRIVATE, iv_fd, 0 ); + } + if( iv_data == MAP_FAILED ) { + FAPI_ERR( "Failed to map %s file\n", iv_filename ); + rc = BAD_ERROR_CODE; + } + } + } + //JDS TODO - how do I make the constructor fail if mapping failed? + +} +#endif + +FapiPoreVeMemArg::FapiPoreVeMemArg( const FapiPoreVeArg_t i_type, + const uint32_t i_base, + const size_t i_size, + void * i_data) : + FapiPoreVeArg(i_type), + iv_base(i_base), +#ifndef __HOSTBOOT_MODULE + iv_filename(NULL), + iv_fd(0), +#endif + iv_size(i_size), + iv_crcEnable(true), + iv_data(i_data) +{ +} + +FapiPoreVeMemArg::~FapiPoreVeMemArg( ) +{ +#ifndef __HOSTBOOT_MODULE + uint32_t rc = 0; + if( iv_data != NULL && iv_data != MAP_FAILED && iv_filename != NULL ) { + int unmap_rc = munmap( iv_data, iv_size ); + if( unmap_rc != 0 ) { + FAPI_ERR( "Failed to unmap %s file\n", iv_filename ); + rc = BAD_ERROR_CODE; + } + } + if( iv_fd >= 0 ) { + int close_rc = close( iv_fd ); + if( close_rc != 0 ) { + FAPI_ERR( "Failed to close %s\n", iv_filename ); + rc = BAD_ERROR_CODE; + } + } +#endif + //JDS TODO - how do I make the destructor fail if unmapping failed? + +} + +#ifndef __HOSTBOOT_MODULE +FapiPoreVeStateArg::FapiPoreVeStateArg( const char* const i_filename ) : + FapiPoreVeArg( ARG_STATE ), + iv_filename(i_filename), + iv_extractState(true), + iv_installState(true), + iv_data(NULL) +{ +} +#endif + +FapiPoreVeStateArg::FapiPoreVeStateArg( void * i_data ) : + FapiPoreVeArg( ARG_STATE ), +#ifndef __HOSTBOOT_MODULE + iv_filename(NULL), +#endif + iv_extractState(true), + iv_installState(true), + iv_data(i_data) +{ +} + +FapiPoreVeStateArg::~FapiPoreVeStateArg( ) +{ +} + +FapiPoreVeHooksArg::FapiPoreVeHooksArg( const char* const i_filename ) : + FapiPoreVeArg( ARG_HOOKS ), + iv_filename(i_filename), + iv_handle(NULL) +{ +} + +FapiPoreVeHooksArg::~FapiPoreVeHooksArg( ) +{ +#ifndef __HOSTBOOT_MODULE + if( iv_handle != NULL ) + { + dlclose(iv_handle); + } +#endif +} + +FapiPoreVeOtherArg::FapiPoreVeOtherArg( const uint64_t i_instructionCount, + const PoreIbufId i_poreType ) : + FapiPoreVeArg( ARG_OTHER ), + iv_instructionCount(i_instructionCount), + iv_poreType(i_poreType), + iv_pdbgArgs(NULL), + iv_entryPoint(NULL), + iv_breakpoint(NULL), + iv_mrr(0) +{ +} + +FapiPoreVeOtherArg::~FapiPoreVeOtherArg( ) +{ +} + + +/* +*************** Do not edit this area *************** +This section is automatically updated by CVS when you check in this file. +Be sure to create CVS comments when you commit so that they are included here. + +$Log: fapiPoreVeArg.C,v $ +Revision 1.16 2012/01/09 20:55:57 jeshua +Don't include file-related code for hostboot + +Revision 1.15 2011/12/07 22:30:59 jeshua +Initial MRR support + +Revision 1.14 2011/12/02 16:12:11 jeshua +Make seeprom writable (for control bits) + +Revision 1.13 2011/11/17 18:20:05 jeshua +Skip file handling for hostboot + +Revision 1.12 2011/09/20 15:38:42 jeshua +Allow creating memory args from memory pointers instead of just files + +Revision 1.11 2011/09/02 20:54:29 jeshua +No longer do file open and close + +Revision 1.10 2011/09/02 20:01:04 jeshua +Fixes for state arg support + +Revision 1.9 2011/07/13 19:13:43 jeshua +Enabled writing of the PNOR at John B's request + +Revision 1.8 2011/07/12 16:39:38 jeshua +Breakpoint support + +Revision 1.7 2011/07/08 23:53:16 jeshua +Updated for FAPI changes + +Revision 1.6 2011/07/07 20:34:43 jeshua +Moved entry point from hooks to other arg + +Revision 1.5 2011/06/03 15:38:50 jeshua +Added pdbgArg to OtherArg type + +Revision 1.4 2011/05/20 14:05:10 jeshua +Don't close hooks file if it wasn't opened + +Revision 1.3 2011/05/20 13:57:48 jeshua +Added const +Use initializers +Unload hooks on destruction + +Revision 1.2 2011/05/13 21:19:42 jeshua +Updated comments +Renamed InstructionCountArg to OtherArg, and added PORE type into it +Added iv_extractState +Added Hooks class + +Revision 1.1 2011/05/11 19:57:29 jeshua +Initial version + + + + +*/ +/* Local Variables: */ +/* c-basic-offset: 4 */ +/* End: */ diff --git a/src/usr/pore/fapiporeve/fapiPoreVeArg.H b/src/usr/pore/fapiporeve/fapiPoreVeArg.H new file mode 100644 index 000000000..8b2b0a9a8 --- /dev/null +++ b/src/usr/pore/fapiporeve/fapiPoreVeArg.H @@ -0,0 +1,197 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/fapiporeve/fapiPoreVeArg.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// -*- mode: C++; c-file-style: "linux"; -*- +// $Id: fapiPoreVeArg.H,v 1.11 2011/12/07 22:31:39 jeshua Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/fapiPoreVeArg.H,v $ +//------------------------------------------------------------------------------ +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! TITLE : fapiPoreVeArg.H +// *! DESCRIPTION : Headers for the args to pass to fapiPoreVe +// *! OWNER NAME : Jeshua Smith Email: jeshua@us.ibm.com +// *! BACKUP NAME : John Bordovsky Email: johnb@us.ibm.com +// #! ADDITIONAL COMMENTS : +// +// + +#ifndef __FAPIPOREVEARG_H +#define __FAPIPOREVEARG_H + +#include "poreconstants.H" + +namespace vsbe +{ + + enum FapiPoreVeArg_t + { + ARG_STATE, + ARG_OTHER, + ARG_HOOKS, + ARG_OTPROM, + ARG_PNOR, + ARG_SEEPROM, + ARG_SRAM, + ARG_MAINMEM, + }; + + const uint32_t BAD_ERROR_CODE = 0xDEADC0DE; + + struct FapiPoreVeArg + { + public: + FapiPoreVeArg( const FapiPoreVeArg_t i_type ); + + virtual ~FapiPoreVeArg(); + + const FapiPoreVeArg_t iv_type; + }; + + struct FapiPoreVeMemArg : public FapiPoreVeArg + { + public: +#ifndef __HOSTBOOT_MODULE + FapiPoreVeMemArg( const FapiPoreVeArg_t i_type, + const char* const i_filename, + const uint32_t i_base ); +#endif + FapiPoreVeMemArg( const FapiPoreVeArg_t i_type, + const uint32_t i_base, + const size_t i_size, + void * i_data ); + + ~FapiPoreVeMemArg(); + + const uint32_t iv_base; +#ifndef __HOSTBOOT_MODULE + const char* iv_filename; + const int iv_fd; +#endif + size_t iv_size; + bool iv_crcEnable; + void * iv_data; + }; + + struct FapiPoreVeStateArg : public FapiPoreVeArg + { + public: +#ifndef __HOSTBOOT_MODULE + FapiPoreVeStateArg( const char* const i_filename ); +#endif + FapiPoreVeStateArg( void * i_data ); + + virtual ~FapiPoreVeStateArg(); + +#ifndef __HOSTBOOT_MODULE + const char* const iv_filename; + FILE * iv_fd; +#endif + bool iv_extractState; + bool iv_installState; + void * iv_data; + }; + + struct FapiPoreVeHooksArg : public FapiPoreVeArg + { + public: + FapiPoreVeHooksArg( const char* const i_filename ); + + virtual ~FapiPoreVeHooksArg(); + + const char* const iv_filename; + void* iv_handle; + }; + + struct FapiPoreVeOtherArg : public FapiPoreVeArg + { + public: + FapiPoreVeOtherArg( const uint64_t i_instructionCount, + const PoreIbufId i_poreType ); + + virtual ~FapiPoreVeOtherArg(); + + uint64_t iv_instructionCount; + PoreIbufId iv_poreType; + const char* iv_pdbgArgs; + char* iv_entryPoint; + char* iv_breakpoint; + uint64_t iv_mrr; + }; +} //end vsbe namespace + +#endif + +/* +*************** Do not edit this area *************** +This section is automatically updated by CVS when you check in this file. +Be sure to create CVS comments when you commit so that they are included here. + +$Log: fapiPoreVeArg.H,v $ +Revision 1.11 2011/12/07 22:31:39 jeshua +Initial MRR support + +Revision 1.10 2011/11/17 18:21:10 jeshua +Skip file handling for hostboot +Keep a pointer to raw state data in the state arg + +Revision 1.9 2011/09/20 15:39:06 jeshua +Allow creating memory args from pointers instead of just files + +Revision 1.8 2011/09/02 19:57:45 jeshua +Updates for state install & extract support + +Revision 1.7 2011/08/03 23:01:47 bcbrock +Update fapiPoreVeArg.H to use the new 'poreconstants.H' + +Revision 1.6 2011/07/12 16:39:39 jeshua +Breakpoint support + +Revision 1.5 2011/07/07 20:34:59 jeshua +Moved entry point from hooks to other arg + +Revision 1.4 2011/06/03 15:38:04 jeshua +Added pdbgArgs to OtherArg type + +Revision 1.3 2011/05/20 13:54:51 jeshua +Changed to struct +Added const +Added entryPoint +Removed dead code + +Revision 1.2 2011/05/13 21:15:22 jeshua +Updated comments +Renamed InstructionCountArg to OtherArg, and added PORE type into it +Added iv_extractState +Added Hooks class + +Revision 1.1 2011/05/11 19:57:30 jeshua +Initial version + + + + +*/ +/* Local Variables: */ +/* c-basic-offset: 4 */ +/* End: */ diff --git a/src/usr/pore/fapiporeve/makefile b/src/usr/pore/fapiporeve/makefile new file mode 100644 index 000000000..b83666c75 --- /dev/null +++ b/src/usr/pore/fapiporeve/makefile @@ -0,0 +1,39 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/pore/fapiporeve/makefile $ +# +# IBM CONFIDENTIAL +# +# COPYRIGHT International Business Machines Corp. 2011 +# +# p1 +# +# Object Code Only (OCO) source materials +# Licensed Internal Code Source Materials +# IBM HostBoot Licensed Internal Code +# +# The source code for this program is not published or other- +# wise divested of its trade secrets, irrespective of what has +# been deposited with the U.S. Copyright Office. +# +# Origin: 30 +# +# IBM_PROLOG_END + +ROOTPATH = ../../../.. +# fapiporeve provides interfaces to create a poreve object +# with a set of pre-defined arguments +MODULE = fapiporeve + +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/ecmddatabuffer +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/fapi +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/plat +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/poreve/porevesrc +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/poreve/pore_model +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/poreve/model + +OBJS = fapiPoreVe.o fapiPoreVeArg.o + +include ${ROOTPATH}/config.mk diff --git a/src/usr/pore/makefile b/src/usr/pore/makefile new file mode 100644 index 000000000..c544e8efb --- /dev/null +++ b/src/usr/pore/makefile @@ -0,0 +1,27 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/xscom/makefile $ +# +# IBM CONFIDENTIAL +# +# COPYRIGHT International Business Machines Corp. 2011 +# +# p1 +# +# Object Code Only (OCO) source materials +# Licensed Internal Code Source Materials +# IBM HostBoot Licensed Internal Code +# +# The source code for this program is not published or other- +# wise divested of its trade secrets, irrespective of what has +# been deposited with the U.S. Copyright Office. +# +# Origin: 30 +# +# IBM_PROLOG_END +ROOTPATH = ../../.. + +SUBDIRS = fapiporeve.d poreve.d test.d + +include ${ROOTPATH}/config.mk diff --git a/src/usr/pore/poreve/hook/sbe_pnor.hooks.cc b/src/usr/pore/poreve/hook/sbe_pnor.hooks.cc new file mode 100755 index 000000000..082f7d672 --- /dev/null +++ b/src/usr/pore/poreve/hook/sbe_pnor.hooks.cc @@ -0,0 +1,798 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/hook/sbe_pnor.hooks.cc $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id$ +// +// File generated by hook_indexer +// Arguments : -g -b bin/sbe_pnor.out -c bin/sbe_pnor.hooks.cc -m pnor +// Generation Date : Thu Jan 12 17:14:04 EST 2012 + +#include "hookmanager.H" + +using namespace vsbe; + +static const char* symbols[374] = { +"oci::sbe_pnor_error_2_control", +"oci::slw_error_2_ptr", +"oci::proc_sbe_instruct_start_winkle_return", +"pnor::slw_deep_winkle_exit_ptr", +"oci::sbe_pnor_undefined_ptr", +"pnor::return_from_proc_sbe_select_ex", +"pnor::proc_sbe_ex_host_runtime_scom_control", +"pnor::return_from_slw_deep_winkle_enter", +"pnor::proc_sbe_ex_chiplet_reset_control", +"oci::proc_sbe_ex_host_runtime_scom", +"pnor::slw_undefined", +"pnor::_sbe_pnor_halt", +"oci::proc_sbe_pnor_setup_control", +"pnor::sbe_pnor_error_3_ptr", +"pnor::return_from_slw_deep_sleep_enter", +"oci::proc_sbe_ex_func_l3_ring_loc", +"pnor::return_from_proc_sbe_ex_core_initf", +"pnor::proc_sbe_ex_startclocks_control", +"oci::return_from_slw_deep_winkle_enter", +"oci::proc_sbe_ex_chiplet_reset_control", +"pnor::proc_sbe_ex_enable_edram_control", +"pnor::proc_sbe_ex_sp_runtime_scom_control", +"oci::proc_slw_prolog", +"pnor::sbe_pnor_error_1_control", +"oci::proc_sbe_ex_startclocks", +"oci::return_from_slw_fast_sleep_exit", +"oci::proc_sbe_ex_sp_runtime_scom", +"oci::slw_power_on_off", +"pnor::slw_fast_sleep_exit", +"pnor::slw_error_1_ptr", +"pnor::proc_sbe_ex_repair_initf", +"pnor::slw_fast_sleep_enter_ptr", +"pnor::sbe_pnor_undefined_ptr", +"oci::proc_sbe_ex_core_initf", +"pnor::exit_ex_scan0_module", +"pnor::sbe_pnor_undefined", +"pnor::host_runtime_scom", +"pnor::proc_sbe_ex_initf", +"pnor::slw_pfet_seq", +"pnor::slw_fast_sleep_exit_control", +"pnor::proc_sbe_ex_repair_initf_control", +"pnor::slw_fast_winkle_enter_ptr", +"pnor::proc_sbe_ring_table_pnor_loc", +"pnor::slw_error_1_control", +"oci::proc_sbe_dd10_ex_func_core_ring", +"pnor::return_from_proc_sbe_instruct_start", +"oci::proc_sbe_ex_core_gptr_time_initf", +"oci::proc_sbe_instruct_start_sleep_return", +"pnor::slw_fast_winkle_enter", +"pnor::proc_sbe_ex_pll_initf_control", +"oci::slw_error_0", +"pnor::slw_branch_table", +"oci::slw_error_1", +"oci::slw_error_2", +"oci::slw_error_3", +"pnor::slw_deep_sleep_enter_ptr", +"pnor::sbe_pnor_error_0_ptr", +"pnor::return_from_proc_sbe_pnor_setup", +"oci::slw_error_4", +"oci::host_runtime_scom", +"oci::proc_sbe_ex_initf", +"oci::proc_sbe_ex_core_gptr_time_initf_control", +"pnor::proc_slw_epilog", +"oci::slw_fast_winkle_enter_ptr", +"pnor::proc_sbe_ex_core_initf", +"pnor::return_from_proc_sbe_ex_pll_initf", +"oci::slw_error_2_control", +"pnor::return_from_proc_sbe_ex_initf", +"pnor::proc_sbe_instruct_start", +"oci::proc_sbe_ex_core_repair_initf", +"oci::proc_sbe_ex_gptr_time_initf", +"pnor::proc_sbe_start_host_deadman_timer", +"oci::return_from_proc_sbe_pb_startclocks", +"pnor::proc_sbe_dd10_ex_func_l3_ring", +"pnor::proc_sbe_ex_occ_runtime_scom", +"oci::proc_sbe_ex_do_manual_inits", +"oci::sp_runtime_scom", +"oci::sbe_pnor_error_3_ptr", +"oci::proc_sbe_run_exinit_sleep_return", +"oci::return_from_proc_sbe_ex_pll_initf", +"oci::proc_sbe_ex_core_repair_initf_control", +"oci::proc_sbe_ex_gptr_time_initf_control", +"pnor::proc_sbe_start_host_deadman_timer_control", +"pnor::proc_sbe_ex_chiplet_reset", +"pnor::proc_sbe_pnor_setup_control", +"oci::proc_sbe_start_host_deadman_timer", +"oci::slw_fast_sleep_exit_ptr", +"oci::slw_deep_winkle_enter", +"pnor::return_from_proc_sbe_ex_arrayinit", +"pnor::ex_scan0_module", +"oci::sbe_pnor_error_3_control", +"oci::proc_sbe_ex_arrayinit_control", +"oci::proc_sbe_pnor_setup", +"pnor::return_from_proc_sbe_start_host_deadman_timer", +"oci::slw_error_4_ptr", +"oci::exit_ex_scan0_module", +"pnor::_sbe_pnor_start", +"oci::proc_sbe_start_host_deadman_timer_control", +"oci::proc_sbe_pb_startclocks_control", +"oci::proc_sbe_ex_chiplet_reset", +"pnor::proc_sbe_ex_enable_edram", +"pnor::proc_sbe_ex_sp_runtime_scom", +"oci::slw_pfet_seq", +"pnor::slw_control_vector", +"oci::return_from_proc_sbe_ex_arrayinit", +"oci::proc_sbe_ring_table_pnor_loc", +"pnor::return_from_proc_sbe_ex_host_runtime_scom", +"oci::proc_sbe_ring_table_pnor", +"oci::sbe_pnor_error_0_ptr", +"pnor::sbe_pnor_error_2_control", +"pnor::return_from_proc_sbe_run_exinit", +"pnor::slw_error_3_ptr", +"pnor::slw_error_0", +"pnor::return_from_slw_deep_sleep_exit", +"pnor::host_image_offset", +"pnor::slw_error_1", +"pnor::return_from_proc_sbe_ex_dpll_initf", +"pnor::slw_error_2", +"oci::return_from_proc_sbe_ex_host_runtime_scom", +"pnor::slw_error_3", +"oci::proc_sbe_ex_startclocks_control", +"oci::return_from_proc_sbe_ex_chiplet_reset", +"pnor::slw_error_4", +"oci::slw_undefined_control", +"oci::proc_sbe_fabricinit_control", +"oci::slw_load_sprg0", +"oci::proc_sbe_ex_occ_runtime_scom", +"pnor::slw_error_2_control", +"oci::slw_error_1_ptr", +"pnor::proc_sbe_select_ex", +"pnor::sbe_pnor_undefined_control", +"oci::proc_sbe_ex_dpll_initf", +"oci::host_image_offset", +"oci::return_from_proc_sbe_ex_init_escape", +"pnor::return_from_proc_sbe_lco_loader", +"oci::return_from_slw_fast_winkle_exit", +"pnor::sbe_pnor_branch_table", +"pnor::proc_sbe_ex_gptr_time_initf", +"pnor::return_from_proc_sbe_pb_startclocks", +"oci::proc_sbe_ex_pll_initf", +"pnor::proc_sbe_ex_do_manual_inits", +"pnor::return_from_proc_sbe_ex_chiplet_init", +"pnor::sbe_pnor_error_2_ptr", +"pnor::slw_power_on_off", +"pnor::proc_sbe_select_ex_control", +"pnor::slw_fast_winkle_enter_control", +"pnor::proc_sbe_ex_gptr_time_initf_control", +"oci::slw_error_3_control", +"oci::proc_sbe_run_exinit", +"pnor::slw_load_sprg0", +"oci::slw_deep_sleep_exit", +"oci::return_from_proc_sbe_pnor_setup", +"pnor::proc_sbe_pb_startclocks", +"pnor::slw_error_0_ptr", +"pnor::return_from_slw_fast_winkle_enter", +"oci::return_from_slw_deep_winkle_exit", +"pnor::proc_sbe_pnor_setup", +"oci::sbe_pnor_error_0", +"pnor::proc_sbe_ex_core_gptr_time_initf", +"oci::proc_slw_epilog", +"pnor::slw_fast_winkle_exit", +"oci::sbe_pnor_error_1", +"pnor::proc_sbe_ex_dpll_initf", +"pnor::proc_sbe_instruct_start_control", +"pnor::proc_sbe_instruct_start_winkle_return", +"oci::sbe_pnor_error_2", +"pnor::return_from_proc_sbe_ex_core_gptr_time_initf", +"pnor::return_from_proc_sbe_ex_core_repair_initf", +"oci::sbe_pnor_error_3", +"oci::proc_sbe_ex_arrayinit", +"oci::slw_deep_sleep_exit_control", +"oci::sbe_pnor_error_4", +"oci::return_from_proc_sbe_ex_core_initf", +"pnor::proc_sbe_ex_occ_runtime_scom_control", +"oci::proc_sbe_instruct_start", +"pnor::return_from_proc_sbe_ex_sp_runtime_scom", +"pnor::return_from_proc_sbe_fabricinit", +"pnor::proc_sbe_ex_host_runtime_scom", +"oci::sbe_pnor_error_0_control", +"pnor::proc_sbe_ex_core_gptr_time_initf_control", +"oci::proc_sbe_lco_loader", +"oci::occ_runtime_scom", +"oci::return_from_slw_fast_winkle_enter", +"oci::sbe_pnor_error_4_control", +"pnor::slw_deep_sleep_exit_ptr", +"oci::return_from_proc_sbe_ex_core_repair_initf", +"oci::return_from_proc_sbe_ex_startclocks", +"oci::proc_sbe_lco_loader_control", +"pnor::slw_deep_winkle_exit", +"oci::slw_deep_winkle_enter_control", +"oci::sbe_pnor_undefined", +"pnor::return_from_slw_error_0", +"pnor::proc_sbe_run_exinit_sleep_return", +"pnor::return_from_slw_error_1", +"pnor::return_from_slw_error_2", +"oci::ex_scan0_module", +"pnor::return_from_slw_error_3", +"pnor::return_from_slw_error_4", +"oci::proc_sbe_ex_host_runtime_scom_control", +"pnor::proc_sbe_fabricinit_control", +"oci::proc_sbe_ex_chiplet_init", +"oci::_sbe_pnor_start", +"oci::return_from_proc_sbe_ex_chiplet_init", +"oci::slw_undefined", +"pnor::sbe_pnor_error_3_control", +"oci::sbe_pnor_error_2_ptr", +"oci::proc_sbe_fabricinit", +"pnor::return_from_proc_sbe_ex_gptr_time_initf", +"pnor::return_from_proc_sbe_ex_init_escape", +"pnor::return_from_proc_sbe_ex_repair_initf", +"oci::proc_sbe_ex_chiplet_init_control", +"pnor::return_from_proc_sbe_ex_do_manual_inits", +"oci::slw_fast_winkle_exit_ptr", +"oci::proc_sbe_ex_core_initf_control", +"oci::return_from_proc_sbe_run_exinit", +"oci::return_from_proc_sbe_ex_occ_runtime_scom", +"oci::slw_fast_winkle_exit", +"pnor::slw_error_3_control", +"pnor::proc_sbe_ring_table_pnor", +"pnor::proc_sbe_run_exinit", +"oci::slw_error_3_ptr", +"oci::return_from_slw_deep_sleep_exit", +"pnor::proc_sbe_ex_initf_control", +"oci::return_from_proc_sbe_ex_core_gptr_time_initf", +"pnor::slw_deep_sleep_exit", +"pnor::proc_sbe_ex_core_repair_initf", +"pnor::proc_sbe_ex_init_escape", +"oci::proc_sbe_ex_occ_runtime_scom_control", +"oci::return_from_slw_fast_sleep_enter", +"oci::return_from_sbe_pnor_undefined", +"pnor::sbe_pnor_error_4_ptr", +"oci::proc_sbe_ex_dpll_initf_control", +"pnor::proc_sbe_run_exinit_winkle_return", +"oci::slw_error_0_control", +"pnor::slw_deep_sleep_exit_control", +"pnor::proc_sbe_ex_core_repair_initf_control", +"oci::proc_sbe_ex_func_core_ring_loc", +"pnor::proc_sbe_ex_init_escape_control", +"oci::slw_fast_winkle_enter", +"oci::proc_sbe_ex_pll_initf_control", +"oci::slw_error_4_control", +"oci::slw_deep_winkle_exit_ptr", +"pnor::slw_deep_winkle_enter_ptr", +"oci::proc_sbe_ex_initf_control", +"oci::return_from_proc_sbe_lco_loader", +"pnor::proc_sbe_lco_loader", +"oci::slw_deep_winkle_exit", +"pnor::slw_deep_winkle_enter", +"pnor::proc_sbe_ex_core_initf_control", +"pnor::proc_sbe_ex_arrayinit_control", +"oci::slw_control_vector", +"pnor::slw_error_2_ptr", +"oci::proc_sbe_run_exinit_control", +"oci::proc_sbe_run_exinit_winkle_return", +"oci::return_from_slw_deep_sleep_enter", +"pnor::return_from_slw_fast_winkle_exit", +"pnor::return_from_proc_sbe_ex_startclocks", +"pnor::slw_fast_sleep_enter", +"pnor::proc_sbe_lco_loader_control", +"oci::return_from_proc_sbe_ex_initf", +"oci::slw_deep_winkle_enter_ptr", +"oci::proc_sbe_ex_do_manual_inits_control", +"pnor::return_from_sbe_pnor_undefined", +"oci::proc_sbe_ex_enable_edram_control", +"pnor::slw_fast_winkle_exit_control", +"oci::sbe_pnor_error_1_control", +"oci::proc_sbe_dd10_ex_func_l3_ring", +"oci::find_ddX_ring_image", +"pnor::proc_sbe_ex_dpll_initf_control", +"oci::proc_sbe_pb_startclocks", +"oci::slw_error_0_ptr", +"pnor::slw_fast_sleep_enter_control", +"pnor::proc_sbe_ex_func_core_ring_loc", +"oci::proc_sbe_ex_repair_initf", +"oci::slw_fast_sleep_enter_ptr", +"pnor::sbe_pnor_branch_table_loc", +"oci::proc_sbe_instruct_start_control", +"oci::return_from_proc_sbe_ex_repair_initf", +"pnor::proc_slw_prolog", +"oci::return_from_proc_sbe_ex_dpll_initf", +"pnor::slw_undefined_ptr", +"pnor::proc_sbe_ex_startclocks", +"oci::return_from_proc_sbe_ex_sp_runtime_scom", +"oci::return_from_proc_sbe_fabricinit", +"pnor::sbe_pnor_error_1_ptr", +"pnor::return_from_slw_fast_sleep_exit", +"pnor::return_from_slw_deep_winkle_exit", +"pnor::proc_sbe_fabricinit", +"pnor::slw_deep_sleep_enter", +"pnor::sbe_pnor_error_0", +"oci::proc_sbe_ex_repair_initf_control", +"pnor::sbe_pnor_error_1", +"pnor::return_from_proc_sbe_ex_enable_edram", +"pnor::sbe_pnor_error_2", +"pnor::return_from_sbe_pnor_error_0", +"pnor::sbe_pnor_error_3", +"pnor::return_from_sbe_pnor_error_1", +"pnor::sbe_pnor_error_4", +"pnor::return_from_sbe_pnor_error_2", +"oci::proc_sbe_select_ex", +"pnor::slw_deep_winkle_exit_control", +"oci::slw_deep_sleep_exit_ptr", +"oci::sbe_pnor_undefined_control", +"oci::sbe_pnor_branch_table_loc", +"pnor::return_from_sbe_pnor_error_3", +"pnor::return_from_proc_sbe_ex_chiplet_reset", +"oci::slw_branch_table", +"pnor::return_from_sbe_pnor_error_4", +"oci::return_from_proc_sbe_start_host_deadman_timer", +"pnor::slw_undefined_control", +"oci::slw_undefined_ptr", +"pnor::slw_deep_sleep_enter_control", +"pnor::sbe_pnor_error_0_control", +"oci::slw_deep_sleep_enter_ptr", +"pnor::occ_runtime_scom", +"pnor::proc_sbe_dd10_ex_func_core_ring", +"pnor::sbe_pnor_error_4_control", +"oci::return_from_slw_error_0", +"oci::proc_sbe_select_ex_control", +"oci::sbe_pnor_error_4_ptr", +"oci::return_from_slw_error_1", +"oci::return_from_slw_error_2", +"oci::return_from_slw_error_3", +"oci::return_from_slw_error_4", +"pnor::return_from_slw_undefined", +"pnor::proc_sbe_ex_pll_initf", +"oci::proc_sbe_ex_sp_runtime_scom_control", +"pnor::slw_error_0_control", +"pnor::proc_sbe_ex_func_l3_ring_loc", +"oci::slw_fast_sleep_exit", +"pnor::slw_error_4_control", +"oci::return_from_proc_sbe_ex_gptr_time_initf", +"oci::slw_fast_sleep_enter", +"pnor::proc_sbe_ex_chiplet_init", +"oci::ex_init_escape", +"oci::return_from_proc_sbe_ex_do_manual_inits", +"oci::return_from_slw_undefined", +"pnor::sp_runtime_scom", +"oci::slw_fast_sleep_exit_control", +"oci::slw_fast_winkle_exit_control", +"pnor::proc_sbe_run_exinit_control", +"oci::slw_error_1_control", +"pnor::proc_sbe_ex_arrayinit", +"oci::return_from_proc_sbe_instruct_start", +"oci::slw_fast_sleep_enter_control", +"pnor::proc_sbe_ex_chiplet_init_control", +"oci::return_from_proc_sbe_select_ex", +"pnor::proc_sbe_ex_do_manual_inits_control", +"oci::sbe_pnor_branch_table", +"oci::proc_sbe_ex_init_escape", +"pnor::slw_fast_sleep_exit_ptr", +"pnor::find_ddX_ring_image", +"pnor::slw_fast_winkle_exit_ptr", +"oci::sbe_pnor_error_1_ptr", +"oci::_sbe_pnor_halt", +"oci::proc_sbe_ex_enable_edram", +"pnor::return_from_proc_sbe_ex_occ_runtime_scom", +"oci::slw_deep_sleep_enter", +"pnor::proc_sbe_instruct_start_sleep_return", +"oci::slw_fast_winkle_enter_control", +"oci::return_from_proc_sbe_ex_enable_edram", +"oci::return_from_sbe_pnor_error_0", +"pnor::slw_error_4_ptr", +"oci::return_from_sbe_pnor_error_1", +"oci::return_from_sbe_pnor_error_2", +"pnor::ex_init_escape", +"oci::proc_sbe_ex_init_escape_control", +"oci::slw_deep_winkle_exit_control", +"pnor::slw_deep_winkle_enter_control", +"oci::return_from_sbe_pnor_error_3", +"pnor::return_from_slw_fast_sleep_enter", +"oci::return_from_sbe_pnor_error_4", +"pnor::proc_sbe_pb_startclocks_control", +"oci::slw_deep_sleep_enter_control", +}; + +static GlobalSymbolInfo info[374] = { +{PoreAddress(0x8000, 0x80000290), 'R'}, +{PoreAddress(0x8000, 0x80001ea8), 'T'}, +{PoreAddress(0x8000, 0x800019ac), 'T'}, +{PoreAddress(0x800b, 0x800016c4), 'T'}, +{PoreAddress(0x8000, 0x800078a8), 'T'}, +{PoreAddress(0x800b, 0x80004b3c), 'T'}, +{PoreAddress(0x800b, 0x80000218), 'R'}, +{PoreAddress(0x800b, 0x80001594), 'T'}, +{PoreAddress(0x800b, 0x80000170), 'R'}, +{PoreAddress(0x8000, 0x80000834), 'T'}, +{PoreAddress(0x800b, 0x80002550), 'T'}, +{PoreAddress(0x800b, 0x800051d4), 'T'}, +{PoreAddress(0x8000, 0x800002b0), 'R'}, +{PoreAddress(0x800b, 0x800075d0), 'T'}, +{PoreAddress(0x800b, 0x800011e4), 'T'}, +{PoreAddress(0x8000, 0x80000120), 'R'}, +{PoreAddress(0x800b, 0x8000665c), 'T'}, +{PoreAddress(0x800b, 0x800001d8), 'R'}, +{PoreAddress(0x8000, 0x80001594), 'T'}, +{PoreAddress(0x8000, 0x80000170), 'R'}, +{PoreAddress(0x800b, 0x800001b8), 'R'}, +{PoreAddress(0x800b, 0x800001f8), 'R'}, +{PoreAddress(0x8000, 0x8000095c), 'T'}, +{PoreAddress(0x800b, 0x80000288), 'R'}, +{PoreAddress(0x8000, 0x800006d4), 'T'}, +{PoreAddress(0x8000, 0x80000c5c), 'T'}, +{PoreAddress(0x8000, 0x800007dc), 'T'}, +{PoreAddress(0x8000, 0x80002558), 'T'}, +{PoreAddress(0x800b, 0x800018cc), 'T'}, +{PoreAddress(0x800b, 0x80001d08), 'T'}, +{PoreAddress(0x800b, 0x800004a0), 'T'}, +{PoreAddress(0x800b, 0x800009dc), 'T'}, +{PoreAddress(0x800b, 0x800078a8), 'T'}, +{PoreAddress(0x8000, 0x80000678), 'T'}, +{PoreAddress(0x800b, 0x80000488), 'T'}, +{PoreAddress(0x800b, 0x80007a28), 'T'}, +{PoreAddress(0x800b, 0x80000210), 'R'}, +{PoreAddress(0x800b, 0x80000620), 'T'}, +{PoreAddress(0x800b, 0x8000272c), 'T'}, +{PoreAddress(0x800b, 0x800002d0), 'R'}, +{PoreAddress(0x800b, 0x80000190), 'R'}, +{PoreAddress(0x800b, 0x80000d8c), 'T'}, +{PoreAddress(0x800b, 0x80000100), 'R'}, +{PoreAddress(0x800b, 0x80000308), 'R'}, +{PoreAddress(0x8000, 0x80000228), 'R'}, +{PoreAddress(0x800b, 0x80004f74), 'T'}, +{PoreAddress(0x8000, 0x800005c8), 'T'}, +{PoreAddress(0x8000, 0x80001910), 'T'}, +{PoreAddress(0x800b, 0x80001938), 'T'}, +{PoreAddress(0x800b, 0x80000180), 'R'}, +{PoreAddress(0x8000, 0x80002528), 'T'}, +{PoreAddress(0x800b, 0x80000860), 'T'}, +{PoreAddress(0x8000, 0x80002530), 'T'}, +{PoreAddress(0x8000, 0x80002538), 'T'}, +{PoreAddress(0x8000, 0x80002540), 'T'}, +{PoreAddress(0x800b, 0x8000113c), 'T'}, +{PoreAddress(0x800b, 0x8000718c), 'T'}, +{PoreAddress(0x800b, 0x80004704), 'T'}, +{PoreAddress(0x8000, 0x80002548), 'T'}, +{PoreAddress(0x8000, 0x80000210), 'R'}, +{PoreAddress(0x8000, 0x80000620), 'T'}, +{PoreAddress(0x8000, 0x800001b0), 'R'}, +{PoreAddress(0x800b, 0x8000099c), 'T'}, +{PoreAddress(0x8000, 0x80000d8c), 'T'}, +{PoreAddress(0x800b, 0x80000678), 'T'}, +{PoreAddress(0x800b, 0x80005c4c), 'T'}, +{PoreAddress(0x8000, 0x80000310), 'R'}, +{PoreAddress(0x800b, 0x800064f4), 'T'}, +{PoreAddress(0x800b, 0x8000702c), 'T'}, +{PoreAddress(0x8000, 0x800004a4), 'T'}, +{PoreAddress(0x8000, 0x800005c4), 'T'}, +{PoreAddress(0x800b, 0x80007028), 'T'}, +{PoreAddress(0x8000, 0x8000486c), 'T'}, +{PoreAddress(0x800b, 0x80000250), 'R'}, +{PoreAddress(0x800b, 0x80000808), 'T'}, +{PoreAddress(0x8000, 0x800006d0), 'T'}, +{PoreAddress(0x8000, 0x800001f0), 'R'}, +{PoreAddress(0x8000, 0x800075d0), 'T'}, +{PoreAddress(0x8000, 0x8000190c), 'T'}, +{PoreAddress(0x8000, 0x80005c4c), 'T'}, +{PoreAddress(0x8000, 0x80000198), 'R'}, +{PoreAddress(0x8000, 0x800001a8), 'R'}, +{PoreAddress(0x800b, 0x80000168), 'R'}, +{PoreAddress(0x800b, 0x80000380), 'T'}, +{PoreAddress(0x800b, 0x800002b0), 'R'}, +{PoreAddress(0x8000, 0x80007028), 'T'}, +{PoreAddress(0x8000, 0x80000bb4), 'T'}, +{PoreAddress(0x8000, 0x80001940), 'T'}, +{PoreAddress(0x800b, 0x80006208), 'T'}, +{PoreAddress(0x800b, 0x80000414), 'T'}, +{PoreAddress(0x8000, 0x80000298), 'R'}, +{PoreAddress(0x8000, 0x800001a0), 'R'}, +{PoreAddress(0x8000, 0x80007a2c), 'T'}, +{PoreAddress(0x800b, 0x800050dc), 'T'}, +{PoreAddress(0x8000, 0x800021e8), 'T'}, +{PoreAddress(0x8000, 0x80000488), 'T'}, +{PoreAddress(0x800b, 0x80004700), 'T'}, +{PoreAddress(0x8000, 0x80000168), 'R'}, +{PoreAddress(0x8000, 0x80000138), 'R'}, +{PoreAddress(0x8000, 0x80000380), 'T'}, +{PoreAddress(0x800b, 0x800005cc), 'T'}, +{PoreAddress(0x800b, 0x800007dc), 'T'}, +{PoreAddress(0x8000, 0x8000272c), 'T'}, +{PoreAddress(0x800b, 0x800002b8), 'R'}, +{PoreAddress(0x8000, 0x80006208), 'T'}, +{PoreAddress(0x8000, 0x80000100), 'R'}, +{PoreAddress(0x800b, 0x80006ecc), 'T'}, +{PoreAddress(0x8000, 0x80000108), 'R'}, +{PoreAddress(0x8000, 0x8000718c), 'T'}, +{PoreAddress(0x800b, 0x80000290), 'R'}, +{PoreAddress(0x800b, 0x80004ca4), 'T'}, +{PoreAddress(0x800b, 0x80002048), 'T'}, +{PoreAddress(0x800b, 0x80002528), 'T'}, +{PoreAddress(0x800b, 0x800013bc), 'T'}, +{PoreAddress(0x800b, 0x80000148), 'R'}, +{PoreAddress(0x800b, 0x80002530), 'T'}, +{PoreAddress(0x800b, 0x80005ae4), 'T'}, +{PoreAddress(0x800b, 0x80002538), 'T'}, +{PoreAddress(0x8000, 0x80006ecc), 'T'}, +{PoreAddress(0x800b, 0x80002540), 'T'}, +{PoreAddress(0x8000, 0x800001d8), 'R'}, +{PoreAddress(0x8000, 0x80005690), 'T'}, +{PoreAddress(0x800b, 0x80002548), 'T'}, +{PoreAddress(0x8000, 0x80000328), 'R'}, +{PoreAddress(0x8000, 0x80000140), 'R'}, +{PoreAddress(0x8000, 0x800019d4), 'T'}, +{PoreAddress(0x8000, 0x80000808), 'T'}, +{PoreAddress(0x800b, 0x80000310), 'R'}, +{PoreAddress(0x8000, 0x80001d08), 'T'}, +{PoreAddress(0x800b, 0x800055a4), 'T'}, +{PoreAddress(0x800b, 0x800002a8), 'R'}, +{PoreAddress(0x8000, 0x800003ec), 'T'}, +{PoreAddress(0x8000, 0x80000148), 'R'}, +{PoreAddress(0x8000, 0x80006a94), 'T'}, +{PoreAddress(0x800b, 0x80004e0c), 'T'}, +{PoreAddress(0x8000, 0x8000100c), 'T'}, +{PoreAddress(0x800b, 0x80007090), 'T'}, +{PoreAddress(0x800b, 0x800005c4), 'T'}, +{PoreAddress(0x800b, 0x8000486c), 'T'}, +{PoreAddress(0x8000, 0x800003f0), 'T'}, +{PoreAddress(0x800b, 0x800006d0), 'T'}, +{PoreAddress(0x800b, 0x80005db4), 'T'}, +{PoreAddress(0x800b, 0x80007464), 'T'}, +{PoreAddress(0x800b, 0x80002558), 'T'}, +{PoreAddress(0x800b, 0x80000158), 'R'}, +{PoreAddress(0x800b, 0x800002e0), 'R'}, +{PoreAddress(0x800b, 0x800001a8), 'R'}, +{PoreAddress(0x8000, 0x80000318), 'R'}, +{PoreAddress(0x8000, 0x80005620), 'T'}, +{PoreAddress(0x800b, 0x800019d4), 'T'}, +{PoreAddress(0x8000, 0x800018d4), 'T'}, +{PoreAddress(0x8000, 0x80004704), 'T'}, +{PoreAddress(0x800b, 0x800051e8), 'T'}, +{PoreAddress(0x800b, 0x80001b68), 'T'}, +{PoreAddress(0x800b, 0x80000e34), 'T'}, +{PoreAddress(0x8000, 0x8000176c), 'T'}, +{PoreAddress(0x800b, 0x80007a2c), 'T'}, +{PoreAddress(0x8000, 0x80007a14), 'T'}, +{PoreAddress(0x800b, 0x800005c8), 'T'}, +{PoreAddress(0x8000, 0x8000099c), 'T'}, +{PoreAddress(0x800b, 0x80001968), 'T'}, +{PoreAddress(0x8000, 0x80007a18), 'T'}, +{PoreAddress(0x800b, 0x800003ec), 'T'}, +{PoreAddress(0x800b, 0x80000220), 'R'}, +{PoreAddress(0x800b, 0x800019ac), 'T'}, +{PoreAddress(0x8000, 0x80007a1c), 'T'}, +{PoreAddress(0x800b, 0x8000597c), 'T'}, +{PoreAddress(0x800b, 0x800060a0), 'T'}, +{PoreAddress(0x8000, 0x80007a20), 'T'}, +{PoreAddress(0x8000, 0x800004a8), 'T'}, +{PoreAddress(0x8000, 0x800002d8), 'R'}, +{PoreAddress(0x8000, 0x80007a24), 'T'}, +{PoreAddress(0x8000, 0x8000665c), 'T'}, +{PoreAddress(0x800b, 0x80000208), 'R'}, +{PoreAddress(0x8000, 0x8000702c), 'T'}, +{PoreAddress(0x800b, 0x80006bfc), 'T'}, +{PoreAddress(0x800b, 0x800049d4), 'T'}, +{PoreAddress(0x800b, 0x80000834), 'T'}, +{PoreAddress(0x8000, 0x80000280), 'R'}, +{PoreAddress(0x800b, 0x800001b0), 'R'}, +{PoreAddress(0x8000, 0x8000534c), 'T'}, +{PoreAddress(0x8000, 0x80000200), 'R'}, +{PoreAddress(0x8000, 0x80000e34), 'T'}, +{PoreAddress(0x8000, 0x800002a0), 'R'}, +{PoreAddress(0x800b, 0x80001314), 'T'}, +{PoreAddress(0x8000, 0x800060a0), 'T'}, +{PoreAddress(0x8000, 0x8000692c), 'T'}, +{PoreAddress(0x8000, 0x80000150), 'R'}, +{PoreAddress(0x800b, 0x80001970), 'T'}, +{PoreAddress(0x8000, 0x800002e8), 'R'}, +{PoreAddress(0x8000, 0x80007a28), 'T'}, +{PoreAddress(0x800b, 0x80001bd8), 'T'}, +{PoreAddress(0x800b, 0x8000190c), 'T'}, +{PoreAddress(0x800b, 0x80001d78), 'T'}, +{PoreAddress(0x800b, 0x80001f18), 'T'}, +{PoreAddress(0x8000, 0x80000414), 'T'}, +{PoreAddress(0x800b, 0x800020b8), 'T'}, +{PoreAddress(0x800b, 0x80002258), 'T'}, +{PoreAddress(0x8000, 0x80000218), 'R'}, +{PoreAddress(0x800b, 0x80000140), 'R'}, +{PoreAddress(0x8000, 0x8000048c), 'T'}, +{PoreAddress(0x8000, 0x80004700), 'T'}, +{PoreAddress(0x8000, 0x80005db4), 'T'}, +{PoreAddress(0x8000, 0x80002550), 'T'}, +{PoreAddress(0x800b, 0x80000298), 'R'}, +{PoreAddress(0x8000, 0x80007464), 'T'}, +{PoreAddress(0x8000, 0x800052cc), 'T'}, +{PoreAddress(0x800b, 0x80005814), 'T'}, +{PoreAddress(0x800b, 0x80006a94), 'T'}, +{PoreAddress(0x800b, 0x80005f38), 'T'}, +{PoreAddress(0x8000, 0x80000188), 'R'}, +{PoreAddress(0x800b, 0x800067c4), 'T'}, +{PoreAddress(0x8000, 0x80000f64), 'T'}, +{PoreAddress(0x8000, 0x800001c8), 'R'}, +{PoreAddress(0x8000, 0x80004ca4), 'T'}, +{PoreAddress(0x8000, 0x80006d64), 'T'}, +{PoreAddress(0x8000, 0x80001968), 'T'}, +{PoreAddress(0x800b, 0x80000318), 'R'}, +{PoreAddress(0x800b, 0x80000108), 'R'}, +{PoreAddress(0x800b, 0x80005620), 'T'}, +{PoreAddress(0x8000, 0x80002048), 'T'}, +{PoreAddress(0x8000, 0x800013bc), 'T'}, +{PoreAddress(0x800b, 0x800001c0), 'R'}, +{PoreAddress(0x8000, 0x8000597c), 'T'}, +{PoreAddress(0x800b, 0x800018d4), 'T'}, +{PoreAddress(0x800b, 0x800004a4), 'T'}, +{PoreAddress(0x800b, 0x800007b0), 'T'}, +{PoreAddress(0x8000, 0x80000208), 'R'}, +{PoreAddress(0x8000, 0x80000a84), 'T'}, +{PoreAddress(0x8000, 0x80007918), 'T'}, +{PoreAddress(0x800b, 0x8000773c), 'T'}, +{PoreAddress(0x8000, 0x80000178), 'R'}, +{PoreAddress(0x800b, 0x800019a8), 'T'}, +{PoreAddress(0x8000, 0x80000300), 'R'}, +{PoreAddress(0x800b, 0x800002d8), 'R'}, +{PoreAddress(0x800b, 0x80000198), 'R'}, +{PoreAddress(0x8000, 0x80000108), 'R'}, +{PoreAddress(0x800b, 0x800001e8), 'R'}, +{PoreAddress(0x8000, 0x80001938), 'T'}, +{PoreAddress(0x8000, 0x80000180), 'R'}, +{PoreAddress(0x8000, 0x80000320), 'R'}, +{PoreAddress(0x8000, 0x800016c4), 'T'}, +{PoreAddress(0x800b, 0x800014ec), 'T'}, +{PoreAddress(0x8000, 0x800001c0), 'R'}, +{PoreAddress(0x8000, 0x80004e0c), 'T'}, +{PoreAddress(0x800b, 0x8000534c), 'T'}, +{PoreAddress(0x8000, 0x80001970), 'T'}, +{PoreAddress(0x800b, 0x80001940), 'T'}, +{PoreAddress(0x800b, 0x800001c8), 'R'}, +{PoreAddress(0x800b, 0x800001a0), 'R'}, +{PoreAddress(0x8000, 0x800002b8), 'R'}, +{PoreAddress(0x800b, 0x80001ea8), 'T'}, +{PoreAddress(0x8000, 0x80000160), 'R'}, +{PoreAddress(0x8000, 0x800019a8), 'T'}, +{PoreAddress(0x8000, 0x800011e4), 'T'}, +{PoreAddress(0x800b, 0x8000100c), 'T'}, +{PoreAddress(0x800b, 0x8000692c), 'T'}, +{PoreAddress(0x800b, 0x8000189c), 'T'}, +{PoreAddress(0x800b, 0x80000150), 'R'}, +{PoreAddress(0x8000, 0x800064f4), 'T'}, +{PoreAddress(0x8000, 0x800014ec), 'T'}, +{PoreAddress(0x8000, 0x800001d0), 'R'}, +{PoreAddress(0x800b, 0x80007918), 'T'}, +{PoreAddress(0x8000, 0x800001b8), 'R'}, +{PoreAddress(0x800b, 0x800002f0), 'R'}, +{PoreAddress(0x8000, 0x80000288), 'R'}, +{PoreAddress(0x8000, 0x80000250), 'R'}, +{PoreAddress(0x8000, 0x800005d0), 'T'}, +{PoreAddress(0x800b, 0x80000178), 'R'}, +{PoreAddress(0x8000, 0x800051e8), 'T'}, +{PoreAddress(0x8000, 0x80001b68), 'T'}, +{PoreAddress(0x800b, 0x800002c0), 'R'}, +{PoreAddress(0x800b, 0x80000108), 'R'}, +{PoreAddress(0x8000, 0x800004a0), 'T'}, +{PoreAddress(0x8000, 0x800009dc), 'T'}, +{PoreAddress(0x800b, 0x80000278), 'R'}, +{PoreAddress(0x8000, 0x80000220), 'R'}, +{PoreAddress(0x8000, 0x80005f38), 'T'}, +{PoreAddress(0x800b, 0x8000095c), 'T'}, +{PoreAddress(0x8000, 0x80005ae4), 'T'}, +{PoreAddress(0x800b, 0x80002388), 'T'}, +{PoreAddress(0x800b, 0x800006d4), 'T'}, +{PoreAddress(0x8000, 0x80006bfc), 'T'}, +{PoreAddress(0x8000, 0x800049d4), 'T'}, +{PoreAddress(0x800b, 0x800072f8), 'T'}, +{PoreAddress(0x800b, 0x80000c5c), 'T'}, +{PoreAddress(0x800b, 0x8000176c), 'T'}, +{PoreAddress(0x800b, 0x800052cc), 'T'}, +{PoreAddress(0x800b, 0x800018a4), 'T'}, +{PoreAddress(0x800b, 0x80007a14), 'T'}, +{PoreAddress(0x8000, 0x80000190), 'R'}, +{PoreAddress(0x800b, 0x80007a18), 'T'}, +{PoreAddress(0x800b, 0x80006370), 'T'}, +{PoreAddress(0x800b, 0x80007a1c), 'T'}, +{PoreAddress(0x800b, 0x800071fc), 'T'}, +{PoreAddress(0x800b, 0x80007a20), 'T'}, +{PoreAddress(0x800b, 0x80007368), 'T'}, +{PoreAddress(0x800b, 0x80007a24), 'T'}, +{PoreAddress(0x800b, 0x800074d4), 'T'}, +{PoreAddress(0x8000, 0x800055a4), 'T'}, +{PoreAddress(0x800b, 0x800002f8), 'R'}, +{PoreAddress(0x8000, 0x80001314), 'T'}, +{PoreAddress(0x8000, 0x800002a8), 'R'}, +{PoreAddress(0x8000, 0x80000278), 'R'}, +{PoreAddress(0x800b, 0x80007640), 'T'}, +{PoreAddress(0x800b, 0x80005690), 'T'}, +{PoreAddress(0x8000, 0x80000860), 'T'}, +{PoreAddress(0x800b, 0x800077ac), 'T'}, +{PoreAddress(0x8000, 0x800050dc), 'T'}, +{PoreAddress(0x800b, 0x80000328), 'R'}, +{PoreAddress(0x8000, 0x80002388), 'T'}, +{PoreAddress(0x800b, 0x800002c8), 'R'}, +{PoreAddress(0x800b, 0x80000280), 'R'}, +{PoreAddress(0x8000, 0x8000113c), 'T'}, +{PoreAddress(0x800b, 0x80000200), 'R'}, +{PoreAddress(0x800b, 0x80000228), 'R'}, +{PoreAddress(0x800b, 0x800002a0), 'R'}, +{PoreAddress(0x8000, 0x80001bd8), 'T'}, +{PoreAddress(0x8000, 0x80000158), 'R'}, +{PoreAddress(0x8000, 0x8000773c), 'T'}, +{PoreAddress(0x8000, 0x80001d78), 'T'}, +{PoreAddress(0x8000, 0x80001f18), 'T'}, +{PoreAddress(0x8000, 0x800020b8), 'T'}, +{PoreAddress(0x8000, 0x80002258), 'T'}, +{PoreAddress(0x800b, 0x800023f8), 'T'}, +{PoreAddress(0x800b, 0x800003f0), 'T'}, +{PoreAddress(0x8000, 0x800001f8), 'R'}, +{PoreAddress(0x800b, 0x80000300), 'R'}, +{PoreAddress(0x800b, 0x80000120), 'R'}, +{PoreAddress(0x8000, 0x800018cc), 'T'}, +{PoreAddress(0x800b, 0x80000320), 'R'}, +{PoreAddress(0x8000, 0x80005814), 'T'}, +{PoreAddress(0x8000, 0x8000189c), 'T'}, +{PoreAddress(0x800b, 0x8000048c), 'T'}, +{PoreAddress(0x8000, 0x800001e0), 'R'}, +{PoreAddress(0x8000, 0x800067c4), 'T'}, +{PoreAddress(0x8000, 0x800023f8), 'T'}, +{PoreAddress(0x800b, 0x800001f0), 'R'}, +{PoreAddress(0x8000, 0x800002d0), 'R'}, +{PoreAddress(0x8000, 0x800002f0), 'R'}, +{PoreAddress(0x800b, 0x80000160), 'R'}, +{PoreAddress(0x8000, 0x80000308), 'R'}, +{PoreAddress(0x800b, 0x800004a8), 'T'}, +{PoreAddress(0x8000, 0x80004f74), 'T'}, +{PoreAddress(0x8000, 0x800002c0), 'R'}, +{PoreAddress(0x800b, 0x80000188), 'R'}, +{PoreAddress(0x8000, 0x80004b3c), 'T'}, +{PoreAddress(0x800b, 0x800001d0), 'R'}, +{PoreAddress(0x8000, 0x80007090), 'T'}, +{PoreAddress(0x8000, 0x800007b0), 'T'}, +{PoreAddress(0x800b, 0x80000bb4), 'T'}, +{PoreAddress(0x800b, 0x800005d0), 'T'}, +{PoreAddress(0x800b, 0x80000f64), 'T'}, +{PoreAddress(0x8000, 0x800072f8), 'T'}, +{PoreAddress(0x8000, 0x800051d4), 'T'}, +{PoreAddress(0x8000, 0x800005cc), 'T'}, +{PoreAddress(0x800b, 0x80006d64), 'T'}, +{PoreAddress(0x8000, 0x800018a4), 'T'}, +{PoreAddress(0x800b, 0x80001910), 'T'}, +{PoreAddress(0x8000, 0x800002e0), 'R'}, +{PoreAddress(0x8000, 0x80006370), 'T'}, +{PoreAddress(0x8000, 0x800071fc), 'T'}, +{PoreAddress(0x800b, 0x800021e8), 'T'}, +{PoreAddress(0x8000, 0x80007368), 'T'}, +{PoreAddress(0x8000, 0x800074d4), 'T'}, +{PoreAddress(0x800b, 0x800001e0), 'R'}, +{PoreAddress(0x8000, 0x800001e8), 'R'}, +{PoreAddress(0x8000, 0x800002f8), 'R'}, +{PoreAddress(0x800b, 0x800002e8), 'R'}, +{PoreAddress(0x8000, 0x80007640), 'T'}, +{PoreAddress(0x800b, 0x80000a84), 'T'}, +{PoreAddress(0x8000, 0x800077ac), 'T'}, +{PoreAddress(0x800b, 0x80000138), 'R'}, +{PoreAddress(0x8000, 0x800002c8), 'R'}, +}; + +static void +init() +{ +int i; +FAPI_INF("HookManager : " + "Indexing global symbols for bin/sbe_pnor.out"); +for (i = 0; i < 374; i++) { + HookManager::registerGlobalSymbol(symbols[i], &(info[i])); +} +} + +static HookInitializer initializer(init); diff --git a/src/usr/pore/poreve/makefile b/src/usr/pore/poreve/makefile new file mode 100644 index 000000000..b1a2b0b89 --- /dev/null +++ b/src/usr/pore/poreve/makefile @@ -0,0 +1,67 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/pore/pore_model/makefile $ +# +# IBM CONFIDENTIAL +# +# COPYRIGHT International Business Machines Corp. 2011 +# +# p1 +# +# Object Code Only (OCO) source materials +# Licensed Internal Code Source Materials +# IBM HostBoot Licensed Internal Code +# +# The source code for this program is not published or other- +# wise divested of its trade secrets, irrespective of what has +# been deposited with the U.S. Copyright Office. +# +# Origin: 30 +# +# IBM_PROLOG_END + +# Module poreve built from 3 different source code areas: +# +# model The source code of the PoreInterface and PoreModel classes, +# including the Transaction model. This pair of abstract classes +# is implemented on the model side by a hardware model +# (e.g., pore_model), and on the interface side by a virtual +# environment (e.g., poreve). +# +# pore_model Model the hardware of the PORE. This containts the "pore-engine-core/interpreter" of the PORe simulation +# The code in this directory is owned by Boeblingen team. +# +# porevesrc The Source code of the PoreVe class, including the Bus and +# Slave models, and the HookManager. +# +ROOTPATH = ../../../.. +MODULE = poreve +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/ecmddatabuffer +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/poreve/model +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/poreve/pore_model/include +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/fapi +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/plat +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/poreve/porevesrc + +CUSTOMFLAGS += -D__BYTE_ORDER=1 -D__BIG_ENDIAN=1 -D__LITTLE_ENDIAN=0 -DFASTI2C_BASE_OFFSET=0 -DDEBUG_FASTI2C=1 -D_BIG_ENDIAN=1 + +# Override to use C++ compiler for %.c/h files +CC_OVERRIDE = 1 + +OBJS = poreveutil.o +OBJS += transaction.o poreaddress.o poremodel.o poreregister.o poreinterface.o porestate.o +OBJS += pore_model.o pore_bus.o pore_fi2c.o pore_inline_decode.o vsbe.o +OBJS += pore.o bus.o hookmanager.o poreve.o pib2cfam.o fasti2c.o sbevital.o create.o +HOOK_SOURCE_FILES = $(notdir $(wildcard ./hook/*sbe*.hooks.cc)) +OBJS += $(patsubst %.cc,%.o,$(HOOK_SOURCE_FILES)) + +vpath %.C ./model/ +vpath %.C ./pore_model/wrapper/ +# Note: small c files +vpath %.c ./pore_model/ibuf/ +vpath %.C ./porevesrc/ +vpath %.cc ./hook/ + +include ${ROOTPATH}/config.mk diff --git a/src/usr/pore/poreve/model/bebits.H b/src/usr/pore/poreve/model/bebits.H new file mode 100644 index 000000000..403dbe53a --- /dev/null +++ b/src/usr/pore/poreve/model/bebits.H @@ -0,0 +1,48 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/bebits.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_BEBITS_H +#define __VSBE_BEBITS_H + +// $Id: bebits.H,v 1.3 2011/06/30 03:34:58 bcbrock Exp $ + +/// \file bebits.H +/// \brief Bit manipulation for Big-Endian data + + +/// A bit mask for a range of bits in a big-endian uint64_t +#define BE64_MASK(begin, end) \ + ((0xffffffffffffffffull >> (64 - ((end) - (begin) + 1))) << (63 - (end))) + +/// A single bit mask for a big-endian uint64_t +#define BE64_BIT(n) (BE64_MASK((n), (n))) + +/// Extract an unsigned field from a uint64_t +#define BE64_GET_FIELD(x, begin, end) \ + (((x) & BE64_MASK((begin), (end))) >> (63 - (end))) + +/// Update an unsigned field in a uint64_t from a right-justified uint64_t value +#define BE64_SET_FIELD(x, begin, end, val) \ + ((((val) << (63 - (end))) & BE64_MASK((begin), (end))) | \ + ((x) & ~BE64_MASK((begin), (end)))) + +#endif // __VSBE_BEBITS_H diff --git a/src/usr/pore/poreve/model/modelerror.H b/src/usr/pore/poreve/model/modelerror.H new file mode 100644 index 000000000..41d42687e --- /dev/null +++ b/src/usr/pore/poreve/model/modelerror.H @@ -0,0 +1,149 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/modelerror.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_MODELERROR_H +#define __VSBE_MODELERROR_H + +// $Id: modelerror.H,v 1.9 2011/07/07 03:51:52 bcbrock Exp $ + +/// \file modelerror.H +/// \brief An enumeration of modeling errors + +namespace vsbe { + + /// \enum ModelError + /// + /// A large number of error conditions can arise in the PORE VE model, + /// ranging all the way from bugs in the model to bugs in the virtual + /// firmware. The PORE VE model includes an enumeration of all of these + /// errors for error reporting and to aid in finding bugs. We chose to use + /// this mechanism rather than defining a FAPI error for each error case + /// since a FAPI error code may imply a complex error diagnosis and/or + /// recovery path, while it's likely that most ModelError that halt + /// simulation are firmware bugs that will be handled the same way. + + enum ModelError { + + /// No error. This code is permanently assigned to 0, so code is free + /// to either check for 0 or for ME_SUCCESS. + ME_SUCCESS = 0, + /// A generic failure from an operation in the environment + ME_FAILURE = 1, + /// An improperly configured model that is missing a bus connection + ME_NO_BUS_MODEL = 2, + /// A HOOK instruction hook returned an error + ME_HOOK_INSTRUCTION_ERROR = 3, + /// A read hook returned an error + ME_HOOK_READ_ERROR = 4, + /// A write hook returned an error + ME_HOOK_WRITE_ERROR = 5, + /// A fetch hook returned an error + ME_HOOK_FETCH_ERROR = 6, + /// The PORE model was constructed but never initialized + ME_PORE_UNINITIALIZED = 7, + /// A generic error from the underlying PoreModel + ME_PORE_MODEL_GENERIC_ERROR = 8, + /// A transaction size error + ME_SIZE_ERROR = 9, + /// An error ocurred on the registerRead() method + ME_REGISTER_READ_ERROR = 10, + /// An error ocurred on the registerWrite() method + ME_REGISTER_WRITE_ERROR = 11, + /// Transaction address is not in any known memory map + ME_NOT_MAPPED_ON_BUS = 12, + /// Transaction address is in a memory map but not in the memory image + ME_NOT_MAPPED_IN_MEMORY = 13, + /// Transaction mode denied by slave permissions found with transaction address + ME_BUS_SLAVE_PERMISSION_DENIED = 14, + /// Transaction mode denied by MemoryImage permissions + ME_MEMORY_IMAGE_PERMISSION_DENIED = 15, + /// There is a bug in the model + ME_BUG = 16, + /// The WAIT implementation failed for some reason + ME_WAIT_FAILURE = 17, + /// There was an error reading or writing a register in the PoreState + ME_PORE_STATE_ERROR = 18, + /// Attempting to read a write-only register + ME_WRITE_ONLY_REGISTER = 19, + /// Attempting to write a read-only register + ME_READ_ONLY_REGISTER = 20, + /// Request for an illegal or unmodeled register + ME_ILLEGAL_REGISTER_OFFSET = 21, + /// An illegal mode or setting was programmed in the I2C controller + ME_FASTI2C_CONTROL_ERROR = 22, + /// An illegal register sequence was attempted on the I2C controller + ME_FASTI2C_SEQUENCE_ERROR = 23, + /// A configuration is duplicate or ambiguous + ME_DUPLICATE_CONFIGURATION = 24, + /// A requested device is not mapped on the I2C controller + ME_NOT_MAPPED_ON_FASTI2C_CONTROLLER = 25, + /// An illegal address was presented to or computed by an I2C memory + ME_I2CMEMORY_ILLEGAL_ADDRESS = 26, + /// Invalid argument + ME_INVALID_ARGUMENT = 27, + /// LPC (PNOR) access outside of ECC bounds + ME_LPC_ILLEGAL_ADDRESS = 28, + /// An illegal usage of PoreModel::forceBranch() + ME_ILLEGAL_FORCED_BRANCH = 29, + }; +}; + +/// HBI doesn't want strings - however for lab/test applications it's nice to +/// be able to print the error codes. This macro can be instantiated to +/// provide this facility. + +#define MODEL_ERROR_STRINGS(var) \ + const char* const var[] = { \ + "Success", \ + "A generic failure from an operation in the environment", \ + "An improperly configured model that is missing a bus connection", \ + "A HOOK instruction hook returned an error", \ + "A read hook returned an error", \ + "A write hook returned an error", \ + "A fetch hook returned an error", \ + "The PORE model was constructed but never initialized", \ + "A generic error from the underlying PoreModel", \ + "A transaction size error", \ + "An error ocurred on the registerRead() method", \ + "An error ocurred on the registerWrite() method", \ + "Transaction address is not in any known memory map", \ + "Transaction address is in a memory map but not in the memory image", \ + "Transaction mode denied by slave permissions found with transaction address", \ + "Transaction mode denied by MemoryImage permissions", \ + "There is a bug in the model", \ + "The WAIT implementation failed for some reason", \ + "There was an error reading or writing a register in the PoreState", \ + "Attempting to read a write-only register", \ + "Attempting to write a read-only register", \ + "Request for an illegal or unmodeled register", \ + "An illegal mode or setting was programmed for I2C", \ + "An illegal register sequence was attempted on the I2C controller", \ + "A configuration is duplicate or ambiguous", \ + "A requested device is not mapped on the I2C controller", \ + "An illegal address was presented to or computed by an I2C memory", \ + "Invalid argument", \ + "LPC (PNOR) access outside of ECC bounds,", \ + "An illegal usage of PoreModel::forceBranch()", \ + }; + +#endif // __VSBE_MODELERROR_H + diff --git a/src/usr/pore/poreve/model/poreaddress.C b/src/usr/pore/poreve/model/poreaddress.C new file mode 100644 index 000000000..84bcaeeee --- /dev/null +++ b/src/usr/pore/poreve/model/poreaddress.C @@ -0,0 +1,78 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poreaddress.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: poreaddress.C,v 1.1 2011/06/08 13:12:50 bcbrock Exp $ + +/// \file poreaddress.C +/// \brief A simple abstract PORE address that separates the memory space from +/// the offset. + +#include "poreaddress.H" + +using namespace vsbe; + +//////////////////////////////////////////////////////////////////////////// +// PoreAddress +//////////////////////////////////////////////////////////////////////////// + +PoreAddress::PoreAddress() +{ + +} + + +PoreAddress::PoreAddress(uint16_t i_memorySpace, uint32_t i_offset) : + iv_offset(i_offset), + iv_memorySpace(i_memorySpace) +{ +} + + +PoreAddress::PoreAddress(uint64_t i_address) : + iv_offset(i_address & 0xffffffff), + iv_memorySpace((i_address >> 32) & 0xffff) +{ +} + + +PoreAddress::~PoreAddress() +{ +} + + +PoreAddress::operator uint64_t () const +{ + return ((uint64_t)iv_memorySpace << 32) | iv_offset; +} + + +PoreAddress& +PoreAddress::setFromPibAddress(uint32_t i_pibAddress) +{ + uint64_t address = i_pibAddress; + + iv_memorySpace = (address >> 16) & 0xffff; + iv_offset = (address & 0xffff) << 3; + + return *this; +} + diff --git a/src/usr/pore/poreve/model/poreaddress.H b/src/usr/pore/poreve/model/poreaddress.H new file mode 100644 index 000000000..ef2578ac1 --- /dev/null +++ b/src/usr/pore/poreve/model/poreaddress.H @@ -0,0 +1,117 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poreaddress.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_POREADDRESS_H +#define __VSBE_POREADDRESS_H + +// $Id: poreaddress.H,v 1.2 2012/01/06 21:25:15 bcbrock Exp $ + +/// \file poreaddress.H +/// \brief A simple abstract PORE address that separates the memory space from +/// the offset. + +#include <stdint.h> + +namespace vsbe { + + class PoreAddress; +} + + +//////////////////////////////////////////////////////////////////////////// +// PoreAddress +//////////////////////////////////////////////////////////////////////////// + +/// A PORE address +/// +/// PORE implements a segmented memory architecure. An address consists of a +/// 16-bit memory space identifier and a 32-bit byte offset within the memory +/// space. The memory space identifer denotes the physical memory interface +/// used for the memory (PIB or OCI). For PIB addresses, the memory space +/// also encodes direct vs. indirect memory access protocols. +/// +/// Inside the PORE the memory space Id is held in the 16 high-order bits of +/// the program counter. Relative branches and relative subroutine branches +/// do not modify the memory space. All other branches, including immediate +/// branches, indirect (dereferenced) branches and return from subroutine +/// update the entire 48-bit PC, and hence change the default memory space. +/// +/// The address registers also include an incomplete memory space field; the +/// field is incomplete because it does not include the PIB/Memory bit which +/// is implied. These memory space Ids are set by loading the registers. The +/// address register memory spaces are only valid for the SBE engine; for all +/// of the OCI-attached PORE engines the address registers only allow OCI +/// access and ignore the memory space Id. +/// +/// Since this is a simple type (equivalent to a uint64_t) we allow the +/// compiler to create the copy and assignment operators for the class. + +class +vsbe::PoreAddress { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + /// Construct an uninitialized PoreAddress + PoreAddress (); + + /// Construct a PoreAddress from a memory space Id + offset + /// + /// \param[in] i_memorySpace The 16-bit memory space descriptor + /// + /// \param[in] i_offset The 32-bit byte address within the memory space + PoreAddress(uint16_t i_memorySpace, uint32_t i_offset); + + /// Construct a PoreAddress from a right-justified uint64_t + /// + /// \param[in] i_address; + PoreAddress(uint64_t i_address); + + ~PoreAddress(); + + //////////////////////////// Operators //////////////////////////// + + /// Convert a PoreAddress to a uint64_t + operator uint64_t () const; + + //////////////////////////// Manipulators //////////////////////////// + + /// Convert a PIB address into a PoreAddress + /// + /// \param[in] i_pibAddress Assumed to be the PIB address of a location in + /// a direct access PIB memory, the address is converted to the equivalent + /// PORE address form + /// + /// \retval address A reference to the object + PoreAddress& setFromPibAddress(uint32_t i_pibAddress); + + ////////////////////////// Implementation //////////////////////////// + + /// The byte offset within the memory space + uint32_t iv_offset; + + /// The memory space identifier + uint16_t iv_memorySpace; +}; + +#endif // __VSBE_POREADDRESS_H diff --git a/src/usr/pore/poreve/model/poreconstants.H b/src/usr/pore/poreve/model/poreconstants.H new file mode 100644 index 000000000..b2d946711 --- /dev/null +++ b/src/usr/pore/poreve/model/poreconstants.H @@ -0,0 +1,275 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poreconstants.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_PORECONSTANTS_H +#define __VSBE_PORECONSTANTS_H + +// $Id: poreconstants.H,v 1.3 2011/10/14 21:35:19 bcbrock Exp $ + +/// \file poreconstants.H +/// \brief Constants associated with the The PORE hardware interface classes + +#include <stdint.h> + +namespace vsbe { + + /// PORE instruction buffer IDs + /// + /// These are the PORE instruction buffer IDs that PORE programs can read + /// out as the low-order 4 bits of the IDFLAGS register. This allows a + /// PORE program to determine which engine it is running on. Most + /// importantly, the Ibuf ID is required by various constructors and + /// methods as there are hardware differences between the various engines. + enum PoreIbufId { + PORE_GPE0 = 0, + PORE_GPE1 = 1, + PORE_SLW = 8, + PORE_SBE = 4 + }; + + /// \defgroup pore_status PORE Hardware Abstract Status + /// + /// The PoreModel produces an abstract status return code that succinctly + /// captures the state of the machine. The status consists of an + /// OR-combination of the PORE_STATUS_* flags. The status flags + /// effectively enumerate all of the reasons that the PORE engine may be + /// physically or abstractly halted or unrunnable. A status of 0 + /// indicates that the PORE engine is runnable and ready to execute the + /// next instruction. Since several of these conditions could be true at + /// once, the status is represented as an OR-mask rather than as a C++ + /// enum. + /// + /// Most of the status conditions require a specific action to clear the + /// status and allow instruction execution to resume. Some conditions are + /// considered fatal and require a reset() to continue. + /// + /// \note The status is currently compiled only by examining the PORE + /// state that is visible in the hardware. Currently this makes it + /// difficult to determine unequivically why the engine stopped. Change + /// requests are pending for the hardware to correct this. If it remains + /// difficult to determine from hardware status precisely why the PORE + /// engine is stopped, then we will have to decide whether to include APIs + /// in the virtual environment to transmit this information, and perhaps + /// diverge the capabilities of the virtual PORE from the real PORE. + + /// @{ + + /// The PORE executed a WAIT 0 (HALT) instruction + /// + /// This condition is determined by noting that the PORE is stopped, and + /// the instruction currently visible in the IBUF0 register is WAIT 0. To + /// continue, the user should either restart() the machine or write a + /// value into the EXE_TRIGGER register. Simply continuing from a HALT + /// would resume execution at the instruction following the HALT, and the + /// PoreModel::run() method will not continue execution as long as + /// this condition is true. + const int PORE_STATUS_HALTED = 0x01; + + /// The PORE halted due to an architected error + /// + /// This bit is determined by seeing the PORE is stopped and examining bit + /// 63 of PIBMS_DBG. 'Debug registers are locked'. To continue, the user + /// should restart () the machine. The PoreModel::run() method will not + /// continue execution as long as this condition is true. + const int PORE_STATUS_ERROR_HALT = 0x02; + + /// The PORE is in the hardware STOP state + /// + /// This flag indicates that bit 0 of the PORE control register is set, + /// signifying that the hardware is stopped. The stop may be due to a + /// halt, error halt, trap or address breakpoint, or may have been + /// commanded by the user. The PoreModel::run() method will normally + /// continue execution from this condition unless specifically prohibited + /// by another status bit. + const int PORE_STATUS_HARDWARE_STOP = 0x04; + + /// The PORE stopped due to an address breakpoint + /// + /// This condition is determined by noting that the PORE engine is stopped + /// in the ABR state, and either 1) the current PC is equal to the visible + /// address breakpoint address, or 2) the PORE_STATUS_TRAP condition is + /// not met. The second condition would arise if the address breakpoint + /// hit on a taken branch, because in the case the PC will end up pointing + /// to the branch target. If this status is set, the PoreModel::run() + /// method will generate the correct sequence to continue execution. + const int PORE_STATUS_BREAKPOINT = 0x08; + + /// The PORE hit an enabled trap + /// + /// This condition is determined by noting that the PORE engine is stopped + /// in the ABR state, the TRAP instruction is enabled, and the instruction + /// currently visible in the IBUF0 register is a TRAP. If this status is + /// set, the PoreModel::run() method will generate the correct sequence to + /// continue execution. + const int PORE_STATUS_TRAP = 0x10; + + /// The PORE model experienced a modeling error + /// + /// This conditon only exists in the virtual PORE model, and indicates + /// that the \a iv_ModelError attribute of the PoreModel is non-0. The + /// only ways to continue from this error are to restart() the machine or + /// to call the clearModelError() method, as the PoreModel::run() method + /// will not continue execution as long as this condition is true. + const int PORE_STATUS_MODEL_ERROR = 0x20; + + /// A debug stop + /// + /// This flag indicates that application code requested a stop by using + /// the stop() method, and the getStopCode() method can be used to recover + /// the argument of the stop() call. This is a debugging aid for use by + /// hooks, and does not actually stop the hardware. The PoreModel::run() + /// method will normally continue execution from this condition unless + /// specifically prohibited by another status bit. + const int PORE_STATUS_DEBUG_STOP = 0x40; + + /// @}; + + + /// \enum PoreRegisterOffset + /// + /// These are the 8-byte aligned address offsets for 4- and 8-byte + /// register accesses. For 4-byte accesses to the low-order word of an + /// 8-byte register, add 4 to the offset. + /// + /// These are the OCI address-space offsets used for the PORE-SLW, + /// PORE-GPE0 and PORE-GPE1 models. The PORE-SBE has a PIB interface, and + /// in that case the PIB slave (SCOM) offsets are actually these offsets / + /// 8. For consistency across all models we use the OCI offset below for + /// all PORE instances however, including the PORE-SBE. + /// + /// The PORE engine contains a number of visible registers, however there + /// remains state that is not visible but must be saved/restored to + /// checkpoint the engine. The final entry in the enumeration defines the + /// total size (in bytes) of the PORE state. This constant is used in the + /// definition of the PoreState struct. The area between + /// SIZEOF_VISIBLE_PORE_STATE and SIZEOF_PORE_STATE is model-specific, + /// programmer-invisible data. Currently there is no established protocol + /// for moving states between different software models or between + /// software and hardware models due to the presence of non-architected + /// state. The hidden state variables are enumerated for consistency with + /// the fapiPoreVe text-based register save/restore methodology. + /// + /// The register names appearing below are taken from the PORE hardware + /// specification. + enum PoreRegisterOffset { + // Visible registers + PORE_STATUS = 0x00, + PORE_CONTROL = 0x08, + PORE_RESET = 0x10, + PORE_ERROR_MASK = 0x18, + PORE_PRV_BASE_ADDR0 = 0x20, + PORE_PRV_BASE_ADDR1 = 0x28, + PORE_OCI_MEMORY_BASE_ADDR0 = 0x30, + PORE_OCI_MEMORY_BASE_ADDR1 = 0x38, + PORE_TABLE_BASE_ADDR = 0x40, + PORE_EXE_TRIGGER = 0x48, + PORE_EXE_TRIGGER_HI = 0x4c, // Programmer-writable bits 32:63 + PORE_SCRATCH0 = 0x50, + PORE_SCRATCH1 = 0x58, + PORE_SCRATCH2 = 0x60, + PORE_IBUF_01 = 0x68, + PORE_IBUF_2 = 0x70, + PORE_DBG0 = 0x78, + PORE_DBG1 = 0x80, + PORE_PC_STACK0 = 0x88, + PORE_PC_STACK1 = 0x90, + PORE_PC_STACK2 = 0x98, + PORE_ID_FLAGS = 0xa0, + PORE_DATA0 = 0xa8, + PORE_MEM_RELOC = 0xb0, + PORE_I2C_E0_PARAM = 0xb8, + PORE_I2C_E1_PARAM = 0xc0, + PORE_I2C_E2_PARAM = 0xc8, + // The size of the visible state + SIZEOF_VISIBLE_PORE_STATE = 0xd0, + // Add hidden state variables + PORE_HIDDEN_STATE_0 = 0xd0, + PORE_HIDDEN_STATE_1 = 0xd8, + PORE_HIDDEN_STATE_2 = 0xe0, + PORE_HIDDEN_STATE_3 = 0xe8, + PORE_HIDDEN_STATE_4 = 0xf0, + SIZEOF_PORE_STATE = 0xf8, + // An illegal offset, for robust error checking + PORE_ILLEGAL = 0xff + }; + + /// \enum PoreRegisterEncoding + /// + /// These are the 4-bit encodings used in the PORE instruction set to + /// identify the programmaer-visible registers. These are the register + /// names and encodings as defined in the PGAS manual. Abstract register + /// names are defined as extra encodings. Every register named here must + /// also be mapped in PORE_REGISTER_MAP. + enum PoreRegisterEncoding { + // These are "real" register encodings + PORE_P0 = 0x0, + PORE_P1 = 0x1, + PORE_A0 = 0x2, + PORE_A1 = 0x3, + PORE_CTR = 0x4, + PORE_D0 = 0x5, + PORE_D1 = 0x6, + PORE_EMR = 0x7, + PORE_ETR = 0x9, + PORE_SPRG0 = 0xa, + PORE_PC = 0xe, + PORE_IFR = 0xf, + // These are model-only encodings + PORE_CIA = 0x10 + }; + + /// This constant maps a PoreRegisterEncoding to the PoreRegisterOffset of + /// the register that contains the programmer-visible or abstract register. + const PoreRegisterOffset PORE_REGISTER_MAP[] = { + // These are "real" register encodings + PORE_PRV_BASE_ADDR0, // 0x0 + PORE_PRV_BASE_ADDR1, // 0x1 + PORE_OCI_MEMORY_BASE_ADDR0, // 0x2 + PORE_OCI_MEMORY_BASE_ADDR1, // 0x3 + PORE_SCRATCH0, // 0x4 + PORE_SCRATCH1, // 0x5 + PORE_SCRATCH2, // 0x6 + PORE_ERROR_MASK, // 0x7 + PORE_ILLEGAL, // 0x8 + PORE_EXE_TRIGGER, // 0x9 + PORE_DATA0, // 0xa + PORE_ILLEGAL, // 0xb + PORE_ILLEGAL, // 0xc + PORE_ILLEGAL, // 0xd + PORE_STATUS, // 0xe + PORE_ID_FLAGS, // 0xf + // These are model-only encodings + PORE_DBG1 // 0x10 + }; + + /// 'Infinity' for the purposes of the Pore run() method. + const uint64_t RUN_UNLIMITED = 0xffffffffffffffffull; + + /// The 'Stop Code' used by setPc() when it stops the processor. + const int STOP_CODE_SET_PC = -1; + + /// A bogus address to install as the breakpoint address to effectively + /// disable PORE address breakpoints. + const uint64_t PORE_UNBREAKABLE_ADDRESS = 0xfffffffffffcull; +}; + +#endif // __VSBE_PORECONSTANTS_H diff --git a/src/usr/pore/poreve/model/poreinterface.C b/src/usr/pore/poreve/model/poreinterface.C new file mode 100644 index 000000000..6adef3b60 --- /dev/null +++ b/src/usr/pore/poreve/model/poreinterface.C @@ -0,0 +1,242 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poreinterface.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: poreinterface.C,v 1.7 2011/10/12 19:55:53 bcbrock Exp $ + +/// \file poreinterface.C +/// \brief The PORE hardware interface class + +#include "poreinterface.H" +#include "poremodel.H" + +using namespace vsbe; + + +//////////////////////////////////////////////////////////////////////////// +// PoreInterface +//////////////////////////////////////////////////////////////////////////// + + +int +PoreInterface::restart() +{ + return iv_model->restart(); +} + + +int +PoreInterface::run(const uint64_t i_instructions, uint64_t& o_ran) +{ + return iv_model->run(i_instructions, o_ran); +} + + +ModelError +PoreInterface::stop(const int i_stopCode) +{ + return iv_model->stop(i_stopCode); +} + + +ModelError +PoreInterface::modelError(const ModelError i_modelError) +{ + return iv_model->modelError(i_modelError); +} + + +void +PoreInterface::clearModelError() +{ + return iv_model->clearModelError(); +} + + +ModelError +PoreInterface::clearHardwareErrors() +{ + return iv_model->clearHardwareErrors(); +} + + +ModelError +PoreInterface::registerRead(const PoreRegisterOffset i_offset, + uint64_t& o_data, + const size_t i_size) +{ + return iv_model->registerRead(i_offset, o_data, i_size); +} + + +ModelError +PoreInterface::registerWrite(const PoreRegisterOffset i_offset, + const uint64_t i_data, + const size_t i_size) +{ + return iv_model->registerWrite(i_offset, i_data, i_size); +} + + +ModelError +PoreInterface::registerReadRaw(const PoreRegisterOffset i_offset, + uint64_t& o_data, + const size_t i_size) +{ + return iv_model->registerReadRaw(i_offset, o_data, i_size); +} + + +ModelError +PoreInterface::registerWriteRaw(const PoreRegisterOffset i_offset, + const uint64_t i_data, + const size_t i_size) +{ + return iv_model->registerWriteRaw(i_offset, i_data, i_size); +} + + +void +PoreInterface::enableHookInstruction(bool i_enable) +{ + iv_model->enableHookInstruction(i_enable); +} + + +void +PoreInterface::enableAddressHooks(bool i_enable) +{ + iv_model->enableAddressHooks(i_enable); +} + + +ModelError +PoreInterface::extractState(PoreState& o_state) +{ + return iv_model->extractState(o_state); +} + + +ModelError +PoreInterface::installState(const PoreState& i_state) +{ + return iv_model->installState(i_state); +} + +ModelError +PoreInterface::forceBranch(const PoreAddress& i_address) +{ + return iv_model->forceBranch(i_address); +} + + +ModelError +PoreInterface::setPc(const PoreAddress& i_address) +{ + return iv_model->setPc(i_address); +} + + +ModelError +PoreInterface::setBreakpoint(const PoreAddress& i_address) +{ + return iv_model->setBreakpoint(i_address); +} + + +ModelError +PoreInterface::disableBreakpoint() +{ + return setBreakpoint(PORE_UNBREAKABLE_ADDRESS); +} + + +ModelError +PoreInterface::enableTrap(const bool i_enable) +{ + return iv_model->enableTrap(i_enable); +} + + +int +PoreInterface::getStatus() +{ + return iv_model->getStatus(); +} + + +ModelError +PoreInterface::getModelError() +{ + return iv_model->getModelError(); +} + + +uint64_t +PoreInterface::getInstructions() +{ + return iv_model->getInstructions(); +} + + +int +PoreInterface::getStopCode() +{ + return iv_model->getStopCode(); +} + + +PoreInterface::PoreInterface(PoreIbufId i_id) : + d0(this, PORE_D0), + d1(this, PORE_D1), + a0(this, PORE_A0), + a1(this, PORE_A1), + p0(this, PORE_P0), + p1(this, PORE_P1), + ctr(this, PORE_CTR), + emr(this, PORE_EMR), + etr(this, PORE_ETR), + sprg0(this, PORE_SPRG0), + pc(this, PORE_PC), + ifr(this, PORE_IFR), + cia(this, PORE_CIA), + iv_model(0) +{ + newModel(i_id); +} + + +PoreInterface::~PoreInterface() +{ + delete iv_model; +} + + +void +PoreInterface::newModel(PoreIbufId i_id) +{ + delete iv_model; + iv_model = PoreModel::create(i_id, this); + iv_ibufId = i_id; +} + + + diff --git a/src/usr/pore/poreve/model/poreinterface.H b/src/usr/pore/poreve/model/poreinterface.H new file mode 100644 index 000000000..9c8b44974 --- /dev/null +++ b/src/usr/pore/poreve/model/poreinterface.H @@ -0,0 +1,346 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poreinterface.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_POREINTERFACE_H +#define __VSBE_POREINTERFACE_H + +// $Id: poreinterface.H,v 1.10 2011/11/07 23:39:33 bcbrock Exp $ + +/// \file poreinterface.H +/// \brief The PORE hardware interface class + +#include <stddef.h> +#include <stdint.h> + +#include "bebits.H" +#include "modelerror.H" +#include "poreaddress.H" +#include "transaction.H" +#include "poreconstants.H" +#include "poreregister.H" +#include "porestate.H" + +// This is required for debugging prints only +#if 1 +#include <stdio.h> +#endif + +namespace vsbe { + + class PoreAddress; + class PoreInterface; + class PoreModel; + class PoreState; +} + + +//////////////////////////////////////////////////////////////////////////// +// PoreInterface +//////////////////////////////////////////////////////////////////////////// + + +/// Abstract base class for the PORE hardware engine virtual environment +/// +/// PoreInterface is an abstract class that specifies the interfaces that a +/// virtual environment must implement on behalf of the abstract PoreModel, +/// and provides the control interfaces into the PoreModel. Applications will +/// never operate on the PoreModel directly, but instead will operate +/// exclusively on classes derived from PoreInterface. + +class +vsbe::PoreInterface { + +public: + + ///////////////////////// Control Interface ///////////////////////// + + /// See PoreModel::restart() + virtual int + restart(); + + /// See PoreModel::run() + virtual int + run(const uint64_t i_instructions, uint64_t& o_ran); + + /// See PoreModel::stop() + virtual ModelError + stop(const int i_stopCode); + + /// See PoreModel::modelError() + virtual ModelError + modelError(const ModelError i_modelError); + + /// See PoreModel::clearModelError() + virtual void + clearModelError(); + + /// See PoreModel::clearHardwareErrors() + virtual ModelError + clearHardwareErrors(); + + /// See PoreModel::registerRead() + virtual ModelError + registerRead(const PoreRegisterOffset i_offset, + uint64_t& o_data, + const size_t i_size = 8); + + /// See PoreModel::registerWrite() + virtual ModelError + registerWrite(const PoreRegisterOffset i_offset, + const uint64_t i_data, + const size_t i_size = 8); + + /// See PoreModel::registerReadRaw() + virtual ModelError + registerReadRaw(const PoreRegisterOffset i_offset, + uint64_t& o_data, + const size_t i_size = 8); + + /// See PoreModel::registerWriteRaw() + virtual ModelError + registerWriteRaw(const PoreRegisterOffset i_offset, + const uint64_t i_data, + const size_t i_size = 8); + + /// See PoreModel::enableHookInstruction() + virtual void + enableHookInstruction(bool i_enable); + + /// See PoreModel::enableAddressHooks() + virtual void + enableAddressHooks(bool i_enable); + + /// See PoreModel::extractState() + virtual ModelError + extractState(PoreState& o_state); + + /// See PoreModel::installState() + virtual ModelError + installState(const PoreState& i_state); + + /// See PoreModel::forceBranch() + virtual ModelError + forceBranch(const PoreAddress& i_address); + + /// See PoreModel::setPc() + virtual ModelError + setPc(const PoreAddress& I_pc); + + /// See PoreModel::setBreakpoint() + virtual ModelError + setBreakpoint(const PoreAddress& i_address); + + /// Effectively disable the PORE address breakpoint + /// + /// \retval 0 Success + /// + /// \retval non-0 Any ModelError returned by underlying hardware + /// operations. + virtual ModelError + disableBreakpoint(); + + /// See PoreModel::enableTrap() + virtual ModelError + enableTrap(const bool i_enable); + + /// See PoreModel::getStatus() + virtual int + getStatus(); + + /// See PoreModel::getModelError() + virtual ModelError + getModelError(); + + /// See PoreModel::getInstructions() + virtual uint64_t + getInstructions(); + + /// See PoreModel::getStopCode() + virtual int + getStopCode(); + + + //////////////////// Abstract Interface ///////////////////////// + + /// See PoreModel::pibMaster() + virtual void + pibMaster(PibTransaction& io_transaction) = 0; + + /// See PoreModel::ociMaster() + virtual void + ociMaster(OciTransaction& io_transaction) = 0; + + /// See PoreModel::wait() + virtual void + wait(const uint32_t i_count) = 0; + + /// See PoreModel::hookInstruction() + virtual void + hookInstruction(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter) = 0; + + /// See PoreModel::hookRead() + virtual void + hookRead(const PoreAddress& i_address) = 0; + + /// See PoreModel::hookWrite() + virtual void + hookWrite(const PoreAddress& i_address) = 0; + + /// See PoreModel::hookFetch() + virtual void + hookFetch(const PoreAddress& i_address) = 0; + + /// See PoreModel::errorIntr() + virtual void + errorIntr(void) = 0; + + /// See PoreModel::fatalErrorIntr() + virtual void + fatalErrorIntr(void) = 0; + + + ////////////////////////////// Creators ////////////////////////////// + + /// Create the PoreInterface + /// + /// \param[in] i_id The IBUF ID (PORE engine type) of the PORE model to + /// create. + PoreInterface(PoreIbufId i_id); + + virtual ~PoreInterface(); + + + ///////////////////// Register Interface //////////////////////////// + + /// \defgroup pore_register_access PORE Register Access + /// + /// These data members of PoreInterface provide easy access to + /// programmer-visible and abstract registers for use by procedures and + /// hooks. Unless otherwise indicated in the brief comment the register is + /// both readable and writable. Data registers, address registers, the + /// counter register and some control register values are right justfied, + /// and only the indicated number of bits are writable. Other hardware + /// control registers have unique layouts. See the detailed comments for + /// each register and the comments for the PoreRegister class for more + /// information. + /// + /// @{ + + /// 64-bit data register D0 + PoreDataBuffer d0; + /// 64-bit data register D1 + PoreDataBuffer d1; + /// 32-bit address register A0 + PoreRegisterWritable a0; + /// 32-bit address register A1 + PoreRegisterWritable a1; + /// 7-bit pervasive chiplet register P0 + PoreRegisterWritable p0; + /// 7-bit pervasive chiplet register P1 + PoreRegisterWritable p1; + /// 24-bit counter CTR + PoreRegisterWritable ctr; + /// 21-bit error mask register + /// + /// The EMR is implemented as a 64-bit registers, however only the + /// high-order 21 bits contain information. + PoreRegisterWritable emr; + /// 64-bit EXE-Trigger Register - Partially writable + /// + /// The low-order 32 bits of the EXE-Trigger register are writable from a + /// PORE program. The register is fully writable externally, however this + /// has the major side effect of kicking off a new PORE program if the + /// high-order 32-bits are written. The write implementation here only + /// writes the low-order 32 bits; to write the entire register call + /// registerWrite() directly. + PoreRegisterWritable etr; + /// 32-bit Special-Purpose General Register 0 + PoreRegisterWritable sprg0; + /// PC - Read-only + /// + /// The 48-bit PC is read-only using the PoreRegister interface. Setting + /// the PC requires using the setPc() procedure on the PoreInterface. + /// It's likely that a hook programmer should actually be using the + /// abstract \c CIA register. + PoreRegister pc; + /// ID-Flags Register - Partial read-only + /// + /// Note that from inside a PORE program this register is read-only. + /// Externally the ALU flags fields of the register are writable, so this + /// behavior is supported. The writable portion (the flags) are bits + /// 48:55. + PoreRegisterWritable ifr; + /// Current instruction address - Read-Only + /// + /// This is an abstract register. If the PORE engine is running or stopped + /// at a breakpoint or trap then reading the CIA returns the address of + /// the currently executing instruction. If the PORE engine is stopped in + /// a wait state then reading the CIA returns the address of the last + /// instruction executed. + /// + /// This register is read-only. If the intention is to force a branch + /// then the forceBranch() or setPc() methods of the PoreInterface should + /// be used. + PoreRegister cia; + + /// @} + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// Create a new underlying model + /// + /// \param[in] i_id The IBUF ID (PORE engine type) of the PORE model to + /// create. + /// + /// This method creates and installs an instance of the PoreModel with a + /// specific PoreIbufId. This method is provided separately from the + /// constructor to support use of the PoreInterface in the Simics + /// environment. In Simics, the type of the engine (GPE0, SLW, etc.) is + /// not known until after model construction, but before actual simulation + /// begins. In Simics models are created with a default type, then later + /// recreated using newModel() once the actual type is known. + virtual void + newModel(PoreIbufId i_id); + + /// The IBUF ID (engine type) of the PORE being modeled + PoreIbufId iv_ibufId; + +private: + + /// The associated PoreModel + /// + /// This object is created and destroyed by the PoreInterface. + PoreModel* iv_model; + + ///////////////////////////// Safety ////////////////////////////////// + +private: + PoreInterface(const PoreInterface& rhs); + PoreInterface& operator=(const PoreInterface& rhs); +}; + + +#endif // __VSBE_POREINTERFACE_H diff --git a/src/usr/pore/poreve/model/poremodel.C b/src/usr/pore/poreve/model/poremodel.C new file mode 100644 index 000000000..dfa8cbbbc --- /dev/null +++ b/src/usr/pore/poreve/model/poremodel.C @@ -0,0 +1,439 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poremodel.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: poremodel.C,v 1.19 2011/11/11 00:50:35 bcbrock Exp $ + +/// \file poremodel.C +/// \brief The PORE hardware engine model and interface to the virtual +/// environment. + +#include "poremodel.H" + +using namespace vsbe; + + +//////////////////////////////////////////////////////////////////////////// +// PoreModel +//////////////////////////////////////////////////////////////////////////// + +/////////////// Common Creation/Control Interface //////////////////// + +int +PoreModel::restart() +{ + flushReset(); + iv_modelError = ME_SUCCESS; + iv_instructions = 0; + iv_stopCode = 0; + return getStatus(); +} + + +// run() refuses to do anything if the status shows a model error or an error +// halt. Otherwise the status is used to determine how to restart the machine +// if it is currently stopped. Then the model is stepped until the number of +// instructions has been executed or the status is non-0. If a debug stop was +// requested this condition is recorded so that PORE_STATUS_DEBUG_STOP can be +// added back to the status at the end. + +// Note: The system model or hooks may call modelError() to update the private +// iv_modelError field to record errors that are not otherwise visible to the +// PORE hardware model. This will cause the PORE_STATUS_MODEL_ERROR to be set +// and terminate the run loop. However note that the instruction will +// complete on the PORE. + +// Note: run(0, ran) simply has the effect of making a stopped machine +// runnable. + +// Note: This method will need to be overridden/reimplemented in a derived +// class that controls actual PORE hardware or a simulation model. + +int +PoreModel::run(const uint64_t i_instructions, uint64_t& o_ran) +{ + uint64_t n = i_instructions; + uint64_t control; + ModelError me = ME_SUCCESS; + bool stepped; + bool writeControl = false; + int iv_status; + + do { + + o_ran = 0; + iv_stopCode = 0; + iv_status = getStatus(); + + if (iv_status & (PORE_STATUS_ERROR_HALT | PORE_STATUS_MODEL_ERROR)) { + break; + } + + me = registerRead(PORE_CONTROL, control); + if (me != 0) break; + + if (iv_status & PORE_STATUS_HARDWARE_STOP) { + control &= ~BE64_BIT(0); + writeControl = true; + } + if (iv_status & (PORE_STATUS_BREAKPOINT | PORE_STATUS_TRAP)) { + control |= BE64_BIT(1); + writeControl = true; + } + + if (writeControl) { + me = registerWrite(PORE_CONTROL, control); + } + if (me != 0) break; + + while (n--) { + me = step(stepped); + if ((me != 0) || !stepped) { + break; + } + o_ran++; + iv_instructions++; + if (getModelError() != 0) { + break; + } + } + + } while (0); + + if (me != 0) { + modelError(me); + } + + return getStatus(); +} + + +ModelError +PoreModel::stop(const int i_stopCode) +{ + uint64_t control; + ModelError me; + + do { + me = iv_modelError; + if (me) break; + me = registerRead(PORE_CONTROL, control); + if (me) break; + me = registerWrite(PORE_CONTROL, control | BE64_BIT(0)); + if (me) break; + if (i_stopCode != 0) { + iv_stopCode = i_stopCode; + } + } while (0); + + return me; +} + +ModelError +PoreModel::modelError(const ModelError i_modelError) +{ + if (i_modelError != 0) { + iv_modelError = i_modelError; + } + return i_modelError; +} + + +void +PoreModel::clearModelError() +{ + iv_modelError = ME_SUCCESS; +} + + +ModelError +PoreModel::clearHardwareErrors() +{ + ModelError me; + + me = registerWrite(PORE_DBG0, 0); + if (me == 0) { + me = registerWrite(PORE_DBG1, 0); + } + return me; +} + + +// Set the PC as specified, leaving the engine in the stopped state. By +// hardware specification, if the control register is written with the set_pc +// bit set, then the only action is to update the PC, which comes in as the +// low-order 48 bits of the CONTROL register. + +ModelError +PoreModel::setPc(const PoreAddress& i_pc) +{ + do { + + if (iv_modelError != 0) break; + stop(STOP_CODE_SET_PC); + if (iv_modelError != 0) break; + + iv_modelError = + registerWrite(PORE_CONTROL, (uint64_t)i_pc | BE64_BIT(3)); + + } while (0); + return iv_modelError; +} + + +// The breakpoint address occupies the lower 48 bits of the control register. + +ModelError +PoreModel::setBreakpoint(const PoreAddress& i_address) +{ + uint64_t control, address; + ModelError me; + + do { + + me = registerRead(PORE_CONTROL, control); + if (me != 0) break; + + address = i_address; + control &= ~BE64_MASK(16, 63); + control |= address; + + me = registerWrite(PORE_CONTROL, control); + if (me != 0) break; + + } while (0); + return me; +} + + +// Bit 11 of the PORE CONTROL register is the TRAP enable bit. + +ModelError +PoreModel::enableTrap(const bool i_enable) +{ + ModelError me; + uint64_t control; + + me = registerRead(PORE_CONTROL, control); + if (me == 0) { + if (i_enable) { + control |= BE64_BIT(11); + } else { + control &= ~BE64_BIT(11); + } + me = registerWrite(PORE_CONTROL, control); + } + return me; +} + + +// Abstract status bits are set as documented. If a ModelError is present the +// state is assumed to be corrupted so PORE_STATUS_MODEL_ERROR is the only +// status returned. + +int +PoreModel::getStatus() +{ + + ModelError me; + uint64_t control, status, ibuf01, dbg1; + int finalStatus; + const unsigned PORE_OPCODE_WAIT = 1; + const unsigned PORE_OPCODE_TRAP = 2; + const unsigned PORE_STATE_ABR = 0xb; // PORE HW State machine state + + do { + + finalStatus = 0; + me = iv_modelError; + if (me != 0) break; + + me = registerRead(PORE_CONTROL, control); + if (me != 0) break; + me = registerRead(PORE_STATUS, status); + if (me != 0) break; + me = registerRead(PORE_IBUF_01, ibuf01); + if (me != 0) break; + me = registerRead(PORE_DBG1, dbg1); + if (me != 0) break; + + // Status associated with the hardware stop condition + + if (control & BE64_BIT(0)) { + + finalStatus |= PORE_STATUS_HARDWARE_STOP; + + if ((BE64_GET_FIELD(ibuf01, 0, 6) == PORE_OPCODE_WAIT) && + (BE64_GET_FIELD(ibuf01, 8, 31) == 0)) { + finalStatus |= PORE_STATUS_HALTED; + } + + if (dbg1 & BE64_BIT(63)) { + finalStatus |= PORE_STATUS_ERROR_HALT; + } + } + + // Status associated with the engine being in the ABR (Address + // BReakpoint) state. We need to disambiguate TRAP, BREAKPOINT, and + // TRAP+BREAKPOINT. This is needlesssly complicated due to lack of + // direct hardware status. + + if (BE64_GET_FIELD(status, 3, 6) == PORE_STATE_ABR) { + + if ((BE64_GET_FIELD(ibuf01, 0, 6) == PORE_OPCODE_TRAP) && + BE64_GET_FIELD(control, 11, 11)) { + finalStatus |= PORE_STATUS_TRAP; + } + + if (BE64_GET_FIELD(control, 16, 63) == + BE64_GET_FIELD(status, 16, 63)) { + finalStatus |= PORE_STATUS_BREAKPOINT; + } else { + if (!(finalStatus & PORE_STATUS_TRAP)) { + finalStatus |= PORE_STATUS_BREAKPOINT; + } + } + } + } while (0); + + if (iv_stopCode != 0) { + finalStatus |= PORE_STATUS_DEBUG_STOP; + } + + if (me != 0) { + modelError(me); + finalStatus = PORE_STATUS_MODEL_ERROR; + } + + return finalStatus; +} + + +ModelError +PoreModel::getModelError() +{ + return iv_modelError; +} + + +uint64_t +PoreModel::getInstructions() +{ + return iv_instructions; +} + + +int +PoreModel::getStopCode() +{ + return iv_stopCode; +} + + +//////////////////// PoreInterface Methods ///////////////////////// + +// The interface methods are responsible for ensuring that any errors are +// captured in the iv_modelError member of the PoreModel. + +void +PoreModel::pibMaster(PibTransaction& transaction) +{ + iv_interface->pibMaster(transaction); +} + + +void +PoreModel::ociMaster(OciTransaction& transaction) +{ + iv_interface->ociMaster(transaction); +} + + +void +PoreModel::wait(const uint32_t i_count) +{ + iv_interface->wait(i_count); +} + + +void +PoreModel::hookInstruction(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter) +{ + iv_interface->hookInstruction(i_address, i_hook, i_parameter); +} + + +void +PoreModel::hookRead(const PoreAddress& i_address) +{ + iv_interface->hookRead(i_address); +} + + +void +PoreModel::hookWrite(const PoreAddress& i_address) +{ + iv_interface->hookWrite(i_address); +} + + +void +PoreModel::hookFetch(const PoreAddress& i_address) +{ + iv_interface->hookFetch(i_address); +} + + +void +PoreModel::errorIntr(void) +{ + iv_interface->errorIntr(); +} + + +void +PoreModel::fatalErrorIntr(void) +{ + iv_interface->fatalErrorIntr(); +} + + +////////////////////////////// Creators ////////////////////////////// + +PoreModel::PoreModel(PoreIbufId i_id, PoreInterface *i_interface) : + iv_ibufId(i_id), + iv_modelError(ME_PORE_UNINITIALIZED), + iv_instructions(0), + iv_stopCode(0), + iv_interface(i_interface) +{ +} + + +PoreModel::~PoreModel() +{ +} + + + + diff --git a/src/usr/pore/poreve/model/poremodel.H b/src/usr/pore/poreve/model/poremodel.H new file mode 100644 index 000000000..be2446c1f --- /dev/null +++ b/src/usr/pore/poreve/model/poremodel.H @@ -0,0 +1,733 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poremodel.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_POREMODEL_H +#define __VSBE_POREMODEL_H + +// $Id: poremodel.H,v 1.23 2011/11/11 00:55:26 bcbrock Exp $ + +/// \file poremodel.H +/// \brief The PORE hardware engine model + +#include <stddef.h> +#include <stdint.h> + +#include "modelerror.H" +#include "poreinterface.H" +#include "transaction.H" + +// This is required for debugging prints only +#if 1 +#include <stdio.h> +#endif + +namespace vsbe { + + class PoreAddress; + class PoreInterface; + class PoreModel; +}; + + +//////////////////////////////////////////////////////////////////////////// +// PoreModel +//////////////////////////////////////////////////////////////////////////// + + +/// Abstract base class for the PORE hardware engine model +/// +/// PoreModel is an abstract class that specifies the interfaces that a PORE +/// model will use to communicate to the virtual environment, and that the +/// environment will use to control the model. This class is designed to +/// allow different implementations of PoreModel to be easily interchanged; +/// see the create() method. +/// +/// The PoreModel is completely abstracted from the environment, however. The +/// PoreModel communicates with the environment through a subclass of the +/// PoreInterface class. This PoreInterface arranges for the implementation +/// of the externalized PoreModel operations. + +class +vsbe::PoreModel { + +public: + + /////////////// Common Creation/Control Interface //////////////////// + + /// Create a new instance of a model derived from PoreModel + /// + /// \param[in] i_id The IBUF ID (PORE engine type) of the model to + /// create. + /// + /// \param[in] i_interface A pointer back to the PoreInterface that + /// creates and owns this object and implements several of the PoreModel + /// methods. This parameter must be provided to the base class + /// constructor. + /// + /// To facilitate swapping different PORE hardware models in and out + /// transparently, this abstract base class declares a static function + /// that creates an instance of the model to use. Whoever provides the + /// implementation of the derived class must define this method to produce + /// an instance of the derived class the conforms to a PORE hardware + /// engine of the parameterized type. + static PoreModel* + create(PoreIbufId i_id, PoreInterface *i_interface); + + /// Restart the PORE engine to its scan-flush state + /// + /// For PORE-SBE, the engine is reset to begin execution from the OTPROM + /// at the proper location, with all configuration registers (e.g., the + /// I2C configuration) flushed to the correct state to begin an IPL. + /// + /// For the other engines, they are reset as documented and will not run + /// (correctly) until the BASE address and EXE trigger registers are + /// written. As a side effect the status of the PoreModel is computed and + /// returned. The PoreModel is defined to be in the restart (scan-flush) + /// state at the end of constructing the model. + /// + /// \retval status PORE-SBE returns 0 (running); The other engines return + /// PORE_STATUS_HARDWARE_STOP. + /// + /// \bug Check to make sure this is true for the SBE. + virtual int + restart(); + + /// Step the model by (at most) N instructions + /// + /// \param[in] i_instructions The (maximum) number of instructions to + /// execute. Use the constant RUN_UNLIMITED to run (effectively) forever. + /// + /// \param[out] o_ran The number of instructions that actually ran. This + /// may be 0 if \a i_instructions is 0, or if the PoreModel was in an + /// unrunnable state when run() was invoked. To find the total number of + /// instructions that have run since model construction (or the last + /// restart()), use the method getInstructions(). + /// + /// When this method is invoked it is assumed that the caller wants the + /// model to run, regardless of its current state. The run() method first + /// attempts to make a stopped machine runnable, and then attempts to + /// execute \a i_instructions and returns the final status and the number + /// of instructions actually completed by this invocation. + /// + /// - If the engine shows an error status before the execution of run() + /// then no instructions will be executed and \a o_ran will be returned as + /// 0. To clear the error status use clearModelError() or + /// clearHardwareErrors() to continue with restart()-ing the machine. + /// + /// - If the engine shows a stopped or error status at any time after the + /// execution of the first instruction but before the execution of the + /// final requested instruction, then run() returns at that point and \a + /// o_ran indicates how many instructions were actually executed. + /// + /// - Calling run() with \a i_instructions == 0 simply makes a stopped + /// machine runnable (if possible). + /// + /// Note that executing a single instruction may entail many bus + /// transactions, especially in the case of the SCAND command which is + /// treated as single instructions. WAIT is also considered a single + /// instruction regardless of the wait count. + /// + /// \retval 0 The PORE remains runnable. In this case \a o_ran == \a + /// i_instructions. + /// + /// \retval status An OR-combination of 1 or more PORE_STATUS_* flags + /// indicating the final state of the PORE. + virtual int + run(const uint64_t i_instructions, uint64_t& o_ran); + + /// Signal a debug-stop + /// + /// \param[in] i_stopCode A user-defined integer code to categorize the + /// reason for the stop. Use \a i_stopCode == 0 to simply stop the + /// machine. Use a non-zero stop code to also cause + /// PORE_STATUS_DEBUG_STOP to be set in the final status. + /// + /// This API is provided for control programs or debugging code + /// (e.g. hooks) to force the simulation to stop during the execution of + /// the run() method, or to insure that the PORE engine is stopped and in + /// the WAIT state prior to updating or examining the state. The effect of + /// stop() is to terminate any ongoing run() method immediately by writing + /// the PORE \c stop_start bit with a 1. Calling the stop() method with a + /// non-zero \a i_stopCode leaves the PORE abstract status with the + /// PORE_STATUS_DEBUG_STOP bit set, and the \a i_stopCode provided can be + /// later recovered with the getStopCode() method. Calling stop() multiple + /// times with non-zero \a i_stopCode only records the last + /// instance. Absent any error conditions a subsequent call of run() will + /// restart the simulation. + /// + /// \retval me Returns 0 for success, otherwise any ModelError + /// encountered during processing of the method. If the engine has + /// ModelError status prior to the call the method returns that status + /// immediately (does not perform the stop() operation). + virtual ModelError + stop(const int i_stopCode); + + /// Signal a modeling error + /// + /// \param[in] i_modelError A model-defined integer code to categorize the + /// type of modeling error. If the model status includes + /// PORE_STATUS_MODEL_ERROR then the getModelError() method returns this + /// code, otherwise 0. If \a i_modelError is 0 then this method has no + /// effect. If modelError() is called multiple times with non-0 \a + /// i_modelError during the execution of a single instruction then only + /// the last non-0 value is recorded. + /// + /// This API is provided as a way for the system-level model or + /// application debugging code (e.g. hooks) to force the simulation to + /// halt with an error during the execution of the run() method. The + /// effect of the modelError() with a non-0 \a i_modelError parameter is + /// to terminate a run() immediately and leave the PORE abstract status + /// with the PORE_STATUS_MODEL_ERROR bit set. This is a fatal error; The + /// model will not run instructions again until restart()-ed or the error + /// is explicitly cleared with clearModelError(). + /// + /// \retval i_modelError This routine returns its input \a i_modelError. + virtual ModelError + modelError(const ModelError i_modelError); + + /// Clear any ModelError from the model + /// + /// Note that the run() method will stop immediately and not continue a + /// model that has a non-0 ModelError status. This method allows the user + /// to clear the ModelError status and continue execution. + virtual void + clearModelError(); + + /// Clear PORE hardware error status + /// + /// PORE hardware error status is stored in the PORE DBG0 and DBG1 + /// registers. This procedure clears both of those registers to allow a + /// simulation (or run) to continue in the event of a hardware error. + /// Note that is a second hardware error occurs while the debug registers + /// are "locked" (i.e., holding an error) the PORE hardware engine will + /// halt. + /// + /// \retval me Will be non-0 if an error occurs during the procedure. + virtual ModelError + clearHardwareErrors(); + + /// Set the program counter + /// + /// \param i_pc The new program counter + /// + /// This method encapsulates the hardware register operations required to + /// force-set the PORE program counter. This method first calls stop() to + /// halt the PORE engine. If the engine is at a trap or breakpoint the + /// stop() will take the engine back to the WAIT state, otherwise the new + /// PC can not be guaranteed to take effect. The PC is then updated. The + /// engine is \e not restarted (if it had been running); At the end of + /// this method the hardware will always be in the stopped state. + /// + /// \retval me Returns 0 for success, otherwise any ModelError + /// encountered during processing of the method. If the engine has + /// ModelError status prior to the call the method returns that status + /// immediately (does not perform the setPc() operation). + virtual ModelError + setPc(const PoreAddress& i_pc); + + /// Set the PORE address breakpoint + /// + /// \param[in] i_address The breakpoint address + /// + /// The PORE supports a single address breakpoint, and calling this API + /// sets the breakpoint. If the PC ever matches the breakpoint address + /// then the PORE engine stops after executing an instruction at that + /// address. + /// + /// The PORE address breakpoint can not be explicitly disabled, however + /// the constant vsbe::PORE_UNBREAKABLE_ADDRESS contains a phony address + /// that can be installed as the breakpoint address to effectively disable + /// the address breakpopint. + /// + /// \retval me Returns 0 for success, otherwise any ModelError + /// encountered during processing of the method. + virtual ModelError + setBreakpoint(const PoreAddress& i_address); + + /// Enable or disable the TRAP instruction + /// + /// \param[in] i_enable Controls whether TRAP is enabled or disabled. + /// + /// By default (or when TRAP is disabled) the TRAP instruction is treated + /// by the PORE hardware as a NOP. If enabled the TRAP instruction causes + /// PORE execution to break in the Address-Breakpoint state, similar to an + /// address breakpoint. The run() method automatically restarts execution + /// if the PORE engine is stopped in this state. + /// + /// \retval me Will be returned non-0 if any errors are encountered + /// executing the procedure. + virtual ModelError + enableTrap(const bool i_enable); + + /// Return the current abstract status + /// + /// \retval status The current PoreModel abstract status as an + /// OR-combination of PORE_STATUS_* bits. See \ref pore_status. + virtual int + getStatus(); + + /// Return the current PoreModel error code + /// + /// \retval error If the PORE status includes the bit + /// PORE_STATUS_MODEL_ERROR then getModelError() returns the ModelError + /// responsible, otherwise 0. + virtual ModelError + getModelError(); + + /// Return the number of executed instructions + /// + /// \retval instrctions The total number of instructions executed since + /// the model was created or restart()-ed. + virtual uint64_t + getInstructions(); + + /// Return the code supplied with the last stop() method. + /// + /// \retval code If the PORE status includes the bit + /// PORE_STATUS_DEBUG_STOP, then getStopCode() returns the parameter + /// supplied with the last stop() call that caused the PORE model to stop. + virtual int + getStopCode(); + + + ///////////////////////// Abstract Interface ///////////////////////// + + /// Reset the PORE engine to its scan-flush state + /// + /// For PORE-SBE, the engine is reset to execute the first instruction of + /// OTPROM. For the other engines, they are reset as documented and will + /// not run (correctly) until the BASE address and EXE trigger registers + /// are written. The PoreModel is defined to be in the reset + /// (scan-flush) state at the end of constructing the model. + /// + /// \retval me Return values other than 0 indicate some type of error in + /// the reset as defined by the ModelError enumeration. + virtual ModelError + flushReset() = 0; + + /// Step the PORE engine one instruction + /// + /// \param[out] o_stepped This parameter is set to true or false depending + /// on whether the model successfully completed a step. + /// + /// Step the model 1 instruction, unless the model is presently in an + /// unrecoverable error state, or the step itself causes an unrecoverable + /// error. + /// + /// Executing a single instruction may entail many bus transactions, + /// especially in the case of the SCAND command which is treated as a + /// single instruction. WAIT is also considered a single instruction + /// regardless of the wait count. Finally, the PORE hardware may also be + /// in a state where it can not execute an instruction without an external + /// control action. + /// + /// \retval me Return values other than 0 indicate some type of error in + /// the step as defined by the ModelError enumeration. + virtual ModelError + step(bool& o_stepped) = 0; + + /// Read a user-visible control or data register \e with side effects + /// + /// \param[in] i_offset The register offset (see below). + /// + /// \param[out] o_data The returned data. For 4-byte reads the data is + /// right justified. + /// + /// \param[in] i_size The size in bytes (see below). + /// + /// In general the PORE supports both 4- and 8-byte access to the control + /// and data register space. Registers are specified as an enumerated + /// offset into the space. Other than 8-byte reads return the data right + /// justfied in the 64-bit returned value. 8-byte reads are only allowed + /// for offsets that are 8-byte aligned; 4-byte reads are allowed for any + /// 4-byte aligned offset. + /// + /// \retval me Return values other than 0 indicate some type of error in + /// the access as defined by the ModelError enumeration. + virtual ModelError + registerRead(const PoreRegisterOffset i_offset, + uint64_t& o_data, + const size_t i_size = 8) = 0; + + /// Write a user-visible control or data register \e with side effects + /// + /// \param[in] i_offset The register offset (see below). + /// + /// \param[in] i_data The write data. For 4-byte writes the data is + /// right justified. + /// + /// \param[in] i_size The size in bytes (see below). + /// + /// In general the PORE supports both 4- and 8-byte access to the control + /// and data register space. Registers are specified as an enumerated + /// offset into the space. 4-byte writes expect the data right justfied in + /// the 64-bit input value. 8-byte writes are only allowed for offsets + /// that are 8-byte aligned; 4-byte writes are allowed for any 4-byte + /// aligned offset. + /// + /// \retval me Return values other than 0 indicate some type of error in + /// the access as defined by the ModelError enumeration. + virtual ModelError + registerWrite(const PoreRegisterOffset i_offset, + const uint64_t i_data, + const size_t i_size = 8) = 0; + + /// Read a user-visible control or data register \e without side effects + /// + /// \param[in] i_offset The register offset (see below). + /// + /// \param[out] o_data The returned data. For 4-byte reads the data is + /// right justified. + /// + /// \param[in] i_size The size in bytes (see below). + /// + /// In general the PORE supports both 4- and 8-byte access to the control + /// and data register space. Registers are specified as an enumerated + /// offset into the space. Other than 8-byte reads return the data right + /// justfied in the 64-bit returned value. 8-byte reads are only allowed + /// for offsets that are 8-byte aligned; 4-byte reads are allowed for any + /// 4-byte aligned offset. + /// + /// \retval me Return values other than 0 indicate some type of error in + /// the access as defined by the ModelError enumeration. + virtual ModelError + registerReadRaw(const PoreRegisterOffset i_offset, + uint64_t& o_data, + const size_t i_size = 8) = 0; + + /// Write a user-visible control or data register \e without side effects + /// + /// \param[in] i_offset The register offset (see below). + /// + /// \param[in] i_data The write data. For 4-byte writes the data is + /// right justified. + /// + /// \param[in] i_size The size in bytes (see below). + /// + /// In general the PORE supports both 4- and 8-byte access to the control + /// and data register space. Registers are specified as an enumerated + /// offset into the space. 4-byte writes expect the data right justfied in + /// the 64-bit input value. 8-byte writes are only allowed for offsets + /// that are 8-byte aligned; 4-byte writes are allowed for any 4-byte + /// aligned offset. + /// + /// \retval me Return values other than 0 indicate some type of error in + /// the access as defined by the ModelError enumeration. + virtual ModelError + registerWriteRaw(const PoreRegisterOffset i_offset, + const uint64_t i_data, + const size_t i_size = 8) = 0; + + /// Enable or disable the HOOKI instruction + /// + /// \param[in] i_enable Either enable or disable the HOOKI instruction. + /// + /// The virtual HOOK instruction is disabled by default. This API enables + /// or disables the PoreModel to call out using the PoreModel::hook() + /// interface when it encounters a HOOKI instruction. + /// + /// \retval me Return values other than 0 indicate some type of error in + /// the method as defined by the ModelError enumeration. + virtual ModelError + enableHookInstruction(bool i_enable) = 0; + + /// Enable or disable address-based hooks + /// + /// \param[in] i_enable Either enable or disable address-based hooks. + /// + /// Address-based hooks are disabled by default. This API enables or + /// disables the PoreModel to call out using the readHook(), writeHook() + /// and fetchHook() interfaces whenever the model is about to read, write + /// or fetch respectively. + /// + /// \retval me Return values other than 0 indicate some type of error in + /// the method as defined by the ModelError enumeration. + virtual ModelError + enableAddressHooks(bool i_enable) = 0; + + /// Extract the PORE state for checkpointing + /// + /// \param[out] o_state A reference to a PoreState object to receive the + /// checkpointed state. + /// + /// This method checkpoints the state of a PORE engine into an abstract + /// PoreState object, in a way that allows the state to be later restored + /// with installState(). The state that is saved is only the PORE engine + /// state, and does not include any other state of the PORE virtual + /// environment. + /// + /// This method must be implemented in the derived class that implements + /// other virtual methods of the PoreModel. A simulation or software + /// model should be able to precisely recover to an arbitrary + /// state. Physical hardware may have limited abilities to do this due to + /// register side effects, read-only state etc., and may return an error + /// code if PORE engine is in a state that can't be restored. + /// + /// Note: The PORE engine must be in the hardware-stop state + /// before checkpointing in order to guarantee that the state can be + /// precisely saved and restored under all conditions. + /// + /// \retval me Normally 0 for success, but may be set by a dervied model + /// that is unable to satisfactorily extract the state for some reason. + virtual ModelError + extractState(PoreState& o_state) = 0; + + /// Install a checkpointed state + /// + /// \param[in] i_state A PoreState object containing the entire visible + /// register state of the PORE. + /// + /// This method restores a PORE engine state checkpointed with + /// extractState(). The state that is restored is only the PORE engine + /// state. The PoreState object does not include any other state of the + /// PORE virtual environment. + /// + /// This method must be implemented in the derived class that implements + /// other virtual methods of the PoreModel. A simulation or software + /// model should be able to precisely recover to an arbitrary + /// state. Physical hardware may have limited abilities to do this due to + /// register side effects, read-only state etc., and may return an error + /// code if unable to restore the state from the PoreState object. + /// + /// \retval me Normally 0 for success, but may be set by a dervied model + /// that is unable to satisfactorily restore a state for some reason. + virtual ModelError + installState(const PoreState& i_state) = 0; + + /// Force the PORE engine to branch (from a hook context) + /// + /// \param[in] i_address The address to branch to. + /// + /// This method is for use only by hooks, and only by address-based fetch + /// hooks and hooks attached to the HOOKI instruction. This method forces + /// the PORE engine to branch to an address specified in the \a i_address + /// parameter. This method is only defined on software simulated models, + /// and will not work on hardware models (including VHDL PORE models). To + /// change the PC from a stopped state use the setPc() method which will + /// work on all underlying models. + /// + /// The behavior varies based on the hook context: + /// + /// - For address-based fetch hooks, the conceptual model is that the hook + /// executes before the instruction that follows the hook. Practically + /// speaking, the hook may actually be invoked at the beginning of + /// instruction fetch. The derived PoreModel will ensure that any fetch + /// and execution of the instruction following the hook is cleanly + /// abandoned, and will instead go to fetch and execute the instruction at + /// \a i_address, including processing any fetch hooks on the new + /// target. The hook subroutine that invokes forceBranch() will be fully + /// executed before the forced branch. + /// + /// - For HOOKI instruction hooks the, the behavior is as if the HOOKI + /// instruction were an immediate branch to the absolute target. Again, + /// the hook subroutine that invokes forceBranch() will be fully executed + /// before the forced branch. + /// + /// If forceBranch() is called from any other context, the PoreModel will + /// return the ModelError ME_ILLEGAL_FORCED_BRANCH. Even so, this API is + /// fraught with potential problems, e.g. ping-pong livelocks between + /// fetch hooks. forceBranch() should only be used for simple, + /// straightforward control flow modifications. + /// + /// \retval Either 0 for SUCCESS, ME_ILLEGAL_FORCED_BRANCH or any other + /// non-0 ModelError that might be signalled during execution of the + /// method. + virtual ModelError + forceBranch(const PoreAddress& i_address) = 0; + + + //////////////////// PoreInterface Methods ///////////////////////// + +protected: + + /// Master a PIB transaction to the virtual environment + /// + /// \param[in,out] io_transaction The abstract PIB transaction + /// + /// PIB/PCB transaction status is returned in the \a iv_pcbReturnCode + /// field of the transaction. A legal API call will always succeed, even + /// if the underlying bus transaction fails. If the transaction is + /// illegal in some way (indicating an issue in the derived PoreModel) then + /// this must be trapped by the PoreInterface. + void + pibMaster(PibTransaction& io_transaction); + + /// Master an OCI transaction to the virtual environment + /// + /// \param[in,out] io_transaction The abstract OCI transaction + /// + /// OCI transaction status is returned in the \a iv_ociReturnCode field of + /// the transaction. A legal API call will always succeed, even if the + /// underlying bus transaction fails. If the transaction is illegal in + /// some way (indicating an issue in the derived PoreModel) then this must + /// be trapped by the PoreInterface. + void + ociMaster(OciTransaction& io_transaction); + + /// Implement the WAIT instruction + /// + /// \param[in] i_count The number of PORE cycles to wait. + /// + /// The PoreModel has no notion of time, so it requires the environment to + /// model WAIT. The hardware treats WAIT 0 as a special HALT instruction, + /// however the concrete model still must still invoke the wait() method + /// in this case to inform the abstract model that the PORE has halted + /// (since this generates a hardware interrupt). Since WAIT can not fail + /// in the hardware, any errors in the implementation of wait() must be + /// handled by the PoreInterface. + void + wait(const uint32_t i_count); + + /// Implement the HOOKI instruction + /// + /// \param[in] i_address The effective address of the HOOKI instruction. + /// + /// \param[in] i_hook The low-order 24 bits of the HOOKI instruction, used + /// to index the hook routine that will process the hook. + /// + /// \param[in] i_parameter A 64-bit parameter for the hook routine. + /// + /// The HOOKI instruction allows the PORE code to invoke a fixed set of + /// hooks indexed by a 24-bit integer code, passing each hook routine a + /// 64-bit parameter. The underlying hardware model has no dependency on + /// the outcome of running a hook, therefore any errors in hook processing + /// must be handled by the PoreInterface. + void + hookInstruction(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter); + + /// Notify the environment of a data read + /// + /// \param[in] i_address The effective PoreAddress of the data read. + /// + /// This method allows the environment to hook data reads. For direct + /// memory accesses, this method is called immediately before a bus + /// transaction is generated to fetch the data at the given effective + /// address. For indirect PIB transactions, this method is invoked prior + /// to the I2C transaction that actually reads the data from the I2C + /// memory. The underlying hardware model has no dependency on the outcome + /// of running a hook, therefore any errors in hook processing must be + /// handled by the PoreInterface. + void + hookRead(const PoreAddress& i_address); + + /// Notify the environment of a data write + /// + /// \param[in] i_address The effective PoreAddress of the data write. + /// + /// This method allows the environment to hook data writes. For direct + /// memory accesses, this method is called immediately before a bus + /// transaction is generated to store the data at the given effective + /// address. For indirect PIB transactions, this method is invoked prior + /// to the I2C transaction that actually writes the data to the I2C + /// memory. The underlying hardware model has no dependency on the outcome + /// of running a hook, therefore any errors in hook processing must be + /// handled by the PoreInterface. + void + hookWrite(const PoreAddress& i_address); + + /// Notify the environment of an instruction fetch + /// + /// \param[in] i_address The effective PoreAddress of the instruction. + /// + /// This method allows the environment to hook instruction fetches, where + /// an instruction fetch refers to reading the first 4 (of potentially 12) + /// bytes that comprise an instruction for the purposes of instruction + /// execution. For direct memory accesses, this method is called + /// immediately before a bus transaction is generated to read the + /// instruction data at the given effective address. For indirect PIB + /// transactions, this method is invoked prior to the I2C transaction that + /// actually fetches the data from the I2C memory. The underlying hardware + /// model has no dependency on the outcome of running a hook, therefore + /// any errors in hook processing must be handled by the PoreInterface. + void + hookFetch(const PoreAddress& i_address); + + /// Notify the environment of the error interrupt + /// + /// This method must be invoked by the deribed PoreModel whenever the + /// execution of an instruction would pulse the PORE hardware \a + /// tp_por_error_out signal. + void + errorIntr(void); + + /// Notify the environment of the fatal error interrupt + /// + /// This method must be invoked by the derived PoreModel whenever the + /// execution of an instruction would pulse the PORE hardware \a + /// tp_por_fatal_error_out signal. + void + fatalErrorIntr(void); + + + ////////////////////////////// Creators ////////////////////////////// + +public: + + /// Create the PoreModel base class + /// + /// The PoreModel is defined to be in the restart (scan-flush) state at + /// the end of constructing the model. + /// + /// \param[in] i_ibufId The IBUF ID (PORE type) of the model. + /// + /// \param[in] i_interface A pointer back to the PoreInterface that + /// created this model. + PoreModel(const PoreIbufId i_ibufId, PoreInterface* i_interface); + + virtual ~PoreModel(); + + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The IBUF ID (engine type) of the PORE being modeled + PoreIbufId iv_ibufId; + +private: + + /// The most recent ModelError generated by the model or by calls of + /// modelError(), or 0 for no error. + ModelError iv_modelError; + + /// The total number of instructions executed since the PoreModel + /// was created, or since the last restart() operation. + uint64_t iv_instructions; + + /// The most recent stop code provided in a call of stop(), or 0 if the + /// model is not stopped. + int iv_stopCode; + + /// Pointer back to the virtual interface containing this hardware model. + PoreInterface* iv_interface; + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + PoreModel(const PoreModel& i_rhs); + PoreModel& operator=(const PoreModel& i_rhs); +}; + +#endif // __VSBE_POREMODEL_H diff --git a/src/usr/pore/poreve/model/poreregister.C b/src/usr/pore/poreve/model/poreregister.C new file mode 100644 index 000000000..7be840b4c --- /dev/null +++ b/src/usr/pore/poreve/model/poreregister.C @@ -0,0 +1,295 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poreregister.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: poreregister.C,v 1.5 2011/08/03 17:59:00 bcbrock Exp $ + +/// \file poreregister.C +/// \brief The PoreRegister and PoreRegisterWritable classes + +#include "poreinterface.H" + +using namespace vsbe; + + +//////////////////////////////////////////////////////////////////////////// +// PoreRegister +//////////////////////////////////////////////////////////////////////////// + +////////////////////////////// Creators ////////////////////////////// + +PoreRegister::PoreRegister(PoreInterface* i_interface, + const PoreRegisterEncoding i_encoding) : + iv_interface(i_interface), + iv_encoding(i_encoding) +{ +} + + +PoreRegister::~PoreRegister() +{ +} + + +uint64_t +PoreRegister::read() const +{ + uint64_t data; + ModelError me; + PoreRegisterOffset offset = PORE_REGISTER_MAP[iv_encoding]; + + switch (iv_encoding) { + + case PORE_D0: + case PORE_D1: + case PORE_A0: + case PORE_A1: + case PORE_EMR: + case PORE_ETR: + case PORE_IFR: + + // These are read as 64-bit registers in the model + + me = iv_interface->registerRead(offset, data); + break; + + case PORE_P0: + case PORE_P1: + case PORE_CTR: + case PORE_SPRG0: + + // These registers are <= 32 bits and stored right-justified in the + // high-order 32 bits of the 64-bit registers. In every case the + // hardware specification specifies that unused bits on the left read + // as 0. + + me = iv_interface->registerRead(offset, data); + data >>= 32; + break; + + case PORE_PC: + + // The PC is read as the low-order 48 bits of the status register. + + me = iv_interface->registerRead(offset, data); + data &= 0xffffffffffffull; + break; + + case PORE_CIA: + + // The CIA is obtained from the high-order 48 bits of the DBG1 + // register. + + me = iv_interface->registerRead(offset, data); + data >>= 16; + break; + + default: + me = ME_BUG; + break; + } + if (me != 0) { + iv_interface->modelError(me); + } + return data; +} + + +PoreRegister::operator uint64_t () const +{ + return read(); +} + + +//////////////////////////////////////////////////////////////////////////// +// PoreRegisterWritable +//////////////////////////////////////////////////////////////////////////// + +PoreRegisterWritable:: +PoreRegisterWritable(PoreInterface* i_interface, + const PoreRegisterEncoding i_encoding) : + PoreRegister(i_interface, i_encoding) +{ +} + + +PoreRegisterWritable::~PoreRegisterWritable() +{ +} + + +uint64_t +PoreRegisterWritable::write(const uint64_t i_data) +{ + ModelError me; + PoreRegisterOffset offset = PORE_REGISTER_MAP[iv_encoding]; + + switch (iv_encoding) { + + case PORE_D0: + case PORE_D1: + + // These are written as 64-bit registers in the model + + me = iv_interface->registerWrite(offset, i_data); + break; + + case PORE_A0: + case PORE_A1: + + // The programmer-writable portion of A0 and A1 are the low-order + // 46 bits. + + me = iv_interface->registerWrite(offset, i_data & 0x3fffffffffffull); + break; + + case PORE_P0: + case PORE_P1: + + // The programmer-visible portion is bits 25:31, the remainder is + // undefined. + + me = iv_interface->registerWrite(offset, (i_data & 0x7f) << 32); + break; + + case PORE_CTR: + + // The programmer-visible portion is bits 8:31, the remainder is + // undefined. + + me = iv_interface->registerWrite(offset, (i_data & 0xffffff) << 32); + break; + + case PORE_EMR: + + // The programmer-visible portion is bits 0:20 + + me = iv_interface->registerWrite(offset, + i_data & 0xfffff80000000000ull); + break; + + case PORE_SPRG0: + + // These register moves the low-order 32 bits of the data to the + // high-order bits of the target. + + me = iv_interface->registerWrite(offset, (i_data & 0xffffffff) << 32); + break; + + case PORE_IFR: + + // Only bits 48:55 of the IFR (the ALU flags) are writable. + + me = iv_interface->registerWrite(offset, i_data & 0xff00ull); + break; + + case PORE_ETR: + + // Only the low-order 32 bits are writable + + me = iv_interface->registerWrite(PORE_EXE_TRIGGER_HI, i_data, 4); + break; + + default: + me = ME_BUG; + break; + } + if (me != 0) { + iv_interface->modelError(me); + } + return i_data; +} + + +uint64_t +PoreRegisterWritable::operator=(const uint64_t& i_data) +{ + return write(i_data); +} + + +//////////////////////////////////////////////////////////////////////////// +// PoreDataBuffer +//////////////////////////////////////////////////////////////////////////// + +PoreDataBuffer::PoreDataBuffer(PoreInterface* i_interface, + const PoreRegisterEncoding i_encoding) : + PoreRegisterWritable(i_interface, i_encoding) +{ +} + + +PoreDataBuffer::~PoreDataBuffer() +{ +} + + +bool +PoreDataBuffer::isBitSet(const uint32_t i_bit) +{ + return (read() & BE64_BIT(i_bit)) != 0; +} + + +bool +PoreDataBuffer::isBitClear(const uint32_t i_bit) +{ + return (read() & BE64_BIT(i_bit)) == 0; +} + + +uint64_t +PoreDataBuffer::extractToRight(const uint32_t i_start, + const uint32_t i_len) +{ + return BE64_GET_FIELD(read(), i_start, (i_start + i_len - 1)); +} + + +// This needs to be replicated here for obscure C++ reasons +uint64_t +PoreDataBuffer::operator=(const uint64_t& i_data) +{ + return write(i_data); +} + + +uint64_t +PoreDataBuffer::setBit(const uint32_t i_bit) +{ + return write(read() | BE64_BIT(i_bit)); +} + + +uint64_t +PoreDataBuffer::clearBit(const uint32_t i_bit) +{ + return write(read() & ~BE64_BIT(i_bit)); +} + +uint64_t +PoreDataBuffer::insertFromRight(const uint64_t i_data, + const uint32_t i_start, + const uint32_t i_len) +{ + return write(BE64_SET_FIELD(read(), i_start, (i_start + i_len - 1), + i_data)); +} diff --git a/src/usr/pore/poreve/model/poreregister.H b/src/usr/pore/poreve/model/poreregister.H new file mode 100644 index 000000000..24147365f --- /dev/null +++ b/src/usr/pore/poreve/model/poreregister.H @@ -0,0 +1,275 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/poreregister.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_POREREGISTER_H +#define __VSBE_POREREGISTER_H + +// $Id: poreregister.H,v 1.2 2011/08/03 17:59:00 bcbrock Exp $ + +/// \file poreregister.H +/// \brief The PoreRegister and PoreRegisterWritable classes + +#include <stdint.h> + +#include "poreconstants.H" + +namespace vsbe { + + class PoreRegister; + class PoreRegisterWritable; + class PoreDataBuffer; + class PoreInterface; +}; + + +//////////////////////////////////////////////////////////////////////////// +// PoreRegister +//////////////////////////////////////////////////////////////////////////// + +/// An abstract PORE programmer-visible register model +/// +/// This class is introduced to provide abstract register models that are easy +/// to program for user code (e.g., hooks), by making the register appear to +/// be a data member of the PoreInterface, but leaving the implementation to +/// the underlying PoreModel. This is necessary in part because there is not +/// always a direct map between the PORE hardware register and the +/// programmer-visible register (or abstract register like CIA). +/// +/// Two types of register are supported here: +/// +/// - True programmer-visible registers like D0, A0, P0, PC +/// - "Abstract" registers introduced to simplify hook programming like CIA +/// +/// The register values manipulated by the PoreRegister associated with true +/// programmer visible registers are always the programmer-visible register +/// contents. Reading the register always returns the value as if the +/// register were moved to a 64-bit data register inside the engine. Writing +/// the register updates the underlying hardware model as if the register were +/// updated by a move from a 64-bit data register. +/// +/// The PoreRegister defines a conversion operator to a uint64_t. This allows +/// the register object to be used as if it were a uint64_t data member of the +/// PoreInterface. Note that for registers smaller than 64 bits the data will +/// be (for reads), or is expected to be (for writes), right justfied in the +/// 64 bit input or result. +/// +/// When the PoreRegister instances are defined as data members of +/// PoreInterface, each instance is parameterized with the information +/// necessary to transform an access of the abstract register into the +/// register interface calls of the PoreModel. Note that in certain cases it +/// may not be possible to use the abstract register directly in an expression +/// because the usage is ambiguous to the compiler. These problems can +/// be solved either by using temporary variables to disambiguate the usage, +/// or by explicitly using the read() methods of the PoreRegister +/// objects. +/// +/// All registers have read access and read() methods. Most are actually +/// implemeted as the PoreRegisterWritable subclass that has write access and +/// a write method as well. + +class +vsbe::PoreRegister { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + /// Create a PoreRegister + /// + /// \param[in] i_interface A pointer to the parent PoreInterface object that + /// implements the underlying registerRead() and registerWrite() methods. + /// + /// \param[in] i_register A value from the enumeration + /// PoreRegisterEncodingore identifying the register. + PoreRegister(PoreInterface* i_interface, + const PoreRegisterEncoding i_register); + + virtual ~PoreRegister(); + + ///////////////////////////// Accessors ////////////////////////////// + + /// Implement the PoreRegister register read + /// + /// Note that if the embedded call of PoreInterface::registerRead() fails + /// it is considered a bug in the model. + /// + /// \retval value The current register value, right justified in the + /// return value. + virtual uint64_t read() const; + + /// Get the register value as a conversion (cast) using read(). + virtual operator uint64_t () const; + + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The parent PoreInterface object + PoreInterface* iv_interface; + + /// The PORE ISA encoding of register + PoreRegisterEncoding iv_encoding; + + ////////////////////////// Safety //////////////////////////// + +private: + + PoreRegister(const PoreRegister& i_rhs); + PoreRegister& operator=(PoreRegister& i_rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// PoreRegisterWritable +//////////////////////////////////////////////////////////////////////////// + +/// A writable PoreRegister +/// +/// This subclass extends the PoreRegister class by the addition of write +/// access and a write() method. + +class +vsbe::PoreRegisterWritable : public PoreRegister { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + /// Create a PoreRegisterWritable + /// + /// \param[in] i_interface A pointer to the parent PoreInterface object that + /// implements the underlying registerRead() and registerWrite() methods. + /// + /// \param[in] i_register A value from the enumeration + /// PoreRegisterEncoding identifying the register. + PoreRegisterWritable(PoreInterface* i_interface, + const PoreRegisterEncoding i_register); + + virtual ~PoreRegisterWritable(); + + + //////////////////////////// Manipulators //////////////////////////// + + /// Implement the PoreRegister register write + /// + /// \param[in] i_data The data to be written to the register + /// + /// For registers smaller than 64 bits, the low-order bits of \a i_data + /// are inserted into the hardware register. Note that if the embedded + /// call of PoreInterface::registerWritw() fails it is considered a bug in + /// the model. + /// + /// \retval data This method returns its input \a data. + virtual uint64_t write(const uint64_t i_data); + + /// Assign a value to a register using operator=(). See write(). + virtual uint64_t operator=(const uint64_t& i_data); + + + ////////////////////////// Safety //////////////////////////// + +private: + + PoreRegisterWritable(const PoreRegisterWritable& i_rhs); + PoreRegisterWritable& operator=(PoreRegisterWritable& i_rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// PoreDataBuffer +//////////////////////////////////////////////////////////////////////////// + +/// A PoreRegister as an ecmdDataBuffer +/// +/// This subclass extends the PoreRegisterWritable class by the addition of +/// selected methods of the ecmdDataBuffer, to provide a familiar and +/// convenient API for manipulating data in the PoreVe. Only the 64-bit data +/// registers D0 and D1 are implemented using this class. +/// +/// Note that the eCmd-like methods are all implemented in functional form for +/// simplicty, and operate on uint64_t data values exclusively. There is no +/// error checking for bit positions, which are assumed to fall with the range +/// 0:63. + +class +vsbe::PoreDataBuffer : public PoreRegisterWritable { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + /// Create a PoreDataBuffer + /// + /// \param[in] i_interface A pointer to the parent PoreInterface object that + /// implements the underlying registerRead() and registerWrite() methods. + /// + /// \param[in] i_register A value from the enumeration + /// PoreRegisterEncoding identifying the register. + PoreDataBuffer(PoreInterface* i_interface, + const PoreRegisterEncoding i_register); + + virtual ~PoreDataBuffer(); + + + //////////////////////////// Accessors //////////////////////////// + + /// Return \a true if bit \a i_bit is set, otherwise \a false + virtual bool isBitSet(const uint32_t i_bit); + + /// Return \a true if bit \a i_bit is clear, otherwise \a false + virtual bool isBitClear(const uint32_t i_bit); + + /// Extract \a i_len bits from \a i_start and right justify into a uint64_t + virtual uint64_t extractToRight(const uint32_t i_start, + const uint32_t i_len); + + using PoreRegister::operator uint64_t; + + + //////////////////////////// Manipulators //////////////////////////// + + /// Assign a value to a register using operator=(). See write(). + virtual uint64_t operator=(const uint64_t& i_data); + + /// Set bit \a i_bit and return the new 64-bit value + virtual uint64_t setBit(const uint32_t i_bit); + + /// Clear bit \a i_bit and return the new 64-bit value + virtual uint64_t clearBit(const uint32_t i_bit); + + /// Insert \a i_len low-order bits of \a i_data at \a i_start and return + /// the new 64-bit value + virtual uint64_t insertFromRight(const uint64_t i_data, + const uint32_t i_start, + const uint32_t i_len); + + + ////////////////////////// Safety //////////////////////////// + +private: + + PoreDataBuffer(const PoreDataBuffer& i_rhs); + PoreDataBuffer& operator=(PoreDataBuffer& i_rhs); +}; + +#endif // __VSBE_POREREGISTER_H diff --git a/src/usr/pore/poreve/model/porestate.C b/src/usr/pore/poreve/model/porestate.C new file mode 100644 index 000000000..b3ce8a087 --- /dev/null +++ b/src/usr/pore/poreve/model/porestate.C @@ -0,0 +1,93 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/porestate.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: porestate.C,v 1.2 2011/10/13 10:04:32 haver Exp $ + +/// \file porestate.C +/// \brief A structure defining the state of a PORE engine for +/// checkpoint/restart purposes. + +#include "porestate.H" +#include <string.h> + +using namespace vsbe; + + +PoreState::PoreState() +{ + // Ensure that reserved/free space is always 0 such that we + // can do memcmp. + memset(state, 0, sizeof(state)); +} + + +PoreState::~PoreState() +{ +} + + +ModelError +PoreState::get(const PoreRegisterOffset i_offset, uint64_t& o_reg) const +{ + ModelError me; + int i; + + if ((i_offset >= SIZEOF_PORE_STATE) || ((i_offset % 8) != 0)) { + me = ME_PORE_STATE_ERROR; + } else { + + me = ME_SUCCESS; + o_reg = 0; + for (i = 0; i < 8; i++) { + o_reg <<= 8; + o_reg |= state[i_offset + i]; + } + } + + return me; +} + + +ModelError +PoreState::put(const PoreRegisterOffset i_offset, const uint64_t i_reg) +{ + ModelError me; + int i; + uint64_t reg; + + if ((i_offset >= SIZEOF_PORE_STATE) || ((i_offset % 8) != 0)) { + me = ME_PORE_STATE_ERROR; + } else { + + me = ME_SUCCESS; + reg = i_reg; + for (i = 7; i >= 0; i--) { + state[i_offset + i] = (reg & 0xff); + reg >>= 8; + } + } + + return me; +} + + + diff --git a/src/usr/pore/poreve/model/porestate.H b/src/usr/pore/poreve/model/porestate.H new file mode 100644 index 000000000..914335ed2 --- /dev/null +++ b/src/usr/pore/poreve/model/porestate.H @@ -0,0 +1,108 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/porestate.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_PORE_STATE_H +#define __VSBE_PORE_STATE_H + +// $Id: porestate.H,v 1.1 2011/06/12 13:14:03 bcbrock Exp $ + +/// \file porestate.H +/// \brief A structure defining the state of a PORE engine for +/// checkpoint/restart purposes. + +#include "poreinterface.H" + +namespace vsbe { + + class PoreState; +}; + + +/// The state of a PORE engine +/// +/// The PoreState class represents the state of the PORE engine for +/// checkpoint/restore purposes. The state is stored as an endian-neutral +/// checkpoint of the register space of the PORE engine, therefore the object +/// can be saved and restored to/from a file regardless of the endianess of +/// the save and restore hosts. Methods are provided to access the hardware +/// register images using the PoreRegisterOffset enumeration offsets. +/// +/// This object is used as a parameter of the PoreInterface::extractState() +/// and poreInterface::installState() methods. Please see the documentation +/// of those methods for information on how the PoreState is checkpointed and +/// restored. + +class +vsbe::PoreState { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + PoreState(); + + virtual ~PoreState(); + + + ///////////////////////////// Accessors ////////////////////////////// + + /// Get a register image from the state + /// + /// \param[in] i_offset The PoreRegisterOffset of the requested register. + /// + /// \param[out] o_reg The requested register value obtained from the state. + /// + /// \retval me Either 0 for success, or a ModelError error code. + virtual ModelError + get(const PoreRegisterOffset i_offset, uint64_t& o_reg) const; + + + ///////////////////////////// Manipulators /////////////////////////// + + /// Put a register image into the state + /// + /// \param[in] i_offset The PoreRegisterOffset of the requested register. + /// + /// \param[in] i_reg The new value of the requested register to store in + /// the state. value. + /// + /// \retval me Either 0 for success, or a ModelError error code. + virtual ModelError + put(const PoreRegisterOffset i_offset, const uint64_t i_reg); + + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The register state + uint8_t state[SIZEOF_PORE_STATE]; + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + PoreState(const PoreState& rhs); + PoreState& operator=(const PoreState& rhs); +}; + +#endif // __VSBE_PORE_STATE diff --git a/src/usr/pore/poreve/model/transaction.C b/src/usr/pore/poreve/model/transaction.C new file mode 100644 index 000000000..92c5692e9 --- /dev/null +++ b/src/usr/pore/poreve/model/transaction.C @@ -0,0 +1,90 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/transaction.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: transaction.C,v 1.1 2011/05/06 23:29:00 bcbrock Exp $ + +/// \file transaction.C +/// \brief PORE abstract bus transactions + +#include "transaction.H" + +using namespace vsbe; + + +// There are no 'obvious' constructors for these classes; Likely the PORE +// model will build one of each type and resuse it over and over, changing the +// fields on each use. + +Transaction::Transaction() +{ +} + + +Transaction::~Transaction() +{ +} + + +PibTransaction::PibTransaction() +{ +} + + +PibTransaction::~PibTransaction() +{ +} + + +ModelError +PibTransaction::busError(ModelError i_me) +{ + iv_modelError = i_me; + if (i_me == ME_SUCCESS) { + iv_pcbReturnCode = PCB_SUCCESS; + } else { + iv_pcbReturnCode = PCB_TIMEOUT; + } + return i_me; +} + + +OciTransaction::OciTransaction() +{ +} + + +OciTransaction::~OciTransaction() +{ +} + + +ModelError +OciTransaction::busError(ModelError i_me) +{ + iv_modelError = i_me; + if (i_me == ME_SUCCESS) { + iv_ociReturnCode = OCI_SUCCESS; + } else { + iv_ociReturnCode = OCI_BUS_ERROR; + } + return i_me; +} diff --git a/src/usr/pore/poreve/model/transaction.H b/src/usr/pore/poreve/model/transaction.H new file mode 100644 index 000000000..39fd0b135 --- /dev/null +++ b/src/usr/pore/poreve/model/transaction.H @@ -0,0 +1,251 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/model/transaction.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_TRANSACTION_H +#define __VSBE_TRANSACTION_H + +// $Id: transaction.H,v 1.4 2011/06/06 15:35:15 bcbrock Exp $ + +/// \file transaction.H +/// \brief PORE abstract bus transactions + +#include <stddef.h> +#include <stdint.h> + +#include "modelerror.H" + + +namespace vsbe { + + class Transaction; + class PibTransaction; + class OciTransaction; + + + /// \defgroup pore_transaction_modes PORE Transaction Modes + /// + /// Each PORE transaction is tagged with a one-hot mask indicating whether + /// the transaction is a read, write or instruction fetch. The Slave + /// and MemoryImage models also include a bit-set of these masks to + /// indicate whether the Slave or MemoryImage supports the indicated + /// access. + /// + /// @{ + + /// A data read; Allow read access + const int ACCESS_MODE_READ = 0x1; + /// A data write; Allow write access + const int ACCESS_MODE_WRITE = 0x2; + /// An instruction fetch; Allow execute access + const int ACCESS_MODE_EXECUTE = 0x4; + + /// @} + + /// The byte size of a transaction on the bus + const int TRANSACTION_SIZE_IN_BYTES = 0x8; + + /// \enum PcbReturnCode + /// + /// This enumeration follows the 3-bit return code as specified in the + /// Pervasive Workbook + enum PcbReturnCode { + PCB_SUCCESS = 0, + PCB_RESOURCE_OCCUPIED = 1, + PCB_CHIPLET_OFFLINE = 2, + PCB_PARTIAL_GOOD = 3, + PCB_ADDRESS_ERROR = 4, + PCB_CLOCK_ERROR = 5, + PCB_PACKET_ERROR = 6, + PCB_TIMEOUT = 7 + }; + + + /// \enum OciReturnCode + /// + /// These return codes are abstractions; The OCI_BUS_ERROR is a catch-all + /// for now. + enum OciReturnCode { + OCI_SUCCESS = 0, + OCI_BUS_ERROR = 1 + }; +}; + + +/// PORE abstract transaction +/// +/// This abstract transaction model is loosely based on the Simics model of a +/// 'generic transaction', plus experience from the PMX model. It takes +/// advantage of the fact that (currently) both the PIB and OCI interfaces use +/// 32-bit addresses and (maximum) 8-byte data. The Pore model supports +/// separate interfaces for PIB and OCI, and the base Transaction is an +/// abstract class that is subclassed for PIB and OCI error reporting +/// purposes. +/// +/// The Transaction is part of the pure abstract PORE model, and is not tied +/// to any particular virtual environment. The Transaction is originaly +/// generated within the PoreModel, moves through the virtual environment, and +/// eventually returns to the PoreModel with read data (for reads) and return +/// codes. For simplicity all of the data members are declared public, and +/// comments with the members indicate which system element is responsible for +/// setting them and when. + +class +vsbe::Transaction { + +public: + + ///////////////////////// Abstract Interface ///////////////////////// + + /// Install \a i_me as the \a modelError field of the transaction and also + /// insert a bus-model specific error code. + /// + /// \param[in] i_me The ModelError associated with this generic bus error. + /// If \a i_me != ME_SUCCESS (0) then this method sets a bus-specific + /// error code in the transaction. If \a i_me == ME_SUCCESS (0) then this + /// method clears the bus-specific error code in the transaction. + /// + /// This method allows the common Bus model or memory models to signal a + /// generic catostrophic error (e.g., no slave or installed memory maps + /// the address) without knowing the derived type of the Transaction. The + /// \a i_me provides as a more descriptive reason for the bus error. + /// + /// \retval i_me This method returns its input parameter, \a i_me. + virtual ModelError + busError(const ModelError i_me) = 0; + + ////////////////////////////// Creators ////////////////////////////// + + Transaction(); + virtual ~Transaction(); + + ////////////////////////// Implementation //////////////////////////// + + /// The access mode (one of the MODE_* constants) set by PoreModel when + /// the transaction is mastered. + int iv_mode; + + /// The 32-bit physical bus address, set by PoreModel when the transaction + /// is mastered. + uint32_t iv_address; + + /// The 64-bit data, set by PoreModel for writes, and by the virtual + /// environment for reads. + /// + /// Data is manipulated by the PORE models in host byte order. The memory + /// models must translate host byte order to and from Big-Endian ordering + /// used in the PORE memory implementations. This implies that for + /// transaction sizes less than 8 bytes (which are all transactions for + /// now), the data is right justified in the data field, and can be + /// interpreted as if the hardware had loaded or stored an unsigned + /// integer of the given \a size. + uint64_t iv_data; + + /// A PORE model error code + /// + /// The virtual environment is responsible for setting the \a modelError + /// for every transaction to a value selected from the ModelError + /// enumeration. + ModelError iv_modelError; + + /// The address offset within the bus slave + /// + /// This field is added for the convenience of bus/slave models. It is + /// designed as a place for the bus/slave model to store the offset of the + /// addressed register/memory from a base address of a memory region or + /// set of registers. The PORE bus masters ignore this field. The PORE + /// bus slaves expect the environment to set this before sending a + /// Transaction into the PIB and OCI slaves. + uint32_t iv_offset; + + ///////////////////////////// Safety ////////////////////////////////// + +private: + Transaction(const Transaction& rhs); + Transaction& operator=(const Transaction& rhs); + +}; + + +/// Refine the Transaction for PIB/PCB-specific error reporting + +class +vsbe::PibTransaction : public vsbe::Transaction { + +public: + + ///////////////////////// Abstract Interface ///////////////////////// + + /// For the PIB bus, a bus error is treated as a PCB_TIMEOUT. See + /// Transaction::busError() for further details. + virtual ModelError busError(const ModelError i_me); + + ////////////////////////////// Creators ////////////////////////////// + + PibTransaction(); + virtual ~PibTransaction(); + + ////////////////////////// Implementation //////////////////////////// + + /// The PIB/PCB return code associated with the transaction, set by the + /// memory subsystem on every operation. + PcbReturnCode iv_pcbReturnCode; + + ///////////////////////////// Safety ////////////////////////////////// + +private: + PibTransaction(const PibTransaction& rhs); + PibTransaction& operator=(const PibTransaction& rhs); +}; + + +/// Refine the Transaction for OCI-specific error reporting + +class +vsbe::OciTransaction : public vsbe::Transaction { + +public: + + ///////////////////////// Abstract Interface ///////////////////////// + + /// For the OCI bus, a bus error is treated as the generic OCI_BUS_ERROR. + /// See Transaction::busError() for further details. + virtual ModelError busError(const ModelError i_me); + + ////////////////////////////// Creators ////////////////////////////// + + OciTransaction(); + virtual ~OciTransaction(); + + ////////////////////////// Implementation //////////////////////////// + + /// The OCI return code associated with the transaction, set by the + /// memory subsystem on every operation. + OciReturnCode iv_ociReturnCode; + + ///////////////////////////// Safety ////////////////////////////////// + +private: + OciTransaction(const OciTransaction& rhs); + OciTransaction& operator=(const OciTransaction& rhs); +}; + +#endif // __VSBE_TRANSACTION_H diff --git a/src/usr/pore/poreve/pore_model/ibuf/pore_bus.c b/src/usr/pore/poreve/pore_model/ibuf/pore_bus.c new file mode 100644 index 000000000..7f8c2af27 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/ibuf/pore_bus.c @@ -0,0 +1,934 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/ibuf/pore_bus.c $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +/****************************************************************************** + * + * Virtual PORe Engine + * + *****************************************************************************/ + +/** + * 24-bit address: + * 11.1111.1111.2222 + * 0123.4567.8901.2345.6789.0123 + * || Mcase, ChipletId ... + * || + * |`0: PIB_base_0 + * | PIB_base_1 + * | + * `0: PIB + * 1: Memory (fi2c when used as SBE or OCI otherwise) + * | + * ` 0: OCI_base_0 & MEM_RELOC + * 1: OCI_base_1 & MEM_RELOC + */ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "pore_regs.h" +#include "pore_model.h" +#include "pore_ibuf.h" + +#define I2C_COMMAND_COMPLETION 16 /* MAX iterations before aborting I2C */ + +/*** OCI Bus access **********************************************************/ + +static int oci_write(struct pore_bus *b, uint64_t addr, + const uint8_t *buf, unsigned int len, + int *err_code) +{ + struct pore_bus *oci = b->slaves[0]; + + if (!oci) { + eprintf(b->pore, "err: no oci available!\n"); + return PORE_ERR_NOACK; + } + + bprintf(b->pore, " %-12s: %s(%p, 0x%llx, %p, %x)\n", b->name, + __func__, b, (long long)addr, buf, len); + return poreb_write(oci, addr & PORE_BITS_32_63, buf, len, err_code); +} + +static int oci_read(struct pore_bus *b, uint64_t addr, uint8_t *buf, + unsigned int len, int *err_code) +{ + struct pore_bus *oci = b->slaves[0]; + + if (!oci) { + eprintf(b->pore, "err: no oci available!\n"); + return PORE_ERR_NOACK; + } + + bprintf(b->pore, " %-12s: %s(%p, 0x%llx, %p, %x)\n", b->name, + __func__, b, (long long)addr, buf, len); + return poreb_read(oci, addr & PORE_BITS_32_63, buf, len, err_code); +} + +/// Fetch Instruction Word from OCI Buffer +/// +/// This method returns an instruction word from the fetch buffer. If +/// the fetch buffer is empty, it does an OCI interface read and +/// populates the buffer before returning the word. + +static int fetchInstructionWordOci(struct pore_bus *b, PoreAddress *pc, + uint32_t *word, int *err_code) +{ + int me = 0; + uint32_t offset = pc->offset; + pore_model_t p = b->pore; + struct pore_bus *oci = b->slaves[0]; + + // If the fetch buffer is not valid, or the data is not + // already present it is fetched. Then the correct word is + // returned from the buffer. + + if(!p->oci_fetchBufferValid || + (p->oci_fetchBufferCursor != (offset & 0xfffffff8))) { + + p->oci_fetchBufferCursor = offset & 0xfffffff8; + me = poreb_read(oci, p->oci_fetchBufferCursor, + (uint8_t *)&p->oci_fetchBuffer, + sizeof(p->oci_fetchBuffer), err_code); + if (me < 0) + return PORE_ERR_FETCH; + + p->oci_fetchBufferValid = 1; + } + *word = ((offset & 0x7) == 0) ? + p->oci_fetchBuffer >> 32 : + p->oci_fetchBuffer & 0xffffffff; + + return me; +} + +/// Model the 1 or 3 word instruction fetch from OCI. +/// +/// This is for GPE0/1 and SLW, and goes through the OCI 8-byte instruction +/// buffer. +static int oci_fetch(struct pore_bus *b, uint64_t _pc, + uint64_t *ibuf_01, uint64_t *ibuf_2, + unsigned int *size, int *err_code) +{ + int me; + uint32_t i_word; + PoreAddress pc; + pore_model_t p = b->pore; + + if (!b || !ibuf_01 || !ibuf_2 || !size || !err_code) + return PORE_ERR_INVALID_PARAM; + + pc.val = _pc; + *ibuf_01 = *ibuf_2 = 0; + pore_relocateAddress(p, &pc.val); + + me = fetchInstructionWordOci(b, &pc, &i_word, err_code); + if (me < 0) + return PORE_ERR_FETCH; + *ibuf_01 = (uint64_t)i_word << 32; + *size = 4; + + if (i_word & 0x80000000) { + pc.offset += 4; + me = fetchInstructionWordOci(b, &pc, &i_word, err_code); + if (me < 0) + return PORE_ERR_FETCH; + *size += 4; + *ibuf_01 |= i_word; + pc.offset += 4; + me = fetchInstructionWordOci(b, &pc, &i_word, err_code); + if (me < 0) + return PORE_ERR_FETCH; + *size += 4; + *ibuf_2 = (uint64_t)i_word << 32; + } + return me; +} + +static int oci_reset(pore_bus_t b) +{ + pore_model_t p = b->pore; + + p->oci_fetchBufferValid = 0; + p->oci_fetchBufferCursor = 0; + p->oci_fetchBuffer = 0; + return 0; +} + +struct pore_bus *poreb_create_pore2oci(struct pore_model *p, + const char *name, + struct pore_bus *oci) +{ + struct pore_bus *b; + + if (!p) { + BUG(); + return NULL; + } + + b = poreb_create(name, 0, oci_read, oci_write, + oci_fetch, oci_reset); + if (!b) + return NULL; + + p->oci_fetchBufferValid = 0; + p->oci_fetchBufferCursor = 0; + p->oci_fetchBuffer = 0; + b->slaves[0] = oci; + b->pore = p; + + return b; +} + +/*** Virtual bus to represent the address range for an fi2c master ***********/ + +struct pore_fi2cm { + struct pore_bus *pib; + pore_i2c_en_param_reg *i2c_param; /* reference to pore_model */ +}; + +/** + * Convert a PoreAddress + I2C register offset into a PIB address + */ +static uint32_t +i2cPibAddress(PoreAddress *address, uint16_t offset) +{ + return ((address->memorySpace & 0x3fff) << 16) + offset; +} + +static int fi2cm_setAddress(struct pore_bus *b, uint64_t addr, int *err_code) +{ + int rc; + unsigned int count; + pore_model_t p = b->pore; + struct pore_fi2cm *fi2cm = (struct pore_fi2cm *)poreb_get_priv(b); + pore_i2c_en_param_reg *i2cp = fi2cm->i2c_param; + PoreAddress address; + fasti2c_control_reg control; + fasti2c_status_reg status; + uint32_t pib_addr; + + iprintf(p, "############ I2C SET ADDRESS #########################\n"); + + /* 4.7.3.1 Set Address */ + address.val = addr; + + /* 1. Write fast I2C Control Register at PRV address */ + control.val = 0; + control.with_start = 1; + control.with_address = 1; + control.with_stop = 1; + control.read_continue = 0; + control.data_length = 0; /* mark this as address write */ + control.device_address = i2cp->i2c_engine_device_id; + control.read_not_write = 0; /* address write */ + control.speed = i2cp->i2c_engine_speed; + control.port_number = i2cp->i2c_engine_port; + control.address_range = i2cp->i2c_engine_address_range; + + /* Add required address bytes to control register */ + control.val |= (address.offset << + ((4 - i2cp->i2c_engine_address_range)*8)); + + pib_addr = i2cPibAddress(&address, FASTI2C_CONTROL_OFFSET); + rc = pore_pib_write(p, pib_addr, (uint8_t *)&control.val, + sizeof(control.val), err_code); + if (rc < 0) + return rc; + + /* 2. Wait for Data fill-level is 4/8 Bytes by polling fast + * I2C status register at PRV address + */ + pib_addr = i2cPibAddress(&address, FASTI2C_STATUS_OFFSET); + for (count = 0; count < I2C_COMMAND_COMPLETION; count++) { + + rc = pore_pib_read(p, pib_addr, (uint8_t *)&status.val, + sizeof(status.val), err_code); + if (rc != sizeof(status.val)) + break; + + iprintf(p, "I2C_COMMAND_STATUS=%016llx count=%d\n" + " i2c_command_complete = %x\n" + " i2c_fifo_entry_count = %x\n", + (long long)status.val, count, + (unsigned int)status.i2c_command_complete, + (unsigned int)status.i2c_fifo_entry_count); + + if (status.i2c_command_complete) + break; + } + /* Check for timeout or error */ + if (count == I2C_COMMAND_COMPLETION || (rc < 0)) + return pore_handleErrEvent(p, 1, PORE_ERR_I2C_POLLING); + + return rc; +} + +static int fi2cm_read(struct pore_bus *b, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code) +{ + int rc; + unsigned int count; + pore_model_t p = b->pore; + struct pore_fi2cm *fi2cm = (struct pore_fi2cm *)poreb_get_priv(b); + pore_i2c_en_param_reg *i2cp = fi2cm->i2c_param; + PoreAddress address; + fasti2c_control_reg control; + fasti2c_status_reg status; + uint32_t pib_addr; + uint64_t read_data = 0; + + if (((size != 8) && (size != 4)) || + ((i2cp->i2c_engine_address_range != 2) && + (i2cp->i2c_engine_address_range != 4))) + return PORE_ERR_INVALID_PARAM; + + rc = fi2cm_setAddress(b, addr, err_code); + if (rc < 0) + return rc; + + iprintf(p, "############ I2C READ (len=%d) #######################\n", + size); + + /* 4.7.3.2 Get Data (4 byte or 8 byte) */ + address.val = addr; + + /* 1. Write fast I2C Control Register at PRV address */ + control.val = 0; + control.with_start = 1; + control.with_address = 1; + control.with_stop = 1; + control.read_continue = 0; + control.data_length = size; + control.device_address = i2cp->i2c_engine_device_id; + control.read_not_write = 1; /* read */ + control.speed = i2cp->i2c_engine_speed; + control.port_number = i2cp->i2c_engine_port; + control.address_range = i2cp->i2c_engine_address_range; + + /* Add required address bytes to control register */ + control.val |= (address.offset << + ((4 - i2cp->i2c_engine_address_range)*8)); + + pib_addr = i2cPibAddress(&address, FASTI2C_CONTROL_OFFSET); + rc = pore_pib_write(p, pib_addr, (uint8_t *)&control.val, + sizeof(control.val), err_code); + if (rc < 0) + return rc; + + /* 2. Wait for Data fill-level is 4/8 Bytes by polling fast + * I2C status register at PRV address + */ + pib_addr = i2cPibAddress(&address, FASTI2C_STATUS_OFFSET); + for (count = 0; count < I2C_COMMAND_COMPLETION; count++) { + + rc = pore_pib_read(p, pib_addr, (uint8_t *)&status.val, + sizeof(status.val), err_code); + if (rc != sizeof(status.val)) + break; + + iprintf(p, "I2C_COMMAND_STATUS=%016llx count=%d\n" + " i2c_command_complete = %x\n" + " i2c_fifo_entry_count = %x\n", + (long long)status.val, count, + (unsigned int)status.i2c_command_complete, + (unsigned int)status.i2c_fifo_entry_count); + + if ((status.i2c_command_complete) && + (status.i2c_fifo_entry_count == size)) { + break; + } + } + /* Check for timeout or error */ + if (count == I2C_COMMAND_COMPLETION || (rc < 0)) + return pore_handleErrEvent(p, 1, PORE_ERR_I2C_POLLING); + + /* 3. Read 32 or 64 bit from fast I2C data register at PRV address */ + pib_addr = i2cPibAddress(&address, FASTI2C_DATA_OFFSET); + rc = pore_pib_read(p, pib_addr, (uint8_t *)&read_data, + sizeof(read_data), err_code); + read_data >>= (8 - size) * 8; + + /* Thi N Trans proposal + * + * #if (__BYTE_ORDER == __LITTLE_ENDIAN) + * memcpy(buf, (uint8_t *)&read_data, size); + * #else + * memcpy(buf, (uint8_t *)&read_data + (8 - size), size); + * #endif + */ + + switch (size) { + case 4: *(uint32_t *)buf = read_data; break; + case 8: *(uint64_t *)buf = read_data; break; + } + return size; +} + +/** + * I2C Write + * o Fill control register with required data. If i2c_engine_address_range + * allows, we need to fill the first few bytes into the control register. + * o Write the data register with the remaining bytes. + * o Poll for completion of the operation. + */ +static int fi2cm_write(struct pore_bus *b, uint64_t addr, + const uint8_t *buf, unsigned int size, + int *err_code) +{ + int rc, count; + pore_model_t p = b->pore; + struct pore_fi2cm *fi2cm = (struct pore_fi2cm *)poreb_get_priv(b); + pore_i2c_en_param_reg *i2cp = fi2cm->i2c_param; + fasti2c_control_reg control; + fasti2c_status_reg status; + PoreAddress address; + uint32_t pib_addr; + uint64_t write_data; + + if ((size != 8) || + ((i2cp->i2c_engine_address_range != 2) && + (i2cp->i2c_engine_address_range != 4))) + return PORE_ERR_INVALID_PARAM; + + rc = fi2cm_setAddress(b, addr, err_code); + if (rc < 0) + return rc; + + iprintf(p, "############ I2C WRITE ###############################\n"); + + /* 4.7.3.3 Write Data (8 byte, SBE memory interface only) */ + address.val = addr; + write_data = *((uint64_t *)buf); + + /* 1. Write fast I2C Control Register at PRV address */ + control.val = 0; + control.with_start = 1; + control.with_address = 1; + control.with_stop = 1; + control.read_continue = 0; + control.data_length = size; + control.device_address = i2cp->i2c_engine_device_id; + control.read_not_write = 0; /* write */ + control.speed = i2cp->i2c_engine_speed; + control.port_number = i2cp->i2c_engine_port; + control.address_range = i2cp->i2c_engine_address_range; + + /* Add required address bytes to control register */ + control.val |= (address.offset << + ((4 - i2cp->i2c_engine_address_range)*8)); + + /* Add possible data bytes to control register */ + if (i2cp->i2c_engine_address_range < 4) + control.val |= (write_data >> + (64 - ((4-i2cp->i2c_engine_address_range)*8))); + + pib_addr = i2cPibAddress(&address, FASTI2C_CONTROL_OFFSET); + rc = pore_pib_write(p, pib_addr, (uint8_t *)&control.val, + sizeof(control.val), err_code); + if (rc < 0) + return rc; + + /* 2. Write fast I2C Data Register at PRV address */ + + /* Write remaining data bytes to data register (left algined)*/ + write_data = write_data << ((4 - i2cp->i2c_engine_address_range) * 8); + + pib_addr = i2cPibAddress(&address, FASTI2C_DATA_OFFSET); + rc = pore_pib_write(p, pib_addr, (uint8_t *)&write_data, + sizeof(write_data), err_code); + if (rc < 0) + return rc; + + /** + * 3. Wait and poll fast I2C status register for operation to + * complete at PRV address + */ + /* FIXME Check instead bit 44 (which is not right in my + * register definition! + */ + pib_addr = i2cPibAddress(&address, FASTI2C_STATUS_OFFSET); + for (count = 0; count < I2C_COMMAND_COMPLETION; count++) { + + rc = pore_pib_read(p, pib_addr, (uint8_t *)&status.val, + sizeof(status.val), err_code); + if (rc != sizeof(status.val)) + break; + + iprintf(p, "I2C_COMMAND_STATUS=%016llx count=%d\n" + " i2c_command_complete = %x\n" + " i2c_fifo_entry_count = %x\n", + (long long)status.val, count, + (unsigned int)status.i2c_command_complete, + (unsigned int)status.i2c_fifo_entry_count); + + if (status.i2c_command_complete) { + return size; + } + } + return pore_handleErrEvent(p, 1, PORE_ERR_I2C_POLLING); +} + +struct pore_bus *poreb_create_fi2cm(pore_model_t p, const char *name, + pore_bus_t pib, + pore_i2c_en_param_reg *i2c_param) +{ + struct pore_bus *b; + struct pore_fi2cm *e; + + b = poreb_create(name, sizeof(*e), fi2cm_read, fi2cm_write, + NULL, NULL); + if (!b) + return NULL; + + e = (struct pore_fi2cm *)poreb_get_priv(b); + e->i2c_param = i2c_param; + e->pib = pib; + b->pore = p; + + return b; +} + +/* FIXME + * 1. Select fi2c master using memory_reloc and oci_base register. + * 2. Perform fi2c access. + */ +static int fi2c_read(struct pore_bus *b, uint64_t addr, uint8_t *buf, + unsigned int len, int *err_code) +{ + int i; + uint32_t port; + pore_model_t p = b->pore; + PoreAddress address; + + bprintf(p, " %-12s: %s(%p, 0x%llx, %p, %x)\n", b->name, __func__, b, + (long long)addr, buf, len); + + address.val = addr; + port = address.memorySpace & 0xf; /* must match i2c_engine_id */ + + for (i = 0; i < 3; i++) { + struct pore_bus *fi2cm = b->slaves[i]; + + if (!fi2cm) + continue; + if (!fi2cm->read) + continue; + + /* Is this fi2c master target of the desired transfer? + * Check i2c_engine_identifier against the port number + * encoded in the upper parts of he address we got. + * The upper part is contructed using the OCI_base register + * used for this acess. + */ + if (p->i2c_e_param[i].i2c_engine_identifier != port) { + continue; + } + + return poreb_read(fi2cm, addr, buf, len, err_code); + } + + return PORE_ERR_READ; +} + +static int fi2c_write(struct pore_bus *b, uint64_t addr, + const uint8_t *buf, unsigned int len, + int *err_code) +{ + int i; + uint32_t port; + pore_model_t p = b->pore; + PoreAddress address; + + address.val = addr; + port = address.memorySpace & 0xf; /* must match i2c_engine_id */ + + for (i = 0; i < 3; i++) { + struct pore_bus *fi2cm = b->slaves[i]; + + if (!fi2cm) + continue; + if (!fi2cm->write) + continue; + + /* is this fi2c master target of the desired transfer? + * I originally wanted to do this compare in the fi2cm + * code but that did not work with memory emulation + * which is not aware of the condition below. + */ + if (p->i2c_e_param[i].i2c_engine_identifier != port) { + continue; + } + + return poreb_write(fi2cm, addr, buf, len, err_code); + + } + + return PORE_ERR_WRITE; +} + +/// Model 1 or 3 word instruction fetch using indirect PIB addressing (SBE). +static int fi2c_fetch(struct pore_bus *b, uint64_t _pc, + uint64_t *ibuf_01, uint64_t *ibuf_2, + unsigned int *size, int *err_code) +{ + int me = PORE_SUCCESS; + uint32_t i_word; + PoreAddress pc; + pore_model_t p = b->pore; + + if (!b || !ibuf_01 || !ibuf_2 || !size || !err_code) + return PORE_ERR_INVALID_PARAM; + + *size = 0; + *ibuf_01 = *ibuf_2 = 0; + pc.val = _pc; + pore_relocateAddress(p, &pc.val); + + me = fi2c_read(b, pc.val, (uint8_t *)&i_word, + sizeof(i_word), err_code); + if (me != sizeof(i_word)) + return PORE_ERR_FETCH; + + *ibuf_01 = (uint64_t)i_word << 32; + *size = 4; + + if (i_word & 0x80000000) { + pc.offset += 4; + me = fi2c_read(b, pc.val, (uint8_t *)&i_word, + sizeof(i_word), err_code); + if (me != sizeof(i_word)) + return PORE_ERR_FETCH; + *size += 4; + *ibuf_01 |= i_word; + pc.offset += 4; + me = fi2c_read(b, pc.val, (uint8_t *)&i_word, + sizeof(i_word), err_code); + if (me != sizeof(i_word)) + return PORE_ERR_FETCH; + *size += 4; + *ibuf_2 = (uint64_t)i_word << 32; + } + return me; +} + + +struct pore_bus *poreb_create_pore2fi2c(pore_model_t p, + const char *name, + struct pore_bus *fi2c0, + struct pore_bus *fi2c1, + struct pore_bus *fi2c2) +{ + struct pore_bus *b; + + b = poreb_create(name, 0, fi2c_read, fi2c_write, fi2c_fetch, NULL); + if (!b) + return NULL; + + b->slaves[0] = fi2c0; + b->slaves[1] = fi2c1; + b->slaves[2] = fi2c2; + b->pore = p; + + return b; +} + +/*** PIB slave to implement self-scomming functionality **********************/ + +static int selfscom_read(struct pore_bus *b, uint64_t addr, + uint8_t *buf, unsigned int len, + int *err_code) +{ + uint64_t *val64 = (uint64_t *)buf; + PibAddress pib_addr, *pore_addr = (PibAddress *)poreb_get_priv(b); + + pib_addr.val = addr; + if ((pib_addr.chiplet_id != pore_addr->chiplet_id) || + (pib_addr.prv_port != pore_addr->prv_port)) + return PORE_ERR_NOACK; + + if (!b->pore) + return PORE_ERR_NOACK; + + switch (addr & 0xffff) { + /* vPORe register - self-scomming */ + case PORE_R_STATUS: + case PORE_R_CONTROL: + case PORE_R_RESET: + case PORE_R_ERROR_MASK: + case PORE_R_PRV_BASE_ADDR0: + case PORE_R_PRV_BASE_ADDR1: + case PORE_R_OCI_MEMORY_BASE_ADDR0: + case PORE_R_OCI_MEMORY_BASE_ADDR1: + case PORE_R_TABLE_BASE_ADDR: + case PORE_R_EXE_TRIGGER: + case PORE_R_SCRATCH0: + case PORE_R_SCRATCH1: + case PORE_R_SCRATCH2: + case PORE_R_IBUF_01: + case PORE_R_IBUF_2: + case PORE_R_DBG0: + case PORE_R_DBG1: + case PORE_R_PC_STACK0: + case PORE_R_PC_STACK1: + case PORE_R_PC_STACK2: + case PORE_R_ID_FLAGS: + case PORE_R_DATA0: + case PORE_R_MEM_RELOC: + case PORE_R_I2C_E0_PARAM: + case PORE_R_I2C_E1_PARAM: + case PORE_R_I2C_E2_PARAM: + *val64 = pore_readReg(b->pore, (pore_reg_t)(addr & 0xff), + PORE_BITS_0_63); + *err_code = PORE_PCB_SUCCESS; + return len; + } + + return PORE_ERR_NOACK; +} + +static int selfscom_write(struct pore_bus *b, uint64_t addr, + const uint8_t *buf, unsigned int len, + int *err_code) +{ + uint64_t *val64 = (uint64_t *)buf; + PibAddress pib_addr, *pore_addr = (PibAddress *)poreb_get_priv(b); + + pib_addr.val = addr; + if ((pib_addr.chiplet_id != pore_addr->chiplet_id) || + (pib_addr.prv_port != pore_addr->prv_port)) + return PORE_ERR_NOACK; + + if (!b->pore) + return PORE_ERR_NOACK; + + switch (addr & 0xffff) { + /* vPORe register - self-scomming */ + case PORE_R_STATUS: + case PORE_R_CONTROL: + case PORE_R_RESET: + case PORE_R_ERROR_MASK: + case PORE_R_PRV_BASE_ADDR0: + case PORE_R_PRV_BASE_ADDR1: + case PORE_R_OCI_MEMORY_BASE_ADDR0: + case PORE_R_OCI_MEMORY_BASE_ADDR1: + case PORE_R_TABLE_BASE_ADDR: + case PORE_R_EXE_TRIGGER: + case PORE_R_SCRATCH0: + case PORE_R_SCRATCH1: + case PORE_R_SCRATCH2: + case PORE_R_IBUF_01: + case PORE_R_IBUF_2: + case PORE_R_DBG0: + case PORE_R_DBG1: + case PORE_R_PC_STACK0: + case PORE_R_PC_STACK1: + case PORE_R_PC_STACK2: + case PORE_R_ID_FLAGS: + case PORE_R_DATA0: + case PORE_R_MEM_RELOC: + case PORE_R_I2C_E0_PARAM: + case PORE_R_I2C_E1_PARAM: + case PORE_R_I2C_E2_PARAM: + pore_writeReg(b->pore, (pore_reg_t)(addr & 0xff), + *val64, PORE_BITS_0_63); + *err_code = PORE_PCB_SUCCESS; + return len; + } + + return PORE_ERR_NOACK; +} + +struct pore_bus *poreb_create_selfscom(const char *name, + unsigned int chiplet_id, + unsigned int prv_port) +{ + struct pore_bus *b; + PibAddress *pib_addr; + + b = poreb_create(name, sizeof(*pib_addr), selfscom_read, + selfscom_write, NULL, NULL); + if (!b) + return NULL; + pib_addr = (PibAddress *)poreb_get_priv(b); + pib_addr->val = 0; + pib_addr->chiplet_id = chiplet_id; + pib_addr->prv_port = prv_port; + + return b; +} + +/*** Generic Bus functionality ***********************************************/ + +static int __poreb_read(struct pore_bus *b, uint64_t addr, + uint8_t *buf, unsigned int len, + int *err_code) +{ + int last_rc = PORE_ERR_NOACK, good_rcs = 0, rc = 0; + unsigned int i; + + for (i = 0; i < PORE_MAX_BUS; i++) { + struct pore_bus *s = b->slaves[i]; + + if (s == NULL) + continue; + + /* We expect PORE_ERR_NOACK if slave is ok, but not + * responsible for this transfer. If anything else is + * returned the first one has it, else try another + * slave. + */ + rc = poreb_read(s, addr, buf, len, err_code); + if (rc != PORE_ERR_NOACK) { + last_rc = rc; + good_rcs++; + + return last_rc; /* FIXME Do not return!!! */ + } + } + if (good_rcs > 1) { + BUG(); + return PORE_ERR_BUS_COLLISION; + } + + return last_rc; +} + + +static int __poreb_write(struct pore_bus *b, uint64_t addr, + const uint8_t *buf, unsigned int len, + int *err_code) +{ + int last_rc = PORE_ERR_NOACK, good_rcs = 0, rc = 0; + unsigned int i; + + for (i = 0; i < PORE_MAX_BUS; i++) { + struct pore_bus *s = b->slaves[i]; + + if (s == NULL) + continue; + + /* We expect PORE_ERR_NOACK if slave is ok, but not + * responsible for this transfer. If anything else is + * returned the first one has it, else try another + * slave. + */ + rc = poreb_write(s, addr, buf, len, err_code); + if (rc != PORE_ERR_NOACK) { + last_rc = rc; + good_rcs++; + + return last_rc; /* FIXME Do not return!!! */ + } + } + if (good_rcs > 1) { + BUG(); + return PORE_ERR_BUS_COLLISION; + } + + return last_rc; +} + +void poreb_destroy(pore_bus_t b) +{ + unsigned int i; + + if (!b) return; + for (i = 0; i < PORE_MAX_BUS; i++) { + if (b->slaves[i]) + poreb_destroy(b->slaves[i]); + } + free(b); +} + +struct pore_bus * +poreb_create(const char *name, size_t priv_data_size, + poreb_read_f r, poreb_write_f w, + poreb_fetch_f f, poreb_reset_f R) +{ + struct pore_bus *b; + + b = (struct pore_bus *)malloc(sizeof(*b) + priv_data_size); + if (!b) + return NULL; + memset(b, 0, sizeof(*b) + priv_data_size); + + b->name = name; + b->read = (r) ? (r) : (__poreb_read); + b->write = (w) ? (w) : (__poreb_write); + b->fetch = (f) ? (f) : (NULL); + b->reset = (R) ? (R) : (NULL); + + return b; +} + +int poreb_read(pore_bus_t b, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code) +{ + if (!b) + return PORE_ERR_INVALID_PARAM; + if (!b->read) + return PORE_ERR_NOT_IMPLEMENTED; + return b->read(b, addr, buf, size, err_code); +} + +int poreb_write(pore_bus_t b, uint64_t addr, const uint8_t *buf, + unsigned int size, int *err_code) +{ + if (!b) + return PORE_ERR_INVALID_PARAM; + if (!b->write) + return PORE_ERR_NOT_IMPLEMENTED; + return b->write(b, addr, buf, size, err_code); +} + +int poreb_fetch(pore_bus_t b, uint64_t pc, uint64_t *i_buf01, + uint64_t *i_buf2, unsigned int *size, int *err_code) +{ + if (!b) + return PORE_ERR_INVALID_PARAM; + if (!b->fetch) + return PORE_ERR_NOT_IMPLEMENTED; + return b->fetch(b, pc, i_buf01, i_buf2, size, err_code); +} + +int poreb_reset(pore_bus_t p) +{ + if (!p) + return PORE_ERR_INVALID_PARAM; + if (!p->reset) + return PORE_ERR_NOT_IMPLEMENTED; + return p->reset(p); +} + +int poreb_attach_slave(struct pore_bus *b, struct pore_bus *s) +{ + unsigned int i; + + for (i = 0; i < PORE_MAX_BUS; i++) { + if (!b->slaves[i]) { + b->slaves[i] = s; + return 0; + } + } + return PORE_ERR_NOSPACE; +} diff --git a/src/usr/pore/poreve/pore_model/ibuf/pore_fi2c.c b/src/usr/pore/poreve/pore_model/ibuf/pore_fi2c.c new file mode 100644 index 000000000..943751d86 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/ibuf/pore_fi2c.c @@ -0,0 +1,550 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/ibuf/pore_fi2c.c $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +/****************************************************************************** + * + * Virtual PORe Engine + * + *****************************************************************************/ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "pore_model.h" +#include "pore_ibuf.h" +#include "pore_regs.h" + +/// \enum FastI2cState +/// +/// The state of the controller. Sequences of register operations are +/// only allowed in a prescribed sequence, depending on the state of the +/// controller. The ERROR state represents a bug in the model and is +/// non-recoverable. + +typedef enum { + ERROR = 0, + IDLE = 1, + ADDRESS_WRITE_ONGOING = 2, + DATA_READ_ONGOING = 3, + DATA_AVAILABLE = 4, + WRITE_DATA_EXPECTED = 5, + DATA_WRITE_ONGOING = 6 +} FastI2cState; + +#define COMMAND_COMPLETION 3 /* command completion timeout */ + +struct fi2c { + pore_bus_t bus; + + uint8_t *mem_buf; /* memory used to emulate data access */ + unsigned int mem_size; /* maximum size of attached memory */ + unsigned int mem_start; /* memory start offset in address space */ + unsigned int address; /* read/write offset */ + uint64_t i2c_en_param_reg; /* figure out if transfer was for us */ + + unsigned int prv_port; /* pervasive port number */ + size_t addressBytes; /* address bytes used, must match request */ + + unsigned int i2c_port; /* i2c port; a master can support multiple */ + unsigned int deviceAddress; /* One FI2C can serve multiple + i2c_port/deviceAddress + combinations aka memory + areas. Support only one for + now. */ + unsigned int command_completion; + + FastI2cState state; + fasti2c_control_reg control; + fasti2c_status_reg status; + uint64_t fifo; /* Data is left-justified in this reg. */ +}; + +/* Memory Access */ + +static int mem_addressWrite(struct fi2c *p, size_t i_bytes, uint32_t i_address) +{ + if (i_bytes != p->addressBytes) { + BUG(); + p->state = ERROR; + return PORE_ERR_I2CMEMORY_ILLEGAL_ADDR; + } + p->address = i_address; + return i_bytes; +} + +/** + * We keep everything outside the PORe model big endian and turn it + * into host-byteorder when reading it in or vice versa when writing + * it out. + */ +static int mem_dataRead(struct fi2c *p, size_t i_bytes, uint64_t *o_data) +{ + unsigned int mem_offs = p->address - p->mem_start; + + if ((p->address < p->mem_start) || + (mem_offs + i_bytes > p->mem_size)) { + BUG(); + p->state = ERROR; + return PORE_ERR_I2CMEMORY_ILLEGAL_ADDR; + } + + switch (i_bytes) { + case 4: + *o_data = pore_be32toh(*((uint32_t *)&p->mem_buf[mem_offs])); + break; + case 8: + *o_data = pore_be64toh(*((uint64_t *)&p->mem_buf[mem_offs])); + break; + default: + return PORE_ERR_INVALID_PARAM; + } + + p->address += i_bytes; + return i_bytes; +} + + +static int mem_dataWrite(struct fi2c *p, size_t i_bytes, uint64_t i_data) +{ + unsigned int mem_offs = p->address - p->mem_start; + + if ((p->address < p->mem_start) || + (mem_offs + i_bytes > p->mem_size)) { + BUG(); + p->state = ERROR; + return PORE_ERR_I2CMEMORY_ILLEGAL_ADDR; + } + + switch (i_bytes) { + case 4: + *((uint32_t *)&p->mem_buf[mem_offs]) = pore_htobe32(i_data); + break; + case 8: + *((uint64_t *)&p->mem_buf[mem_offs]) = pore_htobe64(i_data); + break; + default: + return PORE_ERR_INVALID_PARAM; + } + + p->address += i_bytes; + return i_bytes; +} + +static uint32_t getI2cAddress(fasti2c_control_reg *control) +{ + size_t addressBytes = control->address_range; + return (control->val & 0xffffffff) >> ((4 - addressBytes) * 8); +} + +// The address is left-justified in the low-order 32 bits of the control +// register. + +static int addressWrite(struct fi2c *p) +{ + int me; + unsigned i2c_port = p->control.port_number; + unsigned deviceAddress = p->control.device_address; + size_t addressBytes = p->control.address_range; + + if ((p->i2c_port != i2c_port) || (p->deviceAddress != deviceAddress)) { + BUG(); + return PORE_ERR_NOT_MAPPED_ON_FASTI2C; + } + + me = mem_addressWrite(p, addressBytes, getI2cAddress(&p->control)); + p->state = ADDRESS_WRITE_ONGOING; + return me; +} + + +static int dataRead(struct fi2c *p) +{ + int me; + unsigned i2c_port = p->control.port_number; + unsigned deviceAddress = p->control.device_address; + size_t dataBytes = p->control.data_length; + uint64_t data = 0; + + if ((p->i2c_port != i2c_port) || (p->deviceAddress != deviceAddress)) { + BUG(); + return PORE_ERR_NOT_MAPPED_ON_FASTI2C; + } + + me = mem_dataRead(p, dataBytes, &data); + p->fifo = data << (64 - (dataBytes * 8)); + p->state = DATA_READ_ONGOING; + return me; +} + +// For addresses < 4 bytes, the first slug of data occupies the +// remainder of the low-order word of the control register. Any +// remaining bytes come in on the next transaction targeting the data +// register. This code assumes 8-byte only data writes. + +static int initialDataWrite(struct fi2c *p) +{ + unsigned addressBytes = p->control.address_range; + + if (addressBytes < 4) { + p->fifo = BE64_GET_FIELD(p->control.val & 0xffffffff, + 32 + (addressBytes * 8), 63) + << (64 - (4 - addressBytes) * 8); + } + p->state = WRITE_DATA_EXPECTED; + return PORE_SUCCESS; +} + +// Assume 8-byte only write transactions + +static int finalDataWrite(struct fi2c *p, const uint8_t *buf, unsigned int len) +{ + int me; + unsigned i2c_port = p->control.port_number; + unsigned deviceAddress = p->control.device_address; + size_t addressBytes = p->control.address_range; + uint64_t i_data, i_merge; + + if ((p->i2c_port != i2c_port) || (p->deviceAddress != deviceAddress)) { + BUG(); + return PORE_ERR_NOT_MAPPED_ON_FASTI2C; + } + i_data = *(uint64_t *)buf; + i_merge = BE64_GET_FIELD(i_data, 0, (8 - addressBytes) * 8 - 1); + p->fifo = BE64_SET_FIELD(p->fifo, /* target */ + addressBytes * 8, /* begin */ + 63, /* end */ + i_merge); + + me = mem_dataWrite(p, len, p->fifo); + p->state = DATA_WRITE_ONGOING; + return me; +} + +// Modeling notes: +// +// o The RESET register is not modeled here +// +// o Our models ignore the I2C Speed +// +// o Transactions complete in 0 time and polling always succeeds on the first +// read of the status register. This is done to simplify the PORE +// engine model. +// +// o Only the follwing types of control register actions are modeled: +// * Address write : with_start; with_address; !with_continue; with_stop; +// data_length == 0 +// * Data read : with_start; with_address; !with_continue; with_stop; +// data_length == [4,8] +// * Data write : with_start; with_address; !with_continue; with_stop; +// data_length == 8 +// +// o The memory models hold the last address written +// +// o Redundant reads of the STATUS register are allowed +// +// o PORE only does 4/8 byte reads and 8 byte writes, so any other data +// access is considered an error (although the models could easily be +// extended to allow them). + +static int fi2c_read(struct pore_bus *b, uint64_t addr, + uint8_t *buf, unsigned int len, + int *err_code) +{ + int rc = PORE_FAILURE; + PibAddress pib_addr; + struct fi2c *p = (struct fi2c *)poreb_get_priv(b); + + iprintf(b->pore, " %-12s: %s(%p, 0x%llx, %p, %x)\n", + b->name, __func__, b, (long long)addr, buf, len); + + /* SBE has: prv_port 0xa SEEPROM 2 byte addresses + * " 0x1 OTP 2 byte addresses + * " 0xb PNOR 4 byte addresses + * + * This is adjusted in the i2c_en_param_reg in the fields + * i2c_engine_identifier == prv_port and + * i2c_engine_address_range == addressBytes. + * + * All FI2CMs are in the pervasive chiplet which has 0x0. + */ + pib_addr.val = addr; + if ((pib_addr.chiplet_id != 0x0) || (pib_addr.prv_port != p->prv_port)) + return PORE_ERR_NOACK; /* not for this fi2cm */ + + switch (pib_addr.local_addr) { + + case FASTI2C_CONTROL_OFFSET: + p->state = ERROR; + rc = PORE_ERR_WRITE_ONLY_REGISTER; + break; + + case FASTI2C_STATUS_OFFSET: + if (len != 8) { + rc = PORE_ERR_INVALID_PARAM; + break; + } + + switch (p->state) { + + case ADDRESS_WRITE_ONGOING: + case DATA_WRITE_ONGOING: + p->command_completion++; /* simulate access duration */ + if (p->command_completion < COMMAND_COMPLETION) { + p->status.val = 0; + *(uint64_t *)buf = p->status.val; + rc = len; + break; + } + + p->command_completion = 0; + p->status.val = 0; + p->status.i2c_command_complete = 1; + *(uint64_t *)buf = p->status.val; + p->state = IDLE; + rc = len; + break; + + case DATA_READ_ONGOING: + + p->command_completion++; /* simulate access duration */ + if (p->command_completion < COMMAND_COMPLETION) { + p->status.val = 0; + *(uint64_t *)buf = p->status.val; + rc = len; + break; + } + + p->command_completion = 0; + p->status.val = 0; + p->status.i2c_command_complete = 1; + p->status.i2c_fifo_entry_count = + p->control.data_length; + *(uint64_t *)buf = p->status.val; + p->state = DATA_AVAILABLE; + rc = len; + break; + + case IDLE: + *(uint64_t *)buf = p->status.val; + rc = len; + break; + + default: + BUG(); + p->state = ERROR; + rc = PORE_ERR_FASTI2C_SEQUENCE_ERROR; + break; + } + break; + + case FASTI2C_DATA_OFFSET: + switch (p->state) { + + case DATA_AVAILABLE: + rc = len; + switch (len) { + case 4: *(uint32_t *)buf = (uint32_t)p->fifo; break; + case 8: *(uint64_t *)buf = (uint64_t)p->fifo; break; + default: + rc = PORE_ERR_INVALID_PARAM; + break; + } + p->state = IDLE; + break; + + default: + BUG(); + p->state = ERROR; + rc = PORE_ERR_FASTI2C_SEQUENCE_ERROR; + break; + } + break; + + default: + return PORE_ERR_NOACK; /* not for this fi2cm */ + } + + *err_code = PORE_PCB_SUCCESS; + return rc; +} + + +static int fi2c_write(struct pore_bus *b, uint64_t addr, + const uint8_t *buf, unsigned int len, + int *err_code) +{ + int rc = PORE_FAILURE; + PibAddress pib_addr; + struct fi2c *p = (struct fi2c *)poreb_get_priv(b); + + iprintf(b->pore, " %-12s: %s(%p, 0x%llx, %p, %x)\n", + b->name, __func__, b, (long long)addr, buf, len); + + /* SBE has: prv_port 0xa SEEPROM 2 byte addresses + * " 0x1 OTP 2 byte addresses + * " 0xb PNOR 4 byte addresses + * + * This is adjusted in the i2c_en_param_reg in the fields + * i2c_engine_identifier == prv_port and + * i2c_engine_address_range == addressBytes. + * + * All FI2CMs are in the pervasive chiplet which has 0x0. + */ + pib_addr.val = addr; + if ((pib_addr.chiplet_id != 0x0) || (pib_addr.prv_port != p->prv_port)) + return PORE_ERR_NOACK; /* not for this fi2cm */ + + switch (pib_addr.local_addr) { + + case FASTI2C_CONTROL_OFFSET: + if (len != 8) { + rc = PORE_ERR_INVALID_PARAM; + break; + } + if (p->state != IDLE) { + BUG(); + p->state = ERROR; + rc = PORE_ERR_FASTI2C_SEQUENCE_ERROR; + break; + } + + p->control.val = *(uint64_t *)buf; + + if (!p->control.with_start || + !p->control.with_address || + p->control.read_continue || + !p->control.with_stop) { + BUG(); + p->state = ERROR; + rc = PORE_ERR_FASTI2C_CONTROL_ERROR; + break; + } + + if (p->control.read_not_write == 0) { + if (p->control.address_range == 0) { + BUG(); + p->state = ERROR; + rc = PORE_ERR_FASTI2C_CONTROL_ERROR; + break; + } + if (p->control.data_length == 0) { + rc = addressWrite(p); + if (rc < 0) + break; + rc = len; + break; + } + if (p->control.data_length != 8) { + BUG(); + p->state = ERROR; + rc = PORE_ERR_FASTI2C_CONTROL_ERROR; + break; + } + rc = initialDataWrite(p); + if (rc == PORE_SUCCESS) + rc = len; + break; + + } else { + if ((p->control.data_length != 4) && + (p->control.data_length != 8)) { + BUG(); + p->state = ERROR; + rc = PORE_ERR_FASTI2C_CONTROL_ERROR; + break; + } + rc = dataRead(p); + break; + } + break; + + case FASTI2C_STATUS_OFFSET: + BUG(); + p->state = ERROR; + rc = PORE_ERR_READ_ONLY_REGISTER; + break; + + case FASTI2C_DATA_OFFSET: + if (len != 8) { + rc = PORE_ERR_INVALID_PARAM; + break; + } + + switch (p->state) { + + case WRITE_DATA_EXPECTED: + rc = finalDataWrite(p, buf, 8); + p->state = DATA_WRITE_ONGOING; + break; + + default: + BUG(); + p->state = ERROR; + rc = PORE_ERR_FASTI2C_SEQUENCE_ERROR; + break; + } + break; + + default: + return PORE_ERR_NOACK; /* not for this fi2cm */ + } + + *err_code = PORE_PCB_SUCCESS; + return rc; +} + +struct pore_bus *poreb_create_fi2c(const char *name, + uint8_t *mem_buf, + unsigned int mem_size, + unsigned int mem_start, + unsigned int prv_port, + unsigned int address_bytes, + unsigned int i2c_port, + unsigned int deviceAddress) +{ + struct pore_bus *b; + struct fi2c *e; + + b = poreb_create(name, sizeof(*e), fi2c_read, fi2c_write, + NULL, NULL); + if (!b) + return NULL; + + e = (struct fi2c *)poreb_get_priv(b); + e->bus = b; + e->mem_buf = mem_buf; + e->mem_size = mem_size; + e->mem_start = mem_start; + e->address = 0; + + e->prv_port = prv_port; + e->addressBytes = address_bytes; + + e->i2c_port = i2c_port; + e->deviceAddress = deviceAddress; + e->command_completion = 0; + e->state = IDLE; + + return b; +} diff --git a/src/usr/pore/poreve/pore_model/ibuf/pore_fi2c.h b/src/usr/pore/poreve/pore_model/ibuf/pore_fi2c.h new file mode 100644 index 000000000..6284e3648 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/ibuf/pore_fi2c.h @@ -0,0 +1,47 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/ibuf/pore_fi2c.h $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __PORE_FI2C_H__ +#define __PORE_FI2C_H__ + +/****************************************************************************** + * + * Virtual PORe Engine + * + *****************************************************************************/ + +#include <stdint.h> + +/* FIXME An I2C controller can support more than one ports and it can + * also have more than one device listening on one of those. Just like + * real world I2C busses connected to an I2C master with an output + * multiplexor. For our purpose one i2c_port with one device address + * is enough. + */ +struct pore_bus *poreb_create_fi2c(const char *name, uint8_t *mem_buf, + unsigned int mem_size, + unsigned int prv_port, + unsigned int address_bytes, + unsigned int i2c_port, + unsigned int deviceAddress); + +#endif /* __PORE_FI2C_H__ */ diff --git a/src/usr/pore/poreve/pore_model/ibuf/pore_ibuf.h b/src/usr/pore/poreve/pore_model/ibuf/pore_ibuf.h new file mode 100644 index 000000000..33f9bc30f --- /dev/null +++ b/src/usr/pore/poreve/pore_model/ibuf/pore_ibuf.h @@ -0,0 +1,222 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/ibuf/pore_ibuf.h $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __PORE_IBUF_H__ +#define __PORE_IBUF_H__ + +/****************************************************************************** + * + * Virtual PORe Engine + * + *****************************************************************************/ + +#include <stdint.h> +#include <stdio.h> +#include <stdarg.h> + +#include "pore_regs.h" +#include "pore_model.h" +#include "pore_wrap.h" +#include "pore_inline_decode.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// \brief Bit manipulation for Big-Endian data + +/// A bit mask for a range of bits in a big-endian uint64_t +#define BE64_MASK(begin, end) \ + ((0xffffffffffffffffull >> (64 - ((end) - (begin) + 1))) << (63 - (end))) + +/// A single bit mask for a big-endian uint64_t +#define BE64_BIT(n) (BE64_MASK((n), (n))) + +/// Extract an unsigned field from a uint64_t +#define BE64_GET_FIELD(x, begin, end) \ + (((x) & BE64_MASK((begin), (end))) >> (63 - (end))) + +/// Update an unsigned field in a uint64_t from a right-justified +/// uint64_t value +#define BE64_SET_FIELD(x, begin, end, val) \ + ((((val) << (63 - (end))) & BE64_MASK((begin), (end))) | \ + ((x) & ~BE64_MASK((begin), (end)))) + +/// A bit mask for a range of bits in a big-endian uint32_t +#define BE32_MASK(begin, end) \ + ((0xffffffff >> (32 - ((end) - (begin) + 1))) << (31 - (end))) + +/// A single bit mask for a big-endian uint32_t +#define BE32_BIT(n) (BE32_MASK((n), (n))) + +/// Extract an unsigned field from a uint32_t +#define BE32_GET_FIELD(x, begin, end) \ + (((x) & BE32_MASK((begin), (end))) >> (31 - (end))) + +/// Update an unsigned field in a uint32_t from a right-justified +/// uint32_t value +#define BE32_SET_FIELD(x, begin, end, val) \ + ((((val) << (31 - (end))) & BE32_MASK((begin), (end))) | \ + ((x) & ~BE32_MASK((begin), (end)))) + +// State Definitions. These are the values of the status register +// 'State machine current state' field, that includes the PORE state +// machine state as bits 3:6. When the PORE is running, we report it +// as being in state EXEC. ABR is the address breakpoint state. + +#define PORE_STATE_WAIT 0x02 +#define PORE_STATE_EXEC 0x0e +#define PORE_STATE_ABR 0x16 + +/// The number of PORE error vectors +#define PORE_ERROR_VECTORS 5 + +/// The number of PORE EXE vectors +#define PORE_EXE_VECTORS 16 + +/// The size of a PORE BRAI instruction in bytes +#define PORE_VECTOR_SIZE 12 + +/// Branch modes for Hook implementation +#define FORCED_BRANCH_DISALLOWED 0 +#define FORCED_BRANCH_FETCH_HOOK 1 +#define FORCED_BRANCH_HOOK_INSTRUCTION 2 + +/* Main data of the pore_model hidden from the users */ +struct pore_model { + /* PORe State (for backup/restore) ----------------------------------*/ + pore_status_reg status; /* 0x00000000 */ + pore_control_reg control; /* 0x00000008 */ + pore_reset_reg reset; /* 0x00000010 */ + pore_error_mask_reg error_mask; /* 0x00000018 */ + pore_prv_base_address_reg prv_base[2]; /* 0x00000020 * + * 0x00000028 */ + pore_oci_base_address_reg oci_base[2]; /* 0x00000030 + * 0x00000038 */ + pore_table_base_addr_reg table_base_addr; /* 0x00000040 */ + pore_exe_trigger_reg exe_trigger; /* 0x00000048 */ + pore_scratch0_reg scratch0; /* 0x00000050 */ + uint64_t scratch1; /* 0x00000058 */ + uint64_t scratch2; /* 0x00000060 */ + pore_ibuf_01_reg ibuf_01; /* 0x00000068 */ + pore_ibuf_2_reg ibuf_2; /* 0x00000070 */ + pore_dbg0_reg dbg0; /* 0x00000078 */ + pore_dbg1_reg dbg1; /* 0x00000080 */ + pore_pc_stack0_reg pc_stack[3]; /* 0x00000088 * + * 0x00000090 * + * 0x00000098 */ + pore_id_flags_reg id_flags; /* 0x000000a0 */ + uint64_t data0; /* 0x000000a8 */ + pore_memory_reloc_reg memory_reloc; /* 0x000000b0 */ + pore_i2c_en_param_reg i2c_e_param[3]; /* 0x000000b8 * + * 0x000000c0 * + * 0x000000c8 */ + uint64_t branchTaken; /* last ins branch? pc updated? d0 */ + uint64_t broken; /* in case we ran on a breakpoint d8 */ + uint32_t oci_fetchBufferValid; /* 0x000000e0 */ + uint32_t oci_fetchBufferCursor; + uint64_t oci_fetchBuffer; /* 0x000000e8 */ + /* backup state ends here ------------------------------------------ */ + + const char *name; + void *priv; + int state; + int err_code; + uint64_t trace_flags; + + /* disassembler support */ + unsigned int opcode_len; + PoreInlineDecode dis; + + int enableTrap; /* FIXME discuss this interface */ + int singleStep; /* FIXME discuss this interface */ + uint64_t stack_pointer; + + /* Hook support */ + uint64_t forcedPc; + int forcedBranch; /* FIXME discuss this interface */ + int forcedBranchMode; /* FIXME discuss this interface */ + + int enableHookInstruction; + instrHook_f instrHook; + + int enableAddressHooks; + readHook_f readHook; + writeHook_f writeHook; + fetchHook_f fetchHook; + decodeHook_f decodeHook; + + waitCallback_f waitCallback; + errorCallback_f errorCallback; + errorCallback_f fatalErrorCallback; + + /* address translation objects */ + struct pore_bus *pib; /* Pervasive Interconnect Bus */ + struct pore_bus *mem; /* OCI or FI2C */ +}; + +/* address conversion from pore to oci */ +struct pore_bus *poreb_create_pore2oci(struct pore_model *pore, + const char *name, + struct pore_bus *oci); + +/* attach the three fi2c-masters to the pore-model */ +struct pore_bus *poreb_create_pore2fi2c(struct pore_model *pore, + const char *name, + struct pore_bus *fi2c0, + struct pore_bus *fi2c1, + struct pore_bus *fi2c2); + +/* fast i2cm connected to pib bus */ +struct pore_bus *poreb_create_fi2cm(struct pore_model *pm, const char *name, + pore_bus_t pib, + pore_i2c_en_param_reg *i2c_param); + +int pore_handleErrEvent(pore_model_t p, int error_in, int model_err); + +/** + * @brief Attach PIB bus to PORe model. + * + * @param [in] p reference to PORe model + * @param [in] b referenct to PIB bus-object + */ +int pore_attach_pib (pore_model_t p, struct pore_bus *b); + +/** + * @brief Direct read access to PIB bus e.g. for fi2cm or scand + * operations. + */ +int pore_pib_read (pore_model_t p, uint64_t pib_addr, uint8_t *buf, + unsigned int len, int *err_code); + +/** + * @brief Direct write access to PIB bus e.g. for fi2cm or scand + * operations. + */ +int pore_pib_write (pore_model_t p, uint64_t pib_addr, const uint8_t *buf, + unsigned int len, int *err_code); + +#ifdef __cplusplus +} +#endif + +#endif /* __PORE_IBUF_H__ */ diff --git a/src/usr/pore/poreve/pore_model/ibuf/pore_inline_decode.c b/src/usr/pore/poreve/pore_model/ibuf/pore_inline_decode.c new file mode 100644 index 000000000..d2574fa80 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/ibuf/pore_inline_decode.c @@ -0,0 +1,129 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/ibuf/pore_inline_decode.c $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#include <stdint.h> +#include "pore_inline_decode.h" + +// From a uint32_t, extract a big-endian bit x[i] as either 0 or 1 + +#define BE_BIT_32(x, i) (((x) >> (31 - (i))) & 1) + + +// From a uint32_t, extract big-endian bits x[first:last] as unsigned to +// create a uint32_t. + +#define BE_BITS_32_UNSIGNED(x, first, last) \ + (((x) >> (31 - (last))) & (0xffffffff >> (32 - (last - first + 1)))) + + +// From a uint32_t, extract big-endian bits x[first:last] as signed to create +// an int32_t. + +#define BE_BITS_32_SIGNED(x, first, last) \ + (((x) & (1 << (31 - (first)))) ? \ + (BE_BITS_32_UNSIGNED(x, first, last) | (0xffffffff << (31 - first))) : \ + BE_BITS_32_UNSIGNED(x, first, last)) + +/// Install and decode an instruction into the PoreInlineDissassembly object +/// +/// \param dis A PoreInlineDisassembly structure to contain the disassembled +/// instruction. +/// +/// \param instruction The initial (or only) 32 bits of a PORE instruction +/// +/// For simplicity, instructions are currently (almost) fully decoded for all +/// possible formats. It is up to the application using this API to further +/// decode the actual opcode to determine which of these fields are valid for +/// the current instruction. +/// +/// To simplify parity calculations the \a imd64 field is cleared here. A +/// companion API pore_inline_decode_imd64() is used to decode the final 64 +/// bits of long instructions. +/// +/// This API is designed to be called independently of the full disassembler, +/// in which case any fields of \a dis not explicitly set will be undefined. + +void +pore_inline_decode_instruction(PoreInlineDecode *dis, uint32_t instruction) +{ + dis->instruction = instruction; + + // Generic decoding + dis->opcode = BE_BITS_32_UNSIGNED(instruction, 0, 6); + dis->long_instruction = BE_BIT_32(instruction, 0); + dis->parity = BE_BITS_32_UNSIGNED(instruction, 7, 7); + dis->memory_space = BE_BIT_32(instruction, 8); + dis->update = BE_BIT_32(instruction, 8); + dis->capture = BE_BIT_32(instruction, 9); + dis->imd16 = BE_BITS_32_SIGNED(instruction, 16, 31); + dis->scan_length = BE_BITS_32_UNSIGNED(instruction, 16, 31); + dis->imd20 = BE_BITS_32_SIGNED(instruction, 12, 31); + dis->imd24 = dis->ima24 = BE_BITS_32_UNSIGNED(instruction, 8, 31); + dis->impco20 = BE_BITS_32_SIGNED(instruction, 12, 31); + dis->impco24 = BE_BITS_32_SIGNED(instruction, 8, 31); + dis->tR = dis->r0 = BE_BITS_32_UNSIGNED(instruction, 8, 11); + dis->sR = dis->r1 = BE_BITS_32_UNSIGNED(instruction, 12, 15); + dis->imd64 = 0; + + // imA24 decoding + if (dis->memory_space) { + dis->base_register = + BE_BIT_32(instruction, 9) ? + PORE_OCI_MEMORY_BASE_ADDR1_ENC : + PORE_OCI_MEMORY_BASE_ADDR0_ENC; + + dis->memory_offset = + BE_BITS_32_UNSIGNED(dis->instruction, 10, 31); + } else { + dis->base_register = + BE_BIT_32(instruction, 9) ? + PORE_PRV_BASE_ADDR1_ENC : + PORE_PRV_BASE_ADDR0_ENC; + + dis->pib_offset = + BE_BITS_32_UNSIGNED(dis->instruction, 12, 31); + } +} + + +/// Install and decode an imd64 into a PoreInlineDissassembly object +/// +/// \param dis A PoreInlineDisassembly structure to contain the disassembled +/// data +/// +/// \param imd64 The final 64 bits of a 12-byte PORE instruction +/// +/// For simplicity, instructions are currently (almost) fully decoded for all +/// possible formats. It is up to the application to determine which if any of +/// these fields are valid for the current instruction. +/// +/// This API is designed to be called independently of the full disassembler, +/// in which case any fields of \a dis not explicitly set will be undefined. + +void +pore_inline_decode_imd64(PoreInlineDecode *dis, uint64_t imd64) +{ + dis->imd64 = imd64; + dis->impc48 = dis->imd64 & 0xffffffffffffull; + dis->scan_select = imd64 >> 32; + dis->scan_offset = imd64 & 0xffffffff; +} diff --git a/src/usr/pore/poreve/pore_model/ibuf/pore_inline_decode.h b/src/usr/pore/poreve/pore_model/ibuf/pore_inline_decode.h new file mode 100644 index 000000000..d34317903 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/ibuf/pore_inline_decode.h @@ -0,0 +1,207 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/ibuf/pore_inline_decode.h $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __PORE_INLINE_DECODE_H__ +#define __PORE_INLINE_DECODE_H__ + +#include <stdint.h> +#include "pore_inline_decode.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* latest definitions can be found in pgas.h */ +#define PORE_OPCODE_NOP 0x0f +#define PORE_OPCODE_WAIT 0x01 +#define PORE_OPCODE_TRAP 0x02 +#define PORE_OPCODE_HOOK 0x4f + +#define PORE_OPCODE_BRA 0x10 +#define PORE_OPCODE_BRAZ 0x12 +#define PORE_OPCODE_BRANZ 0x13 +#define PORE_OPCODE_BRAI 0x51 +#define PORE_OPCODE_BSR 0x14 +#define PORE_OPCODE_BRAD 0x1c +#define PORE_OPCODE_BSRD 0x1d +#define PORE_OPCODE_RET 0x15 +#define PORE_OPCODE_CMPBRA 0x56 +#define PORE_OPCODE_CMPNBRA 0x57 +#define PORE_OPCODE_CMPBSR 0x58 +#define PORE_OPCODE_LOOP 0x1f + +#define PORE_OPCODE_ANDI 0x60 +#define PORE_OPCODE_ORI 0x61 +#define PORE_OPCODE_XORI 0x62 + +#define PORE_OPCODE_AND 0x25 +#define PORE_OPCODE_OR 0x26 +#define PORE_OPCODE_XOR 0x27 + +#define PORE_OPCODE_ADD 0x23 +#define PORE_OPCODE_ADDI 0x24 +#define PORE_OPCODE_SUB 0x29 +#define PORE_OPCODE_SUBI 0x28 +#define PORE_OPCODE_NEG 0x2a + +#define PORE_OPCODE_COPY 0x2c +#define PORE_OPCODE_ROL 0x2e + +#define PORE_OPCODE_LOAD20 0x30 +#define PORE_OPCODE_LOAD64 0x71 +#define PORE_OPCODE_SCR1RD 0x32 +#define PORE_OPCODE_SCR1RDA 0x73 +#define PORE_OPCODE_SCR2RD 0x36 +#define PORE_OPCODE_SCR2RDA 0x77 +#define PORE_OPCODE_WRI 0x78 +#define PORE_OPCODE_BS 0x74 +#define PORE_OPCODE_BC 0x75 +#define PORE_OPCODE_SCR1WR 0x39 +#define PORE_OPCODE_SCR2WR 0x3a +#define PORE_OPCODE_SCAND 0x7c + +#ifndef __ASSEMBLER__ + +/* Internal register encodings for the execution engine */ +typedef enum { + PORE_PRV_BASE_ADDR0_ENC = 0x00, + PORE_PRV_BASE_ADDR1_ENC = 0x01, + PORE_OCI_MEMORY_BASE_ADDR0_ENC = 0x02, + PORE_OCI_MEMORY_BASE_ADDR1_ENC = 0x03, + PORE_SCRATCH0_ENC = 0x04, + PORE_SCRATCH1_ENC = 0x05, + PORE_SCRATCH2_ENC = 0x06, + PORE_ERROR_MASK_ENC = 0x07, + /* PORE_MEM_RELOC_ENC = 0x07, */ + PORE_TABLE_BASE_ADDR_ENC = 0x08, + PORE_EXE_TRIGGER_ENC = 0x09, + PORE_DATA0_ENC = 0x0a, + /* PORE_I2C_E0_PARAM_ENC = 0x0b, */ + /* PORE_I2C_E1_PARAM_ENC = 0x0c, */ + /* PORE_I2C_E2_PARAM_ENC = 0x0d, */ + PORE_PC_ENC = 0x0e, + PORE_ALU_IBUF_ID_ENC = 0x0f +} pore_internal_reg_t; + +typedef struct { + + /// The first 32 bits of every instruction + uint32_t instruction; + + /// The opcode; bits 0..6 of the instruction + int opcode; + + // Is this instruction 4 or 12 bytes long; bit 0 of the instruction + int long_instruction; + + // bit 8 of the instruction which is within the ima24 address + int memory_space; + + /// The parity bit; bit 7 of the instruction + int parity; + + /// The register specifier at bits 8..11 of the instruction + /// + /// This register is sometimes called the source, sometimes the target, + /// depending on the opcode. + int tR; + int r0; + + /// The register specifier at bits 12..15 of the instruction + /// + /// This register is always called the 'source' but is named generically + /// here since sometimes the specifier at bits 8..11 is also called a + /// 'source'. + int sR; + int r1; + + /// 'ImD16' is the signed 16-bit immediate for short immediate adds and + /// subtracts. For the rotate instruction this field also contains the + /// rotate count which is either 1, 4, 8, 16 or 32. + int16_t imd16; + + /// 'ImD20' is the 20-bit unsigned immediate for the LOAD20 instruction + int32_t imd20; + + /// 'ImD24' is the 24-bit unsigned immediate for the WAIT instruction + uint32_t imd24; + + /// 'ImA24' is the 24-bit unsigned immediate representing an address + uint32_t ima24; + + /// 'ImD64' is the 64-bit immediate for data immediates and BRAI. This + /// field is only set for 3-word instructions. + uint64_t imd64; + + /// 'ImPCO20' is a signed, 20-bit word offset for branch instructions + int32_t impco20; + + /// 'ImPCO24' is a signed, 24-bit word offset for branch instructions + int32_t impco24; + + /// 'ImPC48' is a signed, 48-bit word offset for branch instructions + int64_t impc48; + + /// This is the base register specifier - either a memory (OCI) base + /// register or a pervasive base register - for Read/Write operations. + int base_register; + + /// This is the 22-bit signed offset for memory (OCI) addressing + int32_t memory_offset; + + /// This field contains the port number and local address portions of the + /// PIB/PCB address for load/store operations that target the PIB/PCB. + /// Note that bits 0..11 will always be 0 in this address. Bits 1..7 (the + /// multicast bit and chiplet id) are sourced from the associated + /// pervasive base register when the instruction executes. + uint32_t pib_offset; + + /// The update bit of the SCAND instruction + int update; + + /// The capture bit of the SCAND instruction + int capture; + + /// The scan length from a SCAND instruction + int scan_length; + + /// The scan select from a SCAND instruction + uint32_t scan_select; + + /// The address offset from a SCAND instruction + uint32_t scan_offset; + +} PoreInlineDecode; + +void +pore_inline_decode_instruction(PoreInlineDecode *dis, uint32_t instruction); + +void +pore_inline_decode_imd64(PoreInlineDecode *dis, uint64_t imd64); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif + +#endif /* __ASSEMBLER__ */ + +#endif /* __PORE_INLINE_DECODE_H__ */ diff --git a/src/usr/pore/poreve/pore_model/ibuf/pore_model.c b/src/usr/pore/poreve/pore_model/ibuf/pore_model.c new file mode 100644 index 000000000..f5306fdb5 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/ibuf/pore_model.c @@ -0,0 +1,3130 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/ibuf/pore_model.c $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +/****************************************************************************** + * + * Virtual PORe Engine + * + *****************************************************************************/ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "pore_regs.h" +#include "pore_ibuf.h" +#include "pore_model.h" +#include "pore_inline_decode.h" + +static int fetch(pore_model_t p); +static int decode(pore_model_t p); +static int execute(pore_model_t p); +static int finishBrokenInstruction(pore_model_t p); + +#define PORE_GET_BITS(X,S,N) \ + ((((~(0xFFFFFFFFFFFFFFFFull >> (N))) >> (S)) \ + & (X)) >> (64 - (S)-(N))) +#define PORE_SET_BITS(Y,X,S,N,V) \ + Y = (((X) & (~((~((~0x0)<<(N))) << (64-(S)-(N))))) | \ + (((~(0xFFFFFFFFFFFFFFFFull << (N))) & (V)) << (64 - (S)-(N)))) + +#define PORE_GET_BIT(X,S) PORE_GET_BITS((X),(S),1) +#define PORE_SET_BIT(Y,X,S,V) PORE_SET_BITS(Y,(X),(S),1,(V)) + +/* Exception handling ********************************************************/ + +/// Set the PC to the Nth combined vector +static int +pore_vectorThroughTable(pore_model_t p, unsigned vector) +{ + uint32_t offset; + + if (vector >= (PORE_ERROR_VECTORS + PORE_EXE_VECTORS)) { + BUG(); + return PORE_ERR_BUG_INVALID_VECTOR; + } + offset = p->table_base_addr.table_base_address + + (vector * PORE_VECTOR_SIZE); + + p->status.pc = ((uint64_t)p->table_base_addr.memory_space << 32) + + offset; + + dprintf(p, "%s: Jumping to vector %d @ %016llx\n", + __func__, vector, (long long)p->status.pc); + + return PORE_SUCCESS; +} + +/// Set the PC to an error vector +static inline int +pore_errorVector(pore_model_t p, unsigned error) +{ + return pore_vectorThroughTable(p, error); +} + +/// Set the PC to an EXE vector +static int +pore_exeVector(pore_model_t p, unsigned vector) +{ + return pore_vectorThroughTable(p, PORE_ERROR_VECTORS + vector); +} + +/* Support read/write registers with side effects ****************************/ + +static inline int +pore_stack0_reg_write(pore_model_t p, uint64_t val, uint64_t mask) +{ + int me = PORE_SUCCESS; + int newSp; + pore_pc_stack0_reg pps0; + + val &= PORE_PC_STACK0_VALID_BITS; + p->pc_stack[0].val = ((val & mask) | + (p->pc_stack[0].val & ~mask)); + p->pc_stack[0].set_stack_pointer = 0; + p->pc_stack[0].new_stack_pointer = 0; + + pps0.val = val & mask; + if (pps0.set_stack_pointer) { + newSp = pps0.new_stack_pointer; + if ((newSp != 0) && + (newSp != 1) && + (newSp != 2) && + (newSp != 4)) { + me = PORE_ERR_INVALID_STACK_POINTER; + } else { + p->status.stack_pointer = newSp; + } + } + return me; +} + +// NB: Technically, if the PORE is being held in reset no other +// register updates should go through or have effect. We don't model +// that, however, and instead just catch cases where firmware tries to +// execute PORE programs while PORE or the OCI master are in reset. + +static inline int +pore_reset_reg_write(pore_model_t p, uint64_t val, uint64_t mask) +{ + pore_reset_reg reset; + + dprintf(p, "%s: val=%016llx mask=%016llx\n", __func__, + (long long)val, (long long)mask); + + val &= PORE_RESET_VALID_BITS; + reset.val = ((val & mask) | + (p->reset.val & ~mask)); + + if (mask & PORE_BITS_0_31) { + if (reset.fn_reset) + return pore_flush_reset(p); + if (reset.oci_reset) + return poreb_reset(p->mem); + if (reset.restart_sbe_trigger) { + /* FIXME SBE will reset and restart initial + * boot code execution + */ + return pore_flush_reset(p); + } + } + + /* The bits of this register are self clearing after the + * resets have been performed. Don't write bits back. + */ + return PORE_SUCCESS; +} + +static inline void +pore_status_reg_print(pore_status_reg *status) +{ + aprintf(" PORE_STATUS %016llx\n" + " cur_state = %02x freeze_action = %x\n" + " stack_pointer = %x pc = %llx\n", + (long long)status->val, + (unsigned int)status->cur_state, + (unsigned int)status->freeze_action, + (unsigned int)status->stack_pointer, + (long long)status->pc); +} + +static inline void +pore_control_reg_print(pore_control_reg *poreControl) +{ + aprintf(" PORE_CONTROL %016llx\n" + " start_stop = %x continue_step = %x\n" + " skip = %x set_pc = %x\n" + " lock_exe_trig = %x trap_enable = %x\n" + " pc_brk_pt = %llx\n", + (long long)poreControl->val, + (unsigned int)poreControl->start_stop, + (unsigned int)poreControl->continue_step, + (unsigned int)poreControl->skip, + (unsigned int)poreControl->set_pc, + (unsigned int)poreControl->lock_exe_trig, + (unsigned int)poreControl->trap_enable, + (long long)poreControl->pc_brk_pt); +} + + +/// Control register write side effects +/// +/// \bug This model is not correct (does not implement) all cases +/// regarding stopping/starting/continue/breakpoints/traps. This is a +/// low priority since OCC firmware is not expected to use these +/// features. + +static inline int +pore_control_reg_write(pore_model_t p, uint64_t val, uint64_t mask) +{ + int me = PORE_SUCCESS; + int squashWrite = 0; + pore_control_reg poreControl; + + poreControl.val = val; + + if (p->trace_flags & PORE_TRACE_IBUF) + pore_control_reg_print(&poreControl); + + if (p->reset.fn_reset == 1) { + return PORE_ERR_IN_RESET; + } + + // Move the value to a local base register for field decoding, + // then process control actions. + if (mask & PORE_BITS_0_31) { + + // Processing Set PC. This only happens on 64-bit + // writes!!! And if it happens, everything else is + // ignored. It is considered a firmware error to set + // the PC when the hardware is not in the wait state. + if (poreControl.set_pc && (mask & PORE_BITS_32_63)) { + squashWrite = 1; + if ((p->control.start_stop != 1) || + (p->status.cur_state != PORE_STATE_WAIT)) { + me = PORE_ERR_NOT_STOPPED_WAIT; + } else { + p->status.pc = poreControl.pc_brk_pt; + } + } else { + // Processing START/STOP bit. If this bit is + // set the PORE stops in the WAIT state. If + // we were in the ABR state we have to finish + // the instruction first. + + if (poreControl.start_stop) { + p->status.cur_state = PORE_STATE_WAIT; + } else if (p->status.cur_state == PORE_STATE_WAIT) { + p->status.cur_state = PORE_STATE_EXEC; + } + + // Hitting the continue bit will restart a + // machine in the ABR (address breakpoint) + // state. If in any other state we punt. + + if (poreControl.continue_step) { + if (p->status.cur_state == PORE_STATE_ABR) { + p->status.cur_state = PORE_STATE_EXEC; + finishBrokenInstruction(p); + + } else { + me = PORE_ERR_BEHAVIOR_NOT_MODELED; + } + } + + if (poreControl.skip) { + me = PORE_ERR_BEHAVIOR_NOT_MODELED; + } + } + } + + if (!me && !squashWrite) { + + // Clear any 'pulse-mode' bits in the register before writing + poreControl.continue_step = 0; + poreControl.skip = 0; + poreControl.set_pc = 0; + + p->control.val = ((poreControl.val & mask) | /* new val */ + (p->control.val & ~mask)); /* old val */ + + dprintf(p, " new control reg val=%016llx\n", + (long long)p->control.val); + } + + return me; +} + +/// EXE_Trigger Register Write Function +/// +/// This function writes to the Exe trigger register and also schedules +/// the instruction for execution when LO order word is written. No side +/// effect when HI order word is written. + +static inline int +pore_exe_trigger_reg_write(pore_model_t p, uint64_t val, uint64_t mask) +{ + int me = PORE_SUCCESS; + + val &= PORE_EXE_TRIGGER_VALID_BITS; + if (p->reset.fn_reset == 1) { + me = PORE_ERR_IN_RESET; + + } else if (mask == PORE_BITS_32_63) { + p->exe_trigger.val = ((val & mask) | + (p->exe_trigger.val & ~mask)); + + } else if (p->control.lock_exe_trig) { + me = PORE_ERR_REGISTER_LOCKED; + + } else { + p->exe_trigger.val = ((val & mask) | + (p->exe_trigger.val & ~mask)); + + // Lock the EXE_TRIGGER register, compute the + // new starting PC, and begin execution. + + p->control.lock_exe_trig = 1; + p->control.start_stop = 0; + pore_exeVector(p, p->exe_trigger.start_vector); + } + return me; +} + +/// write method for IBUF_01 register. Upon write to the ibuf_0 part +/// it executes the instruction. +/// The PORE IBUF0,1,2 registers are read-only, when Instruction +/// engine is in automatic run-mode (Control Register(0) = 0). + +static int +pore_ibuf_01_reg_write(pore_model_t p, uint64_t val, uint64_t mask) +{ + int me = PORE_SUCCESS; + + if (p->reset.fn_reset == 1) { + return PORE_ERR_IN_RESET; + } + if (p->control.start_stop != 1) { + return PORE_ERR_NOT_STOPPED; + } + + p->ibuf_01.val = ((val & mask) | + (p->ibuf_01.val & ~mask)); + + if (mask & PORE_BITS_0_31) { + me = decode(p); + if (me != PORE_SUCCESS) + return me; + + me = execute(p); + if (me != PORE_SUCCESS) + return me; + + /* FIXME In case of stuffing instructions I strongly + assume that the PC must not be upated. */ + } + return me; +} + +void pore_set_trace(pore_model_t pm, uint64_t trace) +{ + pm->trace_flags = trace; +} + +uint64_t pore_get_trace(pore_model_t pm) +{ + return pm->trace_flags; +} + +int pore_instrHook(pore_model_t p, uint64_t addr, + uint32_t im24, uint64_t im64) +{ + if (!p->instrHook) + return 0; + return p->instrHook(p, addr, im24, im64); +} + +int pore_readHook(pore_model_t p, uint64_t addr) +{ + if (!p->readHook) + return 0; + return p->readHook(p, addr); +} + +int pore_writeHook(pore_model_t p, uint64_t addr) +{ + if (!p->writeHook) + return 0; + return p->writeHook(p, addr); +} + +int pore_fetchHook(pore_model_t p, uint64_t addr) +{ + if (!p->fetchHook) + return 0; + return p->fetchHook(p, addr); +} + +static int pore_decodeHook(pore_model_t p, uint8_t *instr, unsigned int size) +{ + if (!p->decodeHook) + return 0; + return p->decodeHook(p, instr, size); +} + +static void pore_waitCallback(pore_model_t p, uint32_t delay) +{ + if (!p->waitCallback) + return; + p->waitCallback(p, delay); +} + +static void incrPc(pore_model_t p) +{ + p->status.pc += p->opcode_len; +} + +static void setJmpTarget(int offset, PoreAddress *next_pc) +{ + next_pc->offset += offset * 4; +} + +/** + * Implements Add Operation with Status Flag Set. + * This function received the pre constructed operands for ADD and calculates + * ALU Status flags. It also updates the id_flags register. + * \param op1 operand 1 + * \param op2 operand 2 + * \param result result of operaton + * \param opcode opcode which was executed + * (e.g. SUBx will change g* and s* flags) + * \retval PORE_SUCCESS + * \todo Make match VHDL model - several issues to resolve. + * + * See also: Table 4.7: Ibuf internal register: ALU flags and Ibuf-ID. + */ +static int setAluFlags(pore_model_t p, int64_t op1, int64_t op2, + int64_t result, int opcode) +{ + PoreInlineDecode *dis = &p->dis; + pore_id_flags_reg *id_flags = &p->id_flags; + + /* Flags are updated only when target is scr1 or src2 */ + if (dis->tR != PORE_SCRATCH1_ENC && dis->tR != PORE_SCRATCH2_ENC) { + return PORE_SUCCESS; + } + + /* N: bit 0 of result goes to N; is result negative? */ + id_flags->n = PORE_GET_BIT(result, 0); + + /* Z: set zero bit */ + if (result == 0) { + id_flags->z = 1; + } else { + id_flags->z = 0; + } + + /* O: check for overflows */ + if ((~((op1 ^ op2) >> 63) & 0x1ull) & + (((result ^ op1) >> 63) & 0x1ull)) { + id_flags->o = 1; + } else { + id_flags->o = 0; + } + + /* C: set carry bit */ + if (((op1 & 0x7fffffffffffffffull) + + (op2 & 0x7FFFFFFFFFFFFFFFull)) & (0x1ull << 63)) { + + if ((PORE_GET_BIT(op1,0) + PORE_GET_BIT(op2,0) + 1 ) >> 1) { + id_flags->c = 1; + } else { + id_flags->c = 0; + } + } else { + if ((PORE_GET_BIT(op1,0) + PORE_GET_BIT(op2,0) ) >> 1) { + id_flags->c = 1; + } else { + id_flags->c = 0; + } + + } + + /* UGT, ULT, SGT, SLT */ + if ((opcode == PORE_OPCODE_SUB) || + (opcode == PORE_OPCODE_SUBI)) { + /* UGT = C AND !Z */ + id_flags->ugt = ((id_flags->c & ~id_flags->z) & 0x1); + + /* ULT = !C AND !Z */ + id_flags->ult = ((~id_flags->c & ~id_flags->z) & 0x1); + + /* SGT = (N AND V AND !Z) OR (!N AND !V AND !Z) + */ + id_flags->sgt = (((id_flags->n & + id_flags->o & + ~id_flags->z) & 0x1) | + ((~id_flags->n & + ~id_flags->o & + ~id_flags->z) & 0x1)); + + /* SLT = (N AND !V) OR (!N AND V) */ + id_flags->slt = (((id_flags->n & ~id_flags->o) & 0x1 ) | + ((~id_flags->n & id_flags->o) & 0x1 )); + } + /* If the instruction is an ADD, then by specification the + * UGT/ULT/SGT/SLT bits are cleared. + */ + else if ((opcode == PORE_OPCODE_ADD) || + (opcode == PORE_OPCODE_ADDI)) { + id_flags->ugt = 0; + id_flags->ult = 0; + id_flags->sgt = 0; + id_flags->slt = 0; + } + + return 0; +} + +/*** Address Decoding ********************************************************/ + +/// Relocate a memory address if it's in the relocation region +void pore_relocateAddress(pore_model_t p, uint64_t *addr) +{ + PoreAddress address; + + address.val = *addr; + + if (p->memory_reloc.memory_reloc_region == (address.offset >> 30)) { + address.offset += (p->memory_reloc.memory_reloc_base << 12); + } + *addr = address.val; +} + +/// Compute OCI effective and real addresses and handle hooks. The +/// returned address is the real (physical) PoreAddress. +static int computeOciDataAddress(pore_model_t p, uint32_t ima24, + PoreAddress *address, int read_not_write) +{ + uint32_t base_select = ima24 & 0x400000; + pore_oci_base_address_reg oci_base; + + // First compute an effective address. The 'oci_mem_route' is + // in the form of a memory space descriptor, minus the + // high-order bit. This memory route is only used in the + // PORE-SBE. + + if (base_select) { + oci_base.val = p->oci_base[1].val; + } else { + oci_base.val = p->oci_base[0].val; + } + + address->memorySpace = oci_base.oci_mem_route | 0x8000; + address->offset = oci_base.oci_base_address + (ima24 & 0x003FFFFF); + + if (pore_get_enableAddressHooks(p)) { + if (read_not_write) { + pore_readHook(p, address->val); + } else { + pore_writeHook(p, address->val); + } + } + + // Return the relocated address + pore_relocateAddress(p, &address->val); + return 0; +} + +/* Internal register encodings ***********************************************/ + +static uint64_t __readReg(pore_model_t p, pore_internal_reg_t reg) +{ + switch (reg) { + case PORE_PRV_BASE_ADDR0_ENC: return p->prv_base[0].val >> 32; + case PORE_PRV_BASE_ADDR1_ENC: return p->prv_base[1].val >> 32; + case PORE_OCI_MEMORY_BASE_ADDR0_ENC: return p->oci_base[0].val; + case PORE_OCI_MEMORY_BASE_ADDR1_ENC: return p->oci_base[1].val; + case PORE_TABLE_BASE_ADDR_ENC: return p->table_base_addr.val; + case PORE_EXE_TRIGGER_ENC: return p->exe_trigger.val; + case PORE_SCRATCH0_ENC: return p->scratch0.val >> 32; + case PORE_SCRATCH1_ENC: return p->scratch1; + case PORE_SCRATCH2_ENC: return p->scratch2; + case PORE_DATA0_ENC: return p->data0 >> 32; + case PORE_ERROR_MASK_ENC: return p->error_mask.val; + case PORE_PC_ENC: return p->status.pc; + case PORE_ALU_IBUF_ID_ENC: return p->id_flags.val; + } + + eprintf(p, "%s: err: illegal reg %x\n", __func__, reg); + return PORE_ERR_INVALID_PARAM; +} + +static int __writeReg(pore_model_t p, pore_internal_reg_t reg, uint64_t val) +{ + switch (reg) { + case PORE_PRV_BASE_ADDR0_ENC: + p->prv_base[0].val = + (val << 32) & PORE_PRV_BASE_ADDRESS_VALID_BITS; + break; + case PORE_PRV_BASE_ADDR1_ENC: + p->prv_base[1].val = + (val << 32) & PORE_PRV_BASE_ADDRESS_VALID_BITS; + break; + + case PORE_OCI_MEMORY_BASE_ADDR0_ENC: + p->oci_base[0].val = + val & PORE_OCI_BASE_ADDRESS_VALID_BITS; + break; + case PORE_OCI_MEMORY_BASE_ADDR1_ENC: + p->oci_base[1].val = + val & PORE_OCI_BASE_ADDRESS_VALID_BITS; + break; + + case PORE_TABLE_BASE_ADDR_ENC: + p->table_base_addr.val = val; break; + case PORE_EXE_TRIGGER_ENC: + /** + * A COPY instruction to the EXE_Trigger register will + * only update the upper half of the register and not + * trigger a new start vector execution. + */ + p->exe_trigger.mc_chiplet_select_mask = val & 0xffffffff; + break; + + case PORE_SCRATCH0_ENC: + p->scratch0.val = (val << 32) & PORE_SCRATCH0_VALID_BITS; + break; + + case PORE_SCRATCH1_ENC: + p->scratch1 = val; + break; + case PORE_SCRATCH2_ENC: + p->scratch2 = val; + break; + + case PORE_DATA0_ENC: + p->data0 = (val << 32) & PORE_DATA0_VALID_BITS; + break; + case PORE_ERROR_MASK_ENC: + p->error_mask.val = val & PORE_ERROR_MASK_VALID_BITS; + break; + case PORE_PC_ENC: p->status.pc = val; break; + case PORE_ALU_IBUF_ID_ENC: + p->id_flags.val = val & PORE_ID_FLAGS_VALID_BITS; + break; + default: + eprintf(p, "%s: err: illegal reg %x\n", __func__, reg); + return PORE_ERR_INVALID_PARAM; + } + return PORE_SUCCESS; +} + +/*** Stack operations ********************************************************/ + +/** + * Stack push. Only in the event of an error push do we allow the 3rd + * level to be used. + * + * 0001: Stack empty + * 0010: Stack filled up to level 1 + * 0100: Stack filled up to level 2 + * 1000: Stack filled up to level 3 (error handler only) + */ +static int push(pore_model_t p, uint64_t next_pc, int error) +{ + int rc = PORE_SUCCESS; + pore_pc_stack0_reg pc_stack0; + + if (p->status.stack_pointer == 0x4) { + BUG(); + p->dbg1.pc_stack_ovflw_undrn_err = 1; + p->control.start_stop = 1; /* FIXME This is brute force */ + return PORE_ERR_STACK_OVERFLOW; + } + + if ((p->status.stack_pointer == 0x2) && !error) { + p->dbg1.pc_stack_ovflw_undrn_err = 1; + rc = pore_handleErrEvent(p, 2, PORE_ERR_STACK_OVERFLOW); + if (rc < 0) { + return rc; + } + } + + pc_stack0.val = p->pc_stack[0].val; + + switch (p->status.stack_pointer) { + case 0x0: + case 0x1: + case 0x2: + p->pc_stack[2].pc_stack = p->pc_stack[1].pc_stack; + p->pc_stack[1].pc_stack = p->pc_stack[0].pc_stack; + pc_stack0.pc_stack = next_pc; + pore_stack0_reg_write(p, pc_stack0.val, PORE_BITS_0_63); + + p->status.stack_pointer = + (p->status.stack_pointer == 0) ? 1 : + (p->status.stack_pointer << 1); + break; + default: + return PORE_ERR_INVALID_STACK_POINTER; + } + + return PORE_SUCCESS; +} + +/** + * Stack pop. + * + * 0001: Stack empty + * 0010: Stack filled up to level 1 + * 0100: Stack filled up to level 2 + * 1000: Stack filled up to level 3 (error handler only) + */ +static int pop(pore_model_t p, PoreAddress *next_pc) +{ + int rc; + pore_pc_stack0_reg pc_stack0; + + pc_stack0.val = p->pc_stack[0].val; + switch (p->status.stack_pointer) { + case 0x0: + p->dbg1.pc_stack_ovflw_undrn_err = 1; + rc = pore_handleErrEvent(p, 2, PORE_ERR_STACK_UNDERFLOW); + if (rc < 0) + return rc; + + case 0x1: + case 0x2: + case 0x4: + next_pc->val = pc_stack0.pc_stack; + pc_stack0.pc_stack = p->pc_stack[1].pc_stack; + pore_stack0_reg_write(p, pc_stack0.val, PORE_BITS_0_63); + p->pc_stack[1].pc_stack = p->pc_stack[2].pc_stack; + p->status.stack_pointer = p->status.stack_pointer >> 1; + break; + default: + return PORE_ERR_INVALID_STACK_POINTER; + } + + return PORE_SUCCESS; +} + +/* Error handling ************************************************************/ + +/// Take Action Based on Error event and Error Mask setting. If PORE +/// is programmed to stop on the error and d_errorBreak is true (the +/// default), we break simulation. + +static void signalError(pore_model_t p) +{ + dprintf(p, "%s()\n", __func__); + + if (!p->errorCallback) + return; + p->errorCallback(p); +} + +static void signalFatalError(pore_model_t p) +{ + dprintf(p, "%s()\n", __func__); + + if (!p->fatalErrorCallback) + return; + return p->fatalErrorCallback(p); +} + +/** + * Error event 0: During instruction execution phase, a non-zero + * return code was received from PORE's pervasive PIB Master interface + * or parity error detected in PIB read data. The SBE will also use + * this error event in case of a Fast I2C protocol hang (poll count + * for SEEPROM/Flash/OTPROM access completion reached threshold as + * defined in). If error mask register bit20 is set, then the + * return-code chiplet offline (0b010) does not trigger this error + * event. + * + * Error event 1: During instruction execution phase, a non-zero + * return code was received from PORE's OCI Master interface or parity + * error detected in OCI read data (PORE_SBE has a pervasive PIB + * Master IF only. So this error event is unused.) + * + * Error event 2: Error during instruction fetching or decode, which + * is either: + * - bad instruction parity, if instruction parity checking is enabled + * - invalid instruction code + * - invalid start vector (SV) trigger + * - invalid instruction path (I2CM parameter miss) + * - invalid instruction operand (any other register selected than + * documented in (Table 4.8)) + * - instruction counter (PC) overflow or underrun in relative addressing + * - PC stack overflow/underrun: BSR/BSRD to a full stack/RET on empty stack + * - instruction fetching error: a non-zero return-code was received + * during instruction fetching (single for short instruction or up to + * three times for long operations) + * - SBE only: Fast I2C protocol hang (poll count for SEEPROM/Flash/OTPROM + * access completion reached threshold during an instruction fetch). + * + * Each error cause is indicated by a corresponding bit in DBG + * Register1. Since errors on this event are fatal for PORE, it is + * highly recommended to configure the actions �Stop IBUF execution + * and IBUF fatal error in the IBUF Error Mask register. This is + * the default setting. + * + * Error event 3: Internal data error during instruction execution: + * Detected bad data consistency checking, e.g. bad scan-data CRC + * + * Error event 4: Error-on-Error. Any error occurred when DBG Regs0-1 + * are already locked: DBG_Reg1(63) = 1. + * + * Error events 2 and 3 will always freeze the DBG registers while + * error event 0 and 1 will only freeze the DBG registers if the + * corresponding Error Handler is enabled in the Error_Mask register. + */ +int +pore_handleErrEvent(pore_model_t p, int error_in, int model_err) +{ + int me; + int error = error_in; + + // Check for error on error. If yes change to err event + // 4. Else lock the debug registers for events 2, 3 and + // 0, 1 only if err_handler is enabled. + + if (p->dbg1.debug_regs_locked == 1) + error = 4; + + switch (error) { + case 0: + if ((p->error_mask.enable_err_output0 == 0) && + (p->error_mask.enable_fatal_error0 == 0) && + (p->error_mask.stop_exe_on_error0 == 0) && + (p->error_mask.enable_err_handler0 == 0)) + return PORE_ERROR_IGNORED; + + if (p->error_mask.enable_err_output0) + signalError(p); + if (p->error_mask.enable_fatal_error0) + signalFatalError(p); + if (p->error_mask.stop_exe_on_error0) { + p->control.start_stop = 1; + } + else if (p->error_mask.enable_err_handler0) { + p->dbg1.debug_regs_locked = 1; + + /* push pc onto stack, only if there is space */ + me = push(p, p->status.pc, 1); + if (me < 0) { + model_err = me; + break; + } + pore_errorVector(p, 0); + } + break; + case 1: + if ((p->error_mask.enable_err_output1 == 0) && + (p->error_mask.enable_fatal_error1 == 0) && + (p->error_mask.stop_exe_on_error1 == 0) && + (p->error_mask.enable_err_handler1 == 0)) + return PORE_ERROR_IGNORED; + + if (p->error_mask.enable_err_output1) + signalError(p); + if (p->error_mask.enable_fatal_error1) + signalFatalError(p); + if (p->error_mask.stop_exe_on_error1) { + p->control.start_stop = 1; + } + else if (p->error_mask.enable_err_handler1) { + p->dbg1.debug_regs_locked = 1; + + /* push pc onto stack, only if there is space */ + me = push(p, p->status.pc, 1); + if (me < 0) { + model_err = me; + break; + } + pore_errorVector(p, 1); + } + break; + case 2: + p->dbg1.debug_regs_locked = 1; + + if ((p->error_mask.enable_err_output2 == 0) && + (p->error_mask.enable_fatal_error2 == 0) && + (p->error_mask.stop_exe_on_error2 == 0) && + (p->error_mask.enable_err_handler2 == 0)) + return PORE_ERROR_IGNORED; + + if (p->error_mask.enable_err_output2) + signalError(p); + if (p->error_mask.enable_fatal_error2) + signalFatalError(p); + if (p->error_mask.stop_exe_on_error2) { + p->control.start_stop = 1; + } + else if (p->error_mask.enable_err_handler2) { + /* push pc onto stack, only if there is space */ + me = push(p, p->status.pc, 1); + if (me < 0) { + model_err = me; + break; + } + pore_errorVector(p, 2); + } + break; + case 3: + p->dbg1.debug_regs_locked = 1; + + if ((p->error_mask.enable_err_output3 == 0) && + (p->error_mask.enable_fatal_error3 == 0) && + (p->error_mask.stop_exe_on_error3 == 0) && + (p->error_mask.enable_err_handler3 == 0)) + return PORE_ERROR_IGNORED; + + if (p->error_mask.enable_err_output3) + signalError(p); + if (p->error_mask.enable_fatal_error3) + signalFatalError(p); + if (p->error_mask.stop_exe_on_error3) { + p->control.start_stop = 1; + } + else if (p->error_mask.enable_err_handler3) { + /* push pc onto stack, only if there is space */ + me = push(p, p->status.pc, 1); + if (me < 0) { + model_err = me; + break; + } + pore_errorVector(p, 3); + } + break; + case 4: + if ((p->error_mask.enable_err_output4 == 0) && + (p->error_mask.enable_fatal_error4 == 0) && + (p->error_mask.stop_exe_on_error4 == 0) && + (p->error_mask.enable_err_handler4 == 0)) + return PORE_ERROR_IGNORED; + + if (p->error_mask.enable_err_output4) + signalError(p); + if (p->error_mask.enable_fatal_error4) + signalFatalError(p); + if (p->error_mask.stop_exe_on_error4) { + p->control.start_stop = 1; + } + else if (p->error_mask.enable_err_handler4) { + me = push(p, p->status.pc, 1); + if (me < 0) { + model_err = me; + break; + } + pore_errorVector(p, 4); + } + break; + default: + return PORE_ERR_NOT_IMPLEMENTED; + } + return model_err; +} + +/* External register encodings ***********************************************/ + +uint64_t pore_readReg(pore_model_t p, pore_reg_t reg, uint64_t msk) +{ + uint64_t val; + + switch (reg) { + case PORE_R_STATUS: val = p->status.val; break; + case PORE_R_CONTROL: val = p->control.val; break; + case PORE_R_RESET: val = p->reset.val; break; + case PORE_R_ERROR_MASK: val = p->error_mask.val; break; + case PORE_R_PRV_BASE_ADDR0: val = p->prv_base[0].val; break; + case PORE_R_PRV_BASE_ADDR1: val = p->prv_base[1].val; break; + case PORE_R_OCI_MEMORY_BASE_ADDR0: val = p->oci_base[0].val; break; + case PORE_R_OCI_MEMORY_BASE_ADDR1: val = p->oci_base[1].val; break; + case PORE_R_TABLE_BASE_ADDR: val = p->table_base_addr.val; break; + case PORE_R_EXE_TRIGGER: val = p->exe_trigger.val; break; + case PORE_R_SCRATCH0: val = p->scratch0.val; break; + case PORE_R_SCRATCH1: val = p->scratch1; break; + case PORE_R_SCRATCH2: val = p->scratch2; break; + case PORE_R_IBUF_01: val = p->ibuf_01.val; break; + case PORE_R_IBUF_2: val = p->ibuf_2.val; break; + case PORE_R_DBG0: val = p->dbg0.val; break; + case PORE_R_DBG1: val = p->dbg1.val; break; + case PORE_R_PC_STACK0: val = p->pc_stack[0].val; break; + case PORE_R_PC_STACK1: val = p->pc_stack[1].val; break; + case PORE_R_PC_STACK2: val = p->pc_stack[2].val; break; + case PORE_R_ID_FLAGS: val = p->id_flags.val; break; + case PORE_R_DATA0: val = p->data0; break; + case PORE_R_MEM_RELOC: val = p->memory_reloc.val; break; + case PORE_R_I2C_E0_PARAM: val = p->i2c_e_param[0].val; break; + case PORE_R_I2C_E1_PARAM: val = p->i2c_e_param[1].val; break; + case PORE_R_I2C_E2_PARAM: val = p->i2c_e_param[2].val; break; + default: + eprintf(p, "%s: err: illegal reg %x\n", __func__, reg); + return PORE_ERR_INVALID_PARAM; + } + + dprintf(p, "<== %s: reg=%02x val=%016llx mask=%016llx\n", + __func__, reg, (long long)val, (long long)msk); + + return val & msk; +} + +uint64_t pore_readRegRaw(pore_model_t p, pore_reg_t reg, + uint64_t msk __attribute__((unused))) +{ + return pore_readReg(p, reg, msk); +} + +static void write_under_mask(uint64_t *reg, uint64_t n_val, uint64_t mask) +{ + uint64_t o_val = *reg; + *reg = ((n_val & mask) | /* new val */ + (o_val & ~mask)); /* old val */ +} + +/** + * Writing any data to either PIBMS_DBG Reg0 or Reg1 unsets their lock + * and resets PIBMS_DBG1(63). + */ +int pore_writeReg(pore_model_t p, pore_reg_t reg, uint64_t val, uint64_t msk) +{ + dprintf(p, "==> %s: reg=%02x val=%016llx mask=%016llx\n", + __func__, reg, (long long)val, (long long)msk); + + switch (reg) { + case PORE_R_STATUS: + write_under_mask(&p->status.val, val, msk); + break; + case PORE_R_CONTROL: /* SIDE EFFECTS */ + return pore_control_reg_write(p, val, msk); + + case PORE_R_RESET: + write_under_mask(&p->reset.val, + val & PORE_RESET_VALID_BITS, msk); + break; + case PORE_R_ERROR_MASK: + write_under_mask(&p->error_mask.val, + val & PORE_ERROR_MASK_VALID_BITS, msk); + break; + + case PORE_R_PRV_BASE_ADDR0: + write_under_mask(&p->prv_base[0].val, + val & PORE_PRV_BASE_ADDRESS_VALID_BITS, msk); + break; + case PORE_R_PRV_BASE_ADDR1: + write_under_mask(&p->prv_base[1].val, + val & PORE_PRV_BASE_ADDRESS_VALID_BITS, msk); + break; + + case PORE_R_OCI_MEMORY_BASE_ADDR0: + write_under_mask(&p->oci_base[0].val, + val & PORE_OCI_BASE_ADDRESS_VALID_BITS, msk); + break; + case PORE_R_OCI_MEMORY_BASE_ADDR1: + write_under_mask(&p->oci_base[1].val, + val & PORE_OCI_BASE_ADDRESS_VALID_BITS, msk); + break; + + case PORE_R_TABLE_BASE_ADDR: + write_under_mask(&p->table_base_addr.val, val, msk); + break; + case PORE_R_EXE_TRIGGER: /* SIDE EFFECTS */ + return pore_exe_trigger_reg_write(p, val, msk); + case PORE_R_SCRATCH0: + write_under_mask(&p->scratch0.val, + val & PORE_SCRATCH0_VALID_BITS, msk); + break; + case PORE_R_SCRATCH1: + write_under_mask(&p->scratch1, val, msk); + break; + case PORE_R_SCRATCH2: + write_under_mask(&p->scratch2, val, msk); + break; + case PORE_R_IBUF_01: /* SIDE EFFECTS */ + return pore_ibuf_01_reg_write(p, val, msk); + case PORE_R_IBUF_2: + write_under_mask(&p->ibuf_2.val, val, msk); + break; + case PORE_R_DBG0: + p->dbg1.debug_regs_locked = 0; /* Writing will unlock */ + write_under_mask(&p->dbg0.val, val& PORE_DBG0_VALID_BITS, msk); + break; + case PORE_R_DBG1: + p->dbg1.debug_regs_locked = 0; /* Writing will unlock */ + write_under_mask(&p->dbg1.val, val& PORE_DBG1_VALID_BITS, msk); + break; + case PORE_R_PC_STACK0: /* SIDE EFFECTS */ + return pore_stack0_reg_write(p, val, msk); + case PORE_R_PC_STACK1: + write_under_mask(&p->pc_stack[1].val, + val & PORE_PC_STACK1_VALID_BITS, msk); + break; + case PORE_R_PC_STACK2: + write_under_mask(&p->pc_stack[2].val, + val & PORE_PC_STACK2_VALID_BITS, msk); + break; + case PORE_R_ID_FLAGS: + write_under_mask(&p->id_flags.val, + val & PORE_ID_FLAGS_VALID_BITS, msk); + break; + case PORE_R_DATA0: + write_under_mask(&p->data0, + val & PORE_DATA0_VALID_BITS, msk); + break; + case PORE_R_MEM_RELOC: + write_under_mask(&p->memory_reloc.val, + val & PORE_MEMORY_RELOC_VALID_BITS, msk); + break; + case PORE_R_I2C_E0_PARAM: + write_under_mask(&p->i2c_e_param[0].val, + val & PORE_I2C_E0_PARAM_VALID_BITS, msk); + break; + case PORE_R_I2C_E1_PARAM: + write_under_mask(&p->i2c_e_param[1].val, + val & PORE_I2C_E1_PARAM_VALID_BITS, msk); + break; + case PORE_R_I2C_E2_PARAM: + write_under_mask(&p->i2c_e_param[2].val, + val & PORE_I2C_E2_PARAM_VALID_BITS, msk); + break; + default: + eprintf(p, "%s: err: illegal reg %x\n", __func__, reg); + return PORE_ERR_INVALID_PARAM; + } + return PORE_SUCCESS; +} + +int pore_writeRegRaw(pore_model_t p, pore_reg_t reg, uint64_t val, + uint64_t msk) +{ + switch (reg) { + case PORE_R_CONTROL: + write_under_mask(&p->control.val, val, msk); + break; + case PORE_R_EXE_TRIGGER: + write_under_mask(&p->exe_trigger.val, + val & PORE_EXE_TRIGGER_VALID_BITS, msk); + break; + case PORE_R_IBUF_01: + write_under_mask(&p->ibuf_01.val, val, msk); + break; + case PORE_R_PC_STACK0: + write_under_mask(&p->pc_stack[0].val, val, msk); + break; + case PORE_R_DBG0: + write_under_mask(&p->dbg0.val, val& PORE_DBG0_VALID_BITS, msk); + break; + case PORE_R_DBG1: + write_under_mask(&p->dbg1.val, val& PORE_DBG1_VALID_BITS, msk); + break; + + default: + return pore_writeReg(p, reg, val, msk); + } + return PORE_SUCCESS; +} + +/*** PIB Bus with correct address translation using PORe offset regs *********/ + +/** + * See Table 4.53: PRV address arithmetic. + */ +static int +computeDirectPibDataAddress(pore_model_t p, uint32_t ima24, + uint32_t *pibAddress, int read_not_write) +{ + int me = 0; + PoreAddress address; + uint32_t baseSelect, localAddress, chipletId, mc, port; + pore_prv_base_address_reg *prv_base; + + if (!p) + return PORE_ERR_INVALID_PARAM; + + localAddress = ima24 & 0xffff; + port = (ima24 >> 16) & 0xf; + address.val = 0; + address.offset = localAddress << 2; + + baseSelect = ima24 & 0x400000; + if (baseSelect) { + prv_base = &p->prv_base[1]; + } else { + prv_base = &p->prv_base[0]; + } + + chipletId = prv_base->chiplet_id; + mc = prv_base->mc; /* multicast */ + address.memorySpace = (mc << 14) | (chipletId << 8) | port; + + if (pore_get_enableAddressHooks(p)) { + if (read_not_write) { + pore_readHook(p, address.val); + } else { + pore_writeHook(p, address.val); + } + } + + *pibAddress = (address.memorySpace << 16) | localAddress; + return me; +} + +int pore_pib_write(pore_model_t p, uint64_t addr, const uint8_t *buf, + unsigned int len, int *err_code) +{ + int rc; + struct pore_bus *pib = p->pib; + + if (!pib) + return PORE_ERR_UNCONNECTED_BUS; + if (len != 8) { + BUG(); + return PORE_ERR_INVALID_PARAM; + } + + rc = poreb_write(pib, addr, buf, len, err_code); + + if (p->dbg1.debug_regs_locked == 0) { + p->dbg0.last_completed_address = addr & 0xFFFFFFFF; + p->dbg0.last_ret_code_prv = *err_code; + } + + p->id_flags.pib_status = *err_code; + p->id_flags.pib_parity_fail = 0; + + pib_printf(p, " putScom: addr=%016llx data=%016llx err_code=%x\n", + (long long)addr, *(long long *)buf, *err_code); + + return rc; +} + +int pore_pib_read(pore_model_t p, uint64_t addr, uint8_t *buf, + unsigned int len, int *err_code) +{ + int rc; + struct pore_bus *pib = p->pib; + + if (!pib) + return PORE_ERR_UNCONNECTED_BUS; + if (len != 8) { + BUG(); + return PORE_ERR_INVALID_PARAM; + } + + rc = poreb_read(pib, addr, buf, len, err_code); + if (p->dbg1.debug_regs_locked == 0) { + p->dbg0.last_completed_address = addr & 0xFFFFFFFF; + p->dbg0.last_ret_code_prv = *err_code; + } + + p->id_flags.pib_status = *err_code; + p->id_flags.pib_parity_fail = 0; + + pib_printf(p, " getScom: addr=%016llx data=%016llx err_code=%x\n", + (long long)addr, *(long long *)buf, *err_code); + + return rc; +} + +/// Fetch an instruction word using PIB direct addressing. This is +/// somewhat analogous to the OCI fetch buffer case in that we fetch 8 +/// bytes but only return 4, however for some reason they don't buffer +/// PIB fetches. + +static int +fetchInstructionWordPibDirect(pore_model_t p, PoreAddress *pc, + uint32_t *word, int *err_code) +{ + int rc = 0; + uint64_t data; + uint32_t offset = pc->offset; + uint32_t pibAddress = (pc->memorySpace << 16) | (offset >> 3); + struct pore_bus *pib = p->pib; + + if (!pib) + return PORE_ERR_UNCONNECTED_BUS; + + /* always fetch 8 byte on the PIB */ + rc = poreb_read(pib, pibAddress, (uint8_t *)&data, sizeof(data), + err_code); + + if (p->dbg1.debug_regs_locked == 0) { + p->dbg0.last_completed_address = pibAddress & 0xFFFFFFFF; + p->dbg0.last_ret_code_prv = *err_code; + } + + p->id_flags.pib_status = *err_code; + p->id_flags.pib_parity_fail = 0; + + pib_printf(p, " getScom: addr=%016llx data=%016llx err_code=%x\n", + (long long)pibAddress, (long long)data, *err_code); + + if (rc != sizeof(data)) { + return PORE_ERR_FETCH; + } + + *word = ((offset & 0x7) == 0) ? data >> 32 : data & 0xffffffff; + return rc; +} + +static int pore_pib_fetch(pore_model_t p, uint64_t _pc, + uint64_t *ibuf_01, + uint64_t *ibuf_2, + unsigned int *size, + int *err_code) +{ + int me; + uint32_t i_word; + PoreAddress pc; + + *ibuf_01 = *ibuf_2 = 0; + pc.val = _pc; + me = fetchInstructionWordPibDirect(p, &pc, &i_word, err_code); + if (me < 0) + return me; + + *ibuf_01 = (uint64_t)i_word << 32; + *size = 4; + if (i_word & 0x80000000) { + pc.offset += 4; + me = fetchInstructionWordPibDirect(p, &pc, &i_word, err_code); + if (me < 0) + return me; + *size += 4; + *ibuf_01 |= i_word; + pc.offset += 4; + me = fetchInstructionWordPibDirect(p, &pc, &i_word, err_code); + if (me < 0) + return me; + *size += 4; + *ibuf_2 = (uint64_t)i_word << 32; + } + return PORE_SUCCESS; +} + +/*****************************************************************************/ + +/// The Instruction Fetch Routine +/// +/// This function computes the effective address and fetches the +/// instructions from the fetch buffer to IBUF. + +static int fetch(pore_model_t p) +{ + int rc; + int recursion_stop = 0; + + redo_fetch: + if (recursion_stop == 2) + return PORE_ERR_INVALID_PARAM; /* STOP calling myself */ + + if (!p) + return PORE_ERR_INVALID_PARAM; + + if (p->enableAddressHooks && p->fetchHook) { + int _rc; + + /* FIXME There is some more done in the existing model + * e.g. setting forchedBranchMode ... Need to + * understand it before I will reintegrate. + */ + p->forcedBranch = 0; + p->forcedBranchMode = FORCED_BRANCH_FETCH_HOOK; + _rc = pore_fetchHook(p, p->status.pc); + p->forcedBranchMode = FORCED_BRANCH_DISALLOWED; + + /* Model was modified from outside!!! */ + if (!_rc) { + if (p->forcedBranch) { + p->status.pc = p->forcedPc; + recursion_stop++; + goto redo_fetch; + } + } + } + + /* zero the input buffers, such that we see 0s even on errors */ + p->ibuf_01.val = 0; + p->ibuf_2.val = 0; + + if (p->status.pc & 0x0000800000000000ull) { + rc = poreb_fetch(p->mem, p->status.pc, + &p->ibuf_01.val, &p->ibuf_2.val, + &p->opcode_len, &p->err_code); + } else { + rc = pore_pib_fetch(p, p->status.pc, + &p->ibuf_01.val, &p->ibuf_2.val, + &p->opcode_len, &p->err_code); + + /* Error occured during transaction try to handle it */ + if ((rc < 0) && (p->id_flags.pib_status != PORE_PCB_SUCCESS)) { + dprintf(p, "PCB ERROR %x occured\n", + (unsigned int)p->id_flags.pib_status); + + if ((p->id_flags.pib_status != PORE_PCB_CHIPLET_OFFLINE) || + (p->error_mask.gate_chiplet_offline_err == 0)) { + rc = pore_handleErrEvent(p, 2, rc); + } else { + /* HW190098: PORE Model not handling + mask of offline cores correctly */ + rc = PORE_SUCCESS; + } + } + } + + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.pc_last_access = p->status.pc; + if (rc < 0) { + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.instruction_fetch_error = 1; + rc = pore_handleErrEvent(p, 2, rc); + return rc; + } + return rc; +} + +static int decode(pore_model_t p) +{ + uint32_t *q; + PoreInlineDecode *dis; + + if (!p) + return PORE_ERR_INVALID_PARAM; + + dis = &p->dis; + pore_inline_decode_instruction(dis, p->ibuf_01.ibuf0); + pore_inline_decode_imd64(dis, ((uint64_t)p->ibuf_01.ibuf1 << 32 | + (uint64_t)p->ibuf_2.ibuf2)); + + p->opcode_len = 4; + if (dis->long_instruction) + p->opcode_len = 12; + + if (p->decodeHook) { + unsigned int i; + uint8_t instr[12]; + + /* data was temporarily turned into the host format */ + q = (uint32_t *)instr; + q[0] = htobe32(p->ibuf_01.ibuf0); + q[1] = htobe32(p->ibuf_01.ibuf1); + q[2] = htobe32(p->ibuf_2.ibuf2); + + dprintf(p, " IBUF[0..2]="); + for (i = 0; i < p->opcode_len; i++) + dprintf(p, "%02x", instr[i]); + + dprintf(p, "\n" + " STAT %016llx CONT %016llx\n" + " D0 %016llx D1 %016llx CTR %016llx\n" + " P0 %016llx P1 %016llx EMR %016llx\n" + " A0 %016llx A1 %016llx ETR %016llx\n" + " I2C0 %016llx I2C0 %016llx I2C0 %016llx\n" + " DBG0 %016llx DBG1 %016llx\n", + (long long)p->status.val, + (long long)p->control.val, + + (long long)p->scratch1, + (long long)p->scratch2, + (long long)p->scratch0.val, + + (long long)p->prv_base[0].val, + (long long)p->prv_base[1].val, + (long long)p->error_mask.val, + + (long long)p->oci_base[0].val, + (long long)p->oci_base[1].val, + (long long)p->exe_trigger.val, + + (long long)p->i2c_e_param[0].val, + (long long)p->i2c_e_param[1].val, + (long long)p->i2c_e_param[2].val, + + (long long)p->dbg0.val, + (long long)p->dbg1.val); + + pore_decodeHook(p, instr, p->opcode_len); + } + return 0; +} + +static int inExeInterfaceWrite(pore_model_t p, uint64_t write_data) +{ + int rc; + PoreInlineDecode *dis = &p->dis; + uint32_t addr_space, pib_addr; + PoreAddress address; + uint64_t addr = dis->ima24; + + /* OCI/MEM Address Space *********************************************/ + addr_space = addr & 0x800000; + if (addr_space) { + address.val = 0; + computeOciDataAddress(p, addr & 0xFFFFFF, &address, 0); + rc = poreb_write(p->mem, address.val, (uint8_t *)&write_data, + sizeof(write_data), &p->err_code); + + if (p->dbg1.debug_regs_locked == 0) { + p->dbg1.oci_master_rd_parity_err = 0; + p->dbg1.last_ret_code_oci = p->err_code; + } + mem_printf(p, " putMem: addr=%016llx data=%016llx " + "err_code=%x\n", (long long)address.val, + (long long)write_data, p->err_code); + + if (rc == sizeof(write_data)) + return PORE_SUCCESS; + + rc = pore_handleErrEvent(p, 2, rc); + return rc; + } + + /* PIB Address Space *************************************************/ + address.val = 0; + computeDirectPibDataAddress(p, addr, &pib_addr, 0); + rc = pore_pib_write(p, pib_addr, (uint8_t *)&write_data, + sizeof(write_data), &p->err_code); + if (rc == sizeof(write_data)) + rc = PORE_SUCCESS; + + /* Error occured during transaction try to handle it */ + if ((rc < 0) && (p->id_flags.pib_status != PORE_PCB_SUCCESS)) { + if ((p->id_flags.pib_status != PORE_PCB_CHIPLET_OFFLINE) || + (p->error_mask.gate_chiplet_offline_err == 0)) { + + rc = pore_handleErrEvent(p, 0, rc); + } else { + /* HW190098: PORE Model not handling mask of + offline cores correctly */ + rc = PORE_SUCCESS; + } + } + return rc; +} + +static int inExeInterfaceRead(pore_model_t p, uint64_t *read_data) +{ + int rc; + PoreInlineDecode *dis = &p->dis; + uint32_t addr_space, pib_addr; + PoreAddress address; + uint64_t addr = dis->ima24; + + *read_data = 0; + + /* OCI/MEM Address Space *********************************************/ + addr_space = addr & 0x800000; + if (addr_space) { + address.val = 0; + computeOciDataAddress(p, addr & 0xFFFFFF, &address, 1); + rc = poreb_read(p->mem, address.val, (uint8_t *)read_data, + sizeof(*read_data), &p->err_code); + + if (p->dbg1.debug_regs_locked == 0) { + p->dbg1.oci_master_rd_parity_err = 0; + p->dbg1.last_ret_code_oci = p->err_code; + } + + mem_printf(p, " getMem: addr=%016llx data=%016llx " + "err_code=%x\n", (long long)address.val, + (long long)*read_data, p->err_code); + + if (rc == sizeof(*read_data)) + return PORE_SUCCESS; + + rc = pore_handleErrEvent(p, 2, rc); + return rc; + } + + /* PIB Address Space *************************************************/ + address.val = 0; + computeDirectPibDataAddress(p, addr, &pib_addr, 1); + rc = pore_pib_read(p, pib_addr, (uint8_t *)read_data, + sizeof(*read_data), &p->err_code); + if (rc == sizeof(*read_data)) + rc = PORE_SUCCESS; + + /* Error occured during transaction try to handle it */ + if ((rc < 0) && (p->id_flags.pib_status != PORE_PCB_SUCCESS)) { + if ((p->id_flags.pib_status != PORE_PCB_CHIPLET_OFFLINE) || + (p->error_mask.gate_chiplet_offline_err == 0)) { + rc = pore_handleErrEvent(p, 0, rc); + } else { + /* HW190098: PORE Model not handling mask of + offline cores correctly */ + rc = PORE_SUCCESS; + } + } + return rc; +} + + +/** + * Example how to do scan a chain via the FSI Scan engine. + * + * General approach: + * + * 1. Write the length of the scan chain to be shifted (in this case + * '1') and the control bits into the Front End Length Register + * putcfam pu 0c02 00000001 + * + * you might also want to set bit2 (setpulse) or bit4 (header check) + * ... but that depends. + * + * 2. Setup the Command Register with the address of the scan chain + * and the desired operation + * + * Now it gets a little more tricky: Bit 0 of the Command Register is + * a write/not_read bit. We will take the write case. The following + * 31 bits is the address of the scan chain. + * + * There are three easy ways to find that: + * - CRONUS: do a getringdump to that ring, and see what is in + * 0c01 => getcfam pu 0c01 + * - CRONUS: do a getringdump pu RINGNAME -debug5.15.f and check + * for the mentioned address take a look at the scandef + * + * 3. Write to the FIFO with the scan info. + * putcfam pu 0c00 00000000 + * + * Repeat step 3. for the length of the scan chain ( => length/32 times ). + * + * 4. Check the status (not mandatory :-) ) + * getcfam pu 0c07 + * + * Example: Scan of ex_dpll_gptr chain on P7 + * + * # scan in + * putcfam pu 0c02 00000147 + * putcfam pu 0c01 88030402 + * + * putcfam pu 0c00 DEADBEEF + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * putcfam pu 0c00 00000000 + * + * # scan out + * putcfam pu 0c02 00000147 + * putcfam pu 0c01 08030402 + * + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * getcfam pu 0c00 + * + * Here and example doing the scan via SCOM commands: + * 1.) Configure Clock Control of respective chiplet + * 2.) Write data packets + * + * Example of EN_LBST Chain with manual 'Headercheck' (DEADBEEF as Header) + * + * en_lbst_scan + * putscom pu 03030007 5E000800 + * + * putscom pu 03038020 deadbeef + * putscom pu 03038020 11112222 + * putscom pu 03038020 33334444 + * putscom pu 03038020 55556666 + * putscom pu 03038020 77778888 + * putscom pu 03038020 9999aaaa + * putscom pu 03038020 bbbbcccc + * putscom pu 03038020 ddddeeee + * putscom pu 03038020 ffff1212 + * putscom pu 03038020 23233434 + * putscom pu 03038020 FE000000 + * putscom pu 03038020 23233434 + * putscom pu 03038020 23233434 + * putscom pu 03038020 23233434 + * putscom pu 03038020 23233434 + * putscom pu 0303801C 23233434 + * + * echo "HEADERCHECK:" + * getscom pu 03038000 + * + * putscom pu 03038020 deadbeef + * getscom pu 03038000 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 03038020 + * getscom pu 0303801C + * + * Binary to Unary Translation of scan_sel: + * WHEN 11 scantype_allf => result := "1101.1100.1110.0000"; + * WHEN 12 scantype_ccvf => result := "0010.1000.0000.0000"; + * WHEN 13 scantype_lbcm => result := "0000.1000.0010.0000"; + * WHEN 14 scantype_abfa => result := "0000.0100.0100.0000"; + * WHEN 15 scantype_fure => result := "1001.0000.0000.0000"; + */ +static const uint16_t bin_2_unary[] = { + /* unary binary */ + 0x8000, /* 0x0 0 */ + 0x4000, /* 0x1 1 */ + 0x2000, /* 0x2 2 */ + 0x1000, /* 0x3 3 */ + 0x0800, /* 0x4 4 */ + 0x0400, /* 0x5 5 */ + 0x0200, /* 0x6 6 */ + 0x0100, /* 0x7 7 */ + 0x0080, /* 0x8 8 */ + 0x0040, /* 0x9 9 */ + 0x0020, /* 0xa 10 */ + 0xdce0, /* 0xb 11 */ + 0x2800, /* 0xc 12 */ + 0x0820, /* 0xd 13 */ + 0x0440, /* 0xe 14 */ + 0x9000, /* 0xf 15 */ +}; + +static int pore_scand_read(pore_model_t p, PoreAddress *addr, uint32_t *word) + +{ + int rc; + uint64_t data; + + if (addr->val & 0x0000800000000000ull) { + uint64_t memAddress; + + memAddress = addr->val; + pore_relocateAddress(p, &memAddress); + rc = poreb_read(p->mem, memAddress, (uint8_t *)word, + sizeof(*word), &p->err_code); + + if (p->dbg1.debug_regs_locked == 0) { + p->dbg1.oci_master_rd_parity_err = 0; + p->dbg1.last_ret_code_oci = p->err_code; + } + + mem_printf(p, " getMem: addr=%016llx data=%016llx " + "err_code=%x\n", (long long)memAddress, + (long long)*word, p->err_code); + + if (rc != sizeof(*word)) + return rc; + + } else { + uint32_t pibAddress = ((addr->memorySpace << 16) | + (addr->offset >> 3)); + + /* always read 8 byte on the PIB */ + rc = poreb_read(p->pib, pibAddress, (uint8_t *)&data, + sizeof(data), &p->err_code); + + if (p->dbg1.debug_regs_locked == 0) { + p->dbg0.last_completed_address = pibAddress; + p->dbg0.last_ret_code_prv = p->err_code; + } + + mem_printf(p, " getScom: addr=%016llx data=%016llx " + "err_code=%x\n", (long long)pibAddress, + (long long)data, p->err_code); + + if (rc != sizeof(data)) { + return rc; + } + *word = ((addr->offset & 0x7) == 0) ? + data >> 32 : data & 0xffffffff; + } + return PORE_SUCCESS; +} + +static int pore_scand(pore_model_t p) +{ + int bits, rem, rc; + PoreInlineDecode *dis = &p->dis; + pore_scratch0_reg *scr0 = &p->scratch0; + uint32_t scan_data = 0, crc32_data = 0; + uint64_t write_data; + PoreAddress addr; + PibAddress pib_addr; + shift_eng_cmd_reg scan_sel; + scan_type_select_reg scan_type_sel; + + pib_addr.val = 0; + scan_sel.val = dis->scan_select; + + addr.val = p->status.pc; + addr.offset += dis->scan_offset * 4; + + /** + * Setup scan region register to select correct chains, + * e.g. write scom 0x02030007 0x0100000800000000 (chiplet 2, + * non-vital region 3, type bndy) + */ + pib_addr.mc = scan_sel.bc; + pib_addr.chiplet_id = scan_sel.chiplet_select; + pib_addr.prv_port = scan_sel.port; + pib_addr.local_addr = SCAN_REGION_OFFSET; + + scan_type_sel.val = 0; + scan_type_sel.region_select = scan_sel.region_select; + scan_type_sel.type_sel_unary = bin_2_unary[scan_sel.type_sel_bin]; + write_data = scan_type_sel.val; + + rc = pore_pib_write(p, pib_addr.val, (uint8_t *)&write_data, + sizeof(write_data), &p->err_code); + if (rc < 0) + return rc; + + for (bits = 0, rem = dis->scan_length, + scr0->scratch0 = dis->scan_length / 32; + bits < dis->scan_length; + bits += 32, rem -= 32, + scr0->scratch0--) { + + int num_bits = rem > 32 ? 32 : rem; + + rc = pore_scand_read(p, &addr, &scan_data); + if (rc < 0) + return rc; + + /** + * Send PCB scan packets which have the following + * layout: + * Address is 0x0<chiplet_id>0x0380<num_bits> + * Data is the left aligned values to get scanned in + * (up to 32 bit). + * + * The last scan packet should have the updateDR bit + * set in the address, i.e. 0x03A0 instead of 0x380. + * + * This will clear the scan region register if scan + * protection is active (default). E.g. write scom + * 0x02038020 0xFFFFFFFF00000000 (scan 32 bit in + * chiplet 2, all '1')). + * + * cDR: See JTAG standard, capture data from scanlatch + * uDR: " update data to scanlatch + * Is used for PLL settings. + */ + + if (scr0->scratch0 == dis->scan_length / 32) { + /* Need to set cDR on 1st data access */ + pib_addr.local_addr = + SCAN_DATA_OFFSET(dis->capture, 0, num_bits); + + } else if (scr0->scratch0 == 0) { + /* Need to set uDR on last data access */ + pib_addr.local_addr = + SCAN_DATA_OFFSET(0, dis->update, num_bits); + } else { + pib_addr.local_addr = + SCAN_DATA_OFFSET(0, 0, num_bits); + } + + write_data = (uint64_t)scan_data << 32; + rc = pore_pib_write(p, pib_addr.val, (uint8_t *)&write_data, + sizeof(write_data), &p->err_code); + if (rc < 0) + return rc; + + addr.offset += 4; + } + rc = pore_scand_read(p, &addr, &crc32_data); + if (rc < 0) + return rc; + p->scratch1 = crc32_data; + + return PORE_SUCCESS; +} + +static int execute(pore_model_t p) +{ + int me = PORE_SUCCESS; + int next_state = PORE_STATE_EXEC; + int trapBreakpoint = 0; + int addressBreakpoint = 0; + PoreInlineDecode *dis; + uint64_t write_data, read_data = 0; + int64_t op1, op2; + PoreAddress next_pc; + + if (!p) + return PORE_ERR_INVALID_PARAM; + + dis = &p->dis; + next_pc.val = p->status.pc; + p->branchTaken = 0; + + switch (dis->opcode) { + + case PORE_OPCODE_NOP: + break; + + case PORE_OPCODE_TRAP: + // PORE hardware trap leaves the machine in the + // address breakpoint state. + if (p->control.trap_enable) { + trapBreakpoint = 1; + next_state = PORE_STATE_ABR; + } + break; + + case PORE_OPCODE_HOOK: + if (p->enableHookInstruction) { + int _rc; + + p->forcedBranch = 0; + p->forcedBranchMode = FORCED_BRANCH_HOOK_INSTRUCTION; + _rc = pore_instrHook(p, p->status.pc, dis->imd24, + dis->imd64); + p->forcedBranchMode = FORCED_BRANCH_DISALLOWED; + if (_rc) { + me = PORE_ERR_HOOK_FAILED; + break; + } + if (p->forcedBranch) { + next_pc.val = p->forcedPc; + p->branchTaken = 1; + } + } + break; + + case PORE_OPCODE_WAIT: + if (p->dis.imd24 == 0) { + // Invalidate fetch buffer for OCI access + /// \bug Buffer is invalidated on reset + p->oci_fetchBufferValid = 0; + p->oci_fetchBufferCursor = 0; + p->oci_fetchBuffer = 0; + + // This is the stop command. Raise the + // pore_stopped signal + p->control.start_stop = 1; + + //unlockRegisters(); + p->control.lock_exe_trig = 0; + } + pore_waitCallback(p, dis->imd24); + break; + + /* Branch Instructions */ + case PORE_OPCODE_BRA: + p->branchTaken = 1; + setJmpTarget(dis->impco24, &next_pc); + break; + + case PORE_OPCODE_BRAD: + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + p->branchTaken = 1; + next_pc.val = __readReg(p, (pore_internal_reg_t)dis->tR); + break; + + case PORE_OPCODE_BRAZ: + if (dis->tR != PORE_SCRATCH0_ENC && + dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + if (__readReg(p, (pore_internal_reg_t)dis->tR) == 0) { + p->branchTaken = 1; + setJmpTarget(dis->impco20, &next_pc); + } + break; + + case PORE_OPCODE_BRANZ: + if (dis->tR != PORE_SCRATCH0_ENC && + dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + if (__readReg(p, (pore_internal_reg_t)dis->tR) != 0) { + p->branchTaken = 1; + setJmpTarget(dis->impco20, &next_pc); + } + break; + + case PORE_OPCODE_BRAI: + p->branchTaken = 1; + next_pc.val = dis->impc48; + break; + + case PORE_OPCODE_BSR: + me = push(p, p->status.pc + 4, 0); + if (me < 0) { + break; + } + + p->branchTaken = 1; + setJmpTarget(dis->impco24 , &next_pc); + break; + + case PORE_OPCODE_BSRD: + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + me = push(p, p->status.pc + 4, 0); + if (me < 0) + break; + + p->branchTaken = 1; + next_pc.val = __readReg(p, (pore_internal_reg_t)dis->tR); + break; + + case PORE_OPCODE_RET: + me = pop(p, &next_pc); + if (me < 0) + break; + + p->branchTaken = 1; + break; + + case PORE_OPCODE_CMPBRA: + if (p->scratch1 == dis->imd64) { + p->branchTaken = 1; + setJmpTarget(dis->impco24, &next_pc); + } + break; + + case PORE_OPCODE_CMPNBRA: + if (p->scratch1 != dis->imd64) { + p->branchTaken = 1; + setJmpTarget(dis->impco24, &next_pc); + } + break; + + case PORE_OPCODE_CMPBSR: + if (p->scratch1 == dis->imd64) { + me = push(p, p->status.pc + 12, 0); + if (me < 0) + break; + + p->branchTaken = 1; + setJmpTarget(dis->impco24, &next_pc); + } + break; + + case PORE_OPCODE_LOOP: + if (p->scratch0.scratch0 > 0) { + p->scratch0.scratch0 = p->scratch0.scratch0 - 1; + p->branchTaken = 1; + setJmpTarget(dis->impco24, &next_pc); + } + break; + + /* ALU Instructions */ + case PORE_OPCODE_ANDI: + if (dis->sR != PORE_SCRATCH1_ENC && + dis->sR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + __writeReg(p, (pore_internal_reg_t)dis->tR, + __readReg(p, (pore_internal_reg_t) + dis->sR) & dis->imd64); + break; + + case PORE_OPCODE_ORI: + if (dis->sR != PORE_SCRATCH1_ENC && + dis->sR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + __writeReg(p, (pore_internal_reg_t)dis->tR, + __readReg(p, (pore_internal_reg_t)dis->sR) | + dis->imd64); + break; + + case PORE_OPCODE_XORI: + if (dis->sR != PORE_SCRATCH1_ENC && + dis->sR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + __writeReg(p, (pore_internal_reg_t)dis->tR, + __readReg(p, (pore_internal_reg_t)dis->sR) ^ + dis->imd64); + break; + + case PORE_OPCODE_AND: + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + __writeReg(p, (pore_internal_reg_t)dis->tR, + p->scratch1 & p->scratch2); + break; + + case PORE_OPCODE_OR: + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + __writeReg(p, (pore_internal_reg_t)dis->tR, + p->scratch1 | p->scratch2); + break; + + case PORE_OPCODE_XOR: + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + __writeReg(p, (pore_internal_reg_t)dis->tR, + p->scratch1 ^ p->scratch2); + break; + + case PORE_OPCODE_ADDI: { + int64_t add_result; + + if (dis->tR == PORE_EXE_TRIGGER_ENC || + dis->tR == PORE_ALU_IBUF_ID_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + + op1 = __readReg(p, (pore_internal_reg_t)dis->tR); + op2 = dis->imd16; + add_result = op1 + op2; + + setAluFlags(p, op1, op2, add_result, dis->opcode); + __writeReg(p, (pore_internal_reg_t)dis->tR, add_result); + break; + } + case PORE_OPCODE_SUBI: { + int64_t sub_result; + + if (dis->tR == PORE_EXE_TRIGGER_ENC || + dis->tR == PORE_ALU_IBUF_ID_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + + op1 = __readReg(p, (pore_internal_reg_t)dis->tR); + op2 = dis->imd16; + op2 = ~op2 + 1; + sub_result = op1 + op2; + + setAluFlags(p, op1, op2, sub_result, dis->opcode); + __writeReg(p, (pore_internal_reg_t)dis->tR, sub_result); + break; + } + case PORE_OPCODE_ADD: { + int64_t add_result; + + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + + op1 = p->scratch1; + op2 = p->scratch2; + add_result = op1 + op2; + + setAluFlags(p, op1, op2, add_result, dis->opcode); + __writeReg(p, (pore_internal_reg_t)dis->tR, add_result); + break; + } + case PORE_OPCODE_SUB: { + int64_t sub_result; + + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + + op1 = p->scratch1; + op2 = p->scratch2; + op2 = ~op2 + 1; + sub_result = op1 + op2; + setAluFlags(p, op1, op2, sub_result, dis->opcode); + __writeReg(p, (pore_internal_reg_t)dis->tR, sub_result); + break; + } + case PORE_OPCODE_NEG: { + int64_t neg_result; + + if (dis->sR != PORE_SCRATCH1_ENC && + dis->sR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + + op1 = __readReg(p, (pore_internal_reg_t)dis->sR); + neg_result = ~op1 + 1; + __writeReg(p, (pore_internal_reg_t)dis->tR, neg_result); + break; + } + case PORE_OPCODE_COPY: + __writeReg(p, (pore_internal_reg_t)dis->tR, + __readReg(p, (pore_internal_reg_t)dis->sR)); + break; + + case PORE_OPCODE_ROL: { + uint16_t rmask = 0; + uint64_t result = 0; + uint64_t src = 0; + + // Operand Check + rmask = dis->imd16; + if (rmask != 0x1 && rmask != 0x4 && rmask != 0x8 + && rmask != 0x10 && rmask != 0x20 ) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + + } else if ( + dis->sR != PORE_SCRATCH1_ENC && + dis->sR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + + } else if (dis->tR != PORE_SCRATCH1_ENC && + dis->tR != PORE_SCRATCH2_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + + } else { + src = __readReg(p, (pore_internal_reg_t)dis->sR); + result = ( src << rmask ) | + (((~(0xFFFFFFFFFFFFFFFFull >> rmask)) & src ) + >> (64 - rmask)); + } + + __writeReg(p, (pore_internal_reg_t)dis->tR, result); + break; + } + /* Load/Store Instructions */ + case PORE_OPCODE_LOAD20: { + if (dis->tR == PORE_EXE_TRIGGER_ENC || + dis->tR == PORE_ALU_IBUF_ID_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + /** + * ImD20 will be signed extended to 64b (on MSB side) + * and then truncated to the width of <tR>. + */ + __writeReg(p, (pore_internal_reg_t)dis->tR, dis->imd20); + break; + } + case PORE_OPCODE_LOAD64: + if (dis->tR == PORE_PRV_BASE_ADDR0_ENC || + dis->tR == PORE_PRV_BASE_ADDR1_ENC || + dis->tR == PORE_EXE_TRIGGER_ENC || + dis->tR == PORE_ALU_IBUF_ID_ENC) { + BUG(); + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instruction_operand = 1; + me = pore_handleErrEvent(p,2,PORE_ERR_INVALID_OPERAND); + break; + } + + __writeReg(p, (pore_internal_reg_t)dis->tR, dis->imd64); + break; + + case PORE_OPCODE_SCR1RD: { + me = inExeInterfaceRead(p, &read_data); + if (me < 0) + break; + p->scratch1 = read_data; + break; + } + case PORE_OPCODE_SCR2RD: { + me = inExeInterfaceRead(p, &read_data); + if (me < 0) + break; + p->scratch2 = read_data; + break; + } + case PORE_OPCODE_SCR1RDA: { + // Read DATA from OCI/PRV Address Space using effective addr + me = inExeInterfaceRead(p, &read_data); + if (me < 0) + break; + // Apply imd64 AND mask + read_data &= dis->imd64; + p->scratch1 = read_data; + break; + } + case PORE_OPCODE_SCR2RDA: { + // Read DATA from OCI/PRV Address Space using effective addr + me = inExeInterfaceRead(p, &read_data); + if (me < 0) + break; + // Apply imd64 AND mask + read_data &= dis->imd64; + p->scratch2 = read_data; + break; + } + case PORE_OPCODE_WRI: { + write_data = dis->imd64; + // Write DATA to OCI/PRV Address Space using effective addr + me = inExeInterfaceWrite(p, write_data); + if (me < 0) + break; + break; + } + case PORE_OPCODE_BS: { + // Read OCI/PRV space from effective address to read_data + me = inExeInterfaceRead(p, &read_data); + if (me < 0) + break; + // Apply OR mask to read_data + read_data |= dis->imd64; + // update scratch register + p->scratch1 = read_data; + // Write the data back to effective address in OCI/PRV + me = inExeInterfaceWrite(p, read_data); + if (me < 0) + break; + break; + } + case PORE_OPCODE_BC: { + // Read OCI/PRV space from effective address to read_data + me = inExeInterfaceRead(p, &read_data); + if (me < 0) + break; + // Apply Inverted AND mask to read_data + read_data &= ~(dis->imd64); + // Update scratch register + p->scratch1 = read_data; + // Write the data back to effective address in OCI/PRV + me = inExeInterfaceWrite(p, read_data); + if (me < 0) + break; + break; + } + case PORE_OPCODE_SCR1WR: { + write_data = p->scratch1; + // Write DATA to OCI/PRV Address Space using effective addr + me = inExeInterfaceWrite(p, write_data); + if (me < 0) + break; + break; + } + case PORE_OPCODE_SCR2WR: { + write_data = p->scratch2; + // Write DATA to OCI/PRV Address Space using effective addr + me = inExeInterfaceWrite(p, write_data); + if (me < 0) + break; + break; + } + case PORE_OPCODE_SCAND: + me = pore_scand(p); + if (me < 0) { + me = pore_handleErrEvent(p, 2, me); + break; + } + break; + + default: + eprintf(p, "err: Invalid Instruction Encoding: " + " %08x %08x %08x\n", + (unsigned int)p->ibuf_01.ibuf0, + (unsigned int)p->ibuf_01.ibuf0, + (unsigned int)p->ibuf_2.ibuf2); + + if (p->dbg1.debug_regs_locked == 0) + p->dbg1.invalid_instr_code = 1; + me = pore_handleErrEvent(p, 2, PORE_ERR_INVALID_OPCODE); + break; + } + + // Check for address, trap, magic breakpoints and single-step. + // Note that we do the dumps + + addressBreakpoint = (p->status.pc == p->control.pc_brk_pt); + + if (addressBreakpoint) { + pore_dump(p); + next_state = PORE_STATE_ABR; + p->broken = 1; + dprintf(p, "PORE Address Breakpoint @ 0x%012llx\n", + (long long)p->status.pc); + } else if (trapBreakpoint) { + pore_dump(p); + next_state = PORE_STATE_ABR; + p->broken = 1; + dprintf(p, "PORE Trap Breakpoint @ 0x%012llx\n", + (long long)p->status.pc); + } + + // Branches have already updated the PC so the assignment to + // the PC is done here. Otherwise we increment the PC for the + // next step unless we're broken. + // + // In case of me < 0 the pore_handeErrEvent() function has set + // a new PC by jumping into the appropriate Error Vector. In + // this case we do not update the current PC instead it was + // pushed onto the stack. After the error handler has tidied + // up, it can jump back to the failing instruction. + + if (me >= 0) { + if (p->branchTaken) { + p->status.pc = next_pc.val; + } else if (!p->broken) { + incrPc(p); + } + } + + // Step mode. don't update state and don't schedule next step + // Condition can occur when we are hitting an error during + // instruction execution, e.g. a pib_read failed. + + if (p->control.start_stop == 1) { + dprintf(p, "PORE was stopped during execution!\n"); + p->status.cur_state = PORE_STATE_WAIT; + + } else if (p->reset.fn_reset) { + dprintf(p, "PORE is being held in reset!\n"); + me = PORE_ERR_IN_RESET; + + } else{ + p->status.cur_state = next_state; + } + + return me; +} + +/// If the instruction was broken, finish it. +/// +/// If the PORE is an a 'broken' state, then we first need to update +/// the PC by re-decoding the current instruction. Taken branches +/// have already updated the PC. +/// +/// The situation occurs if we have hit a breakpoint. In this case the +/// PC has still the value of the breakpoint instruction, but needs to +/// be updated when the user writes 1 to control.continue_step. + +static int finishBrokenInstruction(pore_model_t p) +{ + if (!p) + return PORE_ERR_INVALID_PARAM; + + if (p->broken && !p->branchTaken) { + decode(p); + incrPc(p); + } + + p->branchTaken = 0; + p->broken = 0; + return PORE_SUCCESS; +} + +int pore_step(pore_model_t p) +{ + int rc = PORE_SUCCESS; + + if (!p) + return PORE_ERR_INVALID_PARAM; + + dprintf(p, "(0) ensure we are in correct state to do a step ...\n"); + if (p->reset.fn_reset == 1) { + dprintf(p, " no: engine is in reset\n"); + return PORE_IN_RESET; + } + if (p->control.start_stop == 1) { + dprintf(p, " no: engine is stopped\n"); + return PORE_STOPPED; + } + if (p->status.cur_state == PORE_STATE_ABR) { + dprintf(p, " no: engine has hit a breakpoint\n"); + return PORE_BREAKPOINT_HIT; + } + + p->branchTaken = 0; /* reset internal state */ + p->broken = 0; + + dprintf(p, "(1) fetch @ %016llx ...\n", (long long)p->status.pc); + rc = fetch(p); + if (rc < 0) { + eprintf(p, "%s: err: fetch rc=%d\n", __func__, rc); + return rc; + } + + dprintf(p, "(2) decode ...\n"); + rc = decode(p); + if (rc < 0) { + eprintf(p, "%s: err: decode rc=%d\n", __func__, rc); + return rc; + } + + dprintf(p, "(3) execute ...\n"); + rc = execute(p); + if (rc < 0) { + eprintf(p, "%s: err: execute rc=%d\n", __func__, rc); + return rc; + } + + return rc; +} + +void pore_dump(pore_model_t p) +{ + PoreAddress a0, a1; + PoreAddress sp0, sp1, sp2; + int sp; + uint32_t p0, p1; + + sp0.val = p->pc_stack[0].pc_stack; + sp1.val = p->pc_stack[1].pc_stack; + sp2.val = p->pc_stack[2].pc_stack; + + a0.val = __readReg(p, PORE_OCI_MEMORY_BASE_ADDR0_ENC); + a1.val = __readReg(p, PORE_OCI_MEMORY_BASE_ADDR1_ENC); + p0 = __readReg(p, PORE_PRV_BASE_ADDR0_ENC); + p1 = __readReg(p, PORE_PRV_BASE_ADDR1_ENC); + + aprintf("-------------------------------------" + "-------------------------------------\n" + "%s : PORE Id %d.\n" + "-------------------------------------" + "-------------------------------------\n" + " IBUF: %08llx %08x.%08x.%08x\n" + "-------------------------------------" + "-------------------------------------\n" + " D0 : %016llx D1 : %016llx\n" + " A0 : %04x:%08x A1 : %04x:%08x\n" + " P0 : %02x P1 : %02x\n" + " CTR : %06x\n" + "-------------------------------------" + "-------------------------------------\n", + __func__, + (uint32_t)(p->id_flags.ibuf_id), + (long long)p->status.pc, + p->ibuf_01.ibuf0, + p->ibuf_01.ibuf1, + p->ibuf_2.ibuf2, + (long long)p->scratch1, + (long long)p->scratch2, + (unsigned int)a0.memorySpace, (unsigned int)a0.offset, + (unsigned int)a1.memorySpace, (unsigned int)a1.offset, + p0, p1, (uint32_t)p->scratch0.scratch0); + + sp = p->status.stack_pointer; + /* pore_status_reg_print(&p->status); */ + /* pore_control_reg_print(&p->control); */ + + if (sp == 0) { + aprintf("The stack is empty\n"); + } else { + aprintf("Stack Trace\n" + " Level 0 : %04x:%08x\n", + (unsigned int)sp0.memorySpace, + (unsigned int)sp0.offset); + if (sp > 0x1) { + aprintf(" Level 1 : %04x:%08x\n", + (unsigned int)sp1.memorySpace, + (unsigned int)sp1.offset); + } + if (sp > 0x2) { + aprintf(" Level 2 : %04x:%08x\n", + (unsigned int)sp2.memorySpace, + (unsigned int)sp2.offset); + } + } + + aprintf("-------------------------------------" + "-------------------------------------\n" + "Last pervasive access @ %08x returned error code %d\n" + "-------------------------------------" + "-------------------------------------\n", + (uint32_t)p->dbg0.last_completed_address, + (int)p->dbg0.last_ret_code_prv); + + aprintf(" PORe Registers\n" + " STATUS: %016llx CONTROL: %016llx\n" + " RESET: %016llx ERR_MASK: %016llx\n" + " PVR_BASE0/P0: %016llx PVR_BASE1/P1: %016llx\n" + " OCI_BASE0/A0: %016llx OCI_BASE1/A1: %016llx\n" + " TBL_BASE: %016llx EXE_TRIGGER: %016llx\n" + " SCR0/CTR: %016llx SCR1/D0: %016llx\n" + " SCR2/D1: %016llx IBUF012: %08llx.%08llx.%08llx\n" + " DBG0: %016llx DBG1: %016llx\n" + " PC_STACK0: %016llx PC_STACK1: %016llx\n" + " PC_STACK2: %016llx ID_FLAGS: %016llx\n" + " DATA0: %016llx MEM_RELOC: %016llx\n" + " I2C_E0: %016llx I2C_E1: %016llx\n" + " I2C_E2: %016llx PC: %016llx\n" + "-------------------------------------" + "-------------------------------------\n", + (long long)p->status.val, (long long)p->control.val, + (long long)p->reset.val, (long long)p->error_mask.val, + (long long)p->prv_base[0].val, (long long)p->prv_base[1].val, + (long long)p->oci_base[0].val, (long long)p->oci_base[1].val, + (long long)p->table_base_addr.val, + (long long)p->exe_trigger.val, + (long long)p->scratch0.val, (long long)p->scratch1, + (long long)p->scratch2, (long long)p->ibuf_01.ibuf0, + (long long)p->ibuf_01.ibuf1, (long long)p->ibuf_2.ibuf2, + (long long)p->dbg0.val, (long long)p->dbg1.val, + (long long)p->pc_stack[0].val, (long long)p->pc_stack[1].val, + (long long)p->pc_stack[2].val, (long long)p->id_flags.val, + (long long)p->data0, (long long)p->memory_reloc.val, + (long long)p->i2c_e_param[0].val, + (long long)p->i2c_e_param[1].val, + (long long)p->i2c_e_param[2].val, + (long long)p->status.pc); +} + +/* Model Creation ************************************************************/ + +int pore_flush_reset(pore_model_t p) +{ + dprintf(p, "%s: %s\n", __func__, p->name); + + p->status.val = 0; + p->status.cur_state = PORE_STATE_WAIT; + + p->control.val = 0; + p->control.start_stop = 1; + + p->control.lock_exe_trig = 0; + p->control.check_parity = 0; + p->control.prv_parity = 0; + p->control.pc_brk_pt = 0xffffffffffffull; + + p->prv_base[0].val = 0; + p->prv_base[1].val = 0; + p->oci_base[0].val = 0; + p->oci_base[1].val = 0; + p->table_base_addr.val = 0; + p->exe_trigger.val = 0; + p->scratch0.val = 0; + p->scratch1 = 0; + p->scratch2 = 0; + p->ibuf_01.val = 0; + p->ibuf_2.val = 0; + + p->id_flags.val = p->id_flags.ibuf_id; /* keep ibuf_id */ + p->dbg0.val = 0; + p->dbg1.val = 0; + p->pc_stack[0].val = 0; /* clears one bits on a write */ + p->pc_stack[1].val = 0; + p->pc_stack[2].val = 0; + + p->data0 = 0; + p->memory_reloc.val = 0; + p->status.pc = 0; + p->err_code = 0; + p->branchTaken = 0; + p->broken = 0; + p->singleStep = 0; + p->forcedBranchMode = FORCED_BRANCH_DISALLOWED; + p->forcedPc = 0; + /* page 74: IBUF Err Mask, not altered during functional PORE reset. */ + + poreb_reset(p->pib); /* reset bus models, e.g. clear buffers */ + poreb_reset(p->mem); + + return 0; +} + +pore_model_t pore_model_create(const char *name) +{ + pore_model_t p; + + p = (pore_model_t)malloc(sizeof(*p)); + if (!p) + return NULL; + memset(p, 0, sizeof(*p)); + + p->name = name; + pore_flush_reset(p); + p->status.pc = 0; + p->enableHookInstruction = 0; + p->enableAddressHooks = 0; + + p->trace_flags = PORE_TRACE_ERR; + return p; +} + +void pore_model_destroy(pore_model_t p) +{ + poreb_destroy(p->pib); + poreb_destroy(p->mem); + free(p); +} + +int pore_registerHooks (pore_model_t p, + instrHook_f instrHook, + readHook_f readHook, + writeHook_f writeHook, + fetchHook_f fetchHook, + decodeHook_f decodeHook) +{ + p->instrHook = instrHook; + p->readHook = readHook; + p->writeHook = writeHook; + p->fetchHook = fetchHook; + p->decodeHook = decodeHook; + return 0; +} + +int pore_registerCallbacks(pore_model_t p, + waitCallback_f waitCallback, + errorCallback_f errorCallback, + errorCallback_f fatalErrorCallback) +{ + p->waitCallback = waitCallback; + p->errorCallback = errorCallback; + p->fatalErrorCallback = fatalErrorCallback; + return 0; +} + +void pore_setpriv(pore_model_t p, void *priv) +{ + p->priv = priv; +} + +void *pore_getpriv(pore_model_t p) +{ + return p->priv; +} + +/* recursive function to setup the pore pointer in all bus attachements */ +static void poreb_set_pore(struct pore_bus *b, pore_model_t p) +{ + unsigned int i; + + if (b == NULL) + return; + b->pore = p; + for (i = 0; i < PORE_MAX_BUS; i++) + poreb_set_pore(b->slaves[i], p); +} + +int pore_attach_mem(pore_model_t p, struct pore_bus *b) +{ + p->mem = b; + poreb_set_pore(b, p); + return 0; +} + +int pore_attach_pib(pore_model_t p, struct pore_bus *b) +{ + p->pib = b; + poreb_set_pore(b, p); + return 0; +} + +int pore_extractState(pore_model_t p, struct pore_state *s) +{ + memcpy(s, p, sizeof(*s)); + return 0; +} + +int pore_installState(pore_model_t p, const struct pore_state *s) +{ + memcpy(p, s, sizeof(*s)); + return 0; +} + +void pore_set_enableHookInstr(pore_model_t p, int enabled) +{ + p->enableHookInstruction = enabled; +} + +int pore_get_enableHookInstr(pore_model_t p) +{ + return p->enableHookInstruction; +} + +void pore_set_enableAddressHooks(pore_model_t p, int enabled) +{ + p->enableAddressHooks = enabled; +} + +int pore_get_enableAddressHooks(pore_model_t p) +{ + return p->enableAddressHooks; +} + +int +pore_forceBranch(pore_model_t p, uint64_t addr) +{ + switch (p->forcedBranchMode) { + + case FORCED_BRANCH_DISALLOWED: + return PORE_ERR_ILLEGAL_FORCED_BRANCH; + + case FORCED_BRANCH_FETCH_HOOK: + case FORCED_BRANCH_HOOK_INSTRUCTION: + p->forcedPc = addr; + p->forcedBranch = 1; + break; + } + return PORE_SUCCESS; +} + +int pore_stop(pore_model_t p) +{ + uint64_t control; + control = pore_readReg(p, PORE_R_CONTROL, PORE_BITS_0_63); + /* set start_stop bit[0] */ + pore_writeReg(p, PORE_R_CONTROL, control | BE64_BIT(0), + PORE_BITS_0_63); + return PORE_SUCCESS; +} + +int pore_start(pore_model_t p) +{ + uint64_t control; + control = pore_readReg(p, PORE_R_CONTROL, PORE_BITS_0_63); + /* clear start_stop bit[0] */ + pore_writeReg(p, PORE_R_CONTROL, control & ~BE64_BIT(0), + PORE_BITS_0_63); + return PORE_SUCCESS; +} + +int pore_setPc(pore_model_t p, uint64_t pc) +{ + pore_stop(p); + pore_writeReg(p, PORE_R_CONTROL, BE64_BIT(3) | + (pc & BE64_MASK(16, 63)), PORE_BITS_0_63); + return PORE_SUCCESS; +} + +int pore_setBreakpoint(pore_model_t p, uint64_t bp) +{ + uint64_t control; + + control = pore_readReg(p, PORE_R_CONTROL, PORE_BITS_0_63); + control &= ~BE64_MASK(16, 63); + control |= (bp & BE64_MASK(16, 63)); + pore_writeReg(p, PORE_R_CONTROL, control, PORE_BITS_0_63); + return PORE_SUCCESS; +} + +int pore_enableTrap(pore_model_t p, int enable) +{ + uint64_t control; + + control = pore_readReg(p, PORE_R_CONTROL, PORE_BITS_0_63); + if (enable) { + control |= BE64_BIT(11); + } else { + control &= ~BE64_BIT(11); + } + pore_writeReg(p, PORE_R_CONTROL, control, PORE_BITS_0_63); + return PORE_SUCCESS; +} + +static int __fake_read(struct pore_bus *b, uint64_t addr, + uint8_t *buf, unsigned int len, + int *err_code __attribute__((unused))) +{ + unsigned int i; + + memset(buf, 0xff, len); + dprintf(b->pore, " %-12s: %s(%p, 0x%08llx, ...)\n read: ", + b->name, __func__, b, (long long)addr); + + for (i = 0; i < len; i++) + dprintf(b->pore, "%02x ", buf[i]); + dprintf(b->pore, "\n"); + + return len; +} + +static int __fake_write(struct pore_bus *b, uint64_t addr, + const uint8_t *buf, unsigned int len, + int *err_code __attribute__((unused))) +{ + unsigned int i; + + dprintf(b->pore, " %-12s: %s(%p, 0x%08llx, ...)\n write: ", + b->name, __func__, b, (long long)addr); + for (i = 0; i < len; i++) + dprintf(b->pore, "%02x ", buf[i]); + dprintf(b->pore, "\n"); + + return len; +} + +static int __fake_fetch(struct pore_bus *b, uint64_t pc, + uint64_t *ibuf_01 __attribute__((unused)), + uint64_t *ibuf_2 __attribute__((unused)), + unsigned int *size, + int *err_code __attribute__((unused))) +{ + dprintf(b->pore, " %-12s: %s(%p, 0x%08llx, ...)\n fetch: ", + b->name, __func__, b, (long long)pc); + + *size = 4; + return *size; +} + +static int __fake_reset(struct pore_bus *b) +{ + dprintf(b->pore, " %s: %s(%p)\n", b->name, __func__, b); + return 0; +} + +pore_model_t +pore_sbe_create(pore_bus_t pib) +{ + pore_model_t p; + pore_bus_t fi2cm[3], pore2fi2cm; + + p = pore_model_create("SBE"); + if (!p) + return NULL; + p->id_flags.ibuf_id = PORE_IBUF_ID_SBE; + p->error_mask.val = 0x00BFF00000000000ull; /* FIXME spec undefined */ + + /* SEEPROM */ + p->i2c_e_param[0].i2c_engine_identifier = 0xc; + p->i2c_e_param[0].i2c_engine_address_range = 0x2; + p->i2c_e_param[0].i2c_engine_port = 0x0; + p->i2c_e_param[0].i2c_engine_device_id = 0x0; + + /* OTPROM */ + p->i2c_e_param[1].i2c_engine_identifier = 0x1; + p->i2c_e_param[1].i2c_engine_address_range = 0x2; + p->i2c_e_param[1].i2c_engine_port = 0x0; + p->i2c_e_param[1].i2c_engine_device_id = 0x0; + + /* PNOR */ + p->i2c_e_param[2].i2c_engine_identifier = 0xb; + p->i2c_e_param[2].i2c_engine_address_range = 0x4; + p->i2c_e_param[2].i2c_engine_port = 0x0; + p->i2c_e_param[2].i2c_engine_device_id = 0x0; + + /* OCI/MEM Route */ + p->oci_base[0].val = 0; + p->oci_base[0].oci_mem_route = 0xa; /* matches here SEEPROM */ + p->oci_base[0].oci_base_address = 0x000000000; + + p->oci_base[1].val = 0; + p->oci_base[1].oci_mem_route = 0x1; /* matches here OTP */ + p->oci_base[1].oci_base_address = 0x000000000; + + /* Table base address defines where start and exception vectors are */ + p->table_base_addr.val = 0; + p->table_base_addr.table_base_address = 0x00010008 << 3; /* for SBE */ + + /* setup reference for the case it is not yet done. */ + if (pib) + pib->pore = p; + + /* underlying busses which finally implement functionality */ + if (!pib) + pib = poreb_create("PIB", 0, __fake_read, __fake_write, + __fake_fetch, __fake_reset); + + fi2cm[0] = poreb_create_fi2cm(p, "FI2CM0", pib, &p->i2c_e_param[0]); + fi2cm[1] = poreb_create_fi2cm(p, "FI2CM1", pib, &p->i2c_e_param[1]); + fi2cm[2] = poreb_create_fi2cm(p, "FI2CM2", pib, &p->i2c_e_param[2]); + + /* view of PORe engine which goes through remappings + before the underlying busses are accessed */ + + /* SBE: 3 FI2C masters are servicing this memory range */ + pore2fi2cm = poreb_create_pore2fi2c(p, "PORE2FI2C", + fi2cm[0], fi2cm[1], fi2cm[2]); + if (!pore2fi2cm) + return NULL; + + pore_attach_mem(p, pore2fi2cm); + pore_attach_pib(p, pib); + + return p; +} + +static pore_model_t +__slw_create(const char *name, pore_bus_t pib, pore_bus_t oci, + uint32_t ibuf_id) +{ + pore_model_t p; + struct pore_bus *pore2oci_b; + + p = pore_model_create(name); + if (!p) + return NULL; + p->id_flags.ibuf_id = ibuf_id; + p->error_mask.val = 0x00BFF00000000000ull; + + /* setup reference for the case it is not yet done. */ + if (pib) + pib->pore = p; + if (oci) + oci->pore = p; + + /* underlying busses which finally implement functionality */ + if (!pib) + pib = poreb_create("PIB", 0, __fake_read, __fake_write, + __fake_fetch, __fake_reset); + + if (!oci) + oci = poreb_create("OCI", 0, __fake_read, __fake_write, + __fake_fetch, __fake_reset); + + /* view of PORe engine which goes through remappings + before the underlying busses are accessed */ + + /* SLW/GPE0/GPE1: OCI is servicing this memory range */ + pore2oci_b = poreb_create_pore2oci(p, "PORE2OCI", oci); + if (!pore2oci_b) + return NULL; + + pore_attach_mem(p, pore2oci_b); + pore_attach_pib(p, pib); + return p; +} + +pore_model_t +pore_slw_create(pore_bus_t pib, pore_bus_t oci) +{ + return __slw_create("SLW", pib, oci, PORE_IBUF_ID_SLW); +} + +pore_model_t +pore_gpe0_create(pore_bus_t pib, pore_bus_t oci) +{ + return __slw_create("GPE0", pib, oci, PORE_IBUF_ID_GPE0); +} + +pore_model_t +pore_gpe1_create(pore_bus_t pib, pore_bus_t oci) +{ + return __slw_create("GPE1", pib, oci, PORE_IBUF_ID_GPE1); +} diff --git a/src/usr/pore/poreve/pore_model/ibuf/pore_regs.h b/src/usr/pore/poreve/pore_model/ibuf/pore_regs.h new file mode 100644 index 000000000..0376deeff --- /dev/null +++ b/src/usr/pore/poreve/pore_model/ibuf/pore_regs.h @@ -0,0 +1,671 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/ibuf/pore_regs.h $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __PORE_REGS__ +#define __PORE_REGS__ + +/****************************************************************************** + * + * Virtual PORe Engine + * + *****************************************************************************/ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/* 64-bit in IBM notation: + 11.1111.1111.2222.2222.2233|3333.3333.4444.4444.4455.5555.5555.6666 +0123.4567.8901.2345.6789.0123.4567.8901|2345.6789.0123.4567.8901.2345.6789.0123 +*/ + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t cur_state: 8; + uint64_t freeze_action: 1; + uint64_t spare : 3; + uint64_t stack_pointer : 4; + uint64_t pc : 48; +#else + uint64_t pc : 48; + uint64_t stack_pointer : 4; + uint64_t spare : 3; + uint64_t freeze_action: 1; + uint64_t cur_state: 8; +#endif + }; + uint64_t val; +} pore_status_reg; + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + /* bits 0:3 */ + uint64_t start_stop : 1; + uint64_t continue_step : 1; + uint64_t skip : 1; + uint64_t set_pc : 1; + /* bits 4:7 */ + uint64_t set_tp_scan_clk : 3; + uint64_t lock_exe_trig : 1; + /* bits 8:11 */ + uint64_t freeze_mask : 1; + uint64_t check_parity : 1; + uint64_t prv_parity : 1; + uint64_t trap_enable : 1; + /* bits 12:15 */ + uint64_t tbd : 4; + uint64_t pc_brk_pt : 48; +#else + uint64_t pc_brk_pt : 48; + uint64_t tbd : 4; + uint64_t trap_enable : 1; + uint64_t prv_parity : 1; + uint64_t check_parity : 1; + uint64_t freeze_mask : 1; + uint64_t lock_exe_trig : 1; + uint64_t set_tp_scan_clk : 3; + uint64_t set_pc : 1; + uint64_t skip : 1; + uint64_t continue_step : 1; + uint64_t start_stop : 1; + +#endif + }; + uint64_t val; +} pore_control_reg; + +#define PORE_RESET_VALID_BITS 0xe000000000000000ull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t fn_reset : 1; + uint64_t oci_reset : 1; + uint64_t restart_sbe_trigger : 1; + uint64_t reserved0 : 61; +#else + uint64_t reserved0 : 61; + uint64_t restart_sbe_trigger : 1; + uint64_t oci_reset : 1; + uint64_t fn_reset : 1; +#endif + }; + uint64_t val; +} pore_reset_reg; + +#define PORE_ERROR_MASK_VALID_BITS 0xfffff80000000000ull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t enable_err_handler0 : 1; + uint64_t enable_err_handler1 : 1; + uint64_t enable_err_handler2 : 1; + uint64_t enable_err_handler3 : 1; + + uint64_t enable_err_handler4 : 1; + uint64_t enable_err_output0 : 1; + uint64_t enable_err_output1 : 1; + uint64_t enable_err_output2 : 1; + + uint64_t enable_err_output3 : 1; + uint64_t enable_err_output4 : 1; + uint64_t enable_fatal_error0 : 1; + uint64_t enable_fatal_error1 : 1; + + uint64_t enable_fatal_error2 : 1; + uint64_t enable_fatal_error3 : 1; + uint64_t enable_fatal_error4 : 1; + uint64_t stop_exe_on_error0 : 1; + + uint64_t stop_exe_on_error1 : 1; + uint64_t stop_exe_on_error2 : 1; + uint64_t stop_exe_on_error3 : 1; + uint64_t stop_exe_on_error4 : 1; + + uint64_t gate_chiplet_offline_err : 1; + uint64_t _reserved0 : 43; +#else + uint64_t _reserved0 : 43; + uint64_t gate_chiplet_offline_err : 1; + + uint64_t stop_exe_on_error4 : 1; + uint64_t stop_exe_on_error3 : 1; + uint64_t stop_exe_on_error2 : 1; + uint64_t stop_exe_on_error1 : 1; + + uint64_t stop_exe_on_error0 : 1; + uint64_t enable_fatal_error4 : 1; + uint64_t enable_fatal_error3 : 1; + uint64_t enable_fatal_error2 : 1; + + uint64_t enable_fatal_error1 : 1; + uint64_t enable_fatal_error0 : 1; + uint64_t enable_err_output4 : 1; + uint64_t enable_err_output3 : 1; + + uint64_t enable_err_output2 : 1; + uint64_t enable_err_output1 : 1; + uint64_t enable_err_output0 : 1; + uint64_t enable_err_handler4 : 1; + + uint64_t enable_err_handler3 : 1; + uint64_t enable_err_handler2 : 1; + uint64_t enable_err_handler1 : 1; + uint64_t enable_err_handler0 : 1; +#endif + }; + uint64_t val; +} pore_error_mask_reg; + +#define PORE_PRV_BASE_ADDRESS_VALID_BITS 0x0000007fffffffffull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t spare : 25; + uint64_t mc : 1; + uint64_t chiplet_id : 6; + uint64_t reserved0 : 32; +#else + uint64_t reserved0 : 32; + uint64_t chiplet_id : 6; + uint64_t mc : 1; + uint64_t spare : 25; +#endif + }; + uint64_t val; +} pore_prv_base_address_reg; + +#define PORE_OCI_BASE_ADDRESS_VALID_BITS 0x00003fffffffffffull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t spare : 18; + uint64_t oci_mem_route : 14; + /** + * oci_mem_route : 14 results in: + * 18:32 chiplet_id : 6 + * 24:27 pib_master : 4; + * 28:31 prv_port_no : 4; + */ + uint64_t oci_base_address : 32; +#else + uint64_t oci_base_address : 32; + uint64_t oci_mem_route : 14; + uint64_t spare : 18; +#endif + }; + uint64_t val; +} pore_oci_base_address_reg; + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t reserved : 16; + uint64_t memory_space : 16; + uint64_t table_base_address : 32; +#else + uint64_t table_base_address : 32; + uint64_t memory_space : 16; + uint64_t reserved : 16; +#endif + }; + uint64_t val; +} pore_table_base_addr_reg; + +#define PORE_EXE_TRIGGER_VALID_BITS 0x00fff000ffffffffull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t reserved : 8; + uint64_t start_vector : 4; + uint64_t zeroes : 8; + uint64_t unused : 12; + uint64_t mc_chiplet_select_mask : 32; +#else + uint64_t mc_chiplet_select_mask : 32; + uint64_t unused : 12; + uint64_t zeroes : 8; + uint64_t start_vector : 4; + uint64_t reserved : 8; +#endif + }; + uint64_t val; +} pore_exe_trigger_reg; + +#define PORE_SCRATCH0_VALID_BITS 0x0fffffff00000000ull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t zeroes : 8; + uint64_t scratch0 : 24; + uint64_t reserved : 32; +#else + uint64_t reserved : 32; + uint64_t scratch0 : 24; + uint64_t zeroes : 8; +#endif + }; + uint64_t val; +} pore_scratch0_reg; + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t ibuf0 : 32; + uint64_t ibuf1 : 32; +#else + uint64_t ibuf1 : 32; + uint64_t ibuf0 : 32; +#endif + }; + uint64_t val; +} pore_ibuf_01_reg; + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t ibuf2 : 32; + uint64_t reserved0 : 32; +#else + uint64_t reserved0 : 32; + uint64_t ibuf2 : 32; +#endif + }; + uint64_t val; +} pore_ibuf_2_reg; + +#define PORE_DBG0_VALID_BITS 0xfffffffff0000000ull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t last_completed_address : 32; + uint64_t filler_bit : 1; /* clearOnAnyWrite */ + uint64_t last_ret_code_prv : 3; /* clearOnAnyWrite */ + uint64_t spare : 28; /* clearOnAnyWrite */ +#else + uint64_t spare : 28; /* clearOnAnyWrite */ + uint64_t last_ret_code_prv : 3; /* clearOnAnyWrite */ + uint64_t filler_bit : 1; /* clearOnAnyWrite */ + uint64_t last_completed_address : 32; +#endif + }; + uint64_t val; +} pore_dbg0_reg; + +#define PORE_DBG1_VALID_BITS 0xfffffffffffffffdull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t pc_last_access : 48; + uint64_t oci_master_rd_parity_err : 1; + uint64_t last_ret_code_oci : 3; + uint64_t bad_instr_parity : 1; + uint64_t invalid_instr_code : 1; + uint64_t pc_overflow_underrun : 1; + uint64_t bad_scan_crc : 1; + uint64_t pc_stack_ovflw_undrn_err : 1; + uint64_t instruction_fetch_error : 1; + uint64_t invalid_instruction_operand : 1; + uint64_t invalid_instruction_path : 1; + uint64_t invalid_start_vector : 1; + uint64_t fi2c_protocol_hang : 1; + uint64_t spare : 1; + uint64_t debug_regs_locked : 1; +#else + uint64_t debug_regs_locked : 1; + uint64_t spare : 1; + uint64_t fi2c_protocol_hang : 1; + uint64_t invalid_start_vector : 1; + uint64_t invalid_instruction_path : 1; + uint64_t invalid_instruction_operand : 1; + uint64_t instruction_fetch_error : 1; + uint64_t pc_stack_ovflw_undrn_err : 1; + uint64_t bad_scan_crc : 1; + uint64_t pc_overflow_underrun : 1; + uint64_t invalid_instr_code : 1; + uint64_t bad_instr_parity : 1; + uint64_t last_ret_code_oci : 3; + uint64_t oci_master_rd_parity_err : 1; + uint64_t pc_last_access : 48; +#endif + }; + uint64_t val; +} pore_dbg1_reg; + +#define PORE_PC_STACK0_VALID_BITS 0xffffffffffff001full +#define PORE_PC_STACK1_VALID_BITS 0xffffffffffff0000ull +#define PORE_PC_STACK2_VALID_BITS 0xffffffffffff0000ull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t pc_stack : 48; + uint64_t reserved0 : 11; + uint64_t set_stack_pointer : 1; /* clearOnAnyWrite */ + uint64_t new_stack_pointer : 4; /* clearOnAnyWrite */ +#else + uint64_t new_stack_pointer : 4; /* clearOnAnyWrite */ + uint64_t set_stack_pointer : 1; /* clearOnAnyWrite */ + uint64_t reserved0 : 11; + uint64_t pc_stack : 48; +#endif + }; + uint64_t val; +} pore_pc_stack0_reg; + +#define PORE_ID_FLAGS_VALID_BITS 0xffffffffffffff0full + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t reserved0 : 32; /* 0..31 */ + uint64_t pib_parity_fail : 1; /* 32 */ + uint64_t pib_status : 3; /* 33..35 */ + uint64_t oci_parity_fail : 1; /* 36 */ + uint64_t oci_status : 3; /* 37..39 */ + uint64_t reserved1 : 8; /* 40..47 */ + uint64_t ugt : 1; /* 48 unsigned greater than */ + uint64_t ult : 1; /* 49 unsigned less than */ + uint64_t sgt : 1; /* 50 signed greater than */ + uint64_t slt : 1; /* 51 signed smaller than */ + uint64_t c : 1; /* 52 carry */ + uint64_t o : 1; /* 53 overflow */ + uint64_t n : 1; /* 54 negative */ + uint64_t z : 1; /* 55 zero flag */ + uint64_t reserved2 : 4; /* 56..59 */ + uint64_t ibuf_id : 4; /* 60..63 */ +#else + uint64_t ibuf_id : 4; + uint64_t reserved2 : 4; + uint64_t z : 1; + uint64_t n : 1; + uint64_t o : 1; + uint64_t c : 1; + uint64_t slt : 1; + uint64_t sgt : 1; + uint64_t ult : 1; + uint64_t ugt : 1; + uint64_t reserved1 : 8; + uint64_t oci_status : 3; + uint64_t oci_parity_fail : 1; + uint64_t pib_status : 3; + uint64_t pib_parity_fail : 1; + uint64_t reserved0 : 32; +#endif + }; + uint64_t val; +} pore_id_flags_reg; + +#define PORE_MEMORY_RELOC_VALID_BITS 0x00000003fffff000ull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t reserved0 : 30; + uint64_t memory_reloc_region : 2; + uint64_t memory_reloc_base : 20; + uint64_t reserved1 : 12; +#else + uint64_t reserved1 : 12; + uint64_t memory_reloc_base : 20; + uint64_t memory_reloc_region : 2; + uint64_t reserved0 : 30; +#endif + }; + uint64_t val; +} pore_memory_reloc_reg; + +#define PORE_DATA0_VALID_BITS 0xffffffff00000000ull + +#define PORE_I2C_E0_PARAM_VALID_BITS 0xff3f7fff00000000ull +#define PORE_I2C_E1_PARAM_VALID_BITS 0xff3f7ff000000000ull +#define PORE_I2C_E2_PARAM_VALID_BITS 0xff3f7ff000000000ull + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t i2c_engine_identifier : 4; + uint64_t i2c_engine_address_range : 4; + uint64_t reserved1 : 2; + uint64_t i2c_engine_port : 6; + uint64_t reserved2 : 1; + uint64_t i2c_engine_device_id : 7; + uint64_t i2c_engine_speed : 8; + uint64_t reserved0 : 32; +#else + uint64_t reserved0 : 32; + uint64_t i2c_engine_speed : 8; + uint64_t i2c_engine_device_id : 7; + uint64_t reserved2 : 1; + uint64_t i2c_engine_port : 6; + uint64_t reserved1 : 2; + uint64_t i2c_engine_address_range : 4; + uint64_t i2c_engine_identifier : 4; + +#endif + }; + uint64_t val; +} pore_i2c_en_param_reg; + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint32_t r_n_w : 1; + uint32_t bc : 1; + uint32_t chiplet_select : 6; + uint32_t res0 : 4; + uint32_t port : 4; + uint32_t region_select : 8; + uint32_t res1 : 4; + uint32_t type_sel_bin : 4; +#else + uint32_t type_sel_bin : 4; + uint32_t res1 : 4; + uint32_t region_select : 8; + uint32_t port : 4; + uint32_t res0 : 4; + uint32_t chiplet_select : 6; + uint32_t bc : 1; + uint32_t r_w : 1; +#endif + }; + uint32_t val; +} shift_eng_cmd_reg; + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t region_select : 8; + uint64_t res0 : 8; + uint64_t type_sel_unary : 16; + uint64_t res1 : 32; +#else + uint64_t res1 : 32; + uint64_t type_sel_unary : 16; + uint64_t res0 : 8; + uint64_t region_select : 8; +#endif + }; + uint64_t val; +} scan_type_select_reg; + +/* Scan controller register */ +#define SCAN_REGION_OFFSET 0x0007 +#define SCAN_DATA_OFFSET(cDR, uDR, bits) (0x8000 | \ + ((cDR) & 0x1) << 14 | \ + ((uDR) & 0x1) << 13 | \ + ((bits) & 0x3f)) + +#ifndef FASTI2C_BASE_OFFSET +# define FASTI2C_BASE_OFFSET 0x00008000 +#endif +#define FASTI2C_CONTROL_OFFSET (FASTI2C_BASE_OFFSET + 0x00000000) +#define FASTI2C_RESET_OFFSET (FASTI2C_BASE_OFFSET + 0x00000001) +#define FASTI2C_STATUS_OFFSET (FASTI2C_BASE_OFFSET + 0x00000002) +#define FASTI2C_DATA_OFFSET (FASTI2C_BASE_OFFSET + 0x00000003) + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t with_start : 1; + uint64_t with_address : 1; + uint64_t read_continue : 1; + uint64_t with_stop : 1; + uint64_t data_length : 4; + uint64_t device_address : 7; + uint64_t read_not_write : 1; + + uint64_t speed : 2; + uint64_t port_number : 5; + uint64_t address_range : 3; + uint64_t _reserved0 : 6; + + uint64_t data0 : 8; + uint64_t data1 : 8; + uint64_t data2 : 8; + uint64_t data3 : 8; +#else + uint64_t data3 : 8; + uint64_t data2 : 8; + uint64_t data1 : 8; + uint64_t data0 : 8; + uint64_t _reserved0 : 6; + uint64_t address_range : 3; + uint64_t port_number : 5; + uint64_t speed : 2; + uint64_t read_not_write : 1; + uint64_t device_address : 7; + uint64_t data_length : 4; + uint64_t with_stop : 1; + uint64_t read_continue : 1; + uint64_t with_address : 1; + uint64_t with_start : 1; +#endif + }; + uint64_t val; +} fasti2c_control_reg; + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t pib_address_invalid : 1; /* 0 */ + uint64_t pib_write_invalid : 1; /* 1 */ + uint64_t pib_read_invalid : 1; /* 2 */ + uint64_t pib_address_parity_error : 1; /* 3 */ + uint64_t pib_parity_error : 1; /* 4 */ + uint64_t lb_parity_error : 1; /* 5 */ + uint64_t read_data : 32; /* 6..38 */ + uint64_t _reserved0 : 6; /* 39..45 */ + uint64_t i2c_macro_busy : 1; /* 46 */ + uint64_t i2c_invalid_command : 1; + uint64_t i2c_parity_error : 1; + uint64_t i2c_back_end_overrun_error : 1; + uint64_t i2c_back_end_access_error : 1; + uint64_t i2c_arbitration_lost : 1; + uint64_t i2c_nack_received : 1; + uint64_t i2c_data_request : 1; + uint64_t i2c_command_complete : 1; + uint64_t i2c_stop_error : 1; + uint64_t i2c_port_busy : 1; + uint64_t i2c_interface_busy : 1; + uint64_t i2c_fifo_entry_count : 8; +#else + uint64_t i2c_fifo_entry_count : 8; + uint64_t i2c_interface_busy : 1; + uint64_t i2c_port_busy : 1; + uint64_t i2c_stop_error : 1; + uint64_t i2c_command_complete : 1; + uint64_t i2c_data_request : 1; + uint64_t i2c_nack_received : 1; + uint64_t i2c_arbitration_lost : 1; + uint64_t i2c_back_end_access_error : 1; + uint64_t i2c_back_end_overrun_error : 1; + uint64_t i2c_parity_error : 1; + uint64_t i2c_invalid_command : 1; + uint64_t i2c_macro_busy : 1; + uint64_t _reserved0 : 6; + uint64_t read_data : 32; + uint64_t lb_parity_error : 1; + uint64_t pib_parity_error : 1; + uint64_t pib_address_parity_error : 1; + uint64_t pib_read_invalid : 1; + uint64_t pib_write_invalid : 1; + uint64_t pib_address_invalid : 1; +#endif + }; + uint64_t val; +} fasti2c_status_reg; + +/* Different address definitions */ +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t reserved : 16; + uint64_t memorySpace : 16; + uint64_t offset : 32; +#else + uint64_t offset : 32; + uint64_t memorySpace : 16; + uint64_t reserved : 16; +#endif + }; + uint64_t val; +} PoreAddress; + +typedef union { + struct { +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint64_t reserved : 33; + uint64_t mc : 1; + uint64_t chiplet_id : 6; + uint64_t pibms_id : 4; + uint64_t prv_port : 4; + uint64_t local_addr : 16; +#else + uint64_t local_addr : 16; + uint64_t prv_port : 4; + uint64_t pibms_id : 4; + uint64_t chiplet_id : 6; + uint64_t mc : 1; + uint64_t reserved : 33; +#endif + }; + uint64_t val; +} PibAddress; + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif + +#endif /* __PORE_REGS__ */ diff --git a/src/usr/pore/poreve/pore_model/include/pore_model.h b/src/usr/pore/poreve/pore_model/include/pore_model.h new file mode 100644 index 000000000..b7f3bb5a4 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/include/pore_model.h @@ -0,0 +1,741 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/include/pore_model.h $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __PORE_MODEL__ +#define __PORE_MODEL__ + +/** + * @file pore_model.h + * @Author Frank Haverkamp + * @date October, 2011 + * + * @brief C interface for the Virtual Power-On-Reset Engine + * vPORe. This code should be as portable as possible and have just a + * few references to the outside envirnonment. To use this code in the + * existing C++ environment one needs to use it together with the vsbe + * C++ wrapper. + * + * The model assumes 4 or 8 byte data in host-byte order. That makes + * it necessarry for the outside code to do the endian swapping before + * the data is hand over to the model. Same is true for write requests + * by the model. Here the data is passed in host-endian order to the + * outside of the model. + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** Version of the vPORe model */ +#define PORE_MODEL_VERSION 0x0001000C + +/** + * Different PORe incarations + * PORE_GPE has two IBUF instances: IBUF0_ID = 0b0000, IBUF1_ID = 0b0001 + * PORE_SLW has one IBUF instance: IBUF0_ID = 0b1000 + * PORE_SBE has one IBUF instance: IBUF0_ID = 0b0100 + */ +#define PORE_IBUF_ID_GPE0 0x00 +#define PORE_IBUF_ID_GPE1 0x01 +#define PORE_IBUF_ID_SLW 0x08 +#define PORE_IBUF_ID_SBE 0x04 + +/** Status Codes */ +#define PORE_SUCCESS 0 +#define PORE_IN_RESET 1 +#define PORE_STOPPED 2 +#define PORE_BREAKPOINT_HIT 3 +#define PORE_ERROR_IGNORED 4 + +/** Error Codes */ +#define PORE_FAILURE -100 +#define PORE_ERR_NOACK -102 +#define PORE_ERR_READ -103 +#define PORE_ERR_WRITE -104 +#define PORE_ERR_FETCH -105 +#define PORE_ERR_DECODE -106 +#define PORE_ERR_EXECUTE -107 +#define PORE_ERR_NOSPACE -108 +#define PORE_ERR_FI2CM -109 +#define PORE_ERR_INVALID_PARAM -110 +#define PORE_ERR_NOT_IMPLEMENTED -111 +#define PORE_ERR_I2C_POLLING -112 +#define PORE_ERR_IN_RESET -113 +#define PORE_ERR_ILLEGAL_FORCED_BRANCH -114 +#define PORE_ERR_NOT_STOPPED -115 +#define PORE_ERR_NOT_STOPPED_WAIT -116 +#define PORE_ERR_BEHAVIOR_NOT_MODELED -117 +#define PORE_ERR_REGISTER_LOCKED -118 +#define PORE_ERR_BUG_INVALID_VECTOR -119 +#define PORE_ERR_INVALID_STACK_POINTER -120 +#define PORE_ERR_STACK_OVERFLOW -121 +#define PORE_ERR_STACK_UNDERFLOW -122 +#define PORE_ERR_INVALID_OPCODE -123 +#define PORE_ERR_UNIMPLEMENTED_INSTR -124 +#define PORE_ERR_INVALID_OPERAND -125 +#define PORE_ERR_HOOK_FAILED -126 +#define PORE_ERR_UNCONNECTED_BUS -127 +#define PORE_ERR_WRITE_ONLY_REGISTER -128 +#define PORE_ERR_READ_ONLY_REGISTER -129 +#define PORE_ERR_FASTI2C_SEQUENCE_ERROR -130 +#define PORE_ERR_FASTI2C_CONTROL_ERROR -131 +#define PORE_ERR_ILLEGAL_REG_OFFSET -132 +#define PORE_ERR_I2CMEMORY_ILLEGAL_ADDR -133 +#define PORE_ERR_NOT_MAPPED_ON_FASTI2C -134 +#define PORE_ERR_BUS_COLLISION -135 + +/* ... more to come */ + +/****************************************************************************** + * PORe Bus: master and slave + *****************************************************************************/ + +/** + * @enum pore_PcbReturnCode + * + * This enumeration follows the 3-bit return code as specified in the + * Pervasive Workbook. + */ +enum pore_PcbReturnCode { + PORE_PCB_SUCCESS = 0, + PORE_PCB_RESOURCE_OCCUPIED = 1, + PORE_PCB_CHIPLET_OFFLINE = 2, + PORE_PCB_PARTIAL_GOOD = 3, + PORE_PCB_ADDRESS_ERROR = 4, + PORE_PCB_CLOCK_ERROR = 5, + PORE_PCB_PACKET_ERROR = 6, + PORE_PCB_TIMEOUT = 7 +}; + +/** + * @enum pore_OciReturnCode + * + * These return codes are abstractions; The OCI_BUS_ERROR is a + * catch-all for now. + */ +enum pore_OciReturnCode { + PORE_OCI_SUCCESS = 0, + PORE_OCI_BUS_ERROR = 1 +}; + +#define PORE_MAX_BUS 64 /** maximum number of possible busses/slaves */ + +typedef struct pore_bus *pore_bus_t; + +typedef int (* poreb_read_f) (pore_bus_t p, uint64_t addr, + uint8_t *buf, unsigned int size, + int *err_code); + +typedef int (* poreb_write_f) (pore_bus_t p, uint64_t addr, + const uint8_t *buf, unsigned int size, + int *err_code); + +typedef int (* poreb_fetch_f) (pore_bus_t p, uint64_t pc, + uint64_t *i_buf01, uint64_t *i_buf2, + unsigned int *size, + int *err_code); + +typedef int (* poreb_reset_f) (pore_bus_t p); + + +/** + * @brief The pore_bus structure is public because the user should be + * able to attach his/her own behavior if needed. The read, write, or + * fetch functions are called by the pore-model or by an + * address-translation object. + */ +struct pore_bus { + const char *name; /**< name of the bus, for debug prints */ + struct pore_model *pore;/**< reference to pore_model */ + + poreb_read_f read; /**< read data from bus */ + poreb_write_f write; /**< write data to bus */ + poreb_fetch_f fetch; /**< fetch instructions via the bus */ + poreb_reset_f reset; /**< reset the bus, clear buffers */ + + struct pore_bus *slaves[PORE_MAX_BUS]; /** slave devices/busses */ + uint8_t priv_data[0]; /**< keep internal data here */ +}; + +static inline void *poreb_get_priv(struct pore_bus *b) +{ + return (void *)b->priv_data; +} + +/** + * @brief Create PORe bus-object. The user must create own bus-objects + * to implement PIB and/or OCI accesses. + * + * @param [in] pore reference to PORe model + * @param [in] name name of this bus-object + * @param [in] priv_data_size size of private information + * @return NULL on failure, or reference to bus-object + */ +struct pore_bus *poreb_create(const char *name, + size_t priv_data_size, + poreb_read_f r, + poreb_write_f w, + poreb_fetch_f f, + poreb_reset_f R); + +/** + * @brief Destroy poreb-bus. + * + * @param [in] b reference to PORe bus + */ +void poreb_destroy(pore_bus_t b); + +/** + * @brief Attach a slave to a bus-object. + * + * @param [in] b reference to bus-object + * @param [in] s reference to bus-object which should be attached to b + * @return PORE_SUCCESS, or negative error code + */ +int poreb_attach_slave(struct pore_bus *b, struct pore_bus *s); + +/** + * @brief Read data from bus. + * + * @param [in] p reference to PORe model + * @param [in] addr address for data access + * @param [in] buf address where data should be written to + * @param [in] size size of buf in bytes + * @param [out] err_code Bus error code @see pore_PcbReturnCode, + * @see pore_OciReturnCode + */ +int poreb_read (pore_bus_t p, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code); + +/** + * @brief Write data to bus. + * + * @param [in] p reference to PORe model + * @param [in] addr address for data access + * @param [in] buf address of the data + * @param [in] size size of buf in bytes + * @param [out] err_code Bus error code @see pore_PcbReturnCode, + * @see pore_OciReturnCode + */ +int poreb_write(pore_bus_t p, uint64_t addr, const uint8_t *buf, + unsigned int size, int *err_code); + +/** + * @brief Fetch instruction from bus. + * + * @param [in] p reference to PORe model + * @param [in] pc address for data access + * @param [out] i_buf01 1st part of the instruction + * @param [out] i_buf2 2nd part of the instruction (only for large instr.) + * @param [out] size 4 for normal instr. and 12 for large instr. + * @param [out] err_code Bus error code @see pore_PcbReturnCode, + * @see pore_OciReturnCode + */ +int poreb_fetch(pore_bus_t p, uint64_t pc, uint64_t *i_buf01, + uint64_t *i_buf2, unsigned int *size, int *err_code); + +/** + * @brief Reset the PORe model. Including all busses attached to it. + * + * @param [in] p reference to PORe model + */ +int poreb_reset(pore_bus_t p); + +/** + * @brief Create fast i2c bus-object. + * + * @bugs An I2C controller can support more than one ports and it can + * also have more than one device listening on one of those. Just like + * real world I2C busses connected to an I2C master with an output + * multiplexor. For our purpose one i2c_port with one device address + * is enough. + * + * @param [in] name Name of fi2c device + * @param [in] mem_buf Memory area used to emulate content + * @param [in] mem_size Size of memory area + * @param [in] mem_start Start offset of memory area, e.g. LPC bus has + * flash at end + * @param [in] prv_port Pervasive port number (part of the address) + * @param [in] address_bytes Number of required address bytes + * @param [in] i2c_port Pervasive I2C masters support muxing multiple + * I2C ports + * @param [in] deviceAddress Address of the to be accessed I2C chip + * @return Pointer to pore_bus object, or NULL in case of + * failure + */ +struct pore_bus *poreb_create_fi2c(const char *name, + uint8_t *mem_buf, + unsigned int mem_size, + unsigned int mem_start, + unsigned int prv_port, + unsigned int address_bytes, + unsigned int i2c_port, + unsigned int deviceAddress); + +/****************************************************************************** + * PORe Model + *****************************************************************************/ + +/** + * @brief Reference to PORe model. This reference is used for all functions + * dealing with the PORe model. + */ +typedef struct pore_model *pore_model_t; /** Representation of the virtual + PORE model */ + +/** + * @brief Functions to create different instances of a PORe model. + * @see pore_sbe_create, pore_slw_create, pore_gpe0_create, and + * pore_gpe1_create. + */ +pore_model_t pore_model_create(const char *name); + +/** + * @brief Destroy poreb-bus. + * @param [in] p reference to PORe model + */ +void pore_model_destroy(pore_model_t p); + +void pore_relocateAddress(pore_model_t p, uint64_t *address); + +/** + * @brief Create pore-bus object which can be used to implement + * selfscomming behavior when attached as slave to the PIB + * implementation. + * + * @param [in] name Name of fi2c device + * @param [in] prv_port Pervasive port number (part of the address) + * @return Pointer to pore_bus object, or NULL in case of + * failure + */ +struct pore_bus *poreb_create_selfscom(const char *name, + unsigned int chiplet_id, + unsigned int prv_port); + +/** + * @brief Attach MEM/OCI bus to PORe model. This includes setting up + * the pore member variable of the pore_bus_t object recursively. + * + * @param [in] p reference to PORe model + * @param [in] b referenct to OCI/MEM bus-object + */ +int pore_attach_mem(pore_model_t p, struct pore_bus *b); + +/** + * @brief Unit2: PORE_SBE (1 thread self-boot engine to support + * initial booting) + * + * @param [in] pib reference to pib bus-object + * @return NULL on error, or reference PORe model + */ +pore_model_t pore_sbe_create (pore_bus_t pib); + +/** + * @brief Unit1: PORE_SLW (1 thread engine for waking-up from sleep + * and winkle modes) + * + * @param [in] pib reference to pib bus-object + * @param [in] oci reference to oci bus-object + * @return NULL on error, or reference PORe model + */ +pore_model_t pore_slw_create (pore_bus_t pib, pore_bus_t oci); + +/** + * @brief Unit0: PORE_GPE (2 thread engine to replace OCA) + * + * @param [in] pib reference to pib bus-object + * @param [in] oci reference to oci bus-object + * @return NULL on error, or reference PORe model + */ +pore_model_t pore_gpe0_create (pore_bus_t pib, pore_bus_t oci); + +/** + * @brief Unit0: PORE_GPE (2 thread engine to replace OCA) + * + * @param [in] pib reference to pib bus-object + * @param [in] oci reference to oci bus-object + * @return NULL on error, or reference PORe model + */ +pore_model_t pore_gpe1_create (pore_bus_t pib, pore_bus_t oci); + +void pore_reset(pore_model_t p); +int pore_step(pore_model_t p); +int pore_run(pore_model_t p, int steps); + +typedef enum { + PORE_R_STATUS = 0x00, + PORE_R_CONTROL = 0x08, + PORE_R_RESET = 0x10, + PORE_R_ERROR_MASK = 0x18, + PORE_R_PRV_BASE_ADDR0 = 0x20, + PORE_R_PRV_BASE_ADDR1 = 0x28, + PORE_R_OCI_MEMORY_BASE_ADDR0 = 0x30, + PORE_R_OCI_MEMORY_BASE_ADDR1 = 0x38, + PORE_R_TABLE_BASE_ADDR = 0x40, + PORE_R_EXE_TRIGGER = 0x48, + PORE_R_SCRATCH0 = 0x50, + PORE_R_SCRATCH1 = 0x58, + PORE_R_SCRATCH2 = 0x60, + PORE_R_IBUF_01 = 0x68, + PORE_R_IBUF_2 = 0x70, + PORE_R_DBG0 = 0x78, + PORE_R_DBG1 = 0x80, + PORE_R_PC_STACK0 = 0x88, + PORE_R_PC_STACK1 = 0x90, + PORE_R_PC_STACK2 = 0x98, + PORE_R_ID_FLAGS = 0xa0, + PORE_R_DATA0 = 0xa8, + PORE_R_MEM_RELOC = 0xb0, + PORE_R_I2C_E0_PARAM = 0xb8, + PORE_R_I2C_E1_PARAM = 0xc0, + PORE_R_I2C_E2_PARAM = 0xc8, + /* ------------------------------ */ + /* 4 x uint64_t internal state */ + PORE_R_SIZEOF_PORE_STATE = 0xf0, /**< size of PORe state */ + PORE_R_ILLEGAL = 0xff, /**< illegal offs, err checking */ +} pore_reg_t; /**< register encodings */ + +/** Bits 0:31 of a 64-bit register */ +#define PORE_BITS_0_31 0xffffffff00000000ull + +/** Bits 32:63 of a 64-bit register */ +#define PORE_BITS_32_63 0x00000000ffffffffull + +/** Bits 0:63 of a 64-bit register */ +#define PORE_BITS_0_63 0xffffffffffffffffull + +/** + * @brief Write to PORe register _with_ side effects. + * + * @param [in] p reference to pore_model + * @param [in] reg register id + * @param [in] d data + * @param [in] msk mask for write. 4 and 8 bytes are supported + * Use PORE_BITS_0_31, PORE_BITS_32_63 PORE_BITS_0_63. + * @return 0 on success, else negative error code + */ +int pore_writeReg(pore_model_t p, pore_reg_t reg, uint64_t d, uint64_t msk); + +/** + * @brief Read PORe register _with_ side effects. + * + * @param [in] p reference to pore_model + * @param [in] reg register id + * @param [in] msk mask for read. 4 and 8 bytes are supported + * Use PORE_BITS_0_31, PORE_BITS_32_63 PORE_BITS_0_63. + * @return value of register to read + */ +uint64_t pore_readReg(pore_model_t p, pore_reg_t reg, uint64_t msk); + +/** + * @brief Writes are done _without_ side effects. + * + * @param [in] p reference to pore_model + * @param [in] reg register id + * @param [in] d data + * @param [in] msk mask for read/write. 4 and 8 bytes are supported + * Use PORE_BITS_0_31, PORE_BITS_32_63 PORE_BITS_0_63. + * @return 0 on success, else negative error code + */ +int pore_writeRegRaw(pore_model_t p, pore_reg_t reg, uint64_t d, uint64_t msk); + +/** + * @brief Reads are done _without_ side effects. + * + * @param [in] p reference to pore_model + * @param [in] reg register id + * @param [in] msk mask for read/write. 4 and 8 bytes are supported + * Use PORE_BITS_0_31, PORE_BITS_32_63 PORE_BITS_0_63. + * @return value of register to read + */ +uint64_t pore_readRegRaw(pore_model_t p, pore_reg_t reg, uint64_t msk); + +/** + * @brief The pore_state_t structure defines the state of the + * model. It is used to backup and restore the model state via + * pore_extractState and pore_installState. The structure contains the + * architected registers first and the model/implementation specific + * data hidden at the end. When installing the state the resources + * are restored without any hardware side effects compared to the + * regular writeReg, readReg functionality. + * + * @note The size of the structure must not exceed + * PORE_R_SIZEOF_PORE_STATE. + */ +typedef struct pore_state { + /** start of architected register set */ + uint64_t status; /* 0x00000000 */ + uint64_t pore_control; /* 0x00000008 */ + uint64_t pore_reset; /* 0x00000010 */ + uint64_t pore_error_mask; /* 0x00000018 */ + uint64_t prv_base0; /* 0x00000020 */ + uint64_t prv_base1; /* 0x00000028 */ + uint64_t oci_base0; /* 0x00000030 */ + uint64_t oci_base1; /* 0x00000038 */ + uint64_t pore_table_base_addr; /* 0x00000040 */ + uint64_t exe_trigger; /* 0x00000048 */ + uint64_t scratch0; /* 0x00000050 */ + uint64_t scratch1; /* 0x00000058 */ + uint64_t scratch2; /* 0x00000060 */ + uint64_t ibuf_01; /* 0x00000068 */ + uint64_t ibuf_2; /* 0x00000070 */ + uint64_t dbg0; /* 0x00000078 */ + uint64_t dbg1; /* 0x00000080 */ + uint64_t pc_stack0; /* 0x00000088 */ + uint64_t pc_stack1; /* 0x00000090 */ + uint64_t pc_stack2; /* 0x00000098 */ + uint64_t id_flags; /* 0x000000a0 */ + uint64_t data0; /* 0x000000a8 */ + uint64_t memory_reloc; /* 0x000000b0 */ + uint64_t i2c_e_param[3]; /* 0x000000b8 * + * 0x000000c0 * + * 0x000000c8 */ + /** end of architected register set */ + + uint64_t priv[4]; /* private data */ +} pore_state_t; + +/** + * @brief pore_extract is used to extract the current state of the + * model. Using those functions will not cause register read/write + * side effects. + * + * @param [in] p reference to pore_model + * @param [in] s reference to the pore_state structure which needs to be + * provided by the caller. + * @return 0 on success, else negative error code + */ +int pore_extractState (pore_model_t p, pore_state_t *s); + +/** + * @brief pore_install is used to isntall the current state of the + * model. Using those functions will not cause register read/write + * side effects. + * + * @param [in] p reference to pore_model + * @param [in] s reference to the pore_state structure which needs to be + * provided by the caller. + * @return 0 on success, else negative error code + */ +int pore_installState (pore_model_t p, const pore_state_t *s); + +/** + * @brief Print out model status and registers. This function is + * mainly intended for debugging the model. + * + * @param [in] p reference to pore_model + */ +void pore_dump (pore_model_t p); + +/** + * @brief pore_get|setpriv are used to store private data for + * Hook and Callbacks. Use the set function to store and the + * get function to retrieve the data. + * + * @param [in] p reference to pore_model + * @param [in] priv private data + */ +void pore_setpriv (pore_model_t p, void *priv); +void *pore_getpriv (pore_model_t p); + +/** + * @brief The instruction hook call back is called whenever a "hook" + * instruction got decoded. + */ +typedef int (* instrHook_f) (pore_model_t p, uint64_t addr, uint32_t im24, + uint64_t im64); +/** + * @brief The read hook call back is called before a read to the PIB + * or OCI bus-object is done. + */ +typedef int (* readHook_f) (pore_model_t p, uint64_t addr); + +/** + * @brief The write hook call back is called before a write to the PIB + * or OCI bus-object is done. + */ +typedef int (* writeHook_f) (pore_model_t p, uint64_t addr); + +/** + * @brief The fetch hook call back is called before a fetch from the + * PIB or OCI bus-object is done. + */ +typedef int (* fetchHook_f) (pore_model_t p, uint64_t addr); + +/** + * @brief The decode call back is called before a fetched instruction + * gets decoded. + */ +typedef int (* decodeHook_f) (pore_model_t p, uint8_t *instr, + unsigned int size); +/** + * @brief waitCallback_f functions will be called when certain events or + * situations occur within the model. E.g. if a delay is required the + * outside code has to implement the correct wait time since the model + * has no knowledge about the time. + */ +typedef void (* waitCallback_f) (pore_model_t p, uint32_t delay); + +/** + * @brief errorCallback_f is called on an error. There are "normal" as + * well as "fatal" errors which can occur. + */ +typedef void (* errorCallback_f) (pore_model_t p); + +/** pore_bus implementation needs to call some the hook callbacks */ +int pore_instrHook (pore_model_t p, uint64_t addr, + uint32_t im24, uint64_t im64); +int pore_readHook (pore_model_t p, uint64_t addr); +int pore_writeHook (pore_model_t p, uint64_t addr); +int pore_fetchHook (pore_model_t p, uint64_t addr); + +/** + * @brief Hooks will be called with p as parameter. Use + * pore_set/getpriv to keep internal data. Hooks are expected to + * return 0 on success. If they do not return 0 the model will stop + * executing. + */ +int pore_registerHooks(pore_model_t p, + instrHook_f instrHook, + readHook_f readHook, + writeHook_f writeHook, + fetchHook_f fetchHook, + decodeHook_f decodeHook); + +void pore_set_enableHookInstr(pore_model_t p, int enabled); +int pore_get_enableHookInstr(pore_model_t p); +void pore_set_enableAddressHooks(pore_model_t p, int enabled); +int pore_get_enableAddressHooks(pore_model_t p); + +/** + * @brief Register callback functions. + * + * @param [in] p reference to pore model + * @param [in] waitCallback called when a wait instruction is executed. + * @param [in] errorCallback called when an error occurs. + * @param [in] fatalErrorCallback called when a fatal error occurs. + */ +int pore_registerCallbacks(pore_model_t p, + waitCallback_f waitCallback, + errorCallback_f errorCallback, + errorCallback_f fatalErrorCallback); + +/** + * @brief Perform model reset. + * @param [in] p reference to pore model + */ +int pore_flush_reset(pore_model_t p); + +/** + * @brief Changes the internal branch location to something else. This + * could be used within hooks if there is need to branch to different + * code. FIXME Is this really needed? Is this not dangerous and error + * prone? + * + * @param [in] p reference to pore model + * @param [in] addr new program counter + */ +int pore_forceBranch(pore_model_t p, uint64_t addr); + +#define PORE_TRACE_ERR 0x0001 /**< trace error situations */ +#define PORE_TRACE_IBUF 0x0002 /**< trace fetch/decode/execute */ +#define PORE_TRACE_BUS 0x0004 /**< trace bus events */ +#define PORE_TRACE_I2C 0x0008 /**< trace i2c transactions */ +#define PORE_TRACE_PIB 0x0010 /**< trace PIB traffic */ +#define PORE_TRACE_MEM 0x0020 /**< trace OCI/MEM traffic */ +#define PORE_TRACE_ALL ( PORE_TRACE_ERR | PORE_TRACE_IBUF | \ + PORE_TRACE_BUS | PORE_TRACE_I2C | \ + PORE_TRACE_PIB | PORE_TRACE_MEM ) + +/** + * @brief The PORe model supports tracing the execution flow for + * debugging. Different code areas have individual trace enable + * bits. To print out the trace the instantiator has to provide a + * vprintf function which will get called when tracing is enabled. + * + * @param [in] p reference to pore model + * @param [in] trace bitfield identifying the areas which should be trace. + */ +void pore_set_trace(pore_model_t p, uint64_t trace); +uint64_t pore_get_trace(pore_model_t p); + +/** + * @brief The following function are for easy model operation. They + * make use of the side effects when writing to the PORe control + * register to start/stop the engine or to set/clear breakpoints of + * the program counter PC. + */ + +/** + * @brief Stop a potentially running pore-model via write to + * PORE_R_CONTROL register. + * + * @param [in] p reference to pore model + */ +int pore_stop(pore_model_t p); + +/** + * @brief Start pore-model via write to PORE_R_CONTROL register. + * + * @param [in] p reference to pore model + */ +int pore_start(pore_model_t p); + +/** + * @brief Set program counter to given address. This involves stopping + * the engine and setting the program counter via PORE_R_CONTROL + * register. After calling this funnction the engine will stay + * stopped. + * + * @param [in] p reference to pore model + * @param [in] pc new program counter content + */ +int pore_setPc(pore_model_t p, uint64_t pc); + +/** + * @brief Set a pore-model breakpoint. This is done by using the + * PORE_R_CONTROL register. When the pore-model hits the breakpoint + * address it will automatically stop. + * + * @param [in] p reference to pore model + * @param [in] bp breakpoint address + */ +int pore_setBreakpoint(pore_model_t p, uint64_t bp); + +/** + * @brief Enable/disable the trap instruction by setting the + * appropriate bit in the PORE_R_CONTROL register. + * + * @param [in] p reference to pore model + * @param [in] enable 0: disable, 1: enable + */ +int pore_enableTrap(pore_model_t p, int enable); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif + +#endif /* __PORE_MODEL_H__ */ diff --git a/src/usr/pore/poreve/pore_model/include/pore_wrap.h b/src/usr/pore/poreve/pore_model/include/pore_wrap.h new file mode 100644 index 000000000..370ea378e --- /dev/null +++ b/src/usr/pore/poreve/pore_model/include/pore_wrap.h @@ -0,0 +1,102 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/pore_model/include/pore_wrap.h $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __PORE_TRACE_H__ +#define __PORE_TRACE_H__ + +/** + * @file pore_interface.h (for HostBoot environment) + * @Author Thi Tran + * @date October, 2011 + * + * @brief Trace functions for the Virtual Power-On-Reset Engine vPORe. + * Since different users of this code use different ways of tracing, + * It should be possible to replace the pore_model tracing with a + * private version. In this file we use libc printfs to trace the flow + * of the code if needed. + * + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdarg.h> +#include <trace/interface.H> + +#ifdef __cplusplus +extern "C" { +#endif + +extern trace_desc_t* g_poreDbgTd; +extern trace_desc_t* g_poreErrTd; + +#ifndef htobe32 +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define htobe32(x) __bswap_32 (x) +# define htole32(x) (x) +# define be32toh(x) __bswap_32 (x) +# define le32toh(x) (x) + +# define htobe64(x) __bswap_64 (x) +# define htole64(x) (x) +# define be64toh(x) __bswap_64 (x) +# define le64toh(x) (x) +# else +# define htobe32(x) (x) +# define htole32(x) __bswap_32 (x) +# define be32toh(x) (x) +# define le32toh(x) __bswap_32 (x) + +# define htobe64(x) (x) +# define htole64(x) __bswap_64 (x) +# define be64toh(x) (x) +# define le64toh(x) __bswap_64 (x) +# endif +#endif + +/** Using the following macros should help to adopt the code to + different environments. */ +#define pore_htobe64(x) htobe64(x) +#define pore_be64toh(x) be64toh(x) +#define pore_htobe32(x) htobe32(x) +#define pore_be32toh(x) be32toh(x) + +// Debug trace +// '((void)p);' is to avoid unused variable error when compiling +#define printf(fmt, args...) TRACFCOMP(g_poreDbgTd, fmt, ##args) +#define aprintf(fmt, args...) TRACDCOMP(g_poreDbgTd, fmt, ##args) +#define eprintf(p, fmt, args...) ((void)p); TRACDCOMP(g_poreDbgTd, fmt, ##args) +#define dprintf(p, fmt, args...) ((void)p); TRACDCOMP(g_poreDbgTd, fmt, ##args) +#define bprintf(p, fmt, args...) ((void)p); TRACDCOMP(g_poreDbgTd, fmt, ##args) +#define iprintf(p, fmt, args...) ((void)p); TRACDCOMP(g_poreDbgTd, fmt, ##args) +#define pib_printf(p, fmt, args...) ((void)p); TRACDCOMP(g_poreDbgTd, fmt, ##args) +#define mem_printf(p, fmt, args...) ((void)p); TRACDCOMP(g_poreDbgTd, fmt, ##args) + +// Diagnostic aid +#define BUG() \ + TRACFCOMP(g_poreErrTd, ">>> Bug trapped at %s:%d", \ + __FILE__, __LINE__ ) + +#ifdef __cplusplus +} +#endif + +#endif /* __PORE_TRACE_H__ */ diff --git a/src/usr/pore/poreve/pore_model/include/vsbe.H b/src/usr/pore/poreve/pore_model/include/vsbe.H new file mode 100644 index 000000000..393053303 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/include/vsbe.H @@ -0,0 +1,193 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/include/vsbe.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_H +#define __VSBE_H + +/** + * @file vsbe.H + * @Author Andre Hertwig with additions by Frank Haverkamp + * @date October, 2011 + * + * @brief The interface between the vsbe::PoreModel and the virtual + * pore engine model. + */ + +#include "transaction.H" +#include "modelerror.H" +#include "poremodel.H" +#include "poreinterface.H" +#include "pore_model.h" + +#define PORE_UNRUNNABLE "The PORE engine is not runnable without some control action" + +namespace vsbe { + /** Hooks */ + int vsbeHookReadCallBack (pore_model_t p, uint64_t i_address); + int vsbeHookWriteCallBack (pore_model_t p, uint64_t i_address); + int vsbeHookFetchCallBack (pore_model_t p, uint64_t i_address); + int vsbeHookDecodeCallBack(pore_model_t p, uint8_t *instr, + unsigned int size); + int vsbeHookInstructionCallBack(pore_model_t p, uint64_t i_address, + uint32_t i_hook, uint64_t i_parameter); + + + /** Signals */ + void stoppedIntrCallBack(pore_model_t p); + void fatalErrorIntrCallBack(pore_model_t p); + void errorIntrCallBack(pore_model_t p); + void waitIntrCallBack(pore_model_t p, uint32_t delay); + + /** Data transfer */ + int vsbePibReadCallBack(pore_bus_t p, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code); + + int vsbePibWriteCallBack(pore_bus_t p, uint64_t addr, + const uint8_t *buf, unsigned int size, + int *err_code); + + int vsbeOciReadCallBack(pore_bus_t p, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code); + + int vsbeOciWriteCallBack(pore_bus_t p, uint64_t addr, + const uint8_t *buf, unsigned int size, + int *err_code); +} + +/////////////////////////////////////////////////////////////////////////////// +// Vsbe +/////////////////////////////////////////////////////////////////////////////// + + +/// Implementation of the vsbe::PoreModel class. +/// +/// For interface documentation see vsbe::PoreModel. + + +class Vsbe : public vsbe::PoreModel { + +public: + + ///////////// vsbe::PoreModel Abstract Interface ////////////////////// + + virtual vsbe::ModelError flushReset(); + virtual vsbe::ModelError step(bool& o_stepped); + + /// @brief Register access with real hardware behavior + /// + /// Access upper 32-bit: + /// registerRead(i_offset, data, 4); + /// Access lower 32-bit: + /// registerRead(i_offset + 4, data, 4); + /// Access 64-bit: + /// registerRead(i_offset, data, 8); + /// + virtual vsbe::ModelError + registerRead(const vsbe::PoreRegisterOffset i_offset, + uint64_t& o_data, const size_t i_size); + + virtual vsbe::ModelError + registerWrite(const vsbe::PoreRegisterOffset i_offset, + const uint64_t i_data, const size_t i_size); + + /// @brief Register access without hardware side effects + /// + /// Access upper 32-bit: + /// registerReadRaw(i_offset, data, 4); + /// Access lower 32-bit: + /// registerReadRaw(i_offset + 4, data, 4); + /// Access 64-bit: + /// registerReadRaw(i_offset, data, 8); + /// + virtual vsbe::ModelError + registerReadRaw(const vsbe::PoreRegisterOffset i_offset, + uint64_t& o_data, const size_t i_size); + + virtual vsbe::ModelError + registerWriteRaw(const vsbe::PoreRegisterOffset i_offset, + const uint64_t i_data, const size_t i_size); + + virtual vsbe::ModelError enableHookInstruction(bool i_enable); + virtual vsbe::ModelError enableAddressHooks(bool i_enable); + + virtual vsbe::ModelError extractState(vsbe::PoreState& o_state); + virtual vsbe::ModelError installState(const vsbe::PoreState& i_state); + virtual vsbe::ModelError forceBranch(const vsbe::PoreAddress& + i_address); + + //////////////// Pmx::Pore Abstract Interface ///////////////////////// + + // BB virtual vsbe::ModelError + // BB ociTransport(vsbe::OciTransaction *transaction); + // BB + // BB virtual vsbe::ModelError + // BB pibTransport(vsbe::PibTransaction *transaction); + + virtual vsbe::ModelError + hookInstruction(const vsbe::PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter); + + virtual vsbe::ModelError hookRead(const vsbe::PoreAddress& i_address); + virtual vsbe::ModelError hookWrite(const vsbe::PoreAddress& i_address); + virtual vsbe::ModelError hookFetch(const vsbe::PoreAddress& i_address); + + virtual void wait(const uint32_t i_count); + virtual void fatalErrorIntr(void); + virtual void errorIntr(void); + + ////////////////////////////// Creators /////////////////////////////// + + Vsbe(vsbe::PoreIbufId i_id, vsbe::PoreInterface* i_interface); + + virtual ~Vsbe(); + + ////////////////////////////// Manipulators /////////////////////////// + + int pibReadCallBack(pore_bus_t p, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code); + + int pibWriteCallBack(pore_bus_t p, uint64_t addr, const uint8_t *buf, + unsigned int size, int *err_code); + + int ociReadCallBack(pore_bus_t p, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code); + + int ociWriteCallBack(pore_bus_t p, uint64_t addr, const uint8_t *buf, + unsigned int size, int *err_code); + + ////////////////////////// Implementation ///////////////////////////// + + + /// A vsbe::PibTransaction for PIB mastering + vsbe::PibTransaction d_pibTransaction; + + /// A vsbe::OciTransaction for OCI mastering + vsbe::OciTransaction d_ociTransaction; + +private: + struct pore_model *iv_engine; + pore_reg_t PoreRegOffs_to_pore(vsbe::PoreRegisterOffset reg); + vsbe::PoreRegisterOffset pore_to_PoreRegOffs(pore_reg_t reg); +}; + +#endif // __VSBE_H diff --git a/src/usr/pore/poreve/pore_model/wrapper/vsbe.C b/src/usr/pore/poreve/pore_model/wrapper/vsbe.C new file mode 100644 index 000000000..ac15807e5 --- /dev/null +++ b/src/usr/pore/poreve/pore_model/wrapper/vsbe.C @@ -0,0 +1,692 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/pore_model/wrapper/vsbe.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +/****************************************************************************** + * + * \file vsbe.C + * \brief The interface between the vsbe::PoreModel and the Pmx::Pore + * + *****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include "vsbe.H" +#include "pore_model.h" +#include "pore_wrap.h" + +using namespace vsbe; + +int vsbe::vsbeHookReadCallBack(pore_model_t p, uint64_t i_address) +{ + void *i_vsbe = pore_getpriv(p); + return ((Vsbe*)i_vsbe)->hookRead( PoreAddress(i_address) ); +} + +int vsbe::vsbeHookWriteCallBack(pore_model_t p, uint64_t i_address) +{ + void *i_vsbe = pore_getpriv(p); + return ((Vsbe*)i_vsbe)->hookWrite( PoreAddress(i_address) ); +} + +int vsbe::vsbeHookFetchCallBack(pore_model_t p, uint64_t i_address) +{ + void *i_vsbe = pore_getpriv(p); + return ((Vsbe*)i_vsbe)->hookFetch( PoreAddress(i_address) ); +} + +void vsbe::fatalErrorIntrCallBack(pore_model_t p) +{ + void *i_vsbe = pore_getpriv(p); + ((Vsbe*)i_vsbe)->fatalErrorIntr(); +} + +void vsbe::errorIntrCallBack(pore_model_t p) +{ + void *i_vsbe = pore_getpriv(p); + ((Vsbe*)i_vsbe)->errorIntr(); +} + +void vsbe::waitIntrCallBack(pore_model_t p, uint32_t delay) +{ + void *i_vsbe = pore_getpriv(p); + /** delay == 0 means engine is halted on a WAIT instruction */ + ((Vsbe*)i_vsbe)->wait(delay); +} + +int vsbe::vsbeHookInstructionCallBack(pore_model_t p, uint64_t i_address, + uint32_t i_hook, uint64_t i_parameter) +{ + void* i_vsbe = pore_getpriv(p); + return ((Vsbe*)i_vsbe)->hookInstruction( PoreAddress(i_address), + i_hook, i_parameter ); +} + +////// OCI and PIB Transactions ////////////////////////////////////////////// + +int vsbe::vsbePibReadCallBack(pore_bus_t b, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code) +{ + Vsbe *vsbe = *(Vsbe **)poreb_get_priv(b); + return vsbe->pibReadCallBack(b, addr, buf, size, err_code); +} + +int +Vsbe::pibReadCallBack(pore_bus_t b, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code) +{ + PibTransaction pibTransaction; + + pibTransaction.iv_address = addr; + pibTransaction.iv_offset = 0; + pibTransaction.iv_data = 0; + pibTransaction.iv_mode = vsbe::ACCESS_MODE_READ; + + pibMaster(pibTransaction); + *err_code = pibTransaction.iv_pcbReturnCode; + + if (pibTransaction.iv_pcbReturnCode) { + size = PORE_ERR_READ; + } + + *((uint64_t *)buf) = (*((uint64_t *)(void *)&pibTransaction.iv_data)); + return size; +} + + +int vsbe::vsbePibWriteCallBack(pore_bus_t b, uint64_t addr, + const uint8_t *buf, + unsigned int size, + int *err_code) +{ + Vsbe *vsbe = *(Vsbe **)poreb_get_priv(b); + return vsbe->pibWriteCallBack(b, addr, buf, size, err_code); +} + + +int +Vsbe::pibWriteCallBack(pore_bus_t b, uint64_t addr, const uint8_t *buf, + unsigned int size, int *err_code) +{ + PibTransaction pibTransaction; + + pibTransaction.iv_address = addr; + pibTransaction.iv_offset = 0; + pibTransaction.iv_mode = vsbe::ACCESS_MODE_WRITE; + *(uint64_t *)(void *)&pibTransaction.iv_data = (*((uint64_t *)buf)); + + pibMaster(pibTransaction); + *err_code = pibTransaction.iv_pcbReturnCode; + + if (pibTransaction.iv_pcbReturnCode) { + size = PORE_ERR_WRITE; + } + return size; +} + +int vsbe::vsbeOciReadCallBack(pore_bus_t b, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code) +{ + Vsbe *vsbe = *(Vsbe **)poreb_get_priv(b); + return vsbe->ociReadCallBack(b, addr, buf, size, err_code); +} + +int +Vsbe::ociReadCallBack(pore_bus_t b, uint64_t addr, uint8_t *buf, + unsigned int size, int *err_code) +{ + OciTransaction ociTransaction; + + ociTransaction.iv_address = addr; + ociTransaction.iv_offset = 0; + ociTransaction.iv_data = 0; + ociTransaction.iv_mode = vsbe::ACCESS_MODE_READ; + + ociMaster(ociTransaction); + *err_code = ociTransaction.iv_ociReturnCode; + + if (ociTransaction.iv_ociReturnCode) { + size = PORE_ERR_READ; + } + + *((uint64_t *)buf) = (*((uint64_t *)(void *)&ociTransaction.iv_data)); + return size; +} + +int vsbe::vsbeOciWriteCallBack(pore_bus_t b, uint64_t addr, + const uint8_t *buf, unsigned int size, + int *err_code) +{ + Vsbe *vsbe = *(Vsbe **)poreb_get_priv(b); + return vsbe->ociWriteCallBack(b, addr, buf, size, err_code); +} + + +int +Vsbe::ociWriteCallBack(pore_bus_t b, uint64_t addr, const uint8_t *buf, + unsigned int size, int *err_code) +{ + OciTransaction ociTransaction; + + ociTransaction.iv_address = addr; + ociTransaction.iv_offset = 0; + ociTransaction.iv_mode = vsbe::ACCESS_MODE_WRITE; + *(uint64_t *)(void *)&ociTransaction.iv_data = (*((uint64_t *)buf)); + + ociMaster(ociTransaction); + *err_code = ociTransaction.iv_ociReturnCode; + + if (ociTransaction.iv_ociReturnCode) { + size = PORE_ERR_WRITE; + } + return size; +} + +///////////// vsbe::PoreModel Abstract Interface ///////////////////////////// + +/// Create a PoreModel +/// +/// This is the static create() method required to create an +/// implementation-specific instance of a vsbe::PoreModel. + +PoreModel* PoreModel::create(PoreIbufId i_id, PoreInterface *i_interface) +{ + return new Vsbe(i_id, i_interface); +} + +ModelError Vsbe::flushReset() +{ + return ModelError( pore_flush_reset(iv_engine) ); +} + +pore_reg_t Vsbe::PoreRegOffs_to_pore(vsbe::PoreRegisterOffset reg) +{ + switch (reg) { + case PORE_STATUS: return PORE_R_STATUS; + case PORE_CONTROL: return PORE_R_CONTROL; + case PORE_RESET: return PORE_R_RESET; + case PORE_ERROR_MASK: return PORE_R_ERROR_MASK; + case PORE_PRV_BASE_ADDR0: return PORE_R_PRV_BASE_ADDR0; + case PORE_PRV_BASE_ADDR1: return PORE_R_PRV_BASE_ADDR1; + case PORE_OCI_MEMORY_BASE_ADDR0: return PORE_R_OCI_MEMORY_BASE_ADDR0; + case PORE_OCI_MEMORY_BASE_ADDR1: return PORE_R_OCI_MEMORY_BASE_ADDR1; + case PORE_TABLE_BASE_ADDR: return PORE_R_TABLE_BASE_ADDR; + case PORE_EXE_TRIGGER: return PORE_R_EXE_TRIGGER; + case PORE_SCRATCH0: return PORE_R_SCRATCH0; + case PORE_SCRATCH1: return PORE_R_SCRATCH1; + case PORE_SCRATCH2: return PORE_R_SCRATCH2; + case PORE_IBUF_01: return PORE_R_IBUF_01; + case PORE_IBUF_2: return PORE_R_IBUF_2; + case PORE_DBG0: return PORE_R_DBG0; + case PORE_DBG1: return PORE_R_DBG1; + case PORE_PC_STACK0: return PORE_R_PC_STACK0; + case PORE_PC_STACK1: return PORE_R_PC_STACK1; + case PORE_PC_STACK2: return PORE_R_PC_STACK2; + case PORE_ID_FLAGS: return PORE_R_ID_FLAGS; + case PORE_DATA0: return PORE_R_DATA0; + case PORE_MEM_RELOC: return PORE_R_MEM_RELOC; + case PORE_I2C_E0_PARAM: return PORE_R_I2C_E0_PARAM; + case PORE_I2C_E1_PARAM: return PORE_R_I2C_E1_PARAM; + case PORE_I2C_E2_PARAM: return PORE_R_I2C_E2_PARAM; + default: return PORE_R_ILLEGAL; + } + return PORE_R_ILLEGAL; +} + + +vsbe::PoreRegisterOffset Vsbe::pore_to_PoreRegOffs(pore_reg_t reg) +{ + switch (reg) { + case PORE_R_STATUS: return PORE_STATUS; + case PORE_R_CONTROL: return PORE_CONTROL; + case PORE_R_RESET: return PORE_RESET; + case PORE_R_ERROR_MASK: return PORE_ERROR_MASK; + case PORE_R_PRV_BASE_ADDR0: return PORE_PRV_BASE_ADDR0; + case PORE_R_PRV_BASE_ADDR1: return PORE_PRV_BASE_ADDR1; + case PORE_R_OCI_MEMORY_BASE_ADDR0: return PORE_OCI_MEMORY_BASE_ADDR0; + case PORE_R_OCI_MEMORY_BASE_ADDR1: return PORE_OCI_MEMORY_BASE_ADDR1; + case PORE_R_TABLE_BASE_ADDR: return PORE_TABLE_BASE_ADDR; + case PORE_R_EXE_TRIGGER: return PORE_EXE_TRIGGER; + case PORE_R_SCRATCH0: return PORE_SCRATCH0; + case PORE_R_SCRATCH1: return PORE_SCRATCH1; + case PORE_R_SCRATCH2: return PORE_SCRATCH2; + case PORE_R_IBUF_01: return PORE_IBUF_01; + case PORE_R_IBUF_2: return PORE_IBUF_2; + case PORE_R_DBG0: return PORE_DBG0; + case PORE_R_DBG1: return PORE_DBG1; + case PORE_R_PC_STACK0: return PORE_PC_STACK0; + case PORE_R_PC_STACK1: return PORE_PC_STACK1; + case PORE_R_PC_STACK2: return PORE_PC_STACK2; + case PORE_R_ID_FLAGS: return PORE_ID_FLAGS; + case PORE_R_DATA0: return PORE_DATA0; + case PORE_R_MEM_RELOC: return PORE_MEM_RELOC; + case PORE_R_I2C_E0_PARAM: return PORE_I2C_E0_PARAM; + case PORE_R_I2C_E1_PARAM: return PORE_I2C_E1_PARAM; + case PORE_R_I2C_E2_PARAM: return PORE_I2C_E2_PARAM; + default: return PORE_ILLEGAL;; + } + return PORE_ILLEGAL; +} + + +//TODO Do we really need o_stepped. Ask Bishop if we can change the interface +ModelError Vsbe::step(bool& o_stepped) +{ + int rc, me; + + o_stepped = false; + rc = pore_step(iv_engine); + if ((rc == PORE_SUCCESS) || // Normal execution + (rc == PORE_ERROR_IGNORED)) // An error was ignored! + o_stepped = true; + + if (rc < 0) { + /* FIXME Translate internal to external error codes nicely */ + switch (rc) { + case PORE_ERR_HOOK_FAILED: + me = ME_HOOK_INSTRUCTION_ERROR; break; + case PORE_ERR_READ: + me = ME_PORE_MODEL_GENERIC_ERROR; break; + case PORE_ERR_WRITE: + me = ME_PORE_MODEL_GENERIC_ERROR; break; + + case PORE_ERR_INVALID_OPCODE: + default: + me = ME_FAILURE; break; + } + return ModelError(me); + } + + return ModelError(ME_SUCCESS); +} + +ModelError Vsbe::registerRead(const vsbe::PoreRegisterOffset i_offset, + uint64_t& o_data, const size_t i_size) +{ + pore_reg_t reg = + PoreRegOffs_to_pore(vsbe::PoreRegisterOffset(i_offset & ~0x7)); + + if (((i_offset & 0x7) == 0x4) && (i_size == 4)) { // lower 32-bit + o_data = pore_readReg(iv_engine, reg, PORE_BITS_32_63); + o_data &= 0xffffffffull; + return ME_SUCCESS; + } + if (((i_offset & 0x7) == 0x0) && (i_size == 4)) { // upper 32-bit + o_data = pore_readReg(iv_engine, reg, PORE_BITS_0_31); + o_data >>= 32; + o_data &= 0xffffffffull; + return ME_SUCCESS; + } + o_data = pore_readReg(iv_engine, reg, PORE_BITS_0_63); + return ME_SUCCESS; +} + +ModelError Vsbe::registerWrite(const vsbe::PoreRegisterOffset i_offset, + const uint64_t i_data, const size_t i_size) +{ + pore_reg_t reg = + PoreRegOffs_to_pore(vsbe::PoreRegisterOffset(i_offset & ~0x7)); + + if (((i_offset & 0x7) == 0x4) && (i_size == 4)) { // lower 32-bit + pore_writeReg(iv_engine, reg, i_data, PORE_BITS_32_63); + return ME_SUCCESS; + } + if (((i_offset & 0x7) == 0x0) && (i_size == 4)) { // upper 32-bit + pore_writeReg(iv_engine, reg, i_data << 32, PORE_BITS_0_31); + return ME_SUCCESS; + } + pore_writeReg(iv_engine, reg, i_data, PORE_BITS_0_63); + return ME_SUCCESS; +} + +ModelError Vsbe::registerReadRaw(const vsbe::PoreRegisterOffset i_offset, + uint64_t& o_data, const size_t i_size) +{ + pore_reg_t reg = + PoreRegOffs_to_pore(vsbe::PoreRegisterOffset(i_offset & ~0x7)); + + if (((i_offset & 0x7) == 0x4) && (i_size == 4)) { // lower 32-bit + o_data = pore_readRegRaw(iv_engine, reg, PORE_BITS_32_63); + o_data &= 0xffffffffull; + return ME_SUCCESS; + } + if (((i_offset & 0x7) == 0x0) && (i_size == 4)) { // upper 32-bit + o_data = pore_readRegRaw(iv_engine, reg, PORE_BITS_0_31); + o_data >>= 32; + o_data &= 0xffffffffull; + return ME_SUCCESS; + } + o_data = pore_readRegRaw(iv_engine, reg, PORE_BITS_0_63); + return ME_SUCCESS; +} + +ModelError Vsbe::registerWriteRaw(const vsbe::PoreRegisterOffset i_offset, + const uint64_t i_data, const size_t i_size) +{ + pore_reg_t reg = + PoreRegOffs_to_pore(vsbe::PoreRegisterOffset(i_offset & ~0x7)); + + if (((i_offset & 0x7) == 0x4) && (i_size == 4)) { // lower 32-bit + pore_writeRegRaw(iv_engine, reg, i_data, PORE_BITS_32_63); + return ME_SUCCESS; + } + if (((i_offset & 0x7) == 0x0) && (i_size == 4)) { // upper 32-bit + pore_writeRegRaw(iv_engine, reg, i_data << 32, PORE_BITS_0_31); + return ME_SUCCESS; + } + pore_writeRegRaw(iv_engine, reg, i_data, PORE_BITS_0_63); + return ME_SUCCESS; +} + +ModelError Vsbe::enableHookInstruction(bool i_enable) +{ + pore_set_enableHookInstr(iv_engine, i_enable); + return ME_SUCCESS; +} + + +ModelError Vsbe::enableAddressHooks(bool i_enable) +{ + pore_set_enableAddressHooks(iv_engine, i_enable); + return ME_SUCCESS; +} + + +// To extract the state we simply read out the current register values. +//TODO Check what to do with some state registers like BRANCH_TAKEN, ... +ModelError Vsbe::extractState(vsbe::PoreState& o_state) +{ + pore_state_t s; + unsigned int reg_id; + uint64_t *reg; + + if (PORE_R_SIZEOF_PORE_STATE > (pore_reg_t)SIZEOF_PORE_STATE) { + BUG(); + } + + pore_extractState(iv_engine, &s); + for (reg_id = PORE_R_STATUS; reg_id < PORE_R_SIZEOF_PORE_STATE; + reg_id += 8) { + reg = (uint64_t *)((uint8_t *)&s + reg_id); + o_state.put((vsbe::PoreRegisterOffset)reg_id, *reg); + } + + return ME_SUCCESS; +} + + +// To install the state we simply restore the saved register values. +//TODO Check what to do with some state registers like BRANCH_TAKEN, ... + +ModelError Vsbe::installState(const vsbe::PoreState& i_state) +{ + uint64_t data; + pore_state_t s; + unsigned int reg_id; + uint64_t *reg; + + if (PORE_R_SIZEOF_PORE_STATE > (pore_reg_t)SIZEOF_PORE_STATE) { + BUG(); + } + + for (reg_id = PORE_R_STATUS; reg_id < PORE_R_SIZEOF_PORE_STATE; + reg_id += 8) { + reg = (uint64_t *)((uint8_t *)&s + reg_id); + i_state.get((vsbe::PoreRegisterOffset)reg_id, data); + *reg = data; + } + pore_installState(iv_engine, &s); + + return ME_SUCCESS; +} + + +ModelError Vsbe::forceBranch(const vsbe::PoreAddress& i_address) +{ + return ModelError ( pore_forceBranch(iv_engine, + (uint64_t)i_address) ); +} + +#if 0 +/// \bug We can't distinguish READ from EXECUTE +// Convert a PMX transaction to a VSBE transaction and master it +ModelError Vsbe::ociTransport(OciTransaction *inTransaction) +{ + ModelError me; + vsbe::ModelError vsbe_me; + OciTransaction transaction; + do { + + transaction.iv_address = inTransaction->iv_address; + + if (inTransaction->iv_mode == ACCESS_MODE_READ) { + transaction.iv_mode = vsbe::ACCESS_MODE_READ; + } else { + transaction.iv_mode = vsbe::ACCESS_MODE_WRITE; + transaction.iv_data = inTransaction->iv_data; + } + + vsbe_me = ociMaster(transaction); + if (vsbe_me != 0) { + break; + } + + if (inTransaction->iv_mode == ACCESS_MODE_READ) { + inTransaction->iv_data = transaction.iv_data; + } + } while (0); + + if (vsbe_me != 0) { + modelError(vsbe_me); + //TODO What is the right return value for me? + // me = OCI_TIMEOUT; + me = ME_FAILURE; + + //TODO What is this ? + // DUAL_ERROR(vsbe_me, me); + } else { + me = ME_SUCCESS; + } + return me; +} + + +/// \bug We can't distinguish READ from EXECUTE +// Convert a PMX transaction to a VSBE transaction and master it +ModelError Vsbe::pibTransport(PibTransaction *inPibTransaction) +{ + ModelError me; + vsbe::ModelError vsbe_me; + PibTransaction pibTransaction; + + do { + pibTransaction.iv_address = inPibTransaction->iv_address; + + if (inPibTransaction->iv_mode == vsbe::ACCESS_MODE_READ) { + pibTransaction.iv_mode = vsbe::ACCESS_MODE_READ; + } else { + pibTransaction.iv_mode = vsbe::ACCESS_MODE_WRITE; + pibTransaction.iv_data = inPibTransaction->iv_data; + } + + vsbe_me = pibMaster(pibTransaction); + if (vsbe_me != 0) { + break; + } + + inPibTransaction->iv_pcbReturnCode = + pibTransaction.iv_pcbReturnCode; + if (inPibTransaction->iv_mode == vsbe::ACCESS_MODE_READ) { + inPibTransaction->iv_data = pibTransaction.iv_data; + } + } while (0); + + if (vsbe_me != 0) { + modelError(vsbe_me); + me = inPibTransaction->busError(ME_FAILURE); + //TODO What is this ? + // DUAL_ERROR(vsbe_me, me); + } else { + me = ME_SUCCESS; + } + return me; + } +#endif + +ModelError Vsbe::hookInstruction(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter) +{ + PoreAddress vsbe_address; + + vsbe_address.iv_memorySpace = i_address.iv_memorySpace; + vsbe_address.iv_offset = i_address.iv_offset; + + vsbe::PoreModel::hookInstruction(vsbe_address, + i_hook, + i_parameter); + return ME_SUCCESS; +} + + +ModelError Vsbe::hookRead(const PoreAddress& i_address) +{ + vsbe::PoreAddress vsbe_address; + + vsbe_address.iv_memorySpace = i_address.iv_memorySpace; + vsbe_address.iv_offset = i_address.iv_offset; + + vsbe::PoreModel::hookRead(vsbe_address); + return ME_SUCCESS; +} + + +ModelError Vsbe::hookWrite(const PoreAddress& i_address) +{ + vsbe::PoreAddress vsbe_address; + + vsbe_address.iv_memorySpace = i_address.iv_memorySpace; + vsbe_address.iv_offset = i_address.iv_offset; + + vsbe::PoreModel::hookWrite(vsbe_address); + return ME_SUCCESS; +} + + +ModelError Vsbe::hookFetch(const PoreAddress& i_address) +{ + vsbe::PoreAddress vsbe_address; + + vsbe_address = i_address; + // vsbe_address.iv_memorySpace = i_address.iv_memorySpace; + // vsbe_address.iv_offset = i_address.iv_offset; + + vsbe::PoreModel::hookFetch(vsbe_address); + return ME_SUCCESS; +} + +void Vsbe::fatalErrorIntr(void) +{ + /* aprintf("PORe Model has hit fatalError\n"); */ + vsbe::PoreModel::fatalErrorIntr(); +} + +void Vsbe::errorIntr(void) +{ + /* aprintf("PORe Model has hit Error\n"); */ + vsbe::PoreModel::errorIntr(); +} + +void Vsbe::wait(const uint32_t i_count) +{ + /* aprintf("PORe Model waits for %d ticks\n", i_count); */ + vsbe::PoreModel::wait(i_count); +} + +////////////////////////////// Creators ////////////////////////////// + +Vsbe::Vsbe(PoreIbufId i_id, PoreInterface* i_interface) : + PoreModel(i_id, i_interface) +{ + struct pore_bus *pibBus, *ociBus; + Vsbe **vsbe_p; + + pibBus = poreb_create("PIB_Bus", + sizeof(Vsbe *), + vsbePibReadCallBack, + vsbePibWriteCallBack, + NULL, // fetch + NULL); // reset + if (pibBus == NULL) { + BUG(); + return; + } + vsbe_p = (Vsbe **)poreb_get_priv(pibBus); + *vsbe_p = this; + + ociBus = poreb_create("OCI_Bus", + sizeof(Vsbe *), + vsbeOciReadCallBack, + vsbeOciWriteCallBack, + NULL, // fetch + NULL); // reset + if (pibBus == NULL) { + BUG(); + return; + } + vsbe_p = (Vsbe **)poreb_get_priv(ociBus); + *vsbe_p = this; + + switch (i_id) { + case PORE_GPE0: + iv_engine = pore_gpe0_create(pibBus, ociBus); + break; + case PORE_GPE1: + iv_engine = pore_gpe1_create(pibBus, ociBus); + break; + case PORE_SLW: + iv_engine = pore_slw_create(pibBus, ociBus); + break; + case PORE_SBE: + iv_engine = pore_sbe_create(pibBus); /* pib */ + break; + default: + break; + } + + pore_setpriv(iv_engine, (void *)this); + pore_registerHooks(iv_engine, + vsbeHookInstructionCallBack, + vsbeHookReadCallBack, + vsbeHookWriteCallBack, + vsbeHookFetchCallBack, + NULL); + + pore_registerCallbacks(iv_engine, + waitIntrCallBack, + errorIntrCallBack, + fatalErrorIntrCallBack); +} + +Vsbe::~Vsbe() +{ + pore_model_destroy(iv_engine); /* done */ +} diff --git a/src/usr/pore/poreve/porevesrc/bus.C b/src/usr/pore/poreve/porevesrc/bus.C new file mode 100644 index 000000000..fdf3e90a5 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/bus.C @@ -0,0 +1,900 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/bus.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: bus.C,v 1.22 2012/01/05 23:15:54 bcbrock Exp $ + +/// \file bus.C +/// \brief PoreVe bus and base device models + +#include "bus.H" +#include <fapi.H> +#include <transaction.H> + + + +using namespace vsbe; + +//----------------------------------------------------------------------------- +Bus::Bus() : + iv_primarySlaves(NULL), + iv_secondarySlaves(NULL) +{ +} + +//----------------------------------------------------------------------------- +Bus::~Bus() +{ +} + +//----------------------------------------------------------------------------- +void +Bus::attachPrimarySlave(Slave* i_slave) +{ + if( iv_primarySlaves == 0 ) + { + i_slave->iv_next = 0; + }else{ + i_slave->iv_next = iv_primarySlaves; + } + iv_primarySlaves = i_slave; +} + +//----------------------------------------------------------------------------- +void +Bus::attachSecondarySlave(Slave* i_slave) +{ + if( iv_secondarySlaves == 0 ) + { + i_slave->iv_next = 0; + }else{ + i_slave->iv_next = iv_secondarySlaves; + } + iv_secondarySlaves = i_slave; +} + + +//----------------------------------------------------------------------------- +fapi::ReturnCode +Bus::operation(Transaction& trans) +{ + fapi::ReturnCode rc; + Slave* slave= 0; + + do + { + for( slave = iv_primarySlaves; slave; slave = slave->iv_next ) + { + if( (trans.iv_address >= slave->iv_base) && (trans.iv_address < (slave->iv_base + slave->iv_size) ) ) + { + break; // found a primary slave + } + } + + if( slave == 0 ) + { // primary slaves did not hold the transaction address. Try using the secondary slaves. + for( slave = iv_secondarySlaves; slave; slave = slave->iv_next ) + { + if( (trans.iv_address >= slave->iv_base) && (trans.iv_address < (slave->iv_base + slave->iv_size) ) ) + { + break; // found a secondary slave + } + } + } + + break; + + }while(0); + + do + { + if( slave == 0 ) // neither primary nor secondary slaves held the address + { + trans.busError(ME_NOT_MAPPED_ON_BUS); + rc= 1; + break; + } + + if( (trans.iv_mode & slave->iv_permissions) == 0 ){ + trans.busError(ME_BUS_SLAVE_PERMISSION_DENIED); + rc= 1; + break; + } + + trans.iv_offset = trans.iv_address - slave->iv_base; + rc = slave->operation( trans ); + break; + }while(1); + + return rc; +} + +//----------------------------------------------------------------------------- +Slave::Slave() +:iv_base(0), iv_size(0), iv_permissions(0), +iv_next(NULL), iv_target(NULL), iv_dataBuffer(NULL) +{ + +} + +//----------------------------------------------------------------------------- +Slave::~Slave() +{ +} + +//----------------------------------------------------------------------------- +PibSlave::PibSlave() +{ +} + +//----------------------------------------------------------------------------- +PibSlave::~PibSlave() +{ +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +PibSlave::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + PibTransaction* pt = (PibTransaction*)&io_transaction; + + if( io_transaction.iv_mode & ACCESS_MODE_READ ) + { + rc = getScom( io_transaction.iv_address, io_transaction.iv_data ); + } + else + { + rc = putScom( io_transaction.iv_address, io_transaction.iv_data ); + } + + if( rc.ok() ) + { + pt->iv_pcbReturnCode = PCB_SUCCESS; + } + else + { + if( rc & fapi_PCB_RESOURCE_BUSY ){ + pt->iv_pcbReturnCode = PCB_RESOURCE_OCCUPIED; + }else if( rc & fapi_PCB_OFFLINE_ERROR ){ + pt->iv_pcbReturnCode = PCB_CHIPLET_OFFLINE; + }else if( rc & fapi_PCB_PARTIAL_ERROR ){ + pt->iv_pcbReturnCode = PCB_PARTIAL_GOOD; + }else if( rc & fapi_PCB_ADDRESS_ERROR ){ + pt->iv_pcbReturnCode = PCB_ADDRESS_ERROR; + }else if( rc & fapi_PCB_CLOCK_ERROR ){ + pt->iv_pcbReturnCode = PCB_CLOCK_ERROR; + }else if( rc & fapi_PCB_PARITY_ERROR ){ + pt->iv_pcbReturnCode = PCB_PACKET_ERROR; + }else if( rc & fapi_PCB_TIMEOUT_ERROR ){ + pt->iv_pcbReturnCode = PCB_TIMEOUT; + }else{ + pt->iv_pcbReturnCode = PCB_TIMEOUT; + } + rc = 0; + } + + io_transaction.iv_modelError = ME_SUCCESS; + return rc; +} + + +//----------------------------------------------------------------------------- +void +Slave::configure( + fapi::Target* i_target, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions + ) +{ + iv_target = i_target; + iv_dataBuffer = i_dataBuffer; + iv_base = i_base; + iv_size = i_size; + iv_permissions = i_permissions; + iv_next = NULL; +} + + + +//----------------------------------------------------------------------------- +fapi::ReturnCode +PibSlave::getScom(const uint32_t i_offset, uint64_t& o_data) +{ + fapi::ReturnCode rc; + rc = fapiGetScom( *iv_target, i_offset, *iv_dataBuffer ); + o_data = iv_dataBuffer->getDoubleWord( 0 ); + + return rc; +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +PibSlave::putScom(const uint32_t i_offset, const uint64_t i_data) +{ + fapi::ReturnCode rc; + iv_dataBuffer->setDoubleWordLength( 1 ); + iv_dataBuffer->setDoubleWord( 0, i_data ); + rc = fapiPutScom( *iv_target, i_offset, *iv_dataBuffer ); + + return rc; +} + + +//----------------------------------------------------------------------------- +PibMemory::PibMemory() : +iv_passThrough(false),iv_memory(NULL) +{ +} + +//----------------------------------------------------------------------------- +PibMemory::~PibMemory() +{ +} + +//----------------------------------------------------------------------------- +void +PibMemory::setPassThrough(const bool i_enable) +{ + iv_passThrough = i_enable; +} + +//----------------------------------------------------------------------------- +void +PibMemory::configure( + fapi::Target* i_target, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions, + Memory* i_memory + ) +{ + iv_target = i_target; + iv_dataBuffer = i_dataBuffer; + iv_base = i_base; + iv_size = i_size; + iv_permissions = i_permissions; + iv_memory = i_memory; + iv_next = NULL; +} + + +//----------------------------------------------------------------------------- +// +fapi::ReturnCode +PibMemory::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + ModelError me; + + if( io_transaction.iv_mode & ACCESS_MODE_READ ) + { + me = iv_memory->read( (uint32_t)(io_transaction.iv_offset * TRANSACTION_SIZE_IN_BYTES), io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = getScom( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + else if( io_transaction.iv_mode & ACCESS_MODE_WRITE ) + { + me = iv_memory->write( (uint32_t)(io_transaction.iv_offset * TRANSACTION_SIZE_IN_BYTES), io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = putScom( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + else + { + me = iv_memory->fetch( (uint32_t)(io_transaction.iv_offset * TRANSACTION_SIZE_IN_BYTES), io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = getScom( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + + io_transaction.busError( me ); + + if( me == ME_SUCCESS ) + { + rc = (uint32_t)0; // if read/write or getScom/putScom succeeded then set rc = 0 + } + + // if read/write failed then rc == 1 by default + // if read/write returned ME_NOT_MAPPED_IN_MEMORY && pass through true then rc == value returned from putScom or getScom + + return rc; +} + + +//----------------------------------------------------------------------------- +Memory::Memory() : + iv_images(0) +{ +#if POREVE_STATISTICS + resetStatistics(); +#endif +} + +//----------------------------------------------------------------------------- +Memory::~Memory() +{ +} + +//----------------------------------------------------------------------------- +bool +Memory::checkCrc() +{ + MemoryImage* mi = iv_images; + bool rc = true; + + do{ + + if( mi->checkCrc() == false ) + { + rc = false; + break; + } + mi = mi->iv_next; + + }while( mi != iv_images ); + + return rc; +} + + +//----------------------------------------------------------------------------- +ModelError +Memory::read( + uint32_t i_offset, + uint64_t& o_data, + size_t i_size + ) +{ + char* from_ptr; + char* to_ptr; + size_t cnt; + MemoryImage* mi; + ModelError me; + int mi_found; + + o_data = 0; // Assure all bytes are cleared + + me = ME_SUCCESS; + do{ + if( iv_images == 0 ) + { + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + mi = iv_images; + mi_found = 0; + do{ + + if( (i_offset >= mi->iv_base) && ((i_offset + i_size) <= (mi->iv_base + mi->iv_size) ) ) + { + mi_found= 1; + iv_images = mi; // have the Memory always point to the last MemoryImage that was used + break; // we found a chunk of memory containing the transaction address + } + mi = mi->iv_next; + + }while( mi != iv_images ); + + if( ! mi_found ) + { // There was no MemoryImage that contained the transaction address + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + + if( (mi->iv_permissions & ACCESS_MODE_READ ) == 0 ) + { // The permissions over the memory block do not allow the mode being used by the transaction + me = ME_MEMORY_IMAGE_PERMISSION_DENIED; + break; + } + + // Init the character pointer into the eprom image we are using. + from_ptr = (char*)mi->iv_image + (i_offset - mi->iv_base); + + // Init the character pointer into the o_data buffer. + // Take care of Endianess by moving to one or the other end of the buffer as appropriate. +#ifdef _BIG_ENDIAN + to_ptr = (char*)&o_data + (TRANSACTION_SIZE_IN_BYTES - i_size); +#else + to_ptr = ((char*)&o_data + i_size -1); +#endif + + for( cnt = 0; cnt < i_size; cnt++ ) + { + *to_ptr = *from_ptr++; + + // Move the to pointer either forward or backward as appropriate for Endianess +#ifdef _BIG_ENDIAN + to_ptr++; +#else + to_ptr--; +#endif + } + + me = ME_SUCCESS; + break; + }while(1); + +#if POREVE_STATISTICS + iv_reads++; +#endif + + return me; +} + +//----------------------------------------------------------------------------- +ModelError +Memory::fetch( + uint32_t i_offset, + uint64_t& o_data, + size_t i_size + ) +{ + char* from_ptr; + char* to_ptr; + size_t cnt; + MemoryImage* mi; + ModelError me; + int mi_found; + + o_data = 0; // Assure all bytes are cleared + + me = ME_SUCCESS; + do{ + if( iv_images == 0 ) + { + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + mi = iv_images; + mi_found = 0; + do{ + + if( (i_offset >= mi->iv_base) && ((i_offset + i_size) <= (mi->iv_base + mi->iv_size) ) ) + { + mi_found= 1; + iv_images = mi; // have the Memory always point to the last MemoryImage that was used + break; // we found a chunk of memory containing the transaction address + } + mi = mi->iv_next; + + }while( mi != iv_images ); + + if( ! mi_found ) + { // There was no MemoryImage that contained the transaction address + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + + if( (mi->iv_permissions & ACCESS_MODE_EXECUTE ) == 0 ) + { // The permissions over the memory block do not allow the mode being used by the transaction + me = ME_MEMORY_IMAGE_PERMISSION_DENIED; + break; + } + + // Init the character pointer into the eprom image we are using. + from_ptr = (char*)mi->iv_image + i_offset; + + // Init the character pointer into the o_data buffer. + // Take care of Endianess by moving to one or the other end of the buffer as appropriate. +#ifdef _BIG_ENDIAN + to_ptr = (char*)&o_data + (TRANSACTION_SIZE_IN_BYTES - i_size); +#else + to_ptr = ((char*)&o_data + i_size -1); +#endif + + for( cnt = 0; cnt < i_size; cnt++ ) + { + *to_ptr = *from_ptr++; + + // Move the to pointer either forward or backward as appropriate for Endianess +#ifdef _BIG_ENDIAN + to_ptr++; +#else + to_ptr--; +#endif + } + + me = ME_SUCCESS; + break; + }while(1); + +#if POREVE_STATISTICS + iv_fetches++; +#endif + + return me; +} + + + +//----------------------------------------------------------------------------- +ModelError +Memory::write( + uint32_t i_offset, // the address in the eprom image + uint64_t i_data, // data to write into the eprom image + size_t i_size // number of bytes to write (pretty much going to be TRANSACTION_SIZE_IN_BYTES) + ) +{ + char* to_ptr; + char* from_ptr; + size_t cnt; + MemoryImage* mi; + ModelError me; + int mi_found; + + me = ME_SUCCESS; + do{ + if( iv_images == 0 ) + { + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + mi = iv_images; + mi_found = 0; + do{ + + if( (i_offset >= mi->iv_base) && ((i_offset + i_size) <= (mi->iv_base + mi->iv_size) ) ) + { + mi_found= 1; + iv_images = mi; // have the Memory always point to the last MemoryImage that was used + break; // we found a chunk of memory containing the transaction address + } + mi = mi->iv_next; + + }while( mi != iv_images ); + + if( ! mi_found ) + { // There was no MemoryImage that contained the transaction address + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + + if( (mi->iv_permissions & ACCESS_MODE_WRITE ) == 0 ) + { // The permissions over the memory block do not allow the mode being used by the transaction + me = ME_MEMORY_IMAGE_PERMISSION_DENIED; + break; + } + + // Init the character pointer into the eprom image we are using. + to_ptr = (char*)mi->iv_image + i_offset; + + // Init the character pointer into the o_data buffer. + // Take care of Endianess by moving to one or the other end of the buffer as appropriate. +#ifdef _BIG_ENDIAN + from_ptr = (char*)&i_data + (TRANSACTION_SIZE_IN_BYTES - i_size); +#else + from_ptr = ((char*)&i_data + i_size -1); +#endif + + for( cnt = 0; cnt < i_size; cnt++ ) + { + *to_ptr++ = *from_ptr; + + // Move the to pointer either forward or backward as appropriate for Endianess +#ifdef _BIG_ENDIAN + from_ptr++; +#else + from_ptr--; +#endif + } + + me = ME_SUCCESS; + break; + + }while(1); + +#if POREVE_STATISTICS + iv_writes++; +#endif + + return me; +} + + +//----------------------------------------------------------------------------- +ModelError +Memory::map( + uint32_t i_base, // For direct memory this is the 0 based offset from the Slave iv_base + size_t i_size, // Size of this chunk of memory + int i_permissions, + void* i_image, + bool i_crcEnable + ) +{ + ModelError me = ME_SUCCESS; + MemoryImage* n; + MemoryImage* mi = new MemoryImage( i_base, i_size, i_permissions, i_image, i_crcEnable ); + + if( iv_images == 0 ) + { + iv_images = mi; + mi->iv_next = mi; + }else{ + n = iv_images->iv_next; + while( n->iv_next != iv_images ) + { + n = n->iv_next; + } + n->iv_next = mi; + mi->iv_next = iv_images; + } + + return me; +} + + +//----------------------------------------------------------------------------- +#if POREVE_STATISTICS +void +Memory::resetStatistics() +{ + iv_reads = 0; + iv_writes = 0; + iv_fetches = 0; +} +#endif // POREVE_STATISTICS + + +//----------------------------------------------------------------------------- +MemoryImage::MemoryImage( + uint32_t i_base, + size_t i_size, + int i_permissions, + void* i_image, + bool i_crcEnable + ) +{ + + iv_base = i_base; + iv_size = i_size; + iv_permissions = i_permissions; + iv_image = i_image; + iv_crcEnable = i_crcEnable; + iv_originalCrc = 0; + iv_next = NULL; + + if( i_crcEnable ) + { + iv_originalCrc = computeCrc(); + } + +} + +//----------------------------------------------------------------------------- +MemoryImage::~MemoryImage() +{ +} + +//----------------------------------------------------------------------------- +uint64_t +MemoryImage::computeCrc() +{ + return 0; +} + +//----------------------------------------------------------------------------- +bool +MemoryImage::checkCrc() +{ + bool result = true; + + if( iv_crcEnable == true ) + { + uint64_t current_crc = computeCrc(); + if( current_crc != iv_originalCrc ) + { + result = false; + } + } + + return result; +} + +//----------------------------------------------------------------------------- +OciMemory::OciMemory() : +iv_memory(NULL), iv_passThrough(false) +{ +} + +//----------------------------------------------------------------------------- +OciMemory::~OciMemory() +{ +} + +//----------------------------------------------------------------------------- +void +OciMemory::setPassThrough(const bool i_enable) +{ + iv_passThrough = i_enable; +} + +//----------------------------------------------------------------------------- +void +OciMemory::configure( + fapi::Target* i_target, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions, + Memory* i_memory + ) +{ + iv_target = i_target; + iv_dataBuffer = i_dataBuffer; + iv_base = i_base; + iv_size = i_size; + iv_permissions = i_permissions; + iv_memory = i_memory; +} + + + +//----------------------------------------------------------------------------- +// +fapi::ReturnCode +OciMemory::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + + ModelError me; + + if( io_transaction.iv_mode & ACCESS_MODE_READ ) + { + me = iv_memory->read( (uint32_t)io_transaction.iv_offset, io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = read( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + else + { + me = iv_memory->write( (uint32_t)io_transaction.iv_offset, io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = write( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + + io_transaction.busError( me ); + + if( me == ME_SUCCESS ) + { + rc = (uint32_t)0; + } + + // if read/write failed then rc == 1 by default + // if read/write returned ME_NOT_MAPPED_IN_MEMORY && pass through true then + // rc == value returned from putScom or getScom + + return rc; +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +OciSlave::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + ModelError me; + + if( io_transaction.iv_mode & ACCESS_MODE_READ ) + { + rc = read( io_transaction.iv_address, io_transaction.iv_data ); + } + else + { + rc = write( io_transaction.iv_address, io_transaction.iv_data ); + } + + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + + io_transaction.busError( me ); + + return rc; +} + +//----------------------------------------------------------------------------- +OciSlave::~OciSlave() +{ +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +OciSlave::read(const uint32_t i_address, uint64_t& o_data) +{ + fapi::ReturnCode rc; + return rc; +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +OciSlave::write(const uint32_t i_address, const uint64_t i_data) +{ + fapi::ReturnCode rc; + return rc; +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +OciSlaveWritable::write(const uint32_t i_address, const uint64_t i_data) +{ + + // For this model, print out a message to confirm a write has been written is all it needs. + FAPI_INF("OciSlaveWritable::write(0x%08x, 0x%016llx)", + i_address, i_data); + fapi::ReturnCode rc; + return rc; +} + diff --git a/src/usr/pore/poreve/porevesrc/bus.H b/src/usr/pore/poreve/porevesrc/bus.H new file mode 100644 index 000000000..6370bae84 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/bus.H @@ -0,0 +1,661 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/bus.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_BUS_H +#define __VSBE_BUS_H + +// $Id: bus.H,v 1.14 2011/12/16 21:47:59 bcbrock Exp $ + +/// \file bus.H +/// \brief PoreVe bus and base device models + +#include <fapi.H> +#include "transaction.H" + + +namespace vsbe +{ + +class Slave; +class Memory; + +// Temporary FAPI return codes from getscom/putscom errors +#define fapi_PCB_RESOURCE_BUSY 0x02014003 +#define fapi_PCB_OFFLINE_ERROR 0x02014005 +#define fapi_PCB_PARTIAL_ERROR 0x02014007 +#define fapi_PCB_ADDRESS_ERROR 0x02014009 +#define fapi_PCB_CLOCK_ERROR 0x0201400B +#define fapi_PCB_PARITY_ERROR 0x0201400D +#define fapi_PCB_TIMEOUT_ERROR 0x0201400F + +//----------------------------------------------------------------------------- +/*! +The Pore hardware engine is connected via PIB bus and OCI bus. The Bus object +functions to group all entities on the bus. For example, the PIB has the ability +to run put/getscom via the PibSlave, as well as access OTPROM memory via the +PibMemory object and PNOR and SEEPROM via FastI2cMemory objects. +*/ +/// All pore hardware bus transactions are submitted through a Bus object. +class Bus +{ + +public: + + Bus(); + virtual ~Bus(); + + /*! Primary Slaves are searched first for a given Transaction Address */ + /// Primary Slaves are a linked list of Slave based objects + void attachPrimarySlave(Slave* i_slave); + + /*! If a Secondary slave cannot service the Transaction then the Transaction address + is not mapped on the bus at all. */ + /// Secondary Slaves are searched only if a Primary Slave did not support the Transaction Address + void attachSecondarySlave(Slave* i_slave); + + /*! + The PrimarySlaves attached to the bus are checked to find one that handles the + Transaction address. If no match, then the SecondarySlaves are checked. When a + Slave is found containing the address the Transaction::iv_offset is set to the + Transaction::iv_address - Slave::iv_base. The Slave operation method is then + executed. + + The return code from the Slave is passed back and becomes the return code of the + Bus operation. The Transaction ModelError is set by the Slave and is passed back + as well. + + @returns If any error occurs then the fapi::ReturnCode is not ok, and the + transaction ModelError indicates the kind of problem found. + + @returns rc=1 and Transaction ModelError=ME_NOT_MAPPED_ON_BUS if neither Primary + nor Secondary Slaves have mapped the transaction address. + + @returns rc=1 and Transaction ModelError=ME_BUS_SLAVE_PERMISSION_DENIED if the + transaction address is found on a Slave but the Slave permissions deny the + transaction mode. + + @returns rc=1 and Transaction ModelError= some other Model Error codes if the + Slave operation fails. + + @returns rc=0 and Transaction ModelError=ME_SUCCESS if the transaction was + successful. + */ + /// The basic method called to get a bus transaction done. + fapi::ReturnCode operation(Transaction& io_transaction); + + +protected: + + /// Primary list of "attached" bus elements like PibMemory, OciMemory and so forth + Slave* iv_primarySlaves; + + /// The Secondary list is used when the Primary list fails to contain a Transaction address + Slave* iv_secondarySlaves; + +}; + +//----------------------------------------------------------------------------- +/*! +Any kind of object attached to a Bus must be based upon the Slave class. +Each of the Bus devices must specify their base address, size, and permissions +as well as target and dataBuffer to be used for bus transactions. All these attributes +are defined by the base Slave class. +*/ +/// The Slave object contains the common attributes of all bus devices. +class Slave +{ +public: + + Slave(); + virtual ~Slave(); + + /// Slave based objects must be configured before use. + virtual void configure(fapi::Target* i_target, + ecmdDataBufferBase *i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions); + + /*! + Notice that the operation is pure virtual in the Slave class. All derived bus attached + devices must define their own operation methods since they vary from one to the other. + */ + /// The Slave class also defines the fundamental operation that a Bus can call. + virtual fapi::ReturnCode operation(Transaction& io_transaction) = 0; // the slave instance will implement + + /*! + The iv_base address is specified in terms of the system, so for example it might be the first address + in a range beginning at 0x08000000 in the system memory, or it might be the first address in a range of + scom addresses in the system. + */ + /// The Bus devices base address. A System memory address or scom address, not an offset. + uint32_t iv_base; + + /// This specifies the number of bytes from the iv_base that this Bus device responds to. + uint64_t iv_size; + + /*! + For example: ACCESS_MODE_READ | ACCESS_MODE_WRITE | ACCESS_MODE_EXECUTE + */ + /// Establish the read/write/execute mode allowed upon this Bus device. + int iv_permissions; + + /// Points to the next Slave in a linked list that the Bus::operation will search + Slave* iv_next; + + /// A pointer to the fapi Target to be used when accessing this Bus device. + fapi::Target* iv_target; + + /// A pointer to the fapi DataBuffer to be used when accessing this Bus device. + ecmdDataBufferBase* iv_dataBuffer; + + +}; + + +//----------------------------------------------------------------------------- +/*! +The SCOM addresses of a system are defined by a call to configure to the PIB +slave for the system. There is no mapping done since there is no memory manager +involved. When the PIB bus manager is asked to perform an operation and if the +Transaction iv_address falls into the address range of the SCOM's then the +operation method for the Slave will be called, which will call the +PibSlave::getScom/putScom implemnted with fapiGet/Putscom. +*/ +/// Implements SCOM access to the system. +class PibSlave : public Slave +{ +public: + + PibSlave(); + virtual ~PibSlave(); + + /// Overriding Slave::operation + virtual fapi::ReturnCode operation(Transaction& io_transaction); + +protected: + + /*! + The i_offset is an actual scom address that has not been changed to implement + "core reduction" as an eCMD address might for certain chiplets. The address is + the raw native SCOM address used by the hardware. + + The calling Slave class object iv_target and iv_dataBuffer are used to perform + the operation. + + @returns rc= the value returned by fapi::GetScom + */ + /// PibSlave read calls fapi::GetScom + fapi::ReturnCode getScom(const uint32_t i_offset, uint64_t& o_data); + + /*! + The i_offset is an actual scom address that has not been changed to implement + "core reduction" as an eCMD address might for certain chiplets. The address is + the raw native SCOM address used by the hardware. + + The calling Slave class object iv_target and iv_dataBuffer are used to perform + the operation. + + @returns rc= the value returned by fapi::PutScom + */ + /// PibSlave write calls fapi::PutScom + fapi::ReturnCode putScom(const uint32_t i_offset, const uint64_t i_data); +}; + +//----------------------------------------------------------------------------- +/*! +This object has (virtual) methods to handle directly access memory. +*/ +/// Methods Used to access OTPROM. +class PibMemory : public PibSlave +{ +public: + + PibMemory(); + virtual ~PibMemory(); + + + /// Slave based objects must be configured before use. + virtual void configure(fapi::Target* i_target, + ecmdDataBufferBase *i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions, + Memory* i_memory); + + /*! + Pass-through mode is established with a true value. This mode means that if a + PibMemory address is NOT_MAPPED_IN_MEMORY then the address of a transaction is + passed-through to the PibSlave::getScom or PibSlave::putScom method for resolution. + */ + /// Control the pass-through mode. True means pass-through mode is enabled. + void setPassThrough(const bool i_enable); + + /*! + Bus::operation already made sure the Transaction address is within our chunk of + memory and has set the Transaction::iv_offset. + + This operation accesses direct memory, like OTPROM. + + Transactions give us addresses on 64bit , or 8 byte, boundries. The address + passed into Memory::read or write is calculated as the Transaction::iv_offset * + 8. So, as example, if the Transaction::_iv_address was 0x08000000 and the + PibMemory Slave::iv_base were configured to 0x08000000 then the + Transaction::iv_offset would be 0x00000000. That multiplied by 8 remains + 0x00000000. If the Transaction address were 0x08000001, then the Transaction + offset would be 0x00000001, and that multiplied by 8 would be 0x00000008, the + reall offset into the eprom image we will read or write from. + + If a ACCESS_MODE_READ transaction is called for then the Memory::read method is + called passing the Transaction iv_offset to complete the operation. If Memory::read + returns ME_NOT_MAPPED_IN_MEMORY and if iv_passThrough is true then + PibSlave::getScom is called passing the Transaction iv_address. + + If a ACCESS_MODE_READ transaction is called for then the Memory::write method is + called passing the Transaction iv_offset to complete the operation. If Memory::write + returns ME_NOT_MAPPED_IN_MEMORY and if iv_passThrough is true then + PibSlave::putScom is called passing the Transaction iv_address. + + @returns rc=0 if transaction succeeded + @returns rc=1 if transaction failed and passThrough mode was not active + @returns rc!=0 if read/write failed and passThrough call to getScom/putScom also + failed. In this case the rc value is whatever getScom or putScom returns from + fapi. + + */ + /// Implement a PibMemory transaction. Called by the Bus::operation() + virtual fapi::ReturnCode operation(Transaction& io_transaction); + +protected: + + /// Remember the pass-through mode setting + bool iv_passThrough; + + /// Pointer to Memory manager storing a linked list of MemoryImage (s) "containing" mapped memory areas + Memory* iv_memory; + +}; + +//----------------------------------------------------------------------------- +/// Not sure what a OciSlave does yet +class OciSlave : public Slave +{ +public: + + virtual ~OciSlave(); + + /*! + Bus::operation already made sure the Transaction address is within our chunk of + memory and has set the Transaction::iv_offset. + + If a ACCESS_MODE_READ transaction is called for then the OciSlave::read method is + called passing the Transaction iv_address to complete the operation. + + If a ACCESS_MODE_WRITE transaction is called for then the OciSlave::write method is + called passing the Transaction iv_address to complete the operation. + + @returns rc=0 if transaction succeeded + @returns rc=1 if transaction failed + + */ + virtual fapi::ReturnCode operation(Transaction& io_transaction); + +protected: + + /*! + Called by OciSlave::operation. + */ + virtual fapi::ReturnCode read(const uint32_t i_address, uint64_t& o_data); + + /*! + Called by OciSlave::operation. + */ + virtual fapi::ReturnCode write(const uint32_t i_address, const uint64_t i_data); + +}; + +//----------------------------------------------------------------------------- +/// An OciSlave that accepts and simply swallows write transactions +class OciSlaveWritable : public OciSlave +{ +public: + virtual fapi::ReturnCode write(const uint32_t i_address, const uint64_t i_data); +}; + +//----------------------------------------------------------------------------- +/// Methods Used to access Mainstore/SRAM +class OciMemory : public OciSlave +{ +public: + + OciMemory(); + virtual ~OciMemory(); + + /// Slave based objects must be configured before use. + virtual void configure(fapi::Target* i_target, + ecmdDataBufferBase *i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions, + Memory* i_memory); + + /*! + Bus::operation already made sure the Transaction address is within our chunk of + memory and has set the Transaction::iv_offset. + + This operation accesses memory like Mainstore or SRAM memory. + + Transactions to the OCI bus give us addresses on byte boundries. The offset + passed into Memory::read or write is therefore simply the + Transaction::iv_offset without modification. + + If a ACCESS_MODE_READ transaction is called for then the Memory::read method is + called passing the Transaction iv_offset to complete the operation. If Memory::read + returns ME_NOT_MAPPED_IN_MEMORY and if iv_passThrough is true then + OciSlave::read is called passing the Transaction iv_address. + + If a ACCESS_MODE_READ transaction is called for then the Memory::write method is + called passing the Transaction iv_offset to complete the operation. If Memory::write + returns ME_NOT_MAPPED_IN_MEMORY and if iv_passThrough is true then + OciSlave::write is called passing the Transaction iv_address. + + @returns rc=0 if transaction succeeded + @returns rc=1 if transaction failed and passThrough mode was not active + @returns rc!=0 if read/write failed and passThrough call to OciSlave::read/write also + failed. In this case the rc value is whatever OciSlave::read or OciSlave::write returns. + */ + /// Implement a OciMemory transaction. Called by the Bus::operation() + virtual fapi::ReturnCode operation(Transaction& io_transaction); + + /*! + Pass-through mode is established with a true value. This mode means that if a + OciMemory address is NOT_MAPPED_IN_MEMORY then the address of a transaction is + passed-through to the OciSlave::read or OciSlave::write method for resolution. + */ + /// Control the pass-through mode. True means pass-through mode is enabled. + void setPassThrough(const bool i_enable); + + /// Pointer to Memory manager storing a linked list of MemoryImage (s) "containing" mapped memory areas + Memory *iv_memory; + +protected: + + /// Remember the pass-through mode setting + bool iv_passThrough; +}; + + +//----------------------------------------------------------------------------- +/// Store details of a block of memory being managed by a Memory manager +class MemoryImage +{ +public: + + /*! + A MemoryImage is used to store information about a portion of Memory that has been mapped. + It is created by the Memory::map method. + + @param i_base A zero based offset from the Slave iv_base address + @param i_size Size of i_image in bytes + @param i_permissions The read/write/execute permissions over this block of memory + @param i_image A pointer to an allocated block of memory storing the content of the block of memory + @param i_crcEnable true or false indicating whether crc is to be calculated over the block of memory + */ + MemoryImage(uint32_t i_base, + size_t i_size, + int i_permissions, + void* i_image, + bool i_crcEnable ); + + virtual ~MemoryImage(); + + /*! + When this method is called the crc of the associated MemoryImage is calculated + and compared to iv_originalCrc which was the crc value at the time that the + MemoryImage was mapped into the Memory. + + @returns true if iv_originalCrc == the current crc of the MemoryImage or if crc + checking is not enabled for the MemoryImage. + @returns false if crc checking is enabled and the crc values do not match. + */ + /// true if iv_originalCrc == current crc, or if iv_crcEnable == false + virtual bool checkCrc(); + + /// base address associated with iv_image in the system (not real address of iv_image) + uint32_t iv_base; + + /// byte size of the block of memory pointed to by iv_image + size_t iv_size; + + /// Access permissions over this block of memory (ACCESS_MODE_READ | ACCESS_MODE_WRITE | ACCESS_MODE_EXECUTE) + int iv_permissions; + + /// Pointer to the chunk of memory a user has allocated and stored eprom image into + void* iv_image; + + /// Remember if told to compute crc or not via i_crcEnable + bool iv_crcEnable; + + /// Link to next MemoryImage in the Memory managers circular linked list + MemoryImage* iv_next; + +protected: + + /// Method to calculate crc over iv_image + virtual uint64_t computeCrc(); + + /// If iv_crcEnable is true this is the calculated crc over iv_image at the time it was mapped into Memory + uint64_t iv_originalCrc; +}; + +//----------------------------------------------------------------------------- +/// Contains one or many MemoryImages for a certain type of memory +class Memory +{ +public: + + Memory(); + virtual ~Memory(); + + /*! + The map method is used to register a pointer to a contiguous block of memory + that contains some part of an eeprom image, as well as to declare the offset + from the system base address, the size, and access permissions of that block of + memory. + + The iv_images pointer of the Memory manager points to one or many MemoryImages. + Each time this map method is called a new MemoryImage object is created to + remember all the details about the i_image being passed in. The new MemoryImage + is placed into a circular linked list owned by the Memory manager. + + The Memory manager is always associated with a particuliar kind of memory, like + PibMemory or OciMemory, so the i_image is some portion of PibMemory or + OciMemory. As an example, suppose OTPROM is 0x01000000 bytes in the system, + starting at address 0x80000000. Also suppose you have parts of the OTPROM from + 0x80000000 to 0x80000100 and from 0x80010000 to 0x80010500 in two image files + that you have read into program memory and you want to map into the OTPROM + Memory manager. When calling the configure method on the PibMemory you declare + OTPROM memory starts at 0x80000000 and has 0x01000000 bytes. Then you call map + on the PibMemory manager twice, first declaring an offset 0x00000000 for + 0x00000100 bytes, then again with offset 0x00010000 for 0x00000500 bytes. + + @param i_base A zero based offset from the Slave iv_base address + @param i_size Size of i_image in bytes + @param i_permissions The read/write/execute permissions over this block of memory + @param i_image A pointer to an allocated block of memory storing the content of the block of memory + @param i_crcEnable true or false indicating whether crc is to be calculated over the block of memory + @returns ME_SUCCESS if all's well (currently that's all it can return) + */ + /// Register a "chunk" of memory to the Memory manager + virtual ModelError map(uint32_t i_base, + size_t i_size, + int i_permissions, + void* i_image, + bool i_crcEnable); + + /*! + This method runs through every MemoryImage checking its crc. + + @returns true if all MemoryImage have the same crc as when they were originally mapped into Memory + @returns false if any MemoryImage has a crc that is different + */ + /// Check if crc of all MemoryImages is still the same as when it was originally mapped into Memory + virtual bool checkCrc(); + + /*! + This method is used to read Direct Memory out of an eprom image. An offset from + the base of the eprom memory image is passed in for the access, along with the + number of bytes to read. + + The memory storage may be split into more than one MemoryImage's that have been + mapped. This method runs through the circuliarly linked list of MemoryImage objects + looking for one that contains the block of memory being accessed. + + Upon successfully finding a containing MemoryImage the Memory::iv_images is set + to point to the MemoryImage just found. This should speed up operation assuming + a large number of transactions might occur on contiguous blocks of memory. + + The data are copied out of the MemoryImage::iv_image into the o_data buffer for + return. The Endianess of the host platform being used is considered as this + operation occurs. (It is assumed the MemoryImage::iv_image is stored in + BigEndian order.) + + @returns If there is no MemoryImage that contains the block of memory requested + then ME_NOT_MAPPED_IN_MEMORY is returned. + + @returns If the memory block is found within a MemoryImage but the + MemoryImage::iv_permissions do not permit ACCESS_MODE_READ then + ME_MEMORY_IMAGE_PERMISSION_DENIED is returned. + + @returns ME_SUCCESS if all bytes of the memory requested are contained in the + MemoryImage and the permissions of the MemoryImage allow ACCESS_MODE_READ. + + */ + /// Used to find a MemoryImage from which to read data + virtual ModelError read(uint32_t i_offset, + uint64_t& o_data, + size_t i_size + ); + + /*! + This method is used to fetch instructions from Direct Memory out of an eprom + image. An offset from the base of the eprom memory image is passed in for the + access, along with the number of bytes to read. + + The memory storage may be split into more than one MemoryImage's that have been + mapped. This method runs through the circuliarly linked list of MemoryImage objects + looking for one that contains the block of memory being accessed. + + Upon successfully finding a containing MemoryImage the Memory::iv_images is set + to point to the MemoryImage just found. This should speed up operation assuming + a large number of transactions might occur on contiguous blocks of memory. + + The data are copied out of the MemoryImage::iv_image into the o_data buffer for + return. The Endianess of the host platform being used is considered as this + operation occurs. (It is assumed the MemoryImage::iv_image is stored in + BigEndian order.) + + @returns If there is no MemoryImage that contains the block of memory requested + then ME_NOT_MAPPED_IN_MEMORY is returned. + + @returns If the memory block is found within a MemoryImage but the + MemoryImage::iv_permissions do not permit ACCESS_MODE_EXECUTE then + ME_MEMORY_IMAGE_PERMISSION_DENIED is returned. + + @returns ME_SUCCESS if all bytes of the memory requested are contained in the + MemoryImage and the permissions of the MemoryImage allow ACCESS_MODE_EXECUTE. + + */ + /// Used to find a MemoryImage from which to fetch instructions + virtual ModelError fetch(uint32_t i_offset, + uint64_t& o_data, + size_t i_size + ); + + /*! + This method is used to write Direct Memory out of an eprom image. An offset from + the base of the eprom memory image is passed in for the access, along with the + number of bytes to write. + + The memory storage may be split into more than one MemoryImage's that have been + mapped. This method runs through the circuliarly linked list of MemoryImage objects + looking for one that contains the block of memory being accessed. + + Upon successfully finding a containing MemoryImage the Memory::iv_images is set + to point to the MemoryImage just found. This should speed up operation assuming + a large number of transactions might occur on contiguous blocks of memory. + + The data are copied out of the i_data buffer into the MemoryImage::iv_image. The + Endianess of the host platform being used is considered as this operation + occurs. (It is assumed the MemoryImage::iv_image is stored in BigEndian order.) + + @returns If there is no MemoryImage that contains the block of memory requested + then ME_NOT_MAPPED_IN_MEMORY is returned. + + @returns If the memory block is found within a MemoryImage but the + MemoryImage::iv_permissions do not permit ACCESS_MODE_WRITE then + ME_MEMORY_IMAGE_PERMISSION_DENIED is returned. + + @returns ME_SUCCESS if all bytes of the memory requested are contained in the + MemoryImage and the permissions of the MemoryImage allow ACCESS_MODE_WRITE. + + */ + /// Used to find a MemoryImage to change + virtual ModelError write(uint32_t i_offset, + uint64_t i_data, + size_t i_size); + + /// Pointer to first MemoryImage in a circularly linked list + MemoryImage* iv_images; + +#if POREVE_STATISTICS + + /// Reset Memory usage statistics + /// + /// This API clears the instance variables iv_reads, iv_writes and + /// iv_fetches. + void + resetStatistics(); + + /// Number of read() calls for this memory + uint64_t iv_reads; + + /// Number of write() calls for this memory + uint64_t iv_writes; + + /// Number of fetch() calls for this memory + uint64_t iv_fetches; + +#endif // POREVE_STATISTICS + +}; + + + + + + + + + +} // end of namespace vsbe +#endif diff --git a/src/usr/pore/poreve/porevesrc/create.C b/src/usr/pore/poreve/porevesrc/create.C new file mode 100644 index 000000000..8e0d8d636 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/create.C @@ -0,0 +1,46 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/create.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $ID$ + +/// \file create.C +/// \brief The create method for PoreVe +/// +/// The PoreVe class declares a static create() method that allows link-time +/// selection of a normal vs. debug version of PoreVe. This is similar to the +/// same idea used to make a link-time selection of the Pore hardware model +/// (PMX vs. BOE). This create() method is linked into the poreve.so. The +/// create() method for PoreVeDbg is defined in dbg.C + +#include "poreve.H" + +using namespace vsbe; + +PoreVe* +PoreVe::create(const PoreIbufId i_id, + const fapi::Target i_masterTarget, + const void* i_arg) +{ + // i_arg is needed for subclass to instantiate and the (debug) subclass. + return new PoreVe(i_id, i_masterTarget); +} + diff --git a/src/usr/pore/poreve/porevesrc/fasti2c.C b/src/usr/pore/poreve/porevesrc/fasti2c.C new file mode 100644 index 000000000..676fdccda --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/fasti2c.C @@ -0,0 +1,604 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/fasti2c.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: fasti2c.C,v 1.5 2012/01/10 00:27:41 bcbrock Exp $ + +/// \file fasti2c.C +/// \brief The "fast-mode" I2C controllers and I2C memory models used +/// to implement the OTPROM, PNOR and SEEPROM interfaces. + +#include "fasti2c.H" + +/// Diagnostic aid for debugging fasti2c.C +#ifdef DEBUG_FASTI2C +#define BUG() \ + FAPI_ERR("\n>>> fasti2c:Bug trapped at %s:%d\n\n", \ + __FILE__, __LINE__) +#else +#define BUG() +#endif // DEBUG_FASTI2C + +using namespace vsbe; + +//////////////////////////////////////////////////////////////////////////// +// I2cMemory +//////////////////////////////////////////////////////////////////////////// + +I2cMemory::I2cMemory(const size_t i_addressBytes) : +iv_addressBytes(i_addressBytes), iv_address(0) +{ +} + + +I2cMemory::~I2cMemory() +{ +} + + +ModelError +I2cMemory::addressWrite(const size_t i_bytes, const uint32_t i_address) +{ + ModelError me; + + if (i_bytes != iv_addressBytes) { + BUG(); + me = ME_I2CMEMORY_ILLEGAL_ADDRESS; + } else { + me = ME_SUCCESS; + iv_address = i_address; + } + return me; +} + + +ModelError +I2cMemory::dataRead(const size_t i_bytes, uint64_t& o_data) +{ + ModelError me; + + me = read(iv_address, o_data, i_bytes); + if (me == 0) { + iv_address += i_bytes; + } + return me; +} + + +ModelError +I2cMemory::dataWrite(const size_t i_bytes, const uint64_t i_data) +{ + ModelError me; + + me = write(iv_address, i_data, i_bytes); + if (me == 0) { + iv_address += i_bytes; + } + return me; +} + + +//////////////////////////////////////////////////////////////////////////// +// FastI2cController +//////////////////////////////////////////////////////////////////////////// + +FastI2cController::FastI2cController() : + iv_devices(0), + iv_state(IDLE), iv_fifo(0) + +{ + iv_status.value = 0; + iv_control.value = 0; +} + + +// The destructor deletes the circular list of devices. + +FastI2cController::~FastI2cController() +{ + I2cDevice *p, *next; + + if (iv_devices != 0) { + for (p = iv_devices->next; p != iv_devices; p = next) { + next = p->next; + delete p; + } + delete iv_devices; + } +} + + +ModelError +FastI2cController::attachMemory(I2cMemory* i_memory, + const unsigned i_port, + const unsigned i_deviceAddress) +{ + ModelError me = ME_SUCCESS; + FastI2cControlRegister control; // Used to validate i_Port and i_deviceId + I2cDevice* device = new I2cDevice; + + control.fields.port_number = i_port; + control.fields.device_address = i_deviceAddress; + // Make sure input variables fits into control fields + if ((control.fields.port_number != i_port) || + (control.fields.device_address != i_deviceAddress)) { + BUG(); + me = ME_INVALID_ARGUMENT; + + } else { + + device->iv_port = i_port; + device->iv_deviceAddress = i_deviceAddress; + device->iv_memory = i_memory; + + if (iv_devices == 0) { + iv_devices = device; + device->next = device; + } else { + + if (findDevice(i_port, i_deviceAddress) != 0) { + BUG(); + me = ME_DUPLICATE_CONFIGURATION; + } else { + device->next = iv_devices->next; + iv_devices->next = device; + } + } + } + if (me != 0) { + delete device; + } + return me; +} + + +// Modeling notes: +// +// o The RESET register is not modeled here +// +// o Our models ignore the I2C Speed +// +// o Transactions complete in 0 time and polling always succeeds on the first +// read of the status register. This is done to simplify the PORE +// engine model. +// +// o Only the following types of control register actions are modeled: +// * Address write : with_start; with_address; !with_continue; with_stop; +// data_length == 0 +// * Data read : with_start; with_address; !with_continue; with_stop; +// data_length == [4,8] +// * Data write : with_start; with_address; !with_continue; with_stop; +// data_length == 8 +// +// o The memory models hold the last address written +// +// o Redundant reads of the STATUS register are allowed +// +// o PORE only does 4/8 byte reads and 8 byte writes, so any other data +// access is considered an error (although the models could easily be +// extended to allow them). + +fapi::ReturnCode +FastI2cController::operation(Transaction& io_transaction) +{ + ModelError me; + fapi::ReturnCode rc; + + if (0) { + if (io_transaction.iv_mode == ACCESS_MODE_WRITE) { + FAPI_DBG("FASTI2C : write : offset = %u, data = 0x%016llx\n", + io_transaction.iv_offset, + io_transaction.iv_data); + } else { + FAPI_DBG("FASTI2C : read : offset = %u\n", + io_transaction.iv_offset); + } + } + + switch (io_transaction.iv_offset) { + + case FASTI2C_CONTROL_OFFSET: + + if (io_transaction.iv_mode != ACCESS_MODE_WRITE) { + BUG(); + me = ME_WRITE_ONLY_REGISTER; + + } else if (iv_state != IDLE) { + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + + } else { + + iv_control.value = io_transaction.iv_data; + + if (!iv_control.fields.with_start || + !iv_control.fields.with_address || + iv_control.fields.read_continue || + !iv_control.fields.with_stop) { + BUG(); + me = ME_FASTI2C_CONTROL_ERROR; + + } else if (iv_control.fields.read_not_write == 0) { + + if (iv_control.fields.address_range == 0) { + BUG(); + me = ME_FASTI2C_CONTROL_ERROR; + + } else { + if (iv_control.fields.data_length == 0) { + me = addressWrite(); + + } else if (iv_control.fields.data_length != 8) { + BUG(); + me = ME_FASTI2C_CONTROL_ERROR; + + } else { + me = initialDataWrite(); + } + } + } else { + if ((iv_control.fields.data_length != 4) && + (iv_control.fields.data_length != 8)) { + BUG(); + me = ME_FASTI2C_CONTROL_ERROR; + } else { + me = dataRead(); + } + } + } + break; + + + case FASTI2C_STATUS_OFFSET: + + if (io_transaction.iv_mode != ACCESS_MODE_READ) { + BUG(); + me = ME_READ_ONLY_REGISTER; + + } else { + + switch (iv_state) { + + case ADDRESS_WRITE_ONGOING: + case DATA_WRITE_ONGOING: + iv_status.value = 0; + iv_status.fields.i2c_command_complete = 1; + io_transaction.iv_data = iv_status.value; + iv_state = IDLE; + me = ME_SUCCESS; + break; + + case DATA_READ_ONGOING: + iv_status.value = 0; + iv_status.fields.i2c_command_complete = 1; + iv_status.fields.i2c_fifo_entry_count = + iv_control.fields.data_length; + io_transaction.iv_data = iv_status.value; + iv_state = DATA_AVAILABLE; + me = ME_SUCCESS; + break; + + case IDLE: + io_transaction.iv_data = iv_status.value; + me = ME_SUCCESS; + break; + + default: + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + break; + } + } + break; + + + case FASTI2C_DATA_OFFSET: + + if ((io_transaction.iv_mode == ACCESS_MODE_READ) || + (io_transaction.iv_mode == ACCESS_MODE_EXECUTE)) { + + switch (iv_state) { + + case DATA_AVAILABLE: + io_transaction.iv_data = iv_fifo; + iv_state = IDLE; + me = ME_SUCCESS; + break; + + default: + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + break; + } + } else { + + switch (iv_state) { + + case WRITE_DATA_EXPECTED: + me = finalDataWrite(io_transaction.iv_data); + iv_state = DATA_WRITE_ONGOING; + + default: + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + break; + } + } + break; + + + default: + BUG(); + me = ME_ILLEGAL_REGISTER_OFFSET; + break; + } + + if (me != 0) { + iv_state = ERROR; + rc = 1; // \bug Fix this + } + io_transaction.busError(me); + return rc; +} + + +// Find the device in the circular device list and spin the device to the +// front of the list if found. + +I2cDevice* +FastI2cController::findDevice(const unsigned i_port, + const unsigned i_deviceAddress) +{ + I2cDevice* p; + + p = iv_devices; + if (p != 0) { + do { + if ((p->iv_port == i_port) && + (p->iv_deviceAddress == i_deviceAddress)) { + iv_devices = p; + break; + } + if (p == iv_devices) { + p = 0; + break; + } + } while(1); + } + return p; +} + + +uint32_t +FastI2cController::getI2cAddress(const FastI2cControlRegister i_control) +{ + size_t addressBytes = i_control.fields.address_range; + + return i_control.words.low_order >> ((4 - addressBytes) * 8); +} + + +// The address is left-justified in the low-order 32 bits of the control +// register. + +ModelError +FastI2cController::addressWrite() +{ + ModelError me; + unsigned port = iv_control.fields.port_number; + unsigned deviceAddress = iv_control.fields.device_address; + size_t addressBytes = iv_control.fields.address_range; + I2cDevice* p; + + p = findDevice(port, deviceAddress); + if (p == 0) { + BUG(); + me = ME_NOT_MAPPED_ON_FASTI2C_CONTROLLER; + } else { + me = p->iv_memory->addressWrite(addressBytes, + getI2cAddress(iv_control)); + iv_state = ADDRESS_WRITE_ONGOING; + } + return me; +} + + +ModelError +FastI2cController::dataRead() +{ + ModelError me; + unsigned port = iv_control.fields.port_number; + unsigned deviceAddress = iv_control.fields.device_address; + size_t dataBytes = iv_control.fields.data_length; + uint64_t data; + I2cDevice* p; + + p = findDevice(port, deviceAddress); + if (p == 0) { + BUG(); + me = ME_NOT_MAPPED_ON_FASTI2C_CONTROLLER; + } else { + me = p->iv_memory->dataRead(dataBytes, data); + iv_fifo = data << (64 - (dataBytes * 8)); + iv_state = DATA_READ_ONGOING; + } + return me; +} + + +// For addresses < 4 bytes, the first slug of data occupies the remainder of +// the low-order word of the control register. Any remaining bytes come in on +// the next transaction targeting the data register. This code assumes 8-byte +// only data writes. + +ModelError +FastI2cController::initialDataWrite() +{ + unsigned addressBytes = iv_control.fields.address_range; + + if (addressBytes < 4) { + iv_fifo = + BE64_GET_FIELD(iv_control.words.low_order, + 32 + (addressBytes * 8), + 63) << + ((4 - addressBytes) * 8); + } + iv_state = WRITE_DATA_EXPECTED; + return ME_SUCCESS; +} + + +// Assume 8-byte only write transactions + +ModelError +FastI2cController::finalDataWrite(const uint64_t i_data) +{ + ModelError me; + unsigned port = iv_control.fields.port_number; + unsigned deviceAddress = iv_control.fields.device_address; + size_t addressBytes = iv_control.fields.address_range; + I2cDevice* p; + + iv_fifo = + BE64_SET_FIELD(iv_fifo, addressBytes * 8, 63, + BE64_GET_FIELD(i_data, 0, + ((8 - addressBytes) * 8)) - 1); + + p = findDevice(port, deviceAddress); + if (p == 0) { + BUG(); + me = ME_NOT_MAPPED_ON_FASTI2C_CONTROLLER; + } else { + me = p->iv_memory->dataWrite(8, iv_fifo); + iv_state = DATA_WRITE_ONGOING; + } + return me; +} + + +//////////////////////////////////////////////////////////////////////////// +// LpcController +//////////////////////////////////////////////////////////////////////////// + +LpcController::LpcController() : + iv_eccStart(0), + iv_eccStop(LPC_MEMORY_MAX_SIZE) +{ +} + + +LpcController::~LpcController() +{ +} + + +fapi::ReturnCode +LpcController::operation(Transaction& io_transaction) +{ + ModelError me = ME_SUCCESS; + fapi::ReturnCode rc; + bool handledBySuperclass = false; + FastI2cControlRegister control; + uint32_t address; + + switch (io_transaction.iv_offset) { + + case LPCM_ECC_START_OFFSET: + + if (iv_state != IDLE) { + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + + } else if (io_transaction.iv_mode == ACCESS_MODE_READ) { + io_transaction.iv_data = iv_eccStart; + me = ME_SUCCESS; + + } else if (io_transaction.iv_mode == ACCESS_MODE_WRITE) { + iv_eccStart = io_transaction.iv_data; + me = ME_SUCCESS; + + } else { + BUG(); + me = ME_BUS_SLAVE_PERMISSION_DENIED; + } + break; + + case LPCM_ECC_STOP_OFFSET: + + if (iv_state != IDLE) { + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + + } else if (io_transaction.iv_mode == ACCESS_MODE_READ) { + io_transaction.iv_data = iv_eccStop; + me = ME_SUCCESS; + + } else if (io_transaction.iv_mode == ACCESS_MODE_WRITE) { + iv_eccStop = io_transaction.iv_data; + me = ME_SUCCESS; + + } else { + BUG(); + me = ME_BUS_SLAVE_PERMISSION_DENIED; + } + break; + + default: + + if ((io_transaction.iv_offset == FASTI2C_CONTROL_OFFSET) && + (io_transaction.iv_mode == ACCESS_MODE_WRITE)) { + + control.value = io_transaction.iv_data; + address = getI2cAddress(control); + if ((address < iv_eccStart) || (address >= iv_eccStop)) { + BUG(); + me = ME_LPC_ILLEGAL_ADDRESS; + + } else { + + handledBySuperclass = true; + rc = FastI2cController::operation(io_transaction); + } + } else { + + handledBySuperclass = true; + rc = FastI2cController::operation(io_transaction); + } + break; + } + if (!handledBySuperclass) { + if (me != 0) { + rc = 1; // \bug Fix this; + } + io_transaction.busError(me); + } + return rc; +} + + + + + + + + + + diff --git a/src/usr/pore/poreve/porevesrc/fasti2c.H b/src/usr/pore/poreve/porevesrc/fasti2c.H new file mode 100644 index 000000000..a21288e94 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/fasti2c.H @@ -0,0 +1,564 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/fasti2c.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_FASTI2C_H +#define __VSBE_FASTI2C_H + +// $Id: fasti2c.H,v 1.5 2011/12/16 20:27:26 bcbrock Exp $ + +/// \file fasti2c.H +/// \brief The "fast-mode" I2C controllers and memory models used +/// to implement the OTPROM, PNOR and SEEPROM interfaces. + +#include <fapi.H> + +#include <stddef.h> +#include <stdint.h> + +#include "bebits.H" +#include "bus.H" + +namespace vsbe { + + class FastI2cController; + class LpcController; + class I2cMemory; + + /// \defgroup fasti2c_speeds Fast-Mode I2C Controller Speeds + /// + /// Note that all speeds are considered "legal", and the model does not + /// interpret the speed setting. + /// + /// @{ + + const int FASTI2C_SPEED_100K = 0; + const int FASTI2C_SPEED_400K = 1; + const int FASTI2C_SPEED_3400K = 2; + const int FASTI2C_SPEED_50K = 3; + + /// @} + + /// \defgroup fasti2c_offsets Fast-Mode I2C Controller Register Offsets (PIB) and limits + /// + /// The last two offsets are only valid on the LpcController model. + /// @{ + + const uint32_t FASTI2C_CONTROL_OFFSET = 0x0; + const uint32_t FASTI2C_RESET_OFFSET = 0x1; + const uint32_t FASTI2C_STATUS_OFFSET = 0x2; + const uint32_t FASTI2C_DATA_OFFSET = 0x3; + const size_t FASTI2C_REGISTERS = 0x4; + + const uint32_t LPCM_ECC_START_OFFSET = 0x4; + const uint32_t LPCM_ECC_STOP_OFFSET = 0x5; + const size_t LPCM_REGISTERS = 0x6; + + /// @} + + /// The maximum memory size supported by the LPC controller (64MB) + const uint32_t LPC_MEMORY_MAX_SIZE = (1 << 26); + + + // These register layouts are copied/modified from the PMX model. If they + // need to be modified here then they will also need to be modified in the + // PMX model. + + /// Fast-Mode I2C Controller Control Register Layout + typedef union { + + uint64_t value; + struct { +#ifdef _BIG_ENDIAN + uint32_t high_order; + uint32_t low_order; +#else + uint32_t low_order; + uint32_t high_order; +#endif // _BIG_ENDIAN + } words; + struct { +#ifdef _BIG_ENDIAN + uint64_t with_start : 1; + uint64_t with_address : 1; + uint64_t read_continue : 1; + uint64_t with_stop : 1; + uint64_t data_length : 4; + uint64_t device_address : 7; + uint64_t read_not_write : 1; + uint64_t speed : 2; + uint64_t port_number : 5; + uint64_t address_range : 3; + uint64_t _reserved0 : 6; + uint64_t data0 : 8; + uint64_t data1 : 8; + uint64_t data2 : 8; + uint64_t data3 : 8; +#else + uint64_t data3 : 8; + uint64_t data2 : 8; + uint64_t data1 : 8; + uint64_t data0 : 8; + uint64_t _reserved0 : 6; + uint64_t address_range : 3; + uint64_t port_number : 5; + uint64_t speed : 2; + uint64_t read_not_write : 1; + uint64_t device_address : 7; + uint64_t data_length : 4; + uint64_t with_stop : 1; + uint64_t read_continue : 1; + uint64_t with_address : 1; + uint64_t with_start : 1; +#endif // _BIG_ENDIAN + } fields; + } FastI2cControlRegister; + + + /// Fast-Mode I2C Controller Reset Register Layout + typedef union { + + uint64_t value; + struct { +#ifdef _BIG_ENDIAN + uint32_t high_order; + uint32_t low_order; +#else + uint32_t low_order; + uint32_t high_order; +#endif // _BIG_ENDIAN + } words; + struct { +#ifdef _BIG_ENDIAN + uint64_t value : 64; +#else + uint64_t value : 64; +#endif // _BIG_ENDIAN + } fields; + } FastI2cResetRegister; + + + /// Fast-Mode I2C Controller Status Register Layout + typedef union { + + uint64_t value; + struct { +#ifdef _BIG_ENDIAN + uint32_t high_order; + uint32_t low_order; +#else + uint32_t low_order; + uint32_t high_order; +#endif // _BIG_ENDIAN + } words; + struct { +#ifdef _BIG_ENDIAN + uint64_t pib_address_invalid : 1; + uint64_t pib_write_invalid : 1; + uint64_t pib_read_invalid : 1; + uint64_t pib_address_parity_error : 1; + uint64_t pib_parity_error : 1; + uint64_t lb_parity_error : 1; + uint64_t read_data : 32; + uint64_t _reserved0 : 6; + uint64_t i2c_macro_busy : 1; + uint64_t i2c_invalid_command : 1; + uint64_t i2c_parity_error : 1; + uint64_t i2c_back_end_overrun_error : 1; + uint64_t i2c_back_end_access_error : 1; + uint64_t i2c_arbitration_lost : 1; + uint64_t i2c_nack_received : 1; + uint64_t i2c_data_request : 1; + uint64_t i2c_command_complete : 1; + uint64_t i2c_stop_error : 1; + uint64_t i2c_port_busy : 1; + uint64_t i2c_interface_busy : 1; + uint64_t i2c_fifo_entry_count : 8; +#else + uint64_t i2c_fifo_entry_count : 8; + uint64_t i2c_interface_busy : 1; + uint64_t i2c_port_busy : 1; + uint64_t i2c_stop_error : 1; + uint64_t i2c_command_complete : 1; + uint64_t i2c_data_request : 1; + uint64_t i2c_nack_received : 1; + uint64_t i2c_arbitration_lost : 1; + uint64_t i2c_back_end_access_error : 1; + uint64_t i2c_back_end_overrun_error : 1; + uint64_t i2c_parity_error : 1; + uint64_t i2c_invalid_command : 1; + uint64_t i2c_macro_busy : 1; + uint64_t _reserved0 : 6; + uint64_t read_data : 32; + uint64_t lb_parity_error : 1; + uint64_t pib_parity_error : 1; + uint64_t pib_address_parity_error : 1; + uint64_t pib_read_invalid : 1; + uint64_t pib_write_invalid : 1; + uint64_t pib_address_invalid : 1; +#endif // _BIG_ENDIAN + } fields; + } FastI2cStatusRegister; + +}; + + +//////////////////////////////////////////////////////////////////////////// +// I2cMemory +//////////////////////////////////////////////////////////////////////////// + + +/// An I2C memory model +/// +/// The I2cMemory is a subclass of the Memory. It adds a device address for +/// mapping onto an I2c bus, and also supports I2C memory operations such as +/// addressWrite() and dataRead(). + +class +vsbe::I2cMemory : public Memory +{ + +public: + + ////////////////////////////// Types ////////////////////////////// + + ////////////////////////////// Creators ////////////////////////////// + + /// Create an I2c Memory + /// + /// \param[in] i_addressBytes The number of bytes (1-4) in a memory + /// address for this memory. + I2cMemory(const size_t i_addressBytes); + + virtual ~I2cMemory(); + + ///////////////////////////// Accessors ////////////////////////////// + + //////////////////////////// Manipulators //////////////////////////// + + /// Perform an I2C address write to an attached device. + /// + /// \param[in] i_bytes The number of address bytes, which must match the + /// configuration. + /// + /// \param[in] i_address The memory address. + /// + /// \retval me ModelError return code + ModelError + addressWrite(const size_t i_bytes, const uint32_t i_address); + + /// Perform an I2C data read from an attached device. + /// + /// \param[in] i_bytes The number of data bytes to read + /// + /// \param[out] o_data The data, right justified + /// + /// The read has a side effect of incrementing the address held in the + /// device by \a i_bytes. + /// + /// \retval me ModelError return code + ModelError + dataRead(const size_t i_bytes, uint64_t& o_data); + + /// Perform an I2C data write to an attached device. + /// + /// \param[in] i_bytes The number of data bytes to write + /// + /// \param[in] i_data The data, right justified + /// + /// The write has a side effect of incrementing the address held in the + /// device by \a i_bytes. + /// + /// \retval me ModelError return code + ModelError + dataWrite(const size_t i_bytes, const uint64_t i_data); + + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The number of address bytes (1-4) + const size_t iv_addressBytes; + + /// The address register, auto-incremented on data reads and writes + uint32_t iv_address; + + ///////////////////////////// Safety ////////////////////////////////// + +private: + I2cMemory(const I2cMemory& i_rhs); + I2cMemory& operator=(const I2cMemory& i_rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// I2cDevice +//////////////////////////////////////////////////////////////////////////// + +namespace vsbe { + +/// A simple I2C device/bus model +/// +/// This simple device/bus model is used by the FastI2cController to model the +/// atachment of multiple I2cMemory to the physical busses (ports) controlled +/// by each controller. Normally only 1 or two devices are attached to each +/// controller so it's easiest to model all devices under control of a +/// controller as a single list. + +typedef struct I2cDevice { + + /// The controller port number - associated with a physical I2C bus + unsigned iv_port; + + /// The device address of the device on the bus + unsigned iv_deviceAddress; + + /// The I2cMemory + I2cMemory* iv_memory; + + /// The next I2cdevice in the list of devices + struct I2cDevice* next; + +} I2cDevice; + +}; + +//////////////////////////////////////////////////////////////////////////// +// FastI2cController +//////////////////////////////////////////////////////////////////////////// + + +/// A model of a "fast-mode" I2C Controller +/// +/// The PORE engine only uses the new "fast-mode" protocol to communicate with +/// "I2C Controllers" that implement the physical memory interfaces for SBE +/// memories. These controllers may be either real I2C controllers (like for +/// SEEPROM) or pseudo-I2C-controllers like the PNOR and OTPROM controllers. +/// The "fast-mode" is a new subset of the full I2C controller interface that +/// only uses 4 registers. This model only models fast-mode accesses, and +/// only in the precise way that PORE engines use fast-mode controllers for +/// memory fetches, loads and stores. It will return errors for use of the +/// legacy mode registers or otherwise legal sequences that are simply not +/// modeled. +/// +/// Each controller manages a number of "ports". Each port is a physical I2C +/// bus, and devices attached to each port (bus) must have unique device IDs. +/// We model the devices attached to a port independently. Each controller +/// maintains a list of I2cDevice mapped to its ports. The underlying +/// devices are currently all of the I2cMemory class. + +class +vsbe::FastI2cController : public PibSlave +{ + +public: + + ////////////////////////////// Types ////////////////////////////// + + /// \enum FastI2cState + /// + /// The state of the controller. Sequences of register operations are + /// only allowed in a prescribed sequence, depending on the state of the + /// controller. The ERROR state represents a bug in the model and is + /// non-recoverable. + enum FastI2cState { + ERROR, + IDLE, + ADDRESS_WRITE_ONGOING, + DATA_READ_ONGOING, + DATA_AVAILABLE, + WRITE_DATA_EXPECTED, + DATA_WRITE_ONGOING + }; + + ////////////////////////////// Creators ////////////////////////////// + + FastI2cController(); + + virtual ~FastI2cController(); + + ///////////////////////////// Accessors ////////////////////////////// + + //////////////////////////// Manipulators //////////////////////////// + + /// Attach a memory model to the controller + /// + /// \param[in] i_memory A configured I2cMemory + /// + /// \param[in] i_port The port (bus) number the memory is attached to + /// + /// \param[in] i_deviceAddress The device ID of the memory device on the bus + /// + /// \retval me Either 0 for success, ME_INVALID_ARGUMENT or + /// ME_AMBIGUOUS_CONFIGURATION. + ModelError + attachMemory(I2cMemory* i_memory, + const unsigned i_port, + const unsigned i_deviceAddress); + + /// Handle a PIB transaction + /// + /// \param[in,out] io_transaction An abstract PIB transaction + /// + /// The FastI2cController is an indirect memory. In general several PIB + /// transactions are required to fetch a single doubleword of code or data + /// from the memory. + /// + /// \retval rc Either an "OK" return code for success, or a code + /// describing the error. + virtual fapi::ReturnCode + operation(Transaction& io_transaction); + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// Find a device in the list of devices attached to this controller + /// + /// \param[in] i_port The port number to search + /// + /// \param[in] i_deviceAddress The device address to search + /// + /// \retval device A pointer to the device if found, otherwise 0. + I2cDevice* findDevice(const unsigned i_port, + const unsigned i_deviceAddress); + + /// Extract the I2C address from the CONTROL register + /// + /// \param[in] i_control The FastI2cControl register + /// + /// \retval address The indirect I2C address, taken from bytes 4-7 of the + /// control register depending on how many address bytes are indicated in + /// the control. + uint32_t getI2cAddress(const FastI2cControlRegister i_control); + + /// Perform an I2C address write to an attached device. + /// + /// \retval me A ModelError return code in the event of errors, otherwise + /// 0. + ModelError addressWrite(); + + /// Perform an I2C data read from an attached device. + /// + /// \retval me A ModelError return code in the event of errors, otherwise + /// 0. + ModelError dataRead(); + + /// Begin an I2C data write an attached device. + /// + /// \retval me A ModelError return code in the event of errors, otherwise + /// 0. + ModelError initialDataWrite(); + + /// Finalize an I2C data write an attached device. + /// + /// \param[in] i_data The final bytes of a data write, left justtified. + /// + /// \retval me A ModelError return code in the event of errors, otherwise + /// 0. + ModelError finalDataWrite(const uint64_t i_data); + + /// A list of I2cDevice, each of which is assigned to a controler port and + /// maintains a unique device ID for that port. + I2cDevice* iv_devices; + + /// The abstract state of the controller + FastI2cState iv_state; + + /// The last value written to the control register + FastI2cControlRegister iv_control; + + /// The last value generated in the status register + FastI2cStatusRegister iv_status; + + /// The data FIFO. Data is left-justified in this register. + uint64_t iv_fifo; + + ///////////////////////////// Safety ////////////////////////////////// + +private: + FastI2cController(const FastI2cController& i_rhs); + FastI2cController& operator=(const FastI2cController& i_rhs); +}; + + + +//////////////////////////////////////////////////////////////////////////// +// LpcController +//////////////////////////////////////////////////////////////////////////// + +/// Simplified model of the LPC controller as a fast-mode I2C controller +/// +/// The LPC controller appears as a pseudo-FastI2cController with a couple of +/// extra specializations. The fast-mode I2C controller specification +/// is extended with two extra registers : The ECC start and stop +/// addresses. We do not model ECC in our model, therefore this model only +/// allows accesses that fall within the ECC window. The SBE will never +/// address outside of the ECC window. + +class +vsbe::LpcController : public FastI2cController +{ + +public: + + ////////////////////////////// Types ////////////////////////////// + + ////////////////////////////// Creators ////////////////////////////// + + LpcController(); + + virtual ~LpcController(); + + ///////////////////////////// Accessors ////////////////////////////// + + //////////////////////////// Manipulators //////////////////////////// + + /// Handle a PIB transaction + /// + /// \param[in,out] io_transaction An abstract PIB transaction + /// + /// The LpcController is an indirect memory. In general several PIB + /// transactions are required to fetch a single doubleword of code or data + /// from the memory. The LpcController passes all transactions through to + /// the underlying FastI2cController except for reads/writes to the ECC + /// control registers. We require that any change to the ECC bounds be + /// made while the controller is in its IDLE state. + /// + /// \retval rc Either an "OK" return code for success, or a code + /// describing the error. + virtual fapi::ReturnCode + operation(Transaction& io_transaction); + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The ECC start address register + uint64_t iv_eccStart; + + /// The ECC stop address register + uint64_t iv_eccStop; +}; + + +#endif // __VSBE_FASTI2C_H diff --git a/src/usr/pore/poreve/porevesrc/hookmanager.C b/src/usr/pore/poreve/porevesrc/hookmanager.C new file mode 100644 index 000000000..bf31e76b1 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/hookmanager.C @@ -0,0 +1,575 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/hookmanager.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: hookmanager.C,v 1.12 2012/01/06 21:25:25 bcbrock Exp $ + +/// \file hookmanager.C +/// \brief A portable symbol table and hook execution facility + +#include <stdio.h> +#include <string.h> + +#include "hookmanager.H" + +using namespace vsbe; + + +#ifndef ULL +/// The printf() checker for 64-bit GCC throws a warning if a uint64_t is +/// printed as %llx - I have no idea why, but by casting them to (unsigned +/// long long) the warning goes away. +#define ULL(x) ((unsigned long long)(x)) +#endif + +fapi::ReturnCode vsbe::hookOk; +HookManager* HookManager::s_instance = 0; + + +//////////////////////////////////////////////////////////////////////////// +// CharPointerComparison +//////////////////////////////////////////////////////////////////////////// + +bool +CharPointerComparison::operator()(char const* i_lhs, + char const* i_rhs) const +{ + return strcmp(i_lhs, i_rhs) < 0; +} + + +//////////////////////////////////////////////////////////////////////////// +// HookManager +//////////////////////////////////////////////////////////////////////////// + +////////////////////////////// Creators ////////////////////////////// + +HookManager::HookManager() : + iv_error(HOOK_OK) +{ +} + + +HookManager::~HookManager() +{ +} + + +///////////////////////////// Accessors ////////////////////////////// + +fapi::ReturnCode +HookManager::runInstructionHook(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter, + Pore& io_pore, + const fapi::Target& i_target) +{ + InstructionHookMap::iterator ihmi; + fapi::ReturnCode rc; + + ihmi = instance()->iv_instructionHookMap.find(i_hook); + if (ihmi == instance()->iv_instructionHookMap.end()) { + rc = 0; + } else { + rc = (ihmi->second)(i_address, i_hook, i_parameter, io_pore, i_target); + } + return rc; +} + + +fapi::ReturnCode +HookManager::runReadHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target) + +{ + return instance()->runHooks(HOOK_READ_INTERACTIVE, HOOK_READ_EXTRACTED, + i_address, io_pore, i_target); +} + + +fapi::ReturnCode +HookManager::runWriteHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target) +{ + return instance()->runHooks(HOOK_WRITE_INTERACTIVE, HOOK_WRITE_EXTRACTED, + i_address, io_pore, i_target); +} + + +fapi::ReturnCode +HookManager::runFetchHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target) +{ + return instance()->runHooks(HOOK_FETCH_INTERACTIVE, HOOK_FETCH_EXTRACTED, + i_address, io_pore, i_target); +} + + +HookError +HookManager::findGlobalSymbol(const char* i_symbol, + bool& o_found, + GlobalSymbolInfo& io_info) +{ + GlobalSymbolMap::iterator gsmi; + + o_found = false; + if (!instance()->iv_error) { + gsmi = instance()->iv_globalSymbolMap.find(i_symbol); + if (gsmi != instance()->iv_globalSymbolMap.end()) { + o_found = true; + io_info = *(gsmi->second); + } + } + return instance()->iv_error; +} + + +HookError +HookManager::globalSymbolList(GlobalSymbolList& io_symbols, const char* i_types) +{ + GlobalSymbolMap::iterator gsmi; + + if (!instance()->iv_error) { + for (gsmi = instance()->iv_globalSymbolMap.begin(); + gsmi != instance()->iv_globalSymbolMap.end(); + gsmi++) { + + if ((i_types == 0) || + (strchr(i_types, gsmi->second->iv_type) != 0)) { + io_symbols.push_back(*gsmi); + } + } + } + return instance()->iv_error; +} + + +void +HookManager::report(const int i_options) +{ + InstructionHookMap::iterator ihmi; + HookedAddressMap::iterator hami; + HookedFileMap::iterator hfmi; + GlobalSymbolMap::iterator gsmi; + Hook* hook; + const HookTable* table; + size_t entry; + char type; + ExtractedHook* exHook; + + if (i_options != 0) { + + FAPI_INF(""); + FAPI_INF("------------------------------------------------------"); + FAPI_INF("-- HookManager @ %p", instance()); + FAPI_INF("------------------------------------------------------"); + + if (i_options & HM_REPORT_HOOKED_ADDRESS_MAP) { + + FAPI_INF(""); + FAPI_INF("--- Hooked Address Map : %zu unique addresses ---", + instance()->iv_hookedAddressMap.size()); + FAPI_INF(""); + + for (hami = instance()->iv_hookedAddressMap.begin(); + hami != instance()->iv_hookedAddressMap.end(); + hami++) { + + for (hook = hami->second; hook != 0; hook = hook->iv_next) { + switch (hook->iv_type) { + + case HOOK_READ_INTERACTIVE: + case HOOK_WRITE_INTERACTIVE: + case HOOK_FETCH_INTERACTIVE: + switch (hook->iv_type) { + case HOOK_READ_INTERACTIVE: type = 'r'; break; + case HOOK_WRITE_INTERACTIVE: type = 'w'; break; + case HOOK_FETCH_INTERACTIVE: type = 'x'; break; + default: type = '?'; break; // For GCC -Wall + } + FAPI_INF("%04x:%08x %c %p", + hami->first.iv_memorySpace, + hami->first.iv_offset, + type, hook->iv_hook); + break; + + case HOOK_READ_EXTRACTED: + case HOOK_WRITE_EXTRACTED: + case HOOK_FETCH_EXTRACTED: + switch (hook->iv_type) { + case HOOK_READ_EXTRACTED: type = 'r'; break; + case HOOK_WRITE_EXTRACTED: type = 'w'; break; + case HOOK_FETCH_EXTRACTED: type = 'x'; break; + default: type = '?'; break; // For GCC -Wall + } + exHook = (ExtractedHook*)(hook->iv_hook); + FAPI_INF("%04x:%08x %8zu %s", + hami->first.iv_memorySpace, hami->first.iv_offset, + exHook->iv_index, exHook->iv_file); + break; + + default: break; // For GCC -Wall + } + } + } + } + + if (i_options & HM_REPORT_HOOK_TABLES) { + + FAPI_INF(""); + FAPI_INF("--- Hook Tables : %zu hooked files---", + instance()->iv_hookedFileMap.size()); + + for (hfmi = instance()->iv_hookedFileMap.begin(); + hfmi != instance()->iv_hookedFileMap.end(); + hfmi++) { + + FAPI_INF(""); + FAPI_INF("%s", hfmi->first); + + table = hfmi->second; + for (entry = 0; entry < table->iv_entries; entry++) { + FAPI_INF("%8zu %p", + entry, table->iv_hooks[entry]); + } + } + } + + if (i_options & HM_REPORT_INSTRUCTION_HOOK_MAP) { + + FAPI_INF(""); + FAPI_INF("--- Instruction Hook Map ---"); + FAPI_INF(""); + + for (ihmi = instance()->iv_instructionHookMap.begin(); + ihmi != instance()->iv_instructionHookMap.end(); + ihmi++) { + + FAPI_INF("%06x %p", + ihmi->first, ihmi->second); + } + } + + if (i_options & HM_REPORT_GLOBAL_SYMBOL_MAP) { + + FAPI_INF(""); + FAPI_INF("--- Global Symbol Map ---"); + FAPI_INF(""); + + for (gsmi = instance()->iv_globalSymbolMap.begin(); + gsmi != instance()->iv_globalSymbolMap.end(); + gsmi++) { + + FAPI_INF("%04x:%08x %c %s", + gsmi->second->iv_address.iv_memorySpace, + gsmi->second->iv_address.iv_offset, + gsmi->second->iv_type, + gsmi->first); + } + } + + FAPI_INF(""); + FAPI_INF("------------------------------------------------------"); + FAPI_INF(""); + } +} + + +//////////////////////////// Manipulators //////////////////////////// + +HookError +HookManager::registerInstructionHook(const uint32_t i_index, + HookInstructionHook i_hookRoutine) +{ + InstructionHookMap::iterator ihmi; + + if (!instance()->iv_error) { + + ihmi = instance()->iv_instructionHookMap.find(i_index); + if (ihmi == instance()->iv_instructionHookMap.end()) { + + instance()->iv_instructionHookMap[i_index] = i_hookRoutine; + + } else { + if (ihmi->second != i_hookRoutine) { + FAPI_ERR("%s : Static hook collision for index : %u", + __FUNCTION__, i_index); + instance()->iv_error = HOOK_STATIC_COLLISION; + } + } + } + return instance()->iv_error; +} + + +HookError +HookManager::registerHookTable(const char* i_file, + const HookTable* i_table) +{ + if (!instance()->iv_error) { + + if (instance()->iv_hookedFileMap.find(i_file) != + instance()->iv_hookedFileMap.end()) { + + FAPI_ERR("%s : File name collision : %s", + __FUNCTION__, i_file); + instance()->iv_error = HOOK_FILE_NAME_COLLISION; + } else { + instance()->iv_hookedFileMap[i_file] = i_table; + } + } + return instance()->iv_error; +} + + +HookError +HookManager::registerHook(const PoreAddress& i_address, + Hook* io_hook) +{ + HookedAddressMap::iterator hami; + Hook* hook; + + if (!instance()->iv_error) { + + hami = instance()->iv_hookedAddressMap.find(i_address); + if (hami != instance()->iv_hookedAddressMap.end()) { + for (hook = hami->second; + hook->iv_next != 0; + hook = hook->iv_next); + hook->iv_next = io_hook; + } else { + instance()->iv_hookedAddressMap[i_address] = io_hook; + } + io_hook->iv_next = 0; + } + return instance()->iv_error; +} + + +HookError +HookManager::registerGlobalSymbol(const char* i_symbol, + const GlobalSymbolInfo* i_info) +{ + if (!instance()->iv_error) { + + if (instance()->iv_globalSymbolMap.find(i_symbol) != + instance()->iv_globalSymbolMap.end()) { + + FAPI_ERR("%s : Multiply defined symbol : %s", + __FUNCTION__, i_symbol); + instance()->iv_error = HOOK_MULTIPLY_DEFINED_SYMBOL; + } else { + instance()->iv_globalSymbolMap[i_symbol] = i_info; + } + } + return instance()->iv_error; +} + + +HookError +HookManager::addInteractiveHook(const PoreAddress& i_address, + const HookType i_type, + const AddressBasedHook i_hookRoutine) +{ + Hook* hook = new Hook(); + HookError rc; + + instance()->iv_error = HOOK_OK; + if (hook == 0) { + rc = HOOK_MEMORY_ALLOCATION_FAILED; + } else { + switch (i_type) { + case HOOK_READ_INTERACTIVE: + case HOOK_WRITE_INTERACTIVE: + case HOOK_FETCH_INTERACTIVE: + rc = HOOK_OK; + hook->iv_type = i_type; + hook->iv_hook = (void*)i_hookRoutine; + registerHook(i_address, hook); + break; + default: + delete hook; + rc = HOOK_ILLEGAL_TYPE; + } + } + instance()->iv_error = rc; + return rc; +} + + +HookError +HookManager::deleteInteractiveHooks(const PoreAddress& i_address, + const HookType i_type, + const AddressBasedHook i_hookRoutine) +{ + HookedAddressMap::iterator hami; + Hook **last, *hook, *next; + HookError rc; + bool deleted = false; + + switch (i_type) { + case HOOK_READ_INTERACTIVE: + case HOOK_WRITE_INTERACTIVE: + case HOOK_FETCH_INTERACTIVE: + + hami = instance()->iv_hookedAddressMap.find(i_address); + if (hami != instance()->iv_hookedAddressMap.end()) { + for (last = &(hami->second), hook = hami->second; + hook != 0; + hook = next) { + next = hook->iv_next; + if ((hook->iv_type == i_type) && + ((i_hookRoutine == 0) || + (hook->iv_hook) == i_hookRoutine)) { + delete hook; + deleted = true; + *last = next; + } else { + last = &(hook->iv_next); + } + } + } + if ((i_hookRoutine == 0) || deleted) { + if (hami->second == 0) { + instance()->iv_hookedAddressMap.erase(hami); + } + rc = HOOK_OK; + } else { + rc = HOOK_INTERACTIVE_DELETE_FAILED; + } + break; + + default: + rc = HOOK_ILLEGAL_TYPE; + } + instance()->iv_error = rc; + return rc; +} + + +void +HookManager::clearError() +{ + instance()->iv_error = HOOK_OK; +} + + +////////////////////////// Implementation //////////////////////////// + +fapi::ReturnCode +HookManager::runHooks(const HookType i_interactiveType, + const HookType i_extractedType, + const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target) +{ + HookedAddressMap::iterator hami; + Hook* hook; + ExtractedHook *exHook; + HookedFileMap::iterator hfmi; + const HookTable* table; + fapi::ReturnCode rc; + + hami = instance()->iv_hookedAddressMap.find(i_address); + if (hami != instance()->iv_hookedAddressMap.end()) { + + for (hook = hami->second; + (hook != 0) && rc.ok(); + hook = hook->iv_next) { + + if (hook->iv_type == i_interactiveType) { + + rc = ((AddressBasedHook)(hook->iv_hook))(i_address, + i_interactiveType, + io_pore, + i_target); + + } else if (hook->iv_type == i_extractedType) { + + exHook = (ExtractedHook*)(hook->iv_hook); + hfmi = instance()->iv_hookedFileMap.find(exHook->iv_file); + if (hfmi == instance()->iv_hookedFileMap.end()) { + + FAPI_ERR("%s : Address %04x:%08x is hooked from " + "file '%s', but no HookTable can be found " + "for the file.", + __FUNCTION__, + i_address.iv_memorySpace, + i_address.iv_offset, + exHook->iv_file); + instance()->iv_error = HOOK_TABLE_MISSING; + rc = 1; /// \todo Define this error + + } else { + + table = hfmi->second; + if (exHook->iv_index > table->iv_entries) { + + FAPI_ERR("%s : Address %04x:%08x is hooked from " + "file '%s' at index %zu, " + "but the index exceeds " + "the number of hooks indexed for the " + "file (%zu).", + __FUNCTION__, + i_address.iv_memorySpace, + i_address.iv_offset, + hfmi->first, exHook->iv_index, + table->iv_entries); + instance()->iv_error = HOOK_INDEX_FAILURE; + rc = 1; /// \todo Define this error + + } else { + + rc = + (table->iv_hooks[exHook->iv_index]) + (i_address, i_extractedType, io_pore, i_target); + } + } + } else { + + FAPI_ERR("%s : Bug in HookManager - Unexpected type", + __FUNCTION__); + instance()->iv_error = HOOK_BUG; + rc = 1; /// \todo Define this error + } + if (!rc.ok()) break; + } + } + return rc; +} + + +//////////////////////////////////////////////////////////////////////////// +// HookInitializer +//////////////////////////////////////////////////////////////////////////// + +HookInitializer::HookInitializer(HookManagerInitializer i_function) +{ + i_function(); +} + + +HookInitializer::~HookInitializer() +{ +} diff --git a/src/usr/pore/poreve/porevesrc/hookmanager.H b/src/usr/pore/poreve/porevesrc/hookmanager.H new file mode 100644 index 000000000..5323392c9 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/hookmanager.H @@ -0,0 +1,859 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/hookmanager.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_HOOKMANAGER_H +#define __VSBE_HOOKMANAGER_H + +// $Id: hookmanager.H,v 1.16 2012/01/06 21:25:25 bcbrock Exp $ + +/// \file hookmanager.H +/// \brief A portable symbol table and hook execution facility +/// +/// Although the concept of a HookManager is generic, this implementation is +/// specific to the FAPI PoreVe environment. +/// +/// A hook is a C/C++ subroutine called during execution of the PoreVe. A +/// hook is either associated with a HOOKI instruction, or with a particular +/// PORE effective address. Address-based hooks are either read, write or +/// fetch hooks, and may have either been installed interactively (e.g., by a +/// debugger or hand-written code) or extracted from a source file. We make a +/// distinction because extracted hooks are indexed via static tables created +/// by processing an assembler source file, whereas interactive hooks are +/// inserted individually. Extracted hooks are assumed to be characterized by +/// permanent static data structures and can not be deleted. Interactive +/// hooks can be created and deleted at will. +/// +/// \todo Once the HBI use of the HookManager is finalized, it may be +/// necessary to split this into 2 classes, one for HBI and another for Cronus +/// verisons of PoreVe. +/// +/// \todo Figure out if there is a way to make this more generic without having +/// to use a template. + +#include <stdarg.h> +#include <stdint.h> + +#include <list> +#include <map> +#include <utility> + +#include <fapi.H> + +#include "poremodel.H" + +namespace vsbe { + + struct HookTable; + struct ExtractedHook; + struct Hook; + struct GlobalSymbolInfo; + class HookManager; + class HookInitializer; + class PoreAddress; + class PoreAddressComparison; + class CharPointerComparison; + class Pore; + + /// An "OK" return code for use by hook routines + extern fapi::ReturnCode hookOk; + + /// \enum HookType + /// + /// The type of a hook. See the comments for the file hookmanager.H. + enum HookType { + HOOK_INSTRUCTION, + HOOK_READ_INTERACTIVE, + HOOK_WRITE_INTERACTIVE, + HOOK_FETCH_INTERACTIVE, + HOOK_READ_EXTRACTED, + HOOK_WRITE_EXTRACTED, + HOOK_FETCH_EXTRACTED + }; + + /// The type of a HOOK instruction hook + /// + /// \param[in] i_address The effective address of the HOOK instruction + /// + /// \param[in] i_hook The low-order 24 bits of the HOOK instruction + /// + /// \param[in] i_Parameter A 64-bit parameter for the hook + /// + /// \param[in,out] io_pore The Pore model, to allow the hook to examine or + /// modify the state of the PORE. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + typedef fapi::ReturnCode + (*HookInstructionHook)(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter, + Pore& io_pore, + const fapi::Target& i_target); + + /// The type of an address-based hook + /// + /// \param[in] i_address The effective address associated with the hook + /// + /// \param[in] i_type The type of the address-based hook + /// + /// \param[in,out] io_pore A reference to the Pore model, to allow the + /// hook to examine or modify the state of the PORE. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + typedef fapi::ReturnCode + (*AddressBasedHook)(const PoreAddress& i_address, + const HookType i_type, + Pore& io_pore, + const fapi::Target& i_target); + + /// \enum HookError + /// + /// These error conditions are recognized both while the hook manager is + /// being initialized, and at run time. The last error code generated is + /// stored in the iv_error field of the HookManager. + enum HookError { + HOOK_OK = 0, + /// File name collision between hooked files + HOOK_FILE_NAME_COLLISION = 1, + /// Multiply defined symbol + HOOK_MULTIPLY_DEFINED_SYMBOL = 2, + /// A HookTable for a file is missing, suggesting hooks are out of + /// sync with the hooked sources + HOOK_TABLE_MISSING = 3, + /// Hook index too large, suggesting hooks are out of sync with the + /// hooked sources + HOOK_INDEX_FAILURE = 4, + /// An attempt was made to map more than one hook to a static hook + /// index. + HOOK_STATIC_COLLISION = 5, + /// Deprecated: An instruction hook was called for but not found + HOOK_INSTRUCTION_NOT_FOUND = 6, + /// An illegal HookType was specified for an API + HOOK_ILLEGAL_TYPE = 7, + /// Memory allocation failure for a new interactive hook + HOOK_MEMORY_ALLOCATION_FAILED = 8, + /// A request to delete a specific interactive hook failed + HOOK_INTERACTIVE_DELETE_FAILED = 9, + /// There is a bug in the HookManager + HOOK_BUG = 10, + }; + + /// \defgroup hookmanager_report_options HookManager Report Options + /// + /// By default, the HookManager::report() method prints all elements of + /// the report. An OR-combination of these flags can also be supplied as + /// the argument to explicitly specify that individual sections of the + /// report be printed. + /// + /// @{ + + /// Print the hooked address map + const int HM_REPORT_HOOKED_ADDRESS_MAP = 0x1; + + /// Print the hook tables + const int HM_REPORT_HOOK_TABLES = 0x2; + + /// Print the instruction hook map + const int HM_REPORT_INSTRUCTION_HOOK_MAP = 0x4; + + /// Print the global symbol map + const int HM_REPORT_GLOBAL_SYMBOL_MAP = 0x8; + + /// @} +}; + + +//////////////////////////////////////////////////////////////////////////// +// HookTable +//////////////////////////////////////////////////////////////////////////// + +/// A table of AddressBasedHook function pointers associated with a source +/// file. +/// +/// These structures are created by the \e hook_extractor script as it +/// processes the input to the assembler. Therefore the size of the \a +/// iv_hooks table is constant and known at compile time. To save space the +/// name of the file is not included here - instead the file name is the map +/// key. + +struct +vsbe::HookTable { + + /// The number of hooks defined for the file + size_t iv_entries; + + /// The table of addresses of the hook routines + AddressBasedHook *iv_hooks; +}; + + +//////////////////////////////////////////////////////////////////////////// +// ExtractedHook +//////////////////////////////////////////////////////////////////////////// + +/// An index record for a hook extracted from a source file + +struct +vsbe::ExtractedHook { + + /// The file name of the hooked source file + const char* iv_file; + + /// The index of the hook within the file + size_t iv_index; +}; + + +//////////////////////////////////////////////////////////////////////////// +// Hook +//////////////////////////////////////////////////////////////////////////// + +/// A reference to a hook associated with a particular PORE address +/// +/// The hook architecture allows multiple hooks to be associated with a single +/// address. This situation could arise both by design and also by accident +/// depending for example on conditional compilation or macro expansion. To +/// support all of read, write and fetch hooks as well as static +/// initialization of extracted hooks, this structure holds a generic hook +/// pointer and a \a type field that indicates whether to interpret the +/// pointer as a pointer to an ExtractedHook, or a direct pointer to an +/// AddressBasedHook. + +struct +vsbe::Hook { + + /// The type of hook; See the enumeration HookType + HookType iv_type; + + /// Either an AddressBasedHook or a pointer to an ExtractedHook, depending + /// on the HookType + void* iv_hook; + + /// List linkage + struct Hook* iv_next; +}; + + +//////////////////////////////////////////////////////////////////////////// +// GlobalSymbolInfo +//////////////////////////////////////////////////////////////////////////// + +/// Global Symbol Information +/// +/// Global symbols are mapped by name. This structure includes the symbol +/// address as a PoreAddress plus type information. + +struct +vsbe::GlobalSymbolInfo { + + /// The symbol address + PoreAddress iv_address; + + /// The symbol type + /// + /// Symbol types are the character codes reported by \e nm: + /// + /// - \c B Global BSS (uninitialized data) + /// - \c C Global common (uninitialized data) + /// - \c D Global initialized data + /// - \c T Global text (code) + /// - \c R Global read only data + char iv_type; +}; + + +namespace vsbe { + /// An STL list of <const char *, const GlobalSymbolInfo*> pairs + /// + /// This structure is defined for use in calls to + /// HookManager::globalSymbolList(). + typedef std::list< std::pair<const char*, const GlobalSymbolInfo*> > + GlobalSymbolList; +} + + +//////////////////////////////////////////////////////////////////////////// +// PoreAddressComparison +//////////////////////////////////////////////////////////////////////////// + +/// PoreAddress comparison class +/// +/// This class defines the comparison operator for STL containers using a +/// PoreAddress as the key. + +//////////////////////////////////////////////////////////////////////////// +// CharPointerComparison +//////////////////////////////////////////////////////////////////////////// + +/// char* comparison class +/// +/// This class defines the comparison operator for STL containers using a +/// char* as the key. + +class +vsbe::CharPointerComparison { + +public: + + CharPointerComparison() {} + + ~CharPointerComparison() {} + + /// Compare CharPointer* + /// + /// \param[in] i_lhs Left hand side object + /// + /// \param[in] i_rhs Right hand side object + /// + /// \retval rc This is a simply strcmp(ilhs, irhs) < 0 + bool operator() (char const* i_lhs, + char const* i_rhs) const; + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + // STL requires a copy operator + CharPointerComparison& operator=(const CharPointerComparison& rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// HookManager +//////////////////////////////////////////////////////////////////////////// + +/// A singleton class for managing code hooks for PORE VE +/// +/// The hook manager is a portable C++ implementation of a symbol table for +/// hook functions, hooked instructions and global symbols. Only one +/// HookManager exists at any time. All methods are static and internally +/// reference a singleton instance of a HookManager. The HookManager supports +/// two main types of hooks: +/// +/// - Pre-defined hooks associated with the PORE HOOKI instruction. The HOOKI +/// instruction encodes an unsigned integer index of a hook routine to execute +/// at that point, and also includes an uninterpreted 64-bit parameter. The +/// mapping of hook indices to hook routines will likely be done +/// statically. The HOOK instruction is otherwise a NOP. +/// +/// - Address-based hooks are hooks that are attached to data loads and stores +/// or instruction fetches. These hooks are normally attached by a scripting +/// discipline that processes the input of the assembler to extract the hooks +/// into a separate build and load path. Debugging environments can also add +/// and delete hooks at run time. +/// +/// The symbol table architecure and layout were designed to simplify the +/// mapping and reduce space for the case that hooks are required during a +/// space-constrained HBI procedure. Most symbol table data are defined as +/// constants in the shared objects that initialize the hooks, and should +/// never need to be copied. +/// +/// The HookManager maintains 4 maps: +/// +/// - A map that maps predefined hook indices encoded in HOOKI instructions to +/// the routines that implement the hook. This map is created by calls of +/// registerInstructionHook(). +/// +/// - A map that maps a source file name to a HookTable, that is table of +/// function pointers to the routines that implement the hooks. This map is +/// created by calls of registerHookTable(). +/// +/// - A map that maps a 48-bit \e effective PORE address to a list of Hook +/// objects that identify the hook(s) associated with a PORE address. This map +/// is created by calls of registerHook(). +/// +/// - A map that maps a PORE global symbol name to a pair <address, type>. +/// This map is created by calls of registerGlobalSymbol(). + +class +vsbe::HookManager { + +public: + + ////////////////////////////// Types ////////////////////////////// + + /// A map of HOOKI instruction indices to a HookInstructionHook + /// + /// This map is created by calls of registerInstructionHook(). The + /// application that provides the semantics of each HOOKI instruction + /// index will make these calls. The map is used by the + /// runInstructionHook() API to locate the entry point associated with a + /// HOOKI index. + typedef std::map<uint32_t, HookInstructionHook> InstructionHookMap; + + /// A map of file names to hook routine tables + /// + /// This mapping is created by the *.hook.cc file that is generated by the + /// hook_extractor script for each file of assembler source code. Each + /// one of the *.hook.cc files maps the source code file name to a table + /// of entry points of the hooks extracted from that file. The + /// hook_indexer script references these tables to map hooked PORE + /// addresses to the entry point that implements the hook. + typedef std::map<const char*, const HookTable*> HookedFileMap; + + /// A map of PORE addresses to lists of hooks + /// + /// This map is created by the registerHook() API. For extracted hooks, + /// these calls are made from the *.hooks.cc file created by the + /// hook_indexer from the symbol table of the final link image. The + /// registerHook() API can also be called dynamically by advanced + /// applications like the PDBG debugger for PORE programs. This map is + /// referenced by the runHooks() API. + /// + /// \note The comparison operator being used here is '<' on the uint64_t + /// form of the PoreAddress. + typedef std::map<const PoreAddress, Hook*> HookedAddressMap; + + /// A map of global symbol names to their parameters + /// + /// This map is created by calls of registerGlobalSymbol(), called from + /// the *.hooks.cc file created by the hook_indexer script. This mapping + /// allows the allows the application to find global symbol addresses + /// using the findGlobalSymbol() API. + typedef std::map<const char*, const GlobalSymbolInfo*, + CharPointerComparison> GlobalSymbolMap; + + ////////////////////////////// Creators ////////////////////////////// + + virtual ~HookManager(); + + ///////////////////////////// Accessors ////////////////////////////// + + /// Access the singleton instance + /// + /// This is a standard design pattern: If the static singleton instance of + /// the class already exists, return it. Otherwise create it first. + static HookManager* instance() { + if (s_instance == 0) { + s_instance = new HookManager(); + } + return s_instance; + } + + /// Run a hook assigned to a HOOKI instruction encoding + /// + /// \param[in] i_address The effective address of the HOOKI instruction. + /// + /// \param[in] i_hook The index of the hook to run, taken from the + /// low-order 24 bits of the HOOKI instruction. + /// + /// \param[in] i_parameter A 64-bit parameter for the hook. + /// + /// \param[in,out] io_pore A reference to the Pore object, to allow hooks + /// to examine or alter the PORE state. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// \retval rc If there is a hook routine associated with the hook index + /// \a i_hook, then this is the FAPI return code returned by the hook, + /// otherwise an "ok" (0) FAPI return code. There is no requirememt that + /// a hook routine be present in the Hookmanager for any instruction hook + /// index. + static fapi::ReturnCode + runInstructionHook(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter, + Pore& io_pore, + const fapi::Target& i_target); + + /// Run any hooks associated with a data read of an effective address + /// + /// \param[in] i_address The effective address of the data read + /// + /// \param[in,out] io_pore A reference to the Pore object, to allow hooks + /// to examine or alter the PORE state. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// If supported by the environment this method will be called before + /// every data read to run any hooks associated with reading the address. + /// + /// \retval rc The FAPI return code returned by the first (if any) + /// hook routine to return a non-OK code, otherwise an OK return code. + static fapi::ReturnCode + runReadHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target); + + /// Run any hooks associated with a data write of an effective address + /// + /// \param[in] i_address The effective address of the data write + /// + /// \param[in,out] io_pore A pointer to the Pore object, to allow hooks to + /// examine or alter the PORE state. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// \retval rc The FAPI return code returned by the first (if any) + /// hook routine to return a non-OK code, otherwise an OK return code. + static fapi::ReturnCode + runWriteHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target); + + /// Run any hooks associated with an instruction fetch of an effective + /// address + /// + /// \param[in] i_address The effective address of the instruction fetch + /// + /// \param[in,out] io_pore A pointer to the Pore object, to allow hooks to + /// examine or alter the PORE state. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// If supported by the environment this method will be called before + /// every instruction fetch to run any hooks associated with executing the + /// address. + /// + /// \retval rc The FAPI return code returned by the first (if any) + /// hook routine to return a non-OK code, otherwise an OK return code. + static fapi::ReturnCode + runFetchHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target); + + /// Find a global symbol in the HookManager symbol table + /// + /// \param[in] i_symbol The global symbol name to search for + /// + /// \param[out] o_found Indicates whether the symbol was found + /// + /// \param[in,out] io_info If the symbol is was found, this + /// reference is modified to contain the symbol information, otherwise the + /// reference is not modified. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set at entry. To clear the + /// error status use clearError(). + static HookError + findGlobalSymbol(const char* i_symbol, + bool& o_found, + GlobalSymbolInfo& io_info); + + /// Update a list of GlobalSymbolInfo based on the current state + /// + /// \param[in,out] io_symbols This is a reference to an instance of + /// GlobalSymbolList, an STL list of <const char*, const GlobalSymbolInfo*> + /// pairs. + /// + /// \param[in] i_types This optional parameter is a 0-terminated character + /// string containing 0 or more character codes of symbol types. Only + /// symbols whose type code is an element of the string are appended to \a + /// io_symbols. If \a i_types is 0 (or defaulted) then all global symbols + /// are returned. It probably doesn't make sense to call + /// globalSymbolList() with \a i_types as "" since this call would have no + /// effect. + /// + /// This routine takes a reference to a GlobalSymbolList, and operates by + /// appending (using the STL list push_back() method) a pair consisting of + /// the symbol name string and a pointer to a GlobalSymbolInfo structure + /// for each global symbol currently stored in the Global Symbol Table + /// that matches the symbol type filter. Type filtering is described with + /// the \a i_types argument. Global symbols are appended to \a io_symbols + /// in the lexicographic order defined by strcmp() < 0 on the character + /// string symbol names (i.e., they come back sorted by name). + /// + /// globalSymbolList() only appends to the list passed as the \a + /// io_symbols reference. Use the STL list clear() method to clear the + /// list if necessary prior to calling globalSymbolList(). + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set at entry. To clear the + /// error status use clearError(). + static HookError + globalSymbolList(GlobalSymbolList& io_symbols, const char* i_types = 0); + + /// Report the HookManager state to the FAPI_INF() stream + /// + /// \param[in] i_options Options are selected as an OR-combination of the + /// options documented as \ref hookmanager_report_options. By default all + /// elements of the report are printed. + /// + /// \retval 0 Success + static void + report(const int i_options = -1); + + //////////////////////////// Manipulators //////////////////////////// + + /// Register a HOOKI instruction hook with the HookManager + /// + /// \param[in] i_index The hook index as it will be stored in the HOOKI + /// instruction. + /// + /// \param[in] i_hookRoutine The hook routine + /// + /// It is considered an immediate fatal error (HOOK_STATIC_COLLISION) if + /// an attempt is made to map a single index to different hooks. Although + /// the HookManager could be easily modified to support multiple static + /// hooks for a single index if required, the current thinking is that + /// this more likely represents an error in assigning hook indices rather + /// than a useful feature. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set. To clear the error + /// status use clearError(). + static HookError + registerInstructionHook(const uint32_t i_index, + HookInstructionHook i_hookRoutine); + + /// Register a hook table with the hook manager + /// + /// \param[in] i_file The file name associated with the HookTable. This + /// string is assumed to be a permanent static allocation and is not + /// copied or storage managed by the HookManager. + /// + /// \param[in] i_table A pointer to a HookTable structure. This structure + /// is assumed to be a permanent static allocation and is not copied or + /// storage managed by the HookManager. + /// + /// The table is mapped by the hook manager based on the file name stored + /// in the table. It is considered an immediate fatal error + /// (HOOK_FILE_NAME_COLLISION) if a file name collision is detected. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set. To clear the error + /// status use clearError(). + static HookError + registerHookTable(const char* i_file, + const HookTable* i_table); + + /// Register an extracted Hook structure with the hook manager + /// + /// \param[in] i_address The effective address of a hooked + /// instruction. + /// + /// \param[in,out] io_hook An initialized Hook structure. + /// + /// This method is used directly by code generated from an extraction + /// script to install a hook for an address, due to the fact that + /// extracted hooks are initialized from preconstructed static objects. + /// This is also used as an internal method by addInteractiveHook(). + /// + /// If more than one hook is associated with an address, later hooks are + /// added at the end of the list of hooks. When the hooks are run they + /// are run in list order. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set. To clear the error + /// status use clearError(). + static HookError + registerHook(const PoreAddress& i_address, + Hook* io_hook); + + /// Register a global symbol with the hook manager + /// + /// \param[in] i_symbol The symbol name. This string is assumed to be a + /// permanent static allocation and is not copied or storage managed by + /// the HookManager. + /// + /// \param[in] i_info Information about the symbol. This structure is + /// assumed to be a permanent static allocation and is not copied or + /// storage managed by the HookManager. + /// + /// For simplicity, it is considered an immediate fatal error + /// (HOOK_MULTIPLY_DEFINED_SYMBOL) to hook a symbol more than once. If we + /// need to provide similarly-named symbols in different address spaces + /// then we'll need to revisit the implementation. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set. To clear the error + /// status use clearError(). + static HookError + registerGlobalSymbol(const char* i_symbol, + const GlobalSymbolInfo* i_info); + + /// Add an interactive hook to a PoreAddress + /// + /// \param[in] i_address The effective address of the hooked + /// instruction or data. + /// + /// \param[in] i_type The hook type, which must be one of the *INTERACTIVE + /// types. + /// + /// \param[in] i_hookRoutine The AddressBasedHook that implements the hook. + /// + /// Create and install an interactive hook of \a i_type for an effective + /// PORE address. If more than one hook is associated with an address, + /// later hooks are added at the end of the list of hooks. When the hooks + /// are run they are run in list order. + /// + /// \retval rc A non-zero return value indicates any error that occurred. + /// This method fails immediately if HookManager error status is set at + /// entry. To clear the error status use clearError(). + static HookError + addInteractiveHook(const PoreAddress& i_address, + const HookType i_type, + const AddressBasedHook i_hookRoutine); + + /// Delete interactive hooks of a given type from a PoreAddress + /// + /// \param[in] i_address The effective address of the hooked + /// instruction or data. + /// + /// \param[in] i_type The hook type, which must be one of the *INTERACTIVE + /// types. + /// + /// \param[in] i_hookRoutine The AddressBasedHook that implements the + /// hook, or a default value of 0 which means to delete all interactive + /// hooks of the given type from the address. + /// + /// By default, delete all interactive hooks of \a i_type from an + /// effective PORE address. If \a i_hook is not 0, then all occurrences + /// of only that particular hook are deleted. + /// + /// \retval rc A non-zero return value indicates any error that occurred. + /// This method fails immediately if HookManager error status is set at + /// entry. To clear the error status use clearError(). + static HookError + deleteInteractiveHooks(const PoreAddress& i_address, + const HookType i_type, + const AddressBasedHook i_hookRoutine = 0); + + /// Clear the HookManager error status + /// + /// The HookManager has 'sticky' error status - new operations on the + /// HookManager will fail if the error status is non-zero. This method + /// clears the error status. + static void + clearError(); + + ////////////////////////// Implementation //////////////////////////// + + /// The last HookError encountered + /// + /// Many of the HookError conditions arise during load-time + /// initialization, when there's really no recourse for trapping or + /// handling them. Instead, if the iv_error is non-0 then all load-time + /// HookManager APIs return immediately, allowing some diagnosis (of the + /// first error) after initialization. The interactive methods set and + /// return \a iv_error with the final return code but do not block further + /// operations. + HookError iv_error; + + // NB: s_instance must be public for the Simics workaround + + /// The singleton instance of the HookManager + static HookManager* s_instance; + +protected: + + /// The instruction hook map + InstructionHookMap iv_instructionHookMap; + + /// The hooked file map + HookedFileMap iv_hookedFileMap; + + /// The hooked address map + /// + /// The HookManager system maintains an invariant that if an entry in this + /// map exists, then the list of hooks associated with that address is not + /// empty (i.e., the pointer is not 0). + HookedAddressMap iv_hookedAddressMap; + + /// The global symbol map + GlobalSymbolMap iv_globalSymbolMap; + + /// Run a specific type of hook + /// + /// \param[in] i_interactiveType One of the *INTERACTIVE HookType. + /// + /// \param[in] i_extractedType The *EXTRACTED counterpart of the + /// interactive type. + /// + /// \param[in] i_address The current effective address. + /// + /// \param[in,out] io_pore The Pore model, to allow the hook to examine or + /// modify the state of the PORE. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// This is a helper method for runReadHooks(), runWriteHooks() and + /// runFetchHooks() that actually does the search and execution, given an + /// interactive and extracted hook type to search. + /// + /// \retval rc The FAPI return code returned by the first (if any) + /// hook routine to return a non-OK code, otherwise an OK return code. + fapi::ReturnCode + runHooks(const HookType i_interactiveType, + const HookType i_extractedType, + const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target); + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + HookManager(); + HookManager(const HookManager& i_rhs); + HookManager& operator=(const HookManager& i_rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// HookInitializer +//////////////////////////////////////////////////////////////////////////// + +/// A dummy class used to initialize the HookManager +/// +/// Initialization of the HookManager depends on the ability of C++ to run +/// object constructors at load time. Each hook file and indexing file +/// contains an initialization function that installs information into the +/// symbol table. Each hook file also creates an instance of the +/// HookInitializer whose sole purpose is to run the initialization function +/// in its constructor at load time. + +class +vsbe::HookInitializer { + +public: + + ////////////////////////////// Types ////////////////////////////// + + /// The type of a HookManager initializer function + typedef void (*HookManagerInitializer)(); + + ////////////////////////////// Creators ////////////////////////////// + + /// Create an HookInitializer + /// + /// \param[in] i_function The function to call during construction of the + /// otherwise empty object. + HookInitializer(HookManagerInitializer i_function); + + ~HookInitializer(); + + ///////////////////////////// Safety ////////////////////////////////// + +private: + HookInitializer(const HookInitializer& rhs); + HookInitializer& operator=(const HookInitializer& rhs); +}; + + +#endif // __VSBE_HOOKMANAGER_H diff --git a/src/usr/pore/poreve/porevesrc/pib2cfam.C b/src/usr/pore/poreve/porevesrc/pib2cfam.C new file mode 100644 index 000000000..cf6100767 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/pib2cfam.C @@ -0,0 +1,167 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/pib2cfam.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// -*- mode: C++; c-file-style: "linux"; -*- +// $Id: pib2cfam.C,v 1.9 2012/01/09 21:22:50 jeshua Exp $ + +/// \file pib2cfam.C +/// \brief A temporary hack while waiting for hardware updates - a simple +/// PibSlave that maps a small range of PIB addresses to CFAM addresses. +/// +/// \todo Verify the assumption that the high-order 32 bits of the 64-bit data +/// are the bits that are read and written to the CFAM register. + +#include "pib2cfam.H" +//JDS TODO - remove the ECMD headers once we've got attribute support +#ifndef __HOSTBOOT_MODULE +#include "fapiSharedUtils.H" +#include "ecmdUtils.H" +#endif +using namespace vsbe; + + +////////////////////////////// Creators ////////////////////////////// + +Pib2Cfam::Pib2Cfam() +{ +} + + +Pib2Cfam::~Pib2Cfam() +{ +} + + +//////////////////////////// Manipulators //////////////////////////// + +static uint32_t +translateAddress(uint32_t address, fapi::Target* i_target) +{ + //JDS TODO - change this to get attribute ATTR_FSI_GP_REG_SCOM_ACCESS + bool fsi_gpreg_scom_access = false; +#ifndef __HOSTBOOT_MODULE + ecmdChipData chipdata; + ecmdChipTarget e_target; + uint32_t rc; + std::string chip_type; + + fapiTargetToEcmdTarget( *i_target, e_target); + rc = ecmdGetChipData(e_target, chipdata); + if( rc ) printf( "Problem with getchipdata\n" ); + chip_type = chipdata.chipType; + + if( chip_type == "centaur" ) { + fsi_gpreg_scom_access = false; + } else { + fsi_gpreg_scom_access = true; + } +#endif + + if( fsi_gpreg_scom_access ) { + return (address - 0x00050000) + 0x2800; + } else { + return (address - 0x00050000) + 0x1000; + } +} + + +fapi::ReturnCode +Pib2Cfam::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + ModelError me; + + switch (io_transaction.iv_mode) { + + case ACCESS_MODE_READ: + + switch (io_transaction.iv_address) { + + case 0x00050012: + case 0x00050013: + case 0x00050014: + case 0x00050015: + case 0x00050016: + case 0x00050019: + case 0x0005001A: + case 0x0005001B: + rc = fapiGetCfamRegister(*iv_target, + translateAddress(io_transaction.iv_address, iv_target), + *iv_dataBuffer); + if (rc.ok()) { + io_transaction.iv_data = + ((uint64_t)iv_dataBuffer->getWord(0)) << 32; + me = ME_SUCCESS; + } else { + me = ME_FAILURE; + } + break; + default: + me = ME_NOT_MAPPED_IN_MEMORY; + } + break; + + case ACCESS_MODE_WRITE: + + switch (io_transaction.iv_address) { + + case 0x00050012: + case 0x00050013: + case 0x00050014: + case 0x00050015: + case 0x00050016: + case 0x0005001B: + iv_dataBuffer->setWordLength(1); + iv_dataBuffer->setWord(0, io_transaction.iv_data >> 32); + rc = fapiPutCfamRegister(*iv_target, + translateAddress(io_transaction.iv_address, iv_target), + *iv_dataBuffer); + if (rc.ok()) { + me = ME_SUCCESS; + } else { + me = ME_FAILURE; + } + break; + + case 0x00050019: + case 0x0005001A: + rc = 1; + me = ME_BUS_SLAVE_PERMISSION_DENIED; + break; + + default: + rc = 1; + me = ME_NOT_MAPPED_IN_MEMORY; + } + break; + + default: + rc = 1; + me = ME_BUS_SLAVE_PERMISSION_DENIED; + break; + } + io_transaction.busError(me); + return rc; +} +/* Local Variables: */ +/* c-basic-offset: 4 */ +/* End: */ diff --git a/src/usr/pore/poreve/porevesrc/pib2cfam.H b/src/usr/pore/poreve/porevesrc/pib2cfam.H new file mode 100644 index 000000000..329d3f0a3 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/pib2cfam.H @@ -0,0 +1,94 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/pib2cfam.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_PIB2CFAM_H +#define __VSBE_PIB2CFAM_H + +// $Id: pib2cfam.H,v 1.3 2011/06/21 00:07:35 bcbrock Exp $ + +/// \file pib2cfam.H +/// \brief A temporary hack while waiting for hardware updates - a simple +/// PibSlave that maps a small range of PIB addresses to CFAM addresses. + +#include "bus.H" + +namespace vsbe { + + class Pib2Cfam; + + /// PIB base address of PIB range mapped by Pib2Cfam + const uint32_t PIB2CFAM_PIB_BASE = 0x00050012; + + /// Number of PIB addresses mapped by Pib2Cfam + const int PIB2CFAM_PIB_SIZE = ((0x0005001b - 0x00050012) + 1); +} + + +/// Map PIB accesses to CFAM accesses + +class +vsbe::Pib2Cfam : public PibSlave { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + Pib2Cfam(); + + virtual ~Pib2Cfam(); + + + //////////////////////////// Manipulators //////////////////////////// + + /// Pib2Cfam operation + /// + /// \param[in,out] io_transaction A PIB transaction object + /// + /// This object converts PIB transactions in a certain range in the + /// virtual environment to FAPI PutCfamregister() and GetCfamRegister() + /// calls, returning the FAPI return code from the translated calls. + /// + /// The following PIB registers are mapped to CFAM registers: + /// + /// - PIB 0x00050012 -> CFAM 0x1012, FSIGP3, R/W + /// - PIB 0x00050013 -> CFAM 0x1013, FSIGP4, R/W + /// - PIB 0x00050014 -> CFAM 0x1014, FSIGP5, R/W + /// - PIB 0x00050015 -> CFAM 0x1015, FSIGP6, R/W + /// - PIB 0x00050016 -> CFAM 0x1016, FSIGP7, R/W + /// - PIB 0x00050019 -> CFAM 0x1019, OSC switch sense 1, R + /// - PIB 0x0005001A -> CFAM 0x101A, OSC switch sense 2, R + /// - PIB 0x0005001B -> CFAM 0x101B, GP3 Mirror, R/W + /// + /// \retval rc The fapi::ReturnCode returned by the underlying + /// PutCfamRegister() or GetCfamRegister() call. + fapi::ReturnCode + operation(Transaction& io_transaction); + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + Pib2Cfam(const Pib2Cfam& rhs); + Pib2Cfam& operator=(const Pib2Cfam& rhs); +}; + +#endif // __VSBE_PIB2CFAM_H diff --git a/src/usr/pore/poreve/porevesrc/pore.C b/src/usr/pore/poreve/porevesrc/pore.C new file mode 100644 index 000000000..8f09e2e29 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/pore.C @@ -0,0 +1,269 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/pore.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: pore.C,v 1.13 2011/11/17 19:05:22 jeshua Exp $ + +/// \file pore.C +/// \brief The implementation of the PoreInterface for the PoreVe environment + +#include "pore.H" + +using namespace vsbe; + + +///////////////////////// Control Interface ///////////////////////// + +ModelError +Pore::forceBranch(const char* i_symbol) +{ + ModelError me; + HookError he; + bool found; + GlobalSymbolInfo info; + + he = HookManager::findGlobalSymbol(i_symbol, found, info); + if (he || !found) { + me = ME_ILLEGAL_FORCED_BRANCH; + } else { + me = PoreInterface::forceBranch(info.iv_address); + } + return me; +} + + +//////////////////// PoreInterface Methods ///////////////////////// + +/// \bug We need a FAPI return code for an illegaly configured model + +void +Pore::pibMaster(PibTransaction& io_transaction) +{ + ModelError me; + + if (iv_pib == 0) { + me = ME_NO_BUS_MODEL; + io_transaction.busError(me); + iv_fapiReturnCode = 1; /// \bug Need a return code + } else { + iv_fapiReturnCode = iv_pib->operation(io_transaction); + me = io_transaction.iv_modelError; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::ociMaster(OciTransaction& io_transaction) +{ + ModelError me; + + if (iv_oci == 0) { + me = ME_NO_BUS_MODEL; + io_transaction.busError(me); + iv_fapiReturnCode = 1; /// \bug Need a return code + } else { + iv_fapiReturnCode = iv_oci->operation(io_transaction); + me = io_transaction.iv_modelError; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::wait(const uint32_t i_count) +{ + uint64_t simCycles; + uint64_t nsDelay; + fapi::ReturnCode rc; + ModelError me; + + nsDelay = (uint64_t)((i_count * 1e9) / PORE_FREQUENCY); + + simCycles = (uint64_t) + (SIMULATOR_TICK_FREQUENCY * (i_count / PORE_FREQUENCY)); + nsDelay += 1; // Always round up the real delay. + iv_fapiReturnCode = fapiDelay(nsDelay, simCycles); + + if (iv_fapiReturnCode == 0) { + me = ME_SUCCESS; + } else { + me = ME_WAIT_FAILURE; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::hookInstruction(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter) +{ + ModelError me; + + iv_fapiReturnCode = + HookManager::runInstructionHook(i_address, i_hook, i_parameter, + *this, *iv_target); + if (iv_fapiReturnCode.ok()) { + me = ME_SUCCESS; + } else { + me = ME_HOOK_INSTRUCTION_ERROR; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::hookRead(const PoreAddress& i_address) +{ + ModelError me; + + iv_fapiReturnCode = + HookManager::runReadHooks(i_address, *this, *iv_target); + if (iv_fapiReturnCode.ok()) { + me = ME_SUCCESS; + } else { + me = ME_HOOK_READ_ERROR; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::hookWrite(const PoreAddress& i_address) +{ + ModelError me; + + iv_fapiReturnCode = + HookManager::runWriteHooks(i_address, *this, *iv_target); + if (iv_fapiReturnCode.ok()) { + me = ME_SUCCESS; + } else { + me = ME_HOOK_WRITE_ERROR; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::hookFetch(const PoreAddress& i_address) +{ + ModelError me; + + iv_fapiReturnCode = + HookManager::runFetchHooks(i_address, *this, *iv_target); + if (iv_fapiReturnCode.ok()) { + me = ME_SUCCESS; + } else { + me = ME_HOOK_FETCH_ERROR; + } + if (me != 0) { + modelError(me); + } +} + + +//////////////////////// PibSlave Methods //////////////////////////// + +// All offsets are known to be legal. PIB offsets are converted to OCI +// offsets used in the register read/write methods. + +fapi::ReturnCode +Pore::operation(Transaction& io_transaction) +{ + ModelError me; + fapi::ReturnCode rc; + + switch (io_transaction.iv_mode) { + + case ACCESS_MODE_READ: + me = registerRead((PoreRegisterOffset)(io_transaction.iv_offset * 8), + io_transaction.iv_data); + break; + + case ACCESS_MODE_WRITE: + me = registerWrite((PoreRegisterOffset)(io_transaction.iv_offset * 8), + io_transaction.iv_data); + break; + + default: + me = ME_BUS_SLAVE_PERMISSION_DENIED; + break; + } + + if (me) { + rc = 1; /// \bug Fix this + } + io_transaction.busError(me); + return rc; +} + + +////////////////////////////// Creators ////////////////////////////// + +Pore::Pore(PoreIbufId i_id) : + PoreInterface(i_id), + iv_pib(0), + iv_oci(0), + iv_target(NULL) +{ +} + + +Pore::~Pore() +{ +} + + +//////////////////// Interface Extensions ///////////////////////// + +void +Pore::configure(fapi::Target* i_target, Bus* i_pib, Bus* i_oci, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, uint64_t i_size, int i_permissions) +{ + iv_target = i_target; + iv_pib = i_pib; + iv_oci = i_oci; + PibSlave::configure(i_target, i_dataBuffer, + i_base, i_size, i_permissions); +} + + +fapi::ReturnCode +Pore::getFapiReturnCode() +{ + return iv_fapiReturnCode; +} + + diff --git a/src/usr/pore/poreve/porevesrc/pore.H b/src/usr/pore/poreve/porevesrc/pore.H new file mode 100644 index 000000000..7b773d0ad --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/pore.H @@ -0,0 +1,259 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/pore.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_PORE_H +#define __VSBE_PORE_H + +// $Id: pore.H,v 1.14 2011/11/17 19:04:47 jeshua Exp $ + +/// \file pore.H +/// \brief The implementation of the PoreInterface for the PoreVe environment + +#include <fapi.H> + +#include "bus.H" +#include "poremodel.H" +#include "hookmanager.H" + + #ifdef VBU_HACKS + #include "fapiSharedUtils.H" + #include "ecmdUtils.H" + #endif // VBU_HACKS + + +namespace vsbe { + + class Pore; + + /// This is the putative tick frequency of the simulation environment, + /// used to model the wait() method. + const double SIMULATOR_TICK_FREQUENCY = 12e9; + + /// This is the expected operating frequency of the PORE hardware engine, + /// used to model the wait() method. + const double PORE_FREQUENCY = 600e6; +}; + + +/// The implementation of the PoreInterface for the PoreVe environment +/// +/// This class provides implementations of the virtual interface to the +/// PoreModel for the PoreVe environment. The Pore is configured by providing +/// pointers to the PIB and OCI bus models of the environment. The Pore also +/// contains the last FAPI return code produced by an operation in the virtual +/// environment. +/// +/// The Pore class is also derived from the PibSlave class. This enables the +/// PORE engine to 'self-SCOM' PORE control registers that are not visible as +/// part of the architected state. Since our PoreVe environment does not +/// included a generic OCB bridge, all self-SCOM must be programmed using PIB +/// addresses. + +class +vsbe::Pore : public PoreInterface, + public PibSlave +{ + +public: + + ///////////////////////// Control Interface ///////////////////////// + + /// Force a branch to a global symbol name + /// + /// \param[in] i_symbol A global symbol name; the branch target + /// + /// Pore provides a variant of PoreModel::forceBranch() that forces a + /// branch to a global symbol, assuming the global symbol is known to + /// HookManager. The error code ME_ILLEGAL_FORCED_BRANCH is returned if + /// the symbol is not known to the HookManager. + /// + /// See PoreModel::forceBranch() for more information + /// + /// \retval me Either 0 for success or a ModelError code. + virtual ModelError + forceBranch(const char* i_symbol); + + + //////////////////// PoreInterface Methods ///////////////////////// + + /// See PoreModel::pibMaster() for the interface specification + /// + /// Run the transaction on the PoreVe PIB Bus model. FAPI errors from + /// running PIB/PCB transactions are converted to PCB return codes and + /// stored in the \a iv_pcbReturnCode field of the \a io_transaction. + void + pibMaster(PibTransaction& io_transaction); + + /// See PoreModel::ociMaster() for the interface specification + /// + /// Run the transaction on the PoreVe OCI Bus model. FAPI errors from + /// running OCI transactions are converted to abstract return codes and + /// stored in the \a iv_ociReturnCode field of the \a io_transaction. + + void + ociMaster(OciTransaction& io_transaction); + + /// See PoreModel::wait() for the interface specification + /// + /// Simulate a WAIT of \a i_count PORE cycles. The implementation + /// attempts to accurately model the wait based on the assumed PORE clock + /// frequency, and for simulation, the assumed simulation clock frequency. + /// If execution of the WAIT results in a FAPI error, the FAPI error is + /// stored in the \a iv_fapiReturnCode. + + void + wait(const uint32_t i_count); + + /// See PoreModel::hookInstruction() for the interface specification + /// + /// Use the HookManager to run the numbered hook called out by a PORE + /// HOOKI instruction. It is not considered an error to request a hook + /// that is not mapped in the HookManager. If execution of the hook + /// results in a FAPI error, the FAPI error is stored in the + /// \a iv_fapiReturnCode. + void + hookInstruction(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter); + + /// See PoreModel::hookRead() for the interface specification + /// + /// Run any hooks associated with a read of the given effective address. + /// If execution of the hook results in a FAPI error, the FAPI error is + /// stored in the \a iv_fapiReturnCode. + void + hookRead(const PoreAddress& i_address); + + /// See PoreModel::hookWrite() for the interface specification + /// + /// Run any hooks associated with a write of the given effective address. + /// If execution of the hook results in a FAPI error, the FAPI error is + /// stored in the \a iv_fapiReturnCode. + void + hookWrite(const PoreAddress& i_address); + + /// See PoreModel::hookFetch() for the interface specification + /// + /// Run any hooks associated with an instruction fetch of the given + /// effective address. If execution of the hook results in a FAPI error, + /// the FAPI error is stored in the \a iv_fapiReturnCode. + void + hookFetch(const PoreAddress& i_address); + + /// See PoreModel::errorIntr() for the interface specification + /// + /// Currently not implemented by Pore. + void + errorIntr(void) {} + + /// See PoreModel::fatalErrorIntr() for the interface specification + /// + /// Currently not implemented by Pore. + void + fatalErrorIntr(void) {} + + + //////////////////////// PibSlave Methods //////////////////////////// + + /// See Slave::operation() for the interface specification + virtual fapi::ReturnCode + operation(Transaction& io_transaction); + + + ////////////////////////////// Creators ////////////////////////////// + + /// Create the Pore + /// + /// \param[in] i_id The IBUF ID (PORE engine type) of the PORE model to + /// create. + Pore(PoreIbufId i_id); + + virtual ~Pore(); + + //////////////////// Interface Extensions ///////////////////////// + + /// Configure the Pore model by providing pointers to the Bus models + /// + /// \param[in] i_target A pointer to the FAPI target object associated + /// with the PORE model, for use in hooks and for purposes of the + /// PibSlave. + /// + /// \param[in] i_pib A Bus model (to be) configured as a PIB bus. + /// + /// \param[in] i_oci A Bus model (to be) configured as an OCI bus. + /// + /// \param[in] i_dataBuffer See Slave::configure() + /// + /// \param[in] i_base See Slave::configure() + /// + /// \param[in] i_size See Slave::configure() + /// + /// \param[in] i_permissions See Slave::configure() + /// + /// This interface is introduced simply to encapsulate everything about + /// the Pore that needs to be configured to create a system. + void + configure(fapi::Target* i_target, Bus* i_pib, Bus* i_oci, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, uint64_t i_size, int i_permissions); + + /// Get the FAPI return code from the model + /// + /// \retval rc The last FAPI return code from any PORE operations in the + /// environment. + fapi::ReturnCode + getFapiReturnCode(); + + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The PoreVe PIB Bus model + Bus* iv_pib; + + /// The PoreVe OCI Bus model + Bus* iv_oci; + + /// The last FAPI return code + /// + /// Operations in the PoreVe environment return FAPI ReturnCode objects. + /// The FAPI return code is stored here, and the ModelError returned to + /// the PoreModel dependson the type of error. + fapi::ReturnCode iv_fapiReturnCode; + + /// A pointer to the FAPI target associated with this PORE engine + /// + /// The Pore object holds this pointer for use as an argument to hook + /// routines. + fapi::Target* iv_target; + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + + Pore(const Pore& i_rhs); + Pore& operator=(const Pore& i_rhs); +}; + +#endif // __VSBE_PORE_H diff --git a/src/usr/pore/poreve/porevesrc/poreve.C b/src/usr/pore/poreve/porevesrc/poreve.C new file mode 100644 index 000000000..e0a841cdd --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/poreve.C @@ -0,0 +1,480 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/poreve.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: poreve.C,v 1.15 2011/12/14 22:11:51 bcbrock Exp $ + +/// \file poreve.C +/// \brief The PORE Virtual Environment + +#include "poreve.H" + +using namespace vsbe; + + +//////////////////////////////////////////////////////////////////////////// +// PoreVeBase +//////////////////////////////////////////////////////////////////////////// + + +PoreVeBase::PoreVeBase(const PoreIbufId i_id, + const fapi::Target i_masterTarget) : + iv_pore(i_id), + iv_pnorMemory(PNOR_ADDRESS_BYTES), + iv_id(i_id), + iv_masterTarget(i_masterTarget), + iv_slaveTarget(i_masterTarget) +{ + uint32_t porePibBase; + + // Configure the PORE. Only the PIB bus is connected, the OCI bus remains + // unconnected (0). The PIB self-SCOM interface configuration is a + // function of which PORE egine is being configured. Technically we should + // barf if \a i_id is not PORE_SBE or PORE_SLW, but HBI doesn't want any + // throw()s. + + if (i_id == PORE_SLW) { + porePibBase = PORE_SLW_PIB_BASE; + } else { + porePibBase = PORE_SBE_PIB_BASE; + } + + iv_pore.configure(&iv_slaveTarget, &iv_pib, 0, + &iv_dataBuffer, + porePibBase, PORE_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_pore); + + // Configure the PNOR controller and attach its memory + + iv_pnorController.configure(&iv_masterTarget, + &iv_dataBuffer, + PNOR_PIB_BASE, + PNOR_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_pnorController); + + iv_pnorController.attachMemory(&iv_pnorMemory, + PNOR_I2C_PORT, + PNOR_I2C_DEVICE_ADDRESS); + + + // Configure the PIB catch-all model + + iv_pibDefault.configure(&iv_slaveTarget, + &iv_dataBuffer, + PIB_DEFAULT_PIB_BASE, + PIB_DEFAULT_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachSecondarySlave(&iv_pibDefault); +} + + +PoreVeBase::~PoreVeBase() +{ +} + + +// This is a temporary hack: Until the final specification of the reset state +// of the PORE-SBE engine is available, we initialize the PORE-SBE engine +// here. This is simpler than trying to keep the PMX model up to date as we +// mess with chaging requirements, and it's also better for PMX to assume +// that the PORE-SBE is halted at PMX-IPL, since PMX/Simics is really a model +// for OCC firmware. This initializaton of PORE-SBE is done here rather than +// in the PoreModel because we have the memory address assumptions here. +// +// If this is a PORE-SBE, then the machine comes up running from OTPROM. + +/// \bug Temporary hack + +void +PoreVeBase::reset(fapi::Target i_slaveTarget) +{ + iv_slaveTarget = i_slaveTarget; + iv_pore.restart(); + HookManager::clearError(); + + if (iv_id == PORE_SBE) { + + // The PMX model comes up halted in OCI space. We set the PC to + // OTPROM space and run() 0 instructions. This will clear the stop bit + // to start execution. + + PoreAddress pc; + uint64_t ran; + + pc.setFromPibAddress(OTPROM_PIB_BASE); + iv_pore.setPc(pc); + iv_pore.run(0, ran); + } +} + + +int +PoreVeBase::run(uint64_t i_instructions, uint64_t& o_ran) +{ + return iv_pore.run(i_instructions, o_ran); +} + + +ModelError +PoreVeBase::getscom(const uint32_t i_address, uint64_t& o_data, int& o_rc) +{ + PibTransaction t; + + t.iv_address = i_address; + t.iv_mode = ACCESS_MODE_READ; + + iv_pib.operation(t); + + o_data = t.iv_data; + o_rc = t.iv_pcbReturnCode; + return t.iv_modelError; +} + + +ModelError +PoreVeBase::putscom(const uint32_t i_address, const uint64_t i_data, int& o_rc) +{ + PibTransaction t; + + t.iv_address = i_address; + t.iv_data = i_data; + t.iv_mode = ACCESS_MODE_WRITE; + + iv_pib.operation(t); + + o_rc = t.iv_pcbReturnCode; + return t.iv_modelError; +} + + +//////////////////////////////////////////////////////////////////////////// +// PoreVe +//////////////////////////////////////////////////////////////////////////// + +PoreVe::PoreVe(const PoreIbufId i_id, + const fapi::Target i_masterTarget) : + PoreVeBase(i_id, i_masterTarget), + iv_seepromMemory(SEEPROM_ADDRESS_BYTES) +{ + uint32_t porePibBase; + + // Reconfigure the Pore - this doesn't hurt anything in the previous + // configuration in the base class as this is a set of simple pointer and + // data assignments. But it's another reason to jettison the requirement + // for the base class. The PORE was attached to the PIB in the base + // class. + + if (i_id == PORE_SLW) { + porePibBase = PORE_SLW_PIB_BASE; + } else { + porePibBase = PORE_SBE_PIB_BASE; + } + + iv_pore.configure(&iv_slaveTarget, &iv_pib, &iv_oci, + &iv_dataBuffer, + porePibBase, PORE_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + // Configure the OTPROM + + iv_otprom.configure(&iv_slaveTarget, + &iv_dataBuffer, + OTPROM_PIB_BASE, + OTPROM_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_EXECUTE, + &iv_otpromMemory); + + iv_pib.attachPrimarySlave(&iv_otprom); + + + // Configure the PIBMEM + + iv_pibmem.configure(&iv_slaveTarget, + &iv_dataBuffer, + PIBMEM_PIB_BASE, + PIBMEM_PIB_SIZE, + ACCESS_MODE_READ | + ACCESS_MODE_WRITE | + ACCESS_MODE_EXECUTE, + &iv_pibmemMemory); + + iv_pib.attachPrimarySlave(&iv_pibmem); + + + // Configure the SEEPROM controller + + iv_seepromController.configure(&iv_slaveTarget, + &iv_dataBuffer, + SEEPROM_PIB_BASE, + SEEPROM_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_seepromController); + + iv_seepromController.attachMemory(&iv_seepromMemory, + SEEPROM_I2C_PORT, + SEEPROM_I2C_DEVICE_ADDRESS); + + // Configure Mainstore + + iv_main.configure(&iv_slaveTarget, + &iv_dataBuffer, + MAINSTORE_OCI_BASE, + MAINSTORE_OCI_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE, + &iv_mainMemory); + + iv_oci.attachPrimarySlave(&iv_main); + + + // Configure SRAM + + iv_sram.configure(&iv_slaveTarget, + &iv_dataBuffer, + SRAM_OCI_BASE, + SRAM_OCI_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE, + &iv_sramMemory); + + iv_oci.attachPrimarySlave(&iv_sram); + + +#ifdef PM_HACKS + // This device provides write-only access to a single control register in + // the PMC. + + iv_pmc.configure(&iv_slaveTarget, + &iv_dataBuffer, + PMC_OCI_BASE, + PMC_OCI_SIZE, + ACCESS_MODE_WRITE); + + iv_oci.attachPrimarySlave(&iv_pmc); +#endif // PM_HACKS + + +#ifdef VBU_HACKS + // Configure the temporary Pib2Cfam component + + iv_pib2Cfam.configure(&iv_slaveTarget, + &iv_dataBuffer, + PIB2CFAM_PIB_BASE, + PIB2CFAM_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_pib2Cfam); + + // Configure the temporary sbeVital component + + iv_sbeVital.configure(&iv_slaveTarget, + &iv_dataBuffer, + SBEVITAL_PIB_BASE, + SBEVITAL_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_sbeVital); + +#ifndef SIMPLE_VBU_HACKS_ONLY + + // The VBU_HACKS above are simple - they don't require complex eCMD support so + // we can test them easily with the poreve/test/fapistub test case. + + // The VBU hacks below are complicated to emulate, so we don't even try in + // the test/fapistub test case. + + // Configure the Broadside scan component if using BROADSIDE scan + //JDS TODO - add a check for broadside scan mode + ecmdConfigValid_t validOutput; + std::string tmpStr; + uint32_t tmpNum; + uint32_t rc; + ecmdChipTarget e_target; + + //JDS TODO - change this to get attribute + fapiTargetToEcmdTarget( iv_slaveTarget, e_target); + rc = ecmdGetConfiguration(e_target, "SIM_BROADSIDE_MODE", + validOutput, tmpStr, tmpNum ); + if( rc || + validOutput == ECMD_CONFIG_VALID_FIELD_NONE || + validOutput == ECMD_CONFIG_VALID_FIELD_NUMERIC ) + { + FAPI_ERR( "Unable to determine SIM_BROADSIDE_MODE\n" ); + } + else + { + size_t pos = tmpStr.find( "scan" ); + if( pos != (uint32_t)-1 ) + { +// iv_bsscan_ex00.configure(&iv_slaveTarget, +// &iv_dataBuffer, +// BSSCAN_PIB_BASE | EX00_PIB_BASE, +// BSSCAN_PIB_SIZE, +// ACCESS_MODE_READ | ACCESS_MODE_WRITE); + +// iv_pib.attachPrimarySlave(&iv_bsscan_ex00); + + iv_bsscan_ex01.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX01_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex01); + + iv_bsscan_ex02.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX02_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex02); + + iv_bsscan_ex03.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX03_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex03); + + iv_bsscan_ex04.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX04_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex04); + + iv_bsscan_ex05.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX05_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex05); + + iv_bsscan_ex06.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX06_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex06); + +// iv_bsscan_ex07.configure(&iv_slaveTarget, +// &iv_dataBuffer, +// BSSCAN_PIB_BASE | EX07_PIB_BASE, +// BSSCAN_PIB_SIZE, +// ACCESS_MODE_READ | ACCESS_MODE_WRITE); + +// iv_pib.attachPrimarySlave(&iv_bsscan_ex07); + +// iv_bsscan_ex08.configure(&iv_slaveTarget, +// &iv_dataBuffer, +// BSSCAN_PIB_BASE | EX08_PIB_BASE, +// BSSCAN_PIB_SIZE, +// ACCESS_MODE_READ | ACCESS_MODE_WRITE); + +// iv_pib.attachPrimarySlave(&iv_bsscan_ex08); + + iv_bsscan_ex09.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX09_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex09); + + iv_bsscan_ex10.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX10_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex10); + + iv_bsscan_ex11.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX11_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex11); + + iv_bsscan_ex12.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX12_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex12); + + iv_bsscan_ex13.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX13_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex13); + + iv_bsscan_ex14.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX14_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex14); + +// iv_bsscan_ex15.configure(&iv_slaveTarget, +// &iv_dataBuffer, +// BSSCAN_PIB_BASE | EX15_PIB_BASE, +// BSSCAN_PIB_SIZE, +// ACCESS_MODE_READ | ACCESS_MODE_WRITE); + +// iv_pib.attachPrimarySlave(&iv_bsscan_ex15); + } //end SIM_BROADSIDE_MODE has scan + } //end was able to read SIM_BROADSIDE_MODE + +#endif // SIMPLE_VBU_HACKS_ONLY +#endif // VBU_HACKS +} + + +PoreVe::~PoreVe() +{ +} + + + + + + + + + + + + diff --git a/src/usr/pore/poreve/porevesrc/poreve.H b/src/usr/pore/poreve/porevesrc/poreve.H new file mode 100644 index 000000000..4c2281940 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/poreve.H @@ -0,0 +1,535 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/poreve.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_POREVE_H +#define __VSBE_POREVE_H + +// $Id: poreve.H,v 1.18 2011/12/16 21:47:59 bcbrock Exp $ + +/// \file poreve.H +/// \brief The PORE Virtual Environment +/// +/// The PORE Virtual Environment is a container class that contains a Pore +/// model along with the Bus and Memory models that comprise a Pore system. +/// These system models offer very little in the way of interfaces other than +/// a way to reset() the simulation and a run() method to clock the +/// simulation. Instead, most operations on the PORE (including setting up the +/// initial state) are performed directly on the Pore model data member \a +/// iv_pore itself. Similarly, memories are configured by map() operations +/// directly on the memory objects. +/// +/// The system components are created and interconnected in a simple two-step +/// process: +/// +/// - When objects are created any truly static configuration parameters are +/// passed as arguments of the constructor. +/// +/// - After all components are constructed, simple code sequences stitch +/// together the components using a configure() method provided by each class +/// of component. +/// +/// This two-step sequence eliminates the problem of loops that would arise if +/// we tried to configure the network in the constructor, and is very similar +/// to the way that Simics models are configured. +/// +/// The final PoreVe model is constructed in two steps. We first define a +/// PoreVeBase model. This is a stripped down environment that only contains +/// a PORE engine and the exact components required for the HBI application of +/// PORE-SBE. The Vsbe facade class is later provided as the interface to +/// PoreVeBase. +/// +/// The second step of the derivation is to add all of the remaining +/// components to create the full PoreVe model for use in VBU and lab +/// applications. The derivation is done this way to make the PoreVeBase as +/// small as possible in terms of both code and data size. Ideally however +/// the differences (in code and data size) will turn out to be small enough +/// such that we can drop the separate models and simply always create the +/// full PoreVe model, using the Vsbe facade as the high-level interface for +/// HBI. Frankly, the system design would probably be more robust if we had +/// only one model - we may go ahead and merge the models anyway. + +#include <stdint.h> +#include <stdarg.h> + +#include "fapi.H" + +#include "fasti2c.H" +#include "poremodel.H" +#include "pore.H" + +#ifdef VBU_HACKS +#include "pib2cfam.H" +#include "bsscan.H" +#include "sbevital.H" +#endif // VBU_HACKS + +#ifndef POREVE_STATISTICS +#define POREVE_STATISTICS 0 +#endif + +namespace vsbe { + + class PoreVeBase; + class PoreVe; + + /// \defgroup poreve_config Parameters of PoreVe Configurations + /// + /// These parameters are required for configuring the PoreVe system model. + /// + /// \bug Many of these parameters are fake for now and will be system + /// dependent. + /// + /// @{ + + ////////////////////////////////////////////////////////////////////// + // PORE + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of PORE-SBE control registers + const uint32_t PORE_SBE_PIB_BASE = 0x000e0000; + + /// The PIB base address of PORE-SLW control registers + const uint32_t PORE_SLW_PIB_BASE = 0x00068000; + + /// The size of the PORE control register space. + const uint64_t PORE_PIB_SIZE = ((uint64_t)SIZEOF_VISIBLE_PORE_STATE) / 8; + + + ////////////////////////////////////////////////////////////////////// + // OTPROM + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the OTPROM memory controller + const uint32_t OTPROM_PIB_BASE = 0x00010000; + + /// The number of PIB \e registers defined by the OTPROM memory controller + /// + /// PIB memories are 8-byte \e word addressed. The maximum amount of + /// memory accessible through the controller is (OTPROM_PIB_SIZE * 8) + /// bytes. + const uint64_t OTPROM_PIB_SIZE = 0x200; + + + ////////////////////////////////////////////////////////////////////// + // PIBMEM + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the PIBMEM memory controller + const uint32_t PIBMEM_PIB_BASE = 0x00080000; + + /// The number of PIB \e registers defined by the PIBMEM memory controller + /// + /// PIB memories are 8-byte \e word addressed. The maximum amount of + /// memory accessible through the controller is (PIBMEM_PIB_SIZE * 8) + /// bytes (3KB). + const uint64_t PIBMEM_PIB_SIZE = 0x180; + + + ////////////////////////////////////////////////////////////////////// + // PNOR + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the PNOR (LPCM) memory controller + const uint32_t PNOR_PIB_BASE = 0x000b0000; + + /// The number of registers defined by the PNOR memory controller + const size_t PNOR_PIB_SIZE = LPCM_REGISTERS; + + /// The number of bytes in a PNOR address (actually a parameter of the + /// memory attached to the controller) + const size_t PNOR_ADDRESS_BYTES = 4; + + /// The PNOR I2C Port Number + const unsigned PNOR_I2C_PORT = 0; + + /// The PNOR I2C Device Address + const unsigned PNOR_I2C_DEVICE_ADDRESS = 0; + + + ////////////////////////////////////////////////////////////////////// + // SEEPROM + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the SEEPROM memory controller + const uint32_t SEEPROM_PIB_BASE = 0x000c0000; + + /// The number of registers defined by the SEEPROM memory controller + const uint64_t SEEPROM_PIB_SIZE = FASTI2C_REGISTERS; + + /// The number of bytes in an SEEPROM address + const uint64_t SEEPROM_ADDRESS_BYTES = 2; + + /// The SEEPROM I2C Port Number + const unsigned SEEPROM_I2C_PORT = 0; + + /// The SEEPROM I2C Device Address + /// + /// \bug This value (0) is bogus, need the real value from the system + /// design. + const unsigned SEEPROM_I2C_DEVICE_ADDRESS = 0; + + + ////////////////////////////////////////////////////////////////////// + // PIB Default Catch-All Model + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the default PIB slave + const uint32_t PIB_DEFAULT_PIB_BASE = 0x0; + + /// The number of registers defined by the default PIB slave + const uint64_t PIB_DEFAULT_PIB_SIZE = 0x100000000ull; + + + ////////////////////////////////////////////////////////////////////// + // OCI-Attached Components + ////////////////////////////////////////////////////////////////////// + + /// The OCI base address of the OCI PBA->Mainstore bridge + /// + /// We go ahead and map the entire 1GB. During configuration the actual + /// memory area in use will be defined by Memory::map() calls. + const uint32_t MAINSTORE_OCI_BASE = 0x00000000; + + /// The OCI PBA->Mainstore bridge maps 1GB of the address space + const uint64_t MAINSTORE_OCI_SIZE = 0x40000000; + + + /// The OCI base address of the SRAM + const uint32_t SRAM_OCI_BASE = 0xfff80000; + + /// The OCI SRAM is 512KB + const uint64_t SRAM_OCI_SIZE = 0x00080000; + + /// The OCI address of the PMC_PORE_REQ_STAT_REG Register + /// + /// This is the only OCI control register that PORE-SLW should access, so + /// its size is limited to 8 bytes. + const uint32_t PMC_OCI_BASE = 0x40010480; + + /// PORE-SLW is only allowed to access a specific 8 bytes of the OCI + /// control register space. + const uint64_t PMC_OCI_SIZE = 8; + + /// @} +}; + + +//////////////////////////////////////////////////////////////////////////// +// PoreVeBase +//////////////////////////////////////////////////////////////////////////// + +/// The base class (HBI-only components) of PoreVe. +/// +/// This model contains only those components required for HBI applications +/// of the PORE virtual environment. Currently this is only +/// +/// - A Pore +/// - A PIB bus +/// - A PNOR memory model +/// - A PibSlave to catch any getscom()/putscom() destined for the PIB + +class +vsbe::PoreVeBase { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + /// Construct the PoreVeBase + /// + /// \param[in] i_id The PORE IBUF_ID (engine type) of the Pore component. + /// This will be PORE_SBE for host boot/SBE applications, and PORE_SLW for + /// testing Sleep/Winkle applications. + /// + /// \param[in] i_masterTarget The fapi::Target associated with the master + /// chip in an HBI master/slave configuration. This target is also + /// installed into \a iv_slaveTarget by the constructor. + PoreVeBase(const PoreIbufId i_id, const fapi::Target i_masterTarget); + + virtual ~PoreVeBase(); + + + //////////////////// Simulation Interface ///////////////////////// + + /// Reset the simulation to target a new slave + /// + /// \param[in] i_slaveTarget The slave target of the new slave + /// + /// The reset() method is provided to cleanly reset the simulation for + /// simulation with a new slave target. Once reset, the application is + /// responsible for setting up the register state of the Pore and invoking + /// the run() method to begin simulation. + virtual void + reset(fapi::Target i_slaveTarget); + + + /// See PoreModel::run() + /// + /// This API is provided as a convenience. Currently the only model in + /// the system that is 'clocked' is the PoreModel. + virtual int + run(const uint64_t i_instructions, uint64_t& o_ran); + + + /// Run a 'getscom' on the virtual PIB + /// + /// \param[in] i_address A 32-bit SCOM address + /// + /// \param[out] o_data The 64-bit SCOM data returned from the read + /// + /// \param[out] o_rc The 3-bit PIB/PCB error code returned from the PIB + /// transaction, see the PcbReturnCode enum in transaction.H. + /// + /// This method allows a caller to run a read transaction on the virtual + /// PIB bus, observing the same PIB configuration seen by the virtual PORE + /// engine. Accesses of PIB/PCB addresses that are modeled in the virtual + /// model return modeled results, and accesses of non-modeled addresses + /// are converted into FAPI calls. + /// + /// \returns A return value of 0 indicates success of the method call, but + /// does not guarantee that the PIB transaction succeeded. It will also be + /// necessary to also observe that PIB/PCB return code \a o_rc was + /// returned as 0. A non-0 return code from the method indicates a + /// modeling error. + virtual ModelError + getscom(const uint32_t i_address, uint64_t& o_data, int& o_rc); + + + /// Run a 'putscom' on the virtual PIB + /// + /// \param[in] i_address A 32-bit SCOM address + /// + /// \param[out] i_data The 64-bit SCOM write data + /// + /// \param[out] o_rc The 3-bit PIB/PCB error code returned from the PIB + /// transaction, see the PcbReturnCode enum in transaction.H. + /// + /// This method allows a caller to run a write transaction on the virtual + /// PIB bus, observing the same PIB configuration seen by the virtual PORE + /// engine. Accesses of PIB/PCB addresses that are modeled in the virtual + /// model update modeled registers, and accesses of non-modeled addresses + /// are converted into FAPI calls. + /// + /// \returns A return value of 0 indicates success of the method call, but + /// does not guarantee that the PIB transaction succeeded. It will also be + /// necessary to also observe that PIB/PCB return code \a o_rc was + /// returned as 0. A non-0 return code from the method indicates a + /// modeling error. + virtual ModelError + putscom(const uint32_t i_address, const uint64_t i_data, int& o_rc); + + + //////////////////// Public Implementation //////////////////////////// + + /// The Pore model + Pore iv_pore; + + /// The PIB bus model + Bus iv_pib; + + /// The PNOR controller model + FastI2cController iv_pnorController; + + /// The PNOR memory model + I2cMemory iv_pnorMemory; + + /// The secondary PIB slave. + /// + /// This slave routes all operations that do not hit in a PIB-attached + /// memory model to hardware via FAPI getscom/putcom. + PibSlave iv_pibDefault; + + + //////////////////// Protected Implementation /////////////////////////// + +protected: + + /// The PORE IBUF ID of the PORE engine + PoreIbufId iv_id; + + /// The master fapi::Target + /// + /// HBI applications differentiate between the \e master chip that is + /// brought up first, and the \e slave chips that the master then + /// initializes. The master target is considered a constant and is + /// provided in the constructor. The master target is always associated + /// with the PNOR; the other memory components are associated with the + /// slave target. A pointer to this data member is provided to the PNOR + /// model during configuration. + fapi::Target iv_masterTarget; + + + /// The slave fapi::Target + /// + /// HBI applications differentiate between the \e master chip that is + /// brought up first, and the \e slave chips that the master then + /// initializes. The slave target is considered a variable and the + /// reset() method is provided to safely reset the system and modify the + /// slave target after construction. Note that the slave target is + /// initialized to be identical to the master target by the constructor. + /// A pointer to this data member is provided to all slaves other that the + /// PNOR model during configuration. + fapi::Target iv_slaveTarget; + + + /// The common ecmdDataBufferBase for all FAPI APIs + /// + /// To save memory space we only allocate one FAPI data buffer that is + /// used by all FAPI APIs that require a ecmdDataBuffer. A pointer to + /// this data member is provided to all slaves during configuration. + ecmdDataBufferBase iv_dataBuffer; + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + PoreVeBase(const PoreVeBase& i_rhs); + PoreVeBase& operator=(const PoreVeBase& i_rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// PoreVe +//////////////////////////////////////////////////////////////////////////// + + +/// The full PoreVe configuration +/// +/// This derivation from PoreVeBase adds the remaining PIB models not required +/// by the HBI application, as well as all of the OCI models. Note that +/// unlike the PIB there is no catch-all for OCI accesses; An access must hit +/// within one of the defined memory maps, otherwise the access is considered +/// an error. + +class +vsbe::PoreVe : public vsbe::PoreVeBase { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + /// Construct the PoreVe + /// + /// \param[in] i_id The PORE IBUF_ID (engine type) of the Pore component. + /// This will be PORE_SBE for host boot/SBE applications, and PORE_SLW for + /// testing Sleep/Winkle applications. + /// + /// \param[in] i_masterTarget The fapi::Target associated with the master + /// chip in an HBI master/slave configuration. This target is also + /// installed into \a iv_slaveTarget by the constructor. + PoreVe(const PoreIbufId i_id, const fapi::Target i_masterTarget); + + virtual ~PoreVe(); + + /// Create a PoreVe (subclass) by static link-time selection + /// + /// \param[in] i_id The PORE IBUF_ID (engine type) of the Pore component. + /// This will be PORE_SBE for host boot/SBE applications, and PORE_SLW for + /// testing Sleep/Winkle applications. + /// + /// \param[in] i_masterTarget The fapi::Target associated with the master + /// chip in an HBI master/slave configuration. This target is also + /// installed into \a iv_slaveTarget by the constructor. + /// + /// \param[in] i_arg A private argument for the created model. In the + /// case of a debugged model this is a character string naming a script to + /// be run when the debugger starts. The PoreVe ignores this argument. + /// + /// The static create() method is provided to enable link-time selection + /// of a subclass of PoreVe, in particular to allow a common FAPI PoreVe + /// procedure to create either a 'normal' or 'debug' version of PoreVe. + static PoreVe* create(const PoreIbufId i_id, + const fapi::Target i_masterTarget, + const void* i_arg); + + //////////////////// Public Implementation //////////////////////////// + + /// The OTPROM controller model + PibMemory iv_otprom; + + /// The OTPROM memory model + Memory iv_otpromMemory; + + /// The PIBMEM controller model - No advanced functions implemented for now + PibMemory iv_pibmem; + + /// The PIPMEM memory model + Memory iv_pibmemMemory; + + /// The SEEPROM controller model + FastI2cController iv_seepromController; + + /// The SEEPROM memory model + I2cMemory iv_seepromMemory; + + /// The OCI bus model + Bus iv_oci; + + /// The Mainstore memory controller model + OciMemory iv_main; + + /// The Mainstore memory model + Memory iv_mainMemory; + + /// The SRAM controller model + OciMemory iv_sram; + + /// The SRAM memory model + Memory iv_sramMemory; + +#ifdef PM_HACKS + OciSlaveWritable iv_pmc; +#endif // PM_HACKS + +#ifdef VBU_HACKS + /// The temporary Pib2Cfam PIB Slave + Pib2Cfam iv_pib2Cfam; + + /// The temporary sbeVital PIB Slave + SbeVital iv_sbeVital; + + /// The Broadside Scan components for each EX + // Bsscan iv_bsscan_ex00; + Bsscan iv_bsscan_ex01; + Bsscan iv_bsscan_ex02; + Bsscan iv_bsscan_ex03; + Bsscan iv_bsscan_ex04; + Bsscan iv_bsscan_ex05; + Bsscan iv_bsscan_ex06; + // Bsscan iv_bsscan_ex07; + // Bsscan iv_bsscan_ex08; + Bsscan iv_bsscan_ex09; + Bsscan iv_bsscan_ex10; + Bsscan iv_bsscan_ex11; + Bsscan iv_bsscan_ex12; + Bsscan iv_bsscan_ex13; + Bsscan iv_bsscan_ex14; + // Bsscan iv_bsscan_ex15; +#endif + ///////////////////////////// Safety ////////////////////////////////// + +private: + PoreVe(const PoreVe& i_rhs); + PoreVe& operator=(const PoreVe& i_rhs); +}; + +#endif // __VSBE_POREVE_H diff --git a/src/usr/pore/poreve/porevesrc/sbevital.C b/src/usr/pore/poreve/porevesrc/sbevital.C new file mode 100644 index 000000000..1a80337db --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/sbevital.C @@ -0,0 +1,82 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/sbevital.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// -*- mode: C++; c-file-style: "linux"; -*- +// $Id: sbevital.C,v 1.1 2011/09/19 00:25:32 jeshua Exp $ + +/// \file sbevital.C +/// \brief A temporary hack to create the SBE vital reg before HW has it +/// +#ifdef VBU_HACKS + +#include "sbevital.H" +#include "fapiSharedUtils.H" +#include "ecmdUtils.H" +using namespace vsbe; + + +////////////////////////////// Creators ////////////////////////////// + +SbeVital::SbeVital() +{ + iv_data = 0; +} + + +SbeVital::~SbeVital() +{ +} + + +//////////////////////////// Manipulators //////////////////////////// + +fapi::ReturnCode +SbeVital::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc=0; + ModelError me; + + FAPI_INF("In sbeVital\n"); + + //On a ring write, put the data into the ring + if( io_transaction.iv_mode == ACCESS_MODE_WRITE) + { + iv_data = io_transaction.iv_data >> 32; + me = ME_SUCCESS; + } + else if( io_transaction.iv_mode == ACCESS_MODE_READ ) + { + io_transaction.iv_data = ((uint64_t)(iv_data)) << 32; + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + + io_transaction.busError(me); + return rc; +} +#endif +/* Local Variables: */ +/* c-basic-offset: 4 */ +/* End: */ diff --git a/src/usr/pore/poreve/porevesrc/sbevital.H b/src/usr/pore/poreve/porevesrc/sbevital.H new file mode 100644 index 000000000..66aa83f96 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/sbevital.H @@ -0,0 +1,85 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/sbevital.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_SBEVITAL_H +#define __VSBE_SBEVITAL_H + +// $Id: sbevital.H,v 1.1 2011/09/19 00:25:32 jeshua Exp $ + +/// \file sbevital.H +/// \brief A hack to intercept scan operations and make them broadside + +#include "bus.H" + +namespace vsbe { + + class SbeVital; + + /// PIB base address of PIB range mapped by SbeVital + const uint32_t SBEVITAL_PIB_BASE = 0x0005001C; + + /// Number of PIB addresses mapped by SbeVital + const int SBEVITAL_PIB_SIZE = 1; + +} + + +/// Map PIB accesses to CFAM accesses + +class +vsbe::SbeVital : public PibSlave { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + SbeVital(); + + virtual ~SbeVital(); + + + //////////////////////////// Manipulators //////////////////////////// + + /// SbeVital operation + /// + /// \param[in,out] io_transaction A PIB transaction object + /// + /// This object converts PIB transactions in a certain range in the + /// virtual environment to broadside getRing and putRing operations, + /// returning the FAPI return code from the translated calls. + /// + /// \retval rc The fapi::ReturnCode returned by the underlying + /// getRing() or putRing() call. + fapi::ReturnCode + operation(Transaction& io_transaction); + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + SbeVital(const SbeVital& rhs); + SbeVital& operator=(const SbeVital& rhs); + + uint32_t iv_data; +}; + +#endif // __VSBE_SBEVITAL_H diff --git a/src/usr/pore/poreve/poreveutil.C b/src/usr/pore/poreve/poreveutil.C new file mode 100644 index 000000000..3d8059061 --- /dev/null +++ b/src/usr/pore/poreve/poreveutil.C @@ -0,0 +1,35 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/poreveutil.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#include <trace/interface.H> + +//****************************************************************************** +// Trace descriptors +//****************************************************************************** +trace_desc_t* g_poreDbgTd = NULL; +trace_desc_t* g_poreErrTd = NULL; + +//****************************************************************************** +// Global TracInit objects. Construction will initialize the trace buffer +//****************************************************************************** +TRAC_INIT(&g_poreDbgTd, "PORE_D", 4096); +TRAC_INIT(&g_poreErrTd, "PORE_E", 4096); diff --git a/src/usr/pore/test/makefile b/src/usr/pore/test/makefile new file mode 100644 index 000000000..884fe5ec5 --- /dev/null +++ b/src/usr/pore/test/makefile @@ -0,0 +1,37 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/pore/test/makefile $ +# +# IBM CONFIDENTIAL +# +# COPYRIGHT International Business Machines Corp. 2011 +# +# p1 +# +# Object Code Only (OCO) source materials +# Licensed Internal Code Source Materials +# IBM HostBoot Licensed Internal Code +# +# The source code for this program is not published or other- +# wise divested of its trade secrets, irrespective of what has +# been deposited with the U.S. Copyright Office. +# +# Origin: 30 +# +# IBM_PROLOG_END +ROOTPATH = ../../../.. + +MODULE = testpore + +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/ecmddatabuffer +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/fapiporeve +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/poreve/model +EXTRAINCDIR += ${ROOTPATH}/src/usr/pore/poreve/porevesrc +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/fapi +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/plat +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp + +TESTS = *.H + +include ${ROOTPATH}/config.mk diff --git a/src/usr/pore/test/poretest.H b/src/usr/pore/test/poretest.H new file mode 100644 index 000000000..bc3cd5e72 --- /dev/null +++ b/src/usr/pore/test/poretest.H @@ -0,0 +1,181 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/test/poretest.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __PORETEST_H +#define __PORETEST_H + +/** + * @file poretest.H + * + * @brief Test case for POREVE code +*/ + +#include <list> +#include <cxxtest/TestSuite.H> +#include <targeting/targetservice.H> +#include <fapiPoreVeArg.H> +#include <fapiTarget.H> +#include <fapi.H> +#include <vfs/vfs.H> + +using namespace TARGETING; +using namespace vsbe; +extern fapi::ReturnCode fapiPoreVe(const fapi::Target i_target, + std::list<uint64_t> & io_sharedObjectArgs); + +class PoreTest: public CxxTest::TestSuite +{ +public: + /** + * @brief PORE test #1 + * Run a sample procedure + */ + void testPore1(void) + { + fapi::ReturnCode l_rc = fapi::FAPI_RC_SUCCESS; + fapi::ReturnCode l_rc2 = fapi::FAPI_RC_SUCCESS; + bool l_unloadSbePnorImg = false; + size_t l_sbePnorSize = 0; + const char * l_sbePnorAddr = NULL; + + errlHndl_t l_errl = NULL; + + do + { + // Loading sbe_pnor img + l_errl = VFS::module_load("sbe_pnor.bin"); + if (l_errl) + { + TS_FAIL("testPore1: Error loading sbe_pnor.bin!"); + break; + } + else + { + // Set flag to unload + l_unloadSbePnorImg = true; + l_errl = VFS::module_address("sbe_pnor.bin", l_sbePnorAddr, l_sbePnorSize); + if(l_errl) + { + TS_FAIL("testPore1: Error getting load address of sbe_pnor.bin!"); + break; + } + else + { + char l_header[10]; + memcpy (l_header, l_sbePnorAddr, 9); + l_header[9] = '\0'; + FAPI_INF("Loading sbe_pnor.bin, Addr 0x%llX, Size %d, Header %s", + l_sbePnorAddr, l_sbePnorSize, l_header); + } + } + + // Setting up fapi target + TARGETING::TargetService& l_targetService = + TARGETING::targetService(); + TARGETING::Target* l_testTarget = NULL; + l_targetService.masterProcChipTargetHandle(l_testTarget); + assert(l_testTarget != NULL); + + // Setup args + std::list<uint64_t> myArgs; + + // Run unlimited instruction on SBE engine + FapiPoreVeOtherArg *l_otherArg = + new FapiPoreVeOtherArg(vsbe::RUN_UNLIMITED, + vsbe::PORE_SBE); + //Set entry point + //l_otherArg->iv_entryPoint = const_cast<char*>("pnor::_sbe_pnor_start"); + //l_otherArg->iv_entryPoint = const_cast<char*>("pnor::proc_sbe_fabricinit"); + l_otherArg->iv_entryPoint = const_cast<char*>("pnor::proc_sbe_pb_startclocks"); + + l_otherArg->iv_mrr = 0x280000000; + + uint64_t fapiArg = reinterpret_cast<uint64_t> (l_otherArg); + myArgs.push_back(fapiArg); + + // Set FapiPoreVeMemArg for pnor option, base address = 0 + uint32_t base_addr = 0; + char* l_dataPnor = const_cast<char*>(l_sbePnorAddr); + //@todo - Need to somehow avoid manually entering file size here. + FapiPoreVeMemArg* l_memArg = new FapiPoreVeMemArg(ARG_PNOR, + base_addr, 31360, static_cast<void*>(l_dataPnor)); + fapiArg = reinterpret_cast<uint64_t> (l_memArg); + myArgs.push_back(fapiArg); + + // Create state argument to dump out state for debugging purpose + FapiPoreVeStateArg *l_stateArg = new FapiPoreVeStateArg(NULL); + l_stateArg->iv_installState = false; + l_stateArg->iv_extractState = true; + fapiArg = reinterpret_cast<uint64_t> (l_stateArg); + myArgs.push_back(fapiArg); + + // Create a FAPI Target + fapi::Target l_fapiTarget(fapi::TARGET_TYPE_PROC_CHIP, + reinterpret_cast<void *> (l_testTarget)); + + //@todo - Comment out the actual run for now because + // the "halt" instruction causes poreve to scom SBEVITAL cfam reg, + // which causes an error in SIMICs. + // VBU model also has a hack that models this register + //l_rc = fapiPoreVe(l_fapiTarget, myArgs); + if (l_rc != fapi::FAPI_RC_SUCCESS) + { + uint32_t val = l_rc; + FAPI_ERR("testPore1: Error from fapiPoreVe 0x%llX", val); + } + else + { + FAPI_INF("testPore1: fapiPoreVe runs successfully!"); + } + + } while(0); + + // Unload sbe_pnor + if (l_unloadSbePnorImg == true) + { + l_rc2 = fapiUnloadInitFile("sbe_pnor.bin", l_sbePnorAddr, + l_sbePnorSize); + if (l_rc2 != fapi::FAPI_RC_SUCCESS) + { + FAPI_ERR("testPore1: Error unloading sbe_pnor.bin"); + if (l_rc == fapi::FAPI_RC_SUCCESS) + { + l_rc = l_rc2; + } + } + } + + // Test fail/pass + if (l_rc != fapi::FAPI_RC_SUCCESS) + { + TS_FAIL("testPore1 fails! Check FAPI trace"); + } + else + { + TS_TRACE("testPore1 ran successfully!"); + } + + return; + } +}; + +#endif |