Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions helper_scripts/generate_EmulatorConstants.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ end

local out = io.stdout



out:write(' bytes32 constant UARCH_PRISTINE_STATE_HASH = 0x' .. hexstring(cartesi.UARCH_PRISTINE_STATE_HASH) .. ';\n')
out:write(' uint64 constant UARCH_CYCLE_ADDRESS = 0x' .. hex(cartesi.machine:get_reg_address("uarch_cycle")) .. ';\n')
out:write(' uint64 constant UARCH_HALT_FLAG_ADDRESS = 0x' ..
hex(cartesi.machine:get_reg_address("uarch_halt_flag")) .. ';\n')
Expand All @@ -27,22 +26,28 @@ out:write(' uint64 constant UARCH_SHADOW_LENGTH = 0x' .. hex(cartesi.UARCH_SH
out:write(' uint64 constant UARCH_RAM_START_ADDRESS = 0x' .. hex(cartesi.UARCH_RAM_START_ADDRESS) .. ';\n')
out:write(' uint64 constant UARCH_RAM_LENGTH = 0x' .. hex(cartesi.UARCH_RAM_LENGTH) .. ';\n')
out:write(' uint64 constant UARCH_STATE_START_ADDRESS = 0x' .. hex(cartesi.UARCH_STATE_START_ADDRESS) .. ';\n')
out:write(' uint8 constant UARCH_STATE_LOG2_SIZE = ' .. cartesi.UARCH_STATE_LOG2_SIZE .. ';\n')
out:write(' bytes32 constant UARCH_PRISTINE_STATE_HASH = 0x' .. hexstring(cartesi.UARCH_PRISTINE_STATE_HASH) .. ';\n')
out:write(' uint64 constant UARCH_ECALL_FN_HALT = ' .. cartesi.UARCH_ECALL_FN_HALT .. ';\n')
out:write(' uint64 constant UARCH_ECALL_FN_PUTCHAR = ' .. cartesi.UARCH_ECALL_FN_PUTCHAR .. ';\n')
out:write(' uint64 constant HTIF_YIELD = 0x' .. hex(cartesi.machine:get_reg_address("htif_iyield")) .. ';\n')
out:write(' uint64 constant IFLAGS_Y_ADDRESS = 0x' .. hex(cartesi.machine:get_reg_address("iflags_Y")) .. ';\n')
out:write(' uint64 constant HTIF_FROMHOST_ADDRESS = 0x' ..
hex(cartesi.machine:get_reg_address("htif_fromhost")) .. ';\n')
out:write(' uint8 constant CMIO_YIELD_REASON_ADVANCE_STATE = 0x' ..
hex(cartesi.CMIO_YIELD_REASON_ADVANCE_STATE) .. ';\n')
out:write(' uint64 constant HTIF_TOHOST_ADDRESS = 0x' ..
hex(cartesi.machine:get_reg_address("htif_tohost")) .. ';\n')
out:write(' uint64 constant PMA_CMIO_TX_BUFFER_START = 0x' .. hex(cartesi.PMA_CMIO_TX_BUFFER_START) .. ';\n')
out:write(' uint64 constant PMA_CMIO_RX_BUFFER_START = 0x' .. hex(cartesi.PMA_CMIO_RX_BUFFER_START) .. ';\n')
out:write(' uint32 constant TREE_LOG2_WORD_SIZE = 0x' .. hex(cartesi.TREE_LOG2_WORD_SIZE) .. ';\n')
out:write(' uint32 constant TREE_WORD_SIZE = uint32(1) << TREE_LOG2_WORD_SIZE;\n')
out:write(' uint64 constant PMA_CMIO_RX_BUFFER_START = 0x' .. hex(cartesi.PMA_CMIO_RX_BUFFER_START) .. ';\n')
out:write(' uint8 constant PMA_CMIO_RX_BUFFER_LOG2_SIZE = 0x' .. hex(cartesi.PMA_CMIO_RX_BUFFER_LOG2_SIZE) .. ';\n')
out:write(' uint64 constant PMA_CMIO_TX_BUFFER_START = 0x' .. hex(cartesi.PMA_CMIO_TX_BUFFER_START) .. ';\n')
out:write(' uint16 constant CMIO_YIELD_MANUAL_REASON_RX_ACCEPTED = 0x' ..
hex(cartesi.CMIO_YIELD_MANUAL_REASON_RX_ACCEPTED) .. ';\n')
out:write(' uint16 constant CMIO_YIELD_MANUAL_REASON_RX_REJECTED = 0x' ..
hex(cartesi.CMIO_YIELD_MANUAL_REASON_RX_REJECTED) .. ';\n')
out:write(' uint16 constant CMIO_YIELD_MANUAL_REASON_TX_EXCEPTION = 0x' ..
hex(cartesi.CMIO_YIELD_MANUAL_REASON_TX_EXCEPTION) .. ';\n')
out:write(' uint8 constant UARCH_STATE_LOG2_SIZE = ' .. cartesi.UARCH_STATE_LOG2_SIZE .. ';\n')
out:write(' uint8 constant PMA_CMIO_TX_BUFFER_LOG2_SIZE = 0x' .. hex(cartesi.PMA_CMIO_TX_BUFFER_LOG2_SIZE) .. ';\n')
out:close()
out:write(' uint8 constant PMA_CMIO_RX_BUFFER_LOG2_SIZE = 0x' .. hex(cartesi.PMA_CMIO_RX_BUFFER_LOG2_SIZE) .. ';\n')
out:write(' uint8 constant CMIO_YIELD_REASON_ADVANCE_STATE = 0x' ..
hex(cartesi.CMIO_YIELD_REASON_ADVANCE_STATE) .. ';\n')

out:close()
68 changes: 34 additions & 34 deletions src/AccessLogs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,6 @@ library AccessLogs {
return end2;
}

/// @dev bytes buffer layout is the same for `readWord` and `writeWord`,
/// [32 bytes as read data], [59 * 32 bytes as sibling hashes]

//
// Read methods
//
function readRegion(
AccessLogs.Context memory a,
Memory.Region memory region
Expand All @@ -90,30 +84,6 @@ library AccessLogs {
return readRegion(a, r);
}

function readWord(
AccessLogs.Context memory a,
Memory.PhysicalAddress readAddress
) internal pure returns (uint64) {
(Memory.PhysicalAddress leafAddress, uint64 wordOffset) =
readAddress.truncateToLeaf();

Memory.Region memory region = Memory.regionFromStride(
Memory.strideFromLeafAddress(leafAddress),
Memory.alignedSizeFromLog2(0)
);

bytes32 leaf = a.buffer.consumeBytes32();
bytes32 rootHash =
a.buffer.getRoot(region, keccak256(abi.encodePacked(leaf)));
require(a.currentRootHash == rootHash, "Read word root doesn't match");

bytes8 word = getBytes8FromBytes32AtOffset(leaf, wordOffset);
return machineWordToSolidityUint64(word);
}

//
// Write methods
//
function writeRegion(
AccessLogs.Context memory a,
Memory.Region memory region,
Expand Down Expand Up @@ -141,6 +111,36 @@ library AccessLogs {
writeRegion(a, r, newHash);
}

/// @dev bytes buffer layout is the same for `readWord` and `writeWord`,
/// [32 bytes as read data], [59 * 32 bytes as sibling hashes]

//
// Read methods
//
function readWord(
AccessLogs.Context memory a,
Memory.PhysicalAddress readAddress
) internal pure returns (uint64) {
(Memory.PhysicalAddress leafAddress, uint64 wordOffset) =
readAddress.truncateToLeaf();

Memory.Region memory region = Memory.regionFromStride(
Memory.strideFromLeafAddress(leafAddress),
Memory.alignedSizeFromLog2(0)
);

bytes32 leaf = a.buffer.consumeBytes32();
bytes32 rootHash =
a.buffer.getRoot(region, keccak256(abi.encodePacked(leaf)));
require(a.currentRootHash == rootHash, "Read word root doesn't match");

bytes8 word = getBytes8FromBytes32AtOffset(leaf, wordOffset);
return machineWordToSolidityUint64(word);
}

//
// Write methods
//
function writeWord(
AccessLogs.Context memory a,
Memory.PhysicalAddress writeAddress,
Expand Down Expand Up @@ -169,20 +169,20 @@ library AccessLogs {
a.currentRootHash = newRootHash;
}

function getBytes8FromBytes32AtOffset(bytes32 source, uint64 offset)
function getBytes8FromBytes32AtOffset(bytes32 source, uint64 offsetInBytes)
internal
pure
returns (bytes8)
{
return bytes8(source << (offset << Memory.LOG2_WORD));
return bytes8(source << (offsetInBytes << Memory.LOG2_WORD));
}

function setBytes8ToBytes32AtOffset(
bytes8 word,
bytes32 leaf,
uint64 offset
uint64 offsetInBytes
) internal pure returns (bytes32) {
uint256 wordOffset = offset << Memory.LOG2_WORD;
uint256 wordOffset = offsetInBytes << Memory.LOG2_WORD;
bytes32 toWrite = bytes32(word) >> wordOffset;

bytes32 wordMask = bytes32(~bytes8(0));
Expand Down
76 changes: 76 additions & 0 deletions src/AdvanceStatus.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

/// @title AdvanceStatus
/// @notice Return advance status

pragma solidity ^0.8.0;

import "./EmulatorCompat.sol";
import "./EmulatorConstants.sol";

library AdvanceStatus {
enum Status {
NOT_YIELDED,
ACCEPTED,
REJECTED,
EXCEPTION
}

/*
typedef struct cmt_io_yield {
uint8_t dev;
uint8_t cmd;
uint16_t reason;
uint32_t data;
} cmt_io_yield_t;
*/

error InvalidReason(uint16 reason);

function advanceStatus(AccessLogs.Context memory a)
internal
pure
returns (Status)
{
if (!EmulatorCompat.readIflagsY(a)) {
return Status.NOT_YIELDED;
}

// the following two approaches are equivalent:
// 1. swap the whole struct and then extract the reason
// 2. extract the reason from the struct and then swap the value
// EmulatorCompat.readWord already swaps the struct, so we can extract the reason directly

uint64 tohost =
EmulatorCompat.readWord(a, EmulatorConstants.HTIF_TOHOST_ADDRESS);
uint16 reason = uint16(tohost >> 32);

if (reason == EmulatorConstants.CMIO_YIELD_MANUAL_REASON_RX_ACCEPTED) {
return Status.ACCEPTED;
} else if (
reason == EmulatorConstants.CMIO_YIELD_MANUAL_REASON_RX_REJECTED
) {
return Status.REJECTED;
} else if (
reason == EmulatorConstants.CMIO_YIELD_MANUAL_REASON_TX_EXCEPTION
) {
return Status.EXCEPTION;
} else {
revert InvalidReason(reason);
}
}
}
31 changes: 31 additions & 0 deletions src/EmulatorCompat.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,27 @@ import "./AccessLogs.sol";

library EmulatorCompat {
using AccessLogs for AccessLogs.Context;
using Buffer for Buffer.Context;
using Memory for uint64;

function getCheckpointHash(AccessLogs.Context memory a)
internal
pure
returns (bytes32)
{
bytes32 checkpointHash = a.buffer.consumeBytes32();
bytes32 hashOfCheckpointHash = a.readLeaf(
Memory.strideFromLeafAddress(
EmulatorConstants.CHECKPOINT_ADDRESS.toPhysicalAddress()
)
);
require(
keccak256(abi.encodePacked(checkpointHash)) == hashOfCheckpointHash
);

return checkpointHash;
}

function readCycle(AccessLogs.Context memory a)
internal
pure
Expand Down Expand Up @@ -88,6 +107,18 @@ library EmulatorCompat {
);
}

function setCheckpointHash(
AccessLogs.Context memory a,
bytes32 checkpointHash
) internal pure {
a.writeLeaf(
Memory.strideFromLeafAddress(
EmulatorConstants.CHECKPOINT_ADDRESS.toPhysicalAddress()
),
keccak256(abi.encodePacked(checkpointHash))
);
}

function writePc(AccessLogs.Context memory a, uint64 val) internal pure {
a.writeWord(EmulatorConstants.UARCH_PC_ADDRESS.toPhysicalAddress(), val);
}
Expand Down
19 changes: 12 additions & 7 deletions src/EmulatorConstants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pragma solidity ^0.8.0;
library EmulatorConstants {
// START OF AUTO-GENERATED CODE

bytes32 constant UARCH_PRISTINE_STATE_HASH =
0x1bbf39b2c4324c9c8862b8e5550fe35b06ebccb0dcd2c3f114cc1411813ca5fc;
uint64 constant UARCH_CYCLE_ADDRESS = 0x400008;
uint64 constant UARCH_HALT_FLAG_ADDRESS = 0x400000;
uint64 constant UARCH_PC_ADDRESS = 0x400010;
Expand All @@ -33,23 +35,26 @@ library EmulatorConstants {
uint64 constant UARCH_RAM_START_ADDRESS = 0x600000;
uint64 constant UARCH_RAM_LENGTH = 0x200000;
uint64 constant UARCH_STATE_START_ADDRESS = 0x400000;
uint8 constant UARCH_STATE_LOG2_SIZE = 22;
bytes32 constant UARCH_PRISTINE_STATE_HASH =
0x1bbf39b2c4324c9c8862b8e5550fe35b06ebccb0dcd2c3f114cc1411813ca5fc;
uint64 constant UARCH_ECALL_FN_HALT = 1;
uint64 constant UARCH_ECALL_FN_PUTCHAR = 2;
uint64 constant HTIF_YIELD = 0x348;
uint64 constant IFLAGS_Y_ADDRESS = 0x2f8;
uint64 constant HTIF_FROMHOST_ADDRESS = 0x330;
uint8 constant CMIO_YIELD_REASON_ADVANCE_STATE = 0x0;
uint64 constant HTIF_TOHOST_ADDRESS = 0x328;
uint64 constant PMA_CMIO_TX_BUFFER_START = 0x60800000;
uint64 constant PMA_CMIO_RX_BUFFER_START = 0x60000000;
uint32 constant TREE_LOG2_WORD_SIZE = 0x5;
uint32 constant TREE_WORD_SIZE = uint32(1) << TREE_LOG2_WORD_SIZE;
uint64 constant PMA_CMIO_RX_BUFFER_START = 0x60000000;
uint8 constant PMA_CMIO_RX_BUFFER_LOG2_SIZE = 0x15;
uint64 constant PMA_CMIO_TX_BUFFER_START = 0x60800000;
uint16 constant CMIO_YIELD_MANUAL_REASON_RX_ACCEPTED = 0x1;
uint16 constant CMIO_YIELD_MANUAL_REASON_RX_REJECTED = 0x2;
uint16 constant CMIO_YIELD_MANUAL_REASON_TX_EXCEPTION = 0x4;
uint8 constant UARCH_STATE_LOG2_SIZE = 22;
uint8 constant PMA_CMIO_TX_BUFFER_LOG2_SIZE = 0x15;
uint8 constant PMA_CMIO_RX_BUFFER_LOG2_SIZE = 0x15;
uint8 constant CMIO_YIELD_REASON_ADVANCE_STATE = 0x0;
// END OF AUTO-GENERATED CODE

uint32 constant IFLAGS_Y_SHIFT = 1;
uint64 constant LOG2_CYCLES_TO_RESET = 10;
uint64 constant CHECKPOINT_ADDRESS = 0x7ffff000;
}
Loading