-
Notifications
You must be signed in to change notification settings - Fork 34
Using the C API
Eduardo Bart edited this page Dec 15, 2024
·
4 revisions
Before trying this example first make sure:
- You have Cartesi Machine installed globally in your system.
- You have
linux.bin
androotfs.ext2
images available locally (you could copy them from your installation). - You have a C compiler.
- You are using Cartesi Machine 0.19+ (contains the new C API, it's not released yet).
The following example boots a machine and prints a hello message:
#include <cartesi-machine/machine-c-api.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
// Set machine configuration
const char *config = "{\
\"dtb\": {\
\"entrypoint\": \"echo Hello from inside!\"\
},\
\"flash_drive\": [\
{\"image_filename\": \"rootfs.ext2\"}\
],\
\"ram\": {\
\"length\": 134217728,\
\"image_filename\": \"linux.bin\"\
}\
}";
// Create a new machine
cm_machine *machine = NULL;
if (cm_create_new(config, NULL, &machine) != CM_ERROR_OK) {
printf("failed to create machine: %s\n", cm_get_last_error_message());
return 1;
}
// Run the machine
cm_break_reason break_reason;
if (cm_run(machine, CM_MCYCLE_MAX, &break_reason) != CM_ERROR_OK) {
printf("failed to run machine: %s\n", cm_get_last_error_message());
cm_delete(machine);
return 1;
}
// Print reason for run interruption
switch (break_reason) {
case CM_BREAK_REASON_HALTED:
printf("Halted\n");
break;
case CM_BREAK_REASON_YIELDED_MANUALLY:
printf("Yielded manually\n");
break;
case CM_BREAK_REASON_YIELDED_AUTOMATICALLY:
printf("Yielded automatically\n");
break;
case CM_BREAK_REASON_YIELDED_SOFTLY:
printf("Yielded softly\n");
break;
case CM_BREAK_REASON_REACHED_TARGET_MCYCLE:
printf("Reached target machine cycle\n");
break;
case CM_BREAK_REASON_FAILED:
default:
printf("Interpreter failed\n");
break;
}
// Read and print machine cycles
uint64_t mcycle;
if (cm_read_mcycle(machine, &mcycle) != CM_ERROR_OK) {
printf("failed to read machine cycle: %s\n", cm_get_last_error_message());
cm_delete(machine);
return 1;
}
printf("Cycles: %lu\n", mcycle);
// Cleanup and exit
cm_delete(machine);
return 0;
}
Compile and run with:
gcc example.c -o example -lcartesi
./example
You should get the following output:
Hello from inside!
Halted
Cycles: 48985837
To perform input/output operations from inside a machine to the outside you can use the CMIO (Cartesi Machine IO) with its GIO (generic IO) interface, the following example demonstrates this:
#include <cartesi-machine/machine-c-api.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
// Set machine configuration
const char *config = "{\
\"dtb\": {\
\"entrypoint\": \"echo '{\\\"domain\\\":16,\\\"id\\\":\\\"'$(echo -n Hello from inside! | hex --encode)'\\\"}' | rollup gio | grep -Eo '0x[0-9a-f]+' | tr -d '\\n' | hex --decode; echo\"\
},\
\"flash_drive\": [\
{\"image_filename\": \"rootfs.ext2\"}\
],\
\"ram\": {\
\"length\": 134217728,\
\"image_filename\": \"linux.bin\"\
}\
}";
// Create a new machine
cm_machine *machine = NULL;
if (cm_create_new(config, NULL, &machine) != CM_ERROR_OK) {
printf("failed to create machine: %s\n", cm_get_last_error_message());
return 1;
}
// Run the machine
if (cm_run(machine, CM_MCYCLE_MAX, NULL) != CM_ERROR_OK) {
printf("failed to run machine: %s\n", cm_get_last_error_message());
cm_delete(machine);
return 1;
}
// Receive GIO request
uint8_t cmd;
uint16_t domain;
uint8_t request_data[1024];
uint64_t length = sizeof(request_data);
if (cm_receive_cmio_request(machine, &cmd, &domain, request_data, &length)) {
printf("failed to receive CMIO request: %s\n", cm_get_last_error_message());
cm_delete(machine);
return 1;
}
if (cmd != CM_CMIO_YIELD_COMMAND_MANUAL || domain != 16) {
printf("unsupported CMIO request, expected GIO with domain=16\n");
cm_delete(machine);
return 1;
}
printf("%.*s\n", (int)length, (char*)request_data);
// Send GIO response
const char response_data[] = "Hello from outside!";
if (cm_send_cmio_response(machine, domain, (uint8_t*)response_data, sizeof(response_data)-1) != CM_ERROR_OK) {
printf("failed to send CMIO response: %s\n", cm_get_last_error_message());
cm_delete(machine);
return 1;
}
// Resume the machine
cm_break_reason break_reason;
if (cm_run(machine, CM_MCYCLE_MAX, &break_reason) != CM_ERROR_OK) {
printf("failed to resume machine: %s\n", cm_get_last_error_message());
cm_delete(machine);
return 1;
}
// Print reason for run interruption
switch (break_reason) {
case CM_BREAK_REASON_HALTED:
printf("Halted\n");
break;
case CM_BREAK_REASON_YIELDED_MANUALLY:
printf("Yielded manually\n");
break;
case CM_BREAK_REASON_YIELDED_AUTOMATICALLY:
printf("Yielded automatically\n");
break;
case CM_BREAK_REASON_YIELDED_SOFTLY:
printf("Yielded softly\n");
break;
case CM_BREAK_REASON_REACHED_TARGET_MCYCLE:
printf("Reached target machine cycle\n");
break;
case CM_BREAK_REASON_FAILED:
default:
printf("Interpreter failed\n");
break;
}
// Read and print machine cycles
uint64_t mcycle;
if (cm_read_mcycle(machine, &mcycle) != CM_ERROR_OK) {
printf("failed to read machine cycle: %s\n", cm_get_last_error_message());
cm_delete(machine);
return 1;
}
printf("Cycles: %lu\n", mcycle);
// Cleanup and exit
cm_delete(machine);
return 0;
}
Compile and run with:
gcc example-gio.c -o example-gio -lcartesi
./example-gio
You should get the following output:
Hello from inside!
Hello from outside!
Halted
Cycles: 61800308
For more information on how to use API please read the C API header, every function there is documented.