Word Story::read(OperandType operandType) { switch(operandType) { case OperandType::Large: return readNextWord(); case OperandType::Small: return readNextByte(); case OperandType::Variable: { auto variableID = readNextByte(); return loadVariable(variableID); } case OperandType::Omitted: { throw Exception("Omitted unexpected"); } default: { throw Exception("unexpected operand type"); } } }
OpcodeDetails Story::decode() { auto baseAddress = m_PC; const Byte value = readNextByte(); auto opcodeForm=ToOpcodeForm(value); if(opcodeForm == OpcodeForm::Short) { auto operandCount = ((value & 48) == 48 ? OperandCount::OP0 : OperandCount::OP1); // The opcode is in the bottom 4 bits return OpcodeDetails(baseAddress, value, value & 15, opcodeForm, operandCount); } if(opcodeForm == OpcodeForm::Long) { auto operandCount=OperandCount::OP2; // The opcode is in the bottom 5 bits return OpcodeDetails(baseAddress,value,value & 31, opcodeForm, operandCount); } if(opcodeForm == OpcodeForm::Variable) { auto operandCount = ((value & 32) ? OperandCount::Variable : OperandCount::OP2); // The opcode is in the bottom 5 bits return OpcodeDetails(baseAddress, value, value & 31, opcodeForm, operandCount); } if(opcodeForm == OpcodeForm::Extended) { auto operandCount = OperandCount::Variable; // The next byte has the opcode Byte opcode = readNextByte(); return OpcodeDetails(baseAddress, value, opcode, opcodeForm, operandCount); } throw Exception("unexpected opcode form"); }
BranchDetails Story::readBranchDetails() { Byte b1 = readNextByte(); // If bit 7 is 0 the condition must be false, if 1 then the condition must be true bool comparisonValue = (b1 & 128) ? true : false; Word offset = (b1 & 63); // If bit 6 is set then the branch is 1 byte, otherwise it's 2 if((b1 & 64) == 0) { auto b2 = readNextByte(); offset = ((offset << 8 ) | b2); // We've got a signed 14 bit number. We need to sign extend it to 16 bits if bit 14 is set if(offset & 8192) { offset |= 49152; } } return BranchDetails(AsSignedWord(offset), comparisonValue); }
void Story::callRoutine(Address routineAddress, Word returnVariable, const std::vector<Word> &arguments) { // NOTE: special case! A call to address 0 means return false! if(routineAddress == 0) { returnFromCall(0); return; // NOTE: Early return } Address returnAddress = m_PC; auto normalizedAddress = expandPackedRoutineAddress(routineAddress); // Point to the new routine setPC(normalizedAddress); auto numberOfLocals = readNextByte(); auto stackFrame = allocateNewFrame(returnAddress, arguments.size(), numberOfLocals, returnVariable); // The local default values are stored next if(m_Version <= 4) { // The defaults are next for(Byte i = 0; i < numberOfLocals; i++) { auto value = readNextWord(); storeVariable(i + 1, value); } } else { // They all default to 0 for(Byte i = 0; i < numberOfLocals; i++) { storeVariable(i + 1, 0); } } // Now layer the arguments on top auto argumentsToCopy = std::min(numberOfLocals, static_cast<Byte>(arguments.size())); for(Byte i = 0; i < argumentsToCopy; i++) { storeVariable(i + 1, arguments[i]); } }
//FIXME: void announcePacket(uint16_t packetSize) { void announcePacket() { uint8_t buffer[ANNOUNCE_DATA_SIZE]; uint16_t packetLength; // Transfer entire packet to RAM uint8_t* bufPtr = buffer; uint16_t count; readPointer = spiReadWord(REG_S2_RX_RD0) + S2_RX_START; // Read destination IP address for(count = 0; count < 4; count++) { spiWriteReg(REG_S2_DIPR0 + count, readNextByte()); } // Read destination port - but ignore it and respond on 5555 anyway. readNextByte(); readNextByte(); spiWriteWord(REG_S2_DPORT0, ANNOUNCE_PORT); // Read packet length packetLength = readNextByte() | (readNextByte() << 8); // Trim overlong packets if(packetLength > ANNOUNCE_DATA_SIZE) packetLength = ANNOUNCE_DATA_SIZE; for(count = packetLength; --count;) { *bufPtr++ = readNextByte(); } spiWriteWord(REG_S2_RX_RD0, readPointer - S2_RX_START); // Write back new pointer spiWriteWord(REG_S2_CR, CR_RECV); // Receive again // Dump packet bufPtr = buffer; // Parse packet if(memcmp(buffer, "arduino", 7) == 0) announceReply(); }
void i2cCheckPort(i2cPortData *pPort) { switch(pPort->i2cState) { case I2C_STATE_START: if(!pPort->pConBits->SEN) { // start done - send a read or write address sendAddress(pPort); } break; case I2C_STATE_ADDR: if(!pPort->pStatBits->TRSTAT) { // address send done - did the device ack? if(!pPort->pStatBits->ACKSTAT) { // device ack'd if(pPort->writeSize) { // start writing writeNextByte(pPort); } else { // start reading readNextByte(pPort); } } else { // no ack - do a stop and give up noAck(pPort); } } break; case I2C_STATE_WRITE: if(!pPort->pStatBits->TRSTAT) { // write done - did the device ack? if(!pPort->pStatBits->ACKSTAT) { if(pPort->i2cIndex < pPort->writeSize) { writeNextByte(pPort); } else { // done writing - might need to read if(pPort->readSize) { // repeat start pPort->pConBits->RSEN = 1; pPort->i2cState = I2C_STATE_R_START; } else { i2cStop(pPort); } } } else { noAck(pPort); } } break; case I2C_STATE_R_START: if(!pPort->pConBits->RSEN) { // Repeat start done - back to the address pPort->writeSize = 0; // force a read sendAddress(pPort); } break; case I2C_STATE_READ: if(!pPort->pConBits->RCEN) { // done reading, now do ack pPort->readBuffer[pPort->i2cIndex] = *pPort->pRxReg; pPort->i2cIndex++; pPort->pConBits->ACKDT = (pPort->i2cIndex == pPort->readSize); // NACK on last byte pPort->pConBits->ACKEN = 1; pPort->i2cState = I2C_STATE_READ_ACK; } break; case I2C_STATE_READ_ACK: if(!pPort->pConBits->ACKEN) { // done read ack if(pPort->i2cIndex >= pPort->readSize) { // done receiving i2cStop(pPort); } else { readNextByte(pPort); } } break; case I2C_STATE_STOP: if(!pPort->pConBits->PEN) { // stop condition done pPort->i2cState = I2C_STATE_IDLE; *pPort->pConReg = I2CCON_OFF; // Turn off the I2C } break; default: pPort->i2cState = I2C_STATE_IDLE; break; } }